Doc/db repository (#896)

* docs: update database repository docs

* docs: single relation repository docs

* docs: has many relation repository docs

* docs: belongs to many  relation repository docs

* docs: acl

* docs: actions

Co-authored-by: chenos <chenlinxh@gmail.com>
This commit is contained in:
ChengLei Shao 2022-10-16 19:16:14 +08:00 committed by GitHub
parent 247dd89973
commit 4d6363b47a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 752 additions and 540 deletions

View File

@ -1,19 +0,0 @@
# ACLAvailableAction
用于表示一个可用 ACL Action 的数据结构。
## 类方法
### `constructor(public name: string, public options: AvailableActionOptions)`
实例化 ACLAvailableAction
**参数**
* name: string - 动作名称
* options: AvailableActionOptions
* displayName - action 显示名称
* aliases - action 别名
* resource - action 所属资源名称
* onNewRecord - action 是否是在创建新的数据库记录
* allowConfigureFields - action 是否允许配置字段

View File

@ -1,24 +0,0 @@
# ACLAvailableStrategy
ACL 角色的权限策略,可以使用其判断角色是否有权限访问资源。
## 类方法
### `constructor(acl: ACL, options: AvailableStrategyOptions)`
构造函数,创建一个 `ACLAvailableStrategy` 实例。
### `allow(resourceName: string, actionName: string)`
判断此策略是否允许给定的资源和动作通过鉴权。
## 基础数据结构
### `AvailableStrategyOptions`
策略定义参数,用以描述一组权限配置规则。
* displayName - 策略名称
* allowConfigure - 此策略是否拥有 **配置资源** 的权限,设置此项为`true`之后,请求判断在 `ACL` 中注册成为 `configResources` 资源的权限,会返回通过。
* actions - 策略内的 actions 列表,支持通配符 `*`
* resource - 策略内的 resource 定义,支持通配符 `*`

View File

@ -2,56 +2,56 @@
ACLResourceACL 系统中的资源类。在 ACL 系统中,为用户授予权限时会自动创建对应的资源。 ACLResourceACL 系统中的资源类。在 ACL 系统中,为用户授予权限时会自动创建对应的资源。
## 基础数据结构
### `ResourceActions`
Action 集合对象:
* key 表示 action 的名称
* value 表示 action 的配置参数,见 [`RoleActionParams`](#RoleActionParams)。
**定义**
```typescript
type ResourceActions = { [key: string]: RoleActionParams };
```
## 类方法 ## 类方法
### `constructor(options: AclResourceOptions)` ### `constructor()`
构造函数
创建 `ACLResource` 实例 **签名**
* `constructor(options: AclResourceOptions)`
**AclResourceOptions 参数** **类型**
```typescript
type ResourceActions = { [key: string]: RoleActionParams };
* options - 资源配置参数 interface AclResourceOptions {
* name - 资源名称 name: string; // 资源名称
* role - 资源所属角色 role: ACLRole; // 资源所属角色
* actions - ResourceActions 对象,定义资源的 Action actions?: ResourceActions;
}
```
**详细信息**
`RoleActionParams`详见 [`aclRole.grantAction`](./acl-role.md#grantaction)
### `getActions()` ### `getActions()`
获取资源的所有 Action返回结果为 `ResourceActions` 对象。 获取资源的所有 Action返回结果为 `ResourceActions` 对象。
### `getAction(name: string)` ### `getAction()`
根据名称返回 Action 的参数配置,返回结果为 `RoleActionParams` 对象。 根据名称返回 Action 的参数配置,返回结果为 `RoleActionParams` 对象。
## `setAction(name: string, params: RoleActionParams)` **详细信息**
`RoleActionParams`详见 [`aclRole.grantAction`](./acl-role.md#grantaction)
### `setAction()`
在资源内部设置一个 Action 的参数配置,返回结果为 `RoleActionParams` 对象。 在资源内部设置一个 Action 的参数配置,返回结果为 `RoleActionParams` 对象。
**参数** **签名**
* `setAction(name: string, params: RoleActionParams)`
**详细信息**
* name - 要设置的 action 名称 * name - 要设置的 action 名称
* params - [`RoleActionParams`](#RoleActionParams) * `RoleActionParams`详见 [`aclRole.grantAction`](./acl-role.md#grantaction)
## `setActions(actions: ResourceActions)` ### `setActions()`
**签名**
* `setActions(actions: ResourceActions)`
批量调用 `setAction` 的便捷方法 批量调用 `setAction` 的便捷方法
**参数**
* actions: [RoleActionParams](#RoleActionParams)

View File

@ -4,22 +4,38 @@ ACLRoleACL 系统中的用户角色类。在 ACL 系统中,通常使用 `ac
## 类方法 ## 类方法
### `constructor(public acl: ACL, public name: string)` ### `constructor()`
构造函数
**签名**
* `constructor(public acl: ACL, public name: string)`
**详细信息**
* acl - ACL 实例 * acl - ACL 实例
* name - 角色名称 * name - 角色名称
### `grantAction(path: string, options?: RoleActionParams)` ### `grantAction()`
为角色授予 Action 权限 为角色授予 Action 权限
**签名**
* `grantAction(path: string, options?: RoleActionParams)`
**类型**
```typescript
interface RoleActionParams {
fields?: string[];
filter?: any;
own?: boolean;
whitelist?: string[];
blacklist?: string[];
[key: string]: any;
}
```
**详细信息**
* path - 资源Action路径`posts:edit`,表示 `posts` 资源的 `edit` Action, 资源名称和 Action 之间使用 `:` 冒号分隔。 * path - 资源Action路径`posts:edit`,表示 `posts` 资源的 `edit` Action, 资源名称和 Action 之间使用 `:` 冒号分隔。
* options? - 配置参数,见 [`RoleActionParams`](#RoleActionParams)。
## 参数
### `RoleActionParams`
RoleActionParams 为授权时,对应 action 的可配置参数,用以实现更细粒度的权限控制。 RoleActionParams 为授权时,对应 action 的可配置参数,用以实现更细粒度的权限控制。
@ -68,3 +84,4 @@ RoleActionParams 为授权时,对应 action 的可配置参数,用以实现
``` ```
* whitelist - 白名单,只有在白名单中的字段才能被访问 * whitelist - 白名单,只有在白名单中的字段才能被访问
* blacklist - 黑名单,黑名单中的字段不能被访问 * blacklist - 黑名单,黑名单中的字段不能被访问

View File

@ -1,32 +1,16 @@
# ACL # ACL
ACL 为权限管理类,系统中的角色与资源都可以在 ACL 中进行注册 ACL 为 Nocobase 中的权限控制模块。在 ACL 中注册角色、资源以及配置相应权限之后,即可对角色进行权限判断
## 成员变量 ## 概念解释
### `availableActions: Map<string, AclAvailableAction>` * 角色 (`ACLRole`):权限判断的对象
* 资源 (`ACLResource`):在 Nocobase ACL 中,资源通常对应一个数据库表,概念上可类比为 Restful API 中的 Resource。
* Action对资源的操作`create`、`read`、`update`、`delete` 等。
* 策略 (`ACLAvailableStrategy`): 通常每个角色都有自己的权限策略,策略中定义了默认情况下的用户权限。
* 授权:在 `ACLRole` 实例中调用 `grantAction` 函数,为角色授予 `Action` 的访问权限。
* 鉴权:在 `ACL` 实例中调用 `can` 函数,函数返回结果既为用户的鉴权结果。
ACL 内的 `AclAvailableAction` 名称映射。
### `availableStrategy: Map<string, ACLAvailableStrategy>`
ACL 内的 [`ACLAvailableStrategy`](#ACLAvailableStrategy) 名称映射。
### `middlewares`
ACL 鉴权中间件。
### `roles: Map<string, ACLRole>`
ACL 内的 `ACLRole` 名称映射。
### `actionAlias: Map<string, string>`
Action 别名映射。
### `configResources: Array<string>`
配置资源列表。
## 类方法 ## 类方法
@ -39,11 +23,27 @@ import { ACL } from '@nocobase/database';
const acl = new ACL(); const acl = new ACL();
``` ```
### `define(options: DefineOptions)`
定义系统角色 ### `define()`
**DefineOptions 参数** 定义一个 ACL 角色
**签名**
* `define(options: DefineOptions): ACLRole`
**类型**
```typescript
interface DefineOptions {
role: string;
allowConfigure?: boolean;
strategy?: string | AvailableStrategyOptions;
actions?: ResourceActionsOptions;
routes?: any;
}
```
**详细信息**
* `role` - 角色名称 * `role` - 角色名称
@ -57,9 +57,9 @@ acl.define({
* `allowConfigure` - 是否允许配置权限 * `allowConfigure` - 是否允许配置权限
* `strategy` - 角色的权限策略 * `strategy` - 角色的权限策略
* 可以为 `string`,为要使用的策略名,表示使用已定义的策略。 * 可以为 `string`,为要使用的策略名,表示使用已定义的策略。
* 可以为 `AvailableStrategyOptions`,为该角色定义一个新的策略。 * 可以为 `AvailableStrategyOptions`,为该角色定义一个新的策略,参考[`setAvailableActions()`](#setavailableactions)
* `actions` - 定义角色时,可传入角色可访问的 `actions` 对象, * `actions` - 定义角色时,可传入角色可访问的 `actions` 对象,
之后会依次调用 `aclRole.grantAction` 授予资源权限。详见 [`ResourceActionsOptions`](#ResourceActionsOptions) 之后会依次调用 `aclRole.grantAction` 授予资源权限。详见 [`aclRole.grantAction`](./acl-role.md#grantaction)
```typescript ```typescript
acl.define({ acl.define({
@ -76,34 +76,52 @@ const role = acl.define({
role.grantAction('posts:edit', {}); role.grantAction('posts:edit', {});
``` ```
### `getRole(name: string): ACLRole` ### `getRole()`
根据角色名称返回角色对象 根据角色名称返回已注册的角色对象
### `removeRole(name: string)` **签名**
* `getRole(name: string): ACLRole`
### `removeRole()`
根据角色名称移除角色 根据角色名称移除角色
### `can({ role, resource, action }: CanArgs): CanResult | null` **签名**
* `removeRole(name: string)`
鉴权函数,调用返回为`null`时,表示角色无权限,反之返回`CanResult`对象,表示角色有权限。 ### `can()`
鉴权函数
`can` 方法首先会判断角色是否有注册对应的 `Action` 权限,如果没有则会去判断角色的 `strategy` 是否匹配. **签名**
* `can(options: CanArgs): CanResult | null`
**CanArgs 参数** **类型**
* role - 角色名称
* resource - 资源名称
* action - 操作名称
**CanResult 参数**
* role - 角色名称
* resource - 资源名称
* action - 操作名称
* params - 注册权限时传入的参数
```typescript ```typescript
interface CanArgs {
role: string; // 角色名称
resource: string; // 资源名称
action: string; //操作名称
}
interface CanResult {
role: string; // 角色名称
resource: string; // 资源名称
action: string; // 操作名称
params?: any; // 注册权限时传入的参数
}
```
**详细信息**
`can` 方法首先会判断角色是否有注册对应的 `Action` 权限,如果没有则会去判断角色的 `strategy` 是否匹配。
调用返回为`null`时,表示角色无权限,反之返回 `CanResult`对象,表示角色有权限。
**示例**
```typescript
// 定义角色,注册权限
acl.define({ acl.define({
role: 'admin', role: 'admin',
actions: { actions: {
@ -135,64 +153,30 @@ acl.can({
action: 'destroy', action: 'destroy',
}); // null }); // null
``` ```
### `use(fn: any)` ### `use()`
**签名**
* `use(fn: any)`
向 middlewares 中添加中间件函数。 向 middlewares 中添加中间件函数。
### `middleware()` ### `middleware()`
返回一个中间件函数,用于在 `@nocobase/server` 中使用。使用此 `middleware` 之后,`@nocobase/server` 在每次请求处理之前都会进行权限判断。 返回一个中间件函数,用于在 `@nocobase/server` 中使用。使用此 `middleware` 之后,`@nocobase/server` 在每次请求处理之前都会进行权限判断。
### `setAvailableStrategy(name: string, options: AvailableStrategyOptions)` ### `allow()`
注册一个可用的权限策略 设置资源为可公开访问
### `registerConfigResource(name: string)` **签名**
* `allow(resourceName: string, actionNames: string[] | string, condition?: string | ConditionFunc)`
将传入的资源名称设置为**配置资源**。配置资源是指这样的一种资源,这些资源的改动会调用`ACL`中的角色、权限注册相关方法,例如用户、权限、角色等,这些资源就需要被设置为配置资源。
### `registerConfigResources(names: string[])`
`registerConfigResource` 的批量方法
### `isConfigResource(name: string)`
判断传入的资源名称是否为配置资源
### `setAvailableAction(name: string, options: AvailableActionOptions = {})`
设置 ACL 中有效的 Action 名称。
**参数**
* name - action 名称
* options - action 选项
* displayName - action 显示名称
* aliases - action 别名
* resource - action 所属资源名称
* onNewRecord - action 是否是在创建新的数据库记录
* allowConfigureFields - action 是否允许配置字段
### `getAvailableAction(name: string)`
获取 ACL 中有效的 Action。
### `setAvailableStrategy(name: string, options: AvailableStrategyOptions)`
设置可用的权限策略,详见 [`AvailableStrategyOptions`](#AvailableStrategyOptions)
### `allow(resourceName: string, actionNames: string[] | string, condition?: string | ConditionFunc)`
在不指定角色的情况下,开放资源的访问权限。
举例来说,例如登录操作,可以被公开访问:
**类型**
```typescript ```typescript
// 注册 users:login 可以被公开访问 type ConditionFunc = (ctx: any) => Promise<boolean> | boolean;
acl.allow('users', 'login');
``` ```
**参数** **详细信息**
* resourceName - 资源名称 * resourceName - 资源名称
* actionNames - 资源动作名 * actionNames - 资源动作名
* condition? - 配置生效条件 * condition? - 配置生效条件
@ -212,3 +196,37 @@ acl.allow('users', 'login');
return ctx.state.user?.id === 1; return ctx.state.user?.id === 1;
}); });
``` ```
**示例**
```typescript
// 注册 users:login 可以被公开访问
acl.allow('users', 'login');
```
### `setAvailableActions()`
**签名**
* `setAvailableStrategy(name: string, options: AvailableStrategyOptions)`
注册一个可用的权限策略
**类型**
```typescript
interface AvailableStrategyOptions {
displayName?: string;
actions?: false | string | string[];
allowConfigure?: boolean;
resource?: '*';
}
```
**详细信息**
* displayName - 策略名称
* allowConfigure - 此策略是否拥有 **配置资源** 的权限,设置此项为`true`之后,请求判断在 `ACL` 中注册成为 `configResources` 资源的权限,会返回通过。
* actions - 策略内的 actions 列表,支持通配符 `*`
* resource - 策略内的 resource 定义,支持通配符 `*`

View File

@ -1,55 +0,0 @@
# AllowManager
开放权限管理
## 类方法
### `constructor(public acl: ACL)`
实例化 AllowManger
### `allow(resourceName: string, actionName: string, condition?: string | ConditionFunc)`
注册开放权限
```typescript
// users:login 可以被公开访问
allowManager.allow('users', 'login');
```
**参数**
* resourceName - 资源名称
* actionName - 资源动作名
* condition? - 配置生效条件
* 传入 `string`,表示使用已定义的条件,注册条件使用 `acl.allowManager.registerCondition` 方法。
```typescript
acl.allowManager.registerAllowCondition('superUser', async () => {
return ctx.state.user?.id === 1;
});
// 开放 users:list 的权限,条件为 superUser
acl.allow('users', 'list', 'superUser');
```
* 传入 ConditionFunc可接收 `ctx` 参数,返回 `boolean`,表示是否生效。
```typescript
// 当用户ID为1时可以访问 user:list
acl.allow('users', 'list', (ctx) => {
return ctx.state.user?.id === 1;
});
```
### `registerAllowCondition(name: string, condition: ConditionFunc)`
注册开放权限条件
### `getAllowedConditions(resourceName: string, actionName: string): Array<ConditionFunc | true>`
获取已注册的开放条件
**参数**
* resourceName - 资源名称
* actionName - 资源动作名
### `aclMiddleware()`
中间件,注入于 `acl` 实例中,用于判断是否开放权限,若根据条件判断为开放权限,则在 `acl` middleware 中会跳过权限检查。

View File

@ -1,12 +0,0 @@
# ACL 权限管理
ACL 为 Nocobase 中的权限控制模块。在 ACL 中注册角色、资源以及配置相应权限之后,即可对角色进行权限判断。
## 概念解释
* 角色 (`ACLRole`):权限判断的对象
* 资源 (`ACLResource`):在 Nocobase ACL 中,资源通常对应一个数据库表,概念上可类比为 Restful API 中的 Resource。
* Action对资源的操作`create`、`read`、`update`、`delete` 等。
* 策略 (`ACLAvailableStrategy`): 通常每个角色都有自己的权限策略,策略中定义了默认情况下的用户权限。
* 授权:在 `ACLRole` 实例中调用 `grantAction` 函数,为角色授予 `Action` 的访问权限。
* 鉴权:在 `ACL` 实例中调用 `can` 函数,函数返回结果既为用户的鉴权结果。

View File

@ -292,6 +292,58 @@ app.actions({
}); });
``` ```
### `move()`
对应的 URL 为 `POST /api/<resource>:move`
此方法用于移动数据,调整数据的排序。例如在页面中,拖拽一个元素到另一个元素的上方或下方,可调用此方法实现顺序调整。
**参数**
| 参数名 | 类型 | 默认值 | 描述 |
|----------|-------------| -- |---------------|
| `sourceId` | `targetKey` | - | 移动的元素ID |
| `targetId` | `targetKey` | - | 与移动元素交换位置的元素ID |
| `sortField` | `string` | `sort` | 排序存储的字段名 |
| `targetScope` | `string` | - | 排序的scope一个 resource 可以按照不同的 scope 排序 |
| `sticky` | `boolean` | - | 是否置顶移动的元素 |
| `method` | `insertAfter` \| `prepend` | - | 插入类型,插入目标元素之前还是之后 |
## 关系资源资源操作 ## 关系资源资源操作
TODO ### `add()`
添加与对象的关联关系,对应的 URL 为 `POST /api/<resource.assocition>:add`。适用于 `hasMany``belongsToMany` 关联。
**参数**
| 参数名 | 类型 | 默认值 | 描述 |
|----------|-------------| --- | --- |
| `values` | `TargetKey \| TargetKey[]` | - | 添加的关联对象ID |
### `remove()`
移除与对象的关联关系,对应的 URL 为 `POST /api/<resource.assocition>:remove`
**参数**
| 参数名 | 类型 | 默认值 | 描述 |
|----------|-------------| --- | --- |
| `values` | `TargetKey \| TargetKey[]` | - | 移除的关联对象ID |
### `set()`
设置关联的关联对象,对应的 URL 为 `POST /api/<resource.assocition>:set`
**参数**
| 参数名 | 类型 | 默认值 | 描述 |
|----------|-------------| --- | --- |
| `values` | `TargetKey \| TargetKey[]` | - | 设置的关联对象的ID |
### `toggle()`
切换关联的关联对象,对应的 URL 为 `POST /api/<resource.assocition>:toggle`。`toggle` 在内部判断关联对象是否已经存在,如果存在则移除,如果不存在则添加。
**参数**
| 参数名 | 类型 | 默认值 | 描述 |
|----------|-------------| -- | --- |
| `values` | `TargetKey` | - | 切换的关联对象的ID |

View File

@ -1,23 +1,181 @@
## BelongsToManyRepository # BelongsToManyRepository
`BelongsToManyRepository` 是用于处理 `BelongsToMany` 关系的 `Relation Repository`
### `count()` 不同于其他关系类型,`BelongsToMany` 类型的关系需要通过中间表来记录。
`Nocobase` 中定义关联关系,可自动创建中间表,也可以明确指定中间表。
## 类方法
### `find()` ### `find()`
查找关联对象
**签名**
* `async find(options?: FindOptions): Promise<M[]>`
**详细信息**
查询参数与 [`Repository.find()`](../repository.md#find) 一致。
### `findOne()` ### `findOne()`
查找关联对象,仅返回一条记录
**签名**
* `async findOne(options?: FindOneOptions): Promise<M>`
<embed src="../shared/find-one.md"></embed>
### `count()`
返回符合查询条件的记录数
**签名**
* `async count(options?: CountOptions)`
**类型**
```typescript
interface CountOptions extends Omit<SequelizeCountOptions, 'distinct' | 'where' | 'include'>, Transactionable {
filter?: Filter;
}
```
### `findAndCount()` ### `findAndCount()`
从数据库查询特定条件的数据集和结果数。
**签名**
* `async findAndCount(options?: FindAndCountOptions): Promise<[any[], number]>`
**类型**
```typescript
type FindAndCountOptions = CommonFindOptions
```
### `create()` ### `create()`
创建关联对象
**签名**
* `async create(options?: CreateOptions): Promise<M>`
<embed src="../shared/create-options.md"></embed>
### `update()` ### `update()`
更新符合条件的关联对象
**签名**
* `async update(options?: UpdateOptions): Promise<M>`
<embed src="../shared/update-options.md"></embed>
### `destroy()` ### `destroy()`
删除符合条件的关联对象
**签名**
* `async destroy(options?: TargetKey | TargetKey[] | DestroyOptions): Promise<Boolean>`
<embed src="../shared/destroy-options.md"></embed>
### `add()` ### `add()`
### `remove()` 添加新的关联对象
**签名**
* `async add(
options: TargetKey | TargetKey[] | PrimaryKeyWithThroughValues | PrimaryKeyWithThroughValues[] | AssociatedOptions
): Promise<void>`
**类型**
```typescript
type PrimaryKeyWithThroughValues = [TargetKey, Values];
interface AssociatedOptions extends Transactionable {
tk?: TargetKey | TargetKey[] | PrimaryKeyWithThroughValues | PrimaryKeyWithThroughValues[];
}
```
**详细信息**
可以直接传入关联对象的 `targetKey`,也可将 `targetKey` 与中间表的字段值一并传入。
**示例**
```typescript
const t1 = await Tag.repository.create({
values: { name: 't1' },
});
const t2 = await Tag.repository.create({
values: { name: 't2' },
});
const p1 = await Post.repository.create({
values: { title: 'p1' },
});
const PostTagRepository = new BelongsToManyRepository(Post, 'tags', p1.id);
// 传入 targetKey
PostTagRepository.add([
t1.id, t2.id
]);
// 传入中间表字段
PostTagRepository.add([
[t1.id, { tagged_at: '123' }],
[t2.id, { tagged_at: '456' }],
]);
```
### `set()` ### `set()`
设置关联对象
**签名**
* async set(
options: TargetKey | TargetKey[] | PrimaryKeyWithThroughValues | PrimaryKeyWithThroughValues[] | AssociatedOptions,
): Promise<void>
**详细信息**
参数同 [add()](#add)
### `remove()`
移除与给定对象之间的关联关系
**签名**
* `async remove(options: TargetKey | TargetKey[] | AssociatedOptions)`
**类型**
```typescript
interface AssociatedOptions extends Transactionable {
tk?: TargetKey | TargetKey[];
}
```
### `toggle()` ### `toggle()`
切换关联对象。
在一些业务场景中,经常需要切换关联对象,比如用户收藏商品,用户可以取消收藏,也可以再次收藏。使用 `toggle` 方法可以快速实现类似功能。
**签名**
* `async toggle(options: TargetKey | { tk?: TargetKey; transaction?: Transaction }): Promise<void>`
**详细信息**
`toggle` 方法会自动判断关联对象是否已经存在,如果存在则移除,如果不存在则添加。

View File

@ -1,3 +1,3 @@
## BelongsToRepository ## BelongsToRepository
`BelongsToRepository` 是用于处理 `BelongsTo` 关系的 `Repository`,它提供了一些便捷的方法来处理 `BelongsTo` 关系。其接口与 [HasOneRepository](#has-one-repository) 一致。 `BelongsToRepository` 是用于处理 `BelongsTo` 关系的 `Repository`,它提供了一些便捷的方法来处理 `BelongsTo` 关系。其接口与 [HasOneRepository](./has-one-repository.md) 一致。

View File

@ -1,7 +1,7 @@
# HasManyRepository # HasManyRepository
`HasManyRepository` 是用于处理 `HasMany` 关系的 `Repository`。 `HasManyRepository` 是用于处理 `HasMany` 关系的 `Relation Repository`。
## 类方法 ## 类方法
@ -13,11 +13,9 @@
* `async find(options?: FindOptions): Promise<M[]>` * `async find(options?: FindOptions): Promise<M[]>`
**参数** **详细信息**
| 参数名 | 类型 | 默认值 | 描述 | 查询参数与 [`Repository.find()`](../repository.md#find) 一致。
| --- | --- | --- | --- |
| `options` | `FindOptions` | - | 参见 repository.find |
### `findOne()` ### `findOne()`
@ -27,11 +25,8 @@
* `async findOne(options?: FindOneOptions): Promise<M>` * `async findOne(options?: FindOneOptions): Promise<M>`
**参数** <embed src="../shared/find-one.md"></embed>
| 参数名 | 类型 | 默认值 | 描述 |
| --- | --- | --- | --- |
| `options` | `FindOneOptions` | - | 参见 repository.findOne |
### `count()` ### `count()`
@ -41,26 +36,25 @@
* `async count(options?: CountOptions)` * `async count(options?: CountOptions)`
**参数** **类型**
```typescript
| 参数名 | 类型 | 默认值 | 描述 | interface CountOptions extends Omit<SequelizeCountOptions, 'distinct' | 'where' | 'include'>, Transactionable {
| --- | --- | --- | --- | filter?: Filter;
| `options` | `CountOptions` | - | 参见 repository.count | }
```
### `findAndCount()` ### `findAndCount()`
同时返回符合查询条件的记录集合与记录数 从数据库查询特定条件的数据集和结果数。
**签名** **签名**
* `async findAndCount(options?: FindAndCountOptions): Promise<[any[], number]>` * `async findAndCount(options?: FindAndCountOptions): Promise<[any[], number]>`
**参数** **类型**
```typescript
| 参数名 | 类型 | 默认值 | 描述 | type FindAndCountOptions = CommonFindOptions
| --- | --- | --- | --- | ```
| `options` | `FindAndCountOptions` | - | 参见 repository.findAndCount |
### `create()` ### `create()`
@ -71,12 +65,7 @@
* `async create(options?: CreateOptions): Promise<M>` * `async create(options?: CreateOptions): Promise<M>`
**参数** <embed src="../shared/create-options.md"></embed>
| 参数名 | 类型 | 默认值 | 描述 |
| --- | --- | --- | --- |
| `options` | `CreateOptions` | - | 参见 repository.create |
### `update()` ### `update()`
@ -86,12 +75,7 @@
* `async update(options?: UpdateOptions): Promise<M>` * `async update(options?: UpdateOptions): Promise<M>`
**参数** <embed src="../shared/update-options.md"></embed>
| 参数名 | 类型 | 默认值 | 描述 |
| --- | --- | --- | --- |
| `options` | `UpdateOptions` | - | 参见 repository.update |
### `destroy()` ### `destroy()`
@ -101,41 +85,37 @@
* `async destroy(options?: TK | DestroyOptions): Promise<M>` * `async destroy(options?: TK | DestroyOptions): Promise<M>`
**参数** <embed src="../shared/destroy-options.md"></embed>
| 参数名 | 类型 | 默认值 | 描述 |
| --- | --- | --- | --- |
| `options` | `TK \|DestroyOptions` | - | 传入删除对象的 `targetKeyId`,或者 `targetKeyId` 数组。需传 `transaction` 时 使用 `DestroyOptions` 类型 |
### `add()` ### `add()`
添加关联对象 添加对象关联关系
**签名** **签名**
* `async add(options: TargetKey | TargetKey[] | AssociatedOptions)` * `async add(options: TargetKey | TargetKey[] | AssociatedOptions)`
**参数** **类型**
```typescript
interface AssociatedOptions extends Transactionable {
tk?: TargetKey | TargetKey[];
}
```
| 参数名 | 类型 | 默认值 | 描述 | **详细信息**
| --- | --- | --- | --- |
| `options` | `TargetKey` | - | 关联对象的 `targetKeyId` |
| `options` | `TargetKey[]` | - | 多个关联对象的 `targetKeyId` 数组 |
| `options` | `AssociatedOptions` | - | `options.tk`, 为 `targetKeyId` 或者 `targetKeyId` 数组;`options.transaction`,为 `Transaction` 对象 |
* `tk` - 关联对象的 targetKey 值,可以是单个值,也可以是数组。
<embed src="../shared/transaction.md"></embed>
### `remove()` ### `remove()`
移除符合条件的关联对象 移除与给定对象之间的关联关系
**签名** **签名**
* `async remove(options: TargetKey | TargetKey[] | AssociatedOptions)` * `async remove(options: TargetKey | TargetKey[] | AssociatedOptions)`
**参数** **详细信息**
| 参数名 | 类型 | 默认值 | 描述 |
| --- | --- | --- | --- |
| `options` | `TargetKey \| TargetKey[] \| AssociatedOptions` | - | 同 [add](#add) |
参数同 [`add()`](#add) 方法。
### `set()` ### `set()`
@ -145,8 +125,8 @@
* `async set(options: TargetKey | TargetKey[] | AssociatedOptions)` * `async set(options: TargetKey | TargetKey[] | AssociatedOptions)`
**参数** **详细信息**
参数同 [`add()`](#add) 方法。
| 参数名 | 类型 | 默认值 | 描述 |
| --- | --- | --- | --- |
| `options` | `TargetKey \| TargetKey[] \| AssociatedOptions` | - | 同 [add](#add) |

View File

@ -26,18 +26,44 @@ const userProfileRepository = new HasOneRepository(User, 'profile', user.get('id
## 类方法 ## 类方法
### `create(options?: CreateOptions)` ### `find()`
查找关联对象
**签名**
* `async find(options?: SingleRelationFindOption): Promise<Model<any> | null>`
**类型**
```typescript
interface SingleRelationFindOption extends Transactionable {
fields?: Fields;
except?: Except;
appends?: Appends;
filter?: Filter;
}
```
**详细信息**
查询参数与 [`Repository.find()`](../repository.md#find) 一致。
**示例**
```typescript
const profile = await UserProfileRepository.find();
// 关联对象不存在时,返回 null
```
### `create()`
创建关联对象 创建关联对象
**签名** **签名**
* `async create(options?: CreateOptions): Promise<Model>` * `async create(options?: CreateOptions): Promise<Model>`
**参数** <embed src="../shared/create-options.md"></embed>
| 参数名 | 类型 | 默认值 | 描述 |
| --- | --- | --- | --- |
| `options` | `CreateOptions` | - | 参见 repository.create |
**示例** **示例**
@ -59,30 +85,6 @@ console.log(profile.toJSON());
``` ```
### `find()`
查找关联对象
**签名**
* `async find(options?: SingleRelationFindOption): Promise<Model<any> | null>`
**参数**
| 参数名 | 类型 | 默认值 | 描述 |
| --- | --- | --- | --- |
| `options.fields` | `Fields` | - | 参见 repository.find.fields |
| `options.except` | `Except` | - | 参见 repository.find.except |
| `options.appends` | `Appends` | - | 参见 repository.find.appends |
| `options.filter` | `Filter` | - | 参见 repository.find.filter |
**示例**
```typescript
const profile = await UserProfileRepository.find();
// 关联对象不存在时,返回 null
```
### `update()` ### `update()`
更新关联对象 更新关联对象
@ -91,11 +93,8 @@ const profile = await UserProfileRepository.find();
* `async update(options: UpdateOptions): Promise<Model>` * `async update(options: UpdateOptions): Promise<Model>`
**参数** <embed src="../shared/update-options.md"></embed>
| 参数名 | 类型 | 默认值 | 描述 |
| --- | --- | --- | --- |
| `options` | `UpdateOptions` | - | 参见 repository.update |
**示例** **示例**
@ -115,11 +114,9 @@ profile.get('avatar'); // 'avatar2'
* `async remove(options?: Transactionable): Promise<void>` * `async remove(options?: Transactionable): Promise<void>`
**参数** **详细信息**
| 参数名 | 类型 | 默认值 | 描述 | * `transaction`: 事务对象。如果没有传入事务参数,该方法会自动创建一个内部事务。
| --- | --- | --- | --- |
| `options.transaction` | `Transaction` | - | Transaction |
**示例** **示例**
@ -139,11 +136,9 @@ await Profile.repository.count() === 1; // true
* `async destroy(options?: Transactionable): Promise<Boolean>` * `async destroy(options?: Transactionable): Promise<Boolean>`
**参数** **详细信息**
| 参数名 | 类型 | 默认值 | 描述 | * `transaction`: 事务对象。如果没有传入事务参数,该方法会自动创建一个内部事务。
| --- | --- | --- | --- |
| `options.transaction` | `Transaction` | - | Transaction |
**示例** **示例**
@ -161,11 +156,17 @@ await Profile.repository.count() === 0; // true
* `async set(options: TargetKey | SetOption): Promise<void>` * `async set(options: TargetKey | SetOption): Promise<void>`
**参数** **类型**
| 参数名 | 类型 | 默认值 | 描述 | ```typescript
| --- | --- | --- | --- | interface SetOption extends Transactionable {
| `options` | ` TargetKey \| SetOption` | - | 需要 set 的对象的 targetKey如果需要一同传入 transaction 则修改为 object 类型参数 | tk?: TargetKey;
}
````
**详细信息**
* tk: 设置关联对象的 targetKey
* transaction: 事务对象。如果没有传入事务参数,该方法会自动创建一个内部事务。
**示例** **示例**

View File

@ -53,35 +53,6 @@ await books.myQuery('SELECT * FROM books;');
## 实例方法 ## 实例方法
### `count()`
从数据库查询特定条件的数据总数。相当于 Sequelize 中的 `Model.count()`
**签名**
* `count(options?: CountOptions): Promise<number>`
**参数**
| 参数名 | 类型 | 默认值 | 描述 |
| --- | --- | --- | --- |
| `options.filter?` | `Filter` | `{}` | 查询条件 |
| `options.fields?` | `string[]` | - | 计数列 |
| `options.transaction?` | `Transaction` | - | 事务 |
`filter` 为兼容 Sequelize 查询条件的扩展形式,更多操作符支持详见 [Operators](./operators.md)。
**示例**
```ts
const books = db.getRepository('books');
const count = await books.count({
filter: {
title: '三字经'
}
});
```
### `find()` ### `find()`
@ -91,21 +62,84 @@ const count = await books.count({
* `async find(options?: FindOptions): Promise<Model[]>` * `async find(options?: FindOptions): Promise<Model[]>`
**参数** **类型**
```typescript
type Filter = FilterWithOperator | FilterWithValue | FilterAnd | FilterOr;
type Appends = string[];
type Except = string[];
type Fields = string[];
type Sort = string[] | string;
| 参数名 | 类型 | 默认值 | 描述 | interface SequelizeFindOptions {
| --- | --- | --- | --- | limit?: number;
| `options.filterByTk?` | `number \| string` | `{}` | 主键值 | offset?: number;
| `options.filter?` | `Filter` | `{}` | 查询条件 | }
| `options.fields?` | `string[]` | - | 查询列 |
| `options.appends?` | `string[]` | - | 追加关系数据列 |
| `options.except?` | `string[]` | - | 排除数据列 |
| `options.sort?` | `string[] \| string` | - | 排序 |
| `options.limit?` | `number` | - | 限制条数 |
| `options.offset?` | `number` | - | 跳过条数 |
| `options.transaction?` | `Transaction` | - | 事务 |
`fields``except` 通常只使用其一,相当于 Sequelize 中 `attributes``include` / `exclude`。`appends` 通常用于关系字段。 interface FilterByTk {
filterByTk?: TargetKey;
}
interface CommonFindOptions extends Transactionable {
filter?: Filter;
fields?: Fields;
appends?: Appends;
except?: Except;
sort?: Sort;
}
type FindOptions = SequelizeFindOptions & CommonFindOptions & FilterByTk;
```
**详细信息**
#### `filter: Filter`
查询条件,用于过滤数据结果。传入的查询参数中,`key` 为查询的字段名,`value` 可传要查询的值,
也可配合使用操作符进行其他条件的数据筛选。
```typescript
// 查询 name 为 foo并且 age 大于 18 的记录
repository.find({
filter: {
name: "foo",
age: {
$gt: 18,
},
}
})
```
更多操作符请参考 [查询操作符](./operators.md)。
#### `filterByTk: TargetKey`
通过 `TargetKey` 查询数据,为 `filter` 参数的便捷方法。`TargetKey` 具体是哪一个字段,
可在 `Collection` 中进行[配置](./collection.md#filtertargetkey),默认为 `primaryKey`
```typescript
// 默认情况下,查找 id 为 1 的记录
repository.find({
filterByTk: 1,
});
```
#### `fields: string[]`
查询列,用户控制数据字段结果。传入此参数之后,只会返回指定的字段。
#### `except: string[]`
排除列,用于控制数据字段结果。传入此参数之后,传入的字段将不会输出。
#### `appends: string[]`
追加列,用于加载关联数据。传入此参数之后,指定的关联字段将一并输出。
#### `sort: string[] | string`
指定查询结果排序方式,传入参数为字段名称,默认按照升序 `asc` 排序,若需按降序 `desc` 排序,
可在字段名称前加上 `-` 符号,如:`['-id', 'name']`,表示按 `id desc, name asc` 排序。
#### `limit: number`
限制结果数量,同 `SQL` 中的 `limit`
#### `offset: number`
查询偏移量,同 `SQL` 中的 `offset`
**示例** **示例**
@ -131,20 +165,7 @@ const results = await posts.find({
* `async findOne(options?: FindOneOptions): Promise<Model | null>` * `async findOne(options?: FindOneOptions): Promise<Model | null>`
**参数** <embed src="./shared/find-one.md"></embed>
| 参数名 | 类型 | 默认值 | 描述 |
| --- | --- | --- | --- |
| `options.filterByTk?` | `number \| string` | `{}` | 主键值 |
| `options.filter?` | `Filter` | `{}` | 查询条件 |
| `options.fields?` | `string[]` | - | 查询列 |
| `options.appends?` | `string[]` | - | 追加关系数据列 |
| `options.except?` | `string[]` | - | 排除数据列 |
| `options.sort?` | `string[] \| string` | - | 排序 |
| `options.offset?` | `number` | - | 跳过条数 |
| `options.transaction?` | `Transaction` | - | 事务 |
大部分参数与 `find()` 相同,不同之处在于 `findOne()` 只返回单条数据,所以不需要 `limit` 参数,且查询时始终为 `1`
**示例** **示例**
@ -156,17 +177,50 @@ const result = await posts.findOne({
}); });
``` ```
### `count()`
从数据库查询特定条件的数据总数。相当于 Sequelize 中的 `Model.count()`
**签名**
* `count(options?: CountOptions): Promise<number>`
**类型**
```typescript
interface CountOptions extends Omit<SequelizeCountOptions, 'distinct' | 'where' | 'include'>, Transactionable {
filter?: Filter;
}
```
**示例**
```ts
const books = db.getRepository('books');
const count = await books.count({
filter: {
title: '三字经'
}
});
```
### `findAndCount()` ### `findAndCount()`
从数据库查询特定条件的数据集和总数。相当于 Sequelize 中的 `Model.findAndCountAll()` 从数据库查询特定条件的数据集和结果数。相当于 Sequelize 中的 `Model.findAndCountAll()`
**签名** **签名**
* `async findAndCount(options?: FindAndCountOptions): Promise<[Model[], number]>` * `async findAndCount(options?: FindAndCountOptions): Promise<[Model[], number]>`
**参数** **类型**
```typescript
type FindAndCountOptions = Omit<SequelizeAndCountOptions, 'where' | 'include' | 'order'> & CommonFindOptions;
```
所有参数与 [`find()`](#find) 相同。 **详细信息**
查询参数与 `find()` 相同。返回值为一个数组,第一个元素为查询结果,第二个元素为结果总数。
### `create()` ### `create()`
@ -176,16 +230,7 @@ const result = await posts.findOne({
* `async create<M extends Model>(options: CreateOptions): Promise<M>` * `async create<M extends Model>(options: CreateOptions): Promise<M>`
**参数** <embed src="./shared/create-options.md"></embed>
| 参数名 | 类型 | 默认值 | 描述 |
| --- | --- | --- | --- |
| `options.values` | `M` | `{}` | 插入的数据对象 |
| `options.whitelist?` | `string[]` | - | `values` 字段的白名单,只有名单内的字段会被存储 |
| `options.blacklist?` | `string[]` | - | `values` 字段的黑名单,名单内的字段不会被存储 |
| `options.transaction?` | `Transaction` | - | 事务 |
如果没有传入事务参数,该方法会自动创建一个内部事务。
**示例** **示例**
@ -213,16 +258,17 @@ const result = await posts.create({
* `createMany(options: CreateManyOptions): Promise<Model[]>` * `createMany(options: CreateManyOptions): Promise<Model[]>`
**参数** **类型**
```typescript
interface CreateManyOptions extends BulkCreateOptions {
records: Values[];
}
```
| 参数名 | 类型 | 默认值 | 描述 | **详细信息**
| --- | --- | --- | --- |
| `options.records` | `Model[]` | - | 插入的数据对象数组 |
| `options.whitelist?` | `string[]` | - | `values` 字段的白名单,只有名单内的字段会被存储 |
| `options.blacklist?` | `string[]` | - | `values` 字段的黑名单,名单内的字段不会被存储 |
| `options.transaction?` | `Transaction` | - | 事务 |
如果没有传入事务参数,该方法会自动创建一个内部事务。 * `records`:要创建的记录的数据对象数组。
* `transaction`: 事务对象。如果没有传入事务参数,该方法会自动创建一个内部事务。
**示例** **示例**
@ -258,18 +304,7 @@ const results = await posts.createMany({
* `async update<M extends Model>(options: UpdateOptions): Promise<M>` * `async update<M extends Model>(options: UpdateOptions): Promise<M>`
**参数** <embed src="./shared/update-options.md"></embed>
| 参数名 | 类型 | 默认值 | 描述 |
| --- | --- | --- | --- |
| `options.filterByTk` | `number \| string` | - | 查询主键 |
| `options.filter` | `Filter` | - | 查询条件 |
| `options.values` | `M` | `{}` | 更新的数据对象 |
| `options.whitelist?` | `string[]` | - | `values` 字段的白名单,只有名单内的字段会被存储 |
| `options.blacklist?` | `string[]` | - | `values` 字段的黑名单,名单内的字段不会被存储 |
| `options.transaction?` | `Transaction` | - | 事务 |
`filterByTk``filter` 至少要传其一。如果没有传入事务参数,该方法会自动创建一个内部事务。
**示例** **示例**
@ -298,58 +333,20 @@ const result = await posts.update({
* `async destory(options?: TargetKey | TargetKey[] | DestoryOptions): Promise<number>` * `async destory(options?: TargetKey | TargetKey[] | DestoryOptions): Promise<number>`
**参数** **类型**
| 参数名 | 类型 | 默认值 | 描述 | ```typescript
| --- | --- | --- | --- | interface DestroyOptions extends SequelizeDestroyOptions {
| `options.filterByTk` | `number \| string` | - | 查询主键 | filter?: Filter;
| `options.filter` | `Filter` | - | 查询条件 | filterByTk?: TargetKey | TargetKey[];
| `options.transaction?` | `Transaction` | - | 事务 | truncate?: boolean;
context?: any;
}
```
`filterByTk``filter` 至少要传其一。如果没有传入事务参数,该方法会自动创建一个内部事务。 **详细信息**
## 关系数据仓库类 * `filter`指定要删除的记录的过滤条件。Filter 详细用法可参考 [`find()`](#find) 方法。
* `filterByTk`:按 TargetKey 指定要删除的记录的过滤条件。
通过 `db.getRepository('<name.associatedField>', <id>)` 方法获取到的关系数据仓库管理实例,在调用方法时,会自动在查询条件中加入当前表的主键值。除此以外,还拥有一些基于不同关系类型特有的成员和关系操作方法。 * `truncate`: 是否清空表数据,在没有传入 `filter``filterByTk` 参数时有效。
* `transaction`: 事务对象。如果没有传入事务参数,该方法会自动创建一个内部事务。
### `set()`
相当于 Sequelize 的 `record.setXxx()` 方法,用于设置关联数据。对一的关系参数为对应的外键,对多的关系参数为对应的外键数组。如果关系类型为 `BelongsToMany`,则会自动创建中间表数据。
**签名**
* `async set(association: string | number | string[] | number[]): Promise<void>`
**参数**
| 参数名 | 类型 | 默认值 | 描述 |
| --- | --- | --- | --- |
| `association` | `string \| number \| string[] \| number[]` | - | 关联数据的外键,对多时可用数组 |
### `add()`
相当于 Sequelize 的 `record.addXxx()` 方法,用于附加关联,仅针对对多关系。
**签名**
* `async add(association: string | number | string[] | number[]): Promise<void>`
**参数**
| 参数名 | 类型 | 默认值 | 描述 |
| --- | --- | --- | --- |
| `association` | `string \| number \| string[] \| number[]` | - | 关联数据的外键 |
### `remove()`
相当于 Sequelize 的 `record.removeXxx()` 方法,用于移除关联,仅针对对多关系。
**签名**
* `async remove(association: string | number | string[] | number[]): Promise<void>`
**参数**
| 参数名 | 类型 | 默认值 | 描述 |
| --- | --- | --- | --- |
| `association` | `string \| number \| string[] \| number[]` | - | 关联数据的外键 |

View File

@ -0,0 +1,8 @@
**参数**
| 参数名 | 类型 | 默认值 | 描述 |
| --- | --- | --- | --- |
| `options.values` | `M` | `{}` | 插入的数据对象 |
| `options.whitelist?` | `string[]` | - | `values` 字段的白名单,只有名单内的字段会被存储 |
| `options.blacklist?` | `string[]` | - | `values` 字段的黑名单,名单内的字段不会被存储 |
| `options.transaction?` | `Transaction` | - | 事务 |

View File

@ -0,0 +1,21 @@
**类型**
```typescript
type WhiteList = string[];
type BlackList = string[];
type AssociationKeysToBeUpdate = string[];
interface CreateOptions extends SequelizeCreateOptions {
values?: Values;
whitelist?: WhiteList;
blacklist?: BlackList;
updateAssociationValues?: AssociationKeysToBeUpdate;
context?: any;
}
```
**详细信息**
* `values`:要创建的记录的数据对象。
* `whitelist`:指定要创建的记录的数据对象中,哪些字段**可以被写入**。若不传入此参数,则默认允许所有字段写入。
* `blacklist`:指定要创建的记录的数据对象中,哪些字段**不允许被写入**。若不传入此参数,则默认允许所有字段写入。
* `transaction`: 事务对象。如果没有传入事务参数,该方法会自动创建一个内部事务。

View File

@ -0,0 +1,17 @@
**类型**
```typescript
interface DestroyOptions extends SequelizeDestroyOptions {
filter?: Filter;
filterByTk?: TargetKey | TargetKey[];
truncate?: boolean;
context?: any;
}
```
**详细信息**
* `filter`指定要删除的记录的过滤条件。Filter 详细用法可参考 [`find()`](#find) 方法。
* `filterByTk`:按 TargetKey 指定要删除的记录的过滤条件。
* `truncate`: 是否清空表数据,在没有传入 `filter``filterByTk` 参数时有效。
* `transaction`: 事务对象。如果没有传入事务参数,该方法会自动创建一个内部事务。

View File

@ -0,0 +1,8 @@
**类型**
```typescript
type FindOneOptions = Omit<FindOptions, 'limit'>;
```
**参数**
大部分参数与 `find()` 相同,不同之处在于 `findOne()` 只返回单条数据,所以不需要 `limit` 参数,且查询时始终为 `1`

View File

@ -0,0 +1 @@
* `transaction`: 事务对象。如果没有传入事务参数,该方法会自动创建一个内部事务。

View File

@ -0,0 +1,24 @@
**类型**
```typescript
interface UpdateOptions extends Omit<SequelizeUpdateOptions, 'where'> {
values: Values;
filter?: Filter;
filterByTk?: TargetKey;
whitelist?: WhiteList;
blacklist?: BlackList;
updateAssociationValues?: AssociationKeysToBeUpdate;
context?: any;
}
```
**详细信息**
* `values`:要更新的记录的数据对象。
* `filter`:指定要更新的记录的过滤条件, Filter 详细用法可参考 [`find()`](#find) 方法。
* `filterByTk`:按 TargetKey 指定要更新的记录的过滤条件。
* `whitelist`: `values` 字段的白名单,只有名单内的字段会被写入。
* `blacklist`: `values` 字段的黑名单,名单内的字段不会被写入。
* `transaction`: 事务对象。如果没有传入事务参数,该方法会自动创建一个内部事务。
`filterByTk``filter` 至少要传其一。

View File

@ -156,7 +156,8 @@ export class ACL extends EventEmitter {
this.addListener('beforeGrantAction', listener); this.addListener('beforeGrantAction', listener);
} }
can({ role, resource, action }: CanArgs): CanResult | null { can(options: CanArgs): CanResult | null {
const { role, resource, action } = options;
const aclRole = this.roles.get(role); const aclRole = this.roles.get(role);
if (!aclRole) { if (!aclRole) {

View File

@ -191,8 +191,9 @@ export class OptionsParser {
/** /**
* set include params * set include params
* @param includeRoot * @param model
* @param appends * @param queryParams
* @param append
*/ */
const setInclude = (model: ModelCtor<any>, queryParams: any, append: string) => { const setInclude = (model: ModelCtor<any>, queryParams: any, append: string) => {
const appendFields = append.split('.'); const appendFields = append.split('.');

View File

@ -1,9 +1,9 @@
import lodash from 'lodash'; import lodash from 'lodash';
import { BelongsToMany, Op, Transaction } from 'sequelize'; import { BelongsToMany, Op, Transaction } from 'sequelize';
import { Model } from '../model'; import { Model } from '../model';
import { CreateOptions, DestroyOptions, FindOptions, TargetKey, UpdateOptions } from '../repository'; import { CreateOptions, DestroyOptions, FindOneOptions, FindOptions, TargetKey, UpdateOptions } from '../repository';
import { updateThroughTableValue } from '../update-associations'; import { updateThroughTableValue } from '../update-associations';
import { FindAndCountOptions, FindOneOptions, MultipleRelationRepository } from './multiple-relation-repository'; import { FindAndCountOptions, MultipleRelationRepository } from './multiple-relation-repository';
import { transaction } from './relation-repository'; import { transaction } from './relation-repository';
import { AssociatedOptions, PrimaryKeyWithThroughValues } from './types'; import { AssociatedOptions, PrimaryKeyWithThroughValues } from './types';
@ -14,7 +14,7 @@ interface IBelongsToManyRepository<M extends Model> {
findAndCount(options?: FindAndCountOptions): Promise<[M[], number]>; findAndCount(options?: FindAndCountOptions): Promise<[M[], number]>;
findOne(options?: FindOneOptions): Promise<M>; findOne(options?: FindOneOptions): Promise<M>;
// 新增并关联,存在中间表数据 // 新增并关联,存在中间表数据
create(options?: CreateBelongsToManyOptions): Promise<M>; create(options?: CreateOptions): Promise<M>;
// 更新,存在中间表数据 // 更新,存在中间表数据
update(options?: UpdateOptions): Promise<M>; update(options?: UpdateOptions): Promise<M>;
// 删除 // 删除

View File

@ -1,13 +1,16 @@
import { omit } from 'lodash'; import { omit } from 'lodash';
import { HasMany, Op } from 'sequelize'; import { HasMany, Op } from 'sequelize';
import { Model } from '../model'; import { Model } from '../model';
import { CreateOptions, DestroyOptions, FindOptions, TargetKey, TK, UpdateOptions } from '../repository';
import { import {
AssociatedOptions, CreateOptions,
FindAndCountOptions, DestroyOptions,
FindOneOptions, FindOneOptions,
MultipleRelationRepository FindOptions,
} from './multiple-relation-repository'; TargetKey,
TK,
UpdateOptions,
} from '../repository';
import { AssociatedOptions, FindAndCountOptions, MultipleRelationRepository } from './multiple-relation-repository';
import { transaction } from './relation-repository'; import { transaction } from './relation-repository';
interface IHasManyRepository<M extends Model> { interface IHasManyRepository<M extends Model> {

View File

@ -2,12 +2,10 @@ import { Model } from '../model';
import { CreateOptions } from '../repository'; import { CreateOptions } from '../repository';
import { SingleRelationFindOption, SingleRelationRepository } from './single-relation-repository'; import { SingleRelationFindOption, SingleRelationRepository } from './single-relation-repository';
interface HasOneFindOptions extends SingleRelationFindOption {}
interface IHasOneRepository<M extends Model> { interface IHasOneRepository<M extends Model> {
// 不需要 findOnefind 就是 findOne // 不需要 findOnefind 就是 findOne
find(options?: HasOneFindOptions): Promise<M>; find(options?: SingleRelationFindOption): Promise<M>;
findOne(options?: HasOneFindOptions): Promise<M>; findOne(options?: SingleRelationFindOption): Promise<M>;
// 新增并关联,如果存在关联,解除之后,与新数据建立关联 // 新增并关联,如果存在关联,解除之后,与新数据建立关联
create(options?: CreateOptions): Promise<M>; create(options?: CreateOptions): Promise<M>;
// 更新 // 更新

View File

@ -5,7 +5,7 @@ import {
CountOptions, CountOptions,
DestroyOptions, DestroyOptions,
Filter, Filter,
FilterByTk, FindOneOptions,
FindOptions, FindOptions,
TargetKey, TargetKey,
TK, TK,
@ -16,9 +16,7 @@ import { UpdateGuard } from '../update-guard';
import { RelationRepository, transaction } from './relation-repository'; import { RelationRepository, transaction } from './relation-repository';
import { handleAppendsQuery } from '../utils'; import { handleAppendsQuery } from '../utils';
export interface FindAndCountOptions extends CommonFindOptions {} export type FindAndCountOptions = CommonFindOptions;
export interface FindOneOptions extends CommonFindOptions, FilterByTk {}
export interface AssociatedOptions extends Transactionable { export interface AssociatedOptions extends Transactionable {
tk?: TK; tk?: TK;
@ -88,6 +86,7 @@ export abstract class MultipleRelationRepository extends RelationRepository {
async findAndCount(options?: FindAndCountOptions): Promise<[any[], number]> { async findAndCount(options?: FindAndCountOptions): Promise<[any[], number]> {
const transaction = await this.getTransaction(options, false); const transaction = await this.getTransaction(options, false);
return [ return [
await this.find({ await this.find({
...options, ...options,

View File

@ -2,6 +2,7 @@ import lodash, { omit } from 'lodash';
import { import {
Association, Association,
BulkCreateOptions, BulkCreateOptions,
CountOptions as SequelizeCountOptions,
CreateOptions as SequelizeCreateOptions, CreateOptions as SequelizeCreateOptions,
DestroyOptions as SequelizeDestroyOptions, DestroyOptions as SequelizeDestroyOptions,
FindAndCountOptions as SequelizeAndCountOptions, FindAndCountOptions as SequelizeAndCountOptions,
@ -11,6 +12,7 @@ import {
Transactionable, Transactionable,
UpdateOptions as SequelizeUpdateOptions UpdateOptions as SequelizeUpdateOptions
} from 'sequelize'; } from 'sequelize';
import { WhereOperators } from 'sequelize/types/lib/model';
import { Collection } from './collection'; import { Collection } from './collection';
import { Database } from './database'; import { Database } from './database';
import mustHaveFilter from './decorators/must-have-filter-decorator'; import mustHaveFilter from './decorators/must-have-filter-decorator';
@ -18,6 +20,7 @@ import { transactionWrapperBuilder } from './decorators/transaction-decorator';
import { RelationField } from './fields'; import { RelationField } from './fields';
import FilterParser from './filter-parser'; import FilterParser from './filter-parser';
import { Model } from './model'; import { Model } from './model';
import operators from './operators';
import { OptionsParser } from './options-parser'; import { OptionsParser } from './options-parser';
import { BelongsToManyRepository } from './relation-repository/belongs-to-many-repository'; import { BelongsToManyRepository } from './relation-repository/belongs-to-many-repository';
import { BelongsToRepository } from './relation-repository/belongs-to-repository'; import { BelongsToRepository } from './relation-repository/belongs-to-repository';
@ -45,7 +48,32 @@ export interface FilterAble {
export type TargetKey = string | number; export type TargetKey = string | number;
export type TK = TargetKey | TargetKey[]; export type TK = TargetKey | TargetKey[];
export type Filter = any; type FieldValue = string | number | bigint | boolean | Date | Buffer | null | FieldValue[] | FilterWithOperator;
type Operators = keyof typeof operators & keyof WhereOperators;
export type FilterWithOperator = {
[key: string]:
| {
[K in Operators]: FieldValue;
}
| FieldValue;
};
export type FilterWithValue = {
[key: string]: FieldValue;
};
type FilterAnd = {
$and: Filter[];
};
type FilterOr = {
$or: Filter[];
};
export type Filter = FilterWithOperator | FilterWithValue | FilterAnd | FilterOr;
export type Appends = string[]; export type Appends = string[];
export type Except = string[]; export type Except = string[];
export type Fields = string[]; export type Fields = string[];
@ -53,12 +81,12 @@ export type Sort = string[] | string;
export type WhiteList = string[]; export type WhiteList = string[];
export type BlackList = string[]; export type BlackList = string[];
export type AssociationKeysToBeUpdate = string[]; export type AssociationKeysToBeUpdate = string[];
export type Values = any; export type Values = any;
export interface CountOptions extends Omit<SequelizeCreateOptions, 'distinct' | 'where' | 'include'>, Transactionable { export interface CountOptions extends Omit<SequelizeCountOptions, 'distinct' | 'where' | 'include'>, Transactionable {
fields?: Fields;
filter?: Filter; filter?: Filter;
} }
@ -66,7 +94,7 @@ export interface FilterByTk {
filterByTk?: TargetKey; filterByTk?: TargetKey;
} }
export interface FindOptions extends SequelizeFindOptions, CommonFindOptions, FilterByTk {} export type FindOptions = SequelizeFindOptions & CommonFindOptions & FilterByTk;
export interface CommonFindOptions extends Transactionable { export interface CommonFindOptions extends Transactionable {
filter?: Filter; filter?: Filter;
@ -77,7 +105,7 @@ export interface CommonFindOptions extends Transactionable {
context?: any; context?: any;
} }
interface FindOneOptions extends FindOptions {} export type FindOneOptions = Omit<FindOptions, 'limit'>;
export interface DestroyOptions extends SequelizeDestroyOptions { export interface DestroyOptions extends SequelizeDestroyOptions {
filter?: Filter; filter?: Filter;
@ -86,18 +114,7 @@ export interface DestroyOptions extends SequelizeDestroyOptions {
context?: any; context?: any;
} }
interface FindAndCountOptions extends Omit<SequelizeAndCountOptions, 'where' | 'include' | 'order'> { type FindAndCountOptions = Omit<SequelizeAndCountOptions, 'where' | 'include' | 'order'> & CommonFindOptions;
// 数据过滤
filter?: Filter;
// 输出结果显示哪些字段
fields?: Fields;
// 输出结果不显示哪些字段
except?: Except;
// 附加字段,用于控制关系字段的输出
appends?: Appends;
// 排序,字段前面加上 “-” 表示降序
sort?: Sort;
}
export interface CreateOptions extends SequelizeCreateOptions { export interface CreateOptions extends SequelizeCreateOptions {
values?: Values | Values[]; values?: Values | Values[];
@ -359,6 +376,7 @@ export class Repository<TModelAttributes extends {} = any, TCreationAttributes e
const transaction = await this.getTransaction(options); const transaction = await this.getTransaction(options);
const { records } = options; const { records } = options;
const instances = []; const instances = [];
for (const values of records) { for (const values of records) {
const instance = await this.create({ values, transaction }); const instance = await this.create({ values, transaction });
instances.push(instance); instances.push(instance);

View File

@ -19,7 +19,7 @@ export interface Interceptor {
getReceiver(ctx): string; getReceiver(ctx): string;
getCode?(ctx): string; getCode?(ctx): string;
validate?(ctx: Context, receiver: string): boolean | Promise<boolean>; validate?(ctx: Context, receiver: string): boolean | Promise<boolean>;
}; }
export default class VerificationPlugin extends Plugin { export default class VerificationPlugin extends Plugin {
providers: Registry<typeof Provider> = new Registry(); providers: Registry<typeof Provider> = new Registry();
@ -49,10 +49,10 @@ export default class VerificationPlugin extends Plugin {
type: key, type: key,
content, content,
expiresAt: { expiresAt: {
[Op.gt]: new Date() [Op.gt]: new Date(),
}, },
status: CODE_STATUS_UNUSED status: CODE_STATUS_UNUSED,
} },
}); });
if (!item) { if (!item) {
@ -70,10 +70,9 @@ export default class VerificationPlugin extends Plugin {
// or delete // or delete
await item.update({ await item.update({
status: CODE_STATUS_USED status: CODE_STATUS_USED,
}); });
} };
getName(): string { getName(): string {
return this.getPackageName(__dirname); return this.getPackageName(__dirname);
@ -86,13 +85,14 @@ export default class VerificationPlugin extends Plugin {
INIT_ALI_SMS_ACCESS_KEY_SECRET, INIT_ALI_SMS_ACCESS_KEY_SECRET,
INIT_ALI_SMS_ENDPOINT = 'dysmsapi.aliyuncs.com', INIT_ALI_SMS_ENDPOINT = 'dysmsapi.aliyuncs.com',
INIT_ALI_SMS_VERIFY_CODE_TEMPLATE, INIT_ALI_SMS_VERIFY_CODE_TEMPLATE,
INIT_ALI_SMS_VERIFY_CODE_SIGN INIT_ALI_SMS_VERIFY_CODE_SIGN,
} = process.env; } = process.env;
if (INIT_ALI_SMS_ACCESS_KEY if (
&& INIT_ALI_SMS_ACCESS_KEY_SECRET INIT_ALI_SMS_ACCESS_KEY &&
&& INIT_ALI_SMS_VERIFY_CODE_TEMPLATE INIT_ALI_SMS_ACCESS_KEY_SECRET &&
&& INIT_ALI_SMS_VERIFY_CODE_SIGN INIT_ALI_SMS_VERIFY_CODE_TEMPLATE &&
INIT_ALI_SMS_VERIFY_CODE_SIGN
) { ) {
const ProviderRepo = this.db.getRepository('verifications_providers'); const ProviderRepo = this.db.getRepository('verifications_providers');
await ProviderRepo.create({ await ProviderRepo.create({
@ -105,9 +105,9 @@ export default class VerificationPlugin extends Plugin {
accessKeySecret: INIT_ALI_SMS_ACCESS_KEY_SECRET, accessKeySecret: INIT_ALI_SMS_ACCESS_KEY_SECRET,
endpoint: INIT_ALI_SMS_ENDPOINT, endpoint: INIT_ALI_SMS_ENDPOINT,
sign: INIT_ALI_SMS_VERIFY_CODE_SIGN, sign: INIT_ALI_SMS_VERIFY_CODE_SIGN,
template: INIT_ALI_SMS_VERIFY_CODE_TEMPLATE template: INIT_ALI_SMS_VERIFY_CODE_TEMPLATE,
} },
} },
}); });
} }
} }