feat: collection factory (#3047)
This commit is contained in:
parent
3aca9e05d9
commit
b497ef125e
@ -0,0 +1,40 @@
|
|||||||
|
import Database from '../database';
|
||||||
|
import { mockDatabase } from './index';
|
||||||
|
import { Collection } from '../collection';
|
||||||
|
|
||||||
|
describe('collection factory', function () {
|
||||||
|
let db: Database;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
db = mockDatabase();
|
||||||
|
|
||||||
|
await db.clean({ drop: true });
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
await db.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should register new collection type', async () => {
|
||||||
|
class ChildCollection extends Collection {
|
||||||
|
static type = 'child';
|
||||||
|
}
|
||||||
|
|
||||||
|
db.collectionFactory.registerCollectionType(ChildCollection, (options) => {
|
||||||
|
return options.child == true;
|
||||||
|
});
|
||||||
|
|
||||||
|
const collection = db.collectionFactory.createCollection({
|
||||||
|
name: 'child',
|
||||||
|
child: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(collection).toBeInstanceOf(ChildCollection);
|
||||||
|
|
||||||
|
const collection2 = db.collectionFactory.createCollection({
|
||||||
|
name: 'collection',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(collection2).toBeInstanceOf(Collection);
|
||||||
|
});
|
||||||
|
});
|
29
packages/core/database/src/collection-factory.ts
Normal file
29
packages/core/database/src/collection-factory.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import { Collection, CollectionOptions } from './collection';
|
||||||
|
import Database from './database';
|
||||||
|
|
||||||
|
export class CollectionFactory {
|
||||||
|
private collectionTypes: Array<{
|
||||||
|
ctor: typeof Collection;
|
||||||
|
condition: (options: CollectionOptions) => boolean;
|
||||||
|
}> = [];
|
||||||
|
|
||||||
|
constructor(private database: Database) {}
|
||||||
|
|
||||||
|
registerCollectionType(collectionClass: typeof Collection, condition: (options: CollectionOptions) => boolean) {
|
||||||
|
this.collectionTypes.push({ ctor: collectionClass, condition });
|
||||||
|
}
|
||||||
|
|
||||||
|
createCollection<T extends Collection>(options: CollectionOptions): T {
|
||||||
|
let klass = Collection;
|
||||||
|
for (const { ctor, condition } of this.collectionTypes) {
|
||||||
|
if (condition(options)) {
|
||||||
|
klass = ctor;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new klass(options, {
|
||||||
|
database: this.database,
|
||||||
|
}) as T;
|
||||||
|
}
|
||||||
|
}
|
@ -72,6 +72,7 @@ import {
|
|||||||
import { patchSequelizeQueryInterface, snakeCase } from './utils';
|
import { patchSequelizeQueryInterface, snakeCase } from './utils';
|
||||||
import { BaseValueParser, registerFieldValueParsers } from './value-parsers';
|
import { BaseValueParser, registerFieldValueParsers } from './value-parsers';
|
||||||
import { ViewCollection } from './view-collection';
|
import { ViewCollection } from './view-collection';
|
||||||
|
import { CollectionFactory } from './collection-factory';
|
||||||
|
|
||||||
export type MergeOptions = merge.Options;
|
export type MergeOptions = merge.Options;
|
||||||
|
|
||||||
@ -177,23 +178,17 @@ export class Database extends EventEmitter implements AsyncEmitter {
|
|||||||
tableNameCollectionMap = new Map<string, Collection>();
|
tableNameCollectionMap = new Map<string, Collection>();
|
||||||
context: any = {};
|
context: any = {};
|
||||||
queryInterface: QueryInterface;
|
queryInterface: QueryInterface;
|
||||||
|
|
||||||
_instanceId: string;
|
|
||||||
|
|
||||||
utils = new DatabaseUtils(this);
|
utils = new DatabaseUtils(this);
|
||||||
referenceMap = new ReferencesMap();
|
referenceMap = new ReferencesMap();
|
||||||
inheritanceMap = new InheritanceMap();
|
inheritanceMap = new InheritanceMap();
|
||||||
|
|
||||||
importedFrom = new Map<string, Array<string>>();
|
importedFrom = new Map<string, Array<string>>();
|
||||||
|
|
||||||
modelHook: ModelHook;
|
modelHook: ModelHook;
|
||||||
version: DatabaseVersion;
|
version: DatabaseVersion;
|
||||||
|
|
||||||
delayCollectionExtend = new Map<string, { collectionOptions: CollectionOptions; mergeOptions?: any }[]>();
|
delayCollectionExtend = new Map<string, { collectionOptions: CollectionOptions; mergeOptions?: any }[]>();
|
||||||
|
|
||||||
logger: Logger;
|
logger: Logger;
|
||||||
|
|
||||||
collectionGroupManager = new CollectionGroupManager(this);
|
collectionGroupManager = new CollectionGroupManager(this);
|
||||||
|
|
||||||
|
collectionFactory: CollectionFactory = new CollectionFactory(this);
|
||||||
declare emitAsync: (event: string | symbol, ...args: any[]) => Promise<boolean>;
|
declare emitAsync: (event: string | symbol, ...args: any[]) => Promise<boolean>;
|
||||||
|
|
||||||
constructor(options: DatabaseOptions) {
|
constructor(options: DatabaseOptions) {
|
||||||
@ -307,12 +302,30 @@ export class Database extends EventEmitter implements AsyncEmitter {
|
|||||||
|
|
||||||
this.initListener();
|
this.initListener();
|
||||||
patchSequelizeQueryInterface(this);
|
patchSequelizeQueryInterface(this);
|
||||||
|
|
||||||
|
this.registerCollectionType();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_instanceId: string;
|
||||||
|
|
||||||
get instanceId() {
|
get instanceId() {
|
||||||
return this._instanceId;
|
return this._instanceId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
registerCollectionType() {
|
||||||
|
this.collectionFactory.registerCollectionType(InheritedCollection, (options) => {
|
||||||
|
return options.inherits && lodash.castArray(options.inherits).length > 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.collectionFactory.registerCollectionType(ViewCollection, (options) => {
|
||||||
|
return options.viewName || options.view;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.collectionFactory.registerCollectionType(SqlCollection, (options) => {
|
||||||
|
return options.sql;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
setContext(context: any) {
|
setContext(context: any) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
}
|
}
|
||||||
@ -447,10 +460,6 @@ export class Database extends EventEmitter implements AsyncEmitter {
|
|||||||
return dialect.includes(this.sequelize.getDialect());
|
return dialect.includes(this.sequelize.getDialect());
|
||||||
}
|
}
|
||||||
|
|
||||||
escapeId(identifier: string) {
|
|
||||||
return this.inDialect('mysql') ? `\`${identifier}\`` : `"${identifier}"`;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add collection to database
|
* Add collection to database
|
||||||
* @param options
|
* @param options
|
||||||
@ -466,29 +475,7 @@ export class Database extends EventEmitter implements AsyncEmitter {
|
|||||||
|
|
||||||
this.emit('beforeDefineCollection', options);
|
this.emit('beforeDefineCollection', options);
|
||||||
|
|
||||||
const hasValidInheritsOptions = (() => {
|
const collection = this.collectionFactory.createCollection(options);
|
||||||
return options.inherits && lodash.castArray(options.inherits).length > 0;
|
|
||||||
})();
|
|
||||||
|
|
||||||
const hasViewOptions = options.viewName || options.view;
|
|
||||||
|
|
||||||
const collectionKlass = (() => {
|
|
||||||
if (hasValidInheritsOptions) {
|
|
||||||
return InheritedCollection;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasViewOptions) {
|
|
||||||
return ViewCollection;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.sql) {
|
|
||||||
return SqlCollection;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Collection;
|
|
||||||
})();
|
|
||||||
|
|
||||||
const collection = new collectionKlass(options, { database: this });
|
|
||||||
|
|
||||||
this.collections.set(collection.name, collection);
|
this.collections.set(collection.name, collection);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user