fix(plugin-field-sort): generate unique sort values in bulk create (#9684)

This commit is contained in:
YANG QIA
2026-06-07 12:33:54 +08:00
committed by GitHub
parent eb5835cd5d
commit e2f2078cbb
2 changed files with 89 additions and 23 deletions
@@ -2299,6 +2299,63 @@ describe('basic importer', () => {
expect(users[1].get('email')).toBe('test2@test.com');
});
it('should generate different sort values for imported rows', async () => {
await app.destroy();
app = await createMockServer({
plugins: ['field-sort', 'data-source-main', 'error-handler'],
});
const Task = app.db.collection({
name: 'tasks',
fields: [
{
type: 'string',
name: 'name',
},
{
type: 'sort',
name: 'sort',
},
],
});
await app.db.sync();
const columns = [
{
dataIndex: ['name'],
defaultTitle: 'Name',
},
];
const templateCreator = new TemplateCreator({
collection: Task,
columns,
});
const template = (await templateCreator.run({ returnXLSXWorkbook: true })) as XLSX.WorkBook;
const worksheet = template.Sheets[template.SheetNames[0]];
XLSX.utils.sheet_add_aoa(worksheet, [['task1'], ['task2'], ['task3']], {
origin: 'A2',
});
const importer = new XlsxImporter({
collectionManager: app.mainDataSource.collectionManager,
collection: Task,
columns,
workbook: template,
});
await importer.run();
const tasks = await Task.repository.find({
sort: ['id'],
});
expect(tasks.map((task) => task.get('sort'))).toEqual([1, 2, 3]);
});
describe('template creator', () => {
it('should create template with explain and field descriptions', async () => {
const User = app.db.collection({
@@ -24,33 +24,42 @@ export class SortField extends Field {
const { model } = this.context.collection;
instances = Array.isArray(instances) ? instances : [instances];
for (const instance of instances) {
if (from == 'create' && isNumber(instance.get(name))) {
continue;
}
if (isNumber(instance.get(name)) && instance._previousDataValues[scopeKey] == instance[scopeKey]) {
continue;
}
await (<typeof SortField>this.constructor).lockManager.runExclusive(
this.context.collection.name,
async () => {
const maxCache = new Map<string, number>();
const where = {};
for (const instance of instances) {
if (from == 'create' && isNumber(instance.get(name))) {
continue;
}
if (isNumber(instance.get(name)) && instance._previousDataValues[scopeKey] == instance[scopeKey]) {
continue;
}
if (scopeKey) {
const value = instance.get(scopeKey);
if (value !== undefined && value !== null) {
where[scopeKey] = value;
}
}
const where = {};
let cacheKey = '__default__';
await (<typeof SortField>this.constructor).lockManager.runExclusive(
this.context.collection.name,
async () => {
const max = await model.max<number, any>(name, { ...options, where });
const newValue = (max || 0) + 1;
if (scopeKey) {
const value = instance.get(scopeKey);
if (value !== undefined && value !== null) {
where[scopeKey] = value;
cacheKey = `${typeof value}:${String(value)}`;
}
}
if (!maxCache.has(cacheKey)) {
const max = await model.max<number, any>(name, { ...options, where });
maxCache.set(cacheKey, max || 0);
}
const newValue = (maxCache.get(cacheKey) ?? 0) + 1;
maxCache.set(cacheKey, newValue);
instance.set(name, newValue);
},
2000,
);
}
}
},
2000,
);
};
onScopeChange = async (instance, options) => {