diff --git a/docs/zh-CN/api/acl/acl-available-action.md b/docs/zh-CN/api/acl/acl-available-action.md deleted file mode 100644 index 20a51393f..000000000 --- a/docs/zh-CN/api/acl/acl-available-action.md +++ /dev/null @@ -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 是否允许配置字段 diff --git a/docs/zh-CN/api/acl/acl-available-strategy.md b/docs/zh-CN/api/acl/acl-available-strategy.md deleted file mode 100644 index 805edf60f..000000000 --- a/docs/zh-CN/api/acl/acl-available-strategy.md +++ /dev/null @@ -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 定义,支持通配符 `*` diff --git a/docs/zh-CN/api/acl/acl-resource.md b/docs/zh-CN/api/acl/acl-resource.md index c01283f3d..305b80bed 100644 --- a/docs/zh-CN/api/acl/acl-resource.md +++ b/docs/zh-CN/api/acl/acl-resource.md @@ -2,56 +2,56 @@ ACLResource,ACL 系统中的资源类。在 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 - 资源配置参数 - * name - 资源名称 - * role - 资源所属角色 - * actions - ResourceActions 对象,定义资源的 Action +interface AclResourceOptions { + name: string; // 资源名称 + role: ACLRole; // 资源所属角色 + actions?: ResourceActions; +} +``` + +**详细信息** + +`RoleActionParams`详见 [`aclRole.grantAction`](./acl-role.md#grantaction) ### `getActions()` 获取资源的所有 Action,返回结果为 `ResourceActions` 对象。 -### `getAction(name: string)` - +### `getAction()` 根据名称返回 Action 的参数配置,返回结果为 `RoleActionParams` 对象。 -## `setAction(name: string, params: RoleActionParams)` +**详细信息** + +`RoleActionParams`详见 [`aclRole.grantAction`](./acl-role.md#grantaction) + +### `setAction()` 在资源内部设置一个 Action 的参数配置,返回结果为 `RoleActionParams` 对象。 -**参数** +**签名** +* `setAction(name: string, params: RoleActionParams)` + +**详细信息** * name - 要设置的 action 名称 -* params - [`RoleActionParams`](#RoleActionParams) +* `RoleActionParams`详见 [`aclRole.grantAction`](./acl-role.md#grantaction) -## `setActions(actions: ResourceActions)` +### `setActions()` + +**签名** +* `setActions(actions: ResourceActions)` 批量调用 `setAction` 的便捷方法 - -**参数** - -* actions: [RoleActionParams](#RoleActionParams) diff --git a/docs/zh-CN/api/acl/acl-role.md b/docs/zh-CN/api/acl/acl-role.md index f15af9155..708131702 100644 --- a/docs/zh-CN/api/acl/acl-role.md +++ b/docs/zh-CN/api/acl/acl-role.md @@ -4,22 +4,38 @@ ACLRole,ACL 系统中的用户角色类。在 ACL 系统中,通常使用 `ac ## 类方法 -### `constructor(public acl: ACL, public name: string)` +### `constructor()` +构造函数 +**签名** +* `constructor(public acl: ACL, public name: string)` + +**详细信息** * acl - ACL 实例 * name - 角色名称 -### `grantAction(path: string, options?: RoleActionParams)` +### `grantAction()` 为角色授予 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 之间使用 `:` 冒号分隔。 -* options? - 配置参数,见 [`RoleActionParams`](#RoleActionParams)。 - - -## 参数 - -### `RoleActionParams` RoleActionParams 为授权时,对应 action 的可配置参数,用以实现更细粒度的权限控制。 @@ -68,3 +84,4 @@ RoleActionParams 为授权时,对应 action 的可配置参数,用以实现 ``` * whitelist - 白名单,只有在白名单中的字段才能被访问 * blacklist - 黑名单,黑名单中的字段不能被访问 + diff --git a/docs/zh-CN/api/acl/acl.md b/docs/zh-CN/api/acl/acl.md index dd3c6fa21..dc55f7fca 100644 --- a/docs/zh-CN/api/acl/acl.md +++ b/docs/zh-CN/api/acl/acl.md @@ -1,32 +1,16 @@ # ACL -ACL 为权限管理类,系统中的角色与资源都可以在 ACL 中进行注册。 +ACL 为 Nocobase 中的权限控制模块。在 ACL 中注册角色、资源以及配置相应权限之后,即可对角色进行权限判断。 -## 成员变量 +## 概念解释 -### `availableActions: Map` +* 角色 (`ACLRole`):权限判断的对象 +* 资源 (`ACLResource`):在 Nocobase ACL 中,资源通常对应一个数据库表,概念上可类比为 Restful API 中的 Resource。 +* Action:对资源的操作,如 `create`、`read`、`update`、`delete` 等。 +* 策略 (`ACLAvailableStrategy`): 通常每个角色都有自己的权限策略,策略中定义了默认情况下的用户权限。 +* 授权:在 `ACLRole` 实例中调用 `grantAction` 函数,为角色授予 `Action` 的访问权限。 +* 鉴权:在 `ACL` 实例中调用 `can` 函数,函数返回结果既为用户的鉴权结果。 -ACL 内的 `AclAvailableAction` 名称映射。 - -### `availableStrategy: Map` - -ACL 内的 [`ACLAvailableStrategy`](#ACLAvailableStrategy) 名称映射。 - -### `middlewares` - -ACL 鉴权中间件。 - -### `roles: Map` - -ACL 内的 `ACLRole` 名称映射。 - -### `actionAlias: Map` - -Action 别名映射。 - -### `configResources: Array` - -配置资源列表。 ## 类方法 @@ -39,11 +23,27 @@ import { ACL } from '@nocobase/database'; 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` - 角色名称 @@ -57,9 +57,9 @@ acl.define({ * `allowConfigure` - 是否允许配置权限 * `strategy` - 角色的权限策略 * 可以为 `string`,为要使用的策略名,表示使用已定义的策略。 - * 可以为 `AvailableStrategyOptions`,为该角色定义一个新的策略。 + * 可以为 `AvailableStrategyOptions`,为该角色定义一个新的策略,参考[`setAvailableActions()`](#setavailableactions)。 * `actions` - 定义角色时,可传入角色可访问的 `actions` 对象, - 之后会依次调用 `aclRole.grantAction` 授予资源权限。详见 [`ResourceActionsOptions`](#ResourceActionsOptions) + 之后会依次调用 `aclRole.grantAction` 授予资源权限。详见 [`aclRole.grantAction`](./acl-role.md#grantaction) ```typescript acl.define({ @@ -76,34 +76,52 @@ const role = acl.define({ 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 +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({ role: 'admin', actions: { @@ -135,64 +153,30 @@ acl.can({ action: 'destroy', }); // null ``` -### `use(fn: any)` +### `use()` +**签名** +* `use(fn: any)` 向 middlewares 中添加中间件函数。 ### `middleware()` 返回一个中间件函数,用于在 `@nocobase/server` 中使用。使用此 `middleware` 之后,`@nocobase/server` 在每次请求处理之前都会进行权限判断。 -### `setAvailableStrategy(name: string, options: AvailableStrategyOptions)` +### `allow()` -注册一个可用的权限策略 +设置资源为可公开访问 -### `registerConfigResource(name: string)` - -将传入的资源名称设置为**配置资源**。配置资源是指这样的一种资源,这些资源的改动会调用`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)` - -在不指定角色的情况下,开放资源的访问权限。 -举例来说,例如登录操作,可以被公开访问: +**签名** +* `allow(resourceName: string, actionNames: string[] | string, condition?: string | ConditionFunc)` +**类型** ```typescript -// 注册 users:login 可以被公开访问 -acl.allow('users', 'login'); +type ConditionFunc = (ctx: any) => Promise | boolean; ``` -**参数** +**详细信息** + * resourceName - 资源名称 * actionNames - 资源动作名 * condition? - 配置生效条件 @@ -212,3 +196,37 @@ acl.allow('users', 'login'); 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 定义,支持通配符 `*` + diff --git a/docs/zh-CN/api/acl/allow-manager.md b/docs/zh-CN/api/acl/allow-manager.md deleted file mode 100644 index ee9f9ad73..000000000 --- a/docs/zh-CN/api/acl/allow-manager.md +++ /dev/null @@ -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` - -获取已注册的开放条件 - -**参数** -* resourceName - 资源名称 -* actionName - 资源动作名 - -### `aclMiddleware()` - -中间件,注入于 `acl` 实例中,用于判断是否开放权限,若根据条件判断为开放权限,则在 `acl` middleware 中会跳过权限检查。 - diff --git a/docs/zh-CN/api/acl/index.md b/docs/zh-CN/api/acl/index.md deleted file mode 100644 index fedf8476d..000000000 --- a/docs/zh-CN/api/acl/index.md +++ /dev/null @@ -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` 函数,函数返回结果既为用户的鉴权结果。 diff --git a/docs/zh-CN/api/actions.md b/docs/zh-CN/api/actions.md index d6323acd2..4f64fb1cd 100644 --- a/docs/zh-CN/api/actions.md +++ b/docs/zh-CN/api/actions.md @@ -292,6 +292,58 @@ app.actions({ }); ``` +### `move()` +对应的 URL 为 `POST /api/: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/:add`。适用于 `hasMany` 和 `belongsToMany` 关联。 + +**参数** + +| 参数名 | 类型 | 默认值 | 描述 | +|----------|-------------| --- | --- | +| `values` | `TargetKey \| TargetKey[]` | - | 添加的关联对象ID | + +### `remove()` +移除与对象的关联关系,对应的 URL 为 `POST /api/:remove`。 + +**参数** + +| 参数名 | 类型 | 默认值 | 描述 | +|----------|-------------| --- | --- | +| `values` | `TargetKey \| TargetKey[]` | - | 移除的关联对象ID | + +### `set()` +设置关联的关联对象,对应的 URL 为 `POST /api/:set`。 + +**参数** + +| 参数名 | 类型 | 默认值 | 描述 | +|----------|-------------| --- | --- | +| `values` | `TargetKey \| TargetKey[]` | - | 设置的关联对象的ID | + +### `toggle()` + +切换关联的关联对象,对应的 URL 为 `POST /api/:toggle`。`toggle` 在内部判断关联对象是否已经存在,如果存在则移除,如果不存在则添加。 + +**参数** + +| 参数名 | 类型 | 默认值 | 描述 | +|----------|-------------| -- | --- | +| `values` | `TargetKey` | - | 切换的关联对象的ID | diff --git a/docs/zh-CN/api/database/relation-repository/belongs-to-many-repository.md b/docs/zh-CN/api/database/relation-repository/belongs-to-many-repository.md index c16d0e126..1c612ed46 100644 --- a/docs/zh-CN/api/database/relation-repository/belongs-to-many-repository.md +++ b/docs/zh-CN/api/database/relation-repository/belongs-to-many-repository.md @@ -1,23 +1,181 @@ -## BelongsToManyRepository +# BelongsToManyRepository +`BelongsToManyRepository` 是用于处理 `BelongsToMany` 关系的 `Relation Repository`。 -### `count()` +不同于其他关系类型,`BelongsToMany` 类型的关系需要通过中间表来记录。 +在 `Nocobase` 中定义关联关系,可自动创建中间表,也可以明确指定中间表。 + +## 类方法 ### `find()` +查找关联对象 + +**签名** + +* `async find(options?: FindOptions): Promise` + +**详细信息** + +查询参数与 [`Repository.find()`](../repository.md#find) 一致。 + ### `findOne()` +查找关联对象,仅返回一条记录 + +**签名** + +* `async findOne(options?: FindOneOptions): Promise` + + + + +### `count()` + +返回符合查询条件的记录数 + +**签名** + +* `async count(options?: CountOptions)` + +**类型** +```typescript +interface CountOptions extends Omit, Transactionable { + filter?: Filter; +} +``` + ### `findAndCount()` +从数据库查询特定条件的数据集和结果数。 + +**签名** + +* `async findAndCount(options?: FindAndCountOptions): Promise<[any[], number]>` + +**类型** +```typescript +type FindAndCountOptions = CommonFindOptions +``` + ### `create()` +创建关联对象 + +**签名** + +* `async create(options?: CreateOptions): Promise` + + + ### `update()` +更新符合条件的关联对象 + +**签名** + +* `async update(options?: UpdateOptions): Promise` + + + ### `destroy()` +删除符合条件的关联对象 + +**签名** + +* `async destroy(options?: TargetKey | TargetKey[] | DestroyOptions): Promise` + + + ### `add()` -### `remove()` +添加新的关联对象 + +**签名** + +* `async add( + options: TargetKey | TargetKey[] | PrimaryKeyWithThroughValues | PrimaryKeyWithThroughValues[] | AssociatedOptions + ): Promise` + +**类型** + +```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()` +设置关联对象 + +**签名** +* async set( + options: TargetKey | TargetKey[] | PrimaryKeyWithThroughValues | PrimaryKeyWithThroughValues[] | AssociatedOptions, + ): Promise + +**详细信息** + +参数同 [add()](#add) + +### `remove()` + +移除与给定对象之间的关联关系 + +**签名** +* `async remove(options: TargetKey | TargetKey[] | AssociatedOptions)` + +**类型** +```typescript +interface AssociatedOptions extends Transactionable { + tk?: TargetKey | TargetKey[]; +} +``` + ### `toggle()` + +切换关联对象。 + +在一些业务场景中,经常需要切换关联对象,比如用户收藏商品,用户可以取消收藏,也可以再次收藏。使用 `toggle` 方法可以快速实现类似功能。 + +**签名** + +* `async toggle(options: TargetKey | { tk?: TargetKey; transaction?: Transaction }): Promise` + +**详细信息** + +`toggle` 方法会自动判断关联对象是否已经存在,如果存在则移除,如果不存在则添加。 diff --git a/docs/zh-CN/api/database/relation-repository/belongs-to-repository.md b/docs/zh-CN/api/database/relation-repository/belongs-to-repository.md index f19d75935..15824a3d2 100644 --- a/docs/zh-CN/api/database/relation-repository/belongs-to-repository.md +++ b/docs/zh-CN/api/database/relation-repository/belongs-to-repository.md @@ -1,3 +1,3 @@ ## BelongsToRepository -`BelongsToRepository` 是用于处理 `BelongsTo` 关系的 `Repository`,它提供了一些便捷的方法来处理 `BelongsTo` 关系。其接口与 [HasOneRepository](#has-one-repository) 一致。 +`BelongsToRepository` 是用于处理 `BelongsTo` 关系的 `Repository`,它提供了一些便捷的方法来处理 `BelongsTo` 关系。其接口与 [HasOneRepository](./has-one-repository.md) 一致。 diff --git a/docs/zh-CN/api/database/relation-repository/has-many-repository.md b/docs/zh-CN/api/database/relation-repository/has-many-repository.md index d5dd9d0ae..2e4b2be42 100644 --- a/docs/zh-CN/api/database/relation-repository/has-many-repository.md +++ b/docs/zh-CN/api/database/relation-repository/has-many-repository.md @@ -1,7 +1,7 @@ # HasManyRepository -`HasManyRepository` 是用于处理 `HasMany` 关系的 `Repository`。 +`HasManyRepository` 是用于处理 `HasMany` 关系的 `Relation Repository`。 ## 类方法 @@ -13,11 +13,9 @@ * `async find(options?: FindOptions): Promise` -**参数** +**详细信息** -| 参数名 | 类型 | 默认值 | 描述 | -| --- | --- | --- | --- | -| `options` | `FindOptions` | - | 参见 repository.find | +查询参数与 [`Repository.find()`](../repository.md#find) 一致。 ### `findOne()` @@ -27,11 +25,8 @@ * `async findOne(options?: FindOneOptions): Promise` -**参数** + -| 参数名 | 类型 | 默认值 | 描述 | -| --- | --- | --- | --- | -| `options` | `FindOneOptions` | - | 参见 repository.findOne | ### `count()` @@ -41,26 +36,25 @@ * `async count(options?: CountOptions)` -**参数** - -| 参数名 | 类型 | 默认值 | 描述 | -| --- | --- | --- | --- | -| `options` | `CountOptions` | - | 参见 repository.count | - +**类型** +```typescript +interface CountOptions extends Omit, Transactionable { + filter?: Filter; +} +``` ### `findAndCount()` -同时返回符合查询条件的记录集合与记录数 +从数据库查询特定条件的数据集和结果数。 **签名** * `async findAndCount(options?: FindAndCountOptions): Promise<[any[], number]>` -**参数** - -| 参数名 | 类型 | 默认值 | 描述 | -| --- | --- | --- | --- | -| `options` | `FindAndCountOptions` | - | 参见 repository.findAndCount | +**类型** +```typescript +type FindAndCountOptions = CommonFindOptions +``` ### `create()` @@ -71,12 +65,7 @@ * `async create(options?: CreateOptions): Promise` -**参数** - -| 参数名 | 类型 | 默认值 | 描述 | -| --- | --- | --- | --- | -| `options` | `CreateOptions` | - | 参见 repository.create | - + ### `update()` @@ -86,12 +75,7 @@ * `async update(options?: UpdateOptions): Promise` -**参数** - -| 参数名 | 类型 | 默认值 | 描述 | -| --- | --- | --- | --- | -| `options` | `UpdateOptions` | - | 参见 repository.update | - + ### `destroy()` @@ -101,41 +85,37 @@ * `async destroy(options?: TK | DestroyOptions): Promise` -**参数** - -| 参数名 | 类型 | 默认值 | 描述 | -| --- | --- | --- | --- | -| `options` | `TK \|DestroyOptions` | - | 传入删除对象的 `targetKeyId`,或者 `targetKeyId` 数组。需传 `transaction` 时 使用 `DestroyOptions` 类型 | + ### `add()` -添加关联对象 +添加对象关联关系 **签名** * `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 值,可以是单个值,也可以是数组。 + ### `remove()` -移除符合条件的关联对象 +移除与给定对象之间的关联关系 **签名** * `async remove(options: TargetKey | TargetKey[] | AssociatedOptions)` -**参数** - -| 参数名 | 类型 | 默认值 | 描述 | -| --- | --- | --- | --- | -| `options` | `TargetKey \| TargetKey[] \| AssociatedOptions` | - | 同 [add](#add) | +**详细信息** +参数同 [`add()`](#add) 方法。 ### `set()` @@ -145,8 +125,8 @@ * `async set(options: TargetKey | TargetKey[] | AssociatedOptions)` -**参数** +**详细信息** + +参数同 [`add()`](#add) 方法。 + -| 参数名 | 类型 | 默认值 | 描述 | -| --- | --- | --- | --- | -| `options` | `TargetKey \| TargetKey[] \| AssociatedOptions` | - | 同 [add](#add) | diff --git a/docs/zh-CN/api/database/relation-repository/has-one-repository.md b/docs/zh-CN/api/database/relation-repository/has-one-repository.md index 5ecc683df..fd1037604 100644 --- a/docs/zh-CN/api/database/relation-repository/has-one-repository.md +++ b/docs/zh-CN/api/database/relation-repository/has-one-repository.md @@ -26,18 +26,44 @@ const userProfileRepository = new HasOneRepository(User, 'profile', user.get('id ## 类方法 -### `create(options?: CreateOptions)` +### `find()` + +查找关联对象 + +**签名** + +* `async find(options?: SingleRelationFindOption): Promise | 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` -**参数** - -| 参数名 | 类型 | 默认值 | 描述 | -| --- | --- | --- | --- | -| `options` | `CreateOptions` | - | 参见 repository.create | + **示例** @@ -59,30 +85,6 @@ console.log(profile.toJSON()); ``` -### `find()` - -查找关联对象 - -**签名** - -* `async find(options?: SingleRelationFindOption): Promise | 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()` 更新关联对象 @@ -91,11 +93,8 @@ const profile = await UserProfileRepository.find(); * `async update(options: UpdateOptions): Promise` -**参数** + -| 参数名 | 类型 | 默认值 | 描述 | -| --- | --- | --- | --- | -| `options` | `UpdateOptions` | - | 参见 repository.update | **示例** @@ -115,11 +114,9 @@ profile.get('avatar'); // 'avatar2' * `async remove(options?: Transactionable): Promise` -**参数** +**详细信息** -| 参数名 | 类型 | 默认值 | 描述 | -| --- | --- | --- | --- | -| `options.transaction` | `Transaction` | - | Transaction | +* `transaction`: 事务对象。如果没有传入事务参数,该方法会自动创建一个内部事务。 **示例** @@ -139,11 +136,9 @@ await Profile.repository.count() === 1; // true * `async destroy(options?: Transactionable): Promise` -**参数** +**详细信息** -| 参数名 | 类型 | 默认值 | 描述 | -| --- | --- | --- | --- | -| `options.transaction` | `Transaction` | - | Transaction | +* `transaction`: 事务对象。如果没有传入事务参数,该方法会自动创建一个内部事务。 **示例** @@ -161,11 +156,17 @@ await Profile.repository.count() === 0; // true * `async set(options: TargetKey | SetOption): Promise` -**参数** +**类型** -| 参数名 | 类型 | 默认值 | 描述 | -| --- | --- | --- | --- | -| `options` | ` TargetKey \| SetOption` | - | 需要 set 的对象的 targetKey,如果需要一同传入 transaction 则修改为 object 类型参数 | +```typescript +interface SetOption extends Transactionable { + tk?: TargetKey; +} +```` +**详细信息** + +* tk: 设置关联对象的 targetKey +* transaction: 事务对象。如果没有传入事务参数,该方法会自动创建一个内部事务。 **示例** diff --git a/docs/zh-CN/api/database/repository.md b/docs/zh-CN/api/database/repository.md index 66c6a1a01..f80fde92f 100644 --- a/docs/zh-CN/api/database/repository.md +++ b/docs/zh-CN/api/database/repository.md @@ -53,35 +53,6 @@ await books.myQuery('SELECT * FROM books;'); ## 实例方法 -### `count()` - -从数据库查询特定条件的数据总数。相当于 Sequelize 中的 `Model.count()`。 - -**签名** - -* `count(options?: CountOptions): Promise` - -**参数** - -| 参数名 | 类型 | 默认值 | 描述 | -| --- | --- | --- | --- | -| `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()` @@ -91,21 +62,84 @@ const count = await books.count({ * `async find(options?: FindOptions): Promise` -**参数** +**类型** +```typescript +type Filter = FilterWithOperator | FilterWithValue | FilterAnd | FilterOr; +type Appends = string[]; +type Except = string[]; +type Fields = string[]; +type Sort = string[] | string; -| 参数名 | 类型 | 默认值 | 描述 | -| --- | --- | --- | --- | -| `options.filterByTk?` | `number \| string` | `{}` | 主键值 | -| `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` | - | 事务 | +interface SequelizeFindOptions { + limit?: number; + offset?: number; +} -`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` -**参数** - -| 参数名 | 类型 | 默认值 | 描述 | -| --- | --- | --- | --- | -| `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` + +**类型** +```typescript +interface CountOptions extends Omit, Transactionable { + filter?: Filter; +} +``` + +**示例** + +```ts +const books = db.getRepository('books'); + +const count = await books.count({ + filter: { + title: '三字经' + } +}); +``` + + ### `findAndCount()` -从数据库查询特定条件的数据集和总数。相当于 Sequelize 中的 `Model.findAndCountAll()`。 +从数据库查询特定条件的数据集和结果数。相当于 Sequelize 中的 `Model.findAndCountAll()`。 **签名** * `async findAndCount(options?: FindAndCountOptions): Promise<[Model[], number]>` -**参数** +**类型** +```typescript +type FindAndCountOptions = Omit & CommonFindOptions; +``` -所有参数与 [`find()`](#find) 相同。 +**详细信息** + +查询参数与 `find()` 相同。返回值为一个数组,第一个元素为查询结果,第二个元素为结果总数。 ### `create()` @@ -176,16 +230,7 @@ const result = await posts.findOne({ * `async create(options: CreateOptions): Promise` -**参数** - -| 参数名 | 类型 | 默认值 | 描述 | -| --- | --- | --- | --- | -| `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` -**参数** +**类型** +```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(options: UpdateOptions): Promise` -**参数** - -| 参数名 | 类型 | 默认值 | 描述 | -| --- | --- | --- | --- | -| `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` -**参数** +**类型** -| 参数名 | 类型 | 默认值 | 描述 | -| --- | --- | --- | --- | -| `options.filterByTk` | `number \| string` | - | 查询主键 | -| `options.filter` | `Filter` | - | 查询条件 | -| `options.transaction?` | `Transaction` | - | 事务 | +```typescript +interface DestroyOptions extends SequelizeDestroyOptions { + filter?: Filter; + filterByTk?: TargetKey | TargetKey[]; + truncate?: boolean; + context?: any; +} +``` -`filterByTk` 与 `filter` 至少要传其一。如果没有传入事务参数,该方法会自动创建一个内部事务。 +**详细信息** -## 关系数据仓库类 - -通过 `db.getRepository('', )` 方法获取到的关系数据仓库管理实例,在调用方法时,会自动在查询条件中加入当前表的主键值。除此以外,还拥有一些基于不同关系类型特有的成员和关系操作方法。 - -### `set()` - -相当于 Sequelize 的 `record.setXxx()` 方法,用于设置关联数据。对一的关系参数为对应的外键,对多的关系参数为对应的外键数组。如果关系类型为 `BelongsToMany`,则会自动创建中间表数据。 - -**签名** - -* `async set(association: string | number | string[] | number[]): Promise` - -**参数** - -| 参数名 | 类型 | 默认值 | 描述 | -| --- | --- | --- | --- | -| `association` | `string \| number \| string[] \| number[]` | - | 关联数据的外键,对多时可用数组 | - -### `add()` - -相当于 Sequelize 的 `record.addXxx()` 方法,用于附加关联,仅针对对多关系。 - -**签名** - -* `async add(association: string | number | string[] | number[]): Promise` - -**参数** - -| 参数名 | 类型 | 默认值 | 描述 | -| --- | --- | --- | --- | -| `association` | `string \| number \| string[] \| number[]` | - | 关联数据的外键 | - -### `remove()` - -相当于 Sequelize 的 `record.removeXxx()` 方法,用于移除关联,仅针对对多关系。 - -**签名** - -* `async remove(association: string | number | string[] | number[]): Promise` - -**参数** - -| 参数名 | 类型 | 默认值 | 描述 | -| --- | --- | --- | --- | -| `association` | `string \| number \| string[] \| number[]` | - | 关联数据的外键 | +* `filter`:指定要删除的记录的过滤条件。Filter 详细用法可参考 [`find()`](#find) 方法。 +* `filterByTk`:按 TargetKey 指定要删除的记录的过滤条件。 +* `truncate`: 是否清空表数据,在没有传入 `filter` 或 `filterByTk` 参数时有效。 +* `transaction`: 事务对象。如果没有传入事务参数,该方法会自动创建一个内部事务。 diff --git a/docs/zh-CN/api/database/shared.md b/docs/zh-CN/api/database/shared.md new file mode 100644 index 000000000..fd2b409fb --- /dev/null +++ b/docs/zh-CN/api/database/shared.md @@ -0,0 +1,8 @@ +**参数** + +| 参数名 | 类型 | 默认值 | 描述 | +| --- | --- | --- | --- | +| `options.values` | `M` | `{}` | 插入的数据对象 | +| `options.whitelist?` | `string[]` | - | `values` 字段的白名单,只有名单内的字段会被存储 | +| `options.blacklist?` | `string[]` | - | `values` 字段的黑名单,名单内的字段不会被存储 | +| `options.transaction?` | `Transaction` | - | 事务 | diff --git a/docs/zh-CN/api/database/shared/create-options.md b/docs/zh-CN/api/database/shared/create-options.md new file mode 100644 index 000000000..51b245a45 --- /dev/null +++ b/docs/zh-CN/api/database/shared/create-options.md @@ -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`: 事务对象。如果没有传入事务参数,该方法会自动创建一个内部事务。 diff --git a/docs/zh-CN/api/database/shared/destroy-options.md b/docs/zh-CN/api/database/shared/destroy-options.md new file mode 100644 index 000000000..aaf8e63b9 --- /dev/null +++ b/docs/zh-CN/api/database/shared/destroy-options.md @@ -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`: 事务对象。如果没有传入事务参数,该方法会自动创建一个内部事务。 diff --git a/docs/zh-CN/api/database/shared/find-one.md b/docs/zh-CN/api/database/shared/find-one.md new file mode 100644 index 000000000..47e5f2192 --- /dev/null +++ b/docs/zh-CN/api/database/shared/find-one.md @@ -0,0 +1,8 @@ +**类型** +```typescript +type FindOneOptions = Omit; +``` + +**参数** + +大部分参数与 `find()` 相同,不同之处在于 `findOne()` 只返回单条数据,所以不需要 `limit` 参数,且查询时始终为 `1`。 diff --git a/docs/zh-CN/api/database/shared/find-options.md b/docs/zh-CN/api/database/shared/find-options.md new file mode 100644 index 000000000..e69de29bb diff --git a/docs/zh-CN/api/database/shared/transaction.md b/docs/zh-CN/api/database/shared/transaction.md new file mode 100644 index 000000000..27068fcf9 --- /dev/null +++ b/docs/zh-CN/api/database/shared/transaction.md @@ -0,0 +1 @@ +* `transaction`: 事务对象。如果没有传入事务参数,该方法会自动创建一个内部事务。 diff --git a/docs/zh-CN/api/database/shared/update-options.md b/docs/zh-CN/api/database/shared/update-options.md new file mode 100644 index 000000000..ea03c3ea7 --- /dev/null +++ b/docs/zh-CN/api/database/shared/update-options.md @@ -0,0 +1,24 @@ +**类型** +```typescript +interface UpdateOptions extends Omit { + 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` 至少要传其一。 diff --git a/packages/core/acl/src/acl.ts b/packages/core/acl/src/acl.ts index dcc14e932..6df2316fc 100644 --- a/packages/core/acl/src/acl.ts +++ b/packages/core/acl/src/acl.ts @@ -156,7 +156,8 @@ export class ACL extends EventEmitter { 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); if (!aclRole) { diff --git a/packages/core/database/src/options-parser.ts b/packages/core/database/src/options-parser.ts index fad76a007..0582d6367 100644 --- a/packages/core/database/src/options-parser.ts +++ b/packages/core/database/src/options-parser.ts @@ -191,8 +191,9 @@ export class OptionsParser { /** * set include params - * @param includeRoot - * @param appends + * @param model + * @param queryParams + * @param append */ const setInclude = (model: ModelCtor, queryParams: any, append: string) => { const appendFields = append.split('.'); diff --git a/packages/core/database/src/relation-repository/belongs-to-many-repository.ts b/packages/core/database/src/relation-repository/belongs-to-many-repository.ts index c91144783..1d5438e93 100644 --- a/packages/core/database/src/relation-repository/belongs-to-many-repository.ts +++ b/packages/core/database/src/relation-repository/belongs-to-many-repository.ts @@ -1,9 +1,9 @@ import lodash from 'lodash'; import { BelongsToMany, Op, Transaction } from 'sequelize'; 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 { FindAndCountOptions, FindOneOptions, MultipleRelationRepository } from './multiple-relation-repository'; +import { FindAndCountOptions, MultipleRelationRepository } from './multiple-relation-repository'; import { transaction } from './relation-repository'; import { AssociatedOptions, PrimaryKeyWithThroughValues } from './types'; @@ -14,7 +14,7 @@ interface IBelongsToManyRepository { findAndCount(options?: FindAndCountOptions): Promise<[M[], number]>; findOne(options?: FindOneOptions): Promise; // 新增并关联,存在中间表数据 - create(options?: CreateBelongsToManyOptions): Promise; + create(options?: CreateOptions): Promise; // 更新,存在中间表数据 update(options?: UpdateOptions): Promise; // 删除 diff --git a/packages/core/database/src/relation-repository/hasmany-repository.ts b/packages/core/database/src/relation-repository/hasmany-repository.ts index 8e820f1f8..da721b59d 100644 --- a/packages/core/database/src/relation-repository/hasmany-repository.ts +++ b/packages/core/database/src/relation-repository/hasmany-repository.ts @@ -1,13 +1,16 @@ import { omit } from 'lodash'; import { HasMany, Op } from 'sequelize'; import { Model } from '../model'; -import { CreateOptions, DestroyOptions, FindOptions, TargetKey, TK, UpdateOptions } from '../repository'; import { - AssociatedOptions, - FindAndCountOptions, + CreateOptions, + DestroyOptions, FindOneOptions, - MultipleRelationRepository -} from './multiple-relation-repository'; + FindOptions, + TargetKey, + TK, + UpdateOptions, +} from '../repository'; +import { AssociatedOptions, FindAndCountOptions, MultipleRelationRepository } from './multiple-relation-repository'; import { transaction } from './relation-repository'; interface IHasManyRepository { diff --git a/packages/core/database/src/relation-repository/hasone-repository.ts b/packages/core/database/src/relation-repository/hasone-repository.ts index cd0c7f907..da1f8a5c9 100644 --- a/packages/core/database/src/relation-repository/hasone-repository.ts +++ b/packages/core/database/src/relation-repository/hasone-repository.ts @@ -2,12 +2,10 @@ import { Model } from '../model'; import { CreateOptions } from '../repository'; import { SingleRelationFindOption, SingleRelationRepository } from './single-relation-repository'; -interface HasOneFindOptions extends SingleRelationFindOption {} - interface IHasOneRepository { // 不需要 findOne,find 就是 findOne - find(options?: HasOneFindOptions): Promise; - findOne(options?: HasOneFindOptions): Promise; + find(options?: SingleRelationFindOption): Promise; + findOne(options?: SingleRelationFindOption): Promise; // 新增并关联,如果存在关联,解除之后,与新数据建立关联 create(options?: CreateOptions): Promise; // 更新 diff --git a/packages/core/database/src/relation-repository/multiple-relation-repository.ts b/packages/core/database/src/relation-repository/multiple-relation-repository.ts index a82cb2df0..cf72a29e4 100644 --- a/packages/core/database/src/relation-repository/multiple-relation-repository.ts +++ b/packages/core/database/src/relation-repository/multiple-relation-repository.ts @@ -5,7 +5,7 @@ import { CountOptions, DestroyOptions, Filter, - FilterByTk, + FindOneOptions, FindOptions, TargetKey, TK, @@ -16,9 +16,7 @@ import { UpdateGuard } from '../update-guard'; import { RelationRepository, transaction } from './relation-repository'; import { handleAppendsQuery } from '../utils'; -export interface FindAndCountOptions extends CommonFindOptions {} - -export interface FindOneOptions extends CommonFindOptions, FilterByTk {} +export type FindAndCountOptions = CommonFindOptions; export interface AssociatedOptions extends Transactionable { tk?: TK; @@ -88,6 +86,7 @@ export abstract class MultipleRelationRepository extends RelationRepository { async findAndCount(options?: FindAndCountOptions): Promise<[any[], number]> { const transaction = await this.getTransaction(options, false); + return [ await this.find({ ...options, diff --git a/packages/core/database/src/repository.ts b/packages/core/database/src/repository.ts index 38b514440..402edd5bd 100644 --- a/packages/core/database/src/repository.ts +++ b/packages/core/database/src/repository.ts @@ -2,6 +2,7 @@ import lodash, { omit } from 'lodash'; import { Association, BulkCreateOptions, + CountOptions as SequelizeCountOptions, CreateOptions as SequelizeCreateOptions, DestroyOptions as SequelizeDestroyOptions, FindAndCountOptions as SequelizeAndCountOptions, @@ -11,6 +12,7 @@ import { Transactionable, UpdateOptions as SequelizeUpdateOptions } from 'sequelize'; +import { WhereOperators } from 'sequelize/types/lib/model'; import { Collection } from './collection'; import { Database } from './database'; import mustHaveFilter from './decorators/must-have-filter-decorator'; @@ -18,6 +20,7 @@ import { transactionWrapperBuilder } from './decorators/transaction-decorator'; import { RelationField } from './fields'; import FilterParser from './filter-parser'; import { Model } from './model'; +import operators from './operators'; import { OptionsParser } from './options-parser'; import { BelongsToManyRepository } from './relation-repository/belongs-to-many-repository'; import { BelongsToRepository } from './relation-repository/belongs-to-repository'; @@ -45,7 +48,32 @@ export interface FilterAble { export type TargetKey = string | number; 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 Except = string[]; export type Fields = string[]; @@ -53,12 +81,12 @@ export type Sort = string[] | string; export type WhiteList = string[]; export type BlackList = string[]; + export type AssociationKeysToBeUpdate = string[]; export type Values = any; -export interface CountOptions extends Omit, Transactionable { - fields?: Fields; +export interface CountOptions extends Omit, Transactionable { filter?: Filter; } @@ -66,7 +94,7 @@ export interface FilterByTk { filterByTk?: TargetKey; } -export interface FindOptions extends SequelizeFindOptions, CommonFindOptions, FilterByTk {} +export type FindOptions = SequelizeFindOptions & CommonFindOptions & FilterByTk; export interface CommonFindOptions extends Transactionable { filter?: Filter; @@ -77,7 +105,7 @@ export interface CommonFindOptions extends Transactionable { context?: any; } -interface FindOneOptions extends FindOptions {} +export type FindOneOptions = Omit; export interface DestroyOptions extends SequelizeDestroyOptions { filter?: Filter; @@ -86,18 +114,7 @@ export interface DestroyOptions extends SequelizeDestroyOptions { context?: any; } -interface FindAndCountOptions extends Omit { - // 数据过滤 - filter?: Filter; - // 输出结果显示哪些字段 - fields?: Fields; - // 输出结果不显示哪些字段 - except?: Except; - // 附加字段,用于控制关系字段的输出 - appends?: Appends; - // 排序,字段前面加上 “-” 表示降序 - sort?: Sort; -} +type FindAndCountOptions = Omit & CommonFindOptions; export interface CreateOptions extends SequelizeCreateOptions { values?: Values | Values[]; @@ -359,6 +376,7 @@ export class Repository; -}; +} export default class VerificationPlugin extends Plugin { providers: Registry = new Registry(); @@ -49,10 +49,10 @@ export default class VerificationPlugin extends Plugin { type: key, content, expiresAt: { - [Op.gt]: new Date() + [Op.gt]: new Date(), }, - status: CODE_STATUS_UNUSED - } + status: CODE_STATUS_UNUSED, + }, }); if (!item) { @@ -70,10 +70,9 @@ export default class VerificationPlugin extends Plugin { // or delete await item.update({ - status: CODE_STATUS_USED + status: CODE_STATUS_USED, }); - } - + }; getName(): string { return this.getPackageName(__dirname); @@ -86,13 +85,14 @@ export default class VerificationPlugin extends Plugin { INIT_ALI_SMS_ACCESS_KEY_SECRET, INIT_ALI_SMS_ENDPOINT = 'dysmsapi.aliyuncs.com', INIT_ALI_SMS_VERIFY_CODE_TEMPLATE, - INIT_ALI_SMS_VERIFY_CODE_SIGN + INIT_ALI_SMS_VERIFY_CODE_SIGN, } = process.env; - if (INIT_ALI_SMS_ACCESS_KEY - && INIT_ALI_SMS_ACCESS_KEY_SECRET - && INIT_ALI_SMS_VERIFY_CODE_TEMPLATE - && INIT_ALI_SMS_VERIFY_CODE_SIGN + if ( + INIT_ALI_SMS_ACCESS_KEY && + INIT_ALI_SMS_ACCESS_KEY_SECRET && + INIT_ALI_SMS_VERIFY_CODE_TEMPLATE && + INIT_ALI_SMS_VERIFY_CODE_SIGN ) { const ProviderRepo = this.db.getRepository('verifications_providers'); await ProviderRepo.create({ @@ -105,9 +105,9 @@ export default class VerificationPlugin extends Plugin { accessKeySecret: INIT_ALI_SMS_ACCESS_KEY_SECRET, endpoint: INIT_ALI_SMS_ENDPOINT, sign: INIT_ALI_SMS_VERIFY_CODE_SIGN, - template: INIT_ALI_SMS_VERIFY_CODE_TEMPLATE - } - } + template: INIT_ALI_SMS_VERIFY_CODE_TEMPLATE, + }, + }, }); } }