2021-09-27 15:28:32 +08:00
|
|
|
|
import { Sequelize, ModelCtor, Model, DataTypes, Utils } from 'sequelize';
|
|
|
|
|
import { EventEmitter } from 'events';
|
2021-09-18 00:23:21 +08:00
|
|
|
|
import { Database } from './database';
|
2021-09-27 15:28:32 +08:00
|
|
|
|
import { Field } from './fields';
|
2021-09-18 00:23:21 +08:00
|
|
|
|
import _ from 'lodash';
|
2021-09-25 23:56:26 +08:00
|
|
|
|
import { Repository } from './repository';
|
2021-09-18 00:23:21 +08:00
|
|
|
|
|
|
|
|
|
export interface CollectionOptions {
|
2021-09-27 15:28:32 +08:00
|
|
|
|
name: string;
|
|
|
|
|
tableName?: string;
|
|
|
|
|
fields?: any;
|
2021-09-18 00:23:21 +08:00
|
|
|
|
[key: string]: any;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface CollectionContext {
|
|
|
|
|
database: Database;
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-27 15:28:32 +08:00
|
|
|
|
export class Collection extends EventEmitter {
|
2021-09-18 00:23:21 +08:00
|
|
|
|
options: CollectionOptions;
|
|
|
|
|
context: CollectionContext;
|
2021-09-27 15:28:32 +08:00
|
|
|
|
fields: Map<string, any>;
|
|
|
|
|
model: ModelCtor<Model>;
|
|
|
|
|
repository: Repository;
|
2021-09-18 00:23:21 +08:00
|
|
|
|
|
|
|
|
|
get name() {
|
|
|
|
|
return this.options.name;
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-27 15:28:32 +08:00
|
|
|
|
constructor(options: CollectionOptions, context?: CollectionContext) {
|
|
|
|
|
super();
|
2021-09-18 00:23:21 +08:00
|
|
|
|
this.options = options;
|
|
|
|
|
this.context = context;
|
2021-09-27 15:28:32 +08:00
|
|
|
|
this.fields = new Map<string, any>();
|
2021-09-18 00:23:21 +08:00
|
|
|
|
this.model = class extends Model<any, any> {};
|
|
|
|
|
const attributes = {};
|
2021-09-27 15:28:32 +08:00
|
|
|
|
const { name, tableName } = options;
|
2021-09-23 00:16:04 +08:00
|
|
|
|
// TODO: 不能重复 model.init,如果有涉及 InitOptions 参数修改,需要另外处理。
|
2021-09-18 00:23:21 +08:00
|
|
|
|
this.model.init(attributes, {
|
2021-09-27 15:28:32 +08:00
|
|
|
|
..._.omit(options, ['name', 'fields']),
|
2021-09-18 00:23:21 +08:00
|
|
|
|
sequelize: context.database.sequelize,
|
|
|
|
|
modelName: name,
|
|
|
|
|
tableName: tableName || name,
|
|
|
|
|
});
|
2021-09-27 15:28:32 +08:00
|
|
|
|
this.on('field.afterAdd', (field) => field.bind());
|
|
|
|
|
this.on('field.afterRemove', (field) => field.unbind());
|
|
|
|
|
this.setFields(options.fields);
|
2021-09-25 23:56:26 +08:00
|
|
|
|
this.repository = new Repository(this);
|
2021-09-18 00:23:21 +08:00
|
|
|
|
}
|
|
|
|
|
|
2021-09-27 15:28:32 +08:00
|
|
|
|
forEachField(callback: (field: Field) => void) {
|
|
|
|
|
return [...this.fields.values()].forEach(callback);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
findField(callback: (field: Field) => boolean) {
|
|
|
|
|
return [...this.fields.values()].find(callback);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
hasField(name: string) {
|
|
|
|
|
return this.fields.has(name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
getField(name: string) {
|
|
|
|
|
return this.fields.get(name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
addField(options) {
|
|
|
|
|
const { name, ...others } = options;
|
|
|
|
|
if (!name) {
|
|
|
|
|
return this;
|
|
|
|
|
}
|
|
|
|
|
const { database } = this.context;
|
|
|
|
|
const field = database.buildField({ name, ...others }, {
|
|
|
|
|
...this.context,
|
|
|
|
|
collection: this,
|
|
|
|
|
model: this.model,
|
2021-09-18 00:23:21 +08:00
|
|
|
|
});
|
2021-09-27 15:28:32 +08:00
|
|
|
|
this.fields.set(name, field);
|
|
|
|
|
this.emit('field.afterAdd', field);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
setFields(fields: any, reset = true) {
|
|
|
|
|
if (!fields) {
|
|
|
|
|
return this;
|
|
|
|
|
}
|
|
|
|
|
if (reset) {
|
|
|
|
|
this.fields.clear();
|
|
|
|
|
}
|
|
|
|
|
if (Array.isArray(fields)) {
|
|
|
|
|
for (const field of fields) {
|
|
|
|
|
this.addField(field);
|
|
|
|
|
}
|
|
|
|
|
} else if (typeof fields === 'object') {
|
|
|
|
|
for (const [name, options] of Object.entries<any>(fields)) {
|
|
|
|
|
this.addField({...options, name});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
removeField(name) {
|
|
|
|
|
const field = this.fields.get(name);
|
|
|
|
|
const bool = this.fields.delete(name);
|
|
|
|
|
if (bool) {
|
|
|
|
|
this.emit('field.afterRemove', field);
|
|
|
|
|
}
|
|
|
|
|
return bool;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO
|
|
|
|
|
extend(options) {
|
|
|
|
|
const { fields } = options;
|
|
|
|
|
this.setFields(fields);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sync() {
|
|
|
|
|
|
2021-09-18 00:23:21 +08:00
|
|
|
|
}
|
|
|
|
|
}
|