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,7 +49,41 @@ export function extend(tableOptions: TableOptions, mergeOptions: 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;
 | 
			
		||||
 | 
			
		||||
@ -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