Backfill position when not input (#5696)
- refactor record position factory and record position query factory - override position if not present during createMany To avoid overriding the same positions for all data in createMany, the logic is: - if inserted last, use last position + arg index + 1 - if inserted first, use first position - arg index - 1
This commit is contained in:
@ -16,74 +16,66 @@ describe('RecordPositionQueryFactory', () => {
|
||||
});
|
||||
|
||||
describe('create', () => {
|
||||
describe('createForGet', () => {
|
||||
it('should return a string with the position when positionValue is first', async () => {
|
||||
const positionValue = 'first';
|
||||
|
||||
const result = await factory.create(
|
||||
RecordPositionQueryType.GET,
|
||||
positionValue,
|
||||
objectMetadataItem,
|
||||
dataSourceSchema,
|
||||
);
|
||||
|
||||
expect(result).toEqual(
|
||||
`SELECT position FROM workspace_test."company"
|
||||
WHERE "position" IS NOT NULL ORDER BY "position" ASC LIMIT 1`,
|
||||
);
|
||||
});
|
||||
|
||||
it('should return a string with the position when positionValue is last', async () => {
|
||||
const positionValue = 'last';
|
||||
|
||||
const result = await factory.create(
|
||||
RecordPositionQueryType.GET,
|
||||
positionValue,
|
||||
objectMetadataItem,
|
||||
dataSourceSchema,
|
||||
);
|
||||
|
||||
expect(result).toEqual(
|
||||
`SELECT position FROM workspace_test."company"
|
||||
WHERE "position" IS NOT NULL ORDER BY "position" DESC LIMIT 1`,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('should return a string with the position when positionValue is a number', async () => {
|
||||
it('should return query and params for FIND_BY_POSITION', async () => {
|
||||
const positionValue = 1;
|
||||
|
||||
try {
|
||||
await factory.create(
|
||||
RecordPositionQueryType.GET,
|
||||
positionValue,
|
||||
objectMetadataItem,
|
||||
dataSourceSchema,
|
||||
);
|
||||
} catch (error) {
|
||||
expect(error.message).toEqual(
|
||||
'RecordPositionQueryType.GET requires positionValue to be a number',
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('createForUpdate', () => {
|
||||
it('should return a string when RecordPositionQueryType is UPDATE', async () => {
|
||||
const positionValue = 1;
|
||||
|
||||
const result = await factory.create(
|
||||
RecordPositionQueryType.UPDATE,
|
||||
positionValue,
|
||||
const queryType = RecordPositionQueryType.FIND_BY_POSITION;
|
||||
const [query, params] = await factory.create(
|
||||
{ positionValue, recordPositionQueryType: queryType },
|
||||
objectMetadataItem,
|
||||
dataSourceSchema,
|
||||
);
|
||||
|
||||
expect(result).toEqual(
|
||||
`UPDATE workspace_test."company"
|
||||
expect(query).toEqual(
|
||||
`SELECT position FROM ${dataSourceSchema}."${objectMetadataItem.nameSingular}"
|
||||
WHERE "position" = $1`,
|
||||
);
|
||||
expect(params).toEqual([positionValue]);
|
||||
});
|
||||
|
||||
it('should return query and params for FIND_MIN_POSITION', async () => {
|
||||
const queryType = RecordPositionQueryType.FIND_MIN_POSITION;
|
||||
const [query, params] = await factory.create(
|
||||
{ recordPositionQueryType: queryType },
|
||||
objectMetadataItem,
|
||||
dataSourceSchema,
|
||||
);
|
||||
|
||||
expect(query).toEqual(
|
||||
`SELECT MIN(position) as position FROM ${dataSourceSchema}."${objectMetadataItem.nameSingular}"`,
|
||||
);
|
||||
expect(params).toEqual([]);
|
||||
});
|
||||
|
||||
it('should return query and params for FIND_MAX_POSITION', async () => {
|
||||
const queryType = RecordPositionQueryType.FIND_MAX_POSITION;
|
||||
const [query, params] = await factory.create(
|
||||
{ recordPositionQueryType: queryType },
|
||||
objectMetadataItem,
|
||||
dataSourceSchema,
|
||||
);
|
||||
|
||||
expect(query).toEqual(
|
||||
`SELECT MAX(position) as position FROM ${dataSourceSchema}."${objectMetadataItem.nameSingular}"`,
|
||||
);
|
||||
expect(params).toEqual([]);
|
||||
});
|
||||
|
||||
it('should return query and params for UPDATE_POSITION', async () => {
|
||||
const positionValue = 1;
|
||||
const recordId = '1';
|
||||
const queryType = RecordPositionQueryType.UPDATE_POSITION;
|
||||
const [query, params] = await factory.create(
|
||||
{ positionValue, recordId, recordPositionQueryType: queryType },
|
||||
objectMetadataItem,
|
||||
dataSourceSchema,
|
||||
);
|
||||
|
||||
expect(query).toEqual(
|
||||
`UPDATE ${dataSourceSchema}."${objectMetadataItem.nameSingular}"
|
||||
SET "position" = $1
|
||||
WHERE "id" = $2`,
|
||||
);
|
||||
expect(params).toEqual([positionValue, recordId]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,54 +1,119 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { computeTableName } from 'src/engine/utils/compute-table-name.util';
|
||||
|
||||
export enum RecordPositionQueryType {
|
||||
GET = 'GET',
|
||||
UPDATE = 'UPDATE',
|
||||
FIND_MIN_POSITION = 'FIND_MIN_POSITION',
|
||||
FIND_MAX_POSITION = 'FIND_MAX_POSITION',
|
||||
FIND_BY_POSITION = 'FIND_BY_POSITION',
|
||||
UPDATE_POSITION = 'UPDATE_POSITION',
|
||||
}
|
||||
|
||||
type FindByPositionQueryArgs = {
|
||||
positionValue: number;
|
||||
recordPositionQueryType: RecordPositionQueryType.FIND_BY_POSITION;
|
||||
};
|
||||
|
||||
type FindMinPositionQueryArgs = {
|
||||
recordPositionQueryType: RecordPositionQueryType.FIND_MIN_POSITION;
|
||||
};
|
||||
|
||||
type FindMaxPositionQueryArgs = {
|
||||
recordPositionQueryType: RecordPositionQueryType.FIND_MAX_POSITION;
|
||||
};
|
||||
|
||||
type UpdatePositionQueryArgs = {
|
||||
recordId: string;
|
||||
positionValue: number;
|
||||
recordPositionQueryType: RecordPositionQueryType.UPDATE_POSITION;
|
||||
};
|
||||
|
||||
type RecordPositionQuery = string;
|
||||
|
||||
type RecordPositionQueryParams = any[];
|
||||
|
||||
export type RecordPositionQueryArgs =
|
||||
| FindByPositionQueryArgs
|
||||
| FindMinPositionQueryArgs
|
||||
| FindMaxPositionQueryArgs
|
||||
| UpdatePositionQueryArgs;
|
||||
|
||||
@Injectable()
|
||||
export class RecordPositionQueryFactory {
|
||||
async create(
|
||||
recordPositionQueryType: RecordPositionQueryType,
|
||||
positionValue: 'first' | 'last' | number,
|
||||
create(
|
||||
recordPositionQueryArgs: RecordPositionQueryArgs,
|
||||
objectMetadata: { isCustom: boolean; nameSingular: string },
|
||||
dataSourceSchema: string,
|
||||
): Promise<string> {
|
||||
const name =
|
||||
(objectMetadata.isCustom ? '_' : '') + objectMetadata.nameSingular;
|
||||
): [RecordPositionQuery, RecordPositionQueryParams] {
|
||||
const name = computeTableName(
|
||||
objectMetadata.nameSingular,
|
||||
objectMetadata.isCustom,
|
||||
);
|
||||
|
||||
switch (recordPositionQueryType) {
|
||||
case RecordPositionQueryType.GET:
|
||||
if (typeof positionValue === 'number') {
|
||||
throw new Error(
|
||||
'RecordPositionQueryType.GET requires positionValue to be a number',
|
||||
);
|
||||
}
|
||||
|
||||
return this.createForGet(positionValue, name, dataSourceSchema);
|
||||
case RecordPositionQueryType.UPDATE:
|
||||
return this.createForUpdate(name, dataSourceSchema);
|
||||
switch (recordPositionQueryArgs.recordPositionQueryType) {
|
||||
case RecordPositionQueryType.FIND_BY_POSITION:
|
||||
return this.buildFindByPositionQuery(
|
||||
recordPositionQueryArgs satisfies FindByPositionQueryArgs,
|
||||
name,
|
||||
dataSourceSchema,
|
||||
);
|
||||
case RecordPositionQueryType.FIND_MIN_POSITION:
|
||||
return this.buildFindMinPositionQuery(name, dataSourceSchema);
|
||||
case RecordPositionQueryType.FIND_MAX_POSITION:
|
||||
return this.buildFindMaxPositionQuery(name, dataSourceSchema);
|
||||
case RecordPositionQueryType.UPDATE_POSITION:
|
||||
return this.buildUpdatePositionQuery(
|
||||
recordPositionQueryArgs satisfies UpdatePositionQueryArgs,
|
||||
name,
|
||||
dataSourceSchema,
|
||||
);
|
||||
default:
|
||||
throw new Error('Invalid RecordPositionQueryType');
|
||||
}
|
||||
}
|
||||
|
||||
private async createForGet(
|
||||
positionValue: 'first' | 'last',
|
||||
private buildFindByPositionQuery(
|
||||
{ positionValue }: FindByPositionQueryArgs,
|
||||
name: string,
|
||||
dataSourceSchema: string,
|
||||
): Promise<string> {
|
||||
const orderByDirection = positionValue === 'first' ? 'ASC' : 'DESC';
|
||||
|
||||
return `SELECT position FROM ${dataSourceSchema}."${name}"
|
||||
WHERE "position" IS NOT NULL ORDER BY "position" ${orderByDirection} LIMIT 1`;
|
||||
): [RecordPositionQuery, RecordPositionQueryParams] {
|
||||
return [
|
||||
`SELECT position FROM ${dataSourceSchema}."${name}"
|
||||
WHERE "position" = $1`,
|
||||
[positionValue],
|
||||
];
|
||||
}
|
||||
|
||||
private async createForUpdate(
|
||||
private buildFindMaxPositionQuery(
|
||||
name: string,
|
||||
dataSourceSchema: string,
|
||||
): Promise<string> {
|
||||
return `UPDATE ${dataSourceSchema}."${name}"
|
||||
): [RecordPositionQuery, RecordPositionQueryParams] {
|
||||
return [
|
||||
`SELECT MAX(position) as position FROM ${dataSourceSchema}."${name}"`,
|
||||
[],
|
||||
];
|
||||
}
|
||||
|
||||
private buildFindMinPositionQuery(
|
||||
name: string,
|
||||
dataSourceSchema: string,
|
||||
): [RecordPositionQuery, RecordPositionQueryParams] {
|
||||
return [
|
||||
`SELECT MIN(position) as position FROM ${dataSourceSchema}."${name}"`,
|
||||
[],
|
||||
];
|
||||
}
|
||||
|
||||
private buildUpdatePositionQuery(
|
||||
{ recordId, positionValue }: UpdatePositionQueryArgs,
|
||||
name: string,
|
||||
dataSourceSchema: string,
|
||||
): [RecordPositionQuery, RecordPositionQueryParams] {
|
||||
return [
|
||||
`UPDATE ${dataSourceSchema}."${name}"
|
||||
SET "position" = $1
|
||||
WHERE "id" = $2`;
|
||||
WHERE "id" = $2`,
|
||||
[positionValue, recordId],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user