feat: server hooks model

This commit is contained in:
Chareice 2022-02-08 20:58:57 +08:00 committed by chenos
parent af02e80b6f
commit 3e1cad643b
7 changed files with 157 additions and 38 deletions

View File

@ -214,18 +214,20 @@ export class Repository<TModelAttributes extends {} = any, TCreationAttributes e
};
if (opts.include && opts.include.length > 0) {
// @ts-ignore
const primaryKeyField = model.primaryKeyField || model.primaryKeyAttribute;
const ids = (
await model.findAll({
...opts,
includeIgnoreAttributes: false,
attributes: [model.primaryKeyAttribute],
group: `${model.name}.${model.primaryKeyAttribute}`,
attributes: [primaryKeyField],
group: `${model.name}.${primaryKeyField}`,
transaction,
})
).map((row) => row.get(model.primaryKeyAttribute));
).map((row) => row.get(primaryKeyField));
const where = {
[model.primaryKeyAttribute]: {
[primaryKeyField]: {
[Op.in]: ids,
},
};
@ -415,7 +417,7 @@ export class Repository<TModelAttributes extends {} = any, TCreationAttributes e
}
return await this.destroy({
context: options.context,
...lodash.omit(options, 'filter'),
filterByTk: pks,
transaction,
});

View File

