fix: order nulls last (#519)
* fix: order nulls last * fix: test error * fix: test error
This commit is contained in:
		
							parent
							
								
									529380fb69
								
							
						
					
					
						commit
						22c6591162
					
				@ -1,7 +1,7 @@
 | 
			
		||||
import { Collection } from '../collection';
 | 
			
		||||
import { mockDatabase } from './index';
 | 
			
		||||
import { OptionsParser } from '../options-parser';
 | 
			
		||||
import { Database } from '../database';
 | 
			
		||||
import { OptionsParser } from '../options-parser';
 | 
			
		||||
import { mockDatabase } from './index';
 | 
			
		||||
 | 
			
		||||
describe('option parser', () => {
 | 
			
		||||
  let db: Database;
 | 
			
		||||
@ -83,6 +83,10 @@ describe('option parser', () => {
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  test('with sort option', () => {
 | 
			
		||||
    if (db.inDialect('mysql'))  {
 | 
			
		||||
      expect(1).toBe(1);
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    let options: any = {
 | 
			
		||||
      sort: ['id'],
 | 
			
		||||
    };
 | 
			
		||||
@ -91,7 +95,7 @@ describe('option parser', () => {
 | 
			
		||||
      collection: User,
 | 
			
		||||
    });
 | 
			
		||||
    let params = parser.toSequelizeParams();
 | 
			
		||||
    expect(params['order']).toEqual([['id', 'ASC']]);
 | 
			
		||||
    expect(params['order']).toEqual([['id', 'ASC NULLS LAST']]);
 | 
			
		||||
 | 
			
		||||
    options = {
 | 
			
		||||
      sort: ['id', '-posts.title', 'posts.comments.createdAt'],
 | 
			
		||||
@ -102,9 +106,9 @@ describe('option parser', () => {
 | 
			
		||||
    });
 | 
			
		||||
    params = parser.toSequelizeParams();
 | 
			
		||||
    expect(params['order']).toEqual([
 | 
			
		||||
      ['id', 'ASC'],
 | 
			
		||||
      [Post.model, 'title', 'DESC'],
 | 
			
		||||
      [Post.model, Comment.model, 'createdAt', 'ASC'],
 | 
			
		||||
      ['id', 'ASC NULLS LAST'],
 | 
			
		||||
      [Post.model, 'title', 'DESC NULLS LAST'],
 | 
			
		||||
      [Post.model, Comment.model, 'createdAt', 'ASC NULLS LAST'],
 | 
			
		||||
    ]);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										51
									
								
								packages/core/database/src/__tests__/sort.test.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								packages/core/database/src/__tests__/sort.test.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,51 @@
 | 
			
		||||
import { Database } from '../database';
 | 
			
		||||
import { mockDatabase } from './';
 | 
			
		||||
 | 
			
		||||
describe('sort', function () {
 | 
			
		||||
  let db: Database;
 | 
			
		||||
 | 
			
		||||
  beforeEach(async () => {
 | 
			
		||||
    db = mockDatabase();
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  afterEach(async () => {
 | 
			
		||||
    await db.close();
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  test('order nulls last', async () => {
 | 
			
		||||
    const Test = db.collection({
 | 
			
		||||
      name: 'test',
 | 
			
		||||
      fields: [
 | 
			
		||||
        {
 | 
			
		||||
          type: 'integer',
 | 
			
		||||
          name: 'num',
 | 
			
		||||
        },
 | 
			
		||||
      ],
 | 
			
		||||
    });
 | 
			
		||||
    await Test.sync();
 | 
			
		||||
    await Test.model.bulkCreate([
 | 
			
		||||
      {
 | 
			
		||||
        num: 3,
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        num: 2,
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        num: null,
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        num: 1,
 | 
			
		||||
      },
 | 
			
		||||
    ]);
 | 
			
		||||
    const items = await Test.repository.find({
 | 
			
		||||
      sort: '-num',
 | 
			
		||||
    });
 | 
			
		||||
    const nums = items.map((item) => item.get('num'));
 | 
			
		||||
    expect(nums).toEqual([3,2,1,null]);
 | 
			
		||||
    const items2 = await Test.repository.find({
 | 
			
		||||
      sort: 'num',
 | 
			
		||||
    });
 | 
			
		||||
    const nums2 = items2.map((item) => item.get('num'));
 | 
			
		||||
    expect(nums2).toEqual([1,2,3,null]);
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
@ -177,6 +177,10 @@ export class Database extends EventEmitter implements AsyncEmitter {
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  inDialect(...dialect: string[]) {
 | 
			
		||||
    return dialect.includes(this.sequelize.getDialect());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private requireModule(module: any) {
 | 
			
		||||
    if (typeof module === 'string') {
 | 
			
		||||
      module = require(module);
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
import { FindAttributeOptions, ModelCtor, Op } from 'sequelize';
 | 
			
		||||
import { FindAttributeOptions, ModelCtor, Op, Sequelize } from 'sequelize';
 | 
			
		||||
import { Collection } from './collection';
 | 
			
		||||
import { Database } from './database';
 | 
			
		||||
import FilterParser from './filter-parser';
 | 
			
		||||
@ -70,24 +70,28 @@ export class OptionsParser {
 | 
			
		||||
    if (typeof sort === 'string') {
 | 
			
		||||
      sort = sort.split(',');
 | 
			
		||||
    }
 | 
			
		||||
    const orderParams = sort.map((sortKey: string) => {
 | 
			
		||||
      const direction = sortKey.startsWith('-') ? 'DESC' : 'ASC';
 | 
			
		||||
      const sortField: Array<any> = sortKey.replace('-', '').split('.');
 | 
			
		||||
 | 
			
		||||
    const orderParams = [];
 | 
			
		||||
    for (const sortKey of sort) {
 | 
			
		||||
      let direction = sortKey.startsWith('-') ? 'DESC' : 'ASC';
 | 
			
		||||
      let sortField: Array<any> = sortKey.replace('-', '').split('.');
 | 
			
		||||
      if (this.database.inDialect('postgres', 'sqlite')) {
 | 
			
		||||
        direction = `${direction} NULLS LAST`;
 | 
			
		||||
      }
 | 
			
		||||
      // handle sort by association
 | 
			
		||||
      if (sortField.length > 1) {
 | 
			
		||||
        let associationModel = this.model;
 | 
			
		||||
 | 
			
		||||
        for (let i = 0; i < sortField.length - 1; i++) {
 | 
			
		||||
          const associationKey = sortField[i];
 | 
			
		||||
          sortField[i] = associationModel.associations[associationKey].target;
 | 
			
		||||
          associationModel = sortField[i];
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      sortField.push(direction);
 | 
			
		||||
      return sortField;
 | 
			
		||||
    });
 | 
			
		||||
      if (this.database.inDialect('mysql')) {
 | 
			
		||||
        orderParams.push([Sequelize.fn('ISNULL', Sequelize.col(`${this.model.name}.${sortField[0]}`))]);
 | 
			
		||||
      }
 | 
			
		||||
      orderParams.push(sortField);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (orderParams.length > 0) {
 | 
			
		||||
      return {
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user