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