feat: improve code
This commit is contained in:
parent
99d33a0241
commit
336e0b17b8
@ -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');
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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,
|
||||||
});
|
});
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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"
|
||||||
}
|
}
|
||||||
|
@ -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 () => {
|
||||||
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
@ -1,15 +0,0 @@
|
|||||||
import { TableOptions } from "@nocobase/database";
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'comments',
|
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
type: 'string',
|
|
||||||
name: 'content',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'belongsTo',
|
|
||||||
name: 'post',
|
|
||||||
},
|
|
||||||
]
|
|
||||||
} as TableOptions;
|
|
@ -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;
|
|
@ -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',
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
@ -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;
|
||||||
|
@ -1,7 +0,0 @@
|
|||||||
import { extend } from '@nocobase/database';
|
|
||||||
|
|
||||||
// TODO(bug): collections 表创建关联字段有问题
|
|
||||||
export default extend({
|
|
||||||
name: 'collections',
|
|
||||||
logging: false
|
|
||||||
});
|
|
@ -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();
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
@ -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']);
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user