feat: improve code

This commit is contained in:
chenos 2021-09-09 23:57:01 +08:00
parent 99d33a0241
commit 336e0b17b8
17 changed files with 59 additions and 240 deletions

View File

@ -1,9 +1,10 @@
import Server from '@nocobase/server'; import Server from '@nocobase/server';
import { registerActions } from '@nocobase/actions';
import dotenv from 'dotenv'; import dotenv from 'dotenv';
import path from 'path'; import path from 'path';
const start = Date.now(); const start = Date.now();
console.log('startAt', new Date().toUTCString()); console.log('starting... ', new Date().toUTCString());
dotenv.config({ dotenv.config({
path: path.resolve(__dirname, '../../../../.env'), path: path.resolve(__dirname, '../../../../.env'),
@ -39,11 +40,17 @@ const api = new Server({
resourcer: { resourcer: {
prefix: '/api', prefix: '/api',
}, },
dataWrapping: true,
}); });
console.log(`@nocobase/preset-nocobase/${__filename.endsWith('.ts') ? 'src' : 'lib'}/index`); registerActions(api);
api.registerPlugin('@nocobase/preset-nocobase', require(`@nocobase/preset-nocobase/${__filename.endsWith('.ts') ? 'src' : 'lib'}/index`).default); const file = `${__filename.endsWith('.ts') ? 'src' : 'lib'}/index`;
api.registerPlugin(
'@nocobase/preset-nocobase',
require(`@nocobase/preset-nocobase/${file}`).default,
);
if (process.argv.length < 3) { if (process.argv.length < 3) {
process.argv.push('start', '--port', '2000'); process.argv.push('start', '--port', '2000');

View File

@ -461,36 +461,10 @@ type HookType =
* *
*/ */
public async close() { public async close() {
this.removeAllListeners();
return this.sequelize.close(); return this.sequelize.close();
} }
/**
* hook
*
* @param hookType
* @param fn
*/
public addHook(hookType: HookType | string, fn: Function) {
const hooks = this.hooks[hookType] || [];
hooks.push(fn);
this.hooks[hookType] = hooks;
}
/**
* hook
*
* @param hookType
* @param args
*/
public async runHooks(hookType: HookType | string, ...args) {
const hooks = this.hooks[hookType] || [];
for (const hook of hooks) {
if (typeof hook === 'function') {
await hook(...args);
}
}
}
public getFieldByPath(fieldPath: string) { public getFieldByPath(fieldPath: string) {
const [tableName, fieldName] = fieldPath.split('.'); const [tableName, fieldName] = fieldPath.split('.');
return this.getTable(tableName).getField(fieldName); return this.getTable(tableName).getField(fieldName);

View File

@ -221,7 +221,8 @@ export type ColumnOptions = AbstractFieldOptions
| JsonOptions | JsonOptions
| VirtualOptions | VirtualOptions
| FormulaOptions | FormulaOptions
| ReferenceOptions; | ReferenceOptions
| SortOptions;
export type ElementOptions = BooleanOptions export type ElementOptions = BooleanOptions
| IntegerOptions | IntegerOptions
@ -236,7 +237,8 @@ export type ElementOptions = BooleanOptions
| DateOnlyOptions | DateOnlyOptions
| ArrayOptions | ArrayOptions
| JsonOptions | JsonOptions
| VirtualOptions; | VirtualOptions
| SortOptions;
export type RelationOptions = HasOneOptions | HasManyOptions | BelongsToOptions | BelongsToManyOptions; export type RelationOptions = HasOneOptions | HasManyOptions | BelongsToOptions | BelongsToManyOptions;

View File

@ -530,7 +530,7 @@ export abstract class Model extends SequelizeModel {
}); });
} }
await this.database.runHooks('afterUpdateAssociations', this, { await this.database.emitAsync('afterUpdateAssociations', this, {
...options, ...options,
transaction, transaction,
}); });

View File

@ -139,7 +139,7 @@ export class Table {
constructor(options: TableOptions, context: TabelContext) { constructor(options: TableOptions, context: TabelContext) {
const { database } = context; const { database } = context;
database.runHooks('beforeTableInit', options); database.emit('beforeTableInit', options);
const { const {
model, model,
fields = [], fields = [],
@ -157,7 +157,7 @@ export class Table {
// this.modelInit('modelOnly'); // this.modelInit('modelOnly');
this.setFields(fields); this.setFields(fields);
this.initSortable(); this.initSortable();
database.runHooks('afterTableInit', this); database.emit('afterTableInit', this);
} }
public initSortable() { public initSortable() {
@ -312,7 +312,7 @@ export class Table {
* @param reinitialize * @param reinitialize
*/ */
public addField(options: FieldOptions, reinitialize: Reinitialize = true) { public addField(options: FieldOptions, reinitialize: Reinitialize = true) {
this.database.runHooks('beforeAddField', options, this); this.database.emit('beforeAddField', options, this);
const { name, index } = options; const { name, index } = options;
const field = buildField(options, { const field = buildField(options, {
sourceTable: this, sourceTable: this,
@ -348,7 +348,7 @@ export class Table {
this.modelAttributes[name] = field.getAttributeOptions(); this.modelAttributes[name] = field.getAttributeOptions();
} }
this.modelInit(reinitialize); this.modelInit(reinitialize);
this.database.runHooks('afterAddField', field, this); this.database.emit('afterAddField', field, this);
return field; return field;
} }

View File

@ -9,7 +9,7 @@
}, },
"devDependencies": { "devDependencies": {
"@nocobase/actions": "^0.4.0-alpha.7", "@nocobase/actions": "^0.4.0-alpha.7",
"@nocobase/server": "^0.4.0-alpha.7" "@nocobase/test": "^0.4.0-alpha.7"
}, },
"gitHead": "f0b335ac30f29f25c95d7d137655fa64d8d67f1e" "gitHead": "f0b335ac30f29f25c95d7d137655fa64d8d67f1e"
} }

View File

@ -1,15 +1,22 @@
import Database from '@nocobase/database'; import Database from '@nocobase/database';
import Application from '@nocobase/server'; import { registerActions } from '@nocobase/actions';
import { getApp, getAPI, getAgent } from '.'; import { mockServer, MockServer } from '@nocobase/test';
import logPlugin from '../server';
describe('hook', () => { describe('hook', () => {
let app: Application; let api: MockServer;
let db: Database; let db: Database;
let api;
beforeEach(async () => { beforeEach(async () => {
app = await getApp(); api = mockServer();
db = app.database; api.registerPlugin({
collections: require('@nocobase/plugin-collections/src/server').default,
users: require('@nocobase/plugin-users/src/server').default,
logs: logPlugin,
});
registerActions(api);
await api.loadPlugins();
db = api.database;
db.table({ db.table({
name: 'posts', name: 'posts',
logging: true, logging: true,
@ -28,14 +35,11 @@ describe('hook', () => {
await db.sync(); await db.sync();
const User = db.getModel('users'); const User = db.getModel('users');
const user = await User.create({ nickname: 'a', token: 'token1' }); const user = await User.create({ nickname: 'a', token: 'token1' });
console.log('beforeEach', user); api.agent().set('Authorization', `Bearer ${user.token}`);
const userAgent = getAgent(app);
userAgent.set('Authorization', `Bearer ${user.token}`);
api = getAPI(userAgent);
}); });
afterEach(async () => { afterEach(async () => {
await db.close(); await api.destroy();
}); });
it('database', async () => { it('database', async () => {

View File

@ -1,122 +0,0 @@
import path from 'path';
import qs from 'qs';
import supertest from 'supertest';
import bodyParser from 'koa-bodyparser';
import { Dialect } from 'sequelize';
import Database from '@nocobase/database';
import { actions, middlewares } from '@nocobase/actions';
import { Application } from '@nocobase/server';
import middleware from '@nocobase/server/src/middleware';
import plugin from '../server';
function getTestKey() {
const { id } = require.main;
const key = id
.replace(`${process.env.PWD}/packages`, '')
.replace(/src\/__tests__/g, '')
.replace('.test.ts', '')
.replace(/[^\w]/g, '_')
.replace(/_+/g, '_');
return key
}
const config = {
username: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_DATABASE,
host: process.env.DB_HOST,
port: Number.parseInt(process.env.DB_PORT, 10),
dialect: process.env.DB_DIALECT as Dialect,
logging: process.env.DB_LOG_SQL === 'on',
sync: {
force: true,
alter: {
drop: true,
},
},
hooks: {
beforeDefine(columns, model) {
model.tableName = `${getTestKey()}_${model.tableName || model.name.plural}`;
}
},
};
export function getDatabase() {
return new Database(config);
};
export async function getApp(): Promise<Application> {
const app = new Application({
database: config,
resourcer: {
prefix: '/api',
},
});
app.registerPlugin({
collections: path.resolve(__dirname, '../../../plugin-collections'),
users: path.resolve(__dirname, '../../../plugin-users'),
logs: plugin
});
await app.loadPlugins();
await app.database.sync();
return app;
}
interface ActionParams {
resourceKey?: string | number;
// resourceName?: string;
// associatedName?: string;
associatedKey?: string | number;
fields?: any;
filter?: any;
values?: any;
[key: string]: any;
}
interface Handler {
get: (params?: ActionParams) => Promise<supertest.Response>;
list: (params?: ActionParams) => Promise<supertest.Response>;
create: (params?: ActionParams) => Promise<supertest.Response>;
update: (params?: ActionParams) => Promise<supertest.Response>;
destroy: (params?: ActionParams) => Promise<supertest.Response>;
[name: string]: (params?: ActionParams) => Promise<supertest.Response>;
}
export interface Agent {
resource: (name: string) => Handler;
}
export function getAgent(app: Application) {
return supertest.agent(app.callback());
}
export function getAPI(agent) {
return {
resource(name: string): any {
return new Proxy({}, {
get(target, method: string, receiver) {
return (params: ActionParams = {}) => {
const { associatedKey, resourceKey, values = {}, filePath, ...restParams } = params;
let url = `/api/${name}`;
if (associatedKey) {
url = `/api/${name.split('.').join(`/${associatedKey}/`)}`;
}
url += `:${method as string}`;
if (resourceKey) {
url += `/${resourceKey}`;
}
switch (method) {
case 'list':
case 'get':
return agent.get(`${url}?${qs.stringify(restParams)}`);
default:
return agent.post(`${url}?${qs.stringify(restParams)}`).send(values);
}
}
}
});
}
};
}

View File

@ -1,15 +0,0 @@
import { TableOptions } from "@nocobase/database";
export default {
name: 'comments',
fields: [
{
type: 'string',
name: 'content',
},
{
type: 'belongsTo',
name: 'post',
},
]
} as TableOptions;

View File

@ -1,22 +0,0 @@
import { TableOptions } from "@nocobase/database";
export default {
name: 'posts',
// 目前默认就带了
// createdBy: true,
fields: [
{
type: 'string',
name: 'title',
},
{
type: 'string',
name: 'status',
defaultValue: 'draft',
},
{
type: 'hasMany',
name: 'comments',
}
]
} as TableOptions;

View File

@ -12,18 +12,18 @@ export default {
type: 'belongsTo', type: 'belongsTo',
name: 'log', name: 'log',
target: 'action_logs', target: 'action_logs',
foreignKey: 'log_id', foreignKey: 'action_log_id',
}, },
{ {
type: 'jsonb', type: 'json',
name: 'field', name: 'field',
}, },
{ {
type: 'jsonb', type: 'json',
name: 'before', name: 'before',
}, },
{ {
type: 'jsonb', type: 'json',
name: 'after', name: 'after',
} }
], ],

View File

@ -18,12 +18,16 @@ export default {
target: 'users', target: 'users',
}, },
{ {
type: 'belongsTo', type: 'string',
name: 'collection', name: 'collection_name',
target: 'collections',
targetKey: 'name',
constraints: false,
}, },
// {
// type: 'belongsTo',
// name: 'collection',
// target: 'collections',
// targetKey: 'name',
// constraints: false,
// },
{ {
type: 'string', type: 'string',
name: 'type', name: 'type',
@ -36,7 +40,7 @@ export default {
type: 'hasMany', type: 'hasMany',
name: 'changes', name: 'changes',
target: 'action_changes', target: 'action_changes',
foreignKey: 'log_id', foreignKey: 'action_log_id',
} }
], ],
} as TableOptions; } as TableOptions;

View File

@ -1,7 +0,0 @@
import { extend } from '@nocobase/database';
// TODO(bug): collections 表创建关联字段有问题
export default extend({
name: 'collections',
logging: false
});

View File

@ -1,10 +1,7 @@
import { Model, ModelCtor } from '@nocobase/database'; import { actions, Context, Next } from '@nocobase/actions';
import { actions, middlewares } from '@nocobase/actions';
import { sort } from '@nocobase/actions/src/actions/common';
import { cloneDeep, omit } from 'lodash';
export const create = async (ctx: actions.Context, next: actions.Next) => { export const create = async (ctx: Context, next: Next) => {
await actions.common.create(ctx, async () => {}); await actions.create(ctx, async () => {});
const { associated } = ctx.action.params; const { associated } = ctx.action.params;
await ctx.body.generateReverseField(); await ctx.body.generateReverseField();
await associated.migrate(); await associated.migrate();

View File

@ -1,9 +1,6 @@
import { Model, ModelCtor } from '@nocobase/database'; import { actions, Context, Next } from '@nocobase/actions';
import { actions, middlewares } from '@nocobase/actions';
import { sort } from '@nocobase/actions/src/actions/common';
import { cloneDeep, omit } from 'lodash';
export const findAll = async (ctx: actions.Context, next: actions.Next) => { export const findAll = async (ctx: Context, next: Next) => {
const Collection = ctx.db.getModel('collections'); const Collection = ctx.db.getModel('collections');
const collections = await Collection.findAll(Collection.parseApiJson({ const collections = await Collection.findAll(Collection.parseApiJson({
sort: 'sort', sort: 'sort',
@ -16,7 +13,7 @@ export const findAll = async (ctx: actions.Context, next: actions.Next) => {
await next(); await next();
} }
export const createOrUpdate = async (ctx: actions.Context, next: actions.Next) => { export const createOrUpdate = async (ctx: Context, next: Next) => {
const { values } = ctx.action.params; const { values } = ctx.action.params;
const Collection = ctx.db.getModel('collections'); const Collection = ctx.db.getModel('collections');
let collection; let collection;
@ -55,4 +52,5 @@ export const createOrUpdate = async (ctx: actions.Context, next: actions.Next) =
throw error; throw error;
} }
ctx.body = collection; ctx.body = collection;
await next();
} }

View File

@ -11,8 +11,8 @@ export default async function (this: Application, options = {}) {
database.import({ database.import({
directory: path.resolve(__dirname, 'collections'), directory: path.resolve(__dirname, 'collections'),
}); });
this.on('server.beforeStart', async () => { this.on('plugins.afterLoad', async () => {
console.log('server.beforeStart'); console.log('plugins.afterLoad');
await database.getModel('collections').load(); await database.getModel('collections').load();
}); });
const [Collection, Field] = database.getModels(['collections', 'fields']); const [Collection, Field] = database.getModels(['collections', 'fields']);

View File

@ -10,7 +10,6 @@ import _ from 'lodash';
export interface ResourcerContext { export interface ResourcerContext {
resourcer?: Resourcer; resourcer?: Resourcer;
action?: Action; action?: Action;
params?: ParsedParams;
[key: string]: any; [key: string]: any;
} }