mirror of
https://github.com/nocobase/nocobase
synced 2024-11-15 13:16:08 +00:00
feat: improve code
This commit is contained in:
parent
a8cd70017b
commit
c182c29161
96
packages/database/src/__tests__/emitter.test.ts
Normal file
96
packages/database/src/__tests__/emitter.test.ts
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
import { getDatabase } from './';
|
||||||
|
import Database from '../database';
|
||||||
|
|
||||||
|
let db: Database;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
db = getDatabase();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
await db.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('emitter', () => {
|
||||||
|
it('event emitter', async () => {
|
||||||
|
db.table({
|
||||||
|
name: 'test',
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
type: 'json',
|
||||||
|
name: 'arr',
|
||||||
|
defaultValue: [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
db.table({
|
||||||
|
name: 'test2',
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
type: 'json',
|
||||||
|
name: 'arr',
|
||||||
|
defaultValue: [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
await db.sync();
|
||||||
|
const arr = [];
|
||||||
|
db.on('afterCreate', async function abc1(...args) {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
console.log('db.on.afterCreate')
|
||||||
|
arr.push(1);
|
||||||
|
resolve();
|
||||||
|
}, 200);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
db.on('test.afterCreate', async function abc2(model, options) {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
console.log('db.on.test.afterCreate')
|
||||||
|
arr.push(2);
|
||||||
|
resolve();
|
||||||
|
}, 100);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
db.on('test2.afterCreate', async (model, options) => {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
console.log('db.on.test2.afterCreate')
|
||||||
|
arr.push(3);
|
||||||
|
resolve();
|
||||||
|
}, 100);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
const Test2 = db.getModel('test2');
|
||||||
|
await Test2.create();
|
||||||
|
const Test1 = db.getModel('test');
|
||||||
|
await Test1.create();
|
||||||
|
expect(arr).toEqual([3, 1, 2, 1]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it.only('a', async () => {
|
||||||
|
db.table({
|
||||||
|
name: 'test',
|
||||||
|
fields: [
|
||||||
|
{ type: 'string', name: 'name' }
|
||||||
|
],
|
||||||
|
});
|
||||||
|
db.on('test.afterBulkCreate', async (...args) => {
|
||||||
|
console.log('afterBulkCreate1', args);
|
||||||
|
});
|
||||||
|
db.on('test2.afterBulkCreate', async (...args) => {
|
||||||
|
console.log('afterBulkCreate2', args);
|
||||||
|
});
|
||||||
|
await db.sync();
|
||||||
|
const Test = db.getModel('test');
|
||||||
|
await Test.create();
|
||||||
|
await Test.bulkCreate([{}, {}]);
|
||||||
|
await Test.update({
|
||||||
|
name: 'name'
|
||||||
|
}, {
|
||||||
|
where: {},
|
||||||
|
});
|
||||||
|
await Test.findAll();
|
||||||
|
});
|
||||||
|
});
|
@ -211,61 +211,4 @@ describe('hooks', () => {
|
|||||||
const test = await Test3.create({});
|
const test = await Test3.create({});
|
||||||
expect(test.get('arr')).toEqual([3, 5, 1, 4, 6, 2]);
|
expect(test.get('arr')).toEqual([3, 5, 1, 4, 6, 2]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('event emitter', async () => {
|
|
||||||
const table = db.table({
|
|
||||||
name: 'test',
|
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
type: 'json',
|
|
||||||
name: 'arr',
|
|
||||||
defaultValue: [],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
db.table({
|
|
||||||
name: 'test2',
|
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
type: 'json',
|
|
||||||
name: 'arr',
|
|
||||||
defaultValue: [],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
await db.sync();
|
|
||||||
const arr = [];
|
|
||||||
db.on('afterCreate', async function abc1(...args) {
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
setTimeout(() => {
|
|
||||||
console.log('db.on.afterCreate')
|
|
||||||
arr.push(1);
|
|
||||||
resolve();
|
|
||||||
}, 200);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
db.on('test.afterCreate', async function abc2(model, options) {
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
setTimeout(() => {
|
|
||||||
console.log('db.on.test.afterCreate')
|
|
||||||
arr.push(2);
|
|
||||||
resolve();
|
|
||||||
}, 100);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
db.on('test2.afterCreate', async (model, options) => {
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
setTimeout(() => {
|
|
||||||
console.log('db.on.test2.afterCreate')
|
|
||||||
arr.push(3);
|
|
||||||
resolve();
|
|
||||||
}, 100);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
const Test2 = db.getModel('test2');
|
|
||||||
await Test2.create();
|
|
||||||
const Test1 = db.getModel('test');
|
|
||||||
await Test1.create();
|
|
||||||
expect(arr).toEqual([3,1,2,1]);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
@ -39,9 +39,13 @@ export function getDatabase() {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
hooks: {
|
hooks: {
|
||||||
beforeDefine(columns, model) {
|
beforeDefine(model, options) {
|
||||||
model.tableName = `${getTestKey()}_${model.tableName || model.name.plural}`;
|
// @ts-ignore
|
||||||
}
|
options.tableNamePrefix = `${getTestKey()}_`;
|
||||||
}
|
// @ts-ignore
|
||||||
|
options.hookModelName = options.tableName;
|
||||||
|
options.tableName = `${getTestKey()}_${options.tableName || options.name.plural}`;
|
||||||
|
},
|
||||||
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -34,7 +34,7 @@ export interface ImportOptions {
|
|||||||
export interface DatabaseOptions extends Options {
|
export interface DatabaseOptions extends Options {
|
||||||
}
|
}
|
||||||
|
|
||||||
export type HookType = 'beforeTableInit' | 'afterTableInit' | 'beforeAddField' | 'afterAddField';
|
// export type HookType = 'beforeTableInit' | 'afterTableInit' | 'beforeAddField' | 'afterAddField';
|
||||||
|
|
||||||
export class Extend {
|
export class Extend {
|
||||||
tableOptions: TableOptions;
|
tableOptions: TableOptions;
|
||||||
@ -49,7 +49,41 @@ export function extend(tableOptions: TableOptions, mergeOptions: MergeOptions =
|
|||||||
return new Extend(tableOptions, mergeOptions);
|
return new Extend(tableOptions, mergeOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class Database extends EventEmitter {
|
type HookType =
|
||||||
|
'beforeValidate' |
|
||||||
|
'afterValidate' |
|
||||||
|
'beforeCreate' |
|
||||||
|
'afterCreate' |
|
||||||
|
'beforeDestroy' |
|
||||||
|
'afterDestroy' |
|
||||||
|
'beforeRestore' |
|
||||||
|
'afterRestore' |
|
||||||
|
'beforeUpdate' |
|
||||||
|
'afterUpdate' |
|
||||||
|
'beforeSave' |
|
||||||
|
'afterSave' |
|
||||||
|
'beforeBulkCreate' |
|
||||||
|
'afterBulkCreate' |
|
||||||
|
'beforeBulkDestroy' |
|
||||||
|
'afterBulkDestroy' |
|
||||||
|
'beforeBulkRestore' |
|
||||||
|
'afterBulkRestore' |
|
||||||
|
'beforeBulkUpdate' |
|
||||||
|
'afterBulkUpdate' |
|
||||||
|
'beforeSync' |
|
||||||
|
'afterSync' |
|
||||||
|
'beforeBulkSync' |
|
||||||
|
'afterBulkSync' |
|
||||||
|
'beforeDefine' |
|
||||||
|
'afterDefine' |
|
||||||
|
'beforeInit' |
|
||||||
|
'afterInit' |
|
||||||
|
'beforeConnect' |
|
||||||
|
'afterConnect' |
|
||||||
|
'beforeDisconnect' |
|
||||||
|
'afterDisconnect';
|
||||||
|
|
||||||
|
export default class Database extends EventEmitter {
|
||||||
|
|
||||||
public readonly sequelize: Sequelize;
|
public readonly sequelize: Sequelize;
|
||||||
|
|
||||||
@ -71,52 +105,44 @@ export default class Database extends EventEmitter {
|
|||||||
|
|
||||||
protected extTableOptions = new Map<string, any>();
|
protected extTableOptions = new Map<string, any>();
|
||||||
|
|
||||||
protected hookTypes = new Set([
|
protected hookTypes = new Map(Object.entries({
|
||||||
'beforeValidate',
|
beforeValidate: 1,
|
||||||
'afterValidate',
|
afterValidate: 1,
|
||||||
'validationFailed',
|
beforeCreate: 1,
|
||||||
'beforeCreate',
|
afterCreate: 1,
|
||||||
'afterCreate',
|
beforeDestroy: 1,
|
||||||
'beforeDestroy',
|
afterDestroy: 1,
|
||||||
'afterDestroy',
|
beforeRestore: 1,
|
||||||
'beforeRestore',
|
afterRestore: 1,
|
||||||
'afterRestore',
|
beforeUpdate: 1,
|
||||||
'beforeUpdate',
|
afterUpdate: 1,
|
||||||
'afterUpdate',
|
beforeSave: 1,
|
||||||
'beforeSave',
|
afterSave: 1,
|
||||||
'afterSave',
|
|
||||||
'beforeUpsert',
|
beforeBulkCreate: 2,
|
||||||
'afterUpsert',
|
afterBulkCreate: 2,
|
||||||
'beforeBulkCreate',
|
|
||||||
'afterBulkCreate',
|
beforeBulkDestroy: 3,
|
||||||
'beforeBulkDestroy',
|
afterBulkDestroy: 3,
|
||||||
'afterBulkDestroy',
|
beforeBulkRestore: 3,
|
||||||
'beforeBulkRestore',
|
afterBulkRestore: 3,
|
||||||
'afterBulkRestore',
|
beforeBulkUpdate: 3,
|
||||||
'beforeBulkUpdate',
|
afterBulkUpdate: 3,
|
||||||
'afterBulkUpdate',
|
|
||||||
'beforeFind',
|
beforeSync: 4,
|
||||||
'beforeFindAfterExpandIncludeAll',
|
afterSync: 4,
|
||||||
'beforeFindAfterOptions',
|
beforeBulkSync: 4,
|
||||||
'afterFind',
|
afterBulkSync: 4,
|
||||||
'beforeCount',
|
|
||||||
'beforeDefine',
|
beforeDefine: 0,
|
||||||
'afterDefine',
|
afterDefine: 0,
|
||||||
'beforeInit',
|
beforeInit: 0,
|
||||||
'afterInit',
|
afterInit: 0,
|
||||||
'beforeAssociate',
|
beforeConnect: 0,
|
||||||
'afterAssociate',
|
afterConnect: 0,
|
||||||
'beforeConnect',
|
beforeDisconnect: 0,
|
||||||
'afterConnect',
|
afterDisconnect: 0,
|
||||||
'beforeDisconnect',
|
}));
|
||||||
'afterDisconnect',
|
|
||||||
'beforeSync',
|
|
||||||
'afterSync',
|
|
||||||
'beforeBulkSync',
|
|
||||||
'afterBulkSync',
|
|
||||||
'beforeQuery',
|
|
||||||
'afterQuery'
|
|
||||||
]);
|
|
||||||
|
|
||||||
constructor(options?: DatabaseOptions) {
|
constructor(options?: DatabaseOptions) {
|
||||||
super();
|
super();
|
||||||
@ -138,17 +164,33 @@ export default class Database extends EventEmitter {
|
|||||||
return hookType;
|
return hookType;
|
||||||
}
|
}
|
||||||
|
|
||||||
on(event: string | symbol, listener: (...args: any[]) => void) {
|
on(event: HookType | Omit<string, HookType> | symbol, listener: (...args: any[]) => void) {
|
||||||
const hookType = this._getHookType(event);
|
const hookType = this._getHookType(event);
|
||||||
if (hookType) {
|
if (hookType) {
|
||||||
|
const state = this.hookTypes.get(hookType);
|
||||||
console.log('sequelize.addHook', hookType)
|
console.log('sequelize.addHook', hookType)
|
||||||
this.sequelize.addHook(hookType, async (model) => {
|
this.sequelize.addHook(hookType, async (...args: any[]) => {
|
||||||
await this.emitAsync(`${model.constructor.name}.${hookType}`);
|
let modelName: string;
|
||||||
await this.emitAsync(hookType);
|
switch (state) {
|
||||||
|
case 1:
|
||||||
|
modelName = args?.[0]?.constructor?.name;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
modelName = args?.[1]?.model?.name;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
modelName = args?.[0]?.model?.name;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
console.log({ modelName, args });
|
||||||
|
if (modelName) {
|
||||||
|
await this.emitAsync(`${modelName}.${hookType}`, ...args);
|
||||||
|
}
|
||||||
|
await this.emitAsync(hookType, ...args);
|
||||||
});
|
});
|
||||||
this.hookTypes.delete(hookType);
|
this.hookTypes.delete(hookType);
|
||||||
}
|
}
|
||||||
return super.on(event, listener);
|
return super.on(event as any, listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
async emitAsync(event: string | symbol, ...args: any[]): Promise<boolean> {
|
async emitAsync(event: string | symbol, ...args: any[]): Promise<boolean> {
|
||||||
|
@ -298,9 +298,10 @@ export class PASSWORD extends STRING {
|
|||||||
|
|
||||||
constructor(options: Options.StringOptions, context: FieldContext) {
|
constructor(options: Options.StringOptions, context: FieldContext) {
|
||||||
super(options, context);
|
super(options, context);
|
||||||
const Model = context.sourceTable.getModel();
|
const { database, sourceTable } = context;
|
||||||
Model.addHook('beforeCreate', PASSWORD.hash.bind(this));
|
const name = sourceTable.getName();
|
||||||
Model.addHook('beforeUpdate', PASSWORD.hash.bind(this));
|
database.on(`${name}.beforeCreate`, PASSWORD.hash.bind(this));
|
||||||
|
database.on(`${name}.beforeUpdate`, PASSWORD.hash.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async hash(this: PASSWORD, model) {
|
public static async hash(this: PASSWORD, model) {
|
||||||
@ -361,9 +362,9 @@ export class UID extends Column {
|
|||||||
|
|
||||||
constructor(options: Options.StringOptions, context: FieldContext) {
|
constructor(options: Options.StringOptions, context: FieldContext) {
|
||||||
super(options, context);
|
super(options, context);
|
||||||
|
const { sourceTable, database } = context;
|
||||||
const { name, prefix = '' } = options;
|
const { name, prefix = '' } = options;
|
||||||
const Model = context.sourceTable.getModel();
|
database.on(`${sourceTable.getName()}.beforeCreate`, (model) => {
|
||||||
Model.addHook('beforeCreate', (model) => {
|
|
||||||
if (!model.get(name)) {
|
if (!model.get(name)) {
|
||||||
model.set(name, `${prefix}${uid()}`);
|
model.set(name, `${prefix}${uid()}`);
|
||||||
}
|
}
|
||||||
@ -819,10 +820,14 @@ export class SORT extends NUMBER {
|
|||||||
|
|
||||||
constructor(options: Options.SortOptions, context: FieldContext) {
|
constructor(options: Options.SortOptions, context: FieldContext) {
|
||||||
super(options, context);
|
super(options, context);
|
||||||
const Model = context.sourceTable.getModel();
|
// const Model = context.sourceTable.getModel();
|
||||||
// TODO(feature): 可考虑策略模式,以在需要时对外提供接口
|
// TODO(feature): 可考虑策略模式,以在需要时对外提供接口
|
||||||
Model.addHook('beforeCreate', SORT.beforeCreateHook.bind(this));
|
const { database, sourceTable } = context;
|
||||||
Model.addHook('beforeBulkCreate', SORT.beforeBulkCreateHook.bind(this));
|
const name = sourceTable.getName();
|
||||||
|
database.on(`${name}.beforeCreate`, SORT.beforeCreateHook.bind(this));
|
||||||
|
database.on(`${name}.beforeBulkCreate`, SORT.beforeBulkCreateHook.bind(this));
|
||||||
|
// Model.addHook('beforeCreate', SORT.beforeCreateHook.bind(this));
|
||||||
|
// Model.addHook('beforeBulkCreate', SORT.beforeBulkCreateHook.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
public getDataType(): Function {
|
public getDataType(): Function {
|
||||||
@ -901,15 +906,20 @@ export class Radio extends BOOLEAN {
|
|||||||
}
|
}
|
||||||
|
|
||||||
constructor({ type, ...options }: Options.RadioOptions, context: FieldContext) {
|
constructor({ type, ...options }: Options.RadioOptions, context: FieldContext) {
|
||||||
super({ ...options, type: 'boolean' }, context);
|
super({ ...options, type: 'radio' }, context);
|
||||||
const Model = context.sourceTable.getModel();
|
// const Model = context.sourceTable.getModel();
|
||||||
// TODO(feature): 可考虑策略模式,以在需要时对外提供接口
|
// TODO(feature): 可考虑策略模式,以在需要时对外提供接口
|
||||||
Model.addHook('beforeCreate', Radio.beforeCreateHook.bind(this));
|
// Model.addHook('beforeCreate', Radio.beforeCreateHook.bind(this));
|
||||||
Model.addHook('beforeUpdate', Radio.beforeUpdateHook.bind(this));
|
// Model.addHook('beforeUpdate', Radio.beforeUpdateHook.bind(this));
|
||||||
// Model.addHook('beforeUpsert', beforeSaveHook);
|
// // Model.addHook('beforeUpsert', beforeSaveHook);
|
||||||
Model.addHook('beforeBulkCreate', Radio.beforeBulkCreateHook.bind(this));
|
// Model.addHook('beforeBulkCreate', Radio.beforeBulkCreateHook.bind(this));
|
||||||
// TODO(optimize): bulkUpdate 的 hooks 参数不一样,没有对象列表,考虑到很少用,暂时不实现
|
// TODO(optimize): bulkUpdate 的 hooks 参数不一样,没有对象列表,考虑到很少用,暂时不实现
|
||||||
// Model.addHook('beforeBulkUpdate', beforeBulkCreateHook);
|
// Model.addHook('beforeBulkUpdate', beforeBulkCreateHook);
|
||||||
|
const { database, sourceTable } = context;
|
||||||
|
const name = sourceTable.getName();
|
||||||
|
database.on(`${name}.beforeCreate`, Radio.beforeCreateHook.bind(this));
|
||||||
|
database.on(`${name}.beforeUpdate`, Radio.beforeUpdateHook.bind(this));
|
||||||
|
database.on(`${name}.beforeBulkCreate`, Radio.beforeBulkCreateHook.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
public getDataType() {
|
public getDataType() {
|
||||||
|
Loading…
Reference in New Issue
Block a user