feat: server hooks model
This commit is contained in:
parent
af02e80b6f
commit
3e1cad643b
@ -214,18 +214,20 @@ export class Repository<TModelAttributes extends {} = any, TCreationAttributes e
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (opts.include && opts.include.length > 0) {
|
if (opts.include && opts.include.length > 0) {
|
||||||
|
// @ts-ignore
|
||||||
|
const primaryKeyField = model.primaryKeyField || model.primaryKeyAttribute;
|
||||||
const ids = (
|
const ids = (
|
||||||
await model.findAll({
|
await model.findAll({
|
||||||
...opts,
|
...opts,
|
||||||
includeIgnoreAttributes: false,
|
includeIgnoreAttributes: false,
|
||||||
attributes: [model.primaryKeyAttribute],
|
attributes: [primaryKeyField],
|
||||||
group: `${model.name}.${model.primaryKeyAttribute}`,
|
group: `${model.name}.${primaryKeyField}`,
|
||||||
transaction,
|
transaction,
|
||||||
})
|
})
|
||||||
).map((row) => row.get(model.primaryKeyAttribute));
|
).map((row) => row.get(primaryKeyField));
|
||||||
|
|
||||||
const where = {
|
const where = {
|
||||||
[model.primaryKeyAttribute]: {
|
[primaryKeyField]: {
|
||||||
[Op.in]: ids,
|
[Op.in]: ids,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -415,7 +417,7 @@ export class Repository<TModelAttributes extends {} = any, TCreationAttributes e
|
|||||||
}
|
}
|
||||||
|
|
||||||
return await this.destroy({
|
return await this.destroy({
|
||||||
context: options.context,
|
...lodash.omit(options, 'filter'),
|
||||||
filterByTk: pks,
|
filterByTk: pks,
|
||||||
transaction,
|
transaction,
|
||||||
});
|
});
|
||||||
|
@ -51,7 +51,7 @@ export class CollectionModel extends MagicAttributeModel {
|
|||||||
|
|
||||||
async migrate(options?: SyncOptions & Transactionable) {
|
async migrate(options?: SyncOptions & Transactionable) {
|
||||||
const collection = await this.load({
|
const collection = await this.load({
|
||||||
transaction: options.transaction,
|
transaction: options?.transaction,
|
||||||
});
|
});
|
||||||
await collection.sync({
|
await collection.sync({
|
||||||
force: false,
|
force: false,
|
||||||
|
@ -1,11 +1,44 @@
|
|||||||
import { mockServer, MockServer } from '@nocobase/test';
|
import { mockServer, MockServer } from '@nocobase/test';
|
||||||
import { Database } from '@nocobase/database';
|
import { Database } from '@nocobase/database';
|
||||||
import PluginUiSchema, { UiSchemaRepository } from '@nocobase/plugin-ui-schema-storage';
|
import PluginUiSchema, { UiSchemaRepository } from '@nocobase/plugin-ui-schema-storage';
|
||||||
|
import PluginCollectionManager from '@nocobase/plugin-collection-manager';
|
||||||
|
|
||||||
describe('server hooks', () => {
|
describe('server hooks', () => {
|
||||||
let app: MockServer;
|
let app: MockServer;
|
||||||
let db: Database;
|
let db: Database;
|
||||||
let uiSchemaRepository: UiSchemaRepository;
|
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 () => {
|
afterEach(async () => {
|
||||||
await app.destroy();
|
await app.destroy();
|
||||||
@ -20,40 +53,17 @@ describe('server hooks', () => {
|
|||||||
|
|
||||||
await app.cleanDb();
|
await app.cleanDb();
|
||||||
app.plugin(PluginUiSchema);
|
app.plugin(PluginUiSchema);
|
||||||
|
app.plugin(PluginCollectionManager);
|
||||||
|
|
||||||
await app.loadAndInstall();
|
await app.loadAndInstall();
|
||||||
|
|
||||||
uiSchemaRepository = db.getRepository('ui_schemas');
|
uiSchemaRepository = db.getRepository('ui_schemas');
|
||||||
|
await uiSchemaRepository.insert(schema);
|
||||||
|
|
||||||
|
uiSchemaPlugin = app.getPlugin<PluginUiSchema>('PluginUiSchema');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should save uiSchemaAttrs', async () => {
|
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({
|
const node = await uiSchemaRepository.findOne({
|
||||||
filter: {
|
filter: {
|
||||||
uid: 'table',
|
uid: 'table',
|
||||||
@ -74,4 +84,38 @@ describe('server hooks', () => {
|
|||||||
const nodeFieldAttr = await nodeField.getAttrs();
|
const nodeFieldAttr = await nodeField.getAttrs();
|
||||||
expect(nodeFieldAttr.get('collectionPath')).toEqual('posts.title');
|
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();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -6,7 +6,7 @@ export default {
|
|||||||
autoGenId: false,
|
autoGenId: false,
|
||||||
timestamps: false,
|
timestamps: false,
|
||||||
repository: 'UiSchemaRepository',
|
repository: 'UiSchemaRepository',
|
||||||
model: 'MagicAttributeModel',
|
model: 'UiSchemaModel',
|
||||||
magicAttribute: 'schema',
|
magicAttribute: 'schema',
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
|
@ -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 };
|
||||||
|
57
packages/plugin-ui-schema-storage/src/server-hooks/index.ts
Normal file
57
packages/plugin-ui-schema-storage/src/server-hooks/index.ts
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
@ -3,8 +3,12 @@ import { Plugin } from '@nocobase/server';
|
|||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { uiSchemaActions } from './actions/ui-schema-action';
|
import { uiSchemaActions } from './actions/ui-schema-action';
|
||||||
import UiSchemaRepository from './repository';
|
import UiSchemaRepository from './repository';
|
||||||
|
import { ServerHooks } from './server-hooks';
|
||||||
|
import { UiSchemaModel } from './model';
|
||||||
|
|
||||||
export default class PluginUiSchema extends Plugin {
|
export default class PluginUiSchema extends Plugin {
|
||||||
|
serverHooks: ServerHooks;
|
||||||
|
|
||||||
registerRepository() {
|
registerRepository() {
|
||||||
this.app.db.registerRepositories({
|
this.app.db.registerRepositories({
|
||||||
UiSchemaRepository,
|
UiSchemaRepository,
|
||||||
@ -14,10 +18,16 @@ export default class PluginUiSchema extends Plugin {
|
|||||||
async beforeLoad() {
|
async beforeLoad() {
|
||||||
const db = this.app.db;
|
const db = this.app.db;
|
||||||
|
|
||||||
this.app.db.registerModels({ MagicAttributeModel });
|
this.serverHooks = new ServerHooks(db);
|
||||||
|
|
||||||
|
this.app.db.registerModels({ MagicAttributeModel, UiSchemaModel });
|
||||||
|
|
||||||
this.registerRepository();
|
this.registerRepository();
|
||||||
|
|
||||||
|
db.on('ui_schemas.afterDefine', (model) => {
|
||||||
|
model.primaryKeyAttribute = 'uid';
|
||||||
|
});
|
||||||
|
|
||||||
db.on('ui_schemas.beforeCreate', function setUid(model) {
|
db.on('ui_schemas.beforeCreate', function setUid(model) {
|
||||||
model.set('uid', model.get('x-uid'));
|
model.set('uid', model.get('x-uid'));
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user