mirror of
https://gitee.com/nocobase/nocobase.git
synced 2025-05-08 23:19:26 +08:00
feat: field sort plugin in mssql
This commit is contained in:
parent
09eda5ffdc
commit
d2ff34e17e
@ -27,6 +27,10 @@ describe('sort action', () => {
|
||||
return api.destroy();
|
||||
});
|
||||
|
||||
function parseSortValue(value) {
|
||||
return api.db.options.dialect === 'mssql' ? value.toString() : value;
|
||||
}
|
||||
|
||||
describe('associations', () => {
|
||||
let UserCollection: Collection;
|
||||
|
||||
@ -204,19 +208,19 @@ describe('sort action', () => {
|
||||
data: [
|
||||
{
|
||||
title: 't2',
|
||||
sort: 1,
|
||||
sort: parseSortValue(1),
|
||||
},
|
||||
{
|
||||
title: 't3',
|
||||
sort: 2,
|
||||
sort: parseSortValue(2),
|
||||
},
|
||||
{
|
||||
title: 't1',
|
||||
sort: 3,
|
||||
sort: parseSortValue(3),
|
||||
},
|
||||
{
|
||||
title: 't4',
|
||||
sort: 4,
|
||||
sort: parseSortValue(4),
|
||||
},
|
||||
],
|
||||
});
|
||||
@ -239,19 +243,19 @@ describe('sort action', () => {
|
||||
data: [
|
||||
{
|
||||
title: 't3',
|
||||
sort: 1,
|
||||
sort: parseSortValue(1),
|
||||
},
|
||||
{
|
||||
title: 't1',
|
||||
sort: 2,
|
||||
sort: parseSortValue(2),
|
||||
},
|
||||
{
|
||||
title: 't2',
|
||||
sort: 3,
|
||||
sort: parseSortValue(3),
|
||||
},
|
||||
{
|
||||
title: 't4',
|
||||
sort: 4,
|
||||
sort: parseSortValue(4),
|
||||
},
|
||||
],
|
||||
});
|
||||
@ -274,19 +278,19 @@ describe('sort action', () => {
|
||||
data: [
|
||||
{
|
||||
title: 't2',
|
||||
sort2: 1,
|
||||
sort2: parseSortValue(1),
|
||||
},
|
||||
{
|
||||
title: 't3',
|
||||
sort2: 2,
|
||||
sort2: parseSortValue(2),
|
||||
},
|
||||
{
|
||||
title: 't1',
|
||||
sort2: 3,
|
||||
sort2: parseSortValue(3),
|
||||
},
|
||||
{
|
||||
title: 't4',
|
||||
sort2: 4,
|
||||
sort2: parseSortValue(4),
|
||||
},
|
||||
],
|
||||
});
|
||||
@ -308,19 +312,19 @@ describe('sort action', () => {
|
||||
data: [
|
||||
{
|
||||
title: 't3',
|
||||
sort: 0,
|
||||
sort: parseSortValue(0),
|
||||
},
|
||||
{
|
||||
title: 't1',
|
||||
sort: 1,
|
||||
sort: parseSortValue(1),
|
||||
},
|
||||
{
|
||||
title: 't2',
|
||||
sort: 2,
|
||||
sort: parseSortValue(2),
|
||||
},
|
||||
{
|
||||
title: 't4',
|
||||
sort: 4,
|
||||
sort: parseSortValue(4),
|
||||
},
|
||||
],
|
||||
});
|
||||
@ -492,15 +496,15 @@ describe('sort action', () => {
|
||||
data: [
|
||||
{
|
||||
title: 't12',
|
||||
sort: 2,
|
||||
sort: parseSortValue(2),
|
||||
},
|
||||
{
|
||||
title: 't13',
|
||||
sort: 3,
|
||||
sort: parseSortValue(3),
|
||||
},
|
||||
{
|
||||
title: 't14',
|
||||
sort: 4,
|
||||
sort: parseSortValue(4),
|
||||
},
|
||||
],
|
||||
});
|
||||
@ -517,23 +521,23 @@ describe('sort action', () => {
|
||||
data: [
|
||||
{
|
||||
title: 't21',
|
||||
sort: 1,
|
||||
sort: parseSortValue(1),
|
||||
},
|
||||
{
|
||||
title: 't11',
|
||||
sort: 2,
|
||||
sort: parseSortValue(2),
|
||||
},
|
||||
{
|
||||
title: 't22',
|
||||
sort: 3,
|
||||
sort: parseSortValue(3),
|
||||
},
|
||||
{
|
||||
title: 't23',
|
||||
sort: 4,
|
||||
sort: parseSortValue(4),
|
||||
},
|
||||
{
|
||||
title: 't24',
|
||||
sort: 5,
|
||||
sort: parseSortValue(5),
|
||||
},
|
||||
],
|
||||
});
|
||||
@ -558,15 +562,15 @@ describe('sort action', () => {
|
||||
data: [
|
||||
{
|
||||
title: 't12',
|
||||
sort: 2,
|
||||
sort: parseSortValue(2),
|
||||
},
|
||||
{
|
||||
title: 't13',
|
||||
sort: 3,
|
||||
sort: parseSortValue(3),
|
||||
},
|
||||
{
|
||||
title: 't14',
|
||||
sort: 4,
|
||||
sort: parseSortValue(4),
|
||||
},
|
||||
],
|
||||
});
|
||||
@ -581,23 +585,23 @@ describe('sort action', () => {
|
||||
data: [
|
||||
{
|
||||
title: 't21',
|
||||
sort: 1,
|
||||
sort: parseSortValue(1),
|
||||
},
|
||||
{
|
||||
title: 't22',
|
||||
sort: 2,
|
||||
sort: parseSortValue(2),
|
||||
},
|
||||
{
|
||||
title: 't11',
|
||||
sort: 3,
|
||||
sort: parseSortValue(3),
|
||||
},
|
||||
{
|
||||
title: 't23',
|
||||
sort: 4,
|
||||
sort: parseSortValue(4),
|
||||
},
|
||||
{
|
||||
title: 't24',
|
||||
sort: 5,
|
||||
sort: parseSortValue(5),
|
||||
},
|
||||
],
|
||||
});
|
||||
@ -619,23 +623,23 @@ describe('sort action', () => {
|
||||
data: [
|
||||
{
|
||||
title: 't11',
|
||||
sort: 1,
|
||||
sort: parseSortValue(1),
|
||||
},
|
||||
{
|
||||
title: 't22',
|
||||
sort: 2,
|
||||
sort: parseSortValue(2),
|
||||
},
|
||||
{
|
||||
title: 't12',
|
||||
sort: 3,
|
||||
sort: parseSortValue(3),
|
||||
},
|
||||
{
|
||||
title: 't13',
|
||||
sort: 4,
|
||||
sort: parseSortValue(4),
|
||||
},
|
||||
{
|
||||
title: 't14',
|
||||
sort: 5,
|
||||
sort: parseSortValue(5),
|
||||
},
|
||||
],
|
||||
});
|
||||
@ -650,15 +654,15 @@ describe('sort action', () => {
|
||||
data: [
|
||||
{
|
||||
title: 't21',
|
||||
sort: 1,
|
||||
sort: parseSortValue(1),
|
||||
},
|
||||
{
|
||||
title: 't23',
|
||||
sort: 3,
|
||||
sort: parseSortValue(3),
|
||||
},
|
||||
{
|
||||
title: 't24',
|
||||
sort: 4,
|
||||
sort: parseSortValue(4),
|
||||
},
|
||||
],
|
||||
});
|
||||
@ -681,23 +685,23 @@ describe('sort action', () => {
|
||||
data: [
|
||||
{
|
||||
title: 't11',
|
||||
sort: 1,
|
||||
sort: parseSortValue(1),
|
||||
},
|
||||
{
|
||||
title: 't12',
|
||||
sort: 2,
|
||||
sort: parseSortValue(2),
|
||||
},
|
||||
{
|
||||
title: 't22',
|
||||
sort: 3,
|
||||
sort: parseSortValue(3),
|
||||
},
|
||||
{
|
||||
title: 't13',
|
||||
sort: 4,
|
||||
sort: parseSortValue(4),
|
||||
},
|
||||
{
|
||||
title: 't14',
|
||||
sort: 5,
|
||||
sort: parseSortValue(5),
|
||||
},
|
||||
],
|
||||
});
|
||||
@ -712,15 +716,15 @@ describe('sort action', () => {
|
||||
data: [
|
||||
{
|
||||
title: 't21',
|
||||
sort: 1,
|
||||
sort: parseSortValue(1),
|
||||
},
|
||||
{
|
||||
title: 't23',
|
||||
sort: 3,
|
||||
sort: parseSortValue(3),
|
||||
},
|
||||
{
|
||||
title: 't24',
|
||||
sort: 4,
|
||||
sort: parseSortValue(4),
|
||||
},
|
||||
],
|
||||
});
|
||||
@ -747,15 +751,15 @@ describe('sort action', () => {
|
||||
data: [
|
||||
{
|
||||
title: 't12',
|
||||
sort: 2,
|
||||
sort: parseSortValue(2),
|
||||
},
|
||||
{
|
||||
title: 't13',
|
||||
sort: 3,
|
||||
sort: parseSortValue(3),
|
||||
},
|
||||
{
|
||||
title: 't14',
|
||||
sort: 4,
|
||||
sort: parseSortValue(4),
|
||||
},
|
||||
],
|
||||
});
|
||||
@ -770,23 +774,23 @@ describe('sort action', () => {
|
||||
data: [
|
||||
{
|
||||
title: 't21',
|
||||
sort: 1,
|
||||
sort: parseSortValue(1),
|
||||
},
|
||||
{
|
||||
title: 't22',
|
||||
sort: 2,
|
||||
sort: parseSortValue(2),
|
||||
},
|
||||
{
|
||||
title: 't23',
|
||||
sort: 3,
|
||||
sort: parseSortValue(3),
|
||||
},
|
||||
{
|
||||
title: 't24',
|
||||
sort: 4,
|
||||
sort: parseSortValue(4),
|
||||
},
|
||||
{
|
||||
title: 't11',
|
||||
sort: 5,
|
||||
sort: parseSortValue(5),
|
||||
},
|
||||
],
|
||||
});
|
||||
|
@ -30,6 +30,10 @@ describe('sort collections', () => {
|
||||
await app.destroy();
|
||||
});
|
||||
|
||||
function parseSortValue(value) {
|
||||
return db.options.dialect === 'mssql' ? value.toString() : value;
|
||||
}
|
||||
|
||||
describe('sort collection', () => {
|
||||
beforeEach(async () => {
|
||||
Post = app.db.collection({
|
||||
@ -68,7 +72,7 @@ describe('sort collections', () => {
|
||||
await db.sync();
|
||||
const instance = await model.create();
|
||||
expect(model.rawAttributes['sort']).toBeDefined();
|
||||
expect(instance.get('sort')).toBe(1);
|
||||
expect(instance.get('sort')).toBe(parseSortValue(1));
|
||||
});
|
||||
|
||||
test('sortable=string', async () => {
|
||||
@ -82,7 +86,7 @@ describe('sort collections', () => {
|
||||
await db.sync();
|
||||
const instance = await model.create();
|
||||
expect(model.rawAttributes['order']).toBeDefined();
|
||||
expect(instance.get('order')).toBe(1);
|
||||
expect(instance.get('order')).toBe(parseSortValue(1));
|
||||
});
|
||||
|
||||
test('sortable=object', async () => {
|
||||
@ -102,10 +106,10 @@ describe('sort collections', () => {
|
||||
const t3 = await Test.model.create({ status: 'draft' });
|
||||
const t4 = await Test.model.create({ status: 'draft' });
|
||||
|
||||
expect(t1.get('sort')).toBe(1);
|
||||
expect(t2.get('sort')).toBe(2);
|
||||
expect(t3.get('sort')).toBe(1);
|
||||
expect(t4.get('sort')).toBe(2);
|
||||
expect(t1.get('sort')).toBe(parseSortValue(1));
|
||||
expect(t2.get('sort')).toBe(parseSortValue(2));
|
||||
expect(t3.get('sort')).toBe(parseSortValue(1));
|
||||
expect(t4.get('sort')).toBe(parseSortValue(2));
|
||||
});
|
||||
|
||||
test('forward insert', async () => {
|
||||
@ -133,11 +137,11 @@ describe('sort collections', () => {
|
||||
});
|
||||
|
||||
expect(results).toEqual([
|
||||
{ title: 't1', sort: 1 },
|
||||
{ title: 't3', sort: 2 },
|
||||
{ title: 't4', sort: 3 },
|
||||
{ title: 't2', sort: 4 },
|
||||
{ title: 't5', sort: 5 },
|
||||
{ title: 't1', sort: parseSortValue(1) },
|
||||
{ title: 't3', sort: parseSortValue(2) },
|
||||
{ title: 't4', sort: parseSortValue(3) },
|
||||
{ title: 't2', sort: parseSortValue(4) },
|
||||
{ title: 't5', sort: parseSortValue(5) },
|
||||
]);
|
||||
});
|
||||
|
||||
@ -166,11 +170,11 @@ describe('sort collections', () => {
|
||||
});
|
||||
|
||||
expect(results).toEqual([
|
||||
{ title: 't1', sort: 1 },
|
||||
{ title: 't4', sort: 2 },
|
||||
{ title: 't2', sort: 3 },
|
||||
{ title: 't3', sort: 4 },
|
||||
{ title: 't5', sort: 5 },
|
||||
{ title: 't1', sort: parseSortValue(1) },
|
||||
{ title: 't4', sort: parseSortValue(2) },
|
||||
{ title: 't2', sort: parseSortValue(3) },
|
||||
{ title: 't3', sort: parseSortValue(4) },
|
||||
{ title: 't5', sort: parseSortValue(5) },
|
||||
]);
|
||||
});
|
||||
});
|
||||
@ -245,11 +249,11 @@ describe('sort collections', () => {
|
||||
});
|
||||
|
||||
expect(results).toEqual([
|
||||
{ title: 's1:t1', sort: 1 },
|
||||
{ title: 's1:t3', sort: 2 },
|
||||
{ title: 's1:t4', sort: 3 },
|
||||
{ title: 's1:t2', sort: 4 },
|
||||
{ title: 's1:t5', sort: 5 },
|
||||
{ title: 's1:t1', sort: parseSortValue(1) },
|
||||
{ title: 's1:t3', sort: parseSortValue(2) },
|
||||
{ title: 's1:t4', sort: parseSortValue(3) },
|
||||
{ title: 's1:t2', sort: parseSortValue(4) },
|
||||
{ title: 's1:t5', sort: parseSortValue(5) },
|
||||
]);
|
||||
|
||||
const s2results = (
|
||||
@ -264,11 +268,11 @@ describe('sort collections', () => {
|
||||
});
|
||||
|
||||
expect(s2results).toEqual([
|
||||
{ title: 's2:t1', sort: 1 },
|
||||
{ title: 's2:t2', sort: 2 },
|
||||
{ title: 's2:t3', sort: 3 },
|
||||
{ title: 's2:t4', sort: 4 },
|
||||
{ title: 's2:t5', sort: 5 },
|
||||
{ title: 's2:t1', sort: parseSortValue(1) },
|
||||
{ title: 's2:t2', sort: parseSortValue(2) },
|
||||
{ title: 's2:t3', sort: parseSortValue(3) },
|
||||
{ title: 's2:t4', sort: parseSortValue(4) },
|
||||
{ title: 's2:t5', sort: parseSortValue(5) },
|
||||
]);
|
||||
});
|
||||
|
||||
@ -319,12 +323,12 @@ describe('sort collections', () => {
|
||||
});
|
||||
|
||||
expect(results).toEqual([
|
||||
{ title: 's2:t1', sort: 1 },
|
||||
{ title: 's2:t2', sort: 2 },
|
||||
{ title: 's1:t1', sort: 3 },
|
||||
{ title: 's2:t3', sort: 4 },
|
||||
{ title: 's2:t4', sort: 5 },
|
||||
{ title: 's2:t5', sort: 6 },
|
||||
{ title: 's2:t1', sort: parseSortValue(1) },
|
||||
{ title: 's2:t2', sort: parseSortValue(2) },
|
||||
{ title: 's1:t1', sort: parseSortValue(3) },
|
||||
{ title: 's2:t3', sort: parseSortValue(4) },
|
||||
{ title: 's2:t4', sort: parseSortValue(5) },
|
||||
{ title: 's2:t5', sort: parseSortValue(6) },
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
@ -48,6 +48,10 @@ describe('sort field', () => {
|
||||
await app.destroy();
|
||||
});
|
||||
|
||||
function parseSortValue(value) {
|
||||
return db.options.dialect === 'mssql' ? value.toString() : value;
|
||||
}
|
||||
|
||||
describe('main data source', () => {
|
||||
it('should init with camelCase scope key', async () => {
|
||||
const Test = db.collection({
|
||||
@ -213,9 +217,9 @@ describe('sort field', () => {
|
||||
|
||||
const records = await Test.repository.find({});
|
||||
const r3 = records.find((r) => r.get('name') === 'r3');
|
||||
expect(r3.get('sort')).toBe(2);
|
||||
expect(r3.get('sort')).toBe(parseSortValue(2));
|
||||
const r5 = records.find((r) => r.get('name') === 'r5');
|
||||
expect(r5.get('sort')).toBe(1);
|
||||
expect(r5.get('sort')).toBe(parseSortValue(1));
|
||||
});
|
||||
|
||||
it('should init sorted value by createdAt when primaryKey not exists', async () => {
|
||||
@ -249,11 +253,11 @@ describe('sort field', () => {
|
||||
await db.sync();
|
||||
|
||||
const test1 = await Test.model.create<any>();
|
||||
expect(test1.sort).toBe(1);
|
||||
expect(test1.sort).toBe(parseSortValue(1));
|
||||
const test2 = await Test.model.create<any>();
|
||||
expect(test2.sort).toBe(2);
|
||||
expect(test2.sort).toBe(parseSortValue(2));
|
||||
const test3 = await Test.model.create<any>();
|
||||
expect(test3.sort).toBe(3);
|
||||
expect(test3.sort).toBe(parseSortValue(3));
|
||||
});
|
||||
|
||||
it('should init sort value on data already exits', async () => {
|
||||
@ -292,7 +296,9 @@ describe('sort field', () => {
|
||||
const items = await db.getRepository('tests').find({
|
||||
order: ['id'],
|
||||
});
|
||||
expect(items.map((item) => item.get('sort'))).toEqual([1, 2, 3]);
|
||||
expect(items[0].get('sort')).toBe(parseSortValue(1));
|
||||
expect(items[1].get('sort')).toBe(parseSortValue(2));
|
||||
expect(items[2].get('sort')).toBe(parseSortValue(3));
|
||||
});
|
||||
|
||||
test.skip('simultaneously create ', async () => {
|
||||
@ -311,7 +317,7 @@ describe('sort field', () => {
|
||||
await Promise.all(promise);
|
||||
const tests = await Test.model.findAll();
|
||||
const sortValues = tests.map((t) => t.get('sort')).sort();
|
||||
expect(sortValues).toEqual([1, 2, 3]);
|
||||
expect(sortValues).toEqual(db.options.dialect === 'mssql' ? ['1', '2', '3'] : [1, 2, 3]);
|
||||
});
|
||||
|
||||
it('skip if sort value not empty', async () => {
|
||||
@ -321,11 +327,11 @@ describe('sort field', () => {
|
||||
});
|
||||
await db.sync();
|
||||
const test1 = await Test.model.create<any>({ sort: 3 });
|
||||
expect(test1.sort).toBe(3);
|
||||
expect(test1.sort).toBe(parseSortValue(3));
|
||||
const test2 = await Test.model.create<any>();
|
||||
expect(test2.sort).toBe(4);
|
||||
expect(test2.sort).toBe(parseSortValue(4));
|
||||
const test3 = await Test.model.create<any>();
|
||||
expect(test3.sort).toBe(5);
|
||||
expect(test3.sort).toBe(parseSortValue(5));
|
||||
});
|
||||
|
||||
it('scopeKey', async () => {
|
||||
@ -343,16 +349,16 @@ describe('sort field', () => {
|
||||
const t3 = await Test.model.create({ status: 'draft' });
|
||||
const t4 = await Test.model.create({ status: 'draft' });
|
||||
|
||||
expect(t1.get('sort')).toBe(1);
|
||||
expect(t2.get('sort')).toBe(2);
|
||||
expect(t3.get('sort')).toBe(1);
|
||||
expect(t4.get('sort')).toBe(2);
|
||||
expect(t1.get('sort')).toBe(parseSortValue(1));
|
||||
expect(t2.get('sort')).toBe(parseSortValue(2));
|
||||
expect(t3.get('sort')).toBe(parseSortValue(1));
|
||||
expect(t4.get('sort')).toBe(parseSortValue(2));
|
||||
|
||||
t1.set('status', 'draft');
|
||||
await t1.save();
|
||||
|
||||
await t1.reload();
|
||||
expect(t1.get('sort')).toBe(3);
|
||||
expect(t1.get('sort')).toBe(parseSortValue(3));
|
||||
});
|
||||
});
|
||||
|
||||
@ -374,8 +380,8 @@ describe('sort field', () => {
|
||||
const p2 = await anotherDB.getRepository('posts').create({
|
||||
values: { title: 'p2' },
|
||||
});
|
||||
expect(p1.sort).toBe(1);
|
||||
expect(p2.sort).toBe(2);
|
||||
expect(p1.sort).toBe(parseSortValue(1));
|
||||
expect(p2.sort).toBe(parseSortValue(2));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -132,8 +132,8 @@ export class SortableCollection {
|
||||
async sameScopeMove(sourceInstance: Model, targetInstance: Model, options: MoveOptions) {
|
||||
const fieldName = this.field.get('name');
|
||||
|
||||
const sourceSort = sourceInstance.get(fieldName);
|
||||
let targetSort = targetInstance.get(fieldName);
|
||||
const sourceSort = Number(sourceInstance.get(fieldName));
|
||||
let targetSort = Number(targetInstance.get(fieldName));
|
||||
|
||||
if (options.insertAfter) {
|
||||
targetSort = targetSort + 1;
|
||||
|
@ -171,6 +171,25 @@ export class SortField extends Field {
|
||||
${whereClause}
|
||||
) AS ordered_table ON ${this.collection.quotedTableName()}.${quotedOrderField} = ordered_table.${quotedOrderField}
|
||||
SET ${this.collection.quotedTableName()}.${sortColumnName} = ordered_table.new_sequence_number;
|
||||
`;
|
||||
} else if (this.collection.db.inDialect('mssql')) {
|
||||
// TODO: This MSSQL support is intended for external data sources
|
||||
// Since the core database doesn't support MSSQL, this logic needs to be implemented through an extension mechanism
|
||||
// Potential solutions:
|
||||
// 1. Abstract database dialect-specific logic into separate modules
|
||||
// 2. Consider implementing a dialect adapter pattern for better extensibility
|
||||
sql = `
|
||||
WITH ordered_table AS (
|
||||
SELECT *, ROW_NUMBER() OVER (${
|
||||
scopeKey ? `PARTITION BY ${queryInterface.quoteIdentifier(scopeKey)}` : ''
|
||||
} ORDER BY ${quotedOrderField}) AS new_sequence_number
|
||||
FROM ${this.collection.quotedTableName()}
|
||||
${whereClause}
|
||||
)
|
||||
UPDATE t
|
||||
SET ${sortColumnName} = ot.new_sequence_number
|
||||
FROM ${this.collection.quotedTableName()} t
|
||||
INNER JOIN ordered_table ot ON t.${quotedOrderField} = ot.${quotedOrderField};
|
||||
`;
|
||||
}
|
||||
await this.collection.db.sequelize.query(sql, {
|
||||
|
Loading…
x
Reference in New Issue
Block a user