mirror of
https://github.com/nocobase/nocobase.git
synced 2026-09-24 16:02:20 +08:00
feat(plugin-field-sequence): auto update sequence collection`s current base on business collections (#8063)
* feat(plugin-field-sequence): auto update sequence collection`s current base on business collections * refactor(plugin-field-sequence): invoke collection load method instead of trigger beforeStart event * chore(plugin-field-sequence): change command refresh-data`s name to repair * refactor(plugin-field-sequence): add overwrite options in SequenceField`s update for repair event
This commit is contained in:
@@ -23,6 +23,7 @@ import start from './start';
|
||||
import stop from './stop';
|
||||
import upgrade from './upgrade';
|
||||
import consoleCommand from './console';
|
||||
import repair from './repair';
|
||||
|
||||
export function registerCli(app: Application) {
|
||||
consoleCommand(app);
|
||||
@@ -39,6 +40,7 @@ export function registerCli(app: Application) {
|
||||
destroy(app);
|
||||
start(app);
|
||||
refresh(app);
|
||||
repair(app);
|
||||
|
||||
// development only with @nocobase/cli
|
||||
app.command('build').argument('[packages...]');
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* This file is part of the NocoBase (R) project.
|
||||
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
||||
* Authors: NocoBase Team.
|
||||
*
|
||||
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
||||
* For more information, please refer to: https://www.nocobase.com/agreement.
|
||||
*/
|
||||
|
||||
import Application from '../application';
|
||||
|
||||
export default (app: Application) => {
|
||||
app
|
||||
.command('repair')
|
||||
.auth()
|
||||
.preload()
|
||||
.action(async (options) => {
|
||||
app.log.info('start repair data...');
|
||||
const Collection = app.db.getCollection('collections');
|
||||
if (Collection) {
|
||||
// @ts-ignore
|
||||
await Collection.repository.setApp(app);
|
||||
// @ts-ignore
|
||||
await Collection.repository.load();
|
||||
}
|
||||
await app.emitAsync('repair', options);
|
||||
});
|
||||
};
|
||||
@@ -14,6 +14,8 @@ import { promisify } from 'util';
|
||||
import { Plugin } from '@nocobase/server';
|
||||
import { Registry } from '@nocobase/utils';
|
||||
import { Pattern, SequenceField } from './fields/sequence-field';
|
||||
import _ from 'lodash';
|
||||
import { Field, Model } from '@nocobase/database';
|
||||
|
||||
const asyncRandomInt = promisify(randomInt);
|
||||
|
||||
@@ -108,6 +110,55 @@ export default class PluginFieldSequenceServer extends Plugin {
|
||||
transaction,
|
||||
});
|
||||
});
|
||||
|
||||
app.on('repair', async () => {
|
||||
app.log.info(`app ${app.name} plugin ${this.name} start repair data...`);
|
||||
const sequencesModel = app.db.getModel('sequences');
|
||||
const allSequences = await sequencesModel.findAll();
|
||||
const groupedSequences = _.groupBy(allSequences, 'collection');
|
||||
|
||||
const tasks: (() => Promise<void>)[] = [];
|
||||
for (const [collectionName, sequencesList] of Object.entries(groupedSequences)) {
|
||||
tasks.push(async () => {
|
||||
const collection = app.db.getCollection(collectionName);
|
||||
const fields: Field[] = collection.getFields();
|
||||
const fieldMap = Object.fromEntries<Field>(fields.map((field) => [field.name, field]));
|
||||
|
||||
const [autoIncrementField] = fields.filter((field) => field.options.primaryKey && field.type === 'bigInt');
|
||||
const [createAtField] = fields.filter((field) => field.options.interface === 'createdAt');
|
||||
if (!autoIncrementField && !createAtField) {
|
||||
app.log.warn(
|
||||
`Collection [${collection}] does not have autoIncrement or createdAt fields. Skipping sequences refresh`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const [record] = await collection.model.findAll({
|
||||
order: [[autoIncrementField?.name ?? createAtField?.name, 'DESC']],
|
||||
limit: 1,
|
||||
});
|
||||
if (!record) {
|
||||
app.log.warn(`Collection [${collection}] has no records. Skipping sequences repair`);
|
||||
return;
|
||||
}
|
||||
|
||||
const sequencesFieldSet = _.uniq<string>(sequencesList.map(({ field }) => field));
|
||||
for (const sequencesField of sequencesFieldSet) {
|
||||
const field = fieldMap[sequencesField] as SequenceField;
|
||||
if (!field) {
|
||||
app.log.warn(
|
||||
`Collection [${collection}] field [${sequencesField}] definition not found. Skipping sequences repair`,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
await field.update(record, { overwrite: true });
|
||||
}
|
||||
});
|
||||
}
|
||||
await Promise.all(tasks.map((t) => t()));
|
||||
app.log.info(`app ${app.name} plugin ${this.name} finish repair data`);
|
||||
});
|
||||
}
|
||||
|
||||
async install() {}
|
||||
|
||||
+1137
File diff suppressed because it is too large
Load Diff
+11
-2
@@ -44,7 +44,7 @@ export interface Pattern {
|
||||
instance: Model,
|
||||
value: string,
|
||||
options,
|
||||
transactionable: Transactionable,
|
||||
transactionable: Transactionable & { overwrite?: boolean },
|
||||
): Promise<void>;
|
||||
}
|
||||
|
||||
@@ -235,7 +235,7 @@ sequencePatterns.register('integer', {
|
||||
await lastSeq.save({ transaction });
|
||||
},
|
||||
|
||||
async update(instance, value, options, { transaction }) {
|
||||
async update(instance, value, options, { transaction, overwrite }) {
|
||||
const recordTime = <Date>instance.get('createdAt') ?? new Date();
|
||||
const { digits = 1, start = 0, base = 10, cycle, key } = options;
|
||||
const SeqRepo = this.database.getRepository('sequences');
|
||||
@@ -269,6 +269,15 @@ sequencePatterns.register('integer', {
|
||||
{ transaction },
|
||||
);
|
||||
}
|
||||
if (overwrite === true) {
|
||||
return lastSeq.update(
|
||||
{
|
||||
current,
|
||||
lastGeneratedAt: recordTime,
|
||||
},
|
||||
{ transaction },
|
||||
);
|
||||
}
|
||||
|
||||
if (cycle) {
|
||||
const interval = parser.parseExpression(cycle, { currentDate: <Date>lastSeq.get('lastGeneratedAt') });
|
||||
|
||||
Reference in New Issue
Block a user