feat: docs & examples
This commit is contained in:
parent
b7eb720eb4
commit
17db8b8afb
Binary file not shown.
Before Width: | Height: | Size: 56 KiB |
Binary file not shown.
Before Width: | Height: | Size: 76 KiB |
Binary file not shown.
Before Width: | Height: | Size: 77 KiB |
Binary file not shown.
Before Width: | Height: | Size: 130 KiB |
Binary file not shown.
Before Width: | Height: | Size: 146 KiB |
Binary file not shown.
Before Width: | Height: | Size: 176 KiB |
107
docs/index.md
107
docs/index.md
@ -1,17 +1,17 @@
|
|||||||
---
|
---
|
||||||
title: 介绍
|
title: NocoBase
|
||||||
toc: menu
|
toc: menu
|
||||||
---
|
---
|
||||||
|
|
||||||
# NocoBase
|
# NocoBase
|
||||||
|
|
||||||
考虑到大家是初次接触 NocoBase,开发文档的第一篇,先带大家了解基础概念。NocoBase 采用微内核架构,框架只保留核心,各类功能以插件形式扩展。
|
NocoBase 采用微内核架构,框架只保留核心,各类功能以插件形式扩展。
|
||||||
|
|
||||||
<img src="./NocoBase.png" style="max-width: 800px; width: 100%;">
|
<img src="./NocoBase.png" style="max-width: 800px; width: 100%;">
|
||||||
|
|
||||||
## 微服务 - Microservices
|
## 微服务 - Microservices
|
||||||
|
|
||||||
首先我们创建一个应用,新建一个 app.js 文件,代码如下:
|
为了更快的理解 NocoBase,我们先创建一个应用,新建一个 app.js 文件,代码如下:
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
const { Application } = require('@nocobase/server');
|
const { Application } = require('@nocobase/server');
|
||||||
@ -23,10 +23,10 @@ const app = new Application({
|
|||||||
// 配置一张 users 表
|
// 配置一张 users 表
|
||||||
app.collection({
|
app.collection({
|
||||||
name: 'users',
|
name: 'users',
|
||||||
schema: {
|
schema: [
|
||||||
username: 'string',
|
{ type: 'string', name: 'username' },
|
||||||
password: 'password',
|
{ type: 'password', name: 'password' }
|
||||||
},
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
// 解析 argv 参数,终端通过命令行进行不同操作
|
// 解析 argv 参数,终端通过命令行进行不同操作
|
||||||
@ -37,7 +37,7 @@ app.parse(process.argv);
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 根据配置生成数据库表结构
|
# 根据配置生成数据库表结构
|
||||||
node app.js db sync
|
node app.js db:sync
|
||||||
# 启动应用
|
# 启动应用
|
||||||
node app.js start --port=3000
|
node app.js start --port=3000
|
||||||
```
|
```
|
||||||
@ -113,18 +113,21 @@ await api.resource('users').logout();
|
|||||||
NocoBase 的 Application 继承了 Koa,集成了 DB 和 CLI,添加了一些必要的 API,这里列一些重点:
|
NocoBase 的 Application 继承了 Koa,集成了 DB 和 CLI,添加了一些必要的 API,这里列一些重点:
|
||||||
|
|
||||||
- `app.db`:数据库实例,每个 app 都有自己的 db。
|
- `app.db`:数据库实例,每个 app 都有自己的 db。
|
||||||
- `db.getTable()` 数据表/数据集配置
|
- `db.getCollection()` 数据表/数据集
|
||||||
- `db.getRepository()` 数据仓库
|
- `collection.schema` 数据结构
|
||||||
- `db.getModel()` 数据模型
|
- `collection.repository` 数据仓库
|
||||||
|
- `collection.model` 数据模型
|
||||||
- `db.on()` 添加事件监听,由 EventEmitter 提供
|
- `db.on()` 添加事件监听,由 EventEmitter 提供
|
||||||
- `db.emit()` 触发事件,由 EventEmitter 提供
|
- `db.emit()` 触发事件,由 EventEmitter 提供
|
||||||
- `db.emitAsync()` 触发异步事件
|
- `db.emitAsync()` 触发异步事件
|
||||||
- `app.cli`,commander 实例,提供命令行操作
|
- `app.cli`,Commander 实例,提供命令行操作
|
||||||
- `app.context`,上下文
|
- `app.context`,上下文
|
||||||
- `ctx.db`
|
- `ctx.db`
|
||||||
- `ctx.action`
|
- `ctx.action` 当前资源操作实例
|
||||||
|
- `action.params` 操作参数
|
||||||
|
- `action.mergeParams()` 参数合并方法
|
||||||
- `app.constructor()` 初始化
|
- `app.constructor()` 初始化
|
||||||
- `app.collection()` 定义数据 Schema,等同于 `app.db.table()`
|
- `app.collection()` 定义数据 Schema,等同于 `app.db.collection()`
|
||||||
- `app.resource()` 定义资源
|
- `app.resource()` 定义资源
|
||||||
- `app.actions()` 定义资源的操作方法
|
- `app.actions()` 定义资源的操作方法
|
||||||
- `app.on()` 添加事件监听,由 EventEmitter 提供
|
- `app.on()` 添加事件监听,由 EventEmitter 提供
|
||||||
@ -136,8 +139,6 @@ NocoBase 的 Application 继承了 Koa,集成了 DB 和 CLI,添加了一些
|
|||||||
- `app.load()` 载入配置,主要用于载入插件
|
- `app.load()` 载入配置,主要用于载入插件
|
||||||
- `app.parse()` 解析 argv 参数,写在最后,等同于 `app.cli.parseAsync()`
|
- `app.parse()` 解析 argv 参数,写在最后,等同于 `app.cli.parseAsync()`
|
||||||
|
|
||||||
经过几次改进,以上罗列的 API 趋近于稳定,但也可能有所变动。
|
|
||||||
|
|
||||||
## 数据集 - Collection
|
## 数据集 - Collection
|
||||||
|
|
||||||
NocoBase 通过 `app.collection()` 方法定义数据的 Schema,Schema 的类型包括:
|
NocoBase 通过 `app.collection()` 方法定义数据的 Schema,Schema 的类型包括:
|
||||||
@ -175,17 +176,9 @@ NocoBase 通过 `app.collection()` 方法定义数据的 Schema,Schema 的类
|
|||||||
app.collection({
|
app.collection({
|
||||||
name: 'users',
|
name: 'users',
|
||||||
schema: {
|
schema: {
|
||||||
username: {
|
username: { type: 'string', unique: true },
|
||||||
type: 'string',
|
password: { type: 'password', unique: true },
|
||||||
unique: true,
|
posts: { type: 'hasMany' },
|
||||||
},
|
|
||||||
password: {
|
|
||||||
type: 'password',
|
|
||||||
unique: true,
|
|
||||||
},
|
|
||||||
posts: {
|
|
||||||
type: 'hasMany',
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -197,10 +190,7 @@ app.collection({
|
|||||||
content: 'text',
|
content: 'text',
|
||||||
tags: 'belongsToMany',
|
tags: 'belongsToMany',
|
||||||
comments: 'hasMany',
|
comments: 'hasMany',
|
||||||
author: {
|
author: { type: 'belongsTo', target: 'users' },
|
||||||
type: 'belongsTo',
|
|
||||||
target: 'users',
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -225,13 +215,6 @@ app.collection({
|
|||||||
|
|
||||||
除了通过 `app.collection()` 配置 schema,也可以直接调用 api 插入或修改 schema,collection 的核心 API 有:
|
除了通过 `app.collection()` 配置 schema,也可以直接调用 api 插入或修改 schema,collection 的核心 API 有:
|
||||||
|
|
||||||
- `collection.model` 当前 collection 的数据模型
|
|
||||||
- `collection.repository` 当前 collection 的数据仓库
|
|
||||||
- `repository.findAll()`
|
|
||||||
- `repository.findOne()`
|
|
||||||
- `repository.create()`
|
|
||||||
- `repository.update()`
|
|
||||||
- `repository.destroy()`
|
|
||||||
- `collection.schema` 当前 collection 的数据结构
|
- `collection.schema` 当前 collection 的数据结构
|
||||||
- `schema.has()` 判断是否存在
|
- `schema.has()` 判断是否存在
|
||||||
- `schema.get()` 获取
|
- `schema.get()` 获取
|
||||||
@ -239,8 +222,15 @@ app.collection({
|
|||||||
- `schema.merge()` 添加、或指定 key path 替换
|
- `schema.merge()` 添加、或指定 key path 替换
|
||||||
- `schema.replace()` 替换
|
- `schema.replace()` 替换
|
||||||
- `schema.delete()` 删除
|
- `schema.delete()` 删除
|
||||||
|
- `collection.repository` 当前 collection 的数据仓库
|
||||||
|
- `repository.findAll()`
|
||||||
|
- `repository.findOne()`
|
||||||
|
- `repository.create()`
|
||||||
|
- `repository.update()`
|
||||||
|
- `repository.destroy()`
|
||||||
|
- `collection.model` 当前 collection 的数据模型
|
||||||
|
|
||||||
如:
|
Schema 示例:
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
const collection = app.db.getCollection('posts');
|
const collection = app.db.getCollection('posts');
|
||||||
@ -269,7 +259,7 @@ collection.schema.merge({
|
|||||||
await collection.sync();
|
await collection.sync();
|
||||||
```
|
```
|
||||||
|
|
||||||
存在外键关联时,也无需顾虑建表和字段的顺序,`db sync` 时会自动处理。`db sync` 之后,就可以往表里写入数据了。可以使用 Repository 或 Model 操作。
|
`db:sync` 是非常常用的命令行之一,数据库根据 collection 的 schema 生成表结构。更多详情见 CLI 章节。`db:sync` 之后,就可以往表里写入数据了,可以使用 Repository 或 Model 操作。
|
||||||
|
|
||||||
- Repository 初步提供了 findAll、findOne、create、update、destroy 核心操作方法。
|
- Repository 初步提供了 findAll、findOne、create、update、destroy 核心操作方法。
|
||||||
- Model 为 Sequelize.Model,详细使用说明可以查看 Sequelize 文档。
|
- Model 为 Sequelize.Model,详细使用说明可以查看 Sequelize 文档。
|
||||||
@ -344,7 +334,7 @@ await user.updateAssociations({
|
|||||||
|
|
||||||
Resource 是互联网资源,互联网资源都对应一个地址。客户端请求资源地址,服务器响应请求,在这里「请求」就是一种「操作」,在 REST 里通过判断请求方法(GET/POST/PUT/DELETE)来识别具体的操作,但是请求方法局限性比较大,如上文提到的登录、注册、注销就无法用 REST API 的方式表示。为了解决这类问题,NocoBase 以 `<resourceName>:<actionName>` 格式表示资源的操作。在关系模型的世界里,关系无处不在,基于关系,NocoBase 又延伸了关系资源的概念,对应关系资源的操作的格式为 `<associatedName>.<resourceName>:<actionName>`。
|
Resource 是互联网资源,互联网资源都对应一个地址。客户端请求资源地址,服务器响应请求,在这里「请求」就是一种「操作」,在 REST 里通过判断请求方法(GET/POST/PUT/DELETE)来识别具体的操作,但是请求方法局限性比较大,如上文提到的登录、注册、注销就无法用 REST API 的方式表示。为了解决这类问题,NocoBase 以 `<resourceName>:<actionName>` 格式表示资源的操作。在关系模型的世界里,关系无处不在,基于关系,NocoBase 又延伸了关系资源的概念,对应关系资源的操作的格式为 `<associatedName>.<resourceName>:<actionName>`。
|
||||||
|
|
||||||
Collection 会自动同步给 Resource,上文 Collection 章节定义的 Schema,提炼的资源有:
|
Collection 会自动同步给 Resource,如上文 Collection 章节定义的 Schema,可以提炼的资源有:
|
||||||
|
|
||||||
- `users`
|
- `users`
|
||||||
- `users.posts`
|
- `users.posts`
|
||||||
@ -492,7 +482,7 @@ async function (ctx, next) {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
多来源参数合并,以 `filter` 参数为例。如:客户端请求日期 2021-09-15 创建的文章
|
`ctx.action.mergeParams()` 主要用于多来源参数合并,以 `filter` 参数为例。如:客户端请求日期 2021-09-15 创建的文章
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
GET /api/posts:list?filter={"created_at": "2021-09-15"}
|
GET /api/posts:list?filter={"created_at": "2021-09-15"}
|
||||||
@ -533,6 +523,7 @@ app.use(async (ctx, next) => {
|
|||||||
async function list(ctx, next) {
|
async function list(ctx, next) {
|
||||||
// list 操作中获取到的 filter
|
// list 操作中获取到的 filter
|
||||||
console.log(ctx.params.filter);
|
console.log(ctx.params.filter);
|
||||||
|
// filter 是特殊的 and 合并
|
||||||
// {
|
// {
|
||||||
// and: [
|
// and: [
|
||||||
// { created_at: '2021-09-15' },
|
// { created_at: '2021-09-15' },
|
||||||
@ -576,27 +567,31 @@ app.use(async (ctx, next) => {
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
弥补 `app.use()` 不足,加了个 `middleware()` 适配器,可以用于限定 resource 和 action。除此之外,也可以控制中间件的插入位置。
|
与 `koa.use(middleware)` 略有不同,`app.use(middleware, options)` 多了个 options 参数,可以用于限定 resource 和 action,也可以用于控制中间件的插入位置。
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
import { middleware } from '@nocobase/server';
|
import { middleware } from '@nocobase/server';
|
||||||
|
|
||||||
app.use(middleware(async (ctx, next) => {}, {
|
app.use(async (ctx, next) => {}, {
|
||||||
name: 'middlewareName1',
|
name: 'middlewareName1',
|
||||||
resourceNames: [],
|
resourceNames: [], // 作用于资源内所有 actions
|
||||||
actionNames: [],
|
actionNames: [
|
||||||
|
'list', // 全部 list action
|
||||||
|
'users:list', // 仅 users 资源的 list action,
|
||||||
|
],
|
||||||
insertBefore: '',
|
insertBefore: '',
|
||||||
insertAfter: '',
|
insertAfter: '',
|
||||||
}));
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
## 命令行 - CLI
|
## 命令行 - CLI
|
||||||
|
|
||||||
Application 除了可以做 HTTP Server 以外,也可以是 CLI(内置了 Commander)。目前内置的命令有:
|
Application 除了可以做 HTTP Server 以外,也是 CLI(内置了 Commander)。目前内置的命令有:
|
||||||
|
|
||||||
- `db sync --force` 用于配置与数据库表结构同步
|
- `init` 初始化
|
||||||
|
- `db:sync --force` 用于配置与数据库表结构同步
|
||||||
- `start --port` 启动应用
|
- `start --port` 启动应用
|
||||||
- `plugin` 插件相关
|
- `plugin:**` 插件相关
|
||||||
|
|
||||||
自定义:
|
自定义:
|
||||||
|
|
||||||
@ -624,10 +619,8 @@ app.command('foo').action(async () => {
|
|||||||
- CLI
|
- CLI
|
||||||
- `app.cli` commander 实例
|
- `app.cli` commander 实例
|
||||||
- `app.command()` 等同于 `app.cli.command()`
|
- `app.command()` 等同于 `app.cli.command()`
|
||||||
- Plugin
|
|
||||||
- `app.plugin` 添加插件
|
|
||||||
|
|
||||||
基于以上扩展接口,进一步提供了模块化、可插拔的插件,可以通过 `app.plugin()` 添加。完整的插件包括安装、升级、激活、载入、禁用、卸载流程,但是并不是所有插件都要这完整的流程。比如:
|
基于以上扩展接口,进一步提供了模块化、可插拔的插件,可以通过 `app.plugin()` 添加。插件的流程包括安装、升级、激活、载入、禁用、卸载,不需要的流程可缺失。如:
|
||||||
|
|
||||||
**最简单的插件**
|
**最简单的插件**
|
||||||
|
|
||||||
@ -709,10 +702,10 @@ app.plugin('@nocobase/plugin-action-logs');
|
|||||||
**插件 CLI**
|
**插件 CLI**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
plugin install pluginName1
|
plugin:install pluginName1
|
||||||
plugin unstall pluginName1
|
plugin:unstall pluginName1
|
||||||
plugin activate pluginName1
|
plugin:activate pluginName1
|
||||||
plugin deactivate pluginName1
|
plugin:deactivate pluginName1
|
||||||
```
|
```
|
||||||
|
|
||||||
目前已有的插件:
|
目前已有的插件:
|
||||||
|
@ -1,16 +1,12 @@
|
|||||||
import { Application } from '@nocobase/server/src';
|
import { Application } from '@nocobase/server/src';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import mount from 'koa-mount';
|
|
||||||
import compose from 'koa-compose';
|
import compose from 'koa-compose';
|
||||||
|
|
||||||
const keys = __dirname.split(path.sep);
|
const keys = __dirname.split(path.sep);
|
||||||
const slug = keys[keys.length - 2];
|
const slug = keys[keys.length - 2];
|
||||||
|
|
||||||
const apps = new Map<string, Application>();
|
|
||||||
|
|
||||||
function createApp(opts) {
|
function createApp(opts) {
|
||||||
const { name, prefix } = opts;
|
const { name } = opts;
|
||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
database: {
|
database: {
|
||||||
username: process.env.DB_USER,
|
username: process.env.DB_USER,
|
||||||
@ -23,28 +19,27 @@ function createApp(opts) {
|
|||||||
charset: 'utf8mb4',
|
charset: 'utf8mb4',
|
||||||
collate: 'utf8mb4_unicode_ci',
|
collate: 'utf8mb4_unicode_ci',
|
||||||
},
|
},
|
||||||
|
appName: name,
|
||||||
hooks: {
|
hooks: {
|
||||||
beforeDefine(model, options) {
|
beforeDefine(model, options) {
|
||||||
options.tableName = `examples_${slug}_${name}_${options.tableName || options.name.plural}`;
|
options.tableName = `examples_${slug}_${name}_${
|
||||||
|
options.tableName || options.name.plural
|
||||||
|
}`;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
resourcer: {
|
resourcer: {
|
||||||
prefix,
|
prefix: `/api/examples/${slug}/${name}`,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
console.log(options);
|
|
||||||
const app = new Application(options);
|
const app = new Application(options);
|
||||||
if (name) {
|
|
||||||
apps.set(name, app);
|
|
||||||
}
|
|
||||||
app.resource({
|
app.resource({
|
||||||
name: 'server',
|
name: 'saas',
|
||||||
actions: {
|
actions: {
|
||||||
async getInfo(ctx, next) {
|
async getInfo(ctx, next) {
|
||||||
ctx.body = name;
|
ctx.body = ctx.db.options;
|
||||||
await next();
|
await next();
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
app.collection({
|
app.collection({
|
||||||
@ -57,44 +52,51 @@ function createApp(opts) {
|
|||||||
return app;
|
return app;
|
||||||
}
|
}
|
||||||
|
|
||||||
const app = createApp({
|
const saas = createApp({
|
||||||
name: 'main',
|
name: 'main',
|
||||||
prefix: `/api/examples/${slug}/main`
|
|
||||||
});
|
});
|
||||||
|
|
||||||
app.collection({
|
saas['apps'] = new Map<string, Application>();
|
||||||
|
|
||||||
|
saas.collection({
|
||||||
name: 'applications',
|
name: 'applications',
|
||||||
fields: [
|
fields: [
|
||||||
{ type: 'string', name: 'name', unique: true },
|
{ type: 'string', name: 'name', unique: true },
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
app.command('app-create').argument('<appName>').action(async (appName) => {
|
saas
|
||||||
const App = app.db.getModel('applications');
|
.command('app:create')
|
||||||
const server = await App.create({
|
.argument('<appName>')
|
||||||
|
.action(async (appName) => {
|
||||||
|
const App = saas.db.getModel('applications');
|
||||||
|
const model = await App.create({
|
||||||
name: appName,
|
name: appName,
|
||||||
});
|
});
|
||||||
const api = createApp({
|
const app = createApp({
|
||||||
name: appName,
|
name: appName,
|
||||||
prefix: `/api/examples/${slug}/${appName}`,
|
|
||||||
});
|
});
|
||||||
await api.db.sync();
|
await app.db.sync();
|
||||||
await api.destroy();
|
|
||||||
console.log(server.toJSON());
|
|
||||||
await app.destroy();
|
await app.destroy();
|
||||||
|
await saas.destroy();
|
||||||
|
console.log(model.toJSON());
|
||||||
});
|
});
|
||||||
|
|
||||||
app.command('dbsync')
|
saas
|
||||||
|
.command('db:sync')
|
||||||
.option('-f, --force')
|
.option('-f, --force')
|
||||||
.option('--app [app]')
|
.option('--app [app]')
|
||||||
.action(async (...args) => {
|
.action(async (...args) => {
|
||||||
const cli = args.pop();
|
const cli = args.pop();
|
||||||
const force = cli.opts()?.force;
|
const force = cli.opts()?.force;
|
||||||
const appName = cli.opts()?.app;
|
const appName = cli.opts()?.app;
|
||||||
console.log('ac ac', cli.opts());
|
const app = !appName
|
||||||
const api = apps.get(appName) || app;
|
? saas
|
||||||
await api.load();
|
: createApp({
|
||||||
await api.db.sync(
|
name: appName,
|
||||||
|
});
|
||||||
|
await app.load();
|
||||||
|
await app.db.sync(
|
||||||
force
|
force
|
||||||
? {
|
? {
|
||||||
force: true,
|
force: true,
|
||||||
@ -104,31 +106,49 @@ app.command('dbsync')
|
|||||||
}
|
}
|
||||||
: {},
|
: {},
|
||||||
);
|
);
|
||||||
await api.destroy();
|
await app.destroy();
|
||||||
|
await saas.destroy();
|
||||||
});
|
});
|
||||||
|
|
||||||
app.use(async function(ctx, next) {
|
function multiApps({ getAppName }) {
|
||||||
const appName = ctx.path.split('/')[4];
|
return async function (ctx, next) {
|
||||||
if (appName === 'main') {
|
const appName = getAppName(ctx);
|
||||||
|
if (!appName) {
|
||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
const App = ctx.db.getModel('applications');
|
const App = ctx.db.getModel('applications');
|
||||||
const model = await App.findOne({
|
const model = await App.findOne({
|
||||||
where: { name: appName },
|
where: { name: appName },
|
||||||
});
|
});
|
||||||
console.log({ appName, model })
|
console.log({ appName, model });
|
||||||
if (!model) {
|
if (!model) {
|
||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
|
const apps = ctx.app.apps;
|
||||||
if (!apps.has(appName)) {
|
if (!apps.has(appName)) {
|
||||||
const app1 = createApp({
|
const app = createApp({
|
||||||
name: appName,
|
name: appName,
|
||||||
prefix: `/api/examples/${slug}/${appName}`
|
|
||||||
});
|
});
|
||||||
apps.set(appName, app1);
|
apps.set(appName, app);
|
||||||
|
}
|
||||||
|
const saas = apps.get(appName);
|
||||||
|
await compose(saas.middleware)(ctx, async () => {});
|
||||||
|
};
|
||||||
}
|
}
|
||||||
const server = apps.get(appName);
|
|
||||||
await compose(server.middleware)(ctx, next);
|
|
||||||
});
|
|
||||||
|
|
||||||
app.parse(process.argv);
|
saas.use(
|
||||||
|
multiApps({
|
||||||
|
getAppName(ctx) {
|
||||||
|
const appName = ctx.path.split('/')[4];
|
||||||
|
return appName === 'main' ? null : appName;
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
// saas.use(async (ctx, next) => {
|
||||||
|
// ctx.body = 'aaaaa';
|
||||||
|
// console.log(ctx.db.options);
|
||||||
|
// await next();
|
||||||
|
// });
|
||||||
|
|
||||||
|
saas.parse(process.argv);
|
||||||
|
@ -20,7 +20,34 @@ export interface ApplicationOptions {
|
|||||||
dataWrapping?: boolean;
|
dataWrapping?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Application extends Koa {
|
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[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Application<
|
||||||
|
StateT = DefaultState,
|
||||||
|
ContextT = DefaultContext
|
||||||
|
> extends Koa {
|
||||||
|
|
||||||
public readonly db: Database;
|
public readonly db: Database;
|
||||||
|
|
||||||
@ -55,7 +82,7 @@ export class Application extends Koa {
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
this.use(async (ctx, next) => {
|
this.use<DefaultState, DefaultContext>(async (ctx, next) => {
|
||||||
ctx.db = this.db;
|
ctx.db = this.db;
|
||||||
ctx.resourcer = this.resourcer;
|
ctx.resourcer = this.resourcer;
|
||||||
await next();
|
await next();
|
||||||
@ -71,7 +98,7 @@ export class Application extends Koa {
|
|||||||
registerActions(this);
|
registerActions(this);
|
||||||
|
|
||||||
this.cli
|
this.cli
|
||||||
.command('db sync')
|
.command('db:sync')
|
||||||
.option('-f, --force')
|
.option('-f, --force')
|
||||||
.action(async (...args) => {
|
.action(async (...args) => {
|
||||||
console.log('db sync...');
|
console.log('db sync...');
|
||||||
@ -92,7 +119,7 @@ export class Application extends Koa {
|
|||||||
});
|
});
|
||||||
|
|
||||||
this.cli
|
this.cli
|
||||||
.command('db init')
|
.command('init')
|
||||||
// .option('-f, --force')
|
// .option('-f, --force')
|
||||||
.action(async (...args) => {
|
.action(async (...args) => {
|
||||||
const cli = args.pop();
|
const cli = args.pop();
|
||||||
@ -121,6 +148,15 @@ export class Application extends Koa {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
use<NewStateT = {}, NewContextT = {}>(
|
||||||
|
middleware: Koa.Middleware<StateT & NewStateT, ContextT & NewContextT>,
|
||||||
|
options?: MiddlewareOptions,
|
||||||
|
): Application<StateT & NewStateT, ContextT & NewContextT> {
|
||||||
|
// @ts-ignore
|
||||||
|
return super.use(middleware);
|
||||||
|
}
|
||||||
|
|
||||||
collection(options: TableOptions) {
|
collection(options: TableOptions) {
|
||||||
return this.db.table(options);
|
return this.db.table(options);
|
||||||
}
|
}
|
||||||
@ -129,7 +165,7 @@ export class Application extends Koa {
|
|||||||
return this.resourcer.define(options);
|
return this.resourcer.define(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
actions(handlers: any) {
|
actions(handlers: any, options?: ActionsOptions) {
|
||||||
return this.resourcer.registerActions(handlers);
|
return this.resourcer.registerActions(handlers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user