@ -51,7 +51,7 @@ export class CollectionModel extends MagicAttributeModel {
async migrate(options?: SyncOptions & Transactionable) {
const collection = await this.load({
transaction: options.transaction,
transaction: options?.transaction,
});
await collection.sync({
force: false,

View File

@ -1,11 +1,44 @@
import { mockServer, MockServer } from '@nocobase/test';
import { Database } from '@nocobase/database';
import PluginUiSchema, { UiSchemaRepository } from '@nocobase/plugin-ui-schema-storage';
import PluginCollectionManager from '@nocobase/plugin-collection-manager';
describe('server hooks', () => {
let app: MockServer;
let db: Database;
let uiSchemaRepository: UiSchemaRepository;
let uiSchemaPlugin: PluginUiSchema;
const schema = {
'x-uid': 'root',
name: 'root',
properties: {
row: {
'x-uid': 'table',
'x-component': 'Table',
'x-collection': 'posts',
'x-server-hooks': {
afterDestroyCollection: ['aaa'],
},
properties: {
col1: {
'x-uid': 'col1',
'x-component': 'Col',
properties: {
field1: {
'x-uid': 'field1',
'x-component': 'Input',
'x-collection-field': 'posts.title',
'x-server-hooks': {
afterDestroyField: ['onFieldDestroy'],
},
},
},
},
},
},
},
};
afterEach(async () => {
await app.destroy();
@ -20,40 +53,17 @@ describe('server hooks', () => {
await app.cleanDb();
app.plugin(PluginUiSchema);
app.plugin(PluginCollectionManager);
await app.loadAndInstall();
uiSchemaRepository = db.getRepository('ui_schemas');
await uiSchemaRepository.insert(schema);
uiSchemaPlugin = app.getPlugin<PluginUiSchema>('PluginUiSchema');
});
it('should save uiSchemaAttrs', async () => {
const schema = {
name: 'row',
'x-uid': 'table',
'x-component': 'Table',
'x-collection': 'posts',
'x-server-hooks': {
afterDestroyCollection: ['aaa'],
},
properties: {
col1: {
'x-uid': 'col1',
'x-component': 'Col',
properties: {
field1: {
'x-uid': 'field1',
'x-component': 'Input',
'x-collection-field': 'posts.title',
'x-server-hooks': {
afterDestroyField: ['bbb'],
},
},
},
},
},
};
await uiSchemaRepository.insert(schema);
const node = await uiSchemaRepository.findOne({
filter: {
uid: 'table',
@ -74,4 +84,38 @@ describe('server hooks', () => {
const nodeFieldAttr = await nodeField.getAttrs();
expect(nodeFieldAttr.get('collectionPath')).toEqual('posts.title');
});
it('should call server hooks', async () => {
const PostModel = await db.getRepository('collections').create({
values: {
name: 'posts',
},
});
const fieldModel = await db.getRepository('fields').create({
values: {
name: 'title',
type: 'string',
collectionName: 'posts',
},
});
// @ts-ignore
await PostModel.migrate();
const serverHooks = uiSchemaPlugin.serverHooks;
const hookFn = jest.fn();
serverHooks.register('afterDestroyField', 'onFieldDestroy', hookFn);
// destroy a field
await db.getRepository('fields').destroy({
filter: {
name: 'title',
},
individualHooks: true,
});
expect(hookFn).toHaveBeenCalled();
});
});

View File

@ -6,7 +6,7 @@ export default {
autoGenId: false,
timestamps: false,
repository: 'UiSchemaRepository',
model: 'MagicAttributeModel',
model: 'UiSchemaModel',
magicAttribute: 'schema',
fields: [
{

View File

@ -1,5 +1,11 @@
import { Model } from '@nocobase/database';
import { MagicAttributeModel } from '@nocobase/database';
import { HookType } from './server-hooks';
export class UiSchemaModel extends Model {
class UiSchemaModel extends MagicAttributeModel {
getListenServerHooks(type: HookType) {
const hooks = this.get('x-server-hooks');
return hooks[type] || [];
}
}
export { UiSchemaModel };

View File

@ -0,0 +1,57 @@
import { Database } from '@nocobase/database';
import { UiSchemaModel } from '../model';
export type HookType = 'afterDestroyField';
export class ServerHooks {
hooks = new Map<HookType, Map<string, any>>();
constructor(protected db: Database) {
this.listen();
}
listen() {
this.db.on('fields.afterDestroy', async (model, options) => {
await this.afterFieldDestroy(model, options);
});
}
protected async afterFieldDestroy(fieldModel, options) {
const { transaction } = options;
const collectionPath = `${fieldModel.get('collectionName')}.${fieldModel.get('name')}`;
const listenSchemas = (await this.db.getRepository('ui_schemas').find({
filter: {
'attrs.collectionPath': collectionPath,
},
transaction,
})) as UiSchemaModel[];
for (const listenSchema of listenSchemas) {
const listenHooksName = listenSchema.getListenServerHooks('afterDestroyField');
for (const listenHookName of listenHooksName) {
const hookFunc = this.hooks.get('afterDestroyField')?.get(listenHookName);
await hookFunc({
model: listenSchema,
transaction,
});
}
}
}
/**
* register a server hook function
* @param type type of server hook
* @param name name of server hook
* @param hookFunc server hook function
*/
register(type: HookType, name: string, hookFunc: any) {
if (!this.hooks.has(type)) {
this.hooks.set(type, new Map());
}
const hookTypeMap = this.hooks.get(type);
hookTypeMap.set(name, hookFunc);
}
}

View File

@ -3,8 +3,12 @@ import { Plugin } from '@nocobase/server';
import path from 'path';
import { uiSchemaActions } from './actions/ui-schema-action';
import UiSchemaRepository from './repository';
import { ServerHooks } from './server-hooks';
import { UiSchemaModel } from './model';
export default class PluginUiSchema extends Plugin {
serverHooks: ServerHooks;
registerRepository() {
this.app.db.registerRepositories({
UiSchemaRepository,
@ -14,10 +18,16 @@ export default class PluginUiSchema extends Plugin {
async beforeLoad() {
const db = this.app.db;
this.app.db.registerModels({ MagicAttributeModel });
this.serverHooks = new ServerHooks(db);
this.app.db.registerModels({ MagicAttributeModel, UiSchemaModel });
this.registerRepository();
db.on('ui_schemas.afterDefine', (model) => {
model.primaryKeyAttribute = 'uid';
});
db.on('ui_schemas.beforeCreate', function setUid(model) {
model.set('uid', model.get('x-uid'));
});