feat: removeEmptyParents server hook

This commit is contained in:
Chareice 2022-02-09 23:39:50 +08:00 committed by chenos
parent 85ab936c4c
commit 4607e0da49
4 changed files with 214 additions and 6 deletions

View File

@ -0,0 +1,160 @@
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';
import { removeEmptyParents } from '../server-hooks/removeEmptyParents';
describe('server hooks', () => {
let app: MockServer;
let db: Database;
let uiSchemaRepository: UiSchemaRepository;
let uiSchemaPlugin: PluginUiSchema;
afterEach(async () => {
await app.destroy();
});
beforeEach(async () => {
app = mockServer({
registerActions: true,
});
db = app.db;
await app.cleanDb();
app.plugin(PluginUiSchema);
app.plugin(PluginCollectionManager);
await app.loadAndInstall();
uiSchemaRepository = db.getRepository('ui_schemas');
uiSchemaPlugin = app.getPlugin<PluginUiSchema>('PluginUiSchema');
});
it('should clean row struct', async () => {
const PostModel = await db.getRepository('collections').create({
values: {
name: 'posts',
},
});
await db.getRepository('fields').create({
values: {
name: 'title',
type: 'string',
collectionName: 'posts',
},
});
await db.getRepository('fields').create({
values: {
name: 'name',
type: 'string',
collectionName: 'posts',
},
});
await db.getRepository('fields').create({
values: {
name: 'intro',
type: 'string',
collectionName: 'posts',
},
});
const schema = {
type: 'void',
name: 'grid1',
'x-decorator': 'Form',
'x-component': 'Grid',
'x-item-initializer': 'AddGridFormItem',
'x-uid': 'grid1',
properties: {
row1: {
type: 'void',
'x-component': 'Grid.Row',
'x-uid': 'row1',
properties: {
col11: {
type: 'void',
'x-uid': 'col11',
'x-component': 'Grid.Col',
properties: {
name: {
type: 'string',
title: 'Name',
'x-uid': 'posts-name',
'x-decorator': 'FormItem',
'x-component': 'Input',
'x-collection-field': 'posts.name',
'x-server-hooks': [
{
type: 'onCollectionFieldDestroy',
collection: 'posts',
fields: ['name'],
method: 'removeEmptyParents',
},
],
},
title: {
type: 'string',
title: 'Title',
'x-uid': 'posts-title',
'x-decorator': 'FormItem',
'x-component': 'Input',
'x-collection-field': 'posts.title',
'x-server-hooks': [
{
type: 'onCollectionFieldDestroy',
collection: 'posts',
fields: ['title'],
method: 'removeEmptyParents',
},
],
},
},
},
col12: {
type: 'void',
'x-uid': 'col12',
'x-component': 'Grid.Col',
properties: {
intro: {
'x-uid': 'posts-intro',
type: 'string',
title: 'Intro',
'x-decorator': 'FormItem',
'x-component': 'Input',
'x-server-hooks': [
{
type: 'onCollectionFieldDestroy',
collection: 'posts',
fields: ['intro'],
method: 'removeEmptyParents',
},
],
},
},
},
},
},
},
};
await uiSchemaRepository.insert(schema);
uiSchemaPlugin.serverHooks.register('onCollectionFieldDestroy', 'removeEmptyParents', removeEmptyParents);
await db.getRepository('fields').destroy({
filter: {
name: 'intro',
},
individualHooks: true,
});
const jsonTree = await uiSchemaRepository.getJsonSchema('grid1');
expect(jsonTree['properties']['row1']['properties']['col11']).toBeDefined();
expect(jsonTree['properties']['row1']['properties']['col12']).not.toBeDefined();
});
});

View File

@ -178,11 +178,7 @@ describe('server hooks', () => {
],
};
await uiSchemaRepository.create({
values: {
schema: menuSchema,
},
});
await uiSchemaRepository.insert(menuSchema);
const PostModel = await db.getRepository('collections').create({
values: {

View File

@ -110,7 +110,7 @@ export class ServerHooks {
const hookFunc = this.hooks.get(hookRecord.get('type') as HookType)?.get(hoodMethodName);
if (hookFunc) {
await hookFunc({ ...hooksArgs, schemaInstance: (<any>hookRecord).uiSchema });
await hookFunc({ ...hooksArgs, schemaInstance: (<any>hookRecord).uiSchema, db: this.db });
}
}
}

View File

@ -0,0 +1,52 @@
import { UiSchemaRepository } from '@nocobase/plugin-ui-schema-storage';
// given a child uid, if it is a single child ,return its parent
async function isSingleChild(uid, db, transaction) {
const parent = await db.getRepository('ui_schema_tree_path').findOne({
filter: {
descendant: uid,
depth: 1,
},
});
const countResult = await db.sequelize.query(
`SELECT COUNT(*) FROM ${
db.getCollection('ui_schema_tree_path').model.tableName
} where ancestor = :ancestor and depth = 1`,
{
replacements: {
ancestor: parent.get('ancestor'),
},
type: 'SELECT',
transaction,
},
);
const parentChildrenCount = countResult[0]['count'];
if (parentChildrenCount == 1) {
return parent.get('ancestor');
}
return null;
}
export async function removeEmptyParents({ schemaInstance, options, db }) {
const { transaction } = options;
const uiSchemaRepository: UiSchemaRepository = db.getRepository('ui_schemas');
const uid = schemaInstance.get('uid');
// find parent uid
const parentUid = await isSingleChild(uid, db, transaction);
if (parentUid) {
const rowUid = await isSingleChild(parentUid, db, transaction);
if (rowUid) {
await uiSchemaRepository.remove(rowUid, { transaction });
} else {
await uiSchemaRepository.remove(parentUid, { transaction });
}
} else {
await uiSchemaRepository.remove(uid, { transaction });
}
}