tachybase_todo/packages/server/src/application.ts

178 lines
4.3 KiB
TypeScript
Raw Normal View History

import Koa from 'koa';
2021-09-14 11:09:26 +08:00
import { Command, CommandOptions } from 'commander';
import Database, { DatabaseOptions, TableOptions } from '@nocobase/database';
import Resourcer, { ResourceOptions } from '@nocobase/resourcer';
import { PluginType, Plugin, PluginOptions } from './plugin';
2021-09-16 00:38:48 +08:00
import { registerActions } from '@nocobase/actions';
import {
createCli,
createI18n,
createDatabase,
createResourcer,
registerMiddlewares,
} from './helper';
import { i18n, InitOptions } from 'i18next';
feat: database next (#130) * FIX: database test with sqlite * more types * filter test * split filter parser * filter test * filter test: hasMany * define inverse association for belongsTo & hasMany * chore: console.log * repository count method * chore: Collection * repository filter & appends & fields & expect * repository: sort option * chore: test * add: test * find & findAndCount * chore: test * database-next: update guard * database-next: update guard associationKeysToBeUpdate * chore: comment * update-guard OneToOne Association * has one repository * support through table value * belongs to many repository * has many repository * has many repository find * fix: has many find and count * clean code * add count method * chore: multiple relation * chore: single relation * repository find * relation repository builder * repository count * repository count test * fix test * close db afterEach test * sort with associations * repository update * has many repository: destroy * belongs to many repository: destroy * add transaction decorator * belongs to many with transaction * has many with transaction * clean types * clean types * clean types * repository transaction * fix test * single relation repository with transaction * single relation repository with transaction * fix: test * fix: option parser fields append * fix: typo * fix: string type * fix: import * collection field methods * cleanup * collection sync * fix: import * fix: test * collection update field * collection update options * database hook * database test * database event test * update database event * add async emmit mixin * async model event * database import * fix: model hook type * fix: collection event * recall model.init on collection update * skip redefine collection test * skip collection model update * add model hook class * global model event support * chore * chore * change utils import * add field types * database import * more import test * test case * fix: through model init... * bugfix * fix * update database import * collection sync by foreachModel * fix collection model sync * update * add field types * custom operator * sqlite array field * postgresql array field * array query escape * mysql array operators * date operators * array field sqlite fix * association operator * date operator empty & notEmpty * fix: fields import * fix array field nested association * filter parse prepare * fix test * string field empty * add date operator test * field option types * fix typo * fix: operator name conflict * rename function Co-authored-by: Chareice <chareice@live.com>
2021-12-06 21:12:54 +08:00
import { applyMixins, AsyncEmitter } from '@nocobase/utils';
2021-09-09 13:05:33 +08:00
export interface ResourcerOptions {
prefix?: string;
}
export interface ApplicationOptions {
2021-09-09 13:05:33 +08:00
database?: DatabaseOptions;
resourcer?: ResourcerOptions;
bodyParser?: any;
cors?: any;
dataWrapping?: boolean;
registerActions?: boolean;
i18n?: i18n | InitOptions;
}
2021-09-16 15:57:21 +08:00
interface DefaultState {
currentUser?: any;
[key: string]: any;
}
interface DefaultContext {
db: Database;
resourcer: Resourcer;
[key: string]: any;
}
interface MiddlewareOptions {
name?: string;
resourceName?: string;
resourceNames?: string[];
insertBefore?: string;
insertAfter?: string;
}
interface ActionsOptions {
resourceName?: string;
resourceNames?: string[];
}
feat: database next (#130) * FIX: database test with sqlite * more types * filter test * split filter parser * filter test * filter test: hasMany * define inverse association for belongsTo & hasMany * chore: console.log * repository count method * chore: Collection * repository filter & appends & fields & expect * repository: sort option * chore: test * add: test * find & findAndCount * chore: test * database-next: update guard * database-next: update guard associationKeysToBeUpdate * chore: comment * update-guard OneToOne Association * has one repository * support through table value * belongs to many repository * has many repository * has many repository find * fix: has many find and count * clean code * add count method * chore: multiple relation * chore: single relation * repository find * relation repository builder * repository count * repository count test * fix test * close db afterEach test * sort with associations * repository update * has many repository: destroy * belongs to many repository: destroy * add transaction decorator * belongs to many with transaction * has many with transaction * clean types * clean types * clean types * repository transaction * fix test * single relation repository with transaction * single relation repository with transaction * fix: test * fix: option parser fields append * fix: typo * fix: string type * fix: import * collection field methods * cleanup * collection sync * fix: import * fix: test * collection update field * collection update options * database hook * database test * database event test * update database event * add async emmit mixin * async model event * database import * fix: model hook type * fix: collection event * recall model.init on collection update * skip redefine collection test * skip collection model update * add model hook class * global model event support * chore * chore * change utils import * add field types * database import * more import test * test case * fix: through model init... * bugfix * fix * update database import * collection sync by foreachModel * fix collection model sync * update * add field types * custom operator * sqlite array field * postgresql array field * array query escape * mysql array operators * date operators * array field sqlite fix * association operator * date operator empty & notEmpty * fix: fields import * fix array field nested association * filter parse prepare * fix test * string field empty * add date operator test * field option types * fix typo * fix: operator name conflict * rename function Co-authored-by: Chareice <chareice@live.com>
2021-12-06 21:12:54 +08:00
export class Application<StateT = DefaultState, ContextT = DefaultContext>
extends Koa
implements AsyncEmitter
{
2021-09-14 11:09:26 +08:00
public readonly db: Database;
public readonly resourcer: Resourcer;
public readonly cli: Command;
public readonly i18n: i18n;
2021-09-14 11:09:26 +08:00
protected plugins = new Map<string, Plugin>();
constructor(options: ApplicationOptions) {
super();
2021-09-09 13:05:33 +08:00
this.db = createDatabase(options);
this.resourcer = createResourcer(options);
this.cli = createCli(this, options);
this.i18n = createI18n(options);
registerMiddlewares(this, options);
if (options.registerActions !== false) {
registerActions(this);
2021-09-09 13:05:33 +08:00
}
2020-12-18 19:54:53 +08:00
}
2021-09-16 15:57:21 +08:00
use<NewStateT = {}, NewContextT = {}>(
middleware: Koa.Middleware<StateT & NewStateT, ContextT & NewContextT>,
options?: MiddlewareOptions,
2021-09-23 00:16:04 +08:00
) {
2021-09-16 15:57:21 +08:00
// @ts-ignore
return super.use(middleware);
}
2021-09-14 11:09:26 +08:00
collection(options: TableOptions) {
return this.db.table(options);
}
resource(options: ResourceOptions) {
return this.resourcer.define(options);
}
2021-09-16 15:57:21 +08:00
actions(handlers: any, options?: ActionsOptions) {
2021-09-16 00:38:48 +08:00
return this.resourcer.registerActions(handlers);
}
2021-09-14 11:09:26 +08:00
command(nameAndArgs: string, opts?: CommandOptions) {
return this.cli.command(nameAndArgs, opts);
}
findCommand(name: string): Command {
return (this.cli as any)._findCommand(name);
}
2021-10-01 23:31:49 +08:00
plugin(options?: PluginType | PluginOptions, ext?: PluginOptions): Plugin {
2021-09-23 00:16:04 +08:00
if (typeof options === 'string') {
2021-10-01 23:31:49 +08:00
return this.plugin(require(options).default, ext);
2021-09-14 11:09:26 +08:00
}
let instance: Plugin;
2021-09-23 00:16:04 +08:00
if (typeof options === 'function') {
try {
2021-09-14 11:09:26 +08:00
// @ts-ignore
2021-09-23 00:16:04 +08:00
instance = new options({
name: options.name,
2021-10-01 23:31:49 +08:00
...ext,
2021-09-23 00:16:04 +08:00
app: this,
});
if (!(instance instanceof Plugin)) {
throw new Error('plugin must be instanceof Plugin');
}
} catch (err) {
// console.log(err);
instance = new Plugin({
name: options.name,
2021-10-01 23:31:49 +08:00
...ext,
2021-09-23 00:16:04 +08:00
// @ts-ignore
load: options,
2021-09-14 11:09:26 +08:00
app: this,
});
}
2021-09-23 00:16:04 +08:00
} else if (typeof options === 'object') {
const plugin = options.plugin || Plugin;
instance = new plugin({
name: options.plugin ? plugin.name : undefined,
2021-09-14 11:09:26 +08:00
...options,
2021-10-01 23:31:49 +08:00
...ext,
2021-09-14 11:09:26 +08:00
app: this,
});
}
const name = instance.getName();
if (this.plugins.has(name)) {
throw new Error(`plugin name [${name}] is repeated`);
}
this.plugins.set(name, instance);
return instance;
}
async load() {
await this.emitAsync('plugins.beforeLoad');
for (const [name, plugin] of this.plugins) {
await this.emitAsync(`plugins.${name}.beforeLoad`);
await plugin.load();
await this.emitAsync(`plugins.${name}.afterLoad`);
}
await this.emitAsync('plugins.afterLoad');
}
2021-09-16 00:38:48 +08:00
async parse(argv = process.argv) {
2021-09-28 00:18:09 +08:00
await this.load();
return this.cli.parseAsync(argv);
2020-12-18 19:54:53 +08:00
}
2021-09-09 13:05:33 +08:00
async destroy() {
2021-09-14 11:09:26 +08:00
await this.db.close();
2021-09-09 13:05:33 +08:00
}
feat: database next (#130) * FIX: database test with sqlite * more types * filter test * split filter parser * filter test * filter test: hasMany * define inverse association for belongsTo & hasMany * chore: console.log * repository count method * chore: Collection * repository filter & appends & fields & expect * repository: sort option * chore: test * add: test * find & findAndCount * chore: test * database-next: update guard * database-next: update guard associationKeysToBeUpdate * chore: comment * update-guard OneToOne Association * has one repository * support through table value * belongs to many repository * has many repository * has many repository find * fix: has many find and count * clean code * add count method * chore: multiple relation * chore: single relation * repository find * relation repository builder * repository count * repository count test * fix test * close db afterEach test * sort with associations * repository update * has many repository: destroy * belongs to many repository: destroy * add transaction decorator * belongs to many with transaction * has many with transaction * clean types * clean types * clean types * repository transaction * fix test * single relation repository with transaction * single relation repository with transaction * fix: test * fix: option parser fields append * fix: typo * fix: string type * fix: import * collection field methods * cleanup * collection sync * fix: import * fix: test * collection update field * collection update options * database hook * database test * database event test * update database event * add async emmit mixin * async model event * database import * fix: model hook type * fix: collection event * recall model.init on collection update * skip redefine collection test * skip collection model update * add model hook class * global model event support * chore * chore * change utils import * add field types * database import * more import test * test case * fix: through model init... * bugfix * fix * update database import * collection sync by foreachModel * fix collection model sync * update * add field types * custom operator * sqlite array field * postgresql array field * array query escape * mysql array operators * date operators * array field sqlite fix * association operator * date operator empty & notEmpty * fix: fields import * fix array field nested association * filter parse prepare * fix test * string field empty * add date operator test * field option types * fix typo * fix: operator name conflict * rename function Co-authored-by: Chareice <chareice@live.com>
2021-12-06 21:12:54 +08:00
emitAsync: (event: string | symbol, ...args: any[]) => Promise<boolean>;
}
feat: database next (#130) * FIX: database test with sqlite * more types * filter test * split filter parser * filter test * filter test: hasMany * define inverse association for belongsTo & hasMany * chore: console.log * repository count method * chore: Collection * repository filter & appends & fields & expect * repository: sort option * chore: test * add: test * find & findAndCount * chore: test * database-next: update guard * database-next: update guard associationKeysToBeUpdate * chore: comment * update-guard OneToOne Association * has one repository * support through table value * belongs to many repository * has many repository * has many repository find * fix: has many find and count * clean code * add count method * chore: multiple relation * chore: single relation * repository find * relation repository builder * repository count * repository count test * fix test * close db afterEach test * sort with associations * repository update * has many repository: destroy * belongs to many repository: destroy * add transaction decorator * belongs to many with transaction * has many with transaction * clean types * clean types * clean types * repository transaction * fix test * single relation repository with transaction * single relation repository with transaction * fix: test * fix: option parser fields append * fix: typo * fix: string type * fix: import * collection field methods * cleanup * collection sync * fix: import * fix: test * collection update field * collection update options * database hook * database test * database event test * update database event * add async emmit mixin * async model event * database import * fix: model hook type * fix: collection event * recall model.init on collection update * skip redefine collection test * skip collection model update * add model hook class * global model event support * chore * chore * change utils import * add field types * database import * more import test * test case * fix: through model init... * bugfix * fix * update database import * collection sync by foreachModel * fix collection model sync * update * add field types * custom operator * sqlite array field * postgresql array field * array query escape * mysql array operators * date operators * array field sqlite fix * association operator * date operator empty & notEmpty * fix: fields import * fix array field nested association * filter parse prepare * fix test * string field empty * add date operator test * field option types * fix typo * fix: operator name conflict * rename function Co-authored-by: Chareice <chareice@live.com>
2021-12-06 21:12:54 +08:00
applyMixins(Application, [AsyncEmitter]);
export default Application;