docs: update api docs (#973)
* docs: application * docs: application lifecycle * docs: database * docs: update * docs: repository * docs: repository * docs: plugin * docs: resourcer * docs: database * docs: acl * docs: actions * docs: repository * docs: api * docs: api * docs: api
This commit is contained in:
parent
a6eebb940f
commit
3aada8fe07
@ -1,4 +1,4 @@
|
||||
# ACL Role
|
||||
# ACLRole
|
||||
|
||||
ACLRole,ACL 系统中的用户角色类。在 ACL 系统中,通常使用 `acl.define` 定义角色。
|
||||
|
||||
|
@ -1,8 +1,29 @@
|
||||
# ACL
|
||||
|
||||
## 概览
|
||||
|
||||
ACL 为 Nocobase 中的权限控制模块。在 ACL 中注册角色、资源以及配置相应权限之后,即可对角色进行权限判断。
|
||||
|
||||
## 概念解释
|
||||
### 基本使用
|
||||
|
||||
```javascript
|
||||
const { ACL } = require('@nocobase/acl');
|
||||
|
||||
const acl = new ACL();
|
||||
|
||||
// 定义一个名称为 member 的角色
|
||||
const memberRole = acl.define({
|
||||
role: 'member',
|
||||
});
|
||||
|
||||
// 使 member 角色拥有 posts 资源的 list 权限
|
||||
memberRole.grantAction('posts:list');
|
||||
|
||||
acl.can('member', 'posts:list'); // true
|
||||
acl.can('member', 'posts:edit'); // null
|
||||
```
|
||||
|
||||
### 概念解释
|
||||
|
||||
* 角色 (`ACLRole`):权限判断的对象
|
||||
* 资源 (`ACLResource`):在 Nocobase ACL 中,资源通常对应一个数据库表,概念上可类比为 Restful API 中的 Resource。
|
||||
|
@ -1,20 +1,27 @@
|
||||
# 内置常用资源操作
|
||||
|
||||
## 概览
|
||||
|
||||
针对常用的 CRUD 等数据资源的操作,NocoBase 内置了对应操作方法,并通过数据表资源自动映射相关的操作。
|
||||
|
||||
所有的操作方法都是注册在 resourcer 实例上,也是标准兼容 Koa 的中间件函数(`(ctx, next) => Promise<void>`)。操作的参数由路由解析后附加在 `ctx.action` 对象上,后续参数相关介绍均基于此对象。
|
||||
```javascript
|
||||
import { Application } from "@nocobase/server";
|
||||
|
||||
通常情况下无需直接调用内置的 action 方法,在需要扩展默认操作行为时,可以在自定义的操作方法内调用默认方法。
|
||||
const app = new Application({
|
||||
database: {
|
||||
dialect: 'sqlite',
|
||||
storage: './db.sqlite',
|
||||
},
|
||||
registerActions: true // 注册内置资源操作,默认为 True
|
||||
});
|
||||
|
||||
## 包结构
|
||||
|
||||
可通过以下方式引入相关实体:
|
||||
|
||||
```ts
|
||||
import actions from '@nocobase/actions';
|
||||
```
|
||||
|
||||
## 单一数据资源操作
|
||||
|
||||
内置的操作方法都是注册在 `application` 中的 `resourcer` 实例上。
|
||||
通常情况下无需直接调用内置的 action 方法,在需要扩展默认操作行为时,可以在自定义的操作方法内调用默认方法。
|
||||
|
||||
## 资源操作
|
||||
|
||||
### `list()`
|
||||
|
||||
|
@ -1,13 +1,40 @@
|
||||
# Collection
|
||||
|
||||
数据表结构管理类。
|
||||
## 概览
|
||||
|
||||
大部分接口通常不会直接由开发者调用,除非进行较底层的扩展开发。
|
||||
`Collection` 用于定义系统中的数据模型,如模型名称、字段、索引、关联等信息。
|
||||
一般通过 `Database` 实例的 `collection` 方法作为代理入口调用。
|
||||
|
||||
```javascript
|
||||
const { Database } = require('@nocobase/database')
|
||||
|
||||
// 创建数据库实例
|
||||
const db = new Database({...});
|
||||
|
||||
// 定义数据模型
|
||||
db.collection({
|
||||
name: 'users',
|
||||
// 定义模型字段
|
||||
fields: [
|
||||
// 标量字段
|
||||
{
|
||||
name: 'name',
|
||||
type: 'string',
|
||||
},
|
||||
|
||||
// 关联字段
|
||||
{
|
||||
name: 'profile',
|
||||
type: 'hasOne' // 'hasMany', 'belongsTo', 'belongsToMany'
|
||||
}
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
更多字段类型请参考 [Fields](/api/database/field.md)。
|
||||
|
||||
## 构造函数
|
||||
|
||||
通常不会直接使用,主要通过 `Database` 实例的 `collection` 方法作为代理入口调用。
|
||||
|
||||
**签名**
|
||||
|
||||
* `constructor(options: CollectionOptions, context: CollectionContext)`
|
||||
|
@ -1,7 +1,11 @@
|
||||
# Field
|
||||
|
||||
## 概览
|
||||
|
||||
数据表字段管理类(抽象类)。同时是所有字段类型的基类,其他任意字段类型均通过继承该类来实现。
|
||||
|
||||
如何自定义字段可参考[扩展字段类型](/development/guide/collections-fields#扩展字段类型)
|
||||
|
||||
## 构造函数
|
||||
|
||||
通常不会直接由开发者调用,主要通过 `db.collection({ fields: [] })` 方法作为代理入口调用。
|
||||
|
@ -1,23 +1,106 @@
|
||||
# Database
|
||||
|
||||
NocoBase 内置的数据库访问类,通过封装 [Sequelize](https://sequelize.org/) 提供了更加简单的数据库访问接口和统一化的 JSON 数据库表配置方式,同时也提供了扩展字段类型和查询操作符的能力。
|
||||
## 概览
|
||||
|
||||
Database 类继承自 EventEmitter,可以通过 `db.on('event', callback)` 监听数据库事件,以及 `db.off('event', callback)` 移除监听。
|
||||
Database 是 Nocobase 提供的数据库交互工具,为无代码、低代码应用提供了非常方便的数据库交互功能。目前支持的数据库为:
|
||||
|
||||
## 包结构
|
||||
* SQLite 3.8.8+
|
||||
* MySQL 8.0.17+
|
||||
* PostgreSQL 10.0+
|
||||
|
||||
可通过以下方式引入相关实体:
|
||||
|
||||
```ts
|
||||
import Database, {
|
||||
Field,
|
||||
Collection,
|
||||
Repository,
|
||||
RelationRepository,
|
||||
extend
|
||||
} from '@nocobase/database';
|
||||
### 连接数据库
|
||||
|
||||
在 `Database` 构造函数中,可以通过传入 `options` 参数来配置数据库连接。
|
||||
|
||||
```javascript
|
||||
const { Database } = require('@nocobase/database');
|
||||
|
||||
// SQLite 数据库配置参数
|
||||
const database = new Database({
|
||||
dialect: 'sqlite',
|
||||
storage: 'path/to/database.sqlite'
|
||||
})
|
||||
|
||||
// MySQL \ PostgreSQL 数据库配置参数
|
||||
const database = new Database({
|
||||
dialect: /* 'postgres' 或者 'mysql' */,
|
||||
database: 'database',
|
||||
username: 'username',
|
||||
password: 'password',
|
||||
host: 'localhost',
|
||||
port: 'port'
|
||||
})
|
||||
|
||||
```
|
||||
|
||||
详细的配置参数请参考 [构造函数](#构造函数)。
|
||||
|
||||
### 数据模型定义
|
||||
|
||||
`Database` 通过 `Collection` 定义数据库结构,一个 `Collection` 对象代表了数据库中的一张表。
|
||||
|
||||
```javascript
|
||||
// 定义 Collection
|
||||
const UserCollection = database.collection({
|
||||
name: 'users',
|
||||
fields: [
|
||||
{
|
||||
name: 'name',
|
||||
type: 'string',
|
||||
},
|
||||
{
|
||||
name: 'age',
|
||||
type: 'integer',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
数据库结构定义完成之后,可使用 `sync()` 方法来同步数据库结构。
|
||||
|
||||
```javascript
|
||||
await database.sync();
|
||||
```
|
||||
|
||||
更加详细的 `Collection` 使用方法请参考 [Collection](/api/database/collection.md)。
|
||||
|
||||
### 数据读写
|
||||
|
||||
`Database` 通过 `Repository` 对数据进行操作。
|
||||
|
||||
```javascript
|
||||
|
||||
const UserRepository = UserCollection.repository();
|
||||
|
||||
// 创建
|
||||
await UserRepository.create({
|
||||
name: '张三',
|
||||
age: 18,
|
||||
});
|
||||
|
||||
// 查询
|
||||
const user = await UserRepository.findOne({
|
||||
filter: {
|
||||
name: '张三',
|
||||
},
|
||||
});
|
||||
|
||||
// 修改
|
||||
await UserRepository.update({
|
||||
values: {
|
||||
age: 20,
|
||||
},
|
||||
});
|
||||
|
||||
// 删除
|
||||
await UserRepository.destroy(user.id);
|
||||
```
|
||||
|
||||
更加详细的数据 CRUD 使用方法请参考 [Repository](/api/database/repository.md)。
|
||||
|
||||
|
||||
## 构造函数
|
||||
|
||||
**签名**
|
||||
@ -28,7 +111,6 @@ import Database, {
|
||||
|
||||
**参数**
|
||||
|
||||
`options` 参数与 [Sequelize 的构造参数](https://sequelize.org/api/v6/class/src/sequelize.js~sequelize#instance-constructor-constructor)一致的部分会透传至 Sequelize,同时 NocoBase 也会使用一些额外的参数:
|
||||
|
||||
| 参数名 | 类型 | 默认值 | 描述 |
|
||||
| --- | --- | --- | --- |
|
||||
@ -44,46 +126,6 @@ import Database, {
|
||||
| `options.tablePrefix?` | `string` | `''` | NocoBase 扩展,表名前缀 |
|
||||
| `options.migrator?` | `UmzugOptions` | `{}` | NocoBase 扩展,迁移管理器相关参数,参考 [Umzug](https://github.com/sequelize/umzug/blob/main/src/types.ts#L15) 实现 |
|
||||
|
||||
**示例**
|
||||
|
||||
```ts
|
||||
import Database from '@nocobase/database';
|
||||
|
||||
const app = new Database({
|
||||
dialect: 'mysql',
|
||||
host: 'localhost',
|
||||
port: 3306,
|
||||
username: 'root',
|
||||
password: '123456',
|
||||
database: 'test',
|
||||
tablePrefix: 'my_'
|
||||
});
|
||||
```
|
||||
|
||||
## 实例成员
|
||||
|
||||
### `sequelize`
|
||||
|
||||
初始化后的 Sequelize 实例,在需要使用 sequelize 底层方法时可以调用,相关信息可以直接参考 sequelize 的文档。
|
||||
|
||||
### `options`
|
||||
|
||||
初始化的配置参数,包含了 Sequelize 的配置参数和 NocoBase 的额外配置参数。
|
||||
|
||||
### `version`
|
||||
|
||||
连接的数据库的版本信息对象,可通过 `await db.version.satisfies(<sem_ver>)` 检查是否满足特定数据库版本要求。
|
||||
|
||||
**示例**
|
||||
|
||||
```ts
|
||||
const r = await this.db.version.satisfies({
|
||||
mysql: '>=8.0.17',
|
||||
sqlite: '3.x',
|
||||
postgres: '>=10',
|
||||
});
|
||||
```
|
||||
|
||||
## 迁移相关方法
|
||||
|
||||
### `addMigration()`
|
||||
|
@ -1,6 +1,6 @@
|
||||
# Filter Operators
|
||||
|
||||
用于 Repository 的 find、findOne、findAndCount、count 等 API 的 filter 参数里。如:
|
||||
用于 Repository 的 find、findOne、findAndCount、count 等 API 的 filter 参数中:
|
||||
|
||||
```ts
|
||||
const repository = db.getRepository('books');
|
||||
@ -14,9 +14,7 @@ repository.find({
|
||||
});
|
||||
```
|
||||
|
||||
相当于 Sequelize Where 查询的 [Op](https://sequelize.org/docs/v6/core-concepts/model-querying-basics/#operators) 对象。
|
||||
|
||||
为了支持 JSON 化,NocoBase 中将查询运算符转换为以 $ 为前缀的字符串标识。
|
||||
为了支持 JSON 化,NocoBase 中将查询运算符以 $ 为前缀的字符串标识。
|
||||
|
||||
另外,NocoBase 也提供了扩展运算符的 API,详见 [`db.registerOperators()`](../database#registeroperators)。
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
## BelongsToRepository
|
||||
|
||||
`BelongsToRepository` 是用于处理 `BelongsTo` 关系的 `Repository`,它提供了一些便捷的方法来处理 `BelongsTo` 关系。其接口与 [HasOneRepository](./has-one-repository.md) 一致。
|
||||
其接口与 [HasOneRepository](./has-one-repository.md) 一致。
|
||||
`BelongsToRepository` 是用于处理 `BelongsTo` 关系的 `Repository`,它提供了一些便捷的方法来处理 `BelongsTo` 关系。
|
||||
|
@ -1,4 +1,6 @@
|
||||
# HasOneRepository
|
||||
## 概览
|
||||
|
||||
`HasOneRepository` 为 `HasOne` 类型的关联 Repository。
|
||||
|
||||
```typescript
|
||||
@ -19,8 +21,14 @@ const user = await User.repository.create({
|
||||
values: { name: 'u1' },
|
||||
});
|
||||
|
||||
// 创建 HasOneRepository 实例
|
||||
const userProfileRepository = new HasOneRepository(User, 'profile', user.get('id'));
|
||||
|
||||
// 获取到关联 Repository
|
||||
const userProfileRepository = User.repository.relation('profile').of(user.get('id'));
|
||||
|
||||
// 也可直接初始化
|
||||
new HasOneRepository(User, 'profile', user.get('id'));
|
||||
|
||||
|
||||
|
||||
```
|
||||
|
||||
|
@ -1,6 +1,331 @@
|
||||
# Repository
|
||||
|
||||
数据表数据仓库管理类。大部分基于数据表的数据存取等操作均通过该类实现。
|
||||
## 概览
|
||||
|
||||
在一个给定的 `Collection` 对象上,可以获取到它的 `Repository` 对象来对数据表进行读写操作。
|
||||
|
||||
```javascript
|
||||
const { UserCollection } = require("./collections");
|
||||
|
||||
const UserRepository = UserCollection.repository;
|
||||
|
||||
const user = await UserRepository.findOne({
|
||||
filter: {
|
||||
id: 1
|
||||
},
|
||||
});
|
||||
|
||||
user.name = "new name";
|
||||
await user.save();
|
||||
```
|
||||
|
||||
### 查询
|
||||
|
||||
#### 基础查询
|
||||
|
||||
在 `Repository` 对象上,调用 `find*` 相关方法,可执行查询操作,查询方法都支持传入 `filter` 参数,用于过滤数据。
|
||||
|
||||
```javascript
|
||||
// SELECT * FROM users WHERE id = 1
|
||||
userRepository.find({
|
||||
filter: {
|
||||
id: 1
|
||||
}
|
||||
});
|
||||
|
||||
```
|
||||
#### 操作符
|
||||
|
||||
`Repository` 中的 `filter` 参数,还提供了多种操作符,执行更加多样的查询操作。
|
||||
|
||||
```javascript
|
||||
// SELECT * FROM users WHERE age > 18
|
||||
userRepository.find({
|
||||
filter: {
|
||||
age: {
|
||||
$gt: 18
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// SELECT * FROM users WHERE age > 18 OR name LIKE '%张%'
|
||||
userRepository.find({
|
||||
filter: {
|
||||
$or: [
|
||||
{ age: { $gt: 18 } },
|
||||
{ name: { $like: "%张%" } }
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
操作符的更多详细信息请参考 [Filter Operators](/api/database/operators)。
|
||||
|
||||
#### 字段控制
|
||||
|
||||
在查询操作时,通过 `fields`, `except`, `appends` 参数可以控制输出字段。
|
||||
|
||||
* `fields`: 指定输出字段
|
||||
* `except`: 排除输出字段
|
||||
* `appends`: 追加输出关联字段
|
||||
|
||||
```javascript
|
||||
// 获取的结果只包含 id 和 name 字段
|
||||
userRepository.find({
|
||||
fields: ["id", "name"],
|
||||
});
|
||||
|
||||
// 获取的结果不包含 password 字段
|
||||
userRepository.find({
|
||||
except: ["password"],
|
||||
});
|
||||
|
||||
// 获取的结果会包含关联对象 posts 的数据
|
||||
userRepository.find({
|
||||
appends: ["posts"],
|
||||
});
|
||||
```
|
||||
|
||||
#### 关联字段查询
|
||||
|
||||
`filter` 参数支持按关联字段进行过滤,例如:
|
||||
|
||||
```javascript
|
||||
// 查询 user 对象,其所关联的 posts 存在 title 为 'title1' 的对象
|
||||
userRepository.find({
|
||||
filter: {
|
||||
"posts.title": "post title"
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
关联字段也可进行嵌套
|
||||
|
||||
```javascript
|
||||
// 查询 user 对象,查询结果满足其 posts 的 comments 包含 keywords
|
||||
await userRepository.find({
|
||||
filter: {
|
||||
"posts.comments.content": {
|
||||
$like: "%keywords%"
|
||||
}
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
#### 排序
|
||||
|
||||
通过 `sort` 参数,可以对查询结果进行排序。
|
||||
|
||||
```javascript
|
||||
|
||||
// SELECT * FROM users ORDER BY age
|
||||
await userRepository.find({
|
||||
sort: 'age'
|
||||
});
|
||||
|
||||
|
||||
// SELECT * FROM users ORDER BY age DESC
|
||||
await userRepository.find({
|
||||
sort: '-age'
|
||||
});
|
||||
|
||||
// SELECT * FROM users ORDER BY age DESC, name ASC
|
||||
await userRepository.find({
|
||||
sort: ['-age', "name"],
|
||||
});
|
||||
```
|
||||
|
||||
也可按照关联对象的字段进行排序
|
||||
|
||||
```javascript
|
||||
await userRepository.find({
|
||||
sort: 'profile.createdAt'
|
||||
});
|
||||
```
|
||||
|
||||
### 创建
|
||||
|
||||
#### 基础创建
|
||||
|
||||
通过 `Repository` 创建新的数据对象。
|
||||
|
||||
```javascript
|
||||
|
||||
await userRepository.create({
|
||||
name: "张三",
|
||||
age: 18,
|
||||
});
|
||||
// INSERT INTO users (name, age) VALUES ('张三', 18)
|
||||
|
||||
|
||||
// 支持批量创建
|
||||
await userRepository.create([
|
||||
{
|
||||
name: "张三",
|
||||
age: 18,
|
||||
},
|
||||
{
|
||||
name: "李四",
|
||||
age: 20,
|
||||
},
|
||||
])
|
||||
|
||||
```
|
||||
|
||||
#### 创建关联
|
||||
|
||||
创建时可以同时创建关联对象,和查询类似,也支持关联对象的嵌套使用,例如:
|
||||
|
||||
```javascript
|
||||
await userRepository.create({
|
||||
name: "张三",
|
||||
age: 18,
|
||||
posts: [
|
||||
{
|
||||
title: "post title",
|
||||
content: "post content",
|
||||
tags: [
|
||||
{
|
||||
name: "tag1",
|
||||
},
|
||||
{
|
||||
name: "tag2",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
// 创建用户的同时,创建 post 与用户关联,创建 tags 与 post 相关联。
|
||||
```
|
||||
若关联对象已在数据库中,可传入其ID,创建时会建立与关联对象的关联关系。
|
||||
|
||||
```javascript
|
||||
const tag1 = await tagRepository.findOne({
|
||||
filter: {
|
||||
name: "tag1"
|
||||
},
|
||||
});
|
||||
|
||||
await userRepository.create({
|
||||
name: "张三",
|
||||
age: 18,
|
||||
posts: [
|
||||
{
|
||||
title: "post title",
|
||||
content: "post content",
|
||||
tags: [
|
||||
{
|
||||
id: tag1.id, // 建立与已存在关联对象的关联关系
|
||||
},
|
||||
{
|
||||
name: "tag2",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
### 更新
|
||||
|
||||
#### 基础更新
|
||||
|
||||
获取到数据对象后,可直接在数据对象(`Model`)上修改属性,然后调用 `save` 方法保存修改。
|
||||
|
||||
```javascript
|
||||
const user = await userRepository.findOne({
|
||||
filter: {
|
||||
name: "张三",
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
user.age = 20;
|
||||
await user.save();
|
||||
```
|
||||
|
||||
数据对象 `Model` 继承自 Sequelize Model,对 `Model` 的操作可参考 [Sequelize Model](https://sequelize.org/master/manual/model-basics.html)。
|
||||
|
||||
也可通过 `Repository` 更新数据:
|
||||
|
||||
```javascript
|
||||
// 修改满足筛选条件的数据记录
|
||||
await userRepository.update({
|
||||
filter: {
|
||||
name: "张三",
|
||||
},
|
||||
values: {
|
||||
age: 20,
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
更新时,可以通过 `whitelist` 、`blacklist` 参数控制更新字段,例如:
|
||||
|
||||
```javascript
|
||||
await userRepository.update({
|
||||
filter: {
|
||||
name: "张三",
|
||||
},
|
||||
values: {
|
||||
age: 20,
|
||||
name: "李四",
|
||||
},
|
||||
whitelist: ["age"], // 仅更新 age 字段
|
||||
});
|
||||
````
|
||||
|
||||
#### 更新关联字段
|
||||
|
||||
在更新时,可以设置关联对象,例如:
|
||||
|
||||
```javascript
|
||||
const tag1 = tagRepository.findOne({
|
||||
filter: {
|
||||
id: 1
|
||||
},
|
||||
});
|
||||
|
||||
await postRepository.update({
|
||||
filter: {
|
||||
id: 1
|
||||
},
|
||||
values: {
|
||||
title: "new post title",
|
||||
tags: [
|
||||
{
|
||||
id: tag1.id // 与 tag1 建立关联
|
||||
},
|
||||
{
|
||||
name: "tag2", // 创建新的 tag 并建立关联
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
await postRepository.update({
|
||||
filter: {
|
||||
id: 1
|
||||
},
|
||||
values: {
|
||||
tags: null // 解除 post 与 tags 的关联
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
### 删除
|
||||
|
||||
可调用 `Repository` 中的 `destroy()`方法进行删除操作。删除时需指定筛选条件:
|
||||
|
||||
```javascript
|
||||
await userRepository.destroy({
|
||||
filter: {
|
||||
status: "blocked",
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
## 构造函数
|
||||
|
||||
@ -56,7 +381,7 @@ await books.myQuery('SELECT * FROM books;');
|
||||
|
||||
### `find()`
|
||||
|
||||
从数据库查询特定条件的数据集。相当于 Sequelize 中的 `Model.findAll()`。
|
||||
从数据库查询数据集,可指定筛选条件、排序等。
|
||||
|
||||
**签名**
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
# 概览
|
||||
|
||||
| 模块 | 包名 | 描述 |
|
||||
| --------------------------------- | --------------------- | ------------------- |
|
||||
| [Server](/api/server) | `@nocobase/server` | 服务端应用 |
|
||||
| 模块 | 包名 | 描述 |
|
||||
|-----------------------------------| --------------------- | ------------------- |
|
||||
| [Server](/api/server/application) | `@nocobase/server` | 服务端应用 |
|
||||
| [Database](/api/database) | `@nocobase/database` | 数据库访问层 |
|
||||
| [Resourcer](/api/resourcer) | `@nocobase/resourcer` | 资源与路由映射 |
|
||||
| [ACL](/api/acl) | `@nocobase/acl` | 访问控制表 |
|
||||
|
@ -1,25 +1,57 @@
|
||||
# Resourcer
|
||||
|
||||
Resourcer 主要用于管理 API 资源与路由,也是 NocoBase 的内置模块,app 默认会自动创建一个 Resourcer 实例,大部分情况你可以通过 `app.resourcer` 访问。
|
||||
## 概览
|
||||
|
||||
资源路由管理器主要通过 [资源](/api/server/resourcer/resource) + [操作](/api/server/resourcer/action) 的概念定义服务端 API 接口,与 RESTful 的概念相似。大部分资源通过映射数据库表生成,包含常规的 CRUD 操作,以覆盖常见场景。但如果有额外需求,也可以在此基础上扩展更多的资源类型和操作类型。
|
||||
Nocobase 中的接口遵循面向资源的设计模式。Resourcer 主要用于管理 API 资源与路由。
|
||||
|
||||
## 包结构
|
||||
```javascript
|
||||
const Koa = require('koa');
|
||||
const { Resourcer } = require('@nocobase/resourcer');
|
||||
|
||||
可通过以下方式引入相关实体:
|
||||
const resourcer = new Resourcer();
|
||||
|
||||
```ts
|
||||
import Resourcer, {
|
||||
Resource,
|
||||
Action,
|
||||
Middleware,
|
||||
branch
|
||||
} from '@nocobase/resourcer';
|
||||
// 定义一个资源接口
|
||||
resourcer.define({
|
||||
name: 'users',
|
||||
actions: {
|
||||
async list(ctx) {
|
||||
ctx.body = [
|
||||
{
|
||||
name: "u1",
|
||||
age: 18
|
||||
},
|
||||
{
|
||||
name: "u2",
|
||||
age: 20
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
const app = new Koa();
|
||||
|
||||
// 可在 koa 实例中使用
|
||||
app.use(
|
||||
resourcer.middleware({
|
||||
prefix: '/api', // resourcer 路由前缀
|
||||
}),
|
||||
);
|
||||
|
||||
app.listen(3000);
|
||||
```
|
||||
|
||||
启动服务后,使用`curl`发起请求:
|
||||
```bash
|
||||
>$ curl localhost:3000/api/users
|
||||
[{"name":"u1","age":18},{"name":"u2","age":20}]
|
||||
```
|
||||
更多 Resourcer 的使用说明可参考[资源与操作](/development/guide/resources-actions)。 Resourcer 内置于 [NocoBase Application](/api/server/application#resourcer) ,可以通过 `app.resourcer` 访问。
|
||||
|
||||
|
||||
## 构造函数
|
||||
|
||||
用于创建 Resourcer 管理器实例。由于 app 默认创建一个内置实例,所以通常不会直接使用构造函数。
|
||||
用于创建 Resourcer 管理器实例。
|
||||
|
||||
**签名**
|
||||
|
||||
|
@ -1,6 +1,136 @@
|
||||
# Application
|
||||
|
||||
基于 [Koa](https://koajs.com/) 实现的 WEB 框架,兼容所有的 Koa 插件。
|
||||
## 概览
|
||||
|
||||
### Web服务
|
||||
Nocobase Application 是基于 [Koa](https://koajs.com/) 实现的 WEB 框架,兼容 Koa 的 API。
|
||||
|
||||
```javascript
|
||||
// index.js
|
||||
const { Application } = require('@nocobase/server');
|
||||
|
||||
// 创建App实例,并配置数据库连接信息
|
||||
const app = new Application({
|
||||
database: {
|
||||
dialect: 'sqlite',
|
||||
storage: ':memory:',
|
||||
}
|
||||
});
|
||||
|
||||
// 注册中间件 响应请求
|
||||
app.use(async ctx => {
|
||||
ctx.body = 'Hello World';
|
||||
});
|
||||
|
||||
// 以命令行模式启动
|
||||
app.runAsCLI();
|
||||
```
|
||||
|
||||
在命令行中运行 `node index.js start` 启动服务后,使用 `curl` 请求服务。
|
||||
|
||||
```bash
|
||||
$> curl localhost:3000
|
||||
Hello World
|
||||
```
|
||||
|
||||
### 命令行工具
|
||||
Nocobase Application 中也内置了 `cli commander`,可以当作命令行工具运行。
|
||||
|
||||
```javascript
|
||||
// cmd.js
|
||||
const {Application} = require('@nocobase/server');
|
||||
const app = new Application({
|
||||
database: {
|
||||
dialect: 'sqlite',
|
||||
storage: ':memory:',
|
||||
}
|
||||
});
|
||||
|
||||
app.cli.command('hello').action(async () => {
|
||||
console.log("hello world")
|
||||
});
|
||||
|
||||
app.runAsCLI()
|
||||
```
|
||||
|
||||
在命令行中运行
|
||||
|
||||
```bash
|
||||
$> node cmd.js hello
|
||||
hello world
|
||||
```
|
||||
|
||||
### 插件注入
|
||||
|
||||
Nocobase Application 被设计为高度可扩展的框架,可以编写插件注入到应用中扩展功能。
|
||||
例如上面的 Web 服务可以替换为插件形式。
|
||||
|
||||
```javascript
|
||||
const { Application, Plugin } = require('@nocobase/server');
|
||||
|
||||
// 通过继承 Plugin 类来编写插件
|
||||
class HelloWordPlugin extends Plugin {
|
||||
load() {
|
||||
this.app.use(async (ctx, next) => {
|
||||
ctx.body = "Hello World";
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const app = new Application({
|
||||
database: {
|
||||
dialect: 'sqlite',
|
||||
storage: ':memory:',
|
||||
}
|
||||
});
|
||||
|
||||
// 注入插件
|
||||
app.plugin(HelloWordPlugin, { name: 'hello-world-plugin'} );
|
||||
|
||||
app.runAsCLI()
|
||||
```
|
||||
|
||||
### 更多示例
|
||||
|
||||
更加详细的插件开发文档请参考 [插件开发](./plugin.md)。
|
||||
Application 类的更多示例可参考 [examples](https://github.com/nocobase/nocobase/blob/main/examples/index.md)
|
||||
|
||||
## 生命周期
|
||||
|
||||
根据不同运行模式,Application 有三种生命周期:
|
||||
|
||||
### 安装
|
||||
使用 `cli` 中的 `install` 命令调用安装。
|
||||
一般来说,插件在使用之前若需要在数据库中写入新表或者数据,都需要在安装时执行。在初次使用 Nocobase 时也需要调用安装。
|
||||
|
||||
* 调用 `load` 方法,载入已注册的插件。
|
||||
* 触发 `beforeInstall` 事件。
|
||||
* 调用 `db.sync` 方法,同步数据库。
|
||||
* 调用 `pm.install` 方法,执行已注册插件的 `install` 方法。
|
||||
* 写入 `nocobase` 版本。
|
||||
* 触发 `afterInstall`。
|
||||
* 调用 `stop` 方法,结束安装。
|
||||
|
||||
### 启动
|
||||
使用 `cli` 中的 `start` 命令来启动 Nocobase Web 服务。
|
||||
|
||||
* 调用 `load` 方法,载入已注册的插件。
|
||||
* 调用 `start` 方法
|
||||
* 触发 `beforeStart`
|
||||
* 启动端口监听
|
||||
* 触发 `afterStart`
|
||||
|
||||
### 更新
|
||||
|
||||
当需要更新 Nocobase 时,可使用 `cli` 中的 `upgrade` 命令。
|
||||
|
||||
* 调用 `load` 方法,载入已注册的插件。
|
||||
* 触发 `beforeUpgrade`。
|
||||
* 调用 `db.migrator.up` 方法,执行数据库迁移。
|
||||
* 调用 `db.sync` 方法,同步数据库。
|
||||
* 调用 `version.update` 方法,更新 `nocobase` 版本。
|
||||
* 触发 `afterUpgrade`。
|
||||
* 调用 `stop` 方法,结束更新。
|
||||
|
||||
## 构造函数
|
||||
|
||||
@ -32,29 +162,6 @@ interface ApplicationOptions {
|
||||
}
|
||||
```
|
||||
|
||||
**示例**
|
||||
|
||||
```ts
|
||||
import Application from '@nocobase/server';
|
||||
|
||||
const app = new Application({
|
||||
database: {
|
||||
dialect: 'mysql',
|
||||
host: 'localhost',
|
||||
port: 3306,
|
||||
username: 'root',
|
||||
password: '123456',
|
||||
database: 'test',
|
||||
},
|
||||
resourcer: {
|
||||
prefix: '/api',
|
||||
},
|
||||
cors: {
|
||||
origin: '*',
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## 实例成员
|
||||
|
||||
### `cli`
|
||||
|
@ -1,51 +1,40 @@
|
||||
# Plugin
|
||||
|
||||
## 示例
|
||||
## 概览
|
||||
|
||||
```ts
|
||||
const app = new Application();
|
||||
Nocobase 中的插件为 `Class` 的形式。如需自定义插件,需要继承 `Plugin` 类。
|
||||
|
||||
```typescript
|
||||
import { Plugin } from '@nocobase/server';
|
||||
|
||||
class MyPlugin extends Plugin {
|
||||
afterAdd() {}
|
||||
beforeLoad() {}
|
||||
load() {}
|
||||
install() {}
|
||||
afterEnable() {}
|
||||
afterDisable() {}
|
||||
remove() {}
|
||||
// ...
|
||||
}
|
||||
|
||||
app.plugin(MyPlugin, { name: 'my-plugin' });
|
||||
```
|
||||
|
||||
## 属性
|
||||
## 插件生命周期
|
||||
|
||||
### `options`
|
||||
|
||||
插件配置信息
|
||||
|
||||
### `name`
|
||||
|
||||
插件标识,只读
|
||||
|
||||
## 实例方法
|
||||
|
||||
### `afterAdd()`
|
||||
|
||||
插件 add/addStatic 之后
|
||||
每个插件都包含生命周期方法,你可以重写这些方法,以便于在运行过程中特定的阶段执行这些方法。
|
||||
生命周期方法将由 `Application` 在特定阶段调用,可参考 [`Application`生命周期](./application.md)。
|
||||
|
||||
### `beforeLoad()`
|
||||
|
||||
插件加载前,如事件或类注册
|
||||
插件加载前,如事件或类注册,在此可访问核心接口,其他插件此阶段不可用。
|
||||
|
||||
### `load()`
|
||||
|
||||
加载插件,配置之类
|
||||
加载插件,配置之类。在 `load` 中可调用其他插件实例,而在 `beforeLoad` 中是不行的。
|
||||
|
||||
### `install()`
|
||||
|
||||
插件安装逻辑,如初始化数据
|
||||
|
||||
### `afterAdd()`
|
||||
|
||||
插件 add/addStatic 之后
|
||||
|
||||
### `afterEnable()`
|
||||
|
||||
插件激活之后的逻辑
|
||||
|
@ -229,11 +229,10 @@ export extend({
|
||||
假设我们需要直接应用 Snowflake ID 生成算法,扩展出一个 `snowflake` 字段类型,我们可以创建一个 `fields/snowflake.ts` 文件:
|
||||
|
||||
```ts
|
||||
import { DataTypes } from 'sequelize';
|
||||
// 引入算法工具包
|
||||
import { Snowflake } from 'nodejs-snowflake';
|
||||
// 引入字段类型基类
|
||||
import { Field, BaseColumnFieldOptions } from '@nocobase/database';
|
||||
import { DataTypes, Field, BaseColumnFieldOptions } from '@nocobase/database';
|
||||
|
||||
export interface SnowflakeFieldOptions extends BaseColumnFieldOptions {
|
||||
type: 'snowflake';
|
||||
|
@ -43,7 +43,6 @@ export interface ApplicationOptions {
|
||||
|
||||
export interface DefaultState extends KoaDefaultState {
|
||||
currentUser?: any;
|
||||
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
@ -209,7 +208,6 @@ export class Application<StateT = DefaultState, ContextT = DefaultContext> exten
|
||||
this._eventsCount = [];
|
||||
this.removeAllListeners();
|
||||
this.middleware = new Toposort<any>();
|
||||
// this.context = Object.create(context);
|
||||
this.plugins = new Map<string, Plugin>();
|
||||
this._acl = createACL();
|
||||
if (this._db) {
|
||||
|
@ -175,6 +175,7 @@ export class PluginManager {
|
||||
throw new Error(`plugin name invalid`);
|
||||
}
|
||||
}
|
||||
|
||||
const instance = new plugin(this.app, {
|
||||
name,
|
||||
enabled: true,
|
||||
|
Loading…
Reference in New Issue
Block a user