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({});
|
||||
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: {
|
||||
beforeDefine(columns, model) {
|
||||
model.tableName = `${getTestKey()}_${model.tableName || model.name.plural}`;
|
||||
}
|
||||
}
|
||||
beforeDefine(model, options) {
|
||||
// @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 type HookType = 'beforeTableInit' | 'afterTableInit' | 'beforeAddField' | 'afterAddField';
|
||||
// export type HookType = 'beforeTableInit' | 'afterTableInit' | 'beforeAddField' | 'afterAddField';
|
||||
|
||||
export class Extend {
|
||||
tableOptions: TableOptions;
|
||||
@ -49,6 +49,40 @@ export function extend(tableOptions: TableOptions, mergeOptions: MergeOptions =
|
||||
return new Extend(tableOptions, mergeOptions);
|
||||
}
|
||||
|
||||
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;
|
||||
@ -71,52 +105,44 @@ export default class Database extends EventEmitter {
|
||||
|
||||
protected extTableOptions = new Map<string, any>();
|
||||
|
||||
protected hookTypes = new Set([
|
||||
'beforeValidate',
|
||||
'afterValidate',
|
||||
'validationFailed',
|
||||
'beforeCreate',
|
||||
'afterCreate',
|
||||
'beforeDestroy',
|
||||
'afterDestroy',
|
||||
'beforeRestore',
|
||||
'afterRestore',
|
||||
'beforeUpdate',
|
||||
'afterUpdate',
|
||||
'beforeSave',
|
||||
'afterSave',
|
||||
'beforeUpsert',
|
||||
'afterUpsert',
|
||||
'beforeBulkCreate',
|
||||
'afterBulkCreate',
|
||||
'beforeBulkDestroy',
|
||||
'afterBulkDestroy',
|
||||
'beforeBulkRestore',
|
||||
'afterBulkRestore',
|
||||
'beforeBulkUpdate',
|
||||
'afterBulkUpdate',
|
||||
'beforeFind',
|
||||
'beforeFindAfterExpandIncludeAll',
|
||||
'beforeFindAfterOptions',
|
||||
'afterFind',
|
||||
'beforeCount',
|
||||
'beforeDefine',
|
||||
'afterDefine',
|
||||
'beforeInit',
|
||||
'afterInit',
|
||||
'beforeAssociate',
|
||||
'afterAssociate',
|
||||
'beforeConnect',
|
||||
'afterConnect',
|
||||
'beforeDisconnect',
|
||||
'afterDisconnect',
|
||||
'beforeSync',
|
||||
'afterSync',
|
||||
'beforeBulkSync',
|
||||
'afterBulkSync',
|
||||
'beforeQuery',
|
||||
'afterQuery'
|
||||
]);
|
||||
protected hookTypes = new Map(Object.entries({
|
||||
beforeValidate: 1,
|
||||
afterValidate: 1,
|
||||
beforeCreate: 1,
|
||||
afterCreate: 1,
|
||||
beforeDestroy: 1,
|
||||
afterDestroy: 1,
|
||||
beforeRestore: 1,
|
||||
afterRestore: 1,
|
||||
beforeUpdate: 1,
|
||||
afterUpdate: 1,
|
||||
beforeSave: 1,
|
||||
afterSave: 1,
|
||||
|
||||
beforeBulkCreate: 2,
|
||||
afterBulkCreate: 2,
|
||||
|
||||
beforeBulkDestroy: 3,
|
||||
afterBulkDestroy: 3,
|
||||
beforeBulkRestore: 3,
|
||||
afterBulkRestore: 3,
|
||||
beforeBulkUpdate: 3,
|
||||
afterBulkUpdate: 3,
|
||||
|
||||
beforeSync: 4,
|
||||
afterSync: 4,
|
||||
beforeBulkSync: 4,
|
||||
afterBulkSync: 4,
|
||||
|
||||
beforeDefine: 0,
|
||||
afterDefine: 0,
|
||||
beforeInit: 0,
|
||||
afterInit: 0,
|
||||
beforeConnect: 0,
|
||||
afterConnect: 0,
|
||||
beforeDisconnect: 0,
|
||||
afterDisconnect: 0,
|
||||
}));
|
||||
|
||||
constructor(options?: DatabaseOptions) {
|
||||
super();
|
||||
@ -138,17 +164,33 @@ export default class Database extends EventEmitter {
|
||||
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);
|
||||
if (hookType) {
|
||||
const state = this.hookTypes.get(hookType);
|
||||
console.log('sequelize.addHook', hookType)
|
||||
this.sequelize.addHook(hookType, async (model) => {
|
||||
await this.emitAsync(`${model.constructor.name}.${hookType}`);
|
||||
await this.emitAsync(hookType);
|
||||
this.sequelize.addHook(hookType, async (...args: any[]) => {
|
||||
let modelName: string;
|
||||
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);
|
||||
}
|
||||
return super.on(event, listener);
|
||||
return super.on(event as any, listener);
|
||||
}
|
||||
|
||||
async emitAsync(event: string | symbol, ...args: any[]): Promise<boolean> {
|
||||
|
@ -298,9 +298,10 @@ export class PASSWORD extends STRING {
|
||||
|
||||
constructor(options: Options.StringOptions, context: FieldContext) {
|
||||
super(options, context);
|
||||
const Model = context.sourceTable.getModel();
|
||||
Model.addHook('beforeCreate', PASSWORD.hash.bind(this));
|
||||
Model.addHook('beforeUpdate', PASSWORD.hash.bind(this));
|
||||
const { database, sourceTable } = context;
|
||||
const name = sourceTable.getName();
|
||||
database.on(`${name}.beforeCreate`, PASSWORD.hash.bind(this));
|
||||
database.on(`${name}.beforeUpdate`, PASSWORD.hash.bind(this));
|
||||
}
|
||||
|
||||
public static async hash(this: PASSWORD, model) {
|
||||
@ -361,9 +362,9 @@ export class UID extends Column {
|
||||
|
||||
constructor(options: Options.StringOptions, context: FieldContext) {
|
||||
super(options, context);
|
||||
const { sourceTable, database } = context;
|
||||
const { name, prefix = '' } = options;
|
||||
const Model = context.sourceTable.getModel();
|
||||
Model.addHook('beforeCreate', (model) => {
|
||||
database.on(`${sourceTable.getName()}.beforeCreate`, (model) => {
|
||||
if (!model.get(name)) {
|
||||
model.set(name, `${prefix}${uid()}`);
|
||||
}
|
||||
@ -819,10 +820,14 @@ export class SORT extends NUMBER {
|
||||
|
||||
constructor(options: Options.SortOptions, context: FieldContext) {
|
||||
super(options, context);
|
||||
const Model = context.sourceTable.getModel();
|
||||
// const Model = context.sourceTable.getModel();
|
||||
// TODO(feature): 可考虑策略模式,以在需要时对外提供接口
|
||||
Model.addHook('beforeCreate', SORT.beforeCreateHook.bind(this));
|
||||
Model.addHook('beforeBulkCreate', SORT.beforeBulkCreateHook.bind(this));
|
||||
const { database, sourceTable } = context;
|
||||
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 {
|
||||
@ -901,15 +906,20 @@ export class Radio extends BOOLEAN {
|
||||
}
|
||||
|
||||
constructor({ type, ...options }: Options.RadioOptions, context: FieldContext) {
|
||||
super({ ...options, type: 'boolean' }, context);
|
||||
const Model = context.sourceTable.getModel();
|
||||
super({ ...options, type: 'radio' }, context);
|
||||
// const Model = context.sourceTable.getModel();
|
||||
// TODO(feature): 可考虑策略模式,以在需要时对外提供接口
|
||||
Model.addHook('beforeCreate', Radio.beforeCreateHook.bind(this));
|
||||
Model.addHook('beforeUpdate', Radio.beforeUpdateHook.bind(this));
|
||||
// Model.addHook('beforeUpsert', beforeSaveHook);
|
||||
Model.addHook('beforeBulkCreate', Radio.beforeBulkCreateHook.bind(this));
|
||||
// Model.addHook('beforeCreate', Radio.beforeCreateHook.bind(this));
|
||||
// Model.addHook('beforeUpdate', Radio.beforeUpdateHook.bind(this));
|
||||
// // Model.addHook('beforeUpsert', beforeSaveHook);
|
||||
// Model.addHook('beforeBulkCreate', Radio.beforeBulkCreateHook.bind(this));
|
||||
// TODO(optimize): bulkUpdate 的 hooks 参数不一样,没有对象列表,考虑到很少用,暂时不实现
|
||||
// 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() {
|
||||
|
Loading…
Reference in New Issue
Block a user