## 1. Project Overview & Quickstart (nocobase/README.pt-BR)

## 1. Project Overview & Quickstart (nocobase/README.pt-BR)

## 1. Project Overview & Quickstart (nocobase/README.pt-BR)

## 1. Project Overview & Quickstart (nocobase/README.pt-BR)

## 1. Project Overview & Quickstart (nocobase/README.pt-BR)

# Technical Documentation: nocobase/README.pt-BR

> ℹ️ **Provenance:** Multi-Tier Ingestion · [CodeWiki Reference](https://codewiki.google/github.com/nocobase/README.pt-BR)

# README.pt-BR

### Agent Skills & Rules
- Discovered 21 agent rule(s) and prompt configurations.



--- METRICS ---
- Files Extracted: 1
- Estimated Token Budget: ~25 tokens
- Canonical Reference: https://codewiki.google/github.com/nocobase/README.pt-BR


## 2. Official Technical Reference & Guides (nocobase/docs)

## File: README.md

# NocoBase V1 Documentation (Archived)

> **This repository is archived and no longer maintained.** V2 documentation lives in the main repository: [nocobase/nocobase](https://github.com/nocobase/nocobase) (under the `docs/` directory). For the latest docs, visit [docs.nocobase.com](https://docs.nocobase.com).

If you need to access the V1 documentation, you can run it locally:

## Local Development

```bash
git clone https://github.com/nocobase/docs.git
cd docs
yarn install

# Run English docs
yarn dev:en

# Run Chinese docs
yarn dev

# Run French docs
yarn dev:fr

# Run Japanese docs
yarn dev:ja

# Run Russian docs
yarn dev:ru
```

## Build

```bash
yarn build
```

Note: `yarn dev` and `yarn dev:en` cannot be run at the same time.

---

## File: package.json

{
  "name": "nocobase-docs",
  "version": "0.0.1",
  "description": "A static site based on dumi",
  "scripts": {
    "start": "npm run dev",
    "dev": "dumi dev",
    "dev:en": "cross-env DOC_LANG=en-US dumi dev",
    "dev:fr": "cross-env DOC_LANG=fr-FR dumi dev",
    "dev:ja": "cross-env DOC_LANG=ja-JP dumi dev",
    "dev:ru": "cross-env DOC_LANG=ru-RU dumi dev",
    "build": "dumi build",
    "build:en": "cross-env DOC_LANG=en-US dumi build",
    "build:fr": "cross-env DOC_LANG=fr-FR dumi build",
    "build:ja": "cross-env DOC_LANG=ja-JP dumi build",
    "build:ru": "cross-env DOC_LANG=ru-RU dumi build",
    "prepare": "husky install && dumi setup"
  },
  "authors": [],
  "license": "MIT",
  "commitlint": {
    "extends": [
      "@commitlint/config-conventional"
    ]
  },
  "lint-staged": {
    "*.{md,json}": [
      "prettier --write --no-error-on-unmatched-pattern"
    ]
  },
  "devDependencies": {
    "@alicloud/cdn20180510": "^4.2.2",
    "@commitlint/cli": "^18.2.0",
    "@commitlint/config-conventional": "^18.1.0",
    "ali-oss": "^6.1.0",
    "cross-env": "^7.0.3",
    "dumi": "^2.2.14",
    "husky": "^8.0.3",
    "lint-staged": "^15.0.2",
    "prettier": "^3.0.3"
  },
  "dependencies": {
    "@formulajs/formulajs": "^4.4.9",
    "@nocobase/client": "^0.21.0-alpha.6",
    "axios-mock-adapter": "1.22.0",
    "cytoscape": "^3.23.0",
    "dumi-theme-nocobase": "^0.2.31",
    "moment": "^2.30.1",
    "sucrase": "^3.0.0",
    "vditor": "^3.10.8"
  },
  "volta": {
    "node": "20.14.0",
    "yarn": "1.22.19"
  },
  "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
}

---

## File: tsconfig.json

{
  "compilerOptions": {
    "jsx": "react",
    "strict": true,
    "skipLibCheck": true,
    "noImplicitAny": false,
    "esModuleInterop": true,
    "baseUrl": "./",
    "paths": {
      "@@/*": [".dumi/tmp/*"]
    }
  },
  "include": [".dumirc.ts"]
}

---

## File: docs/en-US/components.md

# Components

---

## File: docs/en-US/index.md

# Index

<Navigate replace to="/welcome/introduction"></Navigate>

---

## File: docs/en-US/_partials/commercial-installation.md

## Installation

This plugin is a commercial plugin, which needs to be uploaded and activated through the plugin manager：

---

## File: docs/en-US/api/actions.md

# @nocobase/actions

## Overview

The `@nocobase/actions` package encapsulates frequently used CRUD-related methods. By simply registering it with the [ResourceManager](./resourcer/resource-manager), CRUD operation interfaces can be globally added to system resources.

### Basic Usage

```typescript
import * as actions from `@nocobase/actions`;

const resourceManager = new ResourceManager({
  // ...options
});

resourceManager.registerActionHandlers(actions);
```

## Action Methods

### create

Creates a resource. `POST /api/<resource>:create`.

```shell
curl "http://localhost:13000/api/users:create" \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{"username": "admin"}'
```

#### Request Body

| Parameter Name  | Type  | Description                                     |
| --------------- | ----- | ----------------------------------------------- |
| `[key: string]` | `any` | Key-value pairs representing resource fields    |

### list

Retrieves a list of resources. `GET /api/<resource>:list`.

```shell
curl -X GET http://localhost:13000/api/users:list
```

#### Parameters

| Parameter  | Type       | Description                                                        | Default |
| ---------- | ---------- | ------------------------------------------------------------------ | ------- |
| `filter`   | `Filter`   | Filtering parameters, see [Filter Operators](./database/operators) | -       |
| `fields`   | `string[]` | Fields to retrieve                                                 | -       |
| `except`   | `string[]` | Fields to exclude                                                  | -       |
| `appends`  | `string[]` | Related fields to append                                           | -       |
| `sort`     | `string[]` | Sorting parameters                                                 | -       |
| `paginate` | `boolean`  | Whether to use pagination                                          | `true`  |
| `page`     | `number`   | Current page number                                                | `1`     |
| `pageSize` | `number`   | Number of items per page                                           | `20`    |

### get

Retrieves a specific resource. `GET /api/<resource>:get`.

```shell
curl -X GET http://localhost:13000/api/users:get?filterByTk=1
```

#### Parameters

| Parameter    | Type               | Description                                                        | Default |
| ------------ | ------------------ | ------------------------------------------------------------------ | ------- |
| `filterByTk` | `number \| string` | Filter by primary key value                                        | -       |
| `filter`     | `Filter`           | Filtering parameters, see [Filter Operators](./database/operators) | -       |
| `fields`     | `string[]`         | Fields to retrieve                                                 | -       |
| `except`     | `string[]`         | Fields to exclude                                                  | -       |
| `appends`    | `string[]`         | Related fields to append                                           | -       |

### update

Updates one or more resources. `PUT /api/<resource>:update`.

```shell
curl "http://localhost:13000/api/users:update?filterByTk=1" \
  -X PUT \
  -H "Content-Type: application/json" \
  -d '{"username": "admin"}'
```

#### Parameters

| Parameter    | Type               | Description                                                        |
| ------------ | ------------------ | ------------------------------------------------------------------ |
| `filter`     | `Filter`           | Filtering parameters, see [Filter Operators](./database/operators) |
| `filterByTk` | `number \| string` | Filter by primary key value                                        |

*Note: At least one of `filter` or `filterByTk` must be provided.*

#### Request Body

| Parameter Name  | Type  | Description                                     |
| --------------- | ----- | ----------------------------------------------- |
| `[key: string]` | `any` | Key-value pairs representing resource fields    |

### destroy

Deletes one or more resources. `DELETE /api/<resource>:destroy`.

```shell
curl -X DELETE http://localhost:13000/api/users:destroy?filterByTk=1
```

#### Parameters

| Parameter    | Type               | Description                                                        |
| ------------ | ------------------ | ------------------------------------------------------------------ |
| `filter`     | `Filter`           | Filtering parameters, see [Filter Operators](./database/operators) |
| `filterByTk` | `number \| string` | Filter by primary key value                                        |

*Note: At least one of `filter` or `filterByTk` must be provided.*

### firstOrCreate

Retrieves or creates a resource. `POST /api/<resource>:firstOrCreate`.

```shell
curl "http://localhost:13000/api/users:firstOrCreate?filterKeys[]=username" \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{"username": "admin", "nickname": "Admin"}'
```

#### Parameters

| Parameter    | Type       | Description                                                |
| ------------ | ---------- | ---------------------------------------------------------- |
| `filterKeys` | `string[]` | Fields in the request body used to find existing resources |

#### Request Body

| Parameter Name  | Type  | Description                                     |
| --------------- | ----- | ----------------------------------------------- |
| `[key: string]` | `any` | Key-value pairs representing resource fields    |

### updateOrCreate

Updates or creates a resource. `POST /api/<resource>:updateOrCreate`.

```shell
curl "http://localhost:13000/api/users:updateOrCreate?filterKeys[]=username" \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{"username": "admin", "nickname": "Admin"}'
```

#### Parameters

| Parameter    | Type       | Description                                                |
| ------------ | ---------- | ---------------------------------------------------------- |
| `filterKeys` | `string[]` | Fields in the request body used to find existing resources |

#### Request Body

| Parameter Name  | Type  | Description                                     |
| --------------- | ----- | ----------------------------------------------- |
| `[key: string]` | `any` | Key-value pairs representing resource fields    |

### move

Moves resources, adjusting the order. Typically used for drag-and-drop sorting in pages. `POST /api/<resource>:move`.

```shell
curl -X POST "http://localhost:13000/api/users:move?sourceId=1&targetId=2"
```

#### Parameters

| Parameter     | Type                       | Description                                                 | Default |
| ------------- | -------------------------- | ----------------------------------------------------------- | ------- |
| `sourceId`    | `targetKey`                | ID of the element to move                                   | -       |
| `targetId`    | `targetKey`                | ID of the element to swap positions with                    | -       |
| `sortField`   | `string`                   | Name of the field where sorting is stored                   | `sort`  |
| `targetScope` | `string`                   | Sorting scope, a resource can be sorted by different scopes | -       |
| `sticky`      | `boolean`                  | Whether to stick the moved element                          | -       |
| `method`      | `insertAfter` \| `prepend` | Insertion method: whether to insert before                  |

### set

Sets associated objects for a resource. `POST /api/<resource>/<resourceKey>/<association>:set`.

```shell
curl "http://localhost:13000/api/users/1/roles:set" \
  -X POST \
  -H "Content-Type: application/json" \
  -d '["admin", "member"]'
```

#### Request Body

- `TargetKey | TargetKey[]` - Array of primary key values for associated objects.

### add

Adds associated objects to a resource. `POST /api/<resource>/<resourceKey>/<association>:add`.

```shell
curl "http://localhost:13000/api/users/1/roles:add" \
  -X POST \
  -H "Content-Type: application/json" \
  -d '["admin"]'
```

#### Request Body

- `TargetKey | TargetKey[]` - Array of primary key values for associated objects.

### remove

Removes associated objects from a resource. `POST /api/<resource>/<resourceKey>/<association>:remove`.

```shell
curl "http://localhost:13000/api/users/1/roles:remove" \
  -X POST \
  -H "Content-Type: application/json" \
  -d '["admin"]'
```

#### Request Body

- `TargetKey | TargetKey[]` - Array of primary key values for associated objects.

### toggle

Toggles associated objects for a resource, adding them if they don't exist, or removing them if they do. `POST /api/<resource>/<resourceKey>/<association>:toggle`.

```shell
curl "http://localhost:13000/api/users/1/roles:toggle" \
  -X POST \
  -H "Content-Type: application/json" \
  -d '["admin", "member"]'
```

#### Request Body

- `TargetKey | TargetKey[]` - Array of primary key values for associated objects.

---

## File: docs/en-US/api/cli.md

# @nocobase/cli

The NocoBase CLI is designed to help you develop, build, and deploy NocoBase applications.

<Alert>

NocoBase CLI supports *ts-node* and *node* two operation modes.

- ts-node mode (Default): Used for development environment, support real-time compilation, with relatively slow response
- node mode：Used for production environment, with quick response, but you need to execute `yarn nocobase build` to compile the entire source code first

</Alert>

## Instructions For Use

```bash
$ yarn nocobase -h

Usage: nocobase [command] [options]

Options:
  -h, --help

Commands:
  console
  db:auth               Verify if the database is successfully connected
  db:sync               Generate relevant data tables and fields through the configuration of collections
  install               Install
  start                 Start application in production environment
  build                 Compile and package
  clean                 Delete the compiled files
  dev                   Start application for development environment with real-time compilation
  doc                   Documentation development
  test                  Testing
  umi
  upgrade               Upgrade
  migrator              Data migration
  pm                    Plugin manager
  help
```

## Application in Scaffolding

`scripts` in the application scaffolding `package.json` is as below:

```json
{
  "scripts": {
    "dev": "nocobase dev",
    "start": "nocobase start",
    "clean": "nocobase clean",
    "build": "nocobase build",
    "test": "nocobase test",
    "pm": "nocobase pm",
    "postinstall": "nocobase postinstall"
  }
}
```

## Command Line Extensions

NocoBase CLI is built based on [commander](https://github.com/tj/commander.js). You can write the extended commands freely in `app/server/index.ts`:

```ts
const app = new Application(config);

app.command('hello').action(() => {});
```

or in the plugin:

```ts
class MyPlugin extends Plugin {
  beforeLoad() {
    this.app.command('hello').action(() => {});
  }
}
```

Run in the terminal:

```bash
$ yarn nocobase hello
```

## Built-in Commands

Sorted by frequency of use.

### `dev`

Start application and compile code in real time in development environment.

<Alert>
NocoBase is installed automatically if it is not installed (Refer to the `install` command).
</Alert>

```bash
Usage: nocobase dev [options]

Options:
  -p, --port [port]
  --client
  --server
  -h, --help
```

Example:

```bash
# Launch application for development environment, with real-time compilation
yarn nocobase dev
# Start the server side only
yarn nocobase dev --server
# Start the client side only
yarn nocobase dev --client
```

### `start`

Start application in production environment, the code needs *yarn build*.

<Alert>

- NocoBase is installed automatically if it is not installed (Refer to the `install` command).
- The source code needs to be re-packaged if it has any modification (Refer to the `build` command).

</Alert>

```bash
$ yarn nocobase start -h

Usage: nocobase start [options]

Options:
  -p, --port
  -s, --silent
  -h, --help
```

Example:

```bash
# Launch application for production environment
yarn nocobase start
```

### `install`

Install.

```bash
$ yarn nocobase install -h

Usage: nocobase install [options]

Options:
  -f, --force
  -c, --clean
  -s, --silent
  -l, --lang [lang]
  -e, --root-email <rootEmail>
  -p, --root-password <rootPassword>
  -n, --root-nickname [rootNickname]
  -h, --help
```

Example:

```bash
# Initial installation
yarn nocobase install -l zh-CN -e admin@nocobase.com -p admin123
# Delete all data tables from NocoBase and reinstall
yarn nocobase install -f -l zh-CN -e admin@nocobase.com -p admin123
# Clear database and reinstall
yarn nocobase install -c -l zh-CN -e admin@nocobase.com -p admin123
```

<Alert>

Difference between `-f/--force` and `-c/--clean`:

- `-f/--force` Delete data tables of NocoBase
- `-c/--clean` Clear database, all data tables are deleted

</Alert>

### `upgrade`

Upgrade.

```bash
yarn nocobase upgrade
```

### `test`

*jest* test, which supports all [jest-cli](https://jestjs.io/docs/cli) options, also supports `-c, --db-clean`.

```bash
$ yarn nocobase test -h

Usage: nocobase test [options]

Options:
  -c, --db-clean        Clear database before running all tests
  -h, --help
```

Example:

```bash
# Run all test files
yarn nocobase test
# Run all test files in the specified folder
yarn nocobase test packages/core/server
# Run all tests in the specified file
yarn nocobase test packages/core/database/src/__tests__/database.test.ts

# Clear database before running all tests
yarn nocobase test -c
yarn nocobase test packages/core/server -c
```

### `build`

The source code needs to be compiled and packaged before the code is deployed to the production environment; and you need to re-build the code if it has any modification.

```bash
# All packages
yarn nocobase build
# Specified packages
yarn nocobase build app/server app/client
```

### `clean`

Delete the compiled files.

```bash
yarn clean
# Equivalent to
yarn rimraf -rf packages/*/*/{lib,esm,es,dist}
```

### `doc`

Documentation development.

```bash
# Start the documentation
yarn doc  --lang=zh-CN # Equivalent to yarn doc dev
# Build the documentation, and output it to . /docs/dist/ directory by default
yarn doc build
# View the final result of the output documentation of dist
yarn doc serve --lang=zh-CN
```

### `db:auth`

Verify if the database is successfully connected.

```bash
$ yarn nocobase db:auth -h

Usage: nocobase db:auth [options]

Options:
  -r, --retry [retry]   Number of retries
  -h, --help
```

### `db:sync`

Generate relevant data tables and fields through the configuration of collections.

```bash
$ yarn nocobase db:sync -h

Usage: nocobase db:sync [options]

Options:
  -f, --force
  -h, --help   display help for command
```

### `migrator`

Data migration.

```bash
$ yarn nocobase migrator

Positional arguments:
  <command>
    up        Applies pending migrations
    down      Revert migrations
    pending   Lists pending migrations
    executed  Lists executed migrations
    create    Create a migration file
```

### `pm`

Plugin manager.

```bash
# Create plugin
yarn pm create hello
# Register plugin
yarn pm add hello
# Enable plugin
yarn pm enable hello
# Disable plugin
yarn pm disable hello
# Remove plugin
yarn pm remove hello
```

Not achieved yet:

```bash
# Upgrade plugin
yarn pm upgrade hello
# Publish plugin
yarn pm publish hello
```

### `umi`

`app/client` is built based on [umi](https://umijs.org/), you can run other relevant commands through `nocobase umi`.

```bash
# Generate the .umi cache needed for the development environment
yarn nocobase umi generate tmp
```

### `help`

The help command, you can also use the option parameter, `-h` and `--help`.

```bash
# View all cli
yarn nocobase help
# Use -h instead
yarn nocobase -h
# Or --help
yarn nocobase --help
# View options of command db:sync
yarn nocobase db:sync -h
```

---

## File: docs/en-US/api/index.md

# Overview

| Module                                                                                                | Package               | Description                     |
| ----------------------------------------------------------------------------------------------------- | --------------------- | ------------------------------- |
| [Server](/api/server/application)                                                                     | `@nocobase/server`    | Server-side application         |
| [Database](/api/database)                                                                             | `@nocobase/database`  | Database access layer           |
| [Resourcer](/api/resourcer/resource-manager)                                                          | `@nocobase/resourcer` | Resource and route mapping      |
| [ACL](/api/acl/acl)                                                                                   | `@nocobase/acl`       | Access Control                  |
| [Auth](/api/auth/auth-manager)                                                                        | `@nocobase/auth`      | User Authentication             |
| [Client](https://client.docs-cn.nocobase.com/core/application/application) | `@nocobase/client`    | Client-side application         |
| [Cache](/api/cache/cache-manager)                                                                     | `@nocobase/cache`     | Server-side cache               |
| [Logger](/api/logger)                                                                                 | `@nocobase/logger`    | Server-side logging             |
| [Telemetry](/api/telemetry/telemetry)                                                                 | `@nocobase/telemetry` | Server-side telemetry           |
| [CLI](/api/cli)                                                                                       | `@nocobase/cli`       | NocoBase Command Line Interface |
| [SDK](/api/sdk)                                                                                       | `@nocobase/sdk`       | NocoBase SDK                    |
| [Actions](/api/actions)                                                                               | `@nocobase/actions`   | Built-in resource operations    |
| [Test](/api/test/server)                                                                              | `@nocobase/test`      | Automated testing               |

---

## File: docs/en-US/api/logger.md

# @nocobase/logger

## Create Logger

### createLogger()

Creates a custom logger.

#### Signature

- `createLogger(options: LoggerOptions)`

#### Type

```ts
interface LoggerOptions
  extends Omit<winston.LoggerOptions, 'transports' | 'format'> {
  dirname?: string;
  filename?: string;
  format?: 'logfmt' | 'json' | 'delimiter' | 'console' | winston.Logform.Format;
  transports?: ('console' | 'file' | 'dailyRotateFile' | winston.transport)[];
}
```

#### Details

- `dirname`: Log directory
- `filename`: Log file name
- `format`: Log format
- `transports`: Log transports

### createSystemLogger()

Creates system runtime logs printed in a specified method. Refer to [Logger plugin - System log](../plugins/logger/index.md#system-log).

#### Signature

- `createSystemLogger(options: SystemLoggerOptions)`

#### Type

```ts
export interface SystemLoggerOptions extends LoggerOptions {
  seperateError?: boolean; // print error seperately, default true
}
```

#### Details

- `seperateError`: Whether to print `error` level logs separately

### app.createLogger()

#### Definition

```ts
class Application {
  createLogger(options: LoggerOptions) {
    const { dirname } = options;
    return createLogger({
      ...options,
      dirname: getLoggerFilePath(this.name || 'main', dirname || ''),
    });
  }
}
```

When `dirname` is a relative path, the log files will be output to the directory named after the current application.

### plugin.createLogger()

Usage is the same as `app.createLogger()`.

#### Definition

```ts
class Plugin {
  createLogger(options: LoggerOptions) {
    return this.app.createLogger(options);
  }
}
```

## Configuration

### getLoggerLevel()

`getLoggerLevel(): 'debug' | 'info' | 'warn' | 'error'`

Gets the log level currently configured in the system.

### getLoggerFilePath()

`getLoggerFilePath(...paths: string[]): string`

Concatenates directory paths based on the log directory currently configured in the system.

### getLoggerTransports()

`getLoggerTransports(): ('console' | 'file' | 'dailyRotateFile')[]`

Gets the log output methods currently configured in the system.

### getLoggerFormat()

`getLoggerFormat(): 'logfmt' | 'json' | 'delimiter' | 'console'`

Gets the log format currently configured in the system.

## Logger Transports

### Transports

Predefined output methods.

- `Transports.console`
- `Transports.file`
- `Transports.dailyRotateFile`

```ts
import { Transports } from '@nocobase/logger';

const transport = Transports.console({
  //...
});
```

## References

- [Development - Logger](../handbook/logger/index.md)
- [Logger Plugin](../plugins/logger/index.md)

---

## File: docs/en-US/api/acl/acl.md

# ACL

## Overview

`ACL` is the permission management module used in NocoBase, responsible for user role management, permission registration and authorization, as well as permission policy evaluation and access control.

### Concepts

- **Resource**: Collections, or custom resources can be registered. Refer to [`@nocobase/resourcer`](../resourcer/resource-manager.md).
- **Action**: An operation interface for a resource, such as create, read, update, delete, or other custom actions. Refer to [`@nocobase/actions`](../actions).
- **Strategy**: Configures global permissions for roles, such as permissions for resource operations like create, read, update, delete, import, export, and system permissions like configuring the user interface.
- **Snippet**: Defines a collection of operations, enabling unified management of operation permissions. Snippet identifiers can be matched using the [minimatch](https://github.com/isaacs/minimatch) rules.

## Class Methods

### `define()`

Defines a role.

#### Signature

- `define(options: DefineOptions): ACLRole`

#### Type Definitions

```typescript
export interface DefineOptions {
  role: string;
  strategy?: string | AvailableStrategyOptions;
  actions?: ResourceActionsOptions;
  snippets?: string[];
}

export interface AvailableStrategyOptions {
  displayName?: string;
  actions?: false | string | string[];
  allowConfigure?: boolean;
  resource?: '*';
}

export interface ResourceActionsOptions {
  [actionName: string]: RoleActionParams;
}

export interface RoleActionParams {
  fields?: string[];
  filter?: any;
  own?: boolean;
  whitelist?: string[];
  blacklist?: string[];
}
```

#### Details

##### DefineOptions

| Property   | Type                                                                | Description                                                       |
| ---------- | ------------------------------------------------------------------- | ----------------------------------------------------------------- |
| `role`     | `string`                                                            | Unique identifier for the role                                    |
| `strategy` | `string` \| [`AvailableStrategyOptions`](#availablestrategyoptions) | Optional, global access strategy for the role                     |
| `actions`  | [`{ [actionName: string]: RoleActionParams; }`](#roleactionparams)  | Optional, permission configuration for actions                    |
| `snippets` | `string[]`                                                          | Optional, defines snippets that the role has permission to access |

##### AvailableStrategyOptions

| Property         | Type                              | Description                                               |
| ---------------- | --------------------------------- | --------------------------------------------------------- |
| `displayName`    | `string`                          | Optional, display name for the strategy                   |
| `action`         | `false` \| `string` \| `string[]` | Optional, operation interfaces                            |
| `allowConfigure` | `boolean`                         | Optional, whether to allow configuring the user interface |
| `resource`       | `*`                               | Applies to all resources                                  |

##### RoleActionParams

| Property    | Type       | Description                                                                                            |
| ----------- | ---------- | ------------------------------------------------------------------------------------------------------ |
| `fields`    | `string[]` | Optional, fields of the data table to operate on                                                       |
| `filter`    | `any`      | Optional, filter parameters that must be met, only records that meet the conditions can be operated on |
| `own`       | `boolean`  | Optional, whether to operate only on records created by oneself                                        |
| `whitelist` | `string[]` | Optional, whitelist of fields that can be accessed, only fields in the whitelist can be accessed       |
| `blacklist` | `string[]` | Optional, blacklist of fields that cannot be accessed, fields in the blacklist cannot be accessed      |

### `can()`

Determines the permission to execute an action and returns the final action parameters. Returns `null` if no permission.

#### Signature

- `can(options: CanArgs): CanResult | null`

#### Type Definitions

```typescript
interface CanArgs {
  role: string;
  resource: string;
  action: string;
  ctx?: any;
}

interface CanResult {
  role: string;
  resource: string;
  action: string;
  params?: any;
}
```

#### Details

##### CanArgs

| Property   | Type     | Description               |
| ---------- | -------- | ------------------------- |
| `role`     | `string` | Role identifier           |
| `resource` | `string` | Resource identifier       |
| `action`   | `string` | Action identifier         |
| `ctx`      | `any`    | Optional, request context |

##### CanResult

| Property   | Type     | Description                 |
| ---------- | -------- | --------------------------- |
| `role`     | `string` | Role identifier             |
| `resource` | `string` | Resource identifier         |
| `action`   | `string` | Action identifier           |
| `params`   | `any`    | Optional, action parameters |

### `registerSnippet()`

Registers a snippet.

#### Signature

- `registerSnippet(snippet: SnippetOptions)`

#### Type Definitions

```typescript
export type SnippetOptions = {
  name: string;
  actions: string[];
};
```

#### Details

| Property  | Type       | Description                                                                                                                              |
| --------- | ---------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `name`    | `string`   | Snippet identifier, can be matched using the [minimatch](https://github.com/isaacs/minimatch) rules. E.g., `auth.auth` matches `auth.*`. |
| `actions` | `string[]` | Resource operations included in the snippet, in the format `resource:action`. E.g., `users:list`.                                        |

### `setAvailableAction()`

Sets allowed actions.

#### Signature

- `setAvailableAction(name: string, options: AvailableActionOptions = {})`

```typescript
export interface AvailableActionOptions {
  displayName?: string;
  aliases?: string[] | string;
  resource?: string;
  // Perform operations on new data
  onNewRecord?: boolean;
  // Allow configuring fields
  allowConfigureFields?: boolean;
}
```

#### Details

| Property               | Type                   | Description                                                                           |
| ---------------------- | ---------------------- | ------------------------------------------------------------------------------------- |
| `displayName`          | `string`               | Optional, display name for the action                                                 |
| `aliases`              | `string` \| `string[]` | Optional, action aliases. E.g., aliases for `get`, `list` operations are both `view`. |
| `resource`             | `string`               | Optional, resource                                                                    |
| `onNewRecord`          | `boolean`              | Optional, whether the operation applies to new data, such as create operation         |
| `allowConfigureFields` | `boolean`              | Optional, whether to allow configuring fields                                         |

### `setAvailableStrategy()`

Sets allowed strategies for actions.

#### Signature

- `setAvailableStrategy(name: string, options: AvailableStrategyOptions)`

Refer to [AvailableStrategyOptions](#availablestrategyoptions).

### `allow()`

Defines the conditions under which operations are allowed.

```typescript
acl.allow('plugins', '*', 'public');
```

#### Signature

- `allow(resourceName: string, actionNames: string[] | string, condition?: string | ConditionFunc)`

#### Type

```typescript
export type ConditionFunc = (ctx: any) => Promise<boolean> | boolean;
```

#### Details

| Parameter      | Type                        | Description                                                                 | Default  |
| -------------- | --------------------------- | --------------------------------------------------------------------------- | -------- |
| `resourceName` | `string`                    | Resource                                                                    | -        |
| `actionNames`  | `string` \| `string[]`      | Action                                                                      | -        |
| `condition`    | `string` \| `ConditionFunc` | Optional, predefined condition identifier, or condition evaluation function | `public` |

Predefined condition identifiers:

- `public`: Public interface.
- `loggedIn`: Allowed when the user is logged in.
- `allowConfigure`: Allowed when the current user role has permission to configure the user interface.

### `addFixedParams()`

Adds fixed parameters to operations, merging them with current request parameters.

```typescript
acl.addFixedParams('users', 'list', () => {
  return {
    filter: {
      id: {
        $eq: 1,
      },
    },
  };
});
```

#### Signature

- `addFixedParams(resource: string, action: string, merger: Merger)`

#### Type Definitions

```typescript
export type Merger = () => object;
```

#### Details

| Parameter  | Type     | Description                                               |
| ---------- | -------- | --------------------------------------------------------- |
| `resource` | `string` | Resource                                                  |
| `action`   | `string` | Action                                                    |
| `merger`   | `Merger` | Function returning the fixed parameter object to be added |

### `use()`

Adds the `ACL` middleware.

```typescript
acl.use(async () => {
  return async function (ctx, next) {
    // ...
    await next();
  };
});
```

#### Signature

- `use(fn: any, options?: ToposortOptions)`

#### Details

Refer to [Middleware](../../development/server/middleware).

### `middleware()`

NocoBase access control middleware.

---

## File: docs/en-US/api/auth/auth-manager.md

# AuthManager

## Overview

`AuthManager` is the user authentication management module in NocoBase, used for registering different types of user authentication.

### Basic Usage

```ts
const authManager = new AuthManager({
  // Key to retrieve the current authenticator identifier from the request header
  authKey: 'X-Authenticator',
});

// Set methods for storing and retrieving authenticators in AuthManager
authManager.setStorer({
  get: async (name: string) => {
    return db.getRepository('authenticators').find({ filter: { name } });
  },
});

// Register an authentication type
authManager.registerTypes('basic', {
  auth: BasicAuth,
  title: 'Password',
});

// Use authentication middleware
app.resourceManager.use(authManager.middleware());
```

### Concepts

- **Authentication type (`AuthType`)**: Different types of authentication, such as Password, SMS, OIDC, SAML, etc.
- **Authenticator**: An authenticator is a database-stored entity linked to a configuration record for a specific authentication type (`AuthType`). Multiple authenticators can exist for one authentication type, each offering diffrent authentications.
- **Authenticator name**: Unique identifier for an authenticator, used to determine the current authentication employed by the current request.

## Class Methods

### `constructor()`

Constructor, creates an instance of `AuthManager`.

#### Signature

- `constructor(options: AuthManagerOptions)`

#### Types

```ts
export interface JwtOptions {
  secret: string;
  expiresIn?: string;
}

export type AuthManagerOptions = {
  authKey: string;
  default?: string;
  jwt?: JwtOptions;
};
```

#### Details

##### AuthManagerOptions

| Attribute | Type                        | Description                                                                     | Default           |
| --------- | --------------------------- | ------------------------------------------------------------------------------- | ----------------- |
| `authKey` | `string`                    | Optional key to save the current authenticator identifier in the request header | `X-Authenticator` |
| `default` | `string`                    | Optional, default authenticator identifier                                      | `basic`           |
| `jwt`     | [`JwtOptions`](#jwtoptions) | Optional, configure if using JWT for authentication                             | -                 |

##### JwtOptions

| Attribute   | Type     | Description                       | Default           |
| ----------- | -------- | --------------------------------- | ----------------- |
| `secret`    | `string` | Token secret key                  | `X-Authenticator` |
| `expiresIn` | `string` | Optional, token expiration period | `7d`              |

### `setStorer()`

Set methods for storing and retrieving authenticator data.

#### Signature

- `setStorer(storer: Storer)`

#### Types

```ts
export interface Authenticator = {
  authType: string;
  options: Record<string, any>;
  [key: string]: any;
};

export interface Storer {
  get: (name: string) => Promise<Authenticator>;
}
```

#### Details

##### Authenticator

| Attribute  | Type                  | Description                          |
| ---------- | --------------------- | ------------------------------------ |
| `authType` | `string`              | Authentication type                  |
| `options`  | `Record<string, any>` | Authenticator-related configurations |

##### Storer

`Storer` is the interface for authenticator storage, containing one method.

- `get(name: string): Promise<Authenticator>` - Get authenticator by identifier. In NocoBase, the actual returned type is [AuthModel](../../handbook/auth/dev/api#authmodel).

### `registerTypes()`

Register authentication types.

#### Signature

- `registerTypes(authType: string, authConfig: AuthConfig)`

#### Types

```ts
export type AuthExtend<T extends Auth> = new (config: Config) => T;

type AuthConfig = {
  auth: AuthExtend<Auth>; // The authentication class.
  title?: string; // The display name of the authentication type.
};
```

#### Details

| Attribute | Type               | Description                                                          |
| --------- | ------------------ | -------------------------------------------------------------------- |
| `auth`    | `AuthExtend<Auth>` | Authentication type implementation, refer to [Auth](./auth.md)       |
| `title`   | `string`           | Optional. Title of the authentication type displayed on the frontend |

### `listTypes()`

Get a list of registered authentication types.

#### Signature

- `listTypes(): { name: string; title: string }[]`

#### Details

| Attribute | Type     | Description                      |
| --------- | -------- | -------------------------------- |
| `name`    | `string` | Authentication type identifier   |
| `title`   | `string` | Title of the authentication type |

### `get()`

Get authenticator.

#### Signature

- `get(name: string, ctx: Context)`

#### Details

| Attribute | Type      | Description              |
| --------- | --------- | ------------------------ |
| `name`    | `string`  | Authenticator identifier |
| `ctx`     | `Context` | Request context          |

### `middleware()`

Authentication middleware. Get the current authenticator and perform user authentication.

---

## File: docs/en-US/api/auth/auth.md

# Auth

## Overview

`Auth` is an abstract class for user authentication types, defining the interfaces required to complete user authentication. To extend new user authentication types, you need to inherit from the `Auth` class and implement its methods. The basic implementation can be referred to as [BaseAuth](./base-auth.md).

```ts
interface IAuth {
  user: Model;
  // Check the authentication status and return the current user.
  check(): Promise<Model>;
  signIn(): Promise<any>;
  signUp(): Promise<any>;
  signOut(): Promise<any>;
}

export abstract class Auth implements IAuth {
  abstract user: Model;
  abstract check(): Promise<Model>;
  // ...
}

class CustomAuth extends Auth {
  // check: Authentication
  async check() {
    // ...
  }
}
```

## Instance Properties

### `user`

Information of the authenticated user.

#### Signature

- `abstract user: Model`

## Class Methods

### `constructor()`

Constructor, creates an instance of `Auth`.

#### Signature

- `constructor(config: AuthConfig)`

#### Types

```ts
export type AuthConfig = {
  authenticator: Authenticator;
  options: {
    [key: string]: any;
  };
  ctx: Context;
};
```

#### Details

##### AuthConfig

| Attribute       | Type                                            | Description                                                                                                                 |
| --------------- | ----------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
| `authenticator` | [`Authenticator`](./auth-manager#authenticator) | Authenticator data model, the actual type in NocoBase applications is [AuthModel](../../handbook/auth/dev/api.md#authmodel) |
| `options`       | `Record<string, any>`                           | Authenticator-related configurations                                                                                        |
| `ctx`           | `Context`                                       | Request context                                                                                                             |

### `check()`

User authentication, returns user information. This is an abstract method that all authentication types must implement.

#### Signature

- `abstract check(): Promise<Model>`

### `signIn()`

User login.

#### Signature

- `signIn(): Promise<any>`

### `signUp()`

User registration.

#### Signature

- `signUp(): Promise<any>`

### `signOut()`

User logout.

#### Signature

- `signOut(): Promise<any>`

---

## File: docs/en-US/api/auth/base-auth.md

# BaseAuth

## Overview

`BaseAuth` inherits from the abstract class [Auth](./auth.md) and serves as the basic implementation for user authentication types, using JWT as the authentication method. In most cases, extending user authentication types can be achieved by inheriting from `BaseAuth` instead of directly inheriting from the `Auth` abstract class.

```ts
class BasicAuth extends BaseAuth {
  constructor(config: AuthConfig) {
    // Set user collection
    const userCollection = config.ctx.db.getCollection('users');
    super({ ...config, userCollection });
  }

  // User authentication logic, called by `auth.signIn`
  // Returns user data
  async validate() {
    const ctx = this.ctx;
    const { values } = ctx.action.params;
    // ...
    return user;
  }
}
```

## Class Methods

### `constructor()`

Constructor, creates an instance of `BaseAuth`.

#### Signature

- `constructor(config: AuthConfig & { userCollection: Collection })`

#### Details

| Parameter        | Type         | Description                                                                                                  |
| ---------------- | ------------ | ------------------------------------------------------------------------------------------------------------ |
| `config`         | `AuthConfig` | Refer to [Auth - AuthConfig](./auth.md#authconfig)                                                           |
| `userCollection` | `Collection` | User collection, e.g., `db.getCollection('users')`, refer to [DataBase - Collection](../database/collection) |

### `user()`

Accessor for setting and getting user information, defaulting to using the `ctx.state.currentUser` object.

#### Signature

- `set user()`
- `get user()`

### `check()`

Authenticates through the request token and returns user information.

### `signIn()`

User login, generates a token.

### `signUp()`

User registration.

### `signOut()`

User logout, token expiration.

### `validate()` \*

Core authentication logic, called by the `signIn` interface, to determine whether the user can successfully log in.

---

## File: docs/en-US/api/cache/cache-manager.md

# CacheManager

## Overview

CacheManager is based on [node-cache-manager](https://github.com/node-cache-manager/node-cache-manager) and provides caching module management for NocoBase. The built-in cache types are:

- **memory**: Provided by the default lru-cache of node-cache-manager.
- **redis**: Supported by node-cache-manager-redis-yet for Redis caching.

More types can be extended and registered through the API.

### Concepts

- **Store**: Defines a caching method, including a factory method for creating caches and other related configurations. Each caching method has a unique identifier provided during registration. The two built-in caching methods correspond to the unique identifiers `memory` and `redis`.

- **Store Factory Method**: Provided by `node-cache-manager` and related extension packages, used to create caches. Examples include `memory` provided by `node-cache-manager` by default, and `redisStore` provided by `node-cache-manager-redis-yet`. In this context, the object to be provided corresponds to [`StoreOptions`](#storeoptions), which is the first parameter of the `caching` method in `node-cache-manager`.

- **Cache**: A class encapsulated by NocoBase, providing methods related to cache usage. When actually using caching, operations are performed on instances of `Cache`. Each `Cache` instance has a unique identifier, which serves as a namespace for distinguishing different modules.

## Class Methods

### `constructor()`

#### Signature

- `constructor(options?: CacheManagerOptions)`

#### Type

```ts
export type CacheManagerOptions = Partial<{
  defaultStore: string;
  stores: {
    [storeType: string]: StoreOptions;
  };
}>;

type StoreOptions = {
  store?: 'memory' | FactoryStore<Store, any>;
  close?: (store: Store) => Promise<void>;
  // global config
  [key: string]: any;
};
```

#### Details

##### CacheManagerOptions

| Property       | Type                           | Description                                                                                                                                                          |
| -------------- | ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `defaultStore` | `string`                       | Unique identifier for the default cache type.                                                                                                                        |
| `stores`       | `Record<string, StoreOptions>` | Registers cache types. The key is the unique identifier for the cache type, and the value is an object containing the registration method and global configurations. |

##### StoreOptions

| Property        | Type                                   | Description                                                                                                                                                                                              |
| --------------- | -------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `store`         | `memory` \| `FactoryStore<Store, any>` | The store factory method, corresponding to the first parameter of the `caching` method.                                                                                                                  |
| `close`         | `(store: Store) => Promise<void>`      | Optional. For middleware that requires establishing a connection, such as Redis, provide a callback method for closing the connection. The parameter is the object returned by the store factory method. |
| `[key: string]` | `any`                                  | Other global configurations for the store, corresponding to the second parameter of the `caching` method.                                                                                                |

#### Default `options`

```ts
import { redisStore, RedisStore } from 'cache-manager-redis-yet';

const defaultOptions: CacheManagerOptions = {
  defaultStore: 'memory',
  stores: {
    memory: {
      store: 'memory',
      // global config
      max: 2000,
    },
    redis: {
      store: redisStore,
      close: async (redis: RedisStore) => {
        await redis.client.quit();
      },
    },
  },
};
```

The `options` parameter will be merged with the default options. Existing default options can be omitted. For example:

```ts
const cacheManager = new CacheManager({
  stores: {
    defaultStore: 'redis',
    redis: {
      // redisStore is already provided in the default options, so only need to provide redisStore configuration.
      url: 'redis://localhost:6379',
    },
  },
});
```

### `registerStore()`

Register a new caching method. Example:

```ts
import { redisStore } from 'cache-manager-redis-yet';

cacheManager.registerStore({
  // Unique identifier for the store
  name: 'redis',
  // Factory method for creating the store
  store: redisStore,
  // Callback method for closing the store connection
  close: async (redis: RedisStore) => {
    await redis.client.quit();
  },
  // Global configurations
  url: 'xxx',
});
```

#### Signature

- `registerStore(options: { name: string } & StoreOptions)`

### `createCache()`

Create a cache. Example:

```ts
await cacheManager.createCache({
  name: 'default', // Unique identifier for the cache
  store: 'memory', // Unique identifier for the store
  prefix: 'mycache', // Automatically adds the 'mycache:' prefix to cache keys, optional
  // Other store configurations, custom configurations that will be merged with global store configurations
  max: 2000,
});
```

#### Signature

- `createCache(options: { name: string; prefix?: string; store?: string; [key: string]: any }): Promise<Cache>`

#### Details

##### options

| Property        | Type     | Description                                        |
| --------------- | -------- | -------------------------------------------------- |
| `name`          | `string` | Unique identifier for the cache                    |
| `store`         | `string` | Unique identifier for the store                    |
| `prefix`        | `string` | Optional. Prefix automatically added to cache keys |
| `[key: string]` | `any`    | Other custom store configurations                  |

When `store` is omitted, the `defaultStore` will be used. In this case, the caching

---

## File: docs/en-US/api/cache/cache.md

# Cache

## Basic Methods

You can refer to the documentation of [node-cache-manager](https://github.com/node-cache-manager/node-cache-manager).

- `get()`
- `set()`
- `del()`
- `reset()`
- `wrap()`
- `mset()`
- `mget()`
- `mdel()`
- `keys()`
- `ttl()`

## Other Methods

### `wrapWithCondition()`

Similar to `wrap()`, but can decide whether to use caching based on conditions.

```ts
async wrapWithCondition<T>(
  key: string,
  fn: () => T | Promise<T>,
  options?: {
    // External parameter to control whether to use cache results
    useCache?: boolean;
    // Determine whether to cache based on data results
    isCacheable?: (val: unknown) => boolean | Promise<boolean>;
    ttl?: Milliseconds;
  },
): Promise<T> {
```

### `setValueInObject()`

When the cached content is an object, changes the value of a specific key.

```ts
async setValueInObject(key: string, objectKey: string, value: unknown)
```

### `getValueInObject()`

When the cached content is an object, retrieves the value of a specific key.

```ts
async getValueInObject(key: string, objectKey: string)
```

### `delValueInObject()`

When the cached content is an object, deletes a specific key.

```ts
async delValueInObject(key: string, objectKey: string)
```

---

## File: docs/en-US/api/client/application.md

# Application

## Constructor

### `constructor()`

Create an application instance.

**Signature**

- `constructor(options: ApplicationOptions)`

**Example**

```ts
const app = new Application({
  apiClient: {
    baseURL: process.env.API_BASE_URL,
  },
  dynamicImport: (name: string) => {
    return import(`../plugins/${name}`);
  },
});
```

## Methods

### use()

Add Providers, build-in Providers are:

- APIClientProvider
- I18nextProvider
- AntdConfigProvider
- SystemSettingsProvider
- PluginManagerProvider
- SchemaComponentProvider
- SchemaInitializerProvider
- BlockSchemaComponentProvider
- AntdSchemaComponentProvider
- ACLProvider
- RemoteDocumentTitleProvider

### render()

Component to render the App.

```ts
import { Application } from '@nocobase/client';

export const app = new Application({
  apiClient: {
    baseURL: process.env.API_BASE_URL,
  },
  dynamicImport: (name: string) => {
    return import(`../plugins/${name}`);
  },
});

export default app.render();
```

---

## File: docs/en-US/api/client/index.md

# Overview

test

---

## File: docs/en-US/api/client/router.md

# Router

## API

### Initial

```tsx | pure
const app = new Application({
  router: {
    type: 'browser', // type default value is `browser`
  },
});

// or
const app = new Application({
  router: {
    type: 'memory',
    initialEntries: ['/'],
  },
});
```

### add Route

#### basic

```tsx | pure
import { RouteObject } from 'react-router-dom';
const app = new Application();

const Hello = () => {
  return <div>Hello</div>;
};

// first argument is `name` of route, second argument is `RouteObject`
app.router.add('root', {
  path: '/',
  element: <Hello />,
});

app.router.add('root', {
  path: '/',
  Component: Hello,
});
```

#### Component is String

```tsx | pure
app.addComponents({
  Hello,
});
app.router.add('root', {
  path: '/',
  Component: 'Hello',
});
```

#### nested

```tsx | pure
import { Outlet } from 'react-router-dom';

const Layout = () => {
  return (
    <div>
      <Link to="/home">Home</Link>
      <Link to="/about">about</Link>

      <Outlet />
    </div>
  );
};

const Home = () => {
  return <div>Home</div>;
};

const About = () => {
  return <div>About</div>;
};

app.router.add('root', {
  element: <Layout />,
});
app.router.add('root.home', {
  path: '/home',
  element: <Home />,
});
app.router.add('root.about', {
  path: '/about',
  element: <About />,
});
```

It will generate the following routes:

```tsx | pure
{
  element: <Layout />,
  children: [
    {
      path: '/home',
      element: <Home />
    },
    {
      path: '/about',
      element: <About />
    }
  ]
}
```

### remove Route

```tsx | pure
// remove route by name
app.router.remove('root.home');
app.router.remove('hello');
```

#### Router in plugin

```tsx | pure
class MyPlugin extends Plugin {
  async load() {
    // add route
    this.app.router.add('hello', {
      path: '/hello',
      element: <div>hello</div>,
    });

    // remove route
    this.app.router.remove('world');
  }
}
```

## Example

```tsx
/**
 * defaultShowCode: true
 */
import React from 'react';
import { Link, Outlet } from 'react-router-dom';
import { Application } from '@nocobase/client';

const Home = () => <h1>Home</h1>;
const About = () => <h1>About</h1>;

const Layout = () => {
  return (
    <div>
      <div>
        <Link to={'/'}>Home</Link>, <Link to={'/about'}>About</Link>
      </div>
      <Outlet />
    </div>
  );
};

const app = new Application({
  router: {
    type: 'memory',
    initialEntries: ['/'],
  },
});

app.router.add('root', {
  element: <Layout />,
});

app.router.add('root.home', {
  path: '/',
  element: <Home />,
});

app.router.add('root.about', {
  path: '/about',
  element: <About />,
});

export default app.getRootComponent();
```

---

## File: docs/en-US/api/client/extensions/acl.md

# ACL

## Components

### `<ACLProvider />`

### `<ACLRolesCheckProvider />`

### `<ACLCollectionProvider />`

### `<ACLActionProvider />`

### `<ACLCollectionFieldProvider />`

### `<ACLMenuItemProvider />`

## Hooks

### `useACLContext()`

### `useACLRoleContext()`

### `useRoleRecheck()`

---

## File: docs/en-US/api/client/extensions/block-provider.md

# BlockProvider

## Kernel Methods

### ``

### `useBlockRequestContext()`

## Build-in BlockProvider Components

### `<CalendarBlockProvider />`

### ``

### ``

### ``

### `<FormBlockProvider />`

### `<FormFieldProvider />`

### ``

### `<KanbanBlockProvider />`

---

## File: docs/en-US/api/client/extensions/collection-manager.md

# CollectionManager

## Components

### CollectionManagerProvider

```jsx | pure
<CollectionManagerProvider
  interfaces={{}}
  collections={[]}
></CollectionManagerProvider>
```

### CollectionProvider

```jsx | pure
const collection = {
  name: 'tests',
  fields: [
    {
      type: 'string',
      name: 'title',
      interface: 'input',
      uiSchema: {
        type: 'string',
        'x-component': 'Input',
      },
    },
  ],
};
<CollectionProvider collection={collection}></CollectionProvider>;
```

If there is no collection parameter passed in, get the collection from CollectionManagerProvider with the corresponding name.

```jsx | pure
const collections = [
  {
    name: 'tests',
    fields: [
      {
        type: 'string',
        name: 'title',
        interface: 'input',
        uiSchema: {
          type: 'string',
          'x-component': 'Input',
        },
      },
    ],
  },
];
<CollectionManagerProvider collections={collections}>
  <CollectionProvider name={'tests'}></CollectionProvider>
</CollectionManagerProvider>;
```

### CollectionFieldProvider

```jsx | pure
const field = {
  type: 'string',
  name: 'title',
  interface: 'input',
  uiSchema: {
    type: 'string',
    'x-component': 'Input',
  },
};
<CollectionFieldProvider field={field}></CollectionFieldProvider>;
```

If there is no field parameter passed in, get the field from CollectionProvider with the corresponding name.

```jsx | pure
const collection = {
  name: 'tests',
  fields: [
    {
      type: 'string',
      name: 'title',
      interface: 'input',
      uiSchema: {
        type: 'string',
        'x-component': 'Input',
      },
    },
  ],
};
<CollectionProvider collection={collection}>
  <CollectionFieldProvider name={'title'}></CollectionFieldProvider>
</CollectionProvider>;
```

### CollectionField

Universal field component that needs to be used with `<CollectionProvider/>`, but only in schema scenarios. Get the field schema from CollectionProvider with the corresponding name. Extend the configuration via the schema where the CollectionField is located.

```ts
{
  name: 'title',
  'x-decorator': 'FormItem',
  'x-decorator-props': {},
  'x-component': 'CollectionField',
  'x-component-props': {},
  properties: {},
}
```

## Hooks

### useCollectionManager()

Use with `<CollectionManagerProvider/>`.

```jsx | pure
const { collections, get } = useCollectionManager();
```

### useCollection()

Use with `<CollectionProvider/>`.

```jsx | pure
const { name, fields, getField, findField, resource } = useCollection();
```

### useCollectionField()

Use with `<CollectionFieldProvider/>`.

```jsx | pure
const { name, uiSchema, resource } = useCollectionField();
```

The resource needs to be used with `<RecordProvider/>` to provide context of the record of the current data table row.

# CollectionManager

## Components

### CollectionManagerProvider

```jsx | pure
<CollectionManagerProvider
  interfaces={{}}
  collections={[]}
></CollectionManagerProvider>
```

### CollectionProvider

```jsx | pure
const collection = {
  name: 'tests',
  fields: [
    {
      type: 'string',
      name: 'title',
      interface: 'input',
      uiSchema: {
        type: 'string',
        'x-component': 'Input',
      },
    },
  ],
};
<CollectionProvider collection={collection}></CollectionProvider>;
```

If there is no collection parameter passed in, get the collection from CollectionManagerProvider with the corresponding name.

```jsx | pure
const collections = [
  {
    name: 'tests',
    fields: [
      {
        type: 'string',
        name: 'title',
        interface: 'input',
        uiSchema: {
          type: 'string',
          'x-component': 'Input',
        },
      },
    ],
  },
];
<CollectionManagerProvider collections={collections}>
  <CollectionProvider name={'tests'}></CollectionProvider>
</CollectionManagerProvider>;
```

### CollectionFieldProvider

```jsx | pure
const field = {
  type: 'string',
  name: 'title',
  interface: 'input',
  uiSchema: {
    type: 'string',
    'x-component': 'Input',
  },
};
<CollectionFieldProvider field={field}></CollectionFieldProvider>;
```

If there is no field parameter passed in, get the field from CollectionProvider with the corresponding name.

```jsx | pure
const collection = {
  name: 'tests',
  fields: [
    {
      type: 'string',
      name: 'title',
      interface: 'input',
      uiSchema: {
        type: 'string',
        'x-component': 'Input',
      },
    },
  ],
};
<CollectionProvider collection={collection}>
  <CollectionFieldProvider name={'title'}></CollectionFieldProvider>
</CollectionProvider>;
```

### CollectionField

Universal field component that needs to be used with `<CollectionProvider/>`, but only in schema scenarios. Get the field schema from CollectionProvider with the corresponding name. Extend the configuration via the schema where the CollectionField is located.

```ts
{
  name: 'title',
  'x-decorator': 'FormItem',
  'x-decorator-props': {},
  'x-component': 'CollectionField',
  'x-component-props': {},
  properties: {},
}
```

## Hooks

### useCollectionManager()

Use with `<CollectionManagerProvider/>`.

```jsx | pure
const { collections, get } = useCollectionManager();
```

### useCollection()

Use with `<CollectionProvider/>`.

```jsx | pure
const { name, fields, getField, findField, resource } = useCollection();
```

### useCollectionField()

Use with `<CollectionFieldProvider/>`.

```jsx | pure
const { name, uiSchema, resource } = useCollectionField();
```

The resource needs to be used with `<RecordProvider/>` to provide context of the record of the current data table row.

---

## File: docs/en-US/api/client/extensions/schema-component.md

# 适配的 Schema 组件

## Common

- DndContext
- SortableItem

## And Design

- Action
- BlockItem
- Calendar
- CardItem
- Cascader

---

## File: docs/en-US/api/client/schema-designer/schema-component.md

# SchemaComponent

## Core Components

### `<SchemaComponentProvider />`

### `<SchemaComponentOptions>`

### `<SchemaComponent>`

## Core Methods

### `createDesignable()`

### `useDesignable()`

### `useCompile()`

---

## File: docs/en-US/api/client/schema-designer/schema-initializer.md

# SchemaInitializer

Used for the initialization of various schemas. Newly added schema can be inserted anywhere in an existing schema node, including:

```ts
{
  properties: {
    // beforeBegin - Insert in front of the current node
    node1: {
      properties: {
        // afterBegin - Insert in front of the first child node of the current node
        // ...
        // beforeEnd - After the last child node of the current node
      },
    },
    // afterEnd - After the current node
  },
}
```

The core of SchemaInitializer includes `<SchemaInitializer.Button />` and `<SchemaInitializer.Item />` the two components. `<SchemaInitializer.Button />` is used to create the dropdown menu button of schema, and the options of the dropdown menu is `<SchemaInitializer.Item/>`.

### `<SchemaInitializerProvider />`

### `<SchemaInitializer.Button />`

### `<SchemaInitializer.Item/>`

---

## File: docs/en-US/api/client/schema-designer/schema-settings.md

# SchemaSettings

### `<SchemaSettings />`

### `<SchemaSettings.Item />`

### `<SchemaSettings.ItemGroup />`

### `<SchemaSettings.SubMenu />`

### `<SchemaSettings.Divider />`

### `<SchemaSettings.Remove />`

### `<SchemaSettings.SelectItem />`

### `<SchemaSettings.SwitchItem />`

### `<SchemaSettings.ModalItem />`

### `<SchemaSettings.ActionModalItem />`

### `<SchemaSettings.Template />`

### `<SchemaSettings.BlockTitleItem />`

---

## File: docs/en-US/api/data-source-manager/data-source.md

# DataSource (abstract)

The `DataSource` abstract class is used to represent a type of data source, which can be a database, API, etc.

## Members

### collectionManager

The CollectionManager instance of the data source, which needs to implement the [`ICollectionManager`](/api/data-source-manager/i-collection-manager) interface.

### resourceManager

The resourceManager instance of the data source, see: [`resourceManager`](/api/resourcer/resource-manager)

### acl

The ACL instance of the data source, see: [`ACL`](/api/acl/acl)

## API

### constructor()

Constructor, creates a `DataSource` instance.

#### Signature

- `constructor(options: DataSourceOptions)`

### init()

Initialization function, called immediately after `constructor`.

#### Signature

- `init(options: DataSourceOptions)`

### name

#### Signature

- `get name()`

Returns the instance name of the data source.

### middleware()

Gets the middleware of the DataSource, used to mount to the Server to receive requests.

### testConnection()

Static method, called during the test connection operation, can be used for parameter validation, specific logic is implemented by subclasses.

#### Signature

- `static testConnection(options?: any): Promise`

### load()

#### Signature

- `async load(options: any = {})`

The loading operation of the data source, logic is implemented by subclasses.

### createCollectionManager()

#### Signature
- `abstract createCollectionManager(options?: any): ICollectionManager`

Creates a CollectionManager instance for the data source, logic is implemented by subclasses.

### createResourceManager()

Creates a ResourceManager instance for the data source, subclasses can override the implementation, by default creates `ResourceManager` from `@nocobase/resourcer`.

### createACL()

- Creates an ACL instance for the DataSource, subclasses can override the implementation, by default creates `ACL` from `@nocobase/acl`.

---

## File: docs/en-US/api/data-source-manager/i-collection-manager.md

# ICollectionManager

The `ICollectionManager` interface is used to manage `Collection` instances of data sources.

## API

### registerFieldTypes()

Registers the field types in a `Collection`.

#### Signature

- `registerFieldTypes(types: Record<string, any>): void`

### registerFieldInterfaces()

Registers the `Interface` for a `Collection`.

#### Signature

- `registerFieldInterfaces(interfaces: Record<string, any>): void`

### registerCollectionTemplates()

Registers `Collection Templates`.

#### Signature

- `registerCollectionTemplates(templates: Record<string, any>): void`

### registerModels()

Registers `Models`.

#### Signature

- `registerModels(models: Record<string, any>): void`

### registerRepositories()

Registers `Repositories`.

#### Signature

- `registerRepositories(repositories: Record<string, any>): void`

### getRegisteredRepository()

Retrieves an instance of a registered repository.

#### Signature

- `getRegisteredRepository(key: string): IRepository`

### defineCollection()

Defines a `Collection`.

#### Signature

- `defineCollection(options: CollectionOptions): ICollection`

### extendCollection()

Modifies an existing `Collection` property.

#### Signature

- `extendCollection(collectionOptions: CollectionOptions, mergeOptions?: MergeOptions): ICollection`

### hasCollection()

Determines if a `Collection` exists.

#### Signature

- `hasCollection(name: string): boolean`

### getCollection()

Retrieves an instance of a `Collection`.

#### Signature

- `getCollection(name: string): ICollection`

### getCollections()

Retrieves all instances of `Collection`.

#### Signature

- `getCollections(): Array`

### getRepository()

Retrieves an instance of a `Repository`.

#### Signature

- `getRepository(name: string, sourceId?: string | number): IRepository`

### sync()

Synchronizes the data source, with the logic implemented by subclasses.

#### Signature

- `sync(): Promise<void>`

---

## File: docs/en-US/api/data-source-manager/i-collection.md

# ICollection

`ICollection` is an interface for data models, which includes information such as the model's name, fields, associations, etc.

```typescript
export interface ICollection {
  repository: IRepository;

  updateOptions(options: any): void;

  setField(name: string, options: any): IField;

  removeField(name: string): void;

  getFields(): Array<IField>;

  getField(name: string): IField;

  [key: string]: any;
}
```

## Members

### repository

The `Repository` instance to which `ICollection` belongs.

## API

### updateOptions()

Updates the properties of the `Collection`.

#### Signature

- `updateOptions(options: any): void`

### setField()

Sets a field of the `Collection`.

#### Signature

- `setField(name: string, options: any): IField`

### removeField()

Removes a field from the `Collection`.

#### Signature

- `removeField(name: string): void`

### getFields()

Retrieves all fields of the `Collection`.

#### Signature

- `getFields(): Array`

### getField()

Retrieves a field of the `Collection` by name.

#### Signature

- `getField(name: string): IField`

---

## File: docs/en-US/api/data-source-manager/i-field.md

# IField

`IField` defines the interface that fields need to implement.

```typescript
export type FieldOptions = {
  name: string;
  field: string;
  rawType: string;
  type: string;
  description?: string;
  interface?: string;
  uiSchema?: any;
  possibleTypes?: string[];
  defaultValue?: any;
  primaryKey: boolean;
  unique: boolean;
  allowNull?: boolean;
  autoIncrement?: boolean;
  [key: string]: any;
};

export interface IField {
  options: FieldOptions;
}
```


## Properties

### options

- **Type**: `FieldOptions`

---

## File: docs/en-US/api/data-source-manager/i-model.md

# IModel

The `IModel` interface defines the basic properties and methods of a model object.

```typescript
export interface IModel {
  toJSON: () => any;
}
```

## API

### toJSON()

Converts the model object to JSON format.

---

## File: docs/en-US/api/data-source-manager/i-repository.md

# IRepository

The `Repository` interface defines a series of model operation methods for adapting CRUD (Create, Read, Update, Delete) operations on data sources.

## API

### find()

Returns a list of models that match the query parameters.

#### Signature

- `find(options?: any): Promise`

### findOne()

Returns the first model that matches the query parameters. If multiple models match, only the first one is returned.

#### Signature

- `findOne(options?: any): Promise`

### count()

Returns the number of models that match the query parameters.

#### Signature

- `count(options?: any): Promise<Number>`

### findAndCount()

Returns both the list of models and the count of models that match the query parameters.

#### Signature

- `findAndCount(options?: any): Promise<[IModel[], Number]>`

### create()

Creates a model data object.

#### Signature

- `create(options: any): void`

### update()

Updates the model data object based on the query conditions.

#### Signature

- `update(options: any): void`

### destroy()

Deletes the model data object based on the query conditions.

#### Signature

- `destroy(options: any): void`

---

## File: docs/en-US/api/data-source-manager/index.md

# DataSourceManager

`DataSourceManager` is a management class for multiple `dataSource` instances.

## API

### add()
Adds a `dataSource` instance.

#### Signature

- `add(dataSource: DataSource, options: any = {}): Promise<void>`

### use()

Adds a global middleware to the `dataSource` instance.

### middleware()

Retrieves the middleware of the current `dataSourceManager` instance, which can be used to respond to HTTP requests.

### afterAddDataSource()

A hook function that is triggered after a new `dataSource` is added.

#### Signature

- `afterAddDataSource(hook: DataSourceHook)`

```typescript
type DataSourceHook = (dataSource: DataSource) => void;
```

### registerDataSourceType()

Registers the data source type and its class.

#### Signature

- `registerDataSourceType(type: string, dataSourceClass: typeof DataSource)`

### getDataSourceType()

Retrieves the data source class.

#### Signature

- `getDataSourceType(type: string): typeof DataSource`

### buildDataSourceByType()

Creates a data source instance based on the registered data source type and instance parameters.

#### Signature

- `buildDataSourceByType(type: string, options: any): DataSource`

---

## File: docs/en-US/api/database/collection.md

# Collection

## Overview

`Collection` is used to define the data model in the system, such as model name, fields, indexes, associations, and other information. It is usually called through the `collection` method of the `Database` instance as a proxy entry.

```javascript
const { Database } = require('@nocobase/database')

// Create database instance
const db = new Database({...});

// Define data model
db.collection({
  name: 'users',
  // Define model fields
  fields: [
    // Scalar field
    {
      name: 'name',
      type: 'string',
    },

    // Association field
    {
      name: 'profile',
      type: 'hasOne' // 'hasMany', 'belongsTo', 'belongsToMany'
    }
  ],
});
```

Refer to [Fields](/api/database/field) for more field types.

## Constructor

**Signature**

- `constructor(options: CollectionOptions, context: CollectionContext)`

**Parameter**

| Name                  | Type                                                        | Default | Description                                                                                                               |
| --------------------- | ----------------------------------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------- |
| `options.name`        | `string`                                                    | -       | Identifier of the collection                                                                                              |
| `options.tableName?`  | `string`                                                    | -       | Database table name, the value of `options.name` is used if not set                                                       |
| `options.fields?`     | `FieldOptions[]`                                            | -       | Definition of fields, refer to [Field](./field) for details                                                               |
| `options.model?`      | `string \| ModelStatic<Model>`                              | -       | Model type of Sequelize; in case `string` is used, this model name needs to be registered in the db before being called   |
| `options.repository?` | `string \| RepositoryType`                                  | -       | Data repository type; in case `string` is used, this repository type needs to be registered in the db before being called |
| `options.sortable?`   | `string \| boolean \| { name?: string; scopeKey?: string }` | -       | Configure which fields are sortable; not sortable by default                                                              |
| `options.autoGenId?`  | `boolean`                                                   | `true`  | Whether to automatically generate unique primary key; `true` by default                                                   |
| `context.database`    | `Database`                                                  | -       | The context database in which it resides                                                                                  |

**Example**

Create a table *posts*:

```ts
const posts = new Collection(
  {
    name: 'posts',
    fields: [
      {
        type: 'string',
        name: 'title',
      },
      {
        type: 'double',
        name: 'price',
      },
    ],
  },
  {
    // An existing database instance
    database: db,
  },
);
```

## Instance Members

### `options`

Initial parameters for data table configuration, which are consistent with the `options` parameter of the constructor.

### `context`

The contextual environment to which the current data table belongs, currently mainly the database instance.

### `name`

Name of the data table.

### `db`

The database instance to which it belongs.

### `filterTargetKey`

Name of the field that is used as the primary key.

### `isThrough`

Whether it is an intermediate table.

### `model`

Match the Model type of Sequelize.

### `repository`

Data repository instance.

## Field Configuration Methods

### `getField()`

Get a field object whose corresponding name has been defined in the data table.

**Signature**

- `getField(name: string): Field`

**Parameter**

| Name   | Type     | Default | Description       |
| ------ | -------- | ------- | ----------------- |
| `name` | `string` | -       | Name of the field |

**Example**

```ts
const posts = db.collection({
  name: 'posts',
  fields: [
    {
      type: 'string',
      name: 'title',
    },
  ],
});

const field = posts.getField('title');
```

### `setField()`

Set a field to the data table.

**Signature**

- `setField(name: string, options: FieldOptions): Field`

**Parameter**

| Name      | Type           | Default | Description                                                       |
| --------- | -------------- | ------- | ----------------------------------------------------------------- |
| `name`    | `string`       | -       | Name of the field                                                 |
| `options` | `FieldOptions` | -       | Configuration of the field, refer to [Field](./field) for details |

**Example**

```ts
const posts = db.collection({ name: 'posts' });

posts.setField('title', { type: 'string' });
```

### `setFields()`

Set multiple fields to the data table.

**Signature**

- `setFields(fields: FieldOptions[], resetFields = true): Field[]`

**Parameter**

| Name          | Type             | Default | Description                                                        |
| ------------- | ---------------- | ------- | ------------------------------------------------------------------ |
| `fields`      | `FieldOptions[]` | -       | Configuration of the fields, refer to [Field](./field) for details |
| `resetFields` | `boolean`        | `true`  | Whether to reset existing fields                                   |

**Example**

```ts
const posts = db.collection({ name: 'posts' });

posts.setFields([
  { type: 'string', name: 'title' },
  { type: 'double', name: 'price' },
]);
```

### `removeField()`

Remove a field object whose corresponding name has been defined in the data table.

**Signature**

- `removeField(name: string): void | Field`

**Parameter**

| Name   | Type     | Default | Description       |
| ------ | -------- | ------- | ----------------- |
| `name` | `string` | -       | Name of the field |

**Example**

```ts
const posts = db.collection({
  name: 'posts',
  fields: [
    {
      type: 'string',
      name: 'title',
    },
  ],
});

posts.removeField('title');
```

### `resetFields()`

Reset (Empty) fields of the data table.

**Signature**

- `resetFields(): void`

**Example**

```ts
const posts = db.collection({
  name: 'posts',
  fields: [
    {
      type: 'string',
      name: 'title',
    },
  ],
});

posts.resetFields();
```

### `hasField()`

Check if the data table has defined a field object with the corresponding name.

**Signature**

- `hasField(name: string): boolean`

**Parameter**

| Name   | Type     | Default | Description       |
| ------ | -------- | ------- | ----------------- |
| `name` | `string` | -       | Name of the field |

**Example**

```ts
const posts = db.collection({
  name: 'posts',
  fields: [
    {
      type: 'string',
      name: 'title',
    },
  ],
});

posts.hasField('title'); // true
```

### `findField()`

Find field objects in the data table that match the conditions.

**Signature**

- `findField(predicate: (field: Field) => boolean): Field | undefined`

**Parameter**

| Name        | Type                        | Default | Description   |
| ----------- | --------------------------- | ------- | ------------- |
| `predicate` | `(field: Field) => boolean` | -       | The condition |

**Example**

```ts
const posts = db.collection({
  name: 'posts',
  fields: [
    {
      type: 'string',
      name: 'title',
    },
  ],
});

posts.findField((field) => field.name === 'title');
```

### `forEachField()`

Iterate over field objects in the data table.

**Signature**

- `forEachField(callback: (field: Field) => void): void`

**Parameter**

| Name       | Type                     | Default | Description       |
| ---------- | ------------------------ | ------- | ----------------- |
| `callback` | `(field: Field) => void` | -       | Callback function |

**Example**

```ts
const posts = db.collection({
  name: 'posts',
  fields: [
    {
      type: 'string',
      name: 'title',
    },
  ],
});

posts.forEachField((field) => console.log(field.name));
```

## Index Configuration Methods

### `addIndex()`

Add data table index.

**Signature**

- `addIndex(index: string | string[] | { fields: string[], unique?: boolean,[key: string]: any })`

**Parameter**

| Name    | Type                                                         | Default | Description                   |
| ------- | ------------------------------------------------------------ | ------- | ----------------------------- |
| `index` | `string \| string[]`                                         | -       | Names of fields to be indexed |
| `index` | `{ fields: string[], unique?: boolean, [key: string]: any }` | -       | Full configuration            |

**Example**

```ts
const posts = db.collection({
  name: 'posts',
  fields: [
    {
      type: 'string',
      name: 'title',
    },
  ],
});

posts.addIndex({
  fields: ['title'],
  unique: true,
});
```

### `removeIndex()`

Remove data table index.

**Signature**

- `removeIndex(fields: string[])`

**Parameter**

| Name     | Type       | Default | Description                       |
| -------- | ---------- | ------- | --------------------------------- |
| `fields` | `string[]` | -       | Names of fields to remove indexes |

**Example**

```ts
const posts = db.collection({
  name: 'posts',
  fields: [
    {
      type: 'string',
      name: 'title',
    },
  ],
  indexes: [
    {
      fields: ['title'],
      unique: true,
    },
  ],
});

posts.removeIndex(['title']);
```

## Table Configuration Methods

### `remove()`

Remove data table.

**Signature**

- `remove(): void`

**Example**

```ts
const posts = db.collection({
  name: 'posts',
  fields: [
    {
      type: 'string',
      name: 'title',
    },
  ],
});

posts.remove();
```

## Database Operation Methods

### `sync()`

Synchronize the definitions in data table to the database. In addition to the default `Model.sync` logic in Sequelize, the data tables corresponding to the relational fields will also be handled together.

**Signature**

- `sync(): Promise<void>`

**Example**

```ts
const posts = db.collection({
  name: 'posts',
  fields: [
    {
      type: 'string',
      name: 'title',
    },
  ],
});

await posts.sync();
```

### `existsInDb()`

Check whether the data table exists in the database.

**Signature**

- `existsInDb(options?: Transactionable): Promise`

**Parameter**

| Name                   | Type          | Default | Description          |
| ---------------------- | ------------- | ------- | -------------------- |
| `options?.transaction` | `Transaction` | -       | Transaction instance |

**Example**

```ts
const posts = db.collection({
  name: 'posts',
  fields: [
    {
      type: 'string',
      name: 'title',
    },
  ],
});

const existed = await posts.existsInDb();

console.log(existed); // false
```

### `removeFromDb()`

**Signature**

- `removeFromDb(): Promise<void>`

**Example**

```ts
const books = db.collection({
  name: 'books',
});

//  Synchronize the table books to the database
await db.sync();

// Remove the table books from the database
await books.removeFromDb();
```

---

## File: docs/en-US/api/database/field.md

# Field

## Overview

Data table field management class (abstract class). It is also the base class for all field types, and any other field types are implemented by inheriting from this class.

Refer to [Extended Field Types](/development/server/collections-fields#extended-field-types) to see how to customize fields.

## Constructor

It is usually not called directly by the developer, but mainly through the `db.collection({ fields: [] })` method as a proxy entry.

Extended field is implemented mainly by inheriting the `Field` abstract class and registering it to a Database instance.

**Signature**

- `constructor(options: FieldOptions, context: FieldContext)`

**Parameter**

| Name                 | Type           | Default | Description                                                                  |
| -------------------- | -------------- | ------- | ---------------------------------------------------------------------------- |
| `options`            | `FieldOptions` | -       | Field configuration object                                                   |
| `options.name`       | `string`       | -       | Field name                                                                   |
| `options.type`       | `string`       | -       | Field type, corresponding to the name of the field type registered in the db |
| `context`            | `FieldContext` | -       | Field context object                                                         |
| `context.database`   | `Database`     | -       | Database instance                                                            |
| `context.collection` | `Collection`   | -       | Data table instance                                                          |

## Instance Members

### `name`

Field name.

### `type`

Field type.

### `dataType`

Data type of the field.

### `options`

Configuration parameters to initialize the field.

### `context`

Field context object.

## Configuration Methods

### `on()`

Quick definition method based on data table events. It is equivalent to `db.on(this.collection.name + '.' + eventName, listener)`.

It is usually not necessary to override this method when inheriting.

**Signature**

- `on(eventName: string, listener: (...args: any[]) => void)`

**Parameter**

| Name        | Type                       | Default | Description    |
| ----------- | -------------------------- | ------- | -------------- |
| `eventName` | `string`                   | -       | Event name     |
| `listener`  | `(...args: any[]) => void` | -       | Event listener |

### `off()`

Quick removal method based on data table events. It is equivalent to `db.off(this.collection.name + '.' + eventName, listener)`.

It is usually not necessary to override this method when inheriting.

**Signature**

- `off(eventName: string, listener: (...args: any[]) => void)`

**Parameter**

| Name        | Type                       | Default | Description    |
| ----------- | -------------------------- | ------- | -------------- |
| `eventName` | `string`                   | -       | Event name     |
| `listener`  | `(...args: any[]) => void` | -       | Event listener |

### `bind()`

The execution content that is triggered when a field is added to data table. Typically used to add data table event listeners and other processing.

The corresponding `super.bind()` method needs to be called first when inheriting.

**Signature**

- `bind()`

### `unbind()`

The execution content that is triggered when a field is removed from data table. Typically used to remove data table event listeners and other processing.

The corresponding `super.unbind()` method needs to be called first when inheriting.

**Signature**

- `unbind()`

### `get()`

Get the values of a configuration item of the field.

**Signature**

- `get(key: string): any`

**Parameter**

| Name  | Type     | Default | Description                    |
| ----- | -------- | ------- | ------------------------------ |
| `key` | `string` | -       | Name of the configuration item |

**Example**

```ts
const field = db.collection('users').getField('name');

// Get and return the values of the configuration item 'name'
console.log(field.get('name'));
```

### `merge()`

Merge the values of a configuration item of the field.

**Signature**

- `merge(options: { [key: string]: any }): void`

**Parameter**

| Name      | Type                     | Default | Description                     |
| --------- | ------------------------ | ------- | ------------------------------- |
| `options` | `{ [key: string]: any }` | -       | The configuration item to merge |

**Example**

```ts
const field = db.collection('users').getField('name');

field.merge({
  // Add an index configuration
  index: true,
});
```

### `remove()`

Remove a field from data table (from memory only).

**Example**

```ts
const books = db.getCollections('books');

books.getField('isbn').remove();

// really remove from db
await books.sync();
```

## Database Methods

### `removeFromDb()`

Remove a field from the database.

**Signature**

- `removeFromDb(options?: Transactionable): Promise<void>`

**Parameter**

| Name                   | Type          | Default | Description          |
| ---------------------- | ------------- | ------- | -------------------- |
| `options.transaction?` | `Transaction` | -       | Transaction instance |

### `existsInDb()`

Check if a field exists in the database.

**Signature**

- `existsInDb(options?: Transactionable): Promise`

**Parameter**

| Name                   | Type          | Default | Description          |
| ---------------------- | ------------- | ------- | -------------------- |
| `options.transaction?` | `Transaction` | -       | Transaction instance |

## Built-in Field Types

NocoBase has some built-in common field types, the corresponding type name can be used directly to specify the type of field upon definition. Fields of different types are configured differently, please refer to the list below.

The configuration items of all field types are passed through to Sequelize in addition to those described below. Therefore, all field configuration items supported by Sequelize can be used here (e.g. `allowNull`, `defaultValue`, etc.).

Moreover, server-side field types are mainly used for solving the problems of database storage and some algorithms, they are barely relevant to the field display types and the use of components in front-end. The front-end field types can be found in the corresponding tutorials.

### `'boolean'`

Boolean type.

**Example**

```js
db.collection({
  name: 'books',
  fields: [
    {
      type: 'boolean',
      name: 'published',
    },
  ],
});
```

### `'integer'`

Integer type (32 bits).

**Example**

```ts
db.collection({
  name: 'books',
  fields: [
    {
      type: 'integer',
      name: 'pages',
    },
  ],
});
```

### `'bigInt'`

Long integer type (64 bits).

**Example**

```ts
db.collection({
  name: 'books',
  fields: [
    {
      type: 'bigInt',
      name: 'words',
    },
  ],
});
```

### `'double'`

Double-precision floating-point format (64 bits).

**Example**

```ts
db.collection({
  name: 'books',
  fields: [
    {
      type: 'double',
      name: 'price',
    },
  ],
});
```

### `'real'`

Real type (PG only).

### `'decimal'`

Decimal type.

### `'string'`

String type. Equivalent to the `VARCHAR` type for most databases.

**Example**

```ts
db.collection({
  name: 'books',
  fields: [
    {
      type: 'string',
      name: 'title',
    },
  ],
});
```

### `'text'`

Text type. Equivalent to the `TEXT` type for most databases.

**Example**

```ts
db.collection({
  name: 'books',
  fields: [
    {
      type: 'text',
      name: 'content',
    },
  ],
});
```

### `'password'`

Password type (NocoBase extension). Password encryption based on the `scrypt` method of Node.js native crypto packages.

**Example**

```ts
db.collection({
  name: 'users',
  fields: [
    {
      type: 'password',
      name: 'password',
      length: 64, // Length, default is 64
      randomBytesSize: 8, // Length of random bytes, default is 8
    },
  ],
});
```

**Parameter**

| Name              | Type     | Default | Description            |
| ----------------- | -------- | ------- | ---------------------- |
| `length`          | `number` | 64      | Length of characters   |
| `randomBytesSize` | `number` | 8       | Length of random bytes |

### `'date'`

Date type.

### `'time'`

Time type.

### `'array'`

Array type (PG only).

### `'json'`

JSON type.

### `'jsonb'`

JSONB type (PG only, others will be compatible with the `'json'` type).

### `'uuid'`

UUID type.

### `'uid'`

UID type (NocoBase extension). Short random string identifier type.

### `'formula'`

Formula type (NocoBase extension). Mathematical formula calculation can be configured based on [mathjs](https://www.npmjs.com/package/mathjs), and the formula can refer to the values of other columns in the same record to participate in the calculation.

**Example**

```ts
db.collection({
  name: 'orders',
  fields: [
    {
      type: 'double',
      name: 'price',
    },
    {
      type: 'integer',
      name: 'quantity',
    },
    {
      type: 'formula',
      name: 'total',
      expression: 'price * quantity',
    },
  ],
});
```

### `'radio'`

Radio type (NocoBase extension). The field value is 'true' for at most one row of data for the full table, all others are 'false' or 'null'.

**Example**

There is only one user marked as *root* in the entire system, once the *root* value of any other user is changed to `true`, all other records with *root* of `true` will be changed to `false`:

```ts
db.collection({
  name: 'users',
  fields: [
    {
      type: 'radio',
      name: 'root',
    },
  ],
});
```

### `'sort'`

Sorting type (NocoBase extension). Sorting based on integer numbers, automatically generating new serial numbers for new records, and rearranging serial numbers when moving data.

If data table has the `sortable` option defined, the corresponding fields will be generated automatically.

**Example**

Posts are sortable based on the users they belong to.

```ts
db.collection({
  name: 'posts',
  fields: [
    {
      type: 'belongsTo',
      name: 'user',
    },
    {
      type: 'sort',
      name: 'priority',
      scopeKey: 'userId', // Sort data grouped by the values of userId
    },
  ],
});
```

### `'virtual'`

Virtual type. No Data is actually stored, it is used only when special getter/setter is defined.

### `'belongsTo'`

Many-to-one association type. Foreign key is stored in its own table, as opposed to `'hasOne'`/`'hasMany'`.

**Example**

Any post belongs to an author:

```ts
db.collection({
  name: 'posts',
  fields: [
    {
      type: 'belongsTo',
      name: 'author',
      target: 'users', // Default table name is the plural form of <name>
      foreignKey: 'authorId', // Default is '<name> + Id'
      sourceKey: 'id', // Default is id of the <target> table
    },
  ],
});
```

### `'hasOne'`

One-to-one association type. Foreign key is stored in the association table, as opposed to `'belongsTo'`.

**Example**

Any user has a profile:

```ts
db.collection({
  name: 'users',
  fields: [
    {
      type: 'hasOne',
      name: 'profile',
      target: 'profiles', // Can be omitted
    },
  ],
});
```

### `'hasMany'`

One-to-many association type. The foreign key is stored in the association table, as opposed to `'belongsTo'`.

**Example**

Any user can have multiple posts:

```ts
db.collection({
  name: 'users',
  fields: [
    {
      type: 'hasMany',
      name: 'posts',
      foreignKey: 'authorId',
      sourceKey: 'id',
    },
  ],
});
```

### `'belongsToMany'`

Many-to-many association type. Intermediate table is used to store both foreign keys. If no existing table is specified as intermediate table, it will be created automatically.

**Example**

Any post can have multiple tags added to it, and any tag can be added to multiple posts:

```ts
db.collection({
  name: 'posts',
  fields: [
    {
      type: 'belongsToMany',
      name: 'tags',
      target: 'tags', // Can be omitted if name is the same
      through: 'postsTags', // Intermediate table will be generated automatically if not specified
      foreignKey: 'postId', // Foreign key in the intermediate table referring to the table itself
      sourceKey: 'id', // Primary key of the table itself
      otherKey: 'tagId', // Foreign key in the intermediate table referring to the association table
    },
  ],
});

db.collection({
  name: 'tags',
  fields: [
    {
      type: 'belongsToMany',
      name: 'posts',
      through: 'postsTags', // Refer to the same intermediate table in the same set of relation
    },
  ],
});
```

---

## File: docs/en-US/api/database/index.md

# Database

## Overview

Database is the database interaction tool provided by NocoBase, it provides very convenient database interaction features for no-code and low-code applications. The supported databases are:

- SQLite 3.8.8+
- MySQL 8.0.17+
- PostgreSQL 10.0+

### Connect to Database

In `Database` constructor, database connection can be configured by passing the `options` parameter.

```javascript
const { Database } = require('@nocobase/database');

// MySQL database configuration parameters
const database = new Database({
  dialect: 'mysql',
  host: 'localhost',
  port: 3306,
  database: 'nocobase',
  username: 'root',
  password: 'password'
})

// MySQL \ PostgreSQL database configuration parameters
const database = new Database({
  dialect: /* 'postgres' or 'mysql' */,
  database: 'database',
  username: 'username',
  password: 'password',
  host: 'localhost',
  port: 'port'
})

```

Refer to [Constructor](#constructor) for detailed configurations.

### Define Data Structure

`Database` defines database structure through `Collection`, one `Collection` object represents one table in the database.

```javascript
// Define Collection
const UserCollection = database.collection({
  name: 'users',
  fields: [
    {
      name: 'name',
      type: 'string',
    },
    {
      name: 'age',
      type: 'integer',
    },
  ],
});
```

After the database structure is defined, use `sync()` method to synchronize the database structure.

```javascript
await database.sync();
```

Refer to [Collection](/api/database/collection) for detailed usage of `Collection`.

### CRUD Data

`Database` operates data through `Repository`.

```javascript
const UserRepository = UserCollection.repository();

// Create
await UserRepository.create({
  name: 'Mark',
  age: 18,
});

// Query
const user = await UserRepository.findOne({
  filter: {
    name: 'Mark',
  },
});

// Update
await UserRepository.update({
  values: {
    age: 20,
  },
});

// Delete
await UserRepository.destroy(user.id);
```

Refer to [Repository](/api/database/repository) for details of data CRUD.

## Constructor

**Signature**

- `constructor(options: DatabaseOptions)`

Create a database instance.

**Parameter**

| Name                   | Type           | Default       | Description                                                                                                                                         |
| ---------------------- | -------------- | ------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| `options.host`         | `string`       | `'localhost'` | Database host                                                                                                                                       |
| `options.port`         | `number`       | -             | Database service port, default port depends on the type of database used                                                                            |
| `options.username`     | `string`       | -             | Database username                                                                                                                                   |
| `options.password`     | `string`       | -             | Database password                                                                                                                                   |
| `options.database`     | `string`       | -             | Database name                                                                                                                                       |
| `options.dialect`      | `string`       | `'mysql'`     | Database type                                                                                                                                       |
| `options.storage?`     | `string`       | `':memory:'`  | Storage mode for SQLite                                                                                                                             |
| `options.logging?`     | `boolean`      | `false`       | Whether to enable logging                                                                                                                           |
| `options.define?`      | `Object`       | `{}`          | Default table definition parameters                                                                                                                 |
| `options.tablePrefix?` | `string`       | `''`          | NocoBase extension, table prefix                                                                                                                    |
| `options.migrator?`    | `UmzugOptions` | `{}`          | NocoBase extension, parameters for migrator, refer to [Umzug](https://github.com/sequelize/umzug/blob/main/src/types.ts#L15) for the implementation |

## Migration Methods

### `addMigration()`

Add single migration file.

**Signature**

- `addMigration(options: MigrationItem)`

**Parameter**

| Name                 | Type               | Default | Description                         |
| -------------------- | ------------------ | ------- | ----------------------------------- |
| `options.name`       | `string`           | -       | Name of the migration file          |
| `options.context?`   | `string`           | -       | Context of the migration file       |
| `options.migration?` | `typeof Migration` | -       | Custom type of the migration file   |
| `options.up`         | `Function`         | -       | `up` method of the migration file   |
| `options.down`       | `Function`         | -       | `down` method of the migration file |

**Example**

```ts
db.addMigration({
  name: '20220916120411-test-1',
  async up() {
    const queryInterface = this.context.db.sequelize.getQueryInterface();
    await queryInterface.query(/* your migration sqls */);
  },
});
```

### `addMigrations()`

Add the migration files in the specified directory.

**Signature**

- `addMigrations(options: AddMigrationsOptions): void`

**Parameter**

| Name                 | Type       | Default        | Description                                     |
| -------------------- | ---------- | -------------- | ----------------------------------------------- |
| `options.directory`  | `string`   | `''`           | Directory where the migration files are located |
| `options.extensions` | `string[]` | `['js', 'ts']` | File extensions                                 |
| `options.namespace?` | `string`   | `''`           | Namespace                                       |
| `options.context?`   | `Object`   | `{ db }`       | Context of the migration files                  |

**Example**

```ts
db.addMigrations({
  directory: path.resolve(__dirname, './migrations'),
  namespace: 'test',
});
```

## Tool Methods

### `inDialect()`

Check whether the current database type is the specified type.

**Signature**

- `inDialect(dialect: string[]): boolean`

**Parameter**

| Name      | Type       | Default | Description                                                 |
| --------- | ---------- | ------- | ----------------------------------------------------------- |
| `dialect` | `string[]` | -       | Database type, options are `mysql`, `postgres` and `mariadb` |

### `getTablePrefix()`

Get the table name prefix in the configuration.

**Signature**

- `getTablePrefix(): string`

## Data Table Configurations

### `collection()`

Define a data table. This is like the `define` method of Sequelize, which only creates table structure in memory. Call the `sync` method if needs to be persisted to the database.

**Signature**

- `collection(options: CollectionOptions): Collection`

**Parameter**

All configuration parameters of `options` is consistent with the constructor of the `Collection` class, refer to [Collection](/api/database/collection#Constructor).

**Event**

- `'beforeDefineCollection'`: Trigger before defining the table.
- `'afterDefineCollection'`: Trigger after defining the table.

**Example**

```ts
db.collection({
  name: 'books',
  fields: [
    {
      type: 'string',
      name: 'title',
    },
    {
      type: 'float',
      name: 'price',
    },
  ],
});

// sync collection as table to db
await db.sync();
```

### `getCollection()`

Get a defined data table.

**Signature**

- `getCollection(name: string): Collection`

**Parameter**

| Name   | Type     | Default | Description |
| ------ | -------- | ------- | ----------- |
| `name` | `string` | -       | Table name  |

**Example**

```ts
const collection = db.getCollection('books');
```

### `hasCollection()`

Check whether a specified data table is defined.

**Signature**

- `hasCollection(name: string): boolean`

**Parameter**

| Name   | Type     | Default | Description |
| ------ | -------- | ------- | ----------- |
| `name` | `string` | -       | Table name  |

**Example**

```ts
db.collection({ name: 'books' });

db.hasCollection('books'); // true

db.hasCollection('authors'); // false
```

### `removeCollection()`

Remove a defined data table. It is to remove from memory only, call the `sync` method if needs to be persisted to the database.

**Signature**

- `removeCollection(name: string): void`

**Parameter**

| Name   | Type     | Default | Description |
| ------ | -------- | ------- | ----------- |
| `name` | `string` | -       | Table name  |

**Event**

- `'beforeRemoveCollection'`: Trigger before removing the table.
- `'afterRemoveCollection'`: Trigger after removing the table

**Example**

```ts
db.collection({ name: 'books' });

db.removeCollection('books');
```

### `import()`

Load all files in the import file directory into memory as the configuration of collection.

**Signature**

- `async import(options: { directory: string; extensions?: ImportFileExtension[] }): Promise<Map<string, Collection>>`

**Parameter**

| Name                 | Type       | Default        | Description                      |
| -------------------- | ---------- | -------------- | -------------------------------- |
| `options.directory`  | `string`   | -              | Path of directory to be imported |
| `options.extensions` | `string[]` | `['ts', 'js']` | Scan for specific suffixes       |

**Example**

The collection defined by file `./collections/books.ts` is as below:

```ts
export default {
  name: 'books',
  fields: [
    {
      type: 'string',
      name: 'title',
    },
  ],
};
```

Import the relevant configurations when loading the plugin:

```ts
class Plugin {
  async load() {
    await this.app.db.import({
      directory: path.resolve(__dirname, './collections'),
    });
  }
}
```

## Extension Registrations and Acquisitions

### `registerFieldTypes()`

Register custom field type.

**Signature**

- `registerFieldTypes(fieldTypes: MapOf<typeof Field>): void`

**Parameter**

`fieldTypes` is a key-value pair, where key is the field type name, and value is the field type class.

**Example**

```ts
import { Field } from '@nocobase/database';

class MyField extends Field {
  // ...
}

db.registerFieldTypes({
  myField: MyField,
});
```

### `registerModels()`

Register custom data model class.

**Signature**

- `registerModels(models: MapOf<ModelStatic<any>>): void`

**Parameter**

`models` is a key-value pair, where key is the data model name, and value is the data model class.

**Example**

```ts
import { Model } from '@nocobase/database';

class MyModel extends Model {
  // ...
}

db.registerModels({
  myModel: MyModel,
});

db.collection({
  name: 'myCollection',
  model: 'myModel',
});
```

### `registerRepositories()`

Register custom data repository class.

**Signature**

- `registerRepositories(repositories: MapOf<RepositoryType>): void`

**Parameter**

`repositories` is a key-value pair, where key is the data repository name, and value is the data repository class.

**Example**

```ts
import { Repository } from '@nocobase/database';

class MyRepository extends Repository {
  // ...
}

db.registerRepositories({
  myRepository: MyRepository,
});

db.collection({
  name: 'myCollection',
  repository: 'myRepository',
});
```

### `registerOperators()`

Register custom data query operator.

**Signature**

- `registerOperators(operators: MapOf<OperatorFunc>)`

**Parameter**

`operators` is a key-value pair, where key is the operator name, and value is the generating function of the comparison operator statement.

**Example**

```ts
db.registerOperators({
  $dateOn(value) {
    return {
      [Op.and]: [
        { [Op.gte]: stringToDate(value) },
        { [Op.lt]: getNextDay(value) },
      ],
    };
  },
});

db.getRepository('books').count({
  filter: {
    createdAt: {
      // registered operator
      $dateOn: '2020-01-01',
    },
  },
});
```

### `getModel()`

Get the defined data model class. If no custom model class has been registered before, the default model class of Sequelize will be returned. The default name is the same as the name defined by collection.

**Signature**

- `getModel(name: string): Model`

**Parameter**

| Name   | Type     | Default | Description           |
| ------ | -------- | ------- | --------------------- |
| `name` | `string` | -       | Registered model name |

**Example**

```ts
db.registerModels({
  books: class MyModel extends Model {},
});

const ModelClass = db.getModel('books');

console.log(ModelClass.prototype instanceof MyModel); // true
```

Note: The model class retrieved from collection is not strictly equivalent to the model class at registration, but is inherited from the model class at registration. Since the properties of Sequelize's model class are modified during initialization, NocoBase automatically handles this inheritance relationship. All the definitions work fine except that the classes are not equal.

### `getRepository()`

Get the defined data repository class. If no custom data repository class has been registered before, the default data repository class of NocoBase will be returned. The default name is the same as the name defined by collection.

Data repository class is mainly used for the CRUD operations based on data model, refer to [Repository](/api/database/repository).

**Signature**

- `getRepository(name: string): Repository`
- `getRepository(name: string, relationId?: string | number): Repository`

**Parameter**

| Name         | Type                 | Default | Description                           |
| ------------ | -------------------- | ------- | ------------------------------------- |
| `name`       | `string`             | -       | Registered data repository name       |
| `relationId` | `string` \| `number` | -       | Foreign key value for relational data |

When the name contains relationship in the form of `'tables.relactions'`, the related data repository class is returned. If the second parameter is provided, the data repository will be used (query, modify, etc.) based on the foreign key values of the relational data.

**Example**

Suppose there are two data tables *posts* and *authors*, and there is a foreign key in the *posts* table points to the *authors* table:

```ts
const AuthorsRepo = db.getRepository('authors');
const author1 = AuthorsRepo.create({ name: 'author1' });

const PostsRepo = db.getRepository('authors.posts', author1.id);
const post1 = AuthorsRepo.create({ title: 'post1' });
asset(post1.authorId === author1.id); // true
```

## Database Events

### `on()`

Listen for database events.

**Signature**

- `on(event: string, listener: (...args: any[]) => void | Promise<void>): void`

**Parameter**

| Name     | Type     | Default | Description    |
| -------- | -------- | ------- | -------------- |
| event    | string   | -       | Event name     |
| listener | Function | -       | Event listener |

Event name supports Model event of Sequelize by default. Global event is listened to by the name `<sequelize_model_global_event>`, single Model event is listened to by the name `<model_name>. <sequelize_model_event>`.

Refer to the [Built-in Events](#built-in-events) section for parameter descriptions and detailed examples of all built-in event types.

### `off()`

Remove the event listener function.

**Signature**

- `off(name: string, listener: Function)`

**Parameter**

| Name     | Type     | Default | Description    |
| -------- | -------- | ------- | -------------- |
| name     | string   | -       | Event name     |
| listener | Function | -       | Event listener |

**Example**

```ts
const listener = async (model, options) => {
  console.log(model);
};

db.on('afterCreate', listener);

db.off('afterCreate', listener);
```

## Database Operations

### `auth()`

Database connection verification. It can be used to ensure that the application has established connection to the data.

**Signature**

- `auth(options: QueryOptions & { retry?: number } = {}): Promise`

**Parameter**

| Name                   | Type                  | Default | Description                                       |
| ---------------------- | --------------------- | ------- | ------------------------------------------------- |
| `options?`             | `Object`              | -       | Verification option                               |
| `options.retry?`       | `number`              | `10`    | Number of retries in case of verification failure |
| `options.transaction?` | `Transaction`         | -       | Transaction object                                |
| `options.logging?`     | `boolean \| Function` | `false` | Whether to print the log                          |

**Example**

```ts
await db.auth();
```

### `reconnect()`

Reconnect to the database.

**Example**

```ts
await db.reconnect();
```

### `closed()`

Check whether database has closed the connection.

**Signature**

- `closed(): boolean`

### `close()`

Closes database connection. Equivalent to `sequelize.close()`.

### `sync()`

Synchronizes database table structure. Equivalent to `sequelize.sync()`, refer to [Sequelize documentation](https://sequelize.org/api/v6/class/src/sequelize.js~sequelize#instance-method-sync) for parameters.

### `clean()`

Empty the database, it will delete all data tables.

**Signature**

- `clean(options: CleanOptions): Promise<void>`

**Parameter**

| Name                  | Type          | Default | Description                       |
| --------------------- | ------------- | ------- | --------------------------------- |
| `options.drop`        | `boolean`     | `false` | Whether to remove all data tables |
| `options.skip`        | `string[]`    | -       | Names of tables to skip           |
| `options.transaction` | `Transaction` | -       | Transaction object                |

**Example**

Remove all tables except for the `users` table.

```ts
await db.clean({
  drop: true,
  skip: ['users'],
});
```

## Package-Level Export

### `defineCollection()`

Create the configuration content of a data table.

**Signature**

- `defineCollection(name: string, config: CollectionOptions): CollectionOptions`

**Parameter**

| Name                | Type                | Default | Description                                        |
| ------------------- | ------------------- | ------- | -------------------------------------------------- |
| `collectionOptions` | `CollectionOptions` | -       | All parameters are the same with `db.collection()` |

**Example**

For the data table configuration file to be imported by `db.import()`:

```ts
import { defineCollection } from '@nocobase/database';

export default defineCollection({
  name: 'users',
  fields: [
    {
      type: 'string',
      name: 'name',
    },
  ],
});
```

### `extendCollection()`

Extent the configuration content of a data table that is already in memory, mainly for the content of files imported by the `import()` method. This is the top-level package export method of `@nocobase/database`, and is not called through db instance. The `extend` alias can also be used.

**Signature**

- `extendCollection(collectionOptions: CollectionOptions, mergeOptions?: MergeOptions): ExtendedCollectionOptions`

**Parameter**

| Name                | Type                | Default | Description                                                             |
| ------------------- | ------------------- | ------- | ----------------------------------------------------------------------- |
| `collectionOptions` | `CollectionOptions` | -       | All the same with `db.collection()`                                     |
| `mergeOptions?`     | `MergeOptions`      | -       | [deepmerge](https://npmjs.com/package/deepmerge) options of npm package |

**Example**

Original definition of the table *books* (books.ts):

```ts
export default {
  name: 'books',
  fields: [{ name: 'title', type: 'string' }],
};
```

Extend the definition of the table *books* (books.extend.ts):

```ts
import { extend } from '@nocobase/database';

// Extend again
export default extend({
  name: 'books',
  fields: [{ name: 'price', type: 'number' }],
});
```

If the above two files are imported when calling `import()`, after being extended again by `extend()`, the table *books* will have `title` and `price` two fields.

This method is especially useful when extending the table structure that is already defined by existing plugin.

## Built-in Events

The following events will be triggered in the corresponding lifecycle of database, subscribe by the `on()` method and perform specific processing to meet some business needs.

### `'beforeSync'` / `'afterSync'`

Events triggered before or after a new table structure configuration (fields, indexes, etc.) is synchronized to the database. This is usually triggered when executing `collection.sync()` (internal call) for the logical processing of the extension of some special fields.

**Signature**

```ts
on(eventName: `${string}.beforeSync` | 'beforeSync' | `${string}.afterSync` | 'afterSync', listener: SyncListener): this
```

**Type**

```ts
import type { SyncOptions, HookReturn } from 'sequelize/types';

type SyncListener = (options?: SyncOptions) => HookReturn;
```

**Example**

```ts
const users = db.collection({
  name: 'users',
  fields: [{ type: 'string', name: 'username' }],
});

db.on('beforeSync', async (options) => {
  // do something
});

db.on('users.afterSync', async (options) => {
  // do something
});

await users.sync();
```

### `'beforeValidate'` / `'afterValidate'`

Before creating or updating data, there is a validation against the data based on the rules defined by the collection, and the corresponding events are triggered before and after the validation. This is triggered when `repository.create()` or `repository.update()` is called.

**Signature**

```ts
on(eventName: `${string}.beforeValidate` | 'beforeValidate' | `${string}.afterValidate` | 'afterValidate', listener: ValidateListener): this
```

**Type**

```ts
import type { ValidationOptions } from 'sequelize/types/lib/instance-validator';
import type { HookReturn } from 'sequelize/types';
import type { Model } from '@nocobase/database';

type ValidateListener = (
  model: Model,
  options?: ValidationOptions,
) => HookReturn;
```

**Example**

```ts
db.collection({
  name: 'tests',
  fields: [
    {
      type: 'string',
      name: 'email',
      validate: {
        isEmail: true,
      },
    },
  ],
});

// all models
db.on('beforeValidate', async (model, options) => {
  // do something
});
// tests model
db.on('tests.beforeValidate', async (model, options) => {
  // do something
});

// all models
db.on('afterValidate', async (model, options) => {
  // do something
});
// tests model
db.on('tests.afterValidate', async (model, options) => {
  // do something
});

const repository = db.getRepository('tests');
await repository.create({
  values: {
    email: 'abc', // checks for email format
  },
});
// or
await repository.update({
  filterByTk: 1,
  values: {
    email: 'abc', // checks for email format
  },
});
```

### `'beforeCreate'` / `'afterCreate'`

Events triggered before or after creating one piece of data. This is triggered when `repository.create()` is called.

**Signature**

```ts
on(eventName: `${string}.beforeCreate` | 'beforeCreate' | `${string}.afterCreate` | 'afterCreate', listener: CreateListener): this
```

**Type**

```ts
import type { CreateOptions, HookReturn } from 'sequelize/types';
import type { Model } from '@nocobase/database';

export type CreateListener = (
  model: Model,
  options?: CreateOptions,
) => HookReturn;
```

**Example**

```ts
db.on('beforeCreate', async (model, options) => {
  // do something
});

db.on('books.afterCreate', async (model, options) => {
  const { transaction } = options;
  const result = await model.constructor.findByPk(model.id, {
    transaction,
  });
  console.log(result);
});
```

### `'beforeUpdate'` / `'afterUpdate'`

Events triggered before or after updating one piece of data. This is triggered when `repository.update()` is called.

**Signature**

```ts
on(eventName: `${string}.beforeUpdate` | 'beforeUpdate' | `${string}.afterUpdate` | 'afterUpdate', listener: UpdateListener): this
```

**Type**

```ts
import type { UpdateOptions, HookReturn } from 'sequelize/types';
import type { Model } from '@nocobase/database';

export type UpdateListener = (
  model: Model,
  options?: UpdateOptions,
) => HookReturn;
```

**Example**

```ts
db.on('beforeUpdate', async (model, options) => {
  // do something
});

db.on('books.afterUpdate', async (model, options) => {
  // do something
});
```

### `'beforeSave'` / `'afterSave'`

Events triggered before or after creating or updating one piece of data. This is triggered when `repository.create()` or `repository.update()` is called.

**Signature**

```ts
on(eventName: `${string}.beforeSave` | 'beforeSave' | `${string}.afterSave` | 'afterSave', listener: SaveListener): this
```

**Type**

```ts
import type { SaveOptions, HookReturn } from 'sequelize/types';
import type { Model } from '@nocobase/database';

export type SaveListener = (model: Model, options?: SaveOptions) => HookReturn;
```

**Example**

```ts
db.on('beforeSave', async (model, options) => {
  // do something
});

db.on('books.afterSave', async (model, options) => {
  // do something
});
```

### `'beforeDestroy'` / `'afterDestroy'`

Events triggered before or after deleting one piece of data. This is triggered when `repository.destroy()` is called.

**Signature**

```ts
on(eventName: `${string}.beforeDestroy` | 'beforeDestroy' | `${string}.afterDestroy` | 'afterDestroy', listener: DestroyListener): this
```

**Type**

```ts
import type { DestroyOptions, HookReturn } from 'sequelize/types';
import type { Model } from '@nocobase/database';

export type DestroyListener = (
  model: Model,
  options?: DestroyOptions,
) => HookReturn;
```

**Example**

```ts
db.on('beforeDestroy', async (model, options) => {
  // do something
});

db.on('books.afterDestroy', async (model, options) => {
  // do something
});
```

### `'afterCreateWithAssociations'`

Events triggered after creating one piece of data that carries hierarchical data. This is triggered when `repository.create()` is called.

**Signature**

```ts
on(eventName: `${string}.afterCreateWithAssociations` | 'afterCreateWithAssociations', listener: CreateWithAssociationsListener): this
```

**Type**

```ts
import type { CreateOptions, HookReturn } from 'sequelize/types';
import type { Model } from '@nocobase/database';

export type CreateWithAssociationsListener = (
  model: Model,
  options?: CreateOptions,
) => HookReturn;
```

**Example**

```ts
db.on('afterCreateWithAssociations', async (model, options) => {
  // do something
});

db.on('books.afterCreateWithAssociations', async (model, options) => {
  // do something
});
```

### `'afterUpdateWithAssociations'`

Events triggered after updating one piece of data that carries hierarchical data. This is triggered when `repository.update()` is called.

**Signature**

```ts
on(eventName: `${string}.afterUpdateWithAssociations` | 'afterUpdateWithAssociations', listener: CreateWithAssociationsListener): this
```

**Type**

```ts
import type { UpdateOptions, HookReturn } from 'sequelize/types';
import type { Model } from '@nocobase/database';

export type UpdateWithAssociationsListener = (
  model: Model,
  options?: UpdateOptions,
) => HookReturn;
```

**Example**

```ts
db.on('afterUpdateWithAssociations', async (model, options) => {
  // do something
});

db.on('books.afterUpdateWithAssociations', async (model, options) => {
  // do something
});
```

### `'afterSaveWithAssociations'`

Events triggered after creating or updating one piece of data that carries hierarchical data. This is triggered when `repository.create()` or `repository.update()` is called.

**Signature**

```ts
on(eventName: `${string}.afterSaveWithAssociations` | 'afterSaveWithAssociations', listener: SaveWithAssociationsListener): this
```

**Type**

```ts
import type { SaveOptions, HookReturn } from 'sequelize/types';
import type { Model } from '@nocobase/database';

export type SaveWithAssociationsListener = (
  model: Model,
  options?: SaveOptions,
) => HookReturn;
```

**Example**

```ts
db.on('afterSaveWithAssociations', async (model, options) => {
  // do something
});

db.on('books.afterSaveWithAssociations', async (model, options) => {
  // do something
});
```

### `'beforeDefineCollection'`

Events triggered before defining a data table, such as when `db.collection()` is called.

Note: This is a synchronous event.

**Signature**

```ts
on(eventName: 'beforeDefineCollection', listener: BeforeDefineCollectionListener): this
```

**Type**

```ts
import type { CollectionOptions } from '@nocobase/database';

export type BeforeDefineCollectionListener = (
  options: CollectionOptions,
) => void;
```

**Example**

```ts
db.on('beforeDefineCollection', (options) => {
  // do something
});
```

### `'afterDefineCollection'`

Events triggered after defining a data table, such as when `db.collection()` is called.

Note: This is a synchronous event.

**Signature**

```ts
on(eventName: 'afterDefineCollection', listener: AfterDefineCollectionListener): this
```

**Type**

```ts
import type { Collection } from '@nocobase/database';

export type AfterDefineCollectionListener = (options: Collection) => void;
```

**Example**

```ts
db.on('afterDefineCollection', (collection) => {
  // do something
});
```

### `'beforeRemoveCollection'` / `'afterRemoveCollection'`

Events triggered before or after removing a data table from memory, such as when `db.removeCollection()` is called.

Note: This is a synchronous event.

**Signature**

```ts
on(eventName: 'beforeRemoveCollection' | 'afterRemoveCollection', listener: RemoveCollectionListener): this
```

**Type**

```ts
import type { Collection } from '@nocobase/database';

export type RemoveCollectionListener = (options: Collection) => void;
```

**Example**

```ts
db.on('beforeRemoveCollection', (collection) => {
  // do something
});

db.on('afterRemoveCollection', (collection) => {
  // do something
});
```

---

## File: docs/en-US/api/database/operators.md

# Filter Operators

Used in the filter parameters of the `find`, `findOne`, `findAndCount`, `count`, etc. APIs of repository:

```ts
const repository = db.getRepository('books');

repository.find({
  filter: {
    title: {
      $eq: 'Spring and Autumn',
    },
  },
});
```

To support JSON, NocoBase identifies query operators as a string prefixed with $.

Moreover, NocoBase provides API to extend operators. Refer to [`db.registerOperators()`](../database#registeroperators).

## General Operators

### `$eq`

Check if the field value is equal to the specified value. Equivalent to `=` in SQL.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $eq: 'Spring and Autumn',
    },
  },
});
```

Equal to `title: 'Spring and Autumn'`

### `$ne`

Check if the field value is not equal to the specified value. Equivalent to `!=` in SQL.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $ne: 'Spring and Autumn',
    },
  },
});
```

### `$is`

Check if the field value is the specified value. Equivalent to `IS` in SQL.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $is: null,
    },
  },
});
```

### `$not`

Check if the field value is not the specified value. Equivalent to `IS NOT` in SQL.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $not: null,
    },
  },
});
```

### `$col`

Check if the field value is equal to the value of another field. Equivalent to `=` in SQL.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $col: 'name',
    },
  },
});
```

### `$in`

Check if the field value is in the specified array. Equivalent to `IN` in SQL.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $in: ['Spring and Autumn', 'Warring States'],
    },
  },
});
```

### `$notIn`

Check if the field value is not in the specified array. Equivalent to `NOT IN` in SQL.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $notIn: ['Spring and Autumn', 'Warring States'],
    },
  },
});
```

### `$empty`

Check if the general field is empty. For string field, check if it is an empty string; for array field, check if it is an empty array.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $empty: true,
    },
  },
});
```

### `$notEmpty`

Check if the general field is not empty. For string field, check if it is not an empty string; for array field, check if it is not an empty array.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $notEmpty: true,
    },
  },
});
```

## Logical Operators

### `$and`

Logical AND. Equivalent to `AND` in SQL.

**Example**

```ts
repository.find({
  filter: {
    $and: [{ title: 'Book of Songs' }, { isbn: '1234567890' }],
  },
});
```

### `$or`

Logical OR. Equivalent to `OR` in SQL.

**Example**

```ts
repository.find({
  filter: {
    $or: [
      { title: 'Book of Songs' },
      { publishedAt: { $lt: '0000-00-00T00:00:00Z' } },
    ],
  },
});
```

## Boolean Field Operators

For boolean fields: `type: 'boolean'`

### `$isFalsy`

Check if a Boolean field value is false. Boolean field values of `false`, `0` and `NULL` are all judged to be `$isFalsy: true`.

**Example**

```ts
repository.find({
  filter: {
    isPublished: {
      $isFalsy: true,
    },
  },
});
```

### `$isTruly`

Check if a Boolean field value is true. Boolean field values of `true` and `1` are all judged to be `$isTruly: true`.

**Example**

```ts
repository.find({
  filter: {
    isPublished: {
      $isTruly: true,
    },
  },
});
```

## Numeric Type Field Operators

For numeric type fields, including:

- `type: 'integer'`
- `type: 'float'`
- `type: 'double'`
- `type: 'real'`
- `type: 'decimal'`

### `$gt`

Check if the field value is greater than the specified value. Equivalent to `>` in SQL.

**Example**

```ts
repository.find({
  filter: {
    price: {
      $gt: 100,
    },
  },
});
```

### `$gte`

Check if the field value is equal to or greater than the specified value. Equivalent to `>=` in SQL.

**Example**

```ts
repository.find({
  filter: {
    price: {
      $gte: 100,
    },
  },
});
```

### `$lt`

Check if the field value is less than the specified value. Equivalent to `<` in SQL.

**Example**

```ts
repository.find({
  filter: {
    price: {
      $lt: 100,
    },
  },
});
```

### `$lte`

Check if the field value is equal to or less than the specified value. Equivalent to `<=` in SQL.

**Example**

```ts
repository.find({
  filter: {
    price: {
      $lte: 100,
    },
  },
});
```

### `$between`

Check if the field value is between the specified two values. Equivalent to `BETWEEN` in SQL.

**Example**

```ts
repository.find({
  filter: {
    price: {
      $between: [100, 200],
    },
  },
});
```

### `$notBetween`

Check if the field value is not between the specified two values. Equivalent to `NOT BETWEEN` in SQL.

**Example**

```ts
repository.find({
  filter: {
    price: {
      $notBetween: [100, 200],
    },
  },
});
```

## String Type Field Operators

For string type fields, including `string`.

### `$includes`

Check if the string field contains the specified substring.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $includes: 'Three Character Classic',
    },
  },
});
```

### `$notIncludes`

Check if the string field does not contain the specified substring.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $notIncludes: 'Three Character Classic',
    },
  },
});
```

### `$startsWith`

Check if the string field starts with the specified substring.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $startsWith: 'Three Character Classic',
    },
  },
});
```

### `$notStatsWith`

Check if the string field does not start with the specified substring.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $notStatsWith: 'Three Character Classic',
    },
  },
});
```

### `$endsWith`

Check if the string field ends with the specified substring.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $endsWith: 'Three Character Classic',
    },
  },
});
```

### `$notEndsWith`

Check if the string field does not end with the specified substring.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $notEndsWith: 'Three Character Classic',
    },
  },
});
```

### `$like`

Check if the field value contains the specified string. Equivalent to `LIKE` in SQL.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $like: 'Computer',
    },
  },
});
```

### `$notLike`

Check if the field value does not contain the specified string. Equivalent to `NOT LIKE` in SQL.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $notLike: 'Computer',
    },
  },
});
```

### `$iLike`

Check if a field value contains the specified string, case ignored. Equivalent to `ILIKE` in SQL (PG only).

**Example**

```ts
repository.find({
  filter: {
    title: {
      $iLike: 'Computer',
    },
  },
});
```

### `$notILike`

Check if a field value does not contain the specified string, case ignored. Equivalent to `NOT ILIKE` in SQL (PG only).

**Example**

```ts
repository.find({
  filter: {
    title: {
      $notILike: 'Computer',
    },
  },
});
```

### `$regexp`

Check if the field value matches the specified regular expression. Equivalent to `REGEXP` in SQL (PG only).

**Example**

```ts
repository.find({
  filter: {
    title: {
      $regexp: '^Computer',
    },
  },
});
```

### `$notRegexp`

Check if the field value does not match the specified regular expression. Equivalent to `NOT REGEXP` in SQL (PG only).

**Example**

```ts
repository.find({
  filter: {
    title: {
      $notRegexp: '^Computer',
    },
  },
});
```

### `$iRegexp`

Check if the field value matches the specified regular expression, case ignored. Equivalent to `~*` in SQL (PG only).

**Example**

```ts
repository.find({
  filter: {
    title: {
      $iRegexp: '^COMPUTER',
    },
  },
});
```

### `$notIRegexp`

Check if the field value does not match the specified regular expression, case ignored. Equivalent to `!~*` in SQL (PG only).

**Example**

```ts
repository.find({
  filter: {
    title: {
      $notIRegexp: '^COMPUTER',
    },
  },
});
```

## Date Type Field Operators

For date type fields: `type: 'date'`

### `$dateOn`

Check if the date field value is within a certain day.

**Example**

```ts
repository.find({
  filter: {
    createdAt: {
      $dateOn: '2021-01-01',
    },
  },
});
```

### `$dateNotOn`

Check if the date field value is not within a certain day.

**Example**

```ts
repository.find({
  filter: {
    createdAt: {
      $dateNotOn: '2021-01-01',
    },
  },
});
```

### `$dateBefore`

Check if the date field value is before a certain value, i.e., less than the one passed in.

**Example**

```ts
repository.find({
  filter: {
    createdAt: {
      $dateBefore: '2021-01-01T00:00:00.000Z',
    },
  },
});
```

### `$dateNotBefore`

Check if the date field value is not before a certain value, i.e., equal to or greater than the one passed in.

**Example**

```ts
repository.find({
  filter: {
    createdAt: {
      $dateNotBefore: '2021-01-01T00:00:00.000Z',
    },
  },
});
```

### `$dateAfter`

Check if the date field value is after a certain value, i.e., greater than the one passed in.

**Example**

```ts
repository.find({
  filter: {
    createdAt: {
      $dateAfter: '2021-01-01T00:00:00.000Z',
    },
  },
});
```

### `$dateNotAfter`

Check if the date field value is not after a certain value, i.e., equal to or greater than the one passed in.

**Example**

```ts
repository.find({
  filter: {
    createdAt: {
      $dateNotAfter: '2021-01-01T00:00:00.000Z',
    },
  },
});
```

## Array Type Field Operators

For array type fields: `type: 'array'`

### `$match`

Check if the array field values match values of the specified array.

**Example**

```ts
repository.find({
  filter: {
    tags: {
      $match: ['literature', 'history'],
    },
  },
});
```

### `$notMatch`

Check if the array field values do not match values of the specified array.

**Example**

```ts
repository.find({
  filter: {
    tags: {
      $notMatch: ['literature', 'history'],
    },
  },
});
```

### `$anyOf`

Check if the array field values contain any of the values of the specified array.

**Example**

```ts
repository.find({
  filter: {
    tags: {
      $anyOf: ['literature', 'history'],
    },
  },
});
```

### `$noneOf`

Check if the array field values contain none of the values of the specified array.

**Example**

```ts
repository.find({
  filter: {
    tags: {
      $noneOf: ['literature', 'history'],
    },
  },
});
```

### `$arrayEmpty`

Check if the array field is empty.

**Example**

```ts
repository.find({
  filter: {
    tags: {
      $arrayEmpty: true,
    },
  },
});
```

### `$arrayNotEmpty`

Check if the array field is not empty.

**Example**

```ts
repository.find({
  filter: {
    tags: {
      $arrayNotEmpty: true,
    },
  },
});
```

## Relational Field Type Operators

For checking if a relationship exists, field types include:

- `type: 'hasOne'`
- `type: 'hasMany'`
- `type: 'belongsTo'`
- `type: 'belongsToMany'`

### `$exists`

There is relational data existing.

**Example**

```ts
repository.find({
  filter: {
    author: {
      $exists: true,
    },
  },
});
```

### `$notExists`

There is no relational data existing.

**Example**

```ts
repository.find({
  filter: {
    author: {
      $notExists: true,
    },
  },
});
```

---

## File: docs/en-US/api/database/repository.md

# Repository

## Overview

On a given `Collection` object, you can get its `Repository` object to perform read and write operations on the data table.

```javascript
const { UserCollection } = require('./collections');

const UserRepository = UserCollection.repository;

const user = await UserRepository.findOne({
  filter: {
    id: 1,
  },
});

user.name = 'new name';
await user.save();
```

### Query

#### Basic Query

On the `Repository` object, call the `find*` methods to perform query. The `filter` parameter is supported by all query methods to filter the data.

```javascript
// SELECT * FROM users WHERE id = 1
userRepository.find({
  filter: {
    id: 1,
  },
});
```

#### Operator

The `filter` parameter in the `Repository` also provides a variety of operators to perform more diverse queries.

```javascript
// SELECT * FROM users WHERE age > 18
userRepository.find({
  filter: {
    age: {
      $gt: 18,
    },
  },
});

// SELECT * FROM users WHERE age > 18 OR name LIKE '%张%'
userRepository.find({
  filter: {
    $or: [{ age: { $gt: 18 } }, { name: { $like: '%张%' } }],
  },
});
```

Refer to [Filter Operators](/api/database/operators) for more details on operators.

#### Field Control

Control the output fields by the `fields`, `except`, and `appends` parameters when performing query.

- `fields`: Specify output fields
- `except`: Exclude output fields
- `appends`: Append output associated fields

```javascript
// The result contains only the id and name fields
userRepository.find({
  fields: ['id', 'name'],
});

// The result does not contain only the password field
userRepository.find({
  except: ['password'],
});

// The result contains data associated with the posts object
userRepository.find({
  appends: ['posts'],
});
```

#### Associated Field Query

The `filter` parameter supports filtering by associated fields, for example:

```javascript
// Find the user objects whose associated posts have title of "post title"
userRepository.find({
  filter: {
    'posts.title': 'post title',
  },
});
```

Associated fields can also be nested:

```javascript
// Find the user objects whose associated posts have comments containing "keywords"
await userRepository.find({
  filter: {
    'posts.comments.content': {
      $like: '%keywords%',
    },
  },
});
```

#### Sort

Sort query results by the `sort` parameter.

```javascript
// SELECT * FROM users ORDER BY age
await userRepository.find({
  sort: 'age',
});

// SELECT * FROM users ORDER BY age DESC
await userRepository.find({
  sort: '-age',
});

// SELECT * FROM users ORDER BY age DESC, name ASC
await userRepository.find({
  sort: ['-age', 'name'],
});
```

Sort by the field of the associated object is also supported:

```javascript
await userRepository.find({
  sort: 'profile.createdAt',
});
```

### Create

#### Basic Create

Create new data objects via `Repository`.

```javascript
await userRepository.create({
  name: 'Mark',
  age: 18,
});
// INSERT INTO users (name, age) VALUES ('Mark', 18)

// Bulk creation
await userRepository.create([
  {
    name: 'Mark',
    age: 18,
  },
  {
    name: 'Alex',
    age: 20,
  },
]);
```

#### Create Association

Create associated objects at the same time of creating data. Like query, nested use of associated objects is also supported. For example:

```javascript
await userRepository.create({
  name: 'Mark',
  age: 18,
  posts: [
    {
      title: 'post title',
      content: 'post content',
      tags: [
        {
          name: 'tag1',
        },
        {
          name: 'tag2',
        },
      ],
    },
  ],
});
// When creating a user, create a post to associate with the user, and create tags to associate with the post
```

If the associated object is already in the database, you can pass its ID to create an association with it.

```javascript
const tag1 = await tagRepository.findOne({
  filter: {
    name: 'tag1',
  },
});

await userRepository.create({
  name: 'Mark',
  age: 18,
  posts: [
    {
      title: 'post title',
      content: 'post content',
      tags: [
        {
          id: tag1.id, // Create an association with an existing associated object
        },
        {
          name: 'tag2',
        },
      ],
    },
  ],
});
```

### Update

#### Basic Update

After getting the data object, you can modify the properties directly on the data object (`Model`), and then call the `save` method to save the changes.

```javascript
const user = await userRepository.findOne({
  filter: {
    name: 'Mark',
  },
});

user.age = 20;
await user.save();
```

The data object `Model` is inherited from Sequelize Model, refer to [Sequelize Model](https://sequelize.org/master/manual/model-basics.html) for the operations on `Model`.

Or update data via `Repository`:

```javascript
// Update the records that meet the filtering condition
await userRepository.update({
  filter: {
    name: 'Mark',
  },
  values: {
    age: 20,
  },
});
```

Control which fields to update by the `whitelist` and `blacklist` parameters, for example:

```javascript
await userRepository.update({
  filter: {
    name: 'Mark',
  },
  values: {
    age: 20,
    name: 'Alex',
  },
  whitelist: ['age'], // Only update the age field
});
```

#### Update Associated Field

Associated objects can be set while updating, for example:

```javascript
const tag1 = tagRepository.findOne({
  filter: {
    id: 1,
  },
});

await postRepository.update({
  filter: {
    id: 1,
  },
  values: {
    title: 'new post title',
    tags: [
      {
        id: tag1.id, // Associate with tag1
      },
      {
        name: 'tag2', // Create new tag and associate with it
      },
    ],
  },
});

await postRepository.update({
  filter: {
    id: 1,
  },
  values: {
    tags: null, // Disassociate post from tags
  },
});
```

### Delete

Call the `destroy()` method in `Repository` to perform the deletion operation. Filtering condition has to be specified to delete.

```javascript
await userRepository.destroy({
  filter: {
    status: 'blocked',
  },
});
```

## Constructor

It is usually not called directly by the developer, the instantiation is done mainly by specifying a corresponding repository type that is already registered in the parameter of `db.colletion()`. Repository type is registered through `db.registerRepositories()`.

**Signature**

- `constructor(collection: Collection)`

**Example**

```ts
import { Repository } from '@nocobase/database';

class MyRepository extends Repository {
  async myQuery(sql) {
    return this.database.sequelize.query(sql);
  }
}

db.registerRepositories({
  books: MyRepository,
});

db.collection({
  name: 'books',
  // here link to the registered repository
  repository: 'books',
});

await db.sync();

const books = db.getRepository('books') as MyRepository;
await books.myQuery('SELECT * FROM books;');
```

## Instance Members

### `database`

The database management instance where the context is located.

### `collection`

The corresponding data table management instance.

### `model`

The corresponding data model class.

## Instance Methods

### `find()`

Find datasets from the database with the specified filtering conditions and sorting, etc.

**Signature**

- `async find(options?: FindOptions): Promise<Model[]>`

**Type**

```typescript
type Filter = FilterWithOperator | FilterWithValue | FilterAnd | FilterOr;
type Appends = string[];
type Except = string[];
type Fields = string[];
type Sort = string[] | string;

interface SequelizeFindOptions {
  limit?: number;
  offset?: number;
}

interface FilterByTk {
  filterByTk?: TargetKey;
}

interface CommonFindOptions extends Transactionable {
  filter?: Filter;
  fields?: Fields;
  appends?: Appends;
  except?: Except;
  sort?: Sort;
}

type FindOptions = SequelizeFindOptions & CommonFindOptions & FilterByTk;
```

**Detailed Information**

#### `filter: Filter`

Query conditions for filtering data results. In the query parameters that passed in, `key` is the name of the field, `value` is the corresponding value. Operators can be used in conjunction with other filtering conditions.

```typescript
// Find records with name "foo" and age above 18
repository.find({
  filter: {
    name: 'foo',
    age: {
      $gt: 18,
    },
  },
});
```

Refer to [Operators](./operators.md) for more information.

#### `filterByTk: TargetKey`

Query data by `TargetKey`, this is shortcut for the `filter` parameter. The field of `TargetKey` can be [configured](./collection.md#filtertargetkey) in `Collection`, the default is `primaryKey`.

```typescript
// By default, find records with id 1
repository.find({
  filterByTk: 1,
});
```

#### `fields: string[]`

Query columns. It is used to control which data fields to output. With this parameter, only the specified fields will be returned.

#### `except: string[]`

Exclude columns. It is used to control which data fields to output. With this parameter, the specified fields will not be returned.

#### `appends: string[]`

Append columns. It is used to load associated data. With this parameter, the specified associated fields will be returned together.

#### `sort: string[] | string`

Specify the sorting method of the query results. The input parameter is the name of the field, by default is to sort in the ascending order (`asc`); a `-` symbol needs to be added before the field name to sort in the descending order (`desc`). For example, `['-id', 'name']` means to sort by `id desc, name asc`.

#### `limit: number`

Limit the number of results, same as `limit` in `SQL`.

#### `offset: number`

The offset of the query, same as `offset` in `SQL`.

**Example**

```ts
const posts = db.getRepository('posts');

const results = await posts.find({
  filter: {
    createdAt: {
      $gt: '2022-01-01T00:00:00.000Z',
    },
  },
  fields: ['title'],
  appends: ['user'],
});
```

### `findOne()`

Find a single piece of data from the database for specific conditions. Equivalent to `Model.findOne()` in Sequelize.

**Signature**

- `async findOne(options?: FindOneOptions): Promise<Model | null>`



**Example**

```ts
const posts = db.getRepository('posts');

const result = await posts.findOne({
  filterByTk: 1,
});
```

### `count()`

Query a certain amount of data from the database for specific conditions. Equivalent to `Model.count()` in Sequelize.

**Signature**

- `count(options?: CountOptions): Promise<number>`

**Type**

```typescript
interface CountOptions
  extends Omit<SequelizeCountOptions, 'distinct' | 'where' | 'include'>,
    Transactionable {
  filter?: Filter;
}
```

**Example**

```ts
const books = db.getRepository('books');

const count = await books.count({
  filter: {
    title: 'Three character classic',
  },
});
```

### `findAndCount()`

Find datasets from the database with the specified filtering conditions and return the number of results. Equivalent to `Model.findAndCountAll()` in Sequelize.

**Signature**

- `async findAndCount(options?: FindAndCountOptions): Promise<[Model[], number]>`

**Type**

```typescript
type FindAndCountOptions = Omit<
  SequelizeAndCountOptions,
  'where' | 'include' | 'order'
> &
  CommonFindOptions;
```

**Detailed Information**

The query parameters are the same as `find()`. An array is returned with the first element of the query results, and the second element of the total number of results.

### `create()`

Inserts a newly created data into the data table. Equivalent to `Model.create()` in Sequelize. When the data object to be created carries any associated field, the corresponding associated data record is created or updated along with it.

**Signature**

- `async create<M extends Model>(options: CreateOptions): Promise<M>`



**Example**

```ts
const posts = db.getRepository('posts');

const result = await posts.create({
  values: {
    title: 'NocoBase 1.0 Release Notes',
    tags: [
      // Update data when there is a primary key and value of the associated table
      { id: 1 },
      // Create data when there is no primary key and value
      { name: 'NocoBase' },
    ],
  },
});
```

### `createMany()`

Inserts multiple newly created data into the data table. This is equivalent to calling the `create()` method multiple times.

**Signature**

- `createMany(options: CreateManyOptions): Promise<Model[]>`

**Type**

```typescript
interface CreateManyOptions extends BulkCreateOptions {
  records: Values[];
}
```

**Detailed Information**

- `records`: An array of data objects to be created.
- `transaction`: Transaction object. If no transaction parameter is passed, the method will automatically create an internal transaction.

**Example**

```ts
const posts = db.getRepository('posts');

const results = await posts.createMany({
  records: [
    {
      title: 'NocoBase 1.0 Release Notes',
      tags: [
        // Update data when there is a primary key and value of the associated table
        { id: 1 },
        // Create data when there is no primary key and value
        { name: 'NocoBase' },
      ],
    },
    {
      title: 'NocoBase 1.1 Release Notes',
      tags: [{ id: 1 }],
    },
  ],
});
```

### `update()`

Update data in the data table. Equivalent to `Model.update()` in Sequelize. When the data object to be updated carries any associated field, the corresponding associated data record is created or updated along with it.

**Signature**

- `async update<M extends Model>(options: UpdateOptions): Promise<M>`



**Example**

```ts
const posts = db.getRepository('posts');

const result = await posts.update({
  filterByTk: 1,
  values: {
    title: 'NocoBase 1.0 Release Notes',
    tags: [
      // Update data when there is a primary key and value of the associated table
      { id: 1 },
      // Create data when there is no primary key and value
      { name: 'NocoBase' },
    ],
  },
});
```

### `destroy()`

Delete data from the data table. Equivalent to `Model.destroy()` in Sequelize.

**Signature**

- `async destroy(options?: TargetKey | TargetKey[] | DestoryOptions): Promise<number>`

**Type**

```typescript
interface DestroyOptions extends SequelizeDestroyOptions {
  filter?: Filter;
  filterByTk?: TargetKey | TargetKey[];
  truncate?: boolean;
  context?: any;
}
```

**Detailed Information**

- `filter`：Specify the filtering conditions of the records to be deleted. Refer to the [`find()`](#find) method for the detailed usage of the filter.
- `filterByTk`：Specify the filtering conditions by TargetKey.
- `truncate`: Whether to empty the table data, this parameter is valid if no `filter` or `filterByTk` parameter is passed.
- `transaction`: Transaction object. If no transaction parameter is passed, the method will automatically create an internal transaction.

---

## File: docs/en-US/api/database/shared.md

**Parameters**

| Parameter Name         | Type          | Default | Description                                           |
| ---------------------- | ------------- | ------- | ----------------------------------------------------- |
| `options.values`       | `M`           | `{}`    | The data object to be inserted                        |
| `options.whitelist?`   | `string[]`    | -       | Whitelist for the `values` field; only fields in the list will be stored |
| `options.blacklist?`   | `string[]`    | -       | Blacklist for the `values` field; fields in the list will not be stored |
| `options.transaction?` | `Transaction` | -       | Transaction                                            |

---

## File: docs/en-US/api/database/interfaces/base-interface.md

# BaseInterface

## Overview

BaseInterface is the foundational class for all Interface types. Users can extend this class to implement custom Interface logic.

```typescript
class CustomInterface extends BaseInterface {
  async toValue(value: string, ctx?: any): Promise<any> {
    // Custom toValue logic
  }

  toString(value: any, ctx?: any) {
    // Custom toString logic
  }
}
// Register Interface
db.interfaceManager.registerInterfaceType('customInterface', CustomInterface)
```

## Interfaces

### toValue(value: string, ctx?: any): Promise<any>

Converts an external string to the actual value of the interface, which can be directly passed to the Repository for write operations.

### toString(value: any, ctx?: any)

Converts the actual value of the interface to a string type, which can be used for exporting or displaying purposes.

---

## File: docs/en-US/api/database/relation-repository/belongs-to-many-repository.md

# BelongsToManyRepository

`BelongsToManyRepository` is the `Relation Repository` for handling `BelongsToMany` relationships.

Unlike other relationship types, the `BelongsToMany` type of relationship needs to be recorded through an intermediate table. The intermediate table can be created automatically or explicitly specified when defining association relationships in NocoBase.

## Class Methods

### `find()`

Find associated objects.

**Signature**

- `async find(options?: FindOptions): Promise<M[]>`

**Detailed Information**

Query parameters are the same as [`Repository.find()`](../repository.md#find).

### `findOne()`

Find associated objects, only to return one record.

**Signature**

- `async findOne(options?: FindOneOptions): Promise<M>`



### `count()`

Return the number of records matching the query criteria.

**Signature**

- `async count(options?: CountOptions)`

**Type**

```typescript
interface CountOptions
  extends Omit<SequelizeCountOptions, 'distinct' | 'where' | 'include'>,
    Transactionable {
  filter?: Filter;
}
```

### `findAndCount()`

Find datasets from the database with the specified filtering conditions and return the number of results.

**Signature**

- `async findAndCount(options?: FindAndCountOptions): Promise<[any[], number]>`

**Type**

```typescript
type FindAndCountOptions = CommonFindOptions;
```

### `create()`

Create associated objects.

**Signature**

- `async create(options?: CreateOptions): Promise<M>`



### `update()`

Update associated objects that match the conditions.

**Signature**

- `async update(options?: UpdateOptions): Promise<M>`



### `destroy()`

Delete associated objects.

**Signature**

- `async destroy(options?: TargetKey | TargetKey[] | DestroyOptions): Promise`



### `add()`

Add new associated objects.

**Signature**

- `async add(
options: TargetKey | TargetKey[] | PrimaryKeyWithThroughValues | PrimaryKeyWithThroughValues[] | AssociatedOptions
): Promise<void>`

**Type**

```typescript
type PrimaryKeyWithThroughValues = [TargetKey, Values];

interface AssociatedOptions extends Transactionable {
  tk?:
    | TargetKey
    | TargetKey[]
    | PrimaryKeyWithThroughValues
    | PrimaryKeyWithThroughValues[];
}
```

**Detailed Information**

Pass the `targetKey` of the associated object directly, or pass the `targetKey` along with the field values of the intermediate table.

**Example**

```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);

// Pass in the targetKey
PostTagRepository.add([t1.id, t2.id]);

// Pass in intermediate table fields
PostTagRepository.add([
  [t1.id, { tagged_at: '123' }],
  [t2.id, { tagged_at: '456' }],
]);
```

### `set()`

Set the associated objects.

**Signature**

- async set(
  options: TargetKey | TargetKey[] | PrimaryKeyWithThroughValues | PrimaryKeyWithThroughValues[] | AssociatedOptions,
  ): Promise<void>

**Detailed Information**

Parameters are the same as [add()](#add).

### `remove()`

Remove the association with the given objects.

**Signature**

- `async remove(options: TargetKey | TargetKey[] | AssociatedOptions)`

**Type**

```typescript
interface AssociatedOptions extends Transactionable {
  tk?: TargetKey | TargetKey[];
}
```

### `toggle()`

Toggle the associated object.

In some business scenarios, it is often needed to toggle the associated object. For example, user adds a product into collection, and the user cancels the collection and collect it again. Using the `toggle` method can quickly implement similar functions.

**Signature**

- `async toggle(options: TargetKey | { tk?: TargetKey; transaction?: Transaction }): Promise<void>`

**Detailed Information**

The `toggle` method automatically checks whether the associated object already exists, and removes it if it does, or adds it if it does not.

---

## File: docs/en-US/api/database/relation-repository/belongs-to-repository.md

## BelongsToRepository

The interface is the same as [HasOneRepository](./has-one-repository.md). `BelongsToRepository` is the `Repository` for handling `BelongsTo` relationships, and it provides some convenient methods to handle `BelongsTo` relationships.

---

## File: docs/en-US/api/database/relation-repository/has-many-repository.md

# HasManyRepository

`HasManyRepository` is the `Relation Repository` for handling `HasMany` relationships.

## Class Methods

### `find()`

Find associated objects.

**Signature**

- `async find(options?: FindOptions): Promise<M[]>`

**Detailed Information**

Query parameters are the same as [`Repository.find()`](../repository.md#find).

### `findOne()`

Find associated objects, only to return one record.

**Signature**

- `async findOne(options?: FindOneOptions): Promise<M>`



### `count()`

Return the number of records matching the query criteria.

**Signature**

- `async count(options?: CountOptions)`

**Type**

```typescript
interface CountOptions
  extends Omit<SequelizeCountOptions, 'distinct' | 'where' | 'include'>,
    Transactionable {
  filter?: Filter;
}
```

### `findAndCount()`

Find datasets from the database with the specified filtering conditions and return the number of results.

**Signature**

- `async findAndCount(options?: FindAndCountOptions): Promise<[any[], number]>`

**Type**

```typescript
type FindAndCountOptions = CommonFindOptions;
```

### `create()`

Create associated objects.

**Signature**

- `async create(options?: CreateOptions): Promise<M>`



### `update()`

Update associated objects that match the conditions.

**Signature**

- `async update(options?: UpdateOptions): Promise<M>`



### `destroy()`

Delete associated objects.

**Signature**

- `async destroy(options?: TK | DestroyOptions): Promise<M>`



### `add()`

Add association relationships between objects.

**Signature**

- `async add(options: TargetKey | TargetKey[] | AssociatedOptions)`

**Type**

```typescript
interface AssociatedOptions extends Transactionable {
  tk?: TargetKey | TargetKey[];
}
```

**Detailed Information**

- `tk` - The targetKey value of the associated object, either as a single value or an array.
  

### `remove()`

Remove the association with the given objects.

**Signature**

- `async remove(options: TargetKey | TargetKey[] | AssociatedOptions)`

**Detailed Information**

Same parameters as the [`add()`](#add) method.

### `set()`

Set the associated object of the current relationship.

**Signature**

- `async set(options: TargetKey | TargetKey[] | AssociatedOptions)`

**Detailed Information**

Same parameters as the [`add()`](#add) method.

---

## File: docs/en-US/api/database/relation-repository/has-one-repository.md

# HasOneRepository

## Overview

`HasOneRepository` is the associated repository of type `HasOne`.

```typescript
const User = db.collection({
  name: 'users',
  fields: [
    { type: 'hasOne', name: 'profile' },
    { type: 'string', name: 'name' },
  ],
});

const Profile = db.collection({
  name: 'profiles',
  fields: [{ type: 'string', name: 'avatar' }],
});

const user = await User.repository.create({
  values: { name: 'u1' },
});

// Get the associated repository
const userProfileRepository = User.repository
  .relation('profile')
  .of(user.get('id'));

// Or to initialize directly
new HasOneRepository(User, 'profile', user.get('id'));
```

## Class Methods

### `find()`

Find associated objects.

**Signature**

- `async find(options?: SingleRelationFindOption): Promise<Model<any> | null>`

**Type**

```typescript
interface SingleRelationFindOption extends Transactionable {
  fields?: Fields;
  except?: Except;
  appends?: Appends;
  filter?: Filter;
}
```

**Detailed Information**

Query parameters are the same as [`Repository.find()`](../repository.md#find).

**Example**

```typescript
const profile = await UserProfileRepository.find();
// Return null if the associated object does not exist
```

### `create()`

Create associated objects.

**Signature**

- `async create(options?: CreateOptions): Promise<Model>`



**Example**

```typescript
const profile = await UserProfileRepository.create({
  values: { avatar: 'avatar1' },
});

console.log(profile.toJSON());
/*
{
  id: 1,
  avatar: 'avatar1',
  userId: 1,
  updatedAt: 2022-09-24T13:59:40.025Z,
  createdAt: 2022-09-24T13:59:40.025Z
}
*/
```

### `update()`

Update associated objects.

**Signature**

- `async update(options: UpdateOptions): Promise<Model>`



**Example**

```typescript
const profile = await UserProfileRepository.update({
  values: { avatar: 'avatar2' },
});

profile.get('avatar'); // 'avatar2'
```

### `remove()`

Remove associated objects. Only to unassociate, not to delete the associated object.

**Signature**

- `async remove(options?: Transactionable): Promise<void>`

**Detailed Information**

- `transaction`: Transaction object. If no transaction parameter is passed, the method will automatically create an internal transaction.

**Example**

```typescript
await UserProfileRepository.remove();
(await UserProfileRepository.find()) == null; // true

(await Profile.repository.count()) === 1; // true
```

### `destroy()`

Delete associated objects.

**Signature**

- `async destroy(options?: Transactionable): Promise`

**Detailed Information**

- `transaction`: Transaction object. If no transaction parameter is passed, the method will automatically create an internal transaction.

**Example**

```typescript
await UserProfileRepository.destroy();
(await UserProfileRepository.find()) == null; // true
(await Profile.repository.count()) === 0; // true
```

### `set()`

Set associated objects.

**Signature**

- `async set(options: TargetKey | SetOption): Promise<void>`

**Type**

```typescript
interface SetOption extends Transactionable {
  tk?: TargetKey;
}
```

**Detailed Information**

- tk: Set the targetKey of the associated object.
- transaction: Transaction object. If no transaction parameter is passed, the method will automatically create an internal transaction.

**Example**

```typescript
const newProfile = await Profile.repository.create({
  values: { avatar: 'avatar2' },
});

await UserProfileRepository.set(newProfile.get('id'));

(await UserProfileRepository.find()).get('id') === newProfile.get('id'); // true
```

---

## File: docs/en-US/api/database/relation-repository/index.md

# RelationRepository

`RelationRepository` is a `Repository` object for relation types, which allows operations on associated data without loading the associations. Based on `RelationRepository`, each association type derives its corresponding implementation, which are:

- [`HasOneRepository`](#has-one-repository)
- `HasManyRepository`
- `BelongsToRepository`
- `BelongsToManyRepository`

## Constructor

**Signature**

- `constructor(sourceCollection: Collection, association: string, sourceKeyValue: string | number)`

**Parameters**

| Parameter Name     | Type               | Default Value | Description                                               |
| ------------------ | ------------------ | ------------- | --------------------------------------------------------- |
| `sourceCollection` | `Collection`       | -             | The Collection corresponding to the referencing relation in the association |
| `association`      | `string`           | -             | The name of the association                               |
| `sourceKeyValue`   | `string \| number` | -             | The key value corresponding to the referencing relation   |

## Base Class Properties

### `db: Database`

Database object

### `sourceCollection`

The Collection corresponding to the referencing relation in the association

### `targetCollection`

The Collection corresponding to the referenced relation in the association

### `association`

The association object in Sequelize corresponding to the current association

### `associationField`

The field in the Collection corresponding to the current association

### `sourceKeyValue`

The key value corresponding to the referencing relation

---

## File: docs/en-US/api/database/shared/create-options.md

**Type**

```typescript
type WhiteList = string[];
type BlackList = string[];
type AssociationKeysToBeUpdate = string[];

interface CreateOptions extends SequelizeCreateOptions {
  values?: Values;
  whitelist?: WhiteList;
  blacklist?: BlackList;
  updateAssociationValues?: AssociationKeysToBeUpdate;
  context?: any;
}
```

**Details**

- `values`: The data object of the record to be created.
- `whitelist`: Specifies which fields in the data object of the record to be created **can be written**. If this parameter is not passed, all fields are allowed to be written by default.
- `blacklist`: Specifies which fields in the data object of the record to be created **are not allowed to be written**. If this parameter is not passed, all fields are allowed to be written by default.
- `transaction`: The transaction object. If no transaction parameter is passed, the method will automatically create an internal transaction.

---

## File: docs/en-US/api/database/shared/destroy-options.md

**Type**

```typescript
interface DestroyOptions extends SequelizeDestroyOptions {
  filter?: Filter;
  filterByTk?: TargetKey | TargetKey[];
  truncate?: boolean;
  context?: any;
}
```

**Details**

- `filter`: Specifies the filtering conditions for the records to be deleted. For detailed usage of Filter, refer to the [`find()`](#find) method.
- `filterByTk`: Specifies the filtering conditions for the records to be deleted by TargetKey.
- `truncate`: Whether to truncate the table data, effective when no `filter` or `filterByTk` parameters are passed.
- `transaction`: Transaction object. If no transaction parameter is passed, the method will automatically create an internal transaction.

---

## File: docs/en-US/api/database/shared/find-one.md

**Type**

```typescript
type FindOneOptions = Omit<FindOptions, 'limit'>;
```

**Parameters**

Most parameters are the same as those in `find()`. The difference is that `findOne()` returns only a single piece of data, so the `limit` parameter is not needed, and the query is always set to `1`.

---

## File: docs/en-US/api/database/shared/find-options.md

[Empty file]

---

## File: docs/en-US/api/database/shared/transaction.md

- `transaction`: Transaction object. If no transaction parameter is passed, the method will automatically create an internal transaction.

---

## File: docs/en-US/api/database/shared/update-options.md

**Type**

```typescript
interface UpdateOptions extends Omit<SequelizeUpdateOptions, 'where'> {
  values: Values;
  filter?: Filter;
  filterByTk?: TargetKey;
  whitelist?: WhiteList;
  blacklist?: BlackList;
  updateAssociationValues?: AssociationKeysToBeUpdate;
  context?: any;
}
```

**Details**

- `values`: The data object of the records to be updated.
- `filter`: Specifies the filter conditions for the records to be updated. For detailed usage of Filter, refer to the [`find()`](#find) method.
- `filterByTk`: Specifies the filter conditions for the records to be updated by TargetKey.
- `whitelist`: A whitelist for the `values` fields. Only fields listed will be written.
- `blacklist`: A blacklist for the `values` fields. Fields listed will not be written.
- `transaction`: The transaction object. If no transaction parameter is passed, the method will automatically create an internal transaction.

At least one of `filterByTk` or `filter` must be provided.

---

## File: docs/en-US/api/field/markdown-vditor/index.md

# markdown

## Example

This is an embedded Markdown editor:

<MarkdownEditor />

---

## File: docs/en-US/api/handlebars-helpers/array.md

# Array

## {{after}}

Returns all of the items in an array after the specified index. Opposite of [before](#before).

**Params**

* `array` **{Array}**: Collection
* `n` **{Number}**: Starting index (number of items to exclude)
* `returns` **{Array}**: Array exluding `n` items.

**Example**

```handlebars
<!-- array: ['a', 'b', 'c'] -->
{{after array 1}}
<!-- results in: '["c"]' -->
```

## {{arrayify}}

Cast the given `value` to an array.

**Params**

* `value` **{any}**
* `returns` **{Array}**

**Example**

```handlebars
{{arrayify "foo"}}
<!-- results in: [ "foo" ] -->
```

## {{before}}

Return all of the items in the collection before the specified count. Opposite of [after](#after).

**Params**

* `array` **{Array}**
* `n` **{Number}**
* `returns` **{Array}**: Array excluding items after the given number.

**Example**

```handlebars
<!-- array: ['a', 'b', 'c'] -->
{{before array 2}}
<!-- results in: '["a", "b"]' -->
```

## {{eachIndex}}

**Params**

* `array` **{Array}**
* `options` **{Object}**
* `returns` **{String}**

**Example**

```handlebars
<!-- array: ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'] -->
{{#eachIndex array}}
  {{item}} is {{index}}
{{/eachIndex}}
```

## {{filter}}

Block helper that filters the given array and renders the block for values that evaluate to `true`, otherwise the inverse block is returned.

**Params**

* `array` **{Array}**
* `value` **{any}**
* `options` **{Object}**
* `returns` **{String}**

**Example**

```handlebars
<!-- array: ['a', 'b', 'c'] -->
{{#filter array "foo"}}AAA{{else}}BBB{{/filter}}
<!-- results in: 'BBB' -->
```

## {{first}}

Returns the first item, or first `n` items of an array.

**Params**

* `array` **{Array}**
* `n` **{Number}**: Number of items to return, starting at `0`.
* `returns` **{Array}**

**Example**

```handlebars
{{first "['a', 'b', 'c', 'd', 'e']" 2}}
<!-- results in: '["a", "b"]' -->
```

## {{forEach}}

Iterates over each item in an array and exposes the current item in the array as context to the inner block. In addition to the current array item, the helper exposes the following variables to the inner block:

* `index`
* `total`
* `isFirst`
* `isLast`
Also, `@index` is exposed as a private variable, and additional
private variables may be defined as hash arguments.

**Params**

* `array` **{Array}**
* `returns` **{String}**

**Example**

```handlebars
<!-- accounts = [
{'name': 'John', 'email': 'john@example.com'},
{'name': 'Malcolm', 'email': 'malcolm@example.com'},
{'name': 'David', 'email': 'david@example.com'}
] -->

{{#forEach accounts}}
  <a href="mailto:{{ email }}" title="Send an email to {{ name }}">
    {{ name }}
  </a>{{#unless isLast}}, {{/unless}}
{{/forEach}}
```

## {{inArray}}

Block helper that renders the block if an array has the given `value`. Optionally specify an inverse block to render when the array does not have the given value.

**Params**

* `array` **{Array}**
* `value` **{any}**
* `options` **{Object}**
* `returns` **{String}**

**Example**

```handlebars
<!-- array: ['a', 'b', 'c'] -->
{{#inArray array "d"}}
  foo
{{else}}
  bar
{{/inArray}}
<!-- results in: 'bar' -->
```

## {{isArray}}

Returns true if `value` is an es5 array.

**Params**

* `value` **{any}**: The value to test.
* `returns` **{Boolean}**

**Example**

```handlebars
{{isArray "abc"}}
<!-- results in: false -->

<!-- array: [1, 2, 3] -->
{{isArray array}}
<!-- results in: true -->
```

## {{itemAt}}

Returns the item from `array` at index `idx`.

**Params**

* `array` **{Array}**
* `idx` **{Number}**
* `returns` **{any}** `value`

**Example**

```handlebars
<!-- array: ['a', 'b', 'c'] -->
{{itemAt array 1}}
<!-- results in: 'b' -->
```

## {{join}}

Join all elements of array into a string, optionally using a given separator.

**Params**

* `array` **{Array}**
* `separator` **{String}**: The separator to use. Defaults to `,`.
* `returns` **{String}**

**Example**

```handlebars
<!-- array: ['a', 'b', 'c'] -->
{{join array}}
<!-- results in: 'a, b, c' -->

{{join array '-'}}
<!-- results in: 'a-b-c' -->
```

## {{equalsLength}}

Returns true if the the length of the given `value` is equal
to the given `length`. Can be used as a block or inline helper.

**Params**

* `value` **{Array|String}**
* `length` **{Number}**
* `options` **{Object}**
* `returns` **{String}**

## {{last}}

Returns the last item, or last `n` items of an array or string. Opposite of [first](#first).

**Params**

* `value` **{Array|String}**: Array or string.
* `n` **{Number}**: Number of items to return from the end of the array.
* `returns` **{Array}**

**Example**

```handlebars
<!-- var value = ['a', 'b', 'c', 'd', 'e'] -->

{{last value}}
<!-- results in: ['e'] -->

{{last value 2}}
<!-- results in: ['d', 'e'] -->

{{last value 3}}
<!-- results in: ['c', 'd', 'e'] -->
```

## {{length}}

Returns the length of the given string or array.

**Params**

* `value` **{Array|Object|String}**
* `returns` **{Number}**: The length of the value.

**Example**

```handlebars
{{length '["a", "b", "c"]'}}
<!-- results in: 3 -->

<!-- results in: myArray = ['a', 'b', 'c', 'd', 'e']; -->
{{length myArray}}
<!-- results in: 5 -->

<!-- results in: myObject = {'a': 'a', 'b': 'b'}; -->
{{length myObject}}
<!-- results in: 2 -->
```

## {{lengthEqual}}

Alias for [equalsLength](#equalsLength)

## {{map}}

Returns a new array, created by calling `function` on each element of the given `array`. For example,

**Params**

* `array` **{Array}**
* `fn` **{Function}**
* `returns` **{String}**

**Example**

```handlebars
<!-- array: ['a', 'b', 'c'], and "double" is a
fictitious function that duplicates letters -->
{{map array double}}
<!-- results in: '["aa", "bb", "cc"]' -->
```

## {{pluck}}

Map over the given object or array or objects and create an array of values from the given `prop`. Dot-notation may be used (as a string) to get nested properties.

**Params**

* `collection` **{Array|Object}**
* `prop` **{Function}**
* `returns` **{String}**

**Example**

```handlebars
// {{pluck items "data.title"}}
<!-- results in: '["aa", "bb", "cc"]' -->
```

## {{reverse}}

Reverse the elements in an array, or the characters in a string.

**Params**

* `value` **{Array|String}**
* `returns` **{Array|String}**: Returns the reversed string or array.

**Example**

```handlebars
<!-- value: 'abcd' -->
{{reverse value}}
<!-- results in: 'dcba' -->
<!-- value: ['a', 'b', 'c', 'd'] -->
{{reverse value}}
<!-- results in: ['d', 'c', 'b', 'a'] -->
```

## {{some}}

Block helper that returns the block if the callback returns true for some value in the given array.

**Params**

* `array` **{Array}**
* `iter` **{Function}**: Iteratee
* **{Options}**: Handlebars provided options object
* `returns` **{String}**

**Example**

```handlebars
<!-- array: [1, 'b', 3] -->
{{#some array isString}}
  Render me if the array has a string.
{{else}}
  Render me if it doesn't.
{{/some}}
<!-- results in: 'Render me if the array has a string.' -->
```

## {{sort}}

Sort the given `array`. If an array of objects is passed, you may optionally pass a `key` to sort on as the second argument. You may alternatively pass a sorting function as the second argument.

**Params**

* `array` **{Array}**: the array to sort.
* `key` **{String|Function}**: The object key to sort by, or sorting function.

**Example**

```handlebars
<!-- array: ['b', 'a', 'c'] -->
{{sort array}}
<!-- results in: '["a", "b", "c"]' -->
```

## {{sortBy}}

Sort an `array`. If an array of objects is passed, you may optionally pass a `key` to sort on as the second argument. You may alternatively pass a sorting function as the second argument.

**Params**

* `array` **{Array}**: the array to sort.
* `props` **{String|Function}**: One or more properties to sort by, or sorting functions to use.

**Example**

```handlebars
<!-- array: [{a: 'zzz'}, {a: 'aaa'}] -->
{{sortBy array "a"}}
<!-- results in: '[{"a":"aaa"}, {"a":"zzz"}]' -->
```

## {{withAfter}}

Use the items in the array _after_ the specified index as context inside a block. Opposite of [withBefore](#withBefore).

**Params**

* `array` **{Array}**
* `idx` **{Number}**
* `options` **{Object}**
* `returns` **{Array}**

**Example**

```handlebars
<!-- array: ['a', 'b', 'c', 'd', 'e'] -->
{{#withAfter array 3}}
  {{this}}
{{/withAfter}}
<!-- results in: "de" -->
```

## {{withBefore}}

Use the items in the array _before_ the specified index as context inside a block. Opposite of [withAfter](#withAfter).

**Params**

* `array` **{Array}**
* `idx` **{Number}**
* `options` **{Object}**
* `returns` **{Array}**

**Example**

```handlebars
<!-- array: ['a', 'b', 'c', 'd', 'e'] -->
{{#withBefore array 3}}
  {{this}}
{{/withBefore}}
<!-- results in: 'ab' -->
```

## {{withFirst}}

Use the first item in a collection inside a handlebars block expression. Opposite of [withLast](#withLast).

**Params**

* `array` **{Array}**
* `idx` **{Number}**
* `options` **{Object}**
* `returns` **{String}**

**Example**

```handlebars
<!-- array: ['a', 'b', 'c'] -->
{{#withFirst array}}
  {{this}}
{{/withFirst}}
<!-- results in: 'a' -->
```

## {{withGroup}}

Block helper that groups array elements by given group `size`.

**Params**

* `array` **{Array}**: The array to iterate over
* `size` **{Number}**: The desired length of each array "group"
* `options` **{Object}**: Handlebars options
* `returns` **{String}**

**Example**

```handlebars
<!-- array: ['a','b','c','d','e','f','g','h'] -->
{{#withGroup array 4}}
  {{#each this}}
    {{.}}
  {{each}}
  <br>
{{/withGroup}}
<!-- results in: -->
<!-- 'a','b','c','d'<br> -->
<!-- 'e','f','g','h'<br> -->
```

## {{withLast}}

Use the last item or `n` items in an array as context inside a block. Opposite of [withFirst](#withFirst).

**Params**

* `array` **{Array}**
* `idx` **{Number}**: The starting index.
* `options` **{Object}**
* `returns` **{String}**

**Example**

```handlebars
<!-- array: ['a', 'b', 'c'] -->
{{#withLast array}}
  {{this}}
{{/withLast}}
<!-- results in: 'c' -->
```

## {{withSort}}

Block helper that sorts a collection and exposes the sorted collection as context inside the block.

**Params**

* `array` **{Array}**
* `prop` **{String}**
* `options` **{Object}**: Specify `reverse="true"` to reverse the array.
* `returns` **{String}**

**Example**

```handlebars
<!-- array: ['b', 'a', 'c'] -->
{{#withSort array}}{{this}}{{/withSort}}
<!-- results in: 'abc' -->
```

## {{unique}}

Block helper that return an array with all duplicate values removed. Best used along with a [each](#each) helper.

**Params**

* `array` **{Array}**
* `options` **{Object}**
* `returns` **{Array}**

**Example**

```handlebars
<!-- array: ['a', 'a', 'c', 'b', 'e', 'e'] -->
{{#each (unique array)}}{{.}}{{/each}}
<!-- results in: 'acbe' -->
```

---

## File: docs/en-US/api/handlebars-helpers/comparison.md

# Comparison

## {{and}}

Helper that renders the block if **both** of the given values are truthy. If an inverse block is specified it will be rendered when falsy. Works as a block helper, inline helper or subexpression.

**Params**

* `a` **{any}**
* `b` **{any}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**

**Example**

```handlebars
<!-- {great: true, magnificent: true} -->
{{#and great magnificent}}A{{else}}B{{/and}}
<!-- results in: 'A' -->
```

## {{compare}}

Render a block when a comparison of the first and third
arguments returns true. The second argument is
the [arithemetic operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operators) to use. You may also
optionally specify an inverse block to render when falsy.

**Params**

* `a` **{}**
* `operator` **{}**: The operator to use. Operators must be enclosed in quotes: `">"`, `"="`, `"<="`, and so on.
* `b` **{}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**: Block, or if specified the inverse block is rendered if falsey.

## {{contains}}

Block helper that renders the block if `collection` has the given `value`, using strict equality (`===`) for comparison, otherwise the inverse block is rendered (if specified). If a `startIndex` is specified and is negative, it is used as the offset from the end of the collection.

**Params**

* `collection` **{Array|Object|String}**: The collection to iterate over.
* `value` **{any}**: The value to check for.
* `[startIndex=0]` **{Number}**: Optionally define the starting index.
* `options` **{Object}**: Handlebars provided options object.

**Example**

```handlebars
<!-- array = ['a', 'b', 'c'] -->
{{#contains array "d"}}
  This will not be rendered.
{{else}}
  This will be rendered.
{{/contains}}
```

## {{default}}

Returns the first value that is not undefined, otherwise the "default" value is returned.

**Params**

* `value` **{any}**
* `defaultValue` **{any}**
* `returns` **{String}**

## {{eq}}

Block helper that renders a block if `a` is **equal to** `b`.
If an inverse block is specified it will be rendered when falsy.
You may optionally use the `compare=""` hash argument for the
second value.

**Params**

* `a` **{String}**
* `b` **{String}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**: Block, or inverse block if specified and falsey.

## {{gt}}

Block helper that renders a block if `a` is **greater than** `b`.

If an inverse block is specified it will be rendered when falsy.
You may optionally use the `compare=""` hash argument for the
second value.

**Params**

* `a` **{String}**
* `b` **{String}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**: Block, or inverse block if specified and falsey.

## {{gte}}

Block helper that renders a block if `a` is **greater than or equal to** `b`.

If an inverse block is specified it will be rendered when falsy.
You may optionally use the `compare=""` hash argument for the
second value.

**Params**

* `a` **{String}**
* `b` **{String}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**: Block, or inverse block if specified and falsey.

## {{has}}

Block helper that renders a block if `value` has `pattern`.
If an inverse block is specified it will be rendered when falsy.

**Params**

* `val` **{any}**: The value to check.
* `pattern` **{any}**: The pattern to check for.
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**

## {{isEmpty}}

Inline, subexpression, or block helper that returns true (or the block) if the given collection is empty, or false (or the inverse block, if supplied) if the colleciton is not empty.

**Params**

* `collection` **{Object}**
* `options` **{Object}**
* `returns` **{String}**

**Example**

```handlebars
<!-- array: [] -->
{{#isEmpty array}}AAA{{else}}BBB{{/isEmpty}}
<!-- results in: 'AAA' -->

<!-- array: [] -->
{{isEmpty array}}
<!-- results in: true -->
```

## {{isFalsey}}

Returns true if the given `value` is falsey. Uses the [falsey](https://github.com/jonschlinkert/falsey)
library for comparisons. Please see that library for more information
or to report bugs with this helper.

**Params**

* `val` **{any}**
* `options` **{Options}**
* `returns` **{Boolean}**

## {{isTruthy}}

Returns true if the given `value` is truthy. Uses the [falsey](https://github.com/jonschlinkert/falsey)
library for comparisons. Please see that library for more information
or to report bugs with this helper.

**Params**

* `val` **{any}**
* `options` **{Options}**
* `returns` **{Boolean}**

## {{ifEven}}

Return true if the given value is an even number.

**Params**

* `number` **{Number}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**: Block, or inverse block if specified and falsey.

**Example**

```handlebars
{{#ifEven value}}
  render A
{{else}}
  render B
{{/ifEven}}
```

## {{ifNth}}

Conditionally renders a block if the remainder is zero when
`a` operand is divided by `b`. If an inverse block is specified
it will be rendered when the remainder is **not zero**.

**Params**

* **{}**: {Number}
* **{}**: {Number}
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**: Block, or inverse block if specified and falsey.

## {{ifOdd}}

Block helper that renders a block if `value` is **an odd number**. If an inverse block is specified it will be rendered when falsy.

**Params**

* `value` **{Object}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**: Block, or inverse block if specified and falsey.

**Example**

```handlebars
{{#ifOdd value}}
  render A
{{else}}
  render B
{{/ifOdd}}
```

## {{is}}

Block helper that renders a block if `a` is **equal to** `b`.
If an inverse block is specified it will be rendered when falsy.
Similar to [eq](#eq) but does not do strict equality.

**Params**

* `a` **{any}**
* `b` **{any}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**

## {{isnt}}

Block helper that renders a block if `a` is **not equal to** `b`.
If an inverse block is specified it will be rendered when falsy.
Similar to [unlessEq](#unlesseq) but does not use strict equality for
comparisons.

**Params**

* `a` **{String}**
* `b` **{String}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**

## {{lt}}

Block helper that renders a block if `a` is **less than** `b`.

If an inverse block is specified it will be rendered when falsy.
You may optionally use the `compare=""` hash argument for the
second value.

**Params**

* `context` **{Object}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**: Block, or inverse block if specified and falsey.

## {{lte}}

Block helper that renders a block if `a` is **less than or equal to** `b`.

If an inverse block is specified it will be rendered when falsy.
You may optionally use the `compare=""` hash argument for the
second value.

**Params**

* `a` **{Sring}**
* `b` **{Sring}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**: Block, or inverse block if specified and falsey.

## {{neither}}

Block helper that renders a block if **neither of** the given values
are truthy. If an inverse block is specified it will be rendered
when falsy.

**Params**

* `a` **{any}**
* `b` **{any}**
* `options` **{}**: Handlebars options object
* `returns` **{String}**: Block, or inverse block if specified and falsey.

## {{not}}

Returns true if `val` is falsey. Works as a block or inline helper.

**Params**

* `val` **{String}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**

## {{or}}

Block helper that renders a block if **any of** the given values is truthy. If an inverse block is specified it will be rendered when falsy.

**Params**

* `arguments` **{...any}**: Variable number of arguments
* `options` **{Object}**: Handlebars options object
* `returns` **{String}**: Block, or inverse block if specified and falsey.

**Example**

```handlebars
{{#or a b c}}
  If any value is true this will be rendered.
{{/or}}
```

## {{unlessEq}}

Block helper that always renders the inverse block **unless `a` is
is equal to `b`**.

**Params**

* `a` **{String}**
* `b` **{String}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**: Inverse block by default, or block if falsey.

## {{unlessGt}}

Block helper that always renders the inverse block **unless `a` is
is greater than `b`**.

**Params**

* `a` **{Object}**: The default value
* `b` **{Object}**: The value to compare
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**: Inverse block by default, or block if falsey.

## {{unlessLt}}

Block helper that always renders the inverse block **unless `a` is
is less than `b`**.

**Params**

* `a` **{Object}**: The default value
* `b` **{Object}**: The value to compare
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**: Block, or inverse block if specified and falsey.

## {{unlessGteq}}

Block helper that always renders the inverse block **unless `a` is
is greater than or equal to `b`**.

**Params**

* `a` **{any}**
* `b` **{any}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**: Block, or inverse block if specified and falsey.

## {{unlessLteq}}

Block helper that always renders the inverse block **unless `a` is
is less than or equal to `b`**.

**Params**

* `a` **{any}**
* `b` **{any}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**: Block, or inverse block if specified and falsey.

---

## File: docs/en-US/api/handlebars-helpers/core.md

# Built-in Helpers

https://handlebarsjs.com/guide/builtin-helpers.html

## {{if}}

Renders a block if the given condition is truthy.

**Params**

- `condition` **{Any}**: The condition to evaluate.

**Returns**: The content inside the block if the condition is truthy, otherwise returns nothing.

**Example**

```handlebars
{{#if condition}}
  This will be displayed if the condition is true.
{{/if}}
```

## {{unless}}

Renders a block if the given condition is falsy. This is the opposite of `if`.

**Params**

- `condition` **{Any}**: The condition to evaluate.

**Returns**: The content inside the block if the condition is falsy, otherwise returns nothing.

**Example**

```handlebars
{{#unless condition}}
  This will be displayed if the condition is false.
{{/unless}}
```

---

## {{each}}

Iterates over an array or object and renders a block for each item.

**Params**

- `collection` **{Array|Object}**: The array or object to iterate over.

**Returns**: Renders the block for each item in the collection.

**Example**

```handlebars
{{#each items}}
  <li>{{this}}</li>
{{/each}}
```

## {{with}}

Renders a block with a given context. It allows you to specify a context for the block, simplifying access to deeply nested properties.

**Params**

- `context` **{Any}**: The context to use within the block.

**Returns**: Renders the block with the provided context.

**Example**

```handlebars
{{#with person}}
  <p>Name: {{name}}</p>
  <p>Age: {{age}}</p>
{{/with}}
```

## {{lookup}}

Looks up the value of a specified key in an object. This helper is useful for accessing dynamic keys.

**Params**

- `context` **{Object}**: The object to look up the key from.
- `key` **{String|Number}**: The key to look up.

**Returns**: The value of the specified key in the object.

**Example**

```handlebars
{{lookup person "name"}}
<!-- If person is { name: "Alice", age: 30 }, it results in: "Alice" -->
```

---

## File: docs/en-US/api/handlebars-helpers/date.md

# Date

## {{dateFormat}}

The "dateFormat" helper in Handlebars is used to format a date using the day.js library. It takes two required arguments and an optional third argument for the timezone.

**Params**

* `datetime` **{String}**
* `format` **{String}**
* `timezone` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{dateFormat now "YYYY-MM-DD HH:mm:ss"}}
{{dateFormat now "YYYY-MM-DD HH:mm:ss" "Asia/Tokyo"}}
{{dateFormat now "YYYY-MM-DD HH:mm:ss" "UTC"}}
```

---

## File: docs/en-US/api/handlebars-helpers/html.md

# HTML

## {{qrcode}}

---

## File: docs/en-US/api/handlebars-helpers/i18n.md

# I18n

## {{t}}

**Params**

* `key` **{String}**
* `ns` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{t "Today"}}
{{t "Permissions" "@nocobase/plugin-acl"}}
```

---

## File: docs/en-US/api/handlebars-helpers/index.md

# Handlebars Helpers

| Category       | Description                         |
|-------------|-------------------------------------|
| [Core](./core.md)      | Built-in helpers        |
| [Array](./array.md)       | Operations and methods related to arrays       |
| [Comparison](./comparison.md) | Comparison operators and related methods       |
| [Date](./date.md)        | Operations and methods related to date and time handling |
| [HTML](./html.md)        | Content related to HTML documents and elements  |
| [I18n](./i18n.md)        | Support for internationalization and multilingual handling |
| [Math](./math.md)        | Mathematical functions and calculations       |
| [Number](./number.md)    | Content related to number handling and formatting |
| [Object](./object.md)    | Methods related to object operations and properties |
| [Path](./path.md)        | Path operations and content related to the file system |
| [Regex](./regex.md)      | Regular expressions and their usage            |
| [String](./string.md)    | Methods related to string manipulation and operations |
| [URL](./url.md)          | Content related to URL parsing and construction  |

---

## File: docs/en-US/api/handlebars-helpers/math.md

# Math

## {{abs}}

Return the magnitude of `a`.

**Params**

* `a` **{Number}**
* `returns` **{Number}**

## {{add}}

Return the sum of `a` plus `b`.

**Params**

* `a` **{Number}**
* `b` **{Number}**
* `returns` **{Number}**

## {{avg}}

Returns the average of all numbers in the given array.

**Params**

* `array` **{Array}**: Array of numbers to add up.
* `returns` **{Number}**

**Example**

```handlebars
{{avg "[1, 2, 3, 4, 5]"}}
<!-- results in: '3' -->
```

## {{ceil}}

Get the `Math.ceil()` of the given value.

**Params**

* `value` **{Number}**
* `returns` **{Number}**

## {{divide}}

Divide `a` by `b`

**Params**

* `a` **{Number}**: numerator
* `b` **{Number}**: denominator

## {{floor}}

Get the `Math.floor()` of the given value.

**Params**

* `value` **{Number}**
* `returns` **{Number}**

## {{minus}}

Return the difference of `a` minus `b`.

**Params**

* `a` **{Number}**
* `b` **{Number}**

## {{modulo}}

Get the remainder of a division operation.

**Params**

* `a` **{Number}**
* `b` **{Number}**
* `returns` **{Number}**

## {{multiply}}

Return the product of `a` times `b`.

**Params**

* `a` **{Number}**: factor
* `b` **{Number}**: multiplier
* `returns` **{Number}**

## {{plus}}

Add `a` by `b`.

**Params**

* `a` **{Number}**: factor
* `b` **{Number}**: multiplier

## {{random}}

Generate a random number between two values

**Params**

* `min` **{Number}**
* `max` **{Number}**
* `returns` **{String}**

## {{remainder}}

Get the remainder when `a` is divided by `b`.

**Params**

* `a` **{Number}**: a
* `b` **{Number}**: b

## {{round}}

Round the given number.

**Params**

* `number` **{Number}**
* `returns` **{Number}**

## {{subtract}}

Return the product of `a` minus `b`.

**Params**

* `a` **{Number}**
* `b` **{Number}**
* `returns` **{Number}**

## {{sum}}

Returns the sum of all numbers in the given array.

**Params**

* `array` **{Array}**: Array of numbers to add up.
* `returns` **{Number}**

**Example**

```handlebars
{{sum "[1, 2, 3, 4, 5]"}}
<!-- results in: '15' -->
```

## {{times}}

Multiply number `a` by number `b`.

**Params**

* `a` **{Number}**: factor
* `b` **{Number}**: multiplier
* `returns` **{Number}**

---

## File: docs/en-US/api/handlebars-helpers/number.md

# Number

## {{bytes}}

Format a number to it's equivalent in bytes. If a string is passed, it's length will be formatted and returned.

**Examples:**

* `'foo' => 3 B`
* `13661855 => 13.66 MB`
* `825399 => 825.39 kB`
* `1396 => 1.4 kB`

**Params**

* `number` **{Number|String}**
* `returns` **{String}**

## {{addCommas}}

Add commas to numbers

**Params**

* `num` **{Number}**
* `returns` **{Number}**

## {{phoneNumber}}

Convert a string or number to a formatted phone number.

**Params**

* `num` **{Number|String}**: The phone number to format, e.g. `8005551212`
* `returns` **{Number}**: Formatted phone number: `(800) 555-1212`

## {{toAbbr}}

Abbreviate numbers to the given number of `precision`. This is for
general numbers, not size in bytes.

**Params**

* `number` **{Number}**
* `precision` **{Number}**
* `returns` **{String}**

## {{toExponential}}

Returns a string representing the given number in exponential notation.

**Params**

* `number` **{Number}**
* `fractionDigits` **{Number}**: Optional. An integer specifying the number of digits to use after the decimal point. Defaults to as many digits as necessary to specify the number.
* `returns` **{Number}**

**Example**

```handlebars
{{toExponential number digits}};
```

## {{toFixed}}

Formats the given number using fixed-point notation.

**Params**

* `number` **{Number}**
* `digits` **{Number}**: (Optional) The number of digits to appear after the decimal point; this may be a value between 0 and 20. If this argument is omitted, it is treated as 0.
* `returns` **{String}**: A string representing the given number using fixed-point notation.

**Example**

```handlebars
{{toFixed "1.1234" 2}}
//=> '1.12'
```

## {{toFloat}}

**Params**

* `number` **{Number}**
* `returns` **{Number}**

## {{toInt}}

**Params**

* `number` **{Number}**
* `returns` **{Number}**

## {{toPrecision}}

Returns a string representing the `Number` object to the specified precision.

**Params**

* `number` **{Number}**
* `precision` **{Number}**: (Optional) An integer specifying the number of significant digits. If precison is not between 1 and 100 (inclusive), it will be coerced to `0`.
* `returns` **{String}**: A string representing a Number object in fixed-point or exponential notation rounded to precision significant digits.

**Example**

```handlebars
{{toPrecision "1.1234" 2}}
//=> '1.1'
```

---

## File: docs/en-US/api/handlebars-helpers/object.md

# Object

## {{extend}}

Extend the context with the properties of other objects.
A shallow merge is performed to avoid mutating the context.

**Params**

* `objects` **{Object}**: One or more objects to extend.
* `returns` **{Object}**

## {{forIn}}

Block helper that iterates over the properties of
an object, exposing each key and value on the context.

**Params**

* `context` **{Object}**
* `options` **{Object}**
* `returns` **{String}**

## {{forOwn}}

Block helper that iterates over the **own** properties of
an object, exposing each key and value on the context.

**Params**

* `obj` **{Object}**: The object to iterate over.
* `options` **{Object}**
* `returns` **{String}**

## {{toPath}}

Take arguments and, if they are string or number, convert them to a dot-delineated object property path.

**Params**

* `prop` **{String|Number}**: The property segments to assemble (can be multiple).
* `returns` **{String}**

## {{get}}

Use property paths (`a.b.c`) to get a value or nested value from
the context. Works as a regular helper or block helper.

**Params**

* `prop` **{String}**: The property to get, optionally using dot notation for nested properties.
* `context` **{Object}**: The context object
* `options` **{Object}**: The handlebars options object, if used as a block helper.
* `returns` **{String}**

## {{getObject}}

Use property paths (`a.b.c`) to get an object from
the context. Differs from the `get` helper in that this
helper will return the actual object, including the
given property key. Also, this helper does not work as a
block helper.

**Params**

* `prop` **{String}**: The property to get, optionally using dot notation for nested properties.
* `context` **{Object}**: The context object
* `returns` **{String}**

## {{hasOwn}}

Return true if `key` is an own, enumerable property of the given `context` object.

**Params**

* `key` **{String}**
* `context` **{Object}**: The context object.
* `returns` **{Boolean}**

**Example**

```handlebars
{{hasOwn context key}}
```

## {{isObject}}

Return true if `value` is an object.

**Params**

* `value` **{String}**
* `returns` **{Boolean}**

**Example**

```handlebars
{{isObject "foo"}}
//=> false
```

## {{JSONparse}}

Parses the given string using `JSON.parse`.

**Params**

* `string` **{String}**: The string to parse

**Example**

```handlebars
<!-- string: '{"foo": "bar"}' -->
{{JSONparse string}}
<!-- results in: { foo: 'bar' } -->
```

## {{JSONstringify}}

Stringify an object using `JSON.stringify`.

**Params**

* `obj` **{Object}**: Object to stringify
* `returns` **{String}**

**Example**

```handlebars
<!-- object: { foo: 'bar' } -->
{{JSONstringify object}}
<!-- results in: '{"foo": "bar"}' -->
```

## {{merge}}

Deeply merge the properties of the given `objects` with the
context object.

**Params**

* `object` **{Object}**: The target object. Pass an empty object to shallow clone.
* `objects` **{Object}**
* `returns` **{Object}**

## {{pick}}

Pick properties from the context object.

**Params**

* `properties` **{Array|String}**: One or more properties to pick.
* `context` **{Object}**
* `options` **{Object}**: Handlebars options object.
* `returns` **{Object}**: Returns an object with the picked values. If used as a block helper, the values are passed as context to the inner block. If no values are found, the context is passed to the inverse block.

---

## File: docs/en-US/api/handlebars-helpers/path.md

# Path

## {{absolute}}

Get the directory path segment from the given `filepath`.

**Params**

* `ext` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{absolute "docs/toc.md"}}
<!-- results in: 'docs' -->
```

## {{dirname}}

Get the directory path segment from the given `filepath`.

**Params**

* `ext` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{dirname "docs/toc.md"}}
<!-- results in: 'docs' -->
```

## {{relative}}

Get the relative filepath from `a` to `b`.

**Params**

* `a` **{String}**
* `b` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{relative a b}}
```

## {{basename}}

Get the file extension from the given `filepath`.

**Params**

* `ext` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{basename "docs/toc.md"}}
<!-- results in: 'toc.md' -->
```

## {{stem}}

Get the "stem" from the given `filepath`.

**Params**

* `filepath` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{stem "docs/toc.md"}}
<!-- results in: 'toc' -->
```

## {{extname}}

Get the file extension from the given `filepath`.

**Params**

* `filepath` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{extname "docs/toc.md"}}
<!-- results in: '.md' -->
```

## {{resolve}}

Resolve an absolute path from the given `filepath`.

**Params**

* `filepath` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{resolve "docs/toc.md"}}
<!-- results in: '/User/dev/docs/toc.md' -->
```

## {{segments}}

Get specific (joined) segments of a file path by passing a range of array indices.

**Params**

* `filepath` **{String}**: The file path to split into segments.
* `returns` **{String}**: Returns a single, joined file path.

**Example**

```handlebars
{{segments "a/b/c/d" "2" "3"}}
<!-- results in: 'c/d' -->

{{segments "a/b/c/d" "1" "3"}}
<!-- results in: 'b/c/d' -->

{{segments "a/b/c/d" "1" "2"}}
<!-- results in: 'b/c' -->
```

---

## File: docs/en-US/api/handlebars-helpers/regex.md

# Regex

## {{toRegex}}

Convert the given string to a regular expression.

**Params**

* `str` **{String}**
* `returns` **{RegExp}**

**Example**

```handlebars
{{toRegex "foo"}}
<!-- results in: /foo/ -->
```

## {{test}}

Returns true if the given `str` matches the given regex. A regex can be passed on the context, or using the [toRegex](#toregex) helper as a subexpression.

**Params**

* `str` **{String}**
* `returns` **{RegExp}**

**Example**

```handlebars
{{test "bar" (toRegex "foo")}}
<!-- results in: false -->
{{test "foobar" (toRegex "foo")}}
<!-- results in: true -->
{{test "foobar" (toRegex "^foo$")}}
<!-- results in: false -->
```

---

## File: docs/en-US/api/handlebars-helpers/string.md

# String

## {{append}}

Append the specified `suffix` to the given string.

**Params**

* `str` **{String}**
* `suffix` **{String}**
* `returns` **{String}**

**Example**

```handlebars
<!-- given that "item.stem" is "foo" -->
{{append item.stem ".html"}}
<!-- results in:  'foo.html' -->
```

## {{camelcase}}

camelCase the characters in the given `string`.

**Params**

* `string` **{String}**: The string to camelcase.
* `returns` **{String}**

**Example**

```handlebars
{{camelcase "foo bar baz"}};
<!-- results in:  'fooBarBaz' -->
```

## {{capitalize}}

Capitalize the first word in a sentence.

**Params**

* `str` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{capitalize "foo bar baz"}}
<!-- results in:  "Foo bar baz" -->
```

## {{capitalizeAll}}

Capitalize all words in a string.

**Params**

* `str` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{capitalizeAll "foo bar baz"}}
<!-- results in:  "Foo Bar Baz" -->
```

## {{center}}

Center a string using non-breaking spaces

**Params**

* `str` **{String}**
* `spaces` **{String}**
* `returns` **{String}**

## {{chop}}

Like trim, but removes both extraneous whitespace **and non-word characters** from the beginning and end of a string.

**Params**

* `string` **{String}**: The string to chop.
* `returns` **{String}**

**Example**

```handlebars
{{chop "_ABC_"}}
<!-- results in:  'ABC' -->

{{chop "-ABC-"}}
<!-- results in:  'ABC' -->

{{chop " ABC "}}
<!-- results in:  'ABC' -->
```

## {{dashcase}}

dash-case the characters in `string`. Replaces non-word characters and periods with hyphens.

**Params**

* `string` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{dashcase "a-b-c d_e"}}
<!-- results in:  'a-b-c-d-e' -->
```

## {{dotcase}}

dot.case the characters in `string`.

**Params**

* `string` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{dotcase "a-b-c d_e"}}
<!-- results in:  'a.b.c.d.e' -->
```

## {{downcase}}

Lowercase all of the characters in the given string. Alias for [lowercase](#lowercase).

**Params**

* `string` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{downcase "aBcDeF"}}
<!-- results in:  'abcdef' -->
```

## {{ellipsis}}

Truncates a string to the specified `length`, and appends it with an elipsis, `…`.

**Params**

* `str` **{String}**
* `length` **{Number}**: The desired length of the returned string.
* `returns` **{String}**: The truncated string.

**Example**

```handlebars
{{ellipsis (sanitize "<span>foo bar baz</span>"), 7}}
<!-- results in:  'foo bar…' -->
{{ellipsis "foo bar baz", 7}}
<!-- results in:  'foo bar…' -->
```

## {{hyphenate}}

Replace spaces in a string with hyphens.

**Params**

* `str` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{hyphenate "foo bar baz qux"}}
<!-- results in:  "foo-bar-baz-qux" -->
```

## {{isString}}

Return true if `value` is a string.

**Params**

* `value` **{String}**
* `returns` **{Boolean}**

**Example**

```handlebars
{{isString "foo"}}
<!-- results in:  'true' -->
```

## {{lowercase}}

Lowercase all characters in the given string.

**Params**

* `str` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{lowercase "Foo BAR baZ"}}
<!-- results in:  'foo bar baz' -->
```

## {{occurrences}}

Return the number of occurrences of `substring` within the given `string`.

**Params**

* `str` **{String}**
* `substring` **{String}**
* `returns` **{Number}**: Number of occurrences

**Example**

```handlebars
{{occurrences "foo bar foo bar baz" "foo"}}
<!-- results in:  2 -->
```

## {{pascalcase}}

PascalCase the characters in `string`.

**Params**

* `string` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{pascalcase "foo bar baz"}}
<!-- results in:  'FooBarBaz' -->
```

## {{pathcase}}

path/case the characters in `string`.

**Params**

* `string` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{pathcase "a-b-c d_e"}}
<!-- results in:  'a/b/c/d/e' -->
```

## {{plusify}}

Replace spaces in the given string with pluses.

**Params**

* `str` **{String}**: The input string
* `returns` **{String}**: Input string with spaces replaced by plus signs

**Example**

```handlebars
{{plusify "foo bar baz"}}
<!-- results in:  'foo+bar+baz' -->
```

## {{prepend}}

Prepends the given `string` with the specified `prefix`.

**Params**

* `str` **{String}**
* `prefix` **{String}**
* `returns` **{String}**

**Example**

```handlebars
<!-- given that "val" is "bar" -->
{{prepend val "foo-"}}
<!-- results in:  'foo-bar' -->
```

## {{raw}}

Render a block without processing mustache templates inside the block.

**Params**

* `options` **{Object}**
* `returns` **{String}**

**Example**

```handlebars
{{{{#raw}}}}
{{foo}}
{{{{/raw}}}}
<!-- results in:  '{{foo}}' -->
```

## {{remove}}

Remove all occurrences of `substring` from the given `str`.

**Params**

* `str` **{String}**
* `substring` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{remove "a b a b a b" "a "}}
<!-- results in:  'b b b' -->
```

## {{removeFirst}}

Remove the first occurrence of `substring` from the given `str`.

**Params**

* `str` **{String}**
* `substring` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{remove "a b a b a b" "a"}}
<!-- results in:  ' b a b a b' -->
```

## {{replace}}

Replace all occurrences of substring `a` with substring `b`.

**Params**

* `str` **{String}**
* `a` **{String}**
* `b` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{replace "a b a b a b" "a" "z"}}
<!-- results in:  'z b z b z b' -->
```

## {{replaceFirst}}

Replace the first occurrence of substring `a` with substring `b`.

**Params**

* `str` **{String}**
* `a` **{String}**
* `b` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{replace "a b a b a b" "a" "z"}}
<!-- results in:  'z b a b a b' -->
```

## {{reverse}}

Reverse a string.

**Params**

* `str` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{reverse "abcde"}}
<!-- results in:  'edcba' -->
```

## {{sentence}}

Sentence case the given string

**Params**

* `str` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{sentence "hello world. goodbye world."}}
<!-- results in:  'Hello world. Goodbye world.' -->
```

## {{snakecase}}

snake_case the characters in the given `string`.

**Params**

* `string` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{snakecase "a-b-c d_e"}}
<!-- results in:  'a_b_c_d_e' -->
```

## {{split}}

Split `string` by the given `character`.

**Params**

* `string` **{String}**: The string to split.
* `returns` **{String}** `character`: Default is an empty string.

**Example**

```handlebars
{{split "a,b,c" ","}}
<!-- results in:  ['a', 'b', 'c'] -->
```

## {{startsWith}}

Tests whether a string begins with the given prefix.

**Params**

* `prefix` **{String}**
* `testString` **{String}**
* `options` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{#startsWith "Goodbye" "Hello, world!"}}
  Whoops
{{else}}
  Bro, do you even hello world?
{{/startsWith}}
```

## {{titleize}}

Title case the given string.

**Params**

* `str` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{titleize "this is title case"}}
<!-- results in:  'This Is Title Case' -->
```

## {{trim}}

Removes extraneous whitespace from the beginning and end of a string.

**Params**

* `string` **{String}**: The string to trim.
* `returns` **{String}**

**Example**

```handlebars
{{trim " ABC "}}
<!-- results in:  'ABC' -->
```

## {{trimLeft}}

Removes extraneous whitespace from the beginning of a string.

**Params**

* `string` **{String}**: The string to trim.
* `returns` **{String}**

**Example**

```handlebars
{{trim " ABC "}}
<!-- results in:  'ABC ' -->
```

## {{trimRight}}

Removes extraneous whitespace from the end of a string.

**Params**

* `string` **{String}**: The string to trim.
* `returns` **{String}**

**Example**

```handlebars
{{trimRight " ABC "}}
<!-- results in:  ' ABC' -->
```

## {{truncate}}

Truncate a string to the specified `length`. Also see [ellipsis](#ellipsis).

**Params**

* `str` **{String}**
* `limit` **{Number}**: The desired length of the returned string.
* `suffix` **{String}**: Optionally supply a string to use as a suffix to denote when the string has been truncated. Otherwise an ellipsis (`…`) will be used.
* `returns` **{String}**: The truncated string.

**Example**

```handlebars
truncate("foo bar baz", 7);
<!-- results in:  'foo bar' -->
truncate(sanitize("<span>foo bar baz</span>", 7));
<!-- results in:  'foo bar' -->
```

## {{truncateWords}}

Truncate a string to have the specified number of words. Also see [truncate](#truncate).

**Params**

* `str` **{String}**
* `limit` **{Number}**: The desired length of the returned string.
* `suffix` **{String}**: Optionally supply a string to use as a suffix to denote when the string has been truncated.
* `returns` **{String}**: The truncated string.

**Example**

```handlebars
truncateWords("foo bar baz", 1);
<!-- results in:  'foo…' -->
truncateWords("foo bar baz", 2);
<!-- results in:  'foo bar…' -->
truncateWords("foo bar baz", 3);
<!-- results in:  'foo bar baz' -->
```

## {{upcase}}

Uppercase all of the characters in the given string. Alias for [uppercase](#uppercase).

**Params**

* `string` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{upcase "aBcDeF"}}
<!-- results in:  'ABCDEF' -->
```

## {{uppercase}}

Uppercase all of the characters in the given string. If used as a block helper it will uppercase the entire block. This helper does not support inverse blocks.

**Params**

* `str` **{String}**: The string to uppercase
* `options` **{Object}**: Handlebars options object
* `returns` **{String}**

**Example**

```handlebars
{{uppercase "aBcDeF"}}
<!-- results in:  'ABCDEF' -->
```

---

## File: docs/en-US/api/handlebars-helpers/url.md

# URL

## {{encodeURI}}

Encodes a Uniform Resource Identifier (URI) component
by replacing each instance of certain characters by
one, two, three, or four escape sequences representing
the UTF-8 encoding of the character.

**Params**

* `str` **{String}**: The un-encoded string
* `returns` **{String}**: The endcoded string

## {{escape}}

Escape the given string by replacing characters with escape sequences.
Useful for allowing the string to be used in a URL, etc.

**Params**

* `str` **{String}**
* `returns` **{String}**: Escaped string.

## {{decodeURI}}

Decode a Uniform Resource Identifier (URI) component.

**Params**

* `str` **{String}**
* `returns` **{String}**

## {{url_encode}}

Alias for [encodeURI](#encodeuri).

## {{url_decode}}

Alias for [decodeURI](#decodeuri).

## {{urlResolve}}

Take a base URL, and a href URL, and resolve them as a
browser would for an anchor tag.

**Params**

* `base` **{String}**
* `href` **{String}**
* `returns` **{String}**

## {{urlParse}}

Parses a `url` string into an object.

**Params**

* `str` **{String}**: URL string
* `returns` **{String}**: Returns stringified JSON

## {{stripQuerystring}}

Strip the query string from the given `url`.

**Params**

* `url` **{String}**
* `returns` **{String}**: the url without the queryString

## {{stripProtocol}}

Strip protocol from a `url`. Useful for displaying media that may have an 'http' protocol on secure connections.

**Params**

* `str` **{String}**
* `returns` **{String}**: the url with http protocol stripped

**Example**

```handlebars
<!-- url = 'http://foo.bar' -->
{{stripProtocol url}}
<!-- results in: '//foo.bar' -->
```

---

## File: docs/en-US/api/http/index.md

# Overview

HTTP API of NocoBase is designed based on Resource & Action, a superset of REST API. The operation includes but not limited to create, read, update and delete. Resource Action can be extended arbitrarily in NocoBase.

## Resource

In NocoBase, resource has two expressions:

- `<collection>`
- `<collection>.<association>`

<Alert>

- Collection is the set of all abstract data
- Association is the associated data of collection
- Resource includes both collection and collection.association

</Alert>

### Example

- `posts` Post
- `posts.user` Post user
- `posts.tags` Post tags

## Action

Action on resource is expressed by `:<action>`

- `<collection>:<action>`
- `<collection>.<association>:<action>`

Built-in global actions for collection or association:

- `create`
- `get`
- `list`
- `update`
- `destroy`
- `move`

Built-in association actions for association only:

- `set`
- `add`
- `remove`
- `toggle`

### Example

- `posts:create` Create post
- `posts.user:get` Get post user
- `posts.tags:add` Add tags to post (associate existing tags with post)

## Request URL

```bash
<GET|POST>   /api/<collection>:<action>
<GET|POST>   /api/<collection>:<action>/<collectionIndex>
<GET|POST>   /api/<collection>/<collectionIndex>/<association>:<action>
<GET|POST>   /api/<collection>/<collectionIndex>/<association>:<action>/<associationIndex>
```

### Example

posts resource

```bash
POST  /api/posts:create
GET   /api/posts:list
GET   /api/posts:get/1
POST  /api/posts:update/1
POST  /api/posts:destroy/1
```

posts.comments resource

```bash
POST  /api/posts/1/comments:create
GET   /api/posts/1/comments:list
GET   /api/posts/1/comments:get/1
POST  /api/posts/1/comments:update/1
POST  /api/posts/1/comments:destroy/1
```

posts.tags resource

```bash
POST  /api/posts/1/tags:create
GET   /api/posts/1/tags:get
GET   /api/posts/1/tags:list
POST  /api/posts/1/tags:update
POST  /api/posts/1/tags:destroy
POST  /api/posts/1/tags:add
GET   /api/posts/1/tags:remove
```

## Locate Resource

- Collection resource locates the data to be processed by `collectionIndex`, `collectionIndex` must be unique.
- Association resource locates the data to be processed by `collectionIndex` and `associationIndex` jointly, `associationIndex` may not be unique, but the joint index of `collectionIndex` and `associationIndex` must be unique.

When viewing details of association resource, the requested URL needs to provide both `<collectionIndex>` and `<associationIndex>`, `<collectionIndex>` is necessary as `<associationIndex>` may not be unique.

For example, `tables.fields` represents the fields of a data table:

```bash
GET   /api/tables/table1/fields/title
GET   /api/tables/table2/fields/title
```

Both table1 and table2 have the title field, title is unique in one table, but other tables may also have fields of that name.

## Request Parameters

Request parameters can be placed in the headers, parameters (query string), and body (GET requests do not have a body) of the request.

Some special request parameters:

- `filter` Data filtering, used in actions related to query.
- `filterByTk` Filter by tk field, used in actions to specify details of data.
- `sort` Sorting, used in actions related to query.
- `fields` Date to output, used in actions related to query
- `appends` Fields of additional relationship, used in actions related to query.
- `except` Exclude some fields (not to output), used in actions related to query.
- `whitelist` Fields whitelist, used in actions related to data creation and update.
- `blacklist` Fields blacklist, used in actions related to data creation and update.

### filter

Data filtering.

```bash
# simple
GET /api/posts?filter[status]=publish
# json string format is recommended, which requires encodeURIComponent encoding
GET /api/posts?filter={"status":"published"}

# filter operators
GET /api/posts?filter[status.$eq]=publish
GET /api/posts?filter={"status.$eq":"published"}

# $and
GET /api/posts?filter={"$and": [{"status.$eq":"published"}, {"title.$includes":"a"}]}
# $or
GET /api/posts?filter={"$or": [{"status.$eq":"pending"}, {"status.$eq":"draft"}]}

# association field
GET /api/posts?filter[user.email.$includes]=gmail
GET /api/posts?filter={"user.email.$includes":"gmail"}
```

[Click here for more information about filter operators](http-api/filter-operators)

### filterByTk

Filter by tk field. In the default settings:

- collection resource: tk is the primary key of the data table.
- association resource: tk is the targetKey field of the association.

```bash
GET   /api/posts:get?filterByTk=1&fields=name,title&appends=tags
```

### sort

Sorting. To sort in the descending order, put `-` in front of the field.

```bash
# Sort createAt field in the ascending order
GET /api/posts:get?sort=createdAt
# Sort createAt field in the descending order
GET /api/posts:get?sort=-createdAt
# Sort multiple fields jointly, createAt field descending, title A-Z ascending
GET /api/posts:get?sort=-createdAt,title
```

### fields

Data to output.

```bash
GET   /api/posts:list?fields=name,title

Response 200 (application/json)
{
  "data": [
    {
      "name": "",
      "title": ""
    }
  ],
  "meta": {}
}
```

### appends

Fields of additional relationship.

### except

Exclude some fields (not to output), used in actions related to query.

### whitelist

Whitelist.

```bash
POST  /api/posts:create?whitelist=title

{
  "title": "My first post",
  "date": "2022-05-19"      # The date field will be filtered out and not be written to the database
}
```

### blacklist

Blacklist.

```bash
POST  /api/posts:create?blacklist=date

# The date field will be filtered out and not be written to the database
{
  "title": "My first post"
}
```

## Request Response

Format of the response:

```ts
type ResponseResult = {
  data?: any; // Main data
  meta?: any; // Additional Data
  errors?: ResponseError[]; // Errors
};

type ResponseError = {
  code?: string;
  message: string;
};
```

### Example

View list:

```bash
GET /api/posts:list

Response 200 (application/json)

{
  data: [
    {
      id: 1
    }
  ],
  meta: {
    count: 1
    page: 1,
    pageSize: 1,
    totalPage: 1
  },
}
```

View details:

```bash
GET /api/posts:get/1

Response 200 (application/json)

{
  data: {
    id: 1
  }
}
```

Error:

```bash
POST /api/posts:create

Response 400 (application/json)

{
  errors: [
    {
      message: 'name must be required',
    },
  ],
}
```

---

## File: docs/en-US/api/http/rest-api.md

# REST API

HTTP API of NocoBase is a superset of REST API, and the standard CRUD API also supports the RESTful style.

## Collection Resources

### Create Collection

HTTP API

```bash
POST  /api/<collection>:create

{} # JSON body
```

REST API

```bash
POST  /api/<collection>

{} # JSON body
```

### View Collection List

HTTP API

```bash
GET   /api/<collection>:list
```

REST API

```bash
GET   /api/<collection>
```

### View Collection Details

HTTP API

```bash
GET   /api/<collection>:get?filterByTk=<collectionIndex>
GET   /api/<collection>:get/<collectionIndex>
```

REST API

```bash
GET   /api/<collection>/<collectionIndex>
```

### Update Collection

HTTP API

```bash
POST   /api/<collection>:update?filterByTk=<collectionIndex>

{} # JSON body

# Or
POST   /api/<collection>:update/<collectionIndex>

{} # JSON body
```

REST API

```bash
PUT    /api/<collection>/<collectionIndex>

{} # JSON body
```

### Delete Collection

HTTP API

```bash
POST      /api/<collection>:destroy?filterByTk=<collectionIndex>
# Or
POST      /api/<collection>:destroy/<collectionIndex>
```

REST API

```bash
DELETE    /api/<collection>/<collectionIndex>
```

## Association Resources

### Create Association

HTTP API

```bash
POST    /api/<collection>/<collectionIndex>/<association>:create

{} # JSON body
```

REST API

```bash
POST    /api/<collection>/<collectionIndex>/<association>

{} # JSON body
```

### View Association List

HTTP API

```bash
GET   /api/<collection>/<collectionIndex>/<association>:list
```

REST API

```bash
GET   /api/<collection>/<collectionIndex>/<association>
```

### View Association Details

HTTP API

```bash
GET   /api/<collection>/<collectionIndex>/<association>:get?filterByTk=<associationIndex>
# Or
GET   /api/<collection>/<collectionIndex>/<association>:get/<associationIndex>
```

REST API

```bash
GET   /api/<collection>/<collectionIndex>/<association>:get/<associationIndex>
```

### Update Association

HTTP API

```bash
POST   /api/<collection>/<collectionIndex>/<association>:update?filterByTk=<associationIndex>

{} # JSON body

# Or
POST   /api/<collection>/<collectionIndex>/<association>:update/<associationIndex>

{} # JSON body
```

REST API

```bash
PUT    /api/<collection>/<collectionIndex>/<association>:update/<associationIndex>

{} # JSON
```

### Delete Association

HTTP API

```bash
POST    /api/<collection>/<collectionIndex>/<association>:destroy?filterByTk=<associationIndex>
# Or
POST    /api/<collection>/<collectionIndex>/<association>:destroy/<associationIndex>
```

REST API

```bash
DELETE  /api/<collection>/<collectionIndex>/<association>/<associationIndex>
```

---

## File: docs/en-US/api/resourcer/action.md

# ctx.action

## Overview

After the resource operation request is parsed by [`resourceManager.middleware()`](./resource-manager#middleware), some important request parameters are stored in `ctx.action` for use by subsequent middleware.

## API

### resourceName

`ctx.action.resourceName`

The name of the resource. It can take two forms:

- `a` - Operates on resource `a`.
- `a.b` - Operates on associated object `b` of resource `a`.

### actionName

`ctx.action.actionName`

The name of the action.

### sourceId

`ctx.action.sourceId`

When the operation object is an associated object of the resource, it represents the primary key value of the corresponding resource. For example: when `resourceName` is `a.b`, `sourceId` represents the primary key value of `a`.

### params

Request parameters.

- URL parameters can be directly obtained from `ctx.action.params`.

```ts
const { filterByTk } = ctx.action.params;
```

- Request body parameters can be obtained using `ctx.action.params.values`.

### mergeParams()

Combines parameter content with request parameters.

```ts
ctx.action.mergeParams(
  {
    filter: {
      name: 'foo',
    },
    fields: ['id', 'name'],
    except: ['name'],
    sort: ['id'],
    page: 1,
    pageSize: 10,
    values: {
      name: 'foo',
    },
  },
  {
    filter: 'and',
    fields: 'union',
    except: 'union',
    sort: 'overwrite',
    page: 'overwrite',
    pageSize: 'overwrite',
    values: 'deepMerge',
  },
);

ctx.action.mergeParams(
  {
    filter: {},
  },
  {
    filter: (x, y) => {
      // ...
    },
  },
);
```

#### Signature

- `mergeParams(params: ActionParams, strategies: MergeStrategies = {})`

#### Type

```ts
export interface ActionParams {
  filterByTk?: any;
  fields?: string[];
  appends?: string[];
  except?: string[];
  whitelist?: string[];
  blacklist?: string[];
  filter?: FilterOptions;
  sort?: string[];
  page?: number;
  pageSize?: number;
  values?: any;
  [key: string]: any;
}

type MergeStrategyType =
  | 'merge'
  | 'deepMerge'
  | 'overwrite'
  | 'andMerge'
  | 'orMerge'
  | 'intersect'
  | 'union';
type MergeStrategyFunc = (x: any, y: any) => any;
export type MergeStrategy = MergeStrategyType | MergeStrategyFunc;
export interface MergeStrategies {
  [key: string]: MergeStrategy;
}
```

#### Details

| Property     | Type                                                     | Description                                                   |
| ------------ | -------------------------------------------------------- | ------------------------------------------------------------- |
| `params`     | [`ActionParams`](#actionparams)                          | Request parameters                                            |
| `strategies` | [`{ [key: string]: MergeStrategies }`](#mergestrategies) | Merge strategies for various fields in the request parameters |

Default `strategies`:

```ts
{
  filter: 'andMerge',
  fields: 'intersect',
  appends: 'union',
  except: 'union',
  whitelist: 'intersect',
  blacklist: 'intersect',
  sort: 'overwrite',
};
```

##### ActionParams

| Property        | Type       | Description                                                             |
| --------------- | ---------- | ----------------------------------------------------------------------- |
| `filterByTk`    | `any`      | The primary key value of the operated resource                          |
| `filter`        | `Filter`   | Filtering parameters, refer to [Filter Operators](./database/operators) |
| `fields`        | `string[]` | Fields to retrieve                                                      |
| `except`        | `string[]` | Fields to exclude                                                       |
| `appends`       | `string[]` | Related fields to append                                                |
| `whitelist`     | `string[]` | Field whitelist                                                         |
| `blacklist`     | `string[]` | Field blacklist                                                         |
| `sort`          | `string[]` | Sorting parameters                                                      |
| `page`          | `number`   | Current page                                                            |
| `pageSize`      | `number`   | Number of data items per page                                           |
| `values`        | `any`      | Request body                                                            |
| `[key: string]` | `any`      | Other extended configurations                                           |

##### MergeStrategies

Predefined merge strategies or custom merge functions.

Predefined merge strategies:

| Strategy Name | Description                                       |
| ------------- | ------------------------------------------------- |
| `merge`       | `Object.assign`                                   |
| `deepMerge`   | Deep traversal merge                              |
| `overwrite`   | Overwrite                                         |
| `andMerge`    | Merge filter parameters using the `$and` operator |
| `orMerge`     | Merge filter parameters using the `$or` operator  |
| `intersect`   | Intersection                                      |
| `union`       | Union                                             |

---

## File: docs/en-US/api/resourcer/middleware.md

# Middleware

It is similar to the middleware of Koa, but with more enhanced features for easy extensions.

The defined middleware can be inserted for use in multiple places, such as the resourcer, and it is up to the developer for when to invoke it.

## Constructor

**Signature**

- `constructor(options: Function)`
- `constructor(options: MiddlewareOptions)`

**Parameter**

| Name              | Type                 | Default | Description                            |
| ----------------- | -------------------- | ------- | -------------------------------------- |
| `options`         | `Function`           | -       | Handler function of middlware          |
| `options`         | `MiddlewareOptions ` | -       | Configuration items of middlware       |
| `options.only`    | `string[]`           | -       | Only the specified actions are allowed |
| `options.except`  | `string[]`           | -       | The specified actions are excluded     |
| `options.handler` | `Function`           | -       | Handler function                       |

**Example**

Simple definition:

```ts
const middleware = new Middleware((ctx, next) => {
  await next();
});
```

Definition with relevant parameters:

```ts
const middleware = new Middleware({
  only: ['create', 'update'],
  async handler(ctx, next) {
    await next();
  },
});
```

## Instance Methods

### `getHandler()`

Get the orchestrated handler functions.

**Example**

The following middleware will output `1` and then `2` when requested.

```ts
const middleware = new Middleware((ctx, next) => {
  console.log(1);
  await next();
});

middleware.use(async (ctx, next) => {
  console.log(2);
  await next();
});

app.resourcer.use(middleware.getHandler());
```

### `use()`

Add a middleware function to the current middleware. Used to provide extension points for the middleware. See `getHandler()` for the examples.

**Signature**

- `use(middleware: Function)`

**Parameter**

| Name         | Type       | Default | Description                        |
| ------------ | ---------- | ------- | ---------------------------------- |
| `middleware` | `Function` | -       | Handler function of the middleware |

### `disuse()`

Remove the middleware functions that have been added to the current middleware.

**Signature**

- `disuse(middleware: Function)`

**Parameter**

| Name         | Type       | Default | Description                        |
| ------------ | ---------- | ------- | ---------------------------------- |
| `middleware` | `Function` | -       | Handler function of the middleware |

**Example**

The following example will only output `1` when requested, the output of `2` in fn1 will not be executed.

```ts
const middleware = new Middleware((ctx, next) => {
  console.log(1);
  await next();
});

async function fn1(ctx, next) {
  console.log(2);
  await next();
}

middleware.use(fn1);

app.resourcer.use(middleware.getHandler());

middleware.disuse(fn1);
```

### `canAccess()`

Check whether the current middleware is to be invoked for a specific action, it is usually handled by the resourcer internally.

**Signature**

- `canAccess(name: string): boolean`

**Parameter**

| Name   | Type     | Default | Description        |
| ------ | -------- | ------- | ------------------ |
| `name` | `string` | -       | Name of the action |

## Other Exports

### `branch()`

Create a branch middleware for branching in the middleware.

**Signature**

- `branch(map: { [key: string]: Function }, reducer: Function, options): Function`

**Parameter**

| Name                     | Type                          | Default          | Description                                                                                                       |
| ------------------------ | ----------------------------- | ---------------- | ----------------------------------------------------------------------------------------------------------------- |
| `map`                    | `{ [key: string]: Function }` | -                | Mapping table of the branch handler function, key names are given by subsequent calculation functions when called |
| `reducer`                | `(ctx) => string`             | -                | Calculation function, it is used to calculate the key name of the branch based on the context                     |
| `options?`               | `Object`                      | -                | Configuration items of the branch                                                                                 |
| `options.keyNotFound?`   | `Function`                    | `ctx.throw(404)` | Handler function when key name is not found                                                                       |
| `options.handlerNotSet?` | `Function`                    | `ctx.throw(404)` | The function when no handler function is defined                                                                  |

**Example**

When authenticating user, determine what to do next according to the value of the `authenticator` parameter in the query section of the request URL.

```ts
app.resourcer.use(
  branch(
    {
      password: async (ctx, next) => {
        // ...
      },
      sms: async (ctx, next) => {
        // ...
      },
    },
    (ctx) => {
      return ctx.action.params.authenticator ?? 'password';
    },
  ),
);
```

---

## File: docs/en-US/api/resourcer/resource-manager.md

# ResourceManager

## Overview

`ResourceManager` is the resource management module of NocoBase, used to define resources and register operation methods for resources.

## Class Methods

### `define()`

Defines a resource.

```ts
app.resourceManager.define({
  name: 'auth',
  actions: {
    check: async (ctx, next) => {
      // ...
      await next();
    },
  },
});
```

#### Signature

- `define(options: ResourceOptions): Resource`

#### Type

```ts
export interface ResourceOptions {
  name: string;
  type?: ResourceType;
  actions?: {
    [key: string]: ActionType;
  };
  only?: Array<ActionName>;
  except?: Array<ActionName>;
  middleware?: MiddlewareType;
  middlewares?: MiddlewareType;
}

export type ResourceType =
  | 'single'
  | 'hasOne'
  | 'hasMany'
  | 'belongsTo'
  | 'belongsToMany';

export type ActionType = HandlerType | ActionOptions;
export type HandlerType = (
  ctx: ResourcerContext,
  next: () => Promise<any>,
) => any;
export interface ActionOptions {
  values?: any;
  fields?: string[];
  appends?: string[];
  except?: string[];
  whitelist?: string[];
  blacklist?: string[];
  filter?: FilterOptions;
  sort?: string[];
  page?: number;
  pageSize?: number;
  maxPageSize?: number;
  middleware?: MiddlewareType;
  middlewares?: MiddlewareType;
  handler?: HandlerType;
  [key: string]: any;
}
```

#### Details

##### ResourceOptions

| Property      | Type                                           | Description            | Default  |
| ------------- | ---------------------------------------------- | ---------------------- | -------- |
| `name`        | `string`                                       | Resource name          | -        |
| `type`        | `ResourceType`                                 | Resource type          | `single` |
| `actions`     | [`{ [key: string]: ActionType }`](#actiontype) | Actions                | -        |
| `only`        | `ActionName[]`                                 | Whitelist of `actions` | -        |
| `except`      | `ActionName[]`                                 | Blacklist of `actions` | -        |
| `middleware`  | `MiddlewareType`                               | Middleware             | -        |
| `middlewares` | `MiddlewareType`                               | Middlewares            | -        |

##### ActionType

There are two types of action methods:

- `HandlerType`

This type directly defines the operation method through middleware. Example:

```ts
app.resourceManager.define({
  name: 'users',
  actions: {
    updateProfile: async (ctx, next) => {
      // ...
      await next();
    },
  },
});
```

- `ActionOptions`

This type is mainly used to override the request parameters of a certain existing operation. Example:

```ts
app.resourceManager.define({
  name: 'users',
  actions: {
    list: {
      fields: [],
      filter: {},
      // ...
    },
  },
});
```

| Property        | Type             | Description                                                                 |
| --------------- | ---------------- | --------------------------------------------------------------------------- |
| `values`        | `any`            | Default values for the action request                                       |
| `filter`        | `Filter`         | Filtering parameters, refer to [Filter Operators](../database/operators.md) |
| `fields`        | `string[]`       | Fields to retrieve                                                          |
| `except`        | `string[]`       | Fields to exclude                                                           |
| `appends`       | `string[]`       | Related fields to append                                                    |
| `whitelist`     | `string[]`       | Field whitelist                                                             |
| `blacklist`     | `string[]`       | Field blacklist                                                             |
| `sort`          | `string[]`       | Sorting parameters                                                          |
| `page`          | `number`         | Current page                                                                |
| `pageSize`      | `number`         | Number of data items per page                                               |
| `maxPageSize`   | `number`         | Maximum number of data items per page                                       |
| `middleware`    | `MiddlewareType` | Middleware                                                                  |
| `middlewares`   | `MiddlewareType` | Middlewares                                                                 |
| `handler`       | `HandlerType`    | Method executed for the action                                              |
| `[key: string]` | `any`            | Other extended configurations                                               |

### `registerActionHandlers()`

Registers action methods.

#### Signature

- `registerActionHandler(name: ActionName, handler: HandlerType)`

#### Type

```ts
export type DefaultActionType =
  | 'list'
  | 'create'
  | 'get'
  | 'update'
  | 'destroy'
  | 'set'
  | 'add'
  | 'remove';
export type ActionName = DefaultActionType | Omit<string, DefaultActionType>;

export type HandlerType = (
  ctx: ResourcerContext,
  next: () => Promise<any>,
) => any;
```

#### Details

| Property  | Type          | Description                                                                                                                                                        |
| --------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `name`    | `ActionName`  | Action name.1. As a regular string, registers actions for all resources.2. In the form `<resource>:<action>`, registers actions for specific resources |
| `handler` | `HandlerType` | Middleware for the action                                                                                                                                          |

### `isDefined()`

Checks if a resource is defined.

#### Signature

- `isDefined(name: string)`

#### Details

| Property | Type     | Description   |
| -------- | -------- | ------------- |
| `name`   | `string` | Resource name |

### `import()`

Loads resource configurations from a specified directory.

```ts
// ./resources/demo.ts
export default {
  name: 'demo',
  actions: {
    async list(ctx, next) {
      // ...
      await next();
    },
  },
};

const resourceManager = new ResourceManager();
await resourceManager.import({
  directory: path.resolve(__dirname, 'resources'),
});
```

#### Signature

- `import(options: ImportOptions): Promise<Map<string, Resource>>`

#### Type

```ts
export interface ImportOptions {
  directory: string;
  extensions?: string[];
}
```

#### Details

| Property     | Type       | Description               | Default Value          |
| ------------ | ---------- | ------------------------- | ---------------------- |
| `directory`  | `string`   | Directory path            | -                      |
| `extensions` | `string[]` | Optional, file extensions | `['js', 'ts', 'json']` |

### `use()`

Adds `ResourceManager` middleware.

```ts
resourceManager.use(async () => {
  return async function (ctx, next) {
    // ...
    await next();
  };
});
```

#### Signature

- `use(middlewares: HandlerType | HandlerType[], options: ToposortOptions = {})`

#### Details

Refer to [Middleware](../../development/server/middleware.md).

### `middleware()`

Middleware for `ResourceManager`, parses request parameters (refer to [ctx.action](./action.md)) and executes operation methods.

---

## File: docs/en-US/api/resourcer/resource.md

# Resource

Resource is used to define resource instance. Resource instances managed by resourcer can be accessed through HTTP requests.

## Constructor

To create resource instance. Normally it is not used directly, but replaced by the call of the `define()` interface of resourcer.

**Signature**

- `constructor(options: ResourceOptions, resourcer: Resourcer)`

**Parameter**

| Name                  | Type                                 | Default    | Description                                                                                                     |
| --------------------- | ------------------------------------ | ---------- | --------------------------------------------------------------------------------------------------------------- |
| `options.name`        | `string`                             | -          | Name of the resource, corresponding to the resource address in the route of the URL                             |
| `options.type`        | `string`                             | `'single'` | Type of the resource, options are `'single'`, `'hasOne'`, `'hasMany'`, `'belongsTo'`, `'belongsToMany'`         |
| `options.actions`     | `Object`                             | -          | List of actions that can be taken on the resource, see the example for details                                  |
| `options.middlewares` | `MiddlewareType \| MiddlewareType[]` | -          | List of middlewares for any operational access to the resource that is defining，see the example for details    |
| `options.only`        | `ActionName[]`                       | `[]`       | Whitelist for global actions, only actions contained in the array (if `length > 0`) can be accessed             |
| `options.except`      | `ActionName[]`                       | `[]`       | Blacklist for global actions, all actions except those contained in the array (if `length > 0`) can be accessed |
| `resourcer`           | `Resourcer`                          | -          | The resourcer instance                                                                                          |

**Example**

```ts
app.resourcer.define({
  name: 'books',
  actions: {
    // Extended action
    publish(ctx, next) {
      ctx.body = 'ok';
    },
  },
  middleware: [
    // Extended middleware
    async (ctx, next) => {
      await next();
    },
  ],
});
```

## Instance Members

### `options`

Configuration items for the current resource.

### `resourcer`

The resourcer instance to which the resource belongs.

### `middlewares`

The registered middlewares.

### `actions`

The registered mapping table of actions.

### `except`

Actions that are excluded.

## Instance Methods

### `getName()`

Get the name of the current resource.

**Signature**

- `getName(): string`

**Example**

```ts
const resource = app.resourcer.define({
  name: 'books',
});

resource.getName(); // 'books'
```

### `getAction()`

Get action with the corresponding name.

**Signature**

- `getAction(name: string): Action`

**Parameter**

| Name   | Type     | Default | Description        |
| ------ | -------- | ------- | ------------------ |
| `name` | `string` | -       | Name of the action |

**Example**

```ts
const resource = app.resourcer.define({
  name: 'books',
  actions: {
    publish(ctx, next) {
      ctx.body = 'ok';
    },
  },
});

resource.getAction('publish'); // [Function: publish]
```

---

## File: docs/en-US/api/sdk/auth.md

# Auth

## Overview

The `Auth` class is primarily used for accessing user information on the client-side, as well as requesting user authentication-related APIs.

## Instance Properties

### `locale`

The language used by the current user.

### `role`

The role used by the current user.

### `token`

The API interface token.

### `authenticator`

The authenticator used for current user authentication. Refer to [User Authentication](../../handbook/auth/user.md).

## Class Methods

### `signIn()`

User login.

#### Signature

- `async signIn(values: any, authenticator?: string): Promise<AxiosResponse<any>>`

#### Details

| Parameter       | Type     | Description                             |
| --------------- | -------- | --------------------------------------- |
| `values`        | `any`    | Login API request parameters            |
| `authenticator` | `string` | Authenticator identifier used for login |

### `signUp()`

User registration.

#### Signature

- `async signUp(values: any, authenticator?: string): Promise<AxiosResponse<any>>`

#### Details

| Parameter       | Type     | Description                                    |
| --------------- | -------- | ---------------------------------------------- |
| `values`        | `any`    | Registration API request parameters            |
| `authenticator` | `string` | Authenticator identifier used for registration |

### `signOut()`

Log out.

#### Signature

- `async signOut(values: any, authenticator?: string): Promise<AxiosResponse<any>>`

#### Details

| Parameter       | Type     | Description                              |
| --------------- | -------- | ---------------------------------------- |
| `values`        | `any`    | Logout API request parameters            |
| `authenticator` | `string` | Authenticator identifier used for logout |

## 2. Official Technical Reference & Guides (nocobase/docs)

## File: README.md

# NocoBase V1 Documentation (Archived)

> **This repository is archived and no longer maintained.** V2 documentation lives in the main repository: [nocobase/nocobase](https://github.com/nocobase/nocobase) (under the `docs/` directory). For the latest docs, visit [docs.nocobase.com](https://docs.nocobase.com).

If you need to access the V1 documentation, you can run it locally:

## Local Development

```bash
git clone https://github.com/nocobase/docs.git
cd docs
yarn install

# Run English docs
yarn dev:en

# Run Chinese docs
yarn dev

# Run French docs
yarn dev:fr

# Run Japanese docs
yarn dev:ja

# Run Russian docs
yarn dev:ru
```

## Build

```bash
yarn build
```

Note: `yarn dev` and `yarn dev:en` cannot be run at the same time.

---

## File: package.json

{
  "name": "nocobase-docs",
  "version": "0.0.1",
  "description": "A static site based on dumi",
  "scripts": {
    "start": "npm run dev",
    "dev": "dumi dev",
    "dev:en": "cross-env DOC_LANG=en-US dumi dev",
    "dev:fr": "cross-env DOC_LANG=fr-FR dumi dev",
    "dev:ja": "cross-env DOC_LANG=ja-JP dumi dev",
    "dev:ru": "cross-env DOC_LANG=ru-RU dumi dev",
    "build": "dumi build",
    "build:en": "cross-env DOC_LANG=en-US dumi build",
    "build:fr": "cross-env DOC_LANG=fr-FR dumi build",
    "build:ja": "cross-env DOC_LANG=ja-JP dumi build",
    "build:ru": "cross-env DOC_LANG=ru-RU dumi build",
    "prepare": "husky install && dumi setup"
  },
  "authors": [],
  "license": "MIT",
  "commitlint": {
    "extends": [
      "@commitlint/config-conventional"
    ]
  },
  "lint-staged": {
    "*.{md,json}": [
      "prettier --write --no-error-on-unmatched-pattern"
    ]
  },
  "devDependencies": {
    "@alicloud/cdn20180510": "^4.2.2",
    "@commitlint/cli": "^18.2.0",
    "@commitlint/config-conventional": "^18.1.0",
    "ali-oss": "^6.1.0",
    "cross-env": "^7.0.3",
    "dumi": "^2.2.14",
    "husky": "^8.0.3",
    "lint-staged": "^15.0.2",
    "prettier": "^3.0.3"
  },
  "dependencies": {
    "@formulajs/formulajs": "^4.4.9",
    "@nocobase/client": "^0.21.0-alpha.6",
    "axios-mock-adapter": "1.22.0",
    "cytoscape": "^3.23.0",
    "dumi-theme-nocobase": "^0.2.31",
    "moment": "^2.30.1",
    "sucrase": "^3.0.0",
    "vditor": "^3.10.8"
  },
  "volta": {
    "node": "20.14.0",
    "yarn": "1.22.19"
  },
  "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
}

---

## File: tsconfig.json

{
  "compilerOptions": {
    "jsx": "react",
    "strict": true,
    "skipLibCheck": true,
    "noImplicitAny": false,
    "esModuleInterop": true,
    "baseUrl": "./",
    "paths": {
      "@@/*": [".dumi/tmp/*"]
    }
  },
  "include": [".dumirc.ts"]
}

---

## File: docs/en-US/components.md

# Components

---

## File: docs/en-US/index.md

# Index

<Navigate replace to="/welcome/introduction"></Navigate>

---

## File: docs/en-US/_partials/commercial-installation.md

## Installation

This plugin is a commercial plugin, which needs to be uploaded and activated through the plugin manager：

---

## File: docs/en-US/api/actions.md

# @nocobase/actions

## Overview

The `@nocobase/actions` package encapsulates frequently used CRUD-related methods. By simply registering it with the [ResourceManager](./resourcer/resource-manager), CRUD operation interfaces can be globally added to system resources.

### Basic Usage

```typescript
import * as actions from `@nocobase/actions`;

const resourceManager = new ResourceManager({
  // ...options
});

resourceManager.registerActionHandlers(actions);
```

## Action Methods

### create

Creates a resource. `POST /api/<resource>:create`.

```shell
curl "http://localhost:13000/api/users:create" \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{"username": "admin"}'
```

#### Request Body

| Parameter Name  | Type  | Description                                     |
| --------------- | ----- | ----------------------------------------------- |
| `[key: string]` | `any` | Key-value pairs representing resource fields    |

### list

Retrieves a list of resources. `GET /api/<resource>:list`.

```shell
curl -X GET http://localhost:13000/api/users:list
```

#### Parameters

| Parameter  | Type       | Description                                                        | Default |
| ---------- | ---------- | ------------------------------------------------------------------ | ------- |
| `filter`   | `Filter`   | Filtering parameters, see [Filter Operators](./database/operators) | -       |
| `fields`   | `string[]` | Fields to retrieve                                                 | -       |
| `except`   | `string[]` | Fields to exclude                                                  | -       |
| `appends`  | `string[]` | Related fields to append                                           | -       |
| `sort`     | `string[]` | Sorting parameters                                                 | -       |
| `paginate` | `boolean`  | Whether to use pagination                                          | `true`  |
| `page`     | `number`   | Current page number                                                | `1`     |
| `pageSize` | `number`   | Number of items per page                                           | `20`    |

### get

Retrieves a specific resource. `GET /api/<resource>:get`.

```shell
curl -X GET http://localhost:13000/api/users:get?filterByTk=1
```

#### Parameters

| Parameter    | Type               | Description                                                        | Default |
| ------------ | ------------------ | ------------------------------------------------------------------ | ------- |
| `filterByTk` | `number \| string` | Filter by primary key value                                        | -       |
| `filter`     | `Filter`           | Filtering parameters, see [Filter Operators](./database/operators) | -       |
| `fields`     | `string[]`         | Fields to retrieve                                                 | -       |
| `except`     | `string[]`         | Fields to exclude                                                  | -       |
| `appends`    | `string[]`         | Related fields to append                                           | -       |

### update

Updates one or more resources. `PUT /api/<resource>:update`.

```shell
curl "http://localhost:13000/api/users:update?filterByTk=1" \
  -X PUT \
  -H "Content-Type: application/json" \
  -d '{"username": "admin"}'
```

#### Parameters

| Parameter    | Type               | Description                                                        |
| ------------ | ------------------ | ------------------------------------------------------------------ |
| `filter`     | `Filter`           | Filtering parameters, see [Filter Operators](./database/operators) |
| `filterByTk` | `number \| string` | Filter by primary key value                                        |

*Note: At least one of `filter` or `filterByTk` must be provided.*

#### Request Body

| Parameter Name  | Type  | Description                                     |
| --------------- | ----- | ----------------------------------------------- |
| `[key: string]` | `any` | Key-value pairs representing resource fields    |

### destroy

Deletes one or more resources. `DELETE /api/<resource>:destroy`.

```shell
curl -X DELETE http://localhost:13000/api/users:destroy?filterByTk=1
```

#### Parameters

| Parameter    | Type               | Description                                                        |
| ------------ | ------------------ | ------------------------------------------------------------------ |
| `filter`     | `Filter`           | Filtering parameters, see [Filter Operators](./database/operators) |
| `filterByTk` | `number \| string` | Filter by primary key value                                        |

*Note: At least one of `filter` or `filterByTk` must be provided.*

### firstOrCreate

Retrieves or creates a resource. `POST /api/<resource>:firstOrCreate`.

```shell
curl "http://localhost:13000/api/users:firstOrCreate?filterKeys[]=username" \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{"username": "admin", "nickname": "Admin"}'
```

#### Parameters

| Parameter    | Type       | Description                                                |
| ------------ | ---------- | ---------------------------------------------------------- |
| `filterKeys` | `string[]` | Fields in the request body used to find existing resources |

#### Request Body

| Parameter Name  | Type  | Description                                     |
| --------------- | ----- | ----------------------------------------------- |
| `[key: string]` | `any` | Key-value pairs representing resource fields    |

### updateOrCreate

Updates or creates a resource. `POST /api/<resource>:updateOrCreate`.

```shell
curl "http://localhost:13000/api/users:updateOrCreate?filterKeys[]=username" \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{"username": "admin", "nickname": "Admin"}'
```

#### Parameters

| Parameter    | Type       | Description                                                |
| ------------ | ---------- | ---------------------------------------------------------- |
| `filterKeys` | `string[]` | Fields in the request body used to find existing resources |

#### Request Body

| Parameter Name  | Type  | Description                                     |
| --------------- | ----- | ----------------------------------------------- |
| `[key: string]` | `any` | Key-value pairs representing resource fields    |

### move

Moves resources, adjusting the order. Typically used for drag-and-drop sorting in pages. `POST /api/<resource>:move`.

```shell
curl -X POST "http://localhost:13000/api/users:move?sourceId=1&targetId=2"
```

#### Parameters

| Parameter     | Type                       | Description                                                 | Default |
| ------------- | -------------------------- | ----------------------------------------------------------- | ------- |
| `sourceId`    | `targetKey`                | ID of the element to move                                   | -       |
| `targetId`    | `targetKey`                | ID of the element to swap positions with                    | -       |
| `sortField`   | `string`                   | Name of the field where sorting is stored                   | `sort`  |
| `targetScope` | `string`                   | Sorting scope, a resource can be sorted by different scopes | -       |
| `sticky`      | `boolean`                  | Whether to stick the moved element                          | -       |
| `method`      | `insertAfter` \| `prepend` | Insertion method: whether to insert before                  |

### set

Sets associated objects for a resource. `POST /api/<resource>/<resourceKey>/<association>:set`.

```shell
curl "http://localhost:13000/api/users/1/roles:set" \
  -X POST \
  -H "Content-Type: application/json" \
  -d '["admin", "member"]'
```

#### Request Body

- `TargetKey | TargetKey[]` - Array of primary key values for associated objects.

### add

Adds associated objects to a resource. `POST /api/<resource>/<resourceKey>/<association>:add`.

```shell
curl "http://localhost:13000/api/users/1/roles:add" \
  -X POST \
  -H "Content-Type: application/json" \
  -d '["admin"]'
```

#### Request Body

- `TargetKey | TargetKey[]` - Array of primary key values for associated objects.

### remove

Removes associated objects from a resource. `POST /api/<resource>/<resourceKey>/<association>:remove`.

```shell
curl "http://localhost:13000/api/users/1/roles:remove" \
  -X POST \
  -H "Content-Type: application/json" \
  -d '["admin"]'
```

#### Request Body

- `TargetKey | TargetKey[]` - Array of primary key values for associated objects.

### toggle

Toggles associated objects for a resource, adding them if they don't exist, or removing them if they do. `POST /api/<resource>/<resourceKey>/<association>:toggle`.

```shell
curl "http://localhost:13000/api/users/1/roles:toggle" \
  -X POST \
  -H "Content-Type: application/json" \
  -d '["admin", "member"]'
```

#### Request Body

- `TargetKey | TargetKey[]` - Array of primary key values for associated objects.

---

## File: docs/en-US/api/cli.md

# @nocobase/cli

The NocoBase CLI is designed to help you develop, build, and deploy NocoBase applications.

<Alert>

NocoBase CLI supports *ts-node* and *node* two operation modes.

- ts-node mode (Default): Used for development environment, support real-time compilation, with relatively slow response
- node mode：Used for production environment, with quick response, but you need to execute `yarn nocobase build` to compile the entire source code first

</Alert>

## Instructions For Use

```bash
$ yarn nocobase -h

Usage: nocobase [command] [options]

Options:
  -h, --help

Commands:
  console
  db:auth               Verify if the database is successfully connected
  db:sync               Generate relevant data tables and fields through the configuration of collections
  install               Install
  start                 Start application in production environment
  build                 Compile and package
  clean                 Delete the compiled files
  dev                   Start application for development environment with real-time compilation
  doc                   Documentation development
  test                  Testing
  umi
  upgrade               Upgrade
  migrator              Data migration
  pm                    Plugin manager
  help
```

## Application in Scaffolding

`scripts` in the application scaffolding `package.json` is as below:

```json
{
  "scripts": {
    "dev": "nocobase dev",
    "start": "nocobase start",
    "clean": "nocobase clean",
    "build": "nocobase build",
    "test": "nocobase test",
    "pm": "nocobase pm",
    "postinstall": "nocobase postinstall"
  }
}
```

## Command Line Extensions

NocoBase CLI is built based on [commander](https://github.com/tj/commander.js). You can write the extended commands freely in `app/server/index.ts`:

```ts
const app = new Application(config);

app.command('hello').action(() => {});
```

or in the plugin:

```ts
class MyPlugin extends Plugin {
  beforeLoad() {
    this.app.command('hello').action(() => {});
  }
}
```

Run in the terminal:

```bash
$ yarn nocobase hello
```

## Built-in Commands

Sorted by frequency of use.

### `dev`

Start application and compile code in real time in development environment.

<Alert>
NocoBase is installed automatically if it is not installed (Refer to the `install` command).
</Alert>

```bash
Usage: nocobase dev [options]

Options:
  -p, --port [port]
  --client
  --server
  -h, --help
```

Example:

```bash
# Launch application for development environment, with real-time compilation
yarn nocobase dev
# Start the server side only
yarn nocobase dev --server
# Start the client side only
yarn nocobase dev --client
```

### `start`

Start application in production environment, the code needs *yarn build*.

<Alert>

- NocoBase is installed automatically if it is not installed (Refer to the `install` command).
- The source code needs to be re-packaged if it has any modification (Refer to the `build` command).

</Alert>

```bash
$ yarn nocobase start -h

Usage: nocobase start [options]

Options:
  -p, --port
  -s, --silent
  -h, --help
```

Example:

```bash
# Launch application for production environment
yarn nocobase start
```

### `install`

Install.

```bash
$ yarn nocobase install -h

Usage: nocobase install [options]

Options:
  -f, --force
  -c, --clean
  -s, --silent
  -l, --lang [lang]
  -e, --root-email <rootEmail>
  -p, --root-password <rootPassword>
  -n, --root-nickname [rootNickname]
  -h, --help
```

Example:

```bash
# Initial installation
yarn nocobase install -l zh-CN -e admin@nocobase.com -p admin123
# Delete all data tables from NocoBase and reinstall
yarn nocobase install -f -l zh-CN -e admin@nocobase.com -p admin123
# Clear database and reinstall
yarn nocobase install -c -l zh-CN -e admin@nocobase.com -p admin123
```

<Alert>

Difference between `-f/--force` and `-c/--clean`:

- `-f/--force` Delete data tables of NocoBase
- `-c/--clean` Clear database, all data tables are deleted

</Alert>

### `upgrade`

Upgrade.

```bash
yarn nocobase upgrade
```

### `test`

*jest* test, which supports all [jest-cli](https://jestjs.io/docs/cli) options, also supports `-c, --db-clean`.

```bash
$ yarn nocobase test -h

Usage: nocobase test [options]

Options:
  -c, --db-clean        Clear database before running all tests
  -h, --help
```

Example:

```bash
# Run all test files
yarn nocobase test
# Run all test files in the specified folder
yarn nocobase test packages/core/server
# Run all tests in the specified file
yarn nocobase test packages/core/database/src/__tests__/database.test.ts

# Clear database before running all tests
yarn nocobase test -c
yarn nocobase test packages/core/server -c
```

### `build`

The source code needs to be compiled and packaged before the code is deployed to the production environment; and you need to re-build the code if it has any modification.

```bash
# All packages
yarn nocobase build
# Specified packages
yarn nocobase build app/server app/client
```

### `clean`

Delete the compiled files.

```bash
yarn clean
# Equivalent to
yarn rimraf -rf packages/*/*/{lib,esm,es,dist}
```

### `doc`

Documentation development.

```bash
# Start the documentation
yarn doc  --lang=zh-CN # Equivalent to yarn doc dev
# Build the documentation, and output it to . /docs/dist/ directory by default
yarn doc build
# View the final result of the output documentation of dist
yarn doc serve --lang=zh-CN
```

### `db:auth`

Verify if the database is successfully connected.

```bash
$ yarn nocobase db:auth -h

Usage: nocobase db:auth [options]

Options:
  -r, --retry [retry]   Number of retries
  -h, --help
```

### `db:sync`

Generate relevant data tables and fields through the configuration of collections.

```bash
$ yarn nocobase db:sync -h

Usage: nocobase db:sync [options]

Options:
  -f, --force
  -h, --help   display help for command
```

### `migrator`

Data migration.

```bash
$ yarn nocobase migrator

Positional arguments:
  <command>
    up        Applies pending migrations
    down      Revert migrations
    pending   Lists pending migrations
    executed  Lists executed migrations
    create    Create a migration file
```

### `pm`

Plugin manager.

```bash
# Create plugin
yarn pm create hello
# Register plugin
yarn pm add hello
# Enable plugin
yarn pm enable hello
# Disable plugin
yarn pm disable hello
# Remove plugin
yarn pm remove hello
```

Not achieved yet:

```bash
# Upgrade plugin
yarn pm upgrade hello
# Publish plugin
yarn pm publish hello
```

### `umi`

`app/client` is built based on [umi](https://umijs.org/), you can run other relevant commands through `nocobase umi`.

```bash
# Generate the .umi cache needed for the development environment
yarn nocobase umi generate tmp
```

### `help`

The help command, you can also use the option parameter, `-h` and `--help`.

```bash
# View all cli
yarn nocobase help
# Use -h instead
yarn nocobase -h
# Or --help
yarn nocobase --help
# View options of command db:sync
yarn nocobase db:sync -h
```

---

## File: docs/en-US/api/index.md

# Overview

| Module                                                                                                | Package               | Description                     |
| ----------------------------------------------------------------------------------------------------- | --------------------- | ------------------------------- |
| [Server](/api/server/application)                                                                     | `@nocobase/server`    | Server-side application         |
| [Database](/api/database)                                                                             | `@nocobase/database`  | Database access layer           |
| [Resourcer](/api/resourcer/resource-manager)                                                          | `@nocobase/resourcer` | Resource and route mapping      |
| [ACL](/api/acl/acl)                                                                                   | `@nocobase/acl`       | Access Control                  |
| [Auth](/api/auth/auth-manager)                                                                        | `@nocobase/auth`      | User Authentication             |
| [Client](https://client.docs-cn.nocobase.com/core/application/application) | `@nocobase/client`    | Client-side application         |
| [Cache](/api/cache/cache-manager)                                                                     | `@nocobase/cache`     | Server-side cache               |
| [Logger](/api/logger)                                                                                 | `@nocobase/logger`    | Server-side logging             |
| [Telemetry](/api/telemetry/telemetry)                                                                 | `@nocobase/telemetry` | Server-side telemetry           |
| [CLI](/api/cli)                                                                                       | `@nocobase/cli`       | NocoBase Command Line Interface |
| [SDK](/api/sdk)                                                                                       | `@nocobase/sdk`       | NocoBase SDK                    |
| [Actions](/api/actions)                                                                               | `@nocobase/actions`   | Built-in resource operations    |
| [Test](/api/test/server)                                                                              | `@nocobase/test`      | Automated testing               |

---

## File: docs/en-US/api/logger.md

# @nocobase/logger

## Create Logger

### createLogger()

Creates a custom logger.

#### Signature

- `createLogger(options: LoggerOptions)`

#### Type

```ts
interface LoggerOptions
  extends Omit<winston.LoggerOptions, 'transports' | 'format'> {
  dirname?: string;
  filename?: string;
  format?: 'logfmt' | 'json' | 'delimiter' | 'console' | winston.Logform.Format;
  transports?: ('console' | 'file' | 'dailyRotateFile' | winston.transport)[];
}
```

#### Details

- `dirname`: Log directory
- `filename`: Log file name
- `format`: Log format
- `transports`: Log transports

### createSystemLogger()

Creates system runtime logs printed in a specified method. Refer to [Logger plugin - System log](../plugins/logger/index.md#system-log).

#### Signature

- `createSystemLogger(options: SystemLoggerOptions)`

#### Type

```ts
export interface SystemLoggerOptions extends LoggerOptions {
  seperateError?: boolean; // print error seperately, default true
}
```

#### Details

- `seperateError`: Whether to print `error` level logs separately

### app.createLogger()

#### Definition

```ts
class Application {
  createLogger(options: LoggerOptions) {
    const { dirname } = options;
    return createLogger({
      ...options,
      dirname: getLoggerFilePath(this.name || 'main', dirname || ''),
    });
  }
}
```

When `dirname` is a relative path, the log files will be output to the directory named after the current application.

### plugin.createLogger()

Usage is the same as `app.createLogger()`.

#### Definition

```ts
class Plugin {
  createLogger(options: LoggerOptions) {
    return this.app.createLogger(options);
  }
}
```

## Configuration

### getLoggerLevel()

`getLoggerLevel(): 'debug' | 'info' | 'warn' | 'error'`

Gets the log level currently configured in the system.

### getLoggerFilePath()

`getLoggerFilePath(...paths: string[]): string`

Concatenates directory paths based on the log directory currently configured in the system.

### getLoggerTransports()

`getLoggerTransports(): ('console' | 'file' | 'dailyRotateFile')[]`

Gets the log output methods currently configured in the system.

### getLoggerFormat()

`getLoggerFormat(): 'logfmt' | 'json' | 'delimiter' | 'console'`

Gets the log format currently configured in the system.

## Logger Transports

### Transports

Predefined output methods.

- `Transports.console`
- `Transports.file`
- `Transports.dailyRotateFile`

```ts
import { Transports } from '@nocobase/logger';

const transport = Transports.console({
  //...
});
```

## References

- [Development - Logger](../handbook/logger/index.md)
- [Logger Plugin](../plugins/logger/index.md)

---

## File: docs/en-US/api/acl/acl.md

# ACL

## Overview

`ACL` is the permission management module used in NocoBase, responsible for user role management, permission registration and authorization, as well as permission policy evaluation and access control.

### Concepts

- **Resource**: Collections, or custom resources can be registered. Refer to [`@nocobase/resourcer`](../resourcer/resource-manager.md).
- **Action**: An operation interface for a resource, such as create, read, update, delete, or other custom actions. Refer to [`@nocobase/actions`](../actions).
- **Strategy**: Configures global permissions for roles, such as permissions for resource operations like create, read, update, delete, import, export, and system permissions like configuring the user interface.
- **Snippet**: Defines a collection of operations, enabling unified management of operation permissions. Snippet identifiers can be matched using the [minimatch](https://github.com/isaacs/minimatch) rules.

## Class Methods

### `define()`

Defines a role.

#### Signature

- `define(options: DefineOptions): ACLRole`

#### Type Definitions

```typescript
export interface DefineOptions {
  role: string;
  strategy?: string | AvailableStrategyOptions;
  actions?: ResourceActionsOptions;
  snippets?: string[];
}

export interface AvailableStrategyOptions {
  displayName?: string;
  actions?: false | string | string[];
  allowConfigure?: boolean;
  resource?: '*';
}

export interface ResourceActionsOptions {
  [actionName: string]: RoleActionParams;
}

export interface RoleActionParams {
  fields?: string[];
  filter?: any;
  own?: boolean;
  whitelist?: string[];
  blacklist?: string[];
}
```

#### Details

##### DefineOptions

| Property   | Type                                                                | Description                                                       |
| ---------- | ------------------------------------------------------------------- | ----------------------------------------------------------------- |
| `role`     | `string`                                                            | Unique identifier for the role                                    |
| `strategy` | `string` \| [`AvailableStrategyOptions`](#availablestrategyoptions) | Optional, global access strategy for the role                     |
| `actions`  | [`{ [actionName: string]: RoleActionParams; }`](#roleactionparams)  | Optional, permission configuration for actions                    |
| `snippets` | `string[]`                                                          | Optional, defines snippets that the role has permission to access |

##### AvailableStrategyOptions

| Property         | Type                              | Description                                               |
| ---------------- | --------------------------------- | --------------------------------------------------------- |
| `displayName`    | `string`                          | Optional, display name for the strategy                   |
| `action`         | `false` \| `string` \| `string[]` | Optional, operation interfaces                            |
| `allowConfigure` | `boolean`                         | Optional, whether to allow configuring the user interface |
| `resource`       | `*`                               | Applies to all resources                                  |

##### RoleActionParams

| Property    | Type       | Description                                                                                            |
| ----------- | ---------- | ------------------------------------------------------------------------------------------------------ |
| `fields`    | `string[]` | Optional, fields of the data table to operate on                                                       |
| `filter`    | `any`      | Optional, filter parameters that must be met, only records that meet the conditions can be operated on |
| `own`       | `boolean`  | Optional, whether to operate only on records created by oneself                                        |
| `whitelist` | `string[]` | Optional, whitelist of fields that can be accessed, only fields in the whitelist can be accessed       |
| `blacklist` | `string[]` | Optional, blacklist of fields that cannot be accessed, fields in the blacklist cannot be accessed      |

### `can()`

Determines the permission to execute an action and returns the final action parameters. Returns `null` if no permission.

#### Signature

- `can(options: CanArgs): CanResult | null`

#### Type Definitions

```typescript
interface CanArgs {
  role: string;
  resource: string;
  action: string;
  ctx?: any;
}

interface CanResult {
  role: string;
  resource: string;
  action: string;
  params?: any;
}
```

#### Details

##### CanArgs

| Property   | Type     | Description               |
| ---------- | -------- | ------------------------- |
| `role`     | `string` | Role identifier           |
| `resource` | `string` | Resource identifier       |
| `action`   | `string` | Action identifier         |
| `ctx`      | `any`    | Optional, request context |

##### CanResult

| Property   | Type     | Description                 |
| ---------- | -------- | --------------------------- |
| `role`     | `string` | Role identifier             |
| `resource` | `string` | Resource identifier         |
| `action`   | `string` | Action identifier           |
| `params`   | `any`    | Optional, action parameters |

### `registerSnippet()`

Registers a snippet.

#### Signature

- `registerSnippet(snippet: SnippetOptions)`

#### Type Definitions

```typescript
export type SnippetOptions = {
  name: string;
  actions: string[];
};
```

#### Details

| Property  | Type       | Description                                                                                                                              |
| --------- | ---------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `name`    | `string`   | Snippet identifier, can be matched using the [minimatch](https://github.com/isaacs/minimatch) rules. E.g., `auth.auth` matches `auth.*`. |
| `actions` | `string[]` | Resource operations included in the snippet, in the format `resource:action`. E.g., `users:list`.                                        |

### `setAvailableAction()`

Sets allowed actions.

#### Signature

- `setAvailableAction(name: string, options: AvailableActionOptions = {})`

```typescript
export interface AvailableActionOptions {
  displayName?: string;
  aliases?: string[] | string;
  resource?: string;
  // Perform operations on new data
  onNewRecord?: boolean;
  // Allow configuring fields
  allowConfigureFields?: boolean;
}
```

#### Details

| Property               | Type                   | Description                                                                           |
| ---------------------- | ---------------------- | ------------------------------------------------------------------------------------- |
| `displayName`          | `string`               | Optional, display name for the action                                                 |
| `aliases`              | `string` \| `string[]` | Optional, action aliases. E.g., aliases for `get`, `list` operations are both `view`. |
| `resource`             | `string`               | Optional, resource                                                                    |
| `onNewRecord`          | `boolean`              | Optional, whether the operation applies to new data, such as create operation         |
| `allowConfigureFields` | `boolean`              | Optional, whether to allow configuring fields                                         |

### `setAvailableStrategy()`

Sets allowed strategies for actions.

#### Signature

- `setAvailableStrategy(name: string, options: AvailableStrategyOptions)`

Refer to [AvailableStrategyOptions](#availablestrategyoptions).

### `allow()`

Defines the conditions under which operations are allowed.

```typescript
acl.allow('plugins', '*', 'public');
```

#### Signature

- `allow(resourceName: string, actionNames: string[] | string, condition?: string | ConditionFunc)`

#### Type

```typescript
export type ConditionFunc = (ctx: any) => Promise<boolean> | boolean;
```

#### Details

| Parameter      | Type                        | Description                                                                 | Default  |
| -------------- | --------------------------- | --------------------------------------------------------------------------- | -------- |
| `resourceName` | `string`                    | Resource                                                                    | -        |
| `actionNames`  | `string` \| `string[]`      | Action                                                                      | -        |
| `condition`    | `string` \| `ConditionFunc` | Optional, predefined condition identifier, or condition evaluation function | `public` |

Predefined condition identifiers:

- `public`: Public interface.
- `loggedIn`: Allowed when the user is logged in.
- `allowConfigure`: Allowed when the current user role has permission to configure the user interface.

### `addFixedParams()`

Adds fixed parameters to operations, merging them with current request parameters.

```typescript
acl.addFixedParams('users', 'list', () => {
  return {
    filter: {
      id: {
        $eq: 1,
      },
    },
  };
});
```

#### Signature

- `addFixedParams(resource: string, action: string, merger: Merger)`

#### Type Definitions

```typescript
export type Merger = () => object;
```

#### Details

| Parameter  | Type     | Description                                               |
| ---------- | -------- | --------------------------------------------------------- |
| `resource` | `string` | Resource                                                  |
| `action`   | `string` | Action                                                    |
| `merger`   | `Merger` | Function returning the fixed parameter object to be added |

### `use()`

Adds the `ACL` middleware.

```typescript
acl.use(async () => {
  return async function (ctx, next) {
    // ...
    await next();
  };
});
```

#### Signature

- `use(fn: any, options?: ToposortOptions)`

#### Details

Refer to [Middleware](../../development/server/middleware).

### `middleware()`

NocoBase access control middleware.

---

## File: docs/en-US/api/auth/auth-manager.md

# AuthManager

## Overview

`AuthManager` is the user authentication management module in NocoBase, used for registering different types of user authentication.

### Basic Usage

```ts
const authManager = new AuthManager({
  // Key to retrieve the current authenticator identifier from the request header
  authKey: 'X-Authenticator',
});

// Set methods for storing and retrieving authenticators in AuthManager
authManager.setStorer({
  get: async (name: string) => {
    return db.getRepository('authenticators').find({ filter: { name } });
  },
});

// Register an authentication type
authManager.registerTypes('basic', {
  auth: BasicAuth,
  title: 'Password',
});

// Use authentication middleware
app.resourceManager.use(authManager.middleware());
```

### Concepts

- **Authentication type (`AuthType`)**: Different types of authentication, such as Password, SMS, OIDC, SAML, etc.
- **Authenticator**: An authenticator is a database-stored entity linked to a configuration record for a specific authentication type (`AuthType`). Multiple authenticators can exist for one authentication type, each offering diffrent authentications.
- **Authenticator name**: Unique identifier for an authenticator, used to determine the current authentication employed by the current request.

## Class Methods

### `constructor()`

Constructor, creates an instance of `AuthManager`.

#### Signature

- `constructor(options: AuthManagerOptions)`

#### Types

```ts
export interface JwtOptions {
  secret: string;
  expiresIn?: string;
}

export type AuthManagerOptions = {
  authKey: string;
  default?: string;
  jwt?: JwtOptions;
};
```

#### Details

##### AuthManagerOptions

| Attribute | Type                        | Description                                                                     | Default           |
| --------- | --------------------------- | ------------------------------------------------------------------------------- | ----------------- |
| `authKey` | `string`                    | Optional key to save the current authenticator identifier in the request header | `X-Authenticator` |
| `default` | `string`                    | Optional, default authenticator identifier                                      | `basic`           |
| `jwt`     | [`JwtOptions`](#jwtoptions) | Optional, configure if using JWT for authentication                             | -                 |

##### JwtOptions

| Attribute   | Type     | Description                       | Default           |
| ----------- | -------- | --------------------------------- | ----------------- |
| `secret`    | `string` | Token secret key                  | `X-Authenticator` |
| `expiresIn` | `string` | Optional, token expiration period | `7d`              |

### `setStorer()`

Set methods for storing and retrieving authenticator data.

#### Signature

- `setStorer(storer: Storer)`

#### Types

```ts
export interface Authenticator = {
  authType: string;
  options: Record<string, any>;
  [key: string]: any;
};

export interface Storer {
  get: (name: string) => Promise<Authenticator>;
}
```

#### Details

##### Authenticator

| Attribute  | Type                  | Description                          |
| ---------- | --------------------- | ------------------------------------ |
| `authType` | `string`              | Authentication type                  |
| `options`  | `Record<string, any>` | Authenticator-related configurations |

##### Storer

`Storer` is the interface for authenticator storage, containing one method.

- `get(name: string): Promise<Authenticator>` - Get authenticator by identifier. In NocoBase, the actual returned type is [AuthModel](../../handbook/auth/dev/api#authmodel).

### `registerTypes()`

Register authentication types.

#### Signature

- `registerTypes(authType: string, authConfig: AuthConfig)`

#### Types

```ts
export type AuthExtend<T extends Auth> = new (config: Config) => T;

type AuthConfig = {
  auth: AuthExtend<Auth>; // The authentication class.
  title?: string; // The display name of the authentication type.
};
```

#### Details

| Attribute | Type               | Description                                                          |
| --------- | ------------------ | -------------------------------------------------------------------- |
| `auth`    | `AuthExtend<Auth>` | Authentication type implementation, refer to [Auth](./auth.md)       |
| `title`   | `string`           | Optional. Title of the authentication type displayed on the frontend |

### `listTypes()`

Get a list of registered authentication types.

#### Signature

- `listTypes(): { name: string; title: string }[]`

#### Details

| Attribute | Type     | Description                      |
| --------- | -------- | -------------------------------- |
| `name`    | `string` | Authentication type identifier   |
| `title`   | `string` | Title of the authentication type |

### `get()`

Get authenticator.

#### Signature

- `get(name: string, ctx: Context)`

#### Details

| Attribute | Type      | Description              |
| --------- | --------- | ------------------------ |
| `name`    | `string`  | Authenticator identifier |
| `ctx`     | `Context` | Request context          |

### `middleware()`

Authentication middleware. Get the current authenticator and perform user authentication.

---

## File: docs/en-US/api/auth/auth.md

# Auth

## Overview

`Auth` is an abstract class for user authentication types, defining the interfaces required to complete user authentication. To extend new user authentication types, you need to inherit from the `Auth` class and implement its methods. The basic implementation can be referred to as [BaseAuth](./base-auth.md).

```ts
interface IAuth {
  user: Model;
  // Check the authentication status and return the current user.
  check(): Promise<Model>;
  signIn(): Promise<any>;
  signUp(): Promise<any>;
  signOut(): Promise<any>;
}

export abstract class Auth implements IAuth {
  abstract user: Model;
  abstract check(): Promise<Model>;
  // ...
}

class CustomAuth extends Auth {
  // check: Authentication
  async check() {
    // ...
  }
}
```

## Instance Properties

### `user`

Information of the authenticated user.

#### Signature

- `abstract user: Model`

## Class Methods

### `constructor()`

Constructor, creates an instance of `Auth`.

#### Signature

- `constructor(config: AuthConfig)`

#### Types

```ts
export type AuthConfig = {
  authenticator: Authenticator;
  options: {
    [key: string]: any;
  };
  ctx: Context;
};
```

#### Details

##### AuthConfig

| Attribute       | Type                                            | Description                                                                                                                 |
| --------------- | ----------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
| `authenticator` | [`Authenticator`](./auth-manager#authenticator) | Authenticator data model, the actual type in NocoBase applications is [AuthModel](../../handbook/auth/dev/api.md#authmodel) |
| `options`       | `Record<string, any>`                           | Authenticator-related configurations                                                                                        |
| `ctx`           | `Context`                                       | Request context                                                                                                             |

### `check()`

User authentication, returns user information. This is an abstract method that all authentication types must implement.

#### Signature

- `abstract check(): Promise<Model>`

### `signIn()`

User login.

#### Signature

- `signIn(): Promise<any>`

### `signUp()`

User registration.

#### Signature

- `signUp(): Promise<any>`

### `signOut()`

User logout.

#### Signature

- `signOut(): Promise<any>`

---

## File: docs/en-US/api/auth/base-auth.md

# BaseAuth

## Overview

`BaseAuth` inherits from the abstract class [Auth](./auth.md) and serves as the basic implementation for user authentication types, using JWT as the authentication method. In most cases, extending user authentication types can be achieved by inheriting from `BaseAuth` instead of directly inheriting from the `Auth` abstract class.

```ts
class BasicAuth extends BaseAuth {
  constructor(config: AuthConfig) {
    // Set user collection
    const userCollection = config.ctx.db.getCollection('users');
    super({ ...config, userCollection });
  }

  // User authentication logic, called by `auth.signIn`
  // Returns user data
  async validate() {
    const ctx = this.ctx;
    const { values } = ctx.action.params;
    // ...
    return user;
  }
}
```

## Class Methods

### `constructor()`

Constructor, creates an instance of `BaseAuth`.

#### Signature

- `constructor(config: AuthConfig & { userCollection: Collection })`

#### Details

| Parameter        | Type         | Description                                                                                                  |
| ---------------- | ------------ | ------------------------------------------------------------------------------------------------------------ |
| `config`         | `AuthConfig` | Refer to [Auth - AuthConfig](./auth.md#authconfig)                                                           |
| `userCollection` | `Collection` | User collection, e.g., `db.getCollection('users')`, refer to [DataBase - Collection](../database/collection) |

### `user()`

Accessor for setting and getting user information, defaulting to using the `ctx.state.currentUser` object.

#### Signature

- `set user()`
- `get user()`

### `check()`

Authenticates through the request token and returns user information.

### `signIn()`

User login, generates a token.

### `signUp()`

User registration.

### `signOut()`

User logout, token expiration.

### `validate()` \*

Core authentication logic, called by the `signIn` interface, to determine whether the user can successfully log in.

---

## File: docs/en-US/api/cache/cache-manager.md

# CacheManager

## Overview

CacheManager is based on [node-cache-manager](https://github.com/node-cache-manager/node-cache-manager) and provides caching module management for NocoBase. The built-in cache types are:

- **memory**: Provided by the default lru-cache of node-cache-manager.
- **redis**: Supported by node-cache-manager-redis-yet for Redis caching.

More types can be extended and registered through the API.

### Concepts

- **Store**: Defines a caching method, including a factory method for creating caches and other related configurations. Each caching method has a unique identifier provided during registration. The two built-in caching methods correspond to the unique identifiers `memory` and `redis`.

- **Store Factory Method**: Provided by `node-cache-manager` and related extension packages, used to create caches. Examples include `memory` provided by `node-cache-manager` by default, and `redisStore` provided by `node-cache-manager-redis-yet`. In this context, the object to be provided corresponds to [`StoreOptions`](#storeoptions), which is the first parameter of the `caching` method in `node-cache-manager`.

- **Cache**: A class encapsulated by NocoBase, providing methods related to cache usage. When actually using caching, operations are performed on instances of `Cache`. Each `Cache` instance has a unique identifier, which serves as a namespace for distinguishing different modules.

## Class Methods

### `constructor()`

#### Signature

- `constructor(options?: CacheManagerOptions)`

#### Type

```ts
export type CacheManagerOptions = Partial<{
  defaultStore: string;
  stores: {
    [storeType: string]: StoreOptions;
  };
}>;

type StoreOptions = {
  store?: 'memory' | FactoryStore<Store, any>;
  close?: (store: Store) => Promise<void>;
  // global config
  [key: string]: any;
};
```

#### Details

##### CacheManagerOptions

| Property       | Type                           | Description                                                                                                                                                          |
| -------------- | ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `defaultStore` | `string`                       | Unique identifier for the default cache type.                                                                                                                        |
| `stores`       | `Record<string, StoreOptions>` | Registers cache types. The key is the unique identifier for the cache type, and the value is an object containing the registration method and global configurations. |

##### StoreOptions

| Property        | Type                                   | Description                                                                                                                                                                                              |
| --------------- | -------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `store`         | `memory` \| `FactoryStore<Store, any>` | The store factory method, corresponding to the first parameter of the `caching` method.                                                                                                                  |
| `close`         | `(store: Store) => Promise<void>`      | Optional. For middleware that requires establishing a connection, such as Redis, provide a callback method for closing the connection. The parameter is the object returned by the store factory method. |
| `[key: string]` | `any`                                  | Other global configurations for the store, corresponding to the second parameter of the `caching` method.                                                                                                |

#### Default `options`

```ts
import { redisStore, RedisStore } from 'cache-manager-redis-yet';

const defaultOptions: CacheManagerOptions = {
  defaultStore: 'memory',
  stores: {
    memory: {
      store: 'memory',
      // global config
      max: 2000,
    },
    redis: {
      store: redisStore,
      close: async (redis: RedisStore) => {
        await redis.client.quit();
      },
    },
  },
};
```

The `options` parameter will be merged with the default options. Existing default options can be omitted. For example:

```ts
const cacheManager = new CacheManager({
  stores: {
    defaultStore: 'redis',
    redis: {
      // redisStore is already provided in the default options, so only need to provide redisStore configuration.
      url: 'redis://localhost:6379',
    },
  },
});
```

### `registerStore()`

Register a new caching method. Example:

```ts
import { redisStore } from 'cache-manager-redis-yet';

cacheManager.registerStore({
  // Unique identifier for the store
  name: 'redis',
  // Factory method for creating the store
  store: redisStore,
  // Callback method for closing the store connection
  close: async (redis: RedisStore) => {
    await redis.client.quit();
  },
  // Global configurations
  url: 'xxx',
});
```

#### Signature

- `registerStore(options: { name: string } & StoreOptions)`

### `createCache()`

Create a cache. Example:

```ts
await cacheManager.createCache({
  name: 'default', // Unique identifier for the cache
  store: 'memory', // Unique identifier for the store
  prefix: 'mycache', // Automatically adds the 'mycache:' prefix to cache keys, optional
  // Other store configurations, custom configurations that will be merged with global store configurations
  max: 2000,
});
```

#### Signature

- `createCache(options: { name: string; prefix?: string; store?: string; [key: string]: any }): Promise<Cache>`

#### Details

##### options

| Property        | Type     | Description                                        |
| --------------- | -------- | -------------------------------------------------- |
| `name`          | `string` | Unique identifier for the cache                    |
| `store`         | `string` | Unique identifier for the store                    |
| `prefix`        | `string` | Optional. Prefix automatically added to cache keys |
| `[key: string]` | `any`    | Other custom store configurations                  |

When `store` is omitted, the `defaultStore` will be used. In this case, the caching

---

## File: docs/en-US/api/cache/cache.md

# Cache

## Basic Methods

You can refer to the documentation of [node-cache-manager](https://github.com/node-cache-manager/node-cache-manager).

- `get()`
- `set()`
- `del()`
- `reset()`
- `wrap()`
- `mset()`
- `mget()`
- `mdel()`
- `keys()`
- `ttl()`

## Other Methods

### `wrapWithCondition()`

Similar to `wrap()`, but can decide whether to use caching based on conditions.

```ts
async wrapWithCondition<T>(
  key: string,
  fn: () => T | Promise<T>,
  options?: {
    // External parameter to control whether to use cache results
    useCache?: boolean;
    // Determine whether to cache based on data results
    isCacheable?: (val: unknown) => boolean | Promise<boolean>;
    ttl?: Milliseconds;
  },
): Promise<T> {
```

### `setValueInObject()`

When the cached content is an object, changes the value of a specific key.

```ts
async setValueInObject(key: string, objectKey: string, value: unknown)
```

### `getValueInObject()`

When the cached content is an object, retrieves the value of a specific key.

```ts
async getValueInObject(key: string, objectKey: string)
```

### `delValueInObject()`

When the cached content is an object, deletes a specific key.

```ts
async delValueInObject(key: string, objectKey: string)
```

---

## File: docs/en-US/api/client/application.md

# Application

## Constructor

### `constructor()`

Create an application instance.

**Signature**

- `constructor(options: ApplicationOptions)`

**Example**

```ts
const app = new Application({
  apiClient: {
    baseURL: process.env.API_BASE_URL,
  },
  dynamicImport: (name: string) => {
    return import(`../plugins/${name}`);
  },
});
```

## Methods

### use()

Add Providers, build-in Providers are:

- APIClientProvider
- I18nextProvider
- AntdConfigProvider
- SystemSettingsProvider
- PluginManagerProvider
- SchemaComponentProvider
- SchemaInitializerProvider
- BlockSchemaComponentProvider
- AntdSchemaComponentProvider
- ACLProvider
- RemoteDocumentTitleProvider

### render()

Component to render the App.

```ts
import { Application } from '@nocobase/client';

export const app = new Application({
  apiClient: {
    baseURL: process.env.API_BASE_URL,
  },
  dynamicImport: (name: string) => {
    return import(`../plugins/${name}`);
  },
});

export default app.render();
```

---

## File: docs/en-US/api/client/index.md

# Overview

test

---

## File: docs/en-US/api/client/router.md

# Router

## API

### Initial

```tsx | pure
const app = new Application({
  router: {
    type: 'browser', // type default value is `browser`
  },
});

// or
const app = new Application({
  router: {
    type: 'memory',
    initialEntries: ['/'],
  },
});
```

### add Route

#### basic

```tsx | pure
import { RouteObject } from 'react-router-dom';
const app = new Application();

const Hello = () => {
  return <div>Hello</div>;
};

// first argument is `name` of route, second argument is `RouteObject`
app.router.add('root', {
  path: '/',
  element: <Hello />,
});

app.router.add('root', {
  path: '/',
  Component: Hello,
});
```

#### Component is String

```tsx | pure
app.addComponents({
  Hello,
});
app.router.add('root', {
  path: '/',
  Component: 'Hello',
});
```

#### nested

```tsx | pure
import { Outlet } from 'react-router-dom';

const Layout = () => {
  return (
    <div>
      <Link to="/home">Home</Link>
      <Link to="/about">about</Link>

      <Outlet />
    </div>
  );
};

const Home = () => {
  return <div>Home</div>;
};

const About = () => {
  return <div>About</div>;
};

app.router.add('root', {
  element: <Layout />,
});
app.router.add('root.home', {
  path: '/home',
  element: <Home />,
});
app.router.add('root.about', {
  path: '/about',
  element: <About />,
});
```

It will generate the following routes:

```tsx | pure
{
  element: <Layout />,
  children: [
    {
      path: '/home',
      element: <Home />
    },
    {
      path: '/about',
      element: <About />
    }
  ]
}
```

### remove Route

```tsx | pure
// remove route by name
app.router.remove('root.home');
app.router.remove('hello');
```

#### Router in plugin

```tsx | pure
class MyPlugin extends Plugin {
  async load() {
    // add route
    this.app.router.add('hello', {
      path: '/hello',
      element: <div>hello</div>,
    });

    // remove route
    this.app.router.remove('world');
  }
}
```

## Example

```tsx
/**
 * defaultShowCode: true
 */
import React from 'react';
import { Link, Outlet } from 'react-router-dom';
import { Application } from '@nocobase/client';

const Home = () => <h1>Home</h1>;
const About = () => <h1>About</h1>;

const Layout = () => {
  return (
    <div>
      <div>
        <Link to={'/'}>Home</Link>, <Link to={'/about'}>About</Link>
      </div>
      <Outlet />
    </div>
  );
};

const app = new Application({
  router: {
    type: 'memory',
    initialEntries: ['/'],
  },
});

app.router.add('root', {
  element: <Layout />,
});

app.router.add('root.home', {
  path: '/',
  element: <Home />,
});

app.router.add('root.about', {
  path: '/about',
  element: <About />,
});

export default app.getRootComponent();
```

---

## File: docs/en-US/api/client/extensions/acl.md

# ACL

## Components

### `<ACLProvider />`

### `<ACLRolesCheckProvider />`

### `<ACLCollectionProvider />`

### `<ACLActionProvider />`

### `<ACLCollectionFieldProvider />`

### `<ACLMenuItemProvider />`

## Hooks

### `useACLContext()`

### `useACLRoleContext()`

### `useRoleRecheck()`

---

## File: docs/en-US/api/client/extensions/block-provider.md

# BlockProvider

## Kernel Methods

### ``

### `useBlockRequestContext()`

## Build-in BlockProvider Components

### `<CalendarBlockProvider />`

### ``

### ``

### ``

### `<FormBlockProvider />`

### `<FormFieldProvider />`

### ``

### `<KanbanBlockProvider />`

---

## File: docs/en-US/api/client/extensions/collection-manager.md

# CollectionManager

## Components

### CollectionManagerProvider

```jsx | pure
<CollectionManagerProvider
  interfaces={{}}
  collections={[]}
></CollectionManagerProvider>
```

### CollectionProvider

```jsx | pure
const collection = {
  name: 'tests',
  fields: [
    {
      type: 'string',
      name: 'title',
      interface: 'input',
      uiSchema: {
        type: 'string',
        'x-component': 'Input',
      },
    },
  ],
};
<CollectionProvider collection={collection}></CollectionProvider>;
```

If there is no collection parameter passed in, get the collection from CollectionManagerProvider with the corresponding name.

```jsx | pure
const collections = [
  {
    name: 'tests',
    fields: [
      {
        type: 'string',
        name: 'title',
        interface: 'input',
        uiSchema: {
          type: 'string',
          'x-component': 'Input',
        },
      },
    ],
  },
];
<CollectionManagerProvider collections={collections}>
  <CollectionProvider name={'tests'}></CollectionProvider>
</CollectionManagerProvider>;
```

### CollectionFieldProvider

```jsx | pure
const field = {
  type: 'string',
  name: 'title',
  interface: 'input',
  uiSchema: {
    type: 'string',
    'x-component': 'Input',
  },
};
<CollectionFieldProvider field={field}></CollectionFieldProvider>;
```

If there is no field parameter passed in, get the field from CollectionProvider with the corresponding name.

```jsx | pure
const collection = {
  name: 'tests',
  fields: [
    {
      type: 'string',
      name: 'title',
      interface: 'input',
      uiSchema: {
        type: 'string',
        'x-component': 'Input',
      },
    },
  ],
};
<CollectionProvider collection={collection}>
  <CollectionFieldProvider name={'title'}></CollectionFieldProvider>
</CollectionProvider>;
```

### CollectionField

Universal field component that needs to be used with `<CollectionProvider/>`, but only in schema scenarios. Get the field schema from CollectionProvider with the corresponding name. Extend the configuration via the schema where the CollectionField is located.

```ts
{
  name: 'title',
  'x-decorator': 'FormItem',
  'x-decorator-props': {},
  'x-component': 'CollectionField',
  'x-component-props': {},
  properties: {},
}
```

## Hooks

### useCollectionManager()

Use with `<CollectionManagerProvider/>`.

```jsx | pure
const { collections, get } = useCollectionManager();
```

### useCollection()

Use with `<CollectionProvider/>`.

```jsx | pure
const { name, fields, getField, findField, resource } = useCollection();
```

### useCollectionField()

Use with `<CollectionFieldProvider/>`.

```jsx | pure
const { name, uiSchema, resource } = useCollectionField();
```

The resource needs to be used with `<RecordProvider/>` to provide context of the record of the current data table row.

# CollectionManager

## Components

### CollectionManagerProvider

```jsx | pure
<CollectionManagerProvider
  interfaces={{}}
  collections={[]}
></CollectionManagerProvider>
```

### CollectionProvider

```jsx | pure
const collection = {
  name: 'tests',
  fields: [
    {
      type: 'string',
      name: 'title',
      interface: 'input',
      uiSchema: {
        type: 'string',
        'x-component': 'Input',
      },
    },
  ],
};
<CollectionProvider collection={collection}></CollectionProvider>;
```

If there is no collection parameter passed in, get the collection from CollectionManagerProvider with the corresponding name.

```jsx | pure
const collections = [
  {
    name: 'tests',
    fields: [
      {
        type: 'string',
        name: 'title',
        interface: 'input',
        uiSchema: {
          type: 'string',
          'x-component': 'Input',
        },
      },
    ],
  },
];
<CollectionManagerProvider collections={collections}>
  <CollectionProvider name={'tests'}></CollectionProvider>
</CollectionManagerProvider>;
```

### CollectionFieldProvider

```jsx | pure
const field = {
  type: 'string',
  name: 'title',
  interface: 'input',
  uiSchema: {
    type: 'string',
    'x-component': 'Input',
  },
};
<CollectionFieldProvider field={field}></CollectionFieldProvider>;
```

If there is no field parameter passed in, get the field from CollectionProvider with the corresponding name.

```jsx | pure
const collection = {
  name: 'tests',
  fields: [
    {
      type: 'string',
      name: 'title',
      interface: 'input',
      uiSchema: {
        type: 'string',
        'x-component': 'Input',
      },
    },
  ],
};
<CollectionProvider collection={collection}>
  <CollectionFieldProvider name={'title'}></CollectionFieldProvider>
</CollectionProvider>;
```

### CollectionField

Universal field component that needs to be used with `<CollectionProvider/>`, but only in schema scenarios. Get the field schema from CollectionProvider with the corresponding name. Extend the configuration via the schema where the CollectionField is located.

```ts
{
  name: 'title',
  'x-decorator': 'FormItem',
  'x-decorator-props': {},
  'x-component': 'CollectionField',
  'x-component-props': {},
  properties: {},
}
```

## Hooks

### useCollectionManager()

Use with `<CollectionManagerProvider/>`.

```jsx | pure
const { collections, get } = useCollectionManager();
```

### useCollection()

Use with `<CollectionProvider/>`.

```jsx | pure
const { name, fields, getField, findField, resource } = useCollection();
```

### useCollectionField()

Use with `<CollectionFieldProvider/>`.

```jsx | pure
const { name, uiSchema, resource } = useCollectionField();
```

The resource needs to be used with `<RecordProvider/>` to provide context of the record of the current data table row.

---

## File: docs/en-US/api/client/extensions/schema-component.md

# 适配的 Schema 组件

## Common

- DndContext
- SortableItem

## And Design

- Action
- BlockItem
- Calendar
- CardItem
- Cascader

---

## File: docs/en-US/api/client/schema-designer/schema-component.md

# SchemaComponent

## Core Components

### `<SchemaComponentProvider />`

### `<SchemaComponentOptions>`

### `<SchemaComponent>`

## Core Methods

### `createDesignable()`

### `useDesignable()`

### `useCompile()`

---

## File: docs/en-US/api/client/schema-designer/schema-initializer.md

# SchemaInitializer

Used for the initialization of various schemas. Newly added schema can be inserted anywhere in an existing schema node, including:

```ts
{
  properties: {
    // beforeBegin - Insert in front of the current node
    node1: {
      properties: {
        // afterBegin - Insert in front of the first child node of the current node
        // ...
        // beforeEnd - After the last child node of the current node
      },
    },
    // afterEnd - After the current node
  },
}
```

The core of SchemaInitializer includes `<SchemaInitializer.Button />` and `<SchemaInitializer.Item />` the two components. `<SchemaInitializer.Button />` is used to create the dropdown menu button of schema, and the options of the dropdown menu is `<SchemaInitializer.Item/>`.

### `<SchemaInitializerProvider />`

### `<SchemaInitializer.Button />`

### `<SchemaInitializer.Item/>`

---

## File: docs/en-US/api/client/schema-designer/schema-settings.md

# SchemaSettings

### `<SchemaSettings />`

### `<SchemaSettings.Item />`

### `<SchemaSettings.ItemGroup />`

### `<SchemaSettings.SubMenu />`

### `<SchemaSettings.Divider />`

### `<SchemaSettings.Remove />`

### `<SchemaSettings.SelectItem />`

### `<SchemaSettings.SwitchItem />`

### `<SchemaSettings.ModalItem />`

### `<SchemaSettings.ActionModalItem />`

### `<SchemaSettings.Template />`

### `<SchemaSettings.BlockTitleItem />`

---

## File: docs/en-US/api/data-source-manager/data-source.md

# DataSource (abstract)

The `DataSource` abstract class is used to represent a type of data source, which can be a database, API, etc.

## Members

### collectionManager

The CollectionManager instance of the data source, which needs to implement the [`ICollectionManager`](/api/data-source-manager/i-collection-manager) interface.

### resourceManager

The resourceManager instance of the data source, see: [`resourceManager`](/api/resourcer/resource-manager)

### acl

The ACL instance of the data source, see: [`ACL`](/api/acl/acl)

## API

### constructor()

Constructor, creates a `DataSource` instance.

#### Signature

- `constructor(options: DataSourceOptions)`

### init()

Initialization function, called immediately after `constructor`.

#### Signature

- `init(options: DataSourceOptions)`

### name

#### Signature

- `get name()`

Returns the instance name of the data source.

### middleware()

Gets the middleware of the DataSource, used to mount to the Server to receive requests.

### testConnection()

Static method, called during the test connection operation, can be used for parameter validation, specific logic is implemented by subclasses.

#### Signature

- `static testConnection(options?: any): Promise`

### load()

#### Signature

- `async load(options: any = {})`

The loading operation of the data source, logic is implemented by subclasses.

### createCollectionManager()

#### Signature
- `abstract createCollectionManager(options?: any): ICollectionManager`

Creates a CollectionManager instance for the data source, logic is implemented by subclasses.

### createResourceManager()

Creates a ResourceManager instance for the data source, subclasses can override the implementation, by default creates `ResourceManager` from `@nocobase/resourcer`.

### createACL()

- Creates an ACL instance for the DataSource, subclasses can override the implementation, by default creates `ACL` from `@nocobase/acl`.

---

## File: docs/en-US/api/data-source-manager/i-collection-manager.md

# ICollectionManager

The `ICollectionManager` interface is used to manage `Collection` instances of data sources.

## API

### registerFieldTypes()

Registers the field types in a `Collection`.

#### Signature

- `registerFieldTypes(types: Record<string, any>): void`

### registerFieldInterfaces()

Registers the `Interface` for a `Collection`.

#### Signature

- `registerFieldInterfaces(interfaces: Record<string, any>): void`

### registerCollectionTemplates()

Registers `Collection Templates`.

#### Signature

- `registerCollectionTemplates(templates: Record<string, any>): void`

### registerModels()

Registers `Models`.

#### Signature

- `registerModels(models: Record<string, any>): void`

### registerRepositories()

Registers `Repositories`.

#### Signature

- `registerRepositories(repositories: Record<string, any>): void`

### getRegisteredRepository()

Retrieves an instance of a registered repository.

#### Signature

- `getRegisteredRepository(key: string): IRepository`

### defineCollection()

Defines a `Collection`.

#### Signature

- `defineCollection(options: CollectionOptions): ICollection`

### extendCollection()

Modifies an existing `Collection` property.

#### Signature

- `extendCollection(collectionOptions: CollectionOptions, mergeOptions?: MergeOptions): ICollection`

### hasCollection()

Determines if a `Collection` exists.

#### Signature

- `hasCollection(name: string): boolean`

### getCollection()

Retrieves an instance of a `Collection`.

#### Signature

- `getCollection(name: string): ICollection`

### getCollections()

Retrieves all instances of `Collection`.

#### Signature

- `getCollections(): Array`

### getRepository()

Retrieves an instance of a `Repository`.

#### Signature

- `getRepository(name: string, sourceId?: string | number): IRepository`

### sync()

Synchronizes the data source, with the logic implemented by subclasses.

#### Signature

- `sync(): Promise<void>`

---

## File: docs/en-US/api/data-source-manager/i-collection.md

# ICollection

`ICollection` is an interface for data models, which includes information such as the model's name, fields, associations, etc.

```typescript
export interface ICollection {
  repository: IRepository;

  updateOptions(options: any): void;

  setField(name: string, options: any): IField;

  removeField(name: string): void;

  getFields(): Array<IField>;

  getField(name: string): IField;

  [key: string]: any;
}
```

## Members

### repository

The `Repository` instance to which `ICollection` belongs.

## API

### updateOptions()

Updates the properties of the `Collection`.

#### Signature

- `updateOptions(options: any): void`

### setField()

Sets a field of the `Collection`.

#### Signature

- `setField(name: string, options: any): IField`

### removeField()

Removes a field from the `Collection`.

#### Signature

- `removeField(name: string): void`

### getFields()

Retrieves all fields of the `Collection`.

#### Signature

- `getFields(): Array`

### getField()

Retrieves a field of the `Collection` by name.

#### Signature

- `getField(name: string): IField`

---

## File: docs/en-US/api/data-source-manager/i-field.md

# IField

`IField` defines the interface that fields need to implement.

```typescript
export type FieldOptions = {
  name: string;
  field: string;
  rawType: string;
  type: string;
  description?: string;
  interface?: string;
  uiSchema?: any;
  possibleTypes?: string[];
  defaultValue?: any;
  primaryKey: boolean;
  unique: boolean;
  allowNull?: boolean;
  autoIncrement?: boolean;
  [key: string]: any;
};

export interface IField {
  options: FieldOptions;
}
```


## Properties

### options

- **Type**: `FieldOptions`

---

## File: docs/en-US/api/data-source-manager/i-model.md

# IModel

The `IModel` interface defines the basic properties and methods of a model object.

```typescript
export interface IModel {
  toJSON: () => any;
}
```

## API

### toJSON()

Converts the model object to JSON format.

---

## File: docs/en-US/api/data-source-manager/i-repository.md

# IRepository

The `Repository` interface defines a series of model operation methods for adapting CRUD (Create, Read, Update, Delete) operations on data sources.

## API

### find()

Returns a list of models that match the query parameters.

#### Signature

- `find(options?: any): Promise`

### findOne()

Returns the first model that matches the query parameters. If multiple models match, only the first one is returned.

#### Signature

- `findOne(options?: any): Promise`

### count()

Returns the number of models that match the query parameters.

#### Signature

- `count(options?: any): Promise<Number>`

### findAndCount()

Returns both the list of models and the count of models that match the query parameters.

#### Signature

- `findAndCount(options?: any): Promise<[IModel[], Number]>`

### create()

Creates a model data object.

#### Signature

- `create(options: any): void`

### update()

Updates the model data object based on the query conditions.

#### Signature

- `update(options: any): void`

### destroy()

Deletes the model data object based on the query conditions.

#### Signature

- `destroy(options: any): void`

---

## File: docs/en-US/api/data-source-manager/index.md

# DataSourceManager

`DataSourceManager` is a management class for multiple `dataSource` instances.

## API

### add()
Adds a `dataSource` instance.

#### Signature

- `add(dataSource: DataSource, options: any = {}): Promise<void>`

### use()

Adds a global middleware to the `dataSource` instance.

### middleware()

Retrieves the middleware of the current `dataSourceManager` instance, which can be used to respond to HTTP requests.

### afterAddDataSource()

A hook function that is triggered after a new `dataSource` is added.

#### Signature

- `afterAddDataSource(hook: DataSourceHook)`

```typescript
type DataSourceHook = (dataSource: DataSource) => void;
```

### registerDataSourceType()

Registers the data source type and its class.

#### Signature

- `registerDataSourceType(type: string, dataSourceClass: typeof DataSource)`

### getDataSourceType()

Retrieves the data source class.

#### Signature

- `getDataSourceType(type: string): typeof DataSource`

### buildDataSourceByType()

Creates a data source instance based on the registered data source type and instance parameters.

#### Signature

- `buildDataSourceByType(type: string, options: any): DataSource`

---

## File: docs/en-US/api/database/collection.md

# Collection

## Overview

`Collection` is used to define the data model in the system, such as model name, fields, indexes, associations, and other information. It is usually called through the `collection` method of the `Database` instance as a proxy entry.

```javascript
const { Database } = require('@nocobase/database')

// Create database instance
const db = new Database({...});

// Define data model
db.collection({
  name: 'users',
  // Define model fields
  fields: [
    // Scalar field
    {
      name: 'name',
      type: 'string',
    },

    // Association field
    {
      name: 'profile',
      type: 'hasOne' // 'hasMany', 'belongsTo', 'belongsToMany'
    }
  ],
});
```

Refer to [Fields](/api/database/field) for more field types.

## Constructor

**Signature**

- `constructor(options: CollectionOptions, context: CollectionContext)`

**Parameter**

| Name                  | Type                                                        | Default | Description                                                                                                               |
| --------------------- | ----------------------------------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------- |
| `options.name`        | `string`                                                    | -       | Identifier of the collection                                                                                              |
| `options.tableName?`  | `string`                                                    | -       | Database table name, the value of `options.name` is used if not set                                                       |
| `options.fields?`     | `FieldOptions[]`                                            | -       | Definition of fields, refer to [Field](./field) for details                                                               |
| `options.model?`      | `string \| ModelStatic<Model>`                              | -       | Model type of Sequelize; in case `string` is used, this model name needs to be registered in the db before being called   |
| `options.repository?` | `string \| RepositoryType`                                  | -       | Data repository type; in case `string` is used, this repository type needs to be registered in the db before being called |
| `options.sortable?`   | `string \| boolean \| { name?: string; scopeKey?: string }` | -       | Configure which fields are sortable; not sortable by default                                                              |
| `options.autoGenId?`  | `boolean`                                                   | `true`  | Whether to automatically generate unique primary key; `true` by default                                                   |
| `context.database`    | `Database`                                                  | -       | The context database in which it resides                                                                                  |

**Example**

Create a table *posts*:

```ts
const posts = new Collection(
  {
    name: 'posts',
    fields: [
      {
        type: 'string',
        name: 'title',
      },
      {
        type: 'double',
        name: 'price',
      },
    ],
  },
  {
    // An existing database instance
    database: db,
  },
);
```

## Instance Members

### `options`

Initial parameters for data table configuration, which are consistent with the `options` parameter of the constructor.

### `context`

The contextual environment to which the current data table belongs, currently mainly the database instance.

### `name`

Name of the data table.

### `db`

The database instance to which it belongs.

### `filterTargetKey`

Name of the field that is used as the primary key.

### `isThrough`

Whether it is an intermediate table.

### `model`

Match the Model type of Sequelize.

### `repository`

Data repository instance.

## Field Configuration Methods

### `getField()`

Get a field object whose corresponding name has been defined in the data table.

**Signature**

- `getField(name: string): Field`

**Parameter**

| Name   | Type     | Default | Description       |
| ------ | -------- | ------- | ----------------- |
| `name` | `string` | -       | Name of the field |

**Example**

```ts
const posts = db.collection({
  name: 'posts',
  fields: [
    {
      type: 'string',
      name: 'title',
    },
  ],
});

const field = posts.getField('title');
```

### `setField()`

Set a field to the data table.

**Signature**

- `setField(name: string, options: FieldOptions): Field`

**Parameter**

| Name      | Type           | Default | Description                                                       |
| --------- | -------------- | ------- | ----------------------------------------------------------------- |
| `name`    | `string`       | -       | Name of the field                                                 |
| `options` | `FieldOptions` | -       | Configuration of the field, refer to [Field](./field) for details |

**Example**

```ts
const posts = db.collection({ name: 'posts' });

posts.setField('title', { type: 'string' });
```

### `setFields()`

Set multiple fields to the data table.

**Signature**

- `setFields(fields: FieldOptions[], resetFields = true): Field[]`

**Parameter**

| Name          | Type             | Default | Description                                                        |
| ------------- | ---------------- | ------- | ------------------------------------------------------------------ |
| `fields`      | `FieldOptions[]` | -       | Configuration of the fields, refer to [Field](./field) for details |
| `resetFields` | `boolean`        | `true`  | Whether to reset existing fields                                   |

**Example**

```ts
const posts = db.collection({ name: 'posts' });

posts.setFields([
  { type: 'string', name: 'title' },
  { type: 'double', name: 'price' },
]);
```

### `removeField()`

Remove a field object whose corresponding name has been defined in the data table.

**Signature**

- `removeField(name: string): void | Field`

**Parameter**

| Name   | Type     | Default | Description       |
| ------ | -------- | ------- | ----------------- |
| `name` | `string` | -       | Name of the field |

**Example**

```ts
const posts = db.collection({
  name: 'posts',
  fields: [
    {
      type: 'string',
      name: 'title',
    },
  ],
});

posts.removeField('title');
```

### `resetFields()`

Reset (Empty) fields of the data table.

**Signature**

- `resetFields(): void`

**Example**

```ts
const posts = db.collection({
  name: 'posts',
  fields: [
    {
      type: 'string',
      name: 'title',
    },
  ],
});

posts.resetFields();
```

### `hasField()`

Check if the data table has defined a field object with the corresponding name.

**Signature**

- `hasField(name: string): boolean`

**Parameter**

| Name   | Type     | Default | Description       |
| ------ | -------- | ------- | ----------------- |
| `name` | `string` | -       | Name of the field |

**Example**

```ts
const posts = db.collection({
  name: 'posts',
  fields: [
    {
      type: 'string',
      name: 'title',
    },
  ],
});

posts.hasField('title'); // true
```

### `findField()`

Find field objects in the data table that match the conditions.

**Signature**

- `findField(predicate: (field: Field) => boolean): Field | undefined`

**Parameter**

| Name        | Type                        | Default | Description   |
| ----------- | --------------------------- | ------- | ------------- |
| `predicate` | `(field: Field) => boolean` | -       | The condition |

**Example**

```ts
const posts = db.collection({
  name: 'posts',
  fields: [
    {
      type: 'string',
      name: 'title',
    },
  ],
});

posts.findField((field) => field.name === 'title');
```

### `forEachField()`

Iterate over field objects in the data table.

**Signature**

- `forEachField(callback: (field: Field) => void): void`

**Parameter**

| Name       | Type                     | Default | Description       |
| ---------- | ------------------------ | ------- | ----------------- |
| `callback` | `(field: Field) => void` | -       | Callback function |

**Example**

```ts
const posts = db.collection({
  name: 'posts',
  fields: [
    {
      type: 'string',
      name: 'title',
    },
  ],
});

posts.forEachField((field) => console.log(field.name));
```

## Index Configuration Methods

### `addIndex()`

Add data table index.

**Signature**

- `addIndex(index: string | string[] | { fields: string[], unique?: boolean,[key: string]: any })`

**Parameter**

| Name    | Type                                                         | Default | Description                   |
| ------- | ------------------------------------------------------------ | ------- | ----------------------------- |
| `index` | `string \| string[]`                                         | -       | Names of fields to be indexed |
| `index` | `{ fields: string[], unique?: boolean, [key: string]: any }` | -       | Full configuration            |

**Example**

```ts
const posts = db.collection({
  name: 'posts',
  fields: [
    {
      type: 'string',
      name: 'title',
    },
  ],
});

posts.addIndex({
  fields: ['title'],
  unique: true,
});
```

### `removeIndex()`

Remove data table index.

**Signature**

- `removeIndex(fields: string[])`

**Parameter**

| Name     | Type       | Default | Description                       |
| -------- | ---------- | ------- | --------------------------------- |
| `fields` | `string[]` | -       | Names of fields to remove indexes |

**Example**

```ts
const posts = db.collection({
  name: 'posts',
  fields: [
    {
      type: 'string',
      name: 'title',
    },
  ],
  indexes: [
    {
      fields: ['title'],
      unique: true,
    },
  ],
});

posts.removeIndex(['title']);
```

## Table Configuration Methods

### `remove()`

Remove data table.

**Signature**

- `remove(): void`

**Example**

```ts
const posts = db.collection({
  name: 'posts',
  fields: [
    {
      type: 'string',
      name: 'title',
    },
  ],
});

posts.remove();
```

## Database Operation Methods

### `sync()`

Synchronize the definitions in data table to the database. In addition to the default `Model.sync` logic in Sequelize, the data tables corresponding to the relational fields will also be handled together.

**Signature**

- `sync(): Promise<void>`

**Example**

```ts
const posts = db.collection({
  name: 'posts',
  fields: [
    {
      type: 'string',
      name: 'title',
    },
  ],
});

await posts.sync();
```

### `existsInDb()`

Check whether the data table exists in the database.

**Signature**

- `existsInDb(options?: Transactionable): Promise`

**Parameter**

| Name                   | Type          | Default | Description          |
| ---------------------- | ------------- | ------- | -------------------- |
| `options?.transaction` | `Transaction` | -       | Transaction instance |

**Example**

```ts
const posts = db.collection({
  name: 'posts',
  fields: [
    {
      type: 'string',
      name: 'title',
    },
  ],
});

const existed = await posts.existsInDb();

console.log(existed); // false
```

### `removeFromDb()`

**Signature**

- `removeFromDb(): Promise<void>`

**Example**

```ts
const books = db.collection({
  name: 'books',
});

//  Synchronize the table books to the database
await db.sync();

// Remove the table books from the database
await books.removeFromDb();
```

---

## File: docs/en-US/api/database/field.md

# Field

## Overview

Data table field management class (abstract class). It is also the base class for all field types, and any other field types are implemented by inheriting from this class.

Refer to [Extended Field Types](/development/server/collections-fields#extended-field-types) to see how to customize fields.

## Constructor

It is usually not called directly by the developer, but mainly through the `db.collection({ fields: [] })` method as a proxy entry.

Extended field is implemented mainly by inheriting the `Field` abstract class and registering it to a Database instance.

**Signature**

- `constructor(options: FieldOptions, context: FieldContext)`

**Parameter**

| Name                 | Type           | Default | Description                                                                  |
| -------------------- | -------------- | ------- | ---------------------------------------------------------------------------- |
| `options`            | `FieldOptions` | -       | Field configuration object                                                   |
| `options.name`       | `string`       | -       | Field name                                                                   |
| `options.type`       | `string`       | -       | Field type, corresponding to the name of the field type registered in the db |
| `context`            | `FieldContext` | -       | Field context object                                                         |
| `context.database`   | `Database`     | -       | Database instance                                                            |
| `context.collection` | `Collection`   | -       | Data table instance                                                          |

## Instance Members

### `name`

Field name.

### `type`

Field type.

### `dataType`

Data type of the field.

### `options`

Configuration parameters to initialize the field.

### `context`

Field context object.

## Configuration Methods

### `on()`

Quick definition method based on data table events. It is equivalent to `db.on(this.collection.name + '.' + eventName, listener)`.

It is usually not necessary to override this method when inheriting.

**Signature**

- `on(eventName: string, listener: (...args: any[]) => void)`

**Parameter**

| Name        | Type                       | Default | Description    |
| ----------- | -------------------------- | ------- | -------------- |
| `eventName` | `string`                   | -       | Event name     |
| `listener`  | `(...args: any[]) => void` | -       | Event listener |

### `off()`

Quick removal method based on data table events. It is equivalent to `db.off(this.collection.name + '.' + eventName, listener)`.

It is usually not necessary to override this method when inheriting.

**Signature**

- `off(eventName: string, listener: (...args: any[]) => void)`

**Parameter**

| Name        | Type                       | Default | Description    |
| ----------- | -------------------------- | ------- | -------------- |
| `eventName` | `string`                   | -       | Event name     |
| `listener`  | `(...args: any[]) => void` | -       | Event listener |

### `bind()`

The execution content that is triggered when a field is added to data table. Typically used to add data table event listeners and other processing.

The corresponding `super.bind()` method needs to be called first when inheriting.

**Signature**

- `bind()`

### `unbind()`

The execution content that is triggered when a field is removed from data table. Typically used to remove data table event listeners and other processing.

The corresponding `super.unbind()` method needs to be called first when inheriting.

**Signature**

- `unbind()`

### `get()`

Get the values of a configuration item of the field.

**Signature**

- `get(key: string): any`

**Parameter**

| Name  | Type     | Default | Description                    |
| ----- | -------- | ------- | ------------------------------ |
| `key` | `string` | -       | Name of the configuration item |

**Example**

```ts
const field = db.collection('users').getField('name');

// Get and return the values of the configuration item 'name'
console.log(field.get('name'));
```

### `merge()`

Merge the values of a configuration item of the field.

**Signature**

- `merge(options: { [key: string]: any }): void`

**Parameter**

| Name      | Type                     | Default | Description                     |
| --------- | ------------------------ | ------- | ------------------------------- |
| `options` | `{ [key: string]: any }` | -       | The configuration item to merge |

**Example**

```ts
const field = db.collection('users').getField('name');

field.merge({
  // Add an index configuration
  index: true,
});
```

### `remove()`

Remove a field from data table (from memory only).

**Example**

```ts
const books = db.getCollections('books');

books.getField('isbn').remove();

// really remove from db
await books.sync();
```

## Database Methods

### `removeFromDb()`

Remove a field from the database.

**Signature**

- `removeFromDb(options?: Transactionable): Promise<void>`

**Parameter**

| Name                   | Type          | Default | Description          |
| ---------------------- | ------------- | ------- | -------------------- |
| `options.transaction?` | `Transaction` | -       | Transaction instance |

### `existsInDb()`

Check if a field exists in the database.

**Signature**

- `existsInDb(options?: Transactionable): Promise`

**Parameter**

| Name                   | Type          | Default | Description          |
| ---------------------- | ------------- | ------- | -------------------- |
| `options.transaction?` | `Transaction` | -       | Transaction instance |

## Built-in Field Types

NocoBase has some built-in common field types, the corresponding type name can be used directly to specify the type of field upon definition. Fields of different types are configured differently, please refer to the list below.

The configuration items of all field types are passed through to Sequelize in addition to those described below. Therefore, all field configuration items supported by Sequelize can be used here (e.g. `allowNull`, `defaultValue`, etc.).

Moreover, server-side field types are mainly used for solving the problems of database storage and some algorithms, they are barely relevant to the field display types and the use of components in front-end. The front-end field types can be found in the corresponding tutorials.

### `'boolean'`

Boolean type.

**Example**

```js
db.collection({
  name: 'books',
  fields: [
    {
      type: 'boolean',
      name: 'published',
    },
  ],
});
```

### `'integer'`

Integer type (32 bits).

**Example**

```ts
db.collection({
  name: 'books',
  fields: [
    {
      type: 'integer',
      name: 'pages',
    },
  ],
});
```

### `'bigInt'`

Long integer type (64 bits).

**Example**

```ts
db.collection({
  name: 'books',
  fields: [
    {
      type: 'bigInt',
      name: 'words',
    },
  ],
});
```

### `'double'`

Double-precision floating-point format (64 bits).

**Example**

```ts
db.collection({
  name: 'books',
  fields: [
    {
      type: 'double',
      name: 'price',
    },
  ],
});
```

### `'real'`

Real type (PG only).

### `'decimal'`

Decimal type.

### `'string'`

String type. Equivalent to the `VARCHAR` type for most databases.

**Example**

```ts
db.collection({
  name: 'books',
  fields: [
    {
      type: 'string',
      name: 'title',
    },
  ],
});
```

### `'text'`

Text type. Equivalent to the `TEXT` type for most databases.

**Example**

```ts
db.collection({
  name: 'books',
  fields: [
    {
      type: 'text',
      name: 'content',
    },
  ],
});
```

### `'password'`

Password type (NocoBase extension). Password encryption based on the `scrypt` method of Node.js native crypto packages.

**Example**

```ts
db.collection({
  name: 'users',
  fields: [
    {
      type: 'password',
      name: 'password',
      length: 64, // Length, default is 64
      randomBytesSize: 8, // Length of random bytes, default is 8
    },
  ],
});
```

**Parameter**

| Name              | Type     | Default | Description            |
| ----------------- | -------- | ------- | ---------------------- |
| `length`          | `number` | 64      | Length of characters   |
| `randomBytesSize` | `number` | 8       | Length of random bytes |

### `'date'`

Date type.

### `'time'`

Time type.

### `'array'`

Array type (PG only).

### `'json'`

JSON type.

### `'jsonb'`

JSONB type (PG only, others will be compatible with the `'json'` type).

### `'uuid'`

UUID type.

### `'uid'`

UID type (NocoBase extension). Short random string identifier type.

### `'formula'`

Formula type (NocoBase extension). Mathematical formula calculation can be configured based on [mathjs](https://www.npmjs.com/package/mathjs), and the formula can refer to the values of other columns in the same record to participate in the calculation.

**Example**

```ts
db.collection({
  name: 'orders',
  fields: [
    {
      type: 'double',
      name: 'price',
    },
    {
      type: 'integer',
      name: 'quantity',
    },
    {
      type: 'formula',
      name: 'total',
      expression: 'price * quantity',
    },
  ],
});
```

### `'radio'`

Radio type (NocoBase extension). The field value is 'true' for at most one row of data for the full table, all others are 'false' or 'null'.

**Example**

There is only one user marked as *root* in the entire system, once the *root* value of any other user is changed to `true`, all other records with *root* of `true` will be changed to `false`:

```ts
db.collection({
  name: 'users',
  fields: [
    {
      type: 'radio',
      name: 'root',
    },
  ],
});
```

### `'sort'`

Sorting type (NocoBase extension). Sorting based on integer numbers, automatically generating new serial numbers for new records, and rearranging serial numbers when moving data.

If data table has the `sortable` option defined, the corresponding fields will be generated automatically.

**Example**

Posts are sortable based on the users they belong to.

```ts
db.collection({
  name: 'posts',
  fields: [
    {
      type: 'belongsTo',
      name: 'user',
    },
    {
      type: 'sort',
      name: 'priority',
      scopeKey: 'userId', // Sort data grouped by the values of userId
    },
  ],
});
```

### `'virtual'`

Virtual type. No Data is actually stored, it is used only when special getter/setter is defined.

### `'belongsTo'`

Many-to-one association type. Foreign key is stored in its own table, as opposed to `'hasOne'`/`'hasMany'`.

**Example**

Any post belongs to an author:

```ts
db.collection({
  name: 'posts',
  fields: [
    {
      type: 'belongsTo',
      name: 'author',
      target: 'users', // Default table name is the plural form of <name>
      foreignKey: 'authorId', // Default is '<name> + Id'
      sourceKey: 'id', // Default is id of the <target> table
    },
  ],
});
```

### `'hasOne'`

One-to-one association type. Foreign key is stored in the association table, as opposed to `'belongsTo'`.

**Example**

Any user has a profile:

```ts
db.collection({
  name: 'users',
  fields: [
    {
      type: 'hasOne',
      name: 'profile',
      target: 'profiles', // Can be omitted
    },
  ],
});
```

### `'hasMany'`

One-to-many association type. The foreign key is stored in the association table, as opposed to `'belongsTo'`.

**Example**

Any user can have multiple posts:

```ts
db.collection({
  name: 'users',
  fields: [
    {
      type: 'hasMany',
      name: 'posts',
      foreignKey: 'authorId',
      sourceKey: 'id',
    },
  ],
});
```

### `'belongsToMany'`

Many-to-many association type. Intermediate table is used to store both foreign keys. If no existing table is specified as intermediate table, it will be created automatically.

**Example**

Any post can have multiple tags added to it, and any tag can be added to multiple posts:

```ts
db.collection({
  name: 'posts',
  fields: [
    {
      type: 'belongsToMany',
      name: 'tags',
      target: 'tags', // Can be omitted if name is the same
      through: 'postsTags', // Intermediate table will be generated automatically if not specified
      foreignKey: 'postId', // Foreign key in the intermediate table referring to the table itself
      sourceKey: 'id', // Primary key of the table itself
      otherKey: 'tagId', // Foreign key in the intermediate table referring to the association table
    },
  ],
});

db.collection({
  name: 'tags',
  fields: [
    {
      type: 'belongsToMany',
      name: 'posts',
      through: 'postsTags', // Refer to the same intermediate table in the same set of relation
    },
  ],
});
```

---

## File: docs/en-US/api/database/index.md

# Database

## Overview

Database is the database interaction tool provided by NocoBase, it provides very convenient database interaction features for no-code and low-code applications. The supported databases are:

- SQLite 3.8.8+
- MySQL 8.0.17+
- PostgreSQL 10.0+

### Connect to Database

In `Database` constructor, database connection can be configured by passing the `options` parameter.

```javascript
const { Database } = require('@nocobase/database');

// MySQL database configuration parameters
const database = new Database({
  dialect: 'mysql',
  host: 'localhost',
  port: 3306,
  database: 'nocobase',
  username: 'root',
  password: 'password'
})

// MySQL \ PostgreSQL database configuration parameters
const database = new Database({
  dialect: /* 'postgres' or 'mysql' */,
  database: 'database',
  username: 'username',
  password: 'password',
  host: 'localhost',
  port: 'port'
})

```

Refer to [Constructor](#constructor) for detailed configurations.

### Define Data Structure

`Database` defines database structure through `Collection`, one `Collection` object represents one table in the database.

```javascript
// Define Collection
const UserCollection = database.collection({
  name: 'users',
  fields: [
    {
      name: 'name',
      type: 'string',
    },
    {
      name: 'age',
      type: 'integer',
    },
  ],
});
```

After the database structure is defined, use `sync()` method to synchronize the database structure.

```javascript
await database.sync();
```

Refer to [Collection](/api/database/collection) for detailed usage of `Collection`.

### CRUD Data

`Database` operates data through `Repository`.

```javascript
const UserRepository = UserCollection.repository();

// Create
await UserRepository.create({
  name: 'Mark',
  age: 18,
});

// Query
const user = await UserRepository.findOne({
  filter: {
    name: 'Mark',
  },
});

// Update
await UserRepository.update({
  values: {
    age: 20,
  },
});

// Delete
await UserRepository.destroy(user.id);
```

Refer to [Repository](/api/database/repository) for details of data CRUD.

## Constructor

**Signature**

- `constructor(options: DatabaseOptions)`

Create a database instance.

**Parameter**

| Name                   | Type           | Default       | Description                                                                                                                                         |
| ---------------------- | -------------- | ------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| `options.host`         | `string`       | `'localhost'` | Database host                                                                                                                                       |
| `options.port`         | `number`       | -             | Database service port, default port depends on the type of database used                                                                            |
| `options.username`     | `string`       | -             | Database username                                                                                                                                   |
| `options.password`     | `string`       | -             | Database password                                                                                                                                   |
| `options.database`     | `string`       | -             | Database name                                                                                                                                       |
| `options.dialect`      | `string`       | `'mysql'`     | Database type                                                                                                                                       |
| `options.storage?`     | `string`       | `':memory:'`  | Storage mode for SQLite                                                                                                                             |
| `options.logging?`     | `boolean`      | `false`       | Whether to enable logging                                                                                                                           |
| `options.define?`      | `Object`       | `{}`          | Default table definition parameters                                                                                                                 |
| `options.tablePrefix?` | `string`       | `''`          | NocoBase extension, table prefix                                                                                                                    |
| `options.migrator?`    | `UmzugOptions` | `{}`          | NocoBase extension, parameters for migrator, refer to [Umzug](https://github.com/sequelize/umzug/blob/main/src/types.ts#L15) for the implementation |

## Migration Methods

### `addMigration()`

Add single migration file.

**Signature**

- `addMigration(options: MigrationItem)`

**Parameter**

| Name                 | Type               | Default | Description                         |
| -------------------- | ------------------ | ------- | ----------------------------------- |
| `options.name`       | `string`           | -       | Name of the migration file          |
| `options.context?`   | `string`           | -       | Context of the migration file       |
| `options.migration?` | `typeof Migration` | -       | Custom type of the migration file   |
| `options.up`         | `Function`         | -       | `up` method of the migration file   |
| `options.down`       | `Function`         | -       | `down` method of the migration file |

**Example**

```ts
db.addMigration({
  name: '20220916120411-test-1',
  async up() {
    const queryInterface = this.context.db.sequelize.getQueryInterface();
    await queryInterface.query(/* your migration sqls */);
  },
});
```

### `addMigrations()`

Add the migration files in the specified directory.

**Signature**

- `addMigrations(options: AddMigrationsOptions): void`

**Parameter**

| Name                 | Type       | Default        | Description                                     |
| -------------------- | ---------- | -------------- | ----------------------------------------------- |
| `options.directory`  | `string`   | `''`           | Directory where the migration files are located |
| `options.extensions` | `string[]` | `['js', 'ts']` | File extensions                                 |
| `options.namespace?` | `string`   | `''`           | Namespace                                       |
| `options.context?`   | `Object`   | `{ db }`       | Context of the migration files                  |

**Example**

```ts
db.addMigrations({
  directory: path.resolve(__dirname, './migrations'),
  namespace: 'test',
});
```

## Tool Methods

### `inDialect()`

Check whether the current database type is the specified type.

**Signature**

- `inDialect(dialect: string[]): boolean`

**Parameter**

| Name      | Type       | Default | Description                                                 |
| --------- | ---------- | ------- | ----------------------------------------------------------- |
| `dialect` | `string[]` | -       | Database type, options are `mysql`, `postgres` and `mariadb` |

### `getTablePrefix()`

Get the table name prefix in the configuration.

**Signature**

- `getTablePrefix(): string`

## Data Table Configurations

### `collection()`

Define a data table. This is like the `define` method of Sequelize, which only creates table structure in memory. Call the `sync` method if needs to be persisted to the database.

**Signature**

- `collection(options: CollectionOptions): Collection`

**Parameter**

All configuration parameters of `options` is consistent with the constructor of the `Collection` class, refer to [Collection](/api/database/collection#Constructor).

**Event**

- `'beforeDefineCollection'`: Trigger before defining the table.
- `'afterDefineCollection'`: Trigger after defining the table.

**Example**

```ts
db.collection({
  name: 'books',
  fields: [
    {
      type: 'string',
      name: 'title',
    },
    {
      type: 'float',
      name: 'price',
    },
  ],
});

// sync collection as table to db
await db.sync();
```

### `getCollection()`

Get a defined data table.

**Signature**

- `getCollection(name: string): Collection`

**Parameter**

| Name   | Type     | Default | Description |
| ------ | -------- | ------- | ----------- |
| `name` | `string` | -       | Table name  |

**Example**

```ts
const collection = db.getCollection('books');
```

### `hasCollection()`

Check whether a specified data table is defined.

**Signature**

- `hasCollection(name: string): boolean`

**Parameter**

| Name   | Type     | Default | Description |
| ------ | -------- | ------- | ----------- |
| `name` | `string` | -       | Table name  |

**Example**

```ts
db.collection({ name: 'books' });

db.hasCollection('books'); // true

db.hasCollection('authors'); // false
```

### `removeCollection()`

Remove a defined data table. It is to remove from memory only, call the `sync` method if needs to be persisted to the database.

**Signature**

- `removeCollection(name: string): void`

**Parameter**

| Name   | Type     | Default | Description |
| ------ | -------- | ------- | ----------- |
| `name` | `string` | -       | Table name  |

**Event**

- `'beforeRemoveCollection'`: Trigger before removing the table.
- `'afterRemoveCollection'`: Trigger after removing the table

**Example**

```ts
db.collection({ name: 'books' });

db.removeCollection('books');
```

### `import()`

Load all files in the import file directory into memory as the configuration of collection.

**Signature**

- `async import(options: { directory: string; extensions?: ImportFileExtension[] }): Promise<Map<string, Collection>>`

**Parameter**

| Name                 | Type       | Default        | Description                      |
| -------------------- | ---------- | -------------- | -------------------------------- |
| `options.directory`  | `string`   | -              | Path of directory to be imported |
| `options.extensions` | `string[]` | `['ts', 'js']` | Scan for specific suffixes       |

**Example**

The collection defined by file `./collections/books.ts` is as below:

```ts
export default {
  name: 'books',
  fields: [
    {
      type: 'string',
      name: 'title',
    },
  ],
};
```

Import the relevant configurations when loading the plugin:

```ts
class Plugin {
  async load() {
    await this.app.db.import({
      directory: path.resolve(__dirname, './collections'),
    });
  }
}
```

## Extension Registrations and Acquisitions

### `registerFieldTypes()`

Register custom field type.

**Signature**

- `registerFieldTypes(fieldTypes: MapOf<typeof Field>): void`

**Parameter**

`fieldTypes` is a key-value pair, where key is the field type name, and value is the field type class.

**Example**

```ts
import { Field } from '@nocobase/database';

class MyField extends Field {
  // ...
}

db.registerFieldTypes({
  myField: MyField,
});
```

### `registerModels()`

Register custom data model class.

**Signature**

- `registerModels(models: MapOf<ModelStatic<any>>): void`

**Parameter**

`models` is a key-value pair, where key is the data model name, and value is the data model class.

**Example**

```ts
import { Model } from '@nocobase/database';

class MyModel extends Model {
  // ...
}

db.registerModels({
  myModel: MyModel,
});

db.collection({
  name: 'myCollection',
  model: 'myModel',
});
```

### `registerRepositories()`

Register custom data repository class.

**Signature**

- `registerRepositories(repositories: MapOf<RepositoryType>): void`

**Parameter**

`repositories` is a key-value pair, where key is the data repository name, and value is the data repository class.

**Example**

```ts
import { Repository } from '@nocobase/database';

class MyRepository extends Repository {
  // ...
}

db.registerRepositories({
  myRepository: MyRepository,
});

db.collection({
  name: 'myCollection',
  repository: 'myRepository',
});
```

### `registerOperators()`

Register custom data query operator.

**Signature**

- `registerOperators(operators: MapOf<OperatorFunc>)`

**Parameter**

`operators` is a key-value pair, where key is the operator name, and value is the generating function of the comparison operator statement.

**Example**

```ts
db.registerOperators({
  $dateOn(value) {
    return {
      [Op.and]: [
        { [Op.gte]: stringToDate(value) },
        { [Op.lt]: getNextDay(value) },
      ],
    };
  },
});

db.getRepository('books').count({
  filter: {
    createdAt: {
      // registered operator
      $dateOn: '2020-01-01',
    },
  },
});
```

### `getModel()`

Get the defined data model class. If no custom model class has been registered before, the default model class of Sequelize will be returned. The default name is the same as the name defined by collection.

**Signature**

- `getModel(name: string): Model`

**Parameter**

| Name   | Type     | Default | Description           |
| ------ | -------- | ------- | --------------------- |
| `name` | `string` | -       | Registered model name |

**Example**

```ts
db.registerModels({
  books: class MyModel extends Model {},
});

const ModelClass = db.getModel('books');

console.log(ModelClass.prototype instanceof MyModel); // true
```

Note: The model class retrieved from collection is not strictly equivalent to the model class at registration, but is inherited from the model class at registration. Since the properties of Sequelize's model class are modified during initialization, NocoBase automatically handles this inheritance relationship. All the definitions work fine except that the classes are not equal.

### `getRepository()`

Get the defined data repository class. If no custom data repository class has been registered before, the default data repository class of NocoBase will be returned. The default name is the same as the name defined by collection.

Data repository class is mainly used for the CRUD operations based on data model, refer to [Repository](/api/database/repository).

**Signature**

- `getRepository(name: string): Repository`
- `getRepository(name: string, relationId?: string | number): Repository`

**Parameter**

| Name         | Type                 | Default | Description                           |
| ------------ | -------------------- | ------- | ------------------------------------- |
| `name`       | `string`             | -       | Registered data repository name       |
| `relationId` | `string` \| `number` | -       | Foreign key value for relational data |

When the name contains relationship in the form of `'tables.relactions'`, the related data repository class is returned. If the second parameter is provided, the data repository will be used (query, modify, etc.) based on the foreign key values of the relational data.

**Example**

Suppose there are two data tables *posts* and *authors*, and there is a foreign key in the *posts* table points to the *authors* table:

```ts
const AuthorsRepo = db.getRepository('authors');
const author1 = AuthorsRepo.create({ name: 'author1' });

const PostsRepo = db.getRepository('authors.posts', author1.id);
const post1 = AuthorsRepo.create({ title: 'post1' });
asset(post1.authorId === author1.id); // true
```

## Database Events

### `on()`

Listen for database events.

**Signature**

- `on(event: string, listener: (...args: any[]) => void | Promise<void>): void`

**Parameter**

| Name     | Type     | Default | Description    |
| -------- | -------- | ------- | -------------- |
| event    | string   | -       | Event name     |
| listener | Function | -       | Event listener |

Event name supports Model event of Sequelize by default. Global event is listened to by the name `<sequelize_model_global_event>`, single Model event is listened to by the name `<model_name>. <sequelize_model_event>`.

Refer to the [Built-in Events](#built-in-events) section for parameter descriptions and detailed examples of all built-in event types.

### `off()`

Remove the event listener function.

**Signature**

- `off(name: string, listener: Function)`

**Parameter**

| Name     | Type     | Default | Description    |
| -------- | -------- | ------- | -------------- |
| name     | string   | -       | Event name     |
| listener | Function | -       | Event listener |

**Example**

```ts
const listener = async (model, options) => {
  console.log(model);
};

db.on('afterCreate', listener);

db.off('afterCreate', listener);
```

## Database Operations

### `auth()`

Database connection verification. It can be used to ensure that the application has established connection to the data.

**Signature**

- `auth(options: QueryOptions & { retry?: number } = {}): Promise`

**Parameter**

| Name                   | Type                  | Default | Description                                       |
| ---------------------- | --------------------- | ------- | ------------------------------------------------- |
| `options?`             | `Object`              | -       | Verification option                               |
| `options.retry?`       | `number`              | `10`    | Number of retries in case of verification failure |
| `options.transaction?` | `Transaction`         | -       | Transaction object                                |
| `options.logging?`     | `boolean \| Function` | `false` | Whether to print the log                          |

**Example**

```ts
await db.auth();
```

### `reconnect()`

Reconnect to the database.

**Example**

```ts
await db.reconnect();
```

### `closed()`

Check whether database has closed the connection.

**Signature**

- `closed(): boolean`

### `close()`

Closes database connection. Equivalent to `sequelize.close()`.

### `sync()`

Synchronizes database table structure. Equivalent to `sequelize.sync()`, refer to [Sequelize documentation](https://sequelize.org/api/v6/class/src/sequelize.js~sequelize#instance-method-sync) for parameters.

### `clean()`

Empty the database, it will delete all data tables.

**Signature**

- `clean(options: CleanOptions): Promise<void>`

**Parameter**

| Name                  | Type          | Default | Description                       |
| --------------------- | ------------- | ------- | --------------------------------- |
| `options.drop`        | `boolean`     | `false` | Whether to remove all data tables |
| `options.skip`        | `string[]`    | -       | Names of tables to skip           |
| `options.transaction` | `Transaction` | -       | Transaction object                |

**Example**

Remove all tables except for the `users` table.

```ts
await db.clean({
  drop: true,
  skip: ['users'],
});
```

## Package-Level Export

### `defineCollection()`

Create the configuration content of a data table.

**Signature**

- `defineCollection(name: string, config: CollectionOptions): CollectionOptions`

**Parameter**

| Name                | Type                | Default | Description                                        |
| ------------------- | ------------------- | ------- | -------------------------------------------------- |
| `collectionOptions` | `CollectionOptions` | -       | All parameters are the same with `db.collection()` |

**Example**

For the data table configuration file to be imported by `db.import()`:

```ts
import { defineCollection } from '@nocobase/database';

export default defineCollection({
  name: 'users',
  fields: [
    {
      type: 'string',
      name: 'name',
    },
  ],
});
```

### `extendCollection()`

Extent the configuration content of a data table that is already in memory, mainly for the content of files imported by the `import()` method. This is the top-level package export method of `@nocobase/database`, and is not called through db instance. The `extend` alias can also be used.

**Signature**

- `extendCollection(collectionOptions: CollectionOptions, mergeOptions?: MergeOptions): ExtendedCollectionOptions`

**Parameter**

| Name                | Type                | Default | Description                                                             |
| ------------------- | ------------------- | ------- | ----------------------------------------------------------------------- |
| `collectionOptions` | `CollectionOptions` | -       | All the same with `db.collection()`                                     |
| `mergeOptions?`     | `MergeOptions`      | -       | [deepmerge](https://npmjs.com/package/deepmerge) options of npm package |

**Example**

Original definition of the table *books* (books.ts):

```ts
export default {
  name: 'books',
  fields: [{ name: 'title', type: 'string' }],
};
```

Extend the definition of the table *books* (books.extend.ts):

```ts
import { extend } from '@nocobase/database';

// Extend again
export default extend({
  name: 'books',
  fields: [{ name: 'price', type: 'number' }],
});
```

If the above two files are imported when calling `import()`, after being extended again by `extend()`, the table *books* will have `title` and `price` two fields.

This method is especially useful when extending the table structure that is already defined by existing plugin.

## Built-in Events

The following events will be triggered in the corresponding lifecycle of database, subscribe by the `on()` method and perform specific processing to meet some business needs.

### `'beforeSync'` / `'afterSync'`

Events triggered before or after a new table structure configuration (fields, indexes, etc.) is synchronized to the database. This is usually triggered when executing `collection.sync()` (internal call) for the logical processing of the extension of some special fields.

**Signature**

```ts
on(eventName: `${string}.beforeSync` | 'beforeSync' | `${string}.afterSync` | 'afterSync', listener: SyncListener): this
```

**Type**

```ts
import type { SyncOptions, HookReturn } from 'sequelize/types';

type SyncListener = (options?: SyncOptions) => HookReturn;
```

**Example**

```ts
const users = db.collection({
  name: 'users',
  fields: [{ type: 'string', name: 'username' }],
});

db.on('beforeSync', async (options) => {
  // do something
});

db.on('users.afterSync', async (options) => {
  // do something
});

await users.sync();
```

### `'beforeValidate'` / `'afterValidate'`

Before creating or updating data, there is a validation against the data based on the rules defined by the collection, and the corresponding events are triggered before and after the validation. This is triggered when `repository.create()` or `repository.update()` is called.

**Signature**

```ts
on(eventName: `${string}.beforeValidate` | 'beforeValidate' | `${string}.afterValidate` | 'afterValidate', listener: ValidateListener): this
```

**Type**

```ts
import type { ValidationOptions } from 'sequelize/types/lib/instance-validator';
import type { HookReturn } from 'sequelize/types';
import type { Model } from '@nocobase/database';

type ValidateListener = (
  model: Model,
  options?: ValidationOptions,
) => HookReturn;
```

**Example**

```ts
db.collection({
  name: 'tests',
  fields: [
    {
      type: 'string',
      name: 'email',
      validate: {
        isEmail: true,
      },
    },
  ],
});

// all models
db.on('beforeValidate', async (model, options) => {
  // do something
});
// tests model
db.on('tests.beforeValidate', async (model, options) => {
  // do something
});

// all models
db.on('afterValidate', async (model, options) => {
  // do something
});
// tests model
db.on('tests.afterValidate', async (model, options) => {
  // do something
});

const repository = db.getRepository('tests');
await repository.create({
  values: {
    email: 'abc', // checks for email format
  },
});
// or
await repository.update({
  filterByTk: 1,
  values: {
    email: 'abc', // checks for email format
  },
});
```

### `'beforeCreate'` / `'afterCreate'`

Events triggered before or after creating one piece of data. This is triggered when `repository.create()` is called.

**Signature**

```ts
on(eventName: `${string}.beforeCreate` | 'beforeCreate' | `${string}.afterCreate` | 'afterCreate', listener: CreateListener): this
```

**Type**

```ts
import type { CreateOptions, HookReturn } from 'sequelize/types';
import type { Model } from '@nocobase/database';

export type CreateListener = (
  model: Model,
  options?: CreateOptions,
) => HookReturn;
```

**Example**

```ts
db.on('beforeCreate', async (model, options) => {
  // do something
});

db.on('books.afterCreate', async (model, options) => {
  const { transaction } = options;
  const result = await model.constructor.findByPk(model.id, {
    transaction,
  });
  console.log(result);
});
```

### `'beforeUpdate'` / `'afterUpdate'`

Events triggered before or after updating one piece of data. This is triggered when `repository.update()` is called.

**Signature**

```ts
on(eventName: `${string}.beforeUpdate` | 'beforeUpdate' | `${string}.afterUpdate` | 'afterUpdate', listener: UpdateListener): this
```

**Type**

```ts
import type { UpdateOptions, HookReturn } from 'sequelize/types';
import type { Model } from '@nocobase/database';

export type UpdateListener = (
  model: Model,
  options?: UpdateOptions,
) => HookReturn;
```

**Example**

```ts
db.on('beforeUpdate', async (model, options) => {
  // do something
});

db.on('books.afterUpdate', async (model, options) => {
  // do something
});
```

### `'beforeSave'` / `'afterSave'`

Events triggered before or after creating or updating one piece of data. This is triggered when `repository.create()` or `repository.update()` is called.

**Signature**

```ts
on(eventName: `${string}.beforeSave` | 'beforeSave' | `${string}.afterSave` | 'afterSave', listener: SaveListener): this
```

**Type**

```ts
import type { SaveOptions, HookReturn } from 'sequelize/types';
import type { Model } from '@nocobase/database';

export type SaveListener = (model: Model, options?: SaveOptions) => HookReturn;
```

**Example**

```ts
db.on('beforeSave', async (model, options) => {
  // do something
});

db.on('books.afterSave', async (model, options) => {
  // do something
});
```

### `'beforeDestroy'` / `'afterDestroy'`

Events triggered before or after deleting one piece of data. This is triggered when `repository.destroy()` is called.

**Signature**

```ts
on(eventName: `${string}.beforeDestroy` | 'beforeDestroy' | `${string}.afterDestroy` | 'afterDestroy', listener: DestroyListener): this
```

**Type**

```ts
import type { DestroyOptions, HookReturn } from 'sequelize/types';
import type { Model } from '@nocobase/database';

export type DestroyListener = (
  model: Model,
  options?: DestroyOptions,
) => HookReturn;
```

**Example**

```ts
db.on('beforeDestroy', async (model, options) => {
  // do something
});

db.on('books.afterDestroy', async (model, options) => {
  // do something
});
```

### `'afterCreateWithAssociations'`

Events triggered after creating one piece of data that carries hierarchical data. This is triggered when `repository.create()` is called.

**Signature**

```ts
on(eventName: `${string}.afterCreateWithAssociations` | 'afterCreateWithAssociations', listener: CreateWithAssociationsListener): this
```

**Type**

```ts
import type { CreateOptions, HookReturn } from 'sequelize/types';
import type { Model } from '@nocobase/database';

export type CreateWithAssociationsListener = (
  model: Model,
  options?: CreateOptions,
) => HookReturn;
```

**Example**

```ts
db.on('afterCreateWithAssociations', async (model, options) => {
  // do something
});

db.on('books.afterCreateWithAssociations', async (model, options) => {
  // do something
});
```

### `'afterUpdateWithAssociations'`

Events triggered after updating one piece of data that carries hierarchical data. This is triggered when `repository.update()` is called.

**Signature**

```ts
on(eventName: `${string}.afterUpdateWithAssociations` | 'afterUpdateWithAssociations', listener: CreateWithAssociationsListener): this
```

**Type**

```ts
import type { UpdateOptions, HookReturn } from 'sequelize/types';
import type { Model } from '@nocobase/database';

export type UpdateWithAssociationsListener = (
  model: Model,
  options?: UpdateOptions,
) => HookReturn;
```

**Example**

```ts
db.on('afterUpdateWithAssociations', async (model, options) => {
  // do something
});

db.on('books.afterUpdateWithAssociations', async (model, options) => {
  // do something
});
```

### `'afterSaveWithAssociations'`

Events triggered after creating or updating one piece of data that carries hierarchical data. This is triggered when `repository.create()` or `repository.update()` is called.

**Signature**

```ts
on(eventName: `${string}.afterSaveWithAssociations` | 'afterSaveWithAssociations', listener: SaveWithAssociationsListener): this
```

**Type**

```ts
import type { SaveOptions, HookReturn } from 'sequelize/types';
import type { Model } from '@nocobase/database';

export type SaveWithAssociationsListener = (
  model: Model,
  options?: SaveOptions,
) => HookReturn;
```

**Example**

```ts
db.on('afterSaveWithAssociations', async (model, options) => {
  // do something
});

db.on('books.afterSaveWithAssociations', async (model, options) => {
  // do something
});
```

### `'beforeDefineCollection'`

Events triggered before defining a data table, such as when `db.collection()` is called.

Note: This is a synchronous event.

**Signature**

```ts
on(eventName: 'beforeDefineCollection', listener: BeforeDefineCollectionListener): this
```

**Type**

```ts
import type { CollectionOptions } from '@nocobase/database';

export type BeforeDefineCollectionListener = (
  options: CollectionOptions,
) => void;
```

**Example**

```ts
db.on('beforeDefineCollection', (options) => {
  // do something
});
```

### `'afterDefineCollection'`

Events triggered after defining a data table, such as when `db.collection()` is called.

Note: This is a synchronous event.

**Signature**

```ts
on(eventName: 'afterDefineCollection', listener: AfterDefineCollectionListener): this
```

**Type**

```ts
import type { Collection } from '@nocobase/database';

export type AfterDefineCollectionListener = (options: Collection) => void;
```

**Example**

```ts
db.on('afterDefineCollection', (collection) => {
  // do something
});
```

### `'beforeRemoveCollection'` / `'afterRemoveCollection'`

Events triggered before or after removing a data table from memory, such as when `db.removeCollection()` is called.

Note: This is a synchronous event.

**Signature**

```ts
on(eventName: 'beforeRemoveCollection' | 'afterRemoveCollection', listener: RemoveCollectionListener): this
```

**Type**

```ts
import type { Collection } from '@nocobase/database';

export type RemoveCollectionListener = (options: Collection) => void;
```

**Example**

```ts
db.on('beforeRemoveCollection', (collection) => {
  // do something
});

db.on('afterRemoveCollection', (collection) => {
  // do something
});
```

---

## File: docs/en-US/api/database/operators.md

# Filter Operators

Used in the filter parameters of the `find`, `findOne`, `findAndCount`, `count`, etc. APIs of repository:

```ts
const repository = db.getRepository('books');

repository.find({
  filter: {
    title: {
      $eq: 'Spring and Autumn',
    },
  },
});
```

To support JSON, NocoBase identifies query operators as a string prefixed with $.

Moreover, NocoBase provides API to extend operators. Refer to [`db.registerOperators()`](../database#registeroperators).

## General Operators

### `$eq`

Check if the field value is equal to the specified value. Equivalent to `=` in SQL.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $eq: 'Spring and Autumn',
    },
  },
});
```

Equal to `title: 'Spring and Autumn'`

### `$ne`

Check if the field value is not equal to the specified value. Equivalent to `!=` in SQL.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $ne: 'Spring and Autumn',
    },
  },
});
```

### `$is`

Check if the field value is the specified value. Equivalent to `IS` in SQL.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $is: null,
    },
  },
});
```

### `$not`

Check if the field value is not the specified value. Equivalent to `IS NOT` in SQL.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $not: null,
    },
  },
});
```

### `$col`

Check if the field value is equal to the value of another field. Equivalent to `=` in SQL.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $col: 'name',
    },
  },
});
```

### `$in`

Check if the field value is in the specified array. Equivalent to `IN` in SQL.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $in: ['Spring and Autumn', 'Warring States'],
    },
  },
});
```

### `$notIn`

Check if the field value is not in the specified array. Equivalent to `NOT IN` in SQL.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $notIn: ['Spring and Autumn', 'Warring States'],
    },
  },
});
```

### `$empty`

Check if the general field is empty. For string field, check if it is an empty string; for array field, check if it is an empty array.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $empty: true,
    },
  },
});
```

### `$notEmpty`

Check if the general field is not empty. For string field, check if it is not an empty string; for array field, check if it is not an empty array.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $notEmpty: true,
    },
  },
});
```

## Logical Operators

### `$and`

Logical AND. Equivalent to `AND` in SQL.

**Example**

```ts
repository.find({
  filter: {
    $and: [{ title: 'Book of Songs' }, { isbn: '1234567890' }],
  },
});
```

### `$or`

Logical OR. Equivalent to `OR` in SQL.

**Example**

```ts
repository.find({
  filter: {
    $or: [
      { title: 'Book of Songs' },
      { publishedAt: { $lt: '0000-00-00T00:00:00Z' } },
    ],
  },
});
```

## Boolean Field Operators

For boolean fields: `type: 'boolean'`

### `$isFalsy`

Check if a Boolean field value is false. Boolean field values of `false`, `0` and `NULL` are all judged to be `$isFalsy: true`.

**Example**

```ts
repository.find({
  filter: {
    isPublished: {
      $isFalsy: true,
    },
  },
});
```

### `$isTruly`

Check if a Boolean field value is true. Boolean field values of `true` and `1` are all judged to be `$isTruly: true`.

**Example**

```ts
repository.find({
  filter: {
    isPublished: {
      $isTruly: true,
    },
  },
});
```

## Numeric Type Field Operators

For numeric type fields, including:

- `type: 'integer'`
- `type: 'float'`
- `type: 'double'`
- `type: 'real'`
- `type: 'decimal'`

### `$gt`

Check if the field value is greater than the specified value. Equivalent to `>` in SQL.

**Example**

```ts
repository.find({
  filter: {
    price: {
      $gt: 100,
    },
  },
});
```

### `$gte`

Check if the field value is equal to or greater than the specified value. Equivalent to `>=` in SQL.

**Example**

```ts
repository.find({
  filter: {
    price: {
      $gte: 100,
    },
  },
});
```

### `$lt`

Check if the field value is less than the specified value. Equivalent to `<` in SQL.

**Example**

```ts
repository.find({
  filter: {
    price: {
      $lt: 100,
    },
  },
});
```

### `$lte`

Check if the field value is equal to or less than the specified value. Equivalent to `<=` in SQL.

**Example**

```ts
repository.find({
  filter: {
    price: {
      $lte: 100,
    },
  },
});
```

### `$between`

Check if the field value is between the specified two values. Equivalent to `BETWEEN` in SQL.

**Example**

```ts
repository.find({
  filter: {
    price: {
      $between: [100, 200],
    },
  },
});
```

### `$notBetween`

Check if the field value is not between the specified two values. Equivalent to `NOT BETWEEN` in SQL.

**Example**

```ts
repository.find({
  filter: {
    price: {
      $notBetween: [100, 200],
    },
  },
});
```

## String Type Field Operators

For string type fields, including `string`.

### `$includes`

Check if the string field contains the specified substring.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $includes: 'Three Character Classic',
    },
  },
});
```

### `$notIncludes`

Check if the string field does not contain the specified substring.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $notIncludes: 'Three Character Classic',
    },
  },
});
```

### `$startsWith`

Check if the string field starts with the specified substring.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $startsWith: 'Three Character Classic',
    },
  },
});
```

### `$notStatsWith`

Check if the string field does not start with the specified substring.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $notStatsWith: 'Three Character Classic',
    },
  },
});
```

### `$endsWith`

Check if the string field ends with the specified substring.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $endsWith: 'Three Character Classic',
    },
  },
});
```

### `$notEndsWith`

Check if the string field does not end with the specified substring.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $notEndsWith: 'Three Character Classic',
    },
  },
});
```

### `$like`

Check if the field value contains the specified string. Equivalent to `LIKE` in SQL.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $like: 'Computer',
    },
  },
});
```

### `$notLike`

Check if the field value does not contain the specified string. Equivalent to `NOT LIKE` in SQL.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $notLike: 'Computer',
    },
  },
});
```

### `$iLike`

Check if a field value contains the specified string, case ignored. Equivalent to `ILIKE` in SQL (PG only).

**Example**

```ts
repository.find({
  filter: {
    title: {
      $iLike: 'Computer',
    },
  },
});
```

### `$notILike`

Check if a field value does not contain the specified string, case ignored. Equivalent to `NOT ILIKE` in SQL (PG only).

**Example**

```ts
repository.find({
  filter: {
    title: {
      $notILike: 'Computer',
    },
  },
});
```

### `$regexp`

Check if the field value matches the specified regular expression. Equivalent to `REGEXP` in SQL (PG only).

**Example**

```ts
repository.find({
  filter: {
    title: {
      $regexp: '^Computer',
    },
  },
});
```

### `$notRegexp`

Check if the field value does not match the specified regular expression. Equivalent to `NOT REGEXP` in SQL (PG only).

**Example**

```ts
repository.find({
  filter: {
    title: {
      $notRegexp: '^Computer',
    },
  },
});
```

### `$iRegexp`

Check if the field value matches the specified regular expression, case ignored. Equivalent to `~*` in SQL (PG only).

**Example**

```ts
repository.find({
  filter: {
    title: {
      $iRegexp: '^COMPUTER',
    },
  },
});
```

### `$notIRegexp`

Check if the field value does not match the specified regular expression, case ignored. Equivalent to `!~*` in SQL (PG only).

**Example**

```ts
repository.find({
  filter: {
    title: {
      $notIRegexp: '^COMPUTER',
    },
  },
});
```

## Date Type Field Operators

For date type fields: `type: 'date'`

### `$dateOn`

Check if the date field value is within a certain day.

**Example**

```ts
repository.find({
  filter: {
    createdAt: {
      $dateOn: '2021-01-01',
    },
  },
});
```

### `$dateNotOn`

Check if the date field value is not within a certain day.

**Example**

```ts
repository.find({
  filter: {
    createdAt: {
      $dateNotOn: '2021-01-01',
    },
  },
});
```

### `$dateBefore`

Check if the date field value is before a certain value, i.e., less than the one passed in.

**Example**

```ts
repository.find({
  filter: {
    createdAt: {
      $dateBefore: '2021-01-01T00:00:00.000Z',
    },
  },
});
```

### `$dateNotBefore`

Check if the date field value is not before a certain value, i.e., equal to or greater than the one passed in.

**Example**

```ts
repository.find({
  filter: {
    createdAt: {
      $dateNotBefore: '2021-01-01T00:00:00.000Z',
    },
  },
});
```

### `$dateAfter`

Check if the date field value is after a certain value, i.e., greater than the one passed in.

**Example**

```ts
repository.find({
  filter: {
    createdAt: {
      $dateAfter: '2021-01-01T00:00:00.000Z',
    },
  },
});
```

### `$dateNotAfter`

Check if the date field value is not after a certain value, i.e., equal to or greater than the one passed in.

**Example**

```ts
repository.find({
  filter: {
    createdAt: {
      $dateNotAfter: '2021-01-01T00:00:00.000Z',
    },
  },
});
```

## Array Type Field Operators

For array type fields: `type: 'array'`

### `$match`

Check if the array field values match values of the specified array.

**Example**

```ts
repository.find({
  filter: {
    tags: {
      $match: ['literature', 'history'],
    },
  },
});
```

### `$notMatch`

Check if the array field values do not match values of the specified array.

**Example**

```ts
repository.find({
  filter: {
    tags: {
      $notMatch: ['literature', 'history'],
    },
  },
});
```

### `$anyOf`

Check if the array field values contain any of the values of the specified array.

**Example**

```ts
repository.find({
  filter: {
    tags: {
      $anyOf: ['literature', 'history'],
    },
  },
});
```

### `$noneOf`

Check if the array field values contain none of the values of the specified array.

**Example**

```ts
repository.find({
  filter: {
    tags: {
      $noneOf: ['literature', 'history'],
    },
  },
});
```

### `$arrayEmpty`

Check if the array field is empty.

**Example**

```ts
repository.find({
  filter: {
    tags: {
      $arrayEmpty: true,
    },
  },
});
```

### `$arrayNotEmpty`

Check if the array field is not empty.

**Example**

```ts
repository.find({
  filter: {
    tags: {
      $arrayNotEmpty: true,
    },
  },
});
```

## Relational Field Type Operators

For checking if a relationship exists, field types include:

- `type: 'hasOne'`
- `type: 'hasMany'`
- `type: 'belongsTo'`
- `type: 'belongsToMany'`

### `$exists`

There is relational data existing.

**Example**

```ts
repository.find({
  filter: {
    author: {
      $exists: true,
    },
  },
});
```

### `$notExists`

There is no relational data existing.

**Example**

```ts
repository.find({
  filter: {
    author: {
      $notExists: true,
    },
  },
});
```

---

## File: docs/en-US/api/database/repository.md

# Repository

## Overview

On a given `Collection` object, you can get its `Repository` object to perform read and write operations on the data table.

```javascript
const { UserCollection } = require('./collections');

const UserRepository = UserCollection.repository;

const user = await UserRepository.findOne({
  filter: {
    id: 1,
  },
});

user.name = 'new name';
await user.save();
```

### Query

#### Basic Query

On the `Repository` object, call the `find*` methods to perform query. The `filter` parameter is supported by all query methods to filter the data.

```javascript
// SELECT * FROM users WHERE id = 1
userRepository.find({
  filter: {
    id: 1,
  },
});
```

#### Operator

The `filter` parameter in the `Repository` also provides a variety of operators to perform more diverse queries.

```javascript
// SELECT * FROM users WHERE age > 18
userRepository.find({
  filter: {
    age: {
      $gt: 18,
    },
  },
});

// SELECT * FROM users WHERE age > 18 OR name LIKE '%张%'
userRepository.find({
  filter: {
    $or: [{ age: { $gt: 18 } }, { name: { $like: '%张%' } }],
  },
});
```

Refer to [Filter Operators](/api/database/operators) for more details on operators.

#### Field Control

Control the output fields by the `fields`, `except`, and `appends` parameters when performing query.

- `fields`: Specify output fields
- `except`: Exclude output fields
- `appends`: Append output associated fields

```javascript
// The result contains only the id and name fields
userRepository.find({
  fields: ['id', 'name'],
});

// The result does not contain only the password field
userRepository.find({
  except: ['password'],
});

// The result contains data associated with the posts object
userRepository.find({
  appends: ['posts'],
});
```

#### Associated Field Query

The `filter` parameter supports filtering by associated fields, for example:

```javascript
// Find the user objects whose associated posts have title of "post title"
userRepository.find({
  filter: {
    'posts.title': 'post title',
  },
});
```

Associated fields can also be nested:

```javascript
// Find the user objects whose associated posts have comments containing "keywords"
await userRepository.find({
  filter: {
    'posts.comments.content': {
      $like: '%keywords%',
    },
  },
});
```

#### Sort

Sort query results by the `sort` parameter.

```javascript
// SELECT * FROM users ORDER BY age
await userRepository.find({
  sort: 'age',
});

// SELECT * FROM users ORDER BY age DESC
await userRepository.find({
  sort: '-age',
});

// SELECT * FROM users ORDER BY age DESC, name ASC
await userRepository.find({
  sort: ['-age', 'name'],
});
```

Sort by the field of the associated object is also supported:

```javascript
await userRepository.find({
  sort: 'profile.createdAt',
});
```

### Create

#### Basic Create

Create new data objects via `Repository`.

```javascript
await userRepository.create({
  name: 'Mark',
  age: 18,
});
// INSERT INTO users (name, age) VALUES ('Mark', 18)

// Bulk creation
await userRepository.create([
  {
    name: 'Mark',
    age: 18,
  },
  {
    name: 'Alex',
    age: 20,
  },
]);
```

#### Create Association

Create associated objects at the same time of creating data. Like query, nested use of associated objects is also supported. For example:

```javascript
await userRepository.create({
  name: 'Mark',
  age: 18,
  posts: [
    {
      title: 'post title',
      content: 'post content',
      tags: [
        {
          name: 'tag1',
        },
        {
          name: 'tag2',
        },
      ],
    },
  ],
});
// When creating a user, create a post to associate with the user, and create tags to associate with the post
```

If the associated object is already in the database, you can pass its ID to create an association with it.

```javascript
const tag1 = await tagRepository.findOne({
  filter: {
    name: 'tag1',
  },
});

await userRepository.create({
  name: 'Mark',
  age: 18,
  posts: [
    {
      title: 'post title',
      content: 'post content',
      tags: [
        {
          id: tag1.id, // Create an association with an existing associated object
        },
        {
          name: 'tag2',
        },
      ],
    },
  ],
});
```

### Update

#### Basic Update

After getting the data object, you can modify the properties directly on the data object (`Model`), and then call the `save` method to save the changes.

```javascript
const user = await userRepository.findOne({
  filter: {
    name: 'Mark',
  },
});

user.age = 20;
await user.save();
```

The data object `Model` is inherited from Sequelize Model, refer to [Sequelize Model](https://sequelize.org/master/manual/model-basics.html) for the operations on `Model`.

Or update data via `Repository`:

```javascript
// Update the records that meet the filtering condition
await userRepository.update({
  filter: {
    name: 'Mark',
  },
  values: {
    age: 20,
  },
});
```

Control which fields to update by the `whitelist` and `blacklist` parameters, for example:

```javascript
await userRepository.update({
  filter: {
    name: 'Mark',
  },
  values: {
    age: 20,
    name: 'Alex',
  },
  whitelist: ['age'], // Only update the age field
});
```

#### Update Associated Field

Associated objects can be set while updating, for example:

```javascript
const tag1 = tagRepository.findOne({
  filter: {
    id: 1,
  },
});

await postRepository.update({
  filter: {
    id: 1,
  },
  values: {
    title: 'new post title',
    tags: [
      {
        id: tag1.id, // Associate with tag1
      },
      {
        name: 'tag2', // Create new tag and associate with it
      },
    ],
  },
});

await postRepository.update({
  filter: {
    id: 1,
  },
  values: {
    tags: null, // Disassociate post from tags
  },
});
```

### Delete

Call the `destroy()` method in `Repository` to perform the deletion operation. Filtering condition has to be specified to delete.

```javascript
await userRepository.destroy({
  filter: {
    status: 'blocked',
  },
});
```

## Constructor

It is usually not called directly by the developer, the instantiation is done mainly by specifying a corresponding repository type that is already registered in the parameter of `db.colletion()`. Repository type is registered through `db.registerRepositories()`.

**Signature**

- `constructor(collection: Collection)`

**Example**

```ts
import { Repository } from '@nocobase/database';

class MyRepository extends Repository {
  async myQuery(sql) {
    return this.database.sequelize.query(sql);
  }
}

db.registerRepositories({
  books: MyRepository,
});

db.collection({
  name: 'books',
  // here link to the registered repository
  repository: 'books',
});

await db.sync();

const books = db.getRepository('books') as MyRepository;
await books.myQuery('SELECT * FROM books;');
```

## Instance Members

### `database`

The database management instance where the context is located.

### `collection`

The corresponding data table management instance.

### `model`

The corresponding data model class.

## Instance Methods

### `find()`

Find datasets from the database with the specified filtering conditions and sorting, etc.

**Signature**

- `async find(options?: FindOptions): Promise<Model[]>`

**Type**

```typescript
type Filter = FilterWithOperator | FilterWithValue | FilterAnd | FilterOr;
type Appends = string[];
type Except = string[];
type Fields = string[];
type Sort = string[] | string;

interface SequelizeFindOptions {
  limit?: number;
  offset?: number;
}

interface FilterByTk {
  filterByTk?: TargetKey;
}

interface CommonFindOptions extends Transactionable {
  filter?: Filter;
  fields?: Fields;
  appends?: Appends;
  except?: Except;
  sort?: Sort;
}

type FindOptions = SequelizeFindOptions & CommonFindOptions & FilterByTk;
```

**Detailed Information**

#### `filter: Filter`

Query conditions for filtering data results. In the query parameters that passed in, `key` is the name of the field, `value` is the corresponding value. Operators can be used in conjunction with other filtering conditions.

```typescript
// Find records with name "foo" and age above 18
repository.find({
  filter: {
    name: 'foo',
    age: {
      $gt: 18,
    },
  },
});
```

Refer to [Operators](./operators.md) for more information.

#### `filterByTk: TargetKey`

Query data by `TargetKey`, this is shortcut for the `filter` parameter. The field of `TargetKey` can be [configured](./collection.md#filtertargetkey) in `Collection`, the default is `primaryKey`.

```typescript
// By default, find records with id 1
repository.find({
  filterByTk: 1,
});
```

#### `fields: string[]`

Query columns. It is used to control which data fields to output. With this parameter, only the specified fields will be returned.

#### `except: string[]`

Exclude columns. It is used to control which data fields to output. With this parameter, the specified fields will not be returned.

#### `appends: string[]`

Append columns. It is used to load associated data. With this parameter, the specified associated fields will be returned together.

#### `sort: string[] | string`

Specify the sorting method of the query results. The input parameter is the name of the field, by default is to sort in the ascending order (`asc`); a `-` symbol needs to be added before the field name to sort in the descending order (`desc`). For example, `['-id', 'name']` means to sort by `id desc, name asc`.

#### `limit: number`

Limit the number of results, same as `limit` in `SQL`.

#### `offset: number`

The offset of the query, same as `offset` in `SQL`.

**Example**

```ts
const posts = db.getRepository('posts');

const results = await posts.find({
  filter: {
    createdAt: {
      $gt: '2022-01-01T00:00:00.000Z',
    },
  },
  fields: ['title'],
  appends: ['user'],
});
```

### `findOne()`

Find a single piece of data from the database for specific conditions. Equivalent to `Model.findOne()` in Sequelize.

**Signature**

- `async findOne(options?: FindOneOptions): Promise<Model | null>`



**Example**

```ts
const posts = db.getRepository('posts');

const result = await posts.findOne({
  filterByTk: 1,
});
```

### `count()`

Query a certain amount of data from the database for specific conditions. Equivalent to `Model.count()` in Sequelize.

**Signature**

- `count(options?: CountOptions): Promise<number>`

**Type**

```typescript
interface CountOptions
  extends Omit<SequelizeCountOptions, 'distinct' | 'where' | 'include'>,
    Transactionable {
  filter?: Filter;
}
```

**Example**

```ts
const books = db.getRepository('books');

const count = await books.count({
  filter: {
    title: 'Three character classic',
  },
});
```

### `findAndCount()`

Find datasets from the database with the specified filtering conditions and return the number of results. Equivalent to `Model.findAndCountAll()` in Sequelize.

**Signature**

- `async findAndCount(options?: FindAndCountOptions): Promise<[Model[], number]>`

**Type**

```typescript
type FindAndCountOptions = Omit<
  SequelizeAndCountOptions,
  'where' | 'include' | 'order'
> &
  CommonFindOptions;
```

**Detailed Information**

The query parameters are the same as `find()`. An array is returned with the first element of the query results, and the second element of the total number of results.

### `create()`

Inserts a newly created data into the data table. Equivalent to `Model.create()` in Sequelize. When the data object to be created carries any associated field, the corresponding associated data record is created or updated along with it.

**Signature**

- `async create<M extends Model>(options: CreateOptions): Promise<M>`



**Example**

```ts
const posts = db.getRepository('posts');

const result = await posts.create({
  values: {
    title: 'NocoBase 1.0 Release Notes',
    tags: [
      // Update data when there is a primary key and value of the associated table
      { id: 1 },
      // Create data when there is no primary key and value
      { name: 'NocoBase' },
    ],
  },
});
```

### `createMany()`

Inserts multiple newly created data into the data table. This is equivalent to calling the `create()` method multiple times.

**Signature**

- `createMany(options: CreateManyOptions): Promise<Model[]>`

**Type**

```typescript
interface CreateManyOptions extends BulkCreateOptions {
  records: Values[];
}
```

**Detailed Information**

- `records`: An array of data objects to be created.
- `transaction`: Transaction object. If no transaction parameter is passed, the method will automatically create an internal transaction.

**Example**

```ts
const posts = db.getRepository('posts');

const results = await posts.createMany({
  records: [
    {
      title: 'NocoBase 1.0 Release Notes',
      tags: [
        // Update data when there is a primary key and value of the associated table
        { id: 1 },
        // Create data when there is no primary key and value
        { name: 'NocoBase' },
      ],
    },
    {
      title: 'NocoBase 1.1 Release Notes',
      tags: [{ id: 1 }],
    },
  ],
});
```

### `update()`

Update data in the data table. Equivalent to `Model.update()` in Sequelize. When the data object to be updated carries any associated field, the corresponding associated data record is created or updated along with it.

**Signature**

- `async update<M extends Model>(options: UpdateOptions): Promise<M>`



**Example**

```ts
const posts = db.getRepository('posts');

const result = await posts.update({
  filterByTk: 1,
  values: {
    title: 'NocoBase 1.0 Release Notes',
    tags: [
      // Update data when there is a primary key and value of the associated table
      { id: 1 },
      // Create data when there is no primary key and value
      { name: 'NocoBase' },
    ],
  },
});
```

### `destroy()`

Delete data from the data table. Equivalent to `Model.destroy()` in Sequelize.

**Signature**

- `async destroy(options?: TargetKey | TargetKey[] | DestoryOptions): Promise<number>`

**Type**

```typescript
interface DestroyOptions extends SequelizeDestroyOptions {
  filter?: Filter;
  filterByTk?: TargetKey | TargetKey[];
  truncate?: boolean;
  context?: any;
}
```

**Detailed Information**

- `filter`：Specify the filtering conditions of the records to be deleted. Refer to the [`find()`](#find) method for the detailed usage of the filter.
- `filterByTk`：Specify the filtering conditions by TargetKey.
- `truncate`: Whether to empty the table data, this parameter is valid if no `filter` or `filterByTk` parameter is passed.
- `transaction`: Transaction object. If no transaction parameter is passed, the method will automatically create an internal transaction.

---

## File: docs/en-US/api/database/shared.md

**Parameters**

| Parameter Name         | Type          | Default | Description                                           |
| ---------------------- | ------------- | ------- | ----------------------------------------------------- |
| `options.values`       | `M`           | `{}`    | The data object to be inserted                        |
| `options.whitelist?`   | `string[]`    | -       | Whitelist for the `values` field; only fields in the list will be stored |
| `options.blacklist?`   | `string[]`    | -       | Blacklist for the `values` field; fields in the list will not be stored |
| `options.transaction?` | `Transaction` | -       | Transaction                                            |

---

## File: docs/en-US/api/database/interfaces/base-interface.md

# BaseInterface

## Overview

BaseInterface is the foundational class for all Interface types. Users can extend this class to implement custom Interface logic.

```typescript
class CustomInterface extends BaseInterface {
  async toValue(value: string, ctx?: any): Promise<any> {
    // Custom toValue logic
  }

  toString(value: any, ctx?: any) {
    // Custom toString logic
  }
}
// Register Interface
db.interfaceManager.registerInterfaceType('customInterface', CustomInterface)
```

## Interfaces

### toValue(value: string, ctx?: any): Promise<any>

Converts an external string to the actual value of the interface, which can be directly passed to the Repository for write operations.

### toString(value: any, ctx?: any)

Converts the actual value of the interface to a string type, which can be used for exporting or displaying purposes.

---

## File: docs/en-US/api/database/relation-repository/belongs-to-many-repository.md

# BelongsToManyRepository

`BelongsToManyRepository` is the `Relation Repository` for handling `BelongsToMany` relationships.

Unlike other relationship types, the `BelongsToMany` type of relationship needs to be recorded through an intermediate table. The intermediate table can be created automatically or explicitly specified when defining association relationships in NocoBase.

## Class Methods

### `find()`

Find associated objects.

**Signature**

- `async find(options?: FindOptions): Promise<M[]>`

**Detailed Information**

Query parameters are the same as [`Repository.find()`](../repository.md#find).

### `findOne()`

Find associated objects, only to return one record.

**Signature**

- `async findOne(options?: FindOneOptions): Promise<M>`



### `count()`

Return the number of records matching the query criteria.

**Signature**

- `async count(options?: CountOptions)`

**Type**

```typescript
interface CountOptions
  extends Omit<SequelizeCountOptions, 'distinct' | 'where' | 'include'>,
    Transactionable {
  filter?: Filter;
}
```

### `findAndCount()`

Find datasets from the database with the specified filtering conditions and return the number of results.

**Signature**

- `async findAndCount(options?: FindAndCountOptions): Promise<[any[], number]>`

**Type**

```typescript
type FindAndCountOptions = CommonFindOptions;
```

### `create()`

Create associated objects.

**Signature**

- `async create(options?: CreateOptions): Promise<M>`



### `update()`

Update associated objects that match the conditions.

**Signature**

- `async update(options?: UpdateOptions): Promise<M>`



### `destroy()`

Delete associated objects.

**Signature**

- `async destroy(options?: TargetKey | TargetKey[] | DestroyOptions): Promise`



### `add()`

Add new associated objects.

**Signature**

- `async add(
options: TargetKey | TargetKey[] | PrimaryKeyWithThroughValues | PrimaryKeyWithThroughValues[] | AssociatedOptions
): Promise<void>`

**Type**

```typescript
type PrimaryKeyWithThroughValues = [TargetKey, Values];

interface AssociatedOptions extends Transactionable {
  tk?:
    | TargetKey
    | TargetKey[]
    | PrimaryKeyWithThroughValues
    | PrimaryKeyWithThroughValues[];
}
```

**Detailed Information**

Pass the `targetKey` of the associated object directly, or pass the `targetKey` along with the field values of the intermediate table.

**Example**

```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);

// Pass in the targetKey
PostTagRepository.add([t1.id, t2.id]);

// Pass in intermediate table fields
PostTagRepository.add([
  [t1.id, { tagged_at: '123' }],
  [t2.id, { tagged_at: '456' }],
]);
```

### `set()`

Set the associated objects.

**Signature**

- async set(
  options: TargetKey | TargetKey[] | PrimaryKeyWithThroughValues | PrimaryKeyWithThroughValues[] | AssociatedOptions,
  ): Promise<void>

**Detailed Information**

Parameters are the same as [add()](#add).

### `remove()`

Remove the association with the given objects.

**Signature**

- `async remove(options: TargetKey | TargetKey[] | AssociatedOptions)`

**Type**

```typescript
interface AssociatedOptions extends Transactionable {
  tk?: TargetKey | TargetKey[];
}
```

### `toggle()`

Toggle the associated object.

In some business scenarios, it is often needed to toggle the associated object. For example, user adds a product into collection, and the user cancels the collection and collect it again. Using the `toggle` method can quickly implement similar functions.

**Signature**

- `async toggle(options: TargetKey | { tk?: TargetKey; transaction?: Transaction }): Promise<void>`

**Detailed Information**

The `toggle` method automatically checks whether the associated object already exists, and removes it if it does, or adds it if it does not.

---

## File: docs/en-US/api/database/relation-repository/belongs-to-repository.md

## BelongsToRepository

The interface is the same as [HasOneRepository](./has-one-repository.md). `BelongsToRepository` is the `Repository` for handling `BelongsTo` relationships, and it provides some convenient methods to handle `BelongsTo` relationships.

---

## File: docs/en-US/api/database/relation-repository/has-many-repository.md

# HasManyRepository

`HasManyRepository` is the `Relation Repository` for handling `HasMany` relationships.

## Class Methods

### `find()`

Find associated objects.

**Signature**

- `async find(options?: FindOptions): Promise<M[]>`

**Detailed Information**

Query parameters are the same as [`Repository.find()`](../repository.md#find).

### `findOne()`

Find associated objects, only to return one record.

**Signature**

- `async findOne(options?: FindOneOptions): Promise<M>`



### `count()`

Return the number of records matching the query criteria.

**Signature**

- `async count(options?: CountOptions)`

**Type**

```typescript
interface CountOptions
  extends Omit<SequelizeCountOptions, 'distinct' | 'where' | 'include'>,
    Transactionable {
  filter?: Filter;
}
```

### `findAndCount()`

Find datasets from the database with the specified filtering conditions and return the number of results.

**Signature**

- `async findAndCount(options?: FindAndCountOptions): Promise<[any[], number]>`

**Type**

```typescript
type FindAndCountOptions = CommonFindOptions;
```

### `create()`

Create associated objects.

**Signature**

- `async create(options?: CreateOptions): Promise<M>`



### `update()`

Update associated objects that match the conditions.

**Signature**

- `async update(options?: UpdateOptions): Promise<M>`



### `destroy()`

Delete associated objects.

**Signature**

- `async destroy(options?: TK | DestroyOptions): Promise<M>`



### `add()`

Add association relationships between objects.

**Signature**

- `async add(options: TargetKey | TargetKey[] | AssociatedOptions)`

**Type**

```typescript
interface AssociatedOptions extends Transactionable {
  tk?: TargetKey | TargetKey[];
}
```

**Detailed Information**

- `tk` - The targetKey value of the associated object, either as a single value or an array.
  

### `remove()`

Remove the association with the given objects.

**Signature**

- `async remove(options: TargetKey | TargetKey[] | AssociatedOptions)`

**Detailed Information**

Same parameters as the [`add()`](#add) method.

### `set()`

Set the associated object of the current relationship.

**Signature**

- `async set(options: TargetKey | TargetKey[] | AssociatedOptions)`

**Detailed Information**

Same parameters as the [`add()`](#add) method.

---

## File: docs/en-US/api/database/relation-repository/has-one-repository.md

# HasOneRepository

## Overview

`HasOneRepository` is the associated repository of type `HasOne`.

```typescript
const User = db.collection({
  name: 'users',
  fields: [
    { type: 'hasOne', name: 'profile' },
    { type: 'string', name: 'name' },
  ],
});

const Profile = db.collection({
  name: 'profiles',
  fields: [{ type: 'string', name: 'avatar' }],
});

const user = await User.repository.create({
  values: { name: 'u1' },
});

// Get the associated repository
const userProfileRepository = User.repository
  .relation('profile')
  .of(user.get('id'));

// Or to initialize directly
new HasOneRepository(User, 'profile', user.get('id'));
```

## Class Methods

### `find()`

Find associated objects.

**Signature**

- `async find(options?: SingleRelationFindOption): Promise<Model<any> | null>`

**Type**

```typescript
interface SingleRelationFindOption extends Transactionable {
  fields?: Fields;
  except?: Except;
  appends?: Appends;
  filter?: Filter;
}
```

**Detailed Information**

Query parameters are the same as [`Repository.find()`](../repository.md#find).

**Example**

```typescript
const profile = await UserProfileRepository.find();
// Return null if the associated object does not exist
```

### `create()`

Create associated objects.

**Signature**

- `async create(options?: CreateOptions): Promise<Model>`



**Example**

```typescript
const profile = await UserProfileRepository.create({
  values: { avatar: 'avatar1' },
});

console.log(profile.toJSON());
/*
{
  id: 1,
  avatar: 'avatar1',
  userId: 1,
  updatedAt: 2022-09-24T13:59:40.025Z,
  createdAt: 2022-09-24T13:59:40.025Z
}
*/
```

### `update()`

Update associated objects.

**Signature**

- `async update(options: UpdateOptions): Promise<Model>`



**Example**

```typescript
const profile = await UserProfileRepository.update({
  values: { avatar: 'avatar2' },
});

profile.get('avatar'); // 'avatar2'
```

### `remove()`

Remove associated objects. Only to unassociate, not to delete the associated object.

**Signature**

- `async remove(options?: Transactionable): Promise<void>`

**Detailed Information**

- `transaction`: Transaction object. If no transaction parameter is passed, the method will automatically create an internal transaction.

**Example**

```typescript
await UserProfileRepository.remove();
(await UserProfileRepository.find()) == null; // true

(await Profile.repository.count()) === 1; // true
```

### `destroy()`

Delete associated objects.

**Signature**

- `async destroy(options?: Transactionable): Promise`

**Detailed Information**

- `transaction`: Transaction object. If no transaction parameter is passed, the method will automatically create an internal transaction.

**Example**

```typescript
await UserProfileRepository.destroy();
(await UserProfileRepository.find()) == null; // true
(await Profile.repository.count()) === 0; // true
```

### `set()`

Set associated objects.

**Signature**

- `async set(options: TargetKey | SetOption): Promise<void>`

**Type**

```typescript
interface SetOption extends Transactionable {
  tk?: TargetKey;
}
```

**Detailed Information**

- tk: Set the targetKey of the associated object.
- transaction: Transaction object. If no transaction parameter is passed, the method will automatically create an internal transaction.

**Example**

```typescript
const newProfile = await Profile.repository.create({
  values: { avatar: 'avatar2' },
});

await UserProfileRepository.set(newProfile.get('id'));

(await UserProfileRepository.find()).get('id') === newProfile.get('id'); // true
```

---

## File: docs/en-US/api/database/relation-repository/index.md

# RelationRepository

`RelationRepository` is a `Repository` object for relation types, which allows operations on associated data without loading the associations. Based on `RelationRepository`, each association type derives its corresponding implementation, which are:

- [`HasOneRepository`](#has-one-repository)
- `HasManyRepository`
- `BelongsToRepository`
- `BelongsToManyRepository`

## Constructor

**Signature**

- `constructor(sourceCollection: Collection, association: string, sourceKeyValue: string | number)`

**Parameters**

| Parameter Name     | Type               | Default Value | Description                                               |
| ------------------ | ------------------ | ------------- | --------------------------------------------------------- |
| `sourceCollection` | `Collection`       | -             | The Collection corresponding to the referencing relation in the association |
| `association`      | `string`           | -             | The name of the association                               |
| `sourceKeyValue`   | `string \| number` | -             | The key value corresponding to the referencing relation   |

## Base Class Properties

### `db: Database`

Database object

### `sourceCollection`

The Collection corresponding to the referencing relation in the association

### `targetCollection`

The Collection corresponding to the referenced relation in the association

### `association`

The association object in Sequelize corresponding to the current association

### `associationField`

The field in the Collection corresponding to the current association

### `sourceKeyValue`

The key value corresponding to the referencing relation

---

## File: docs/en-US/api/database/shared/create-options.md

**Type**

```typescript
type WhiteList = string[];
type BlackList = string[];
type AssociationKeysToBeUpdate = string[];

interface CreateOptions extends SequelizeCreateOptions {
  values?: Values;
  whitelist?: WhiteList;
  blacklist?: BlackList;
  updateAssociationValues?: AssociationKeysToBeUpdate;
  context?: any;
}
```

**Details**

- `values`: The data object of the record to be created.
- `whitelist`: Specifies which fields in the data object of the record to be created **can be written**. If this parameter is not passed, all fields are allowed to be written by default.
- `blacklist`: Specifies which fields in the data object of the record to be created **are not allowed to be written**. If this parameter is not passed, all fields are allowed to be written by default.
- `transaction`: The transaction object. If no transaction parameter is passed, the method will automatically create an internal transaction.

---

## File: docs/en-US/api/database/shared/destroy-options.md

**Type**

```typescript
interface DestroyOptions extends SequelizeDestroyOptions {
  filter?: Filter;
  filterByTk?: TargetKey | TargetKey[];
  truncate?: boolean;
  context?: any;
}
```

**Details**

- `filter`: Specifies the filtering conditions for the records to be deleted. For detailed usage of Filter, refer to the [`find()`](#find) method.
- `filterByTk`: Specifies the filtering conditions for the records to be deleted by TargetKey.
- `truncate`: Whether to truncate the table data, effective when no `filter` or `filterByTk` parameters are passed.
- `transaction`: Transaction object. If no transaction parameter is passed, the method will automatically create an internal transaction.

---

## File: docs/en-US/api/database/shared/find-one.md

**Type**

```typescript
type FindOneOptions = Omit<FindOptions, 'limit'>;
```

**Parameters**

Most parameters are the same as those in `find()`. The difference is that `findOne()` returns only a single piece of data, so the `limit` parameter is not needed, and the query is always set to `1`.

---

## File: docs/en-US/api/database/shared/find-options.md

[Empty file]

---

## File: docs/en-US/api/database/shared/transaction.md

- `transaction`: Transaction object. If no transaction parameter is passed, the method will automatically create an internal transaction.

---

## File: docs/en-US/api/database/shared/update-options.md

**Type**

```typescript
interface UpdateOptions extends Omit<SequelizeUpdateOptions, 'where'> {
  values: Values;
  filter?: Filter;
  filterByTk?: TargetKey;
  whitelist?: WhiteList;
  blacklist?: BlackList;
  updateAssociationValues?: AssociationKeysToBeUpdate;
  context?: any;
}
```

**Details**

- `values`: The data object of the records to be updated.
- `filter`: Specifies the filter conditions for the records to be updated. For detailed usage of Filter, refer to the [`find()`](#find) method.
- `filterByTk`: Specifies the filter conditions for the records to be updated by TargetKey.
- `whitelist`: A whitelist for the `values` fields. Only fields listed will be written.
- `blacklist`: A blacklist for the `values` fields. Fields listed will not be written.
- `transaction`: The transaction object. If no transaction parameter is passed, the method will automatically create an internal transaction.

At least one of `filterByTk` or `filter` must be provided.

---

## File: docs/en-US/api/field/markdown-vditor/index.md

# markdown

## Example

This is an embedded Markdown editor:

<MarkdownEditor />

---

## File: docs/en-US/api/handlebars-helpers/array.md

# Array

## {{after}}

Returns all of the items in an array after the specified index. Opposite of [before](#before).

**Params**

* `array` **{Array}**: Collection
* `n` **{Number}**: Starting index (number of items to exclude)
* `returns` **{Array}**: Array exluding `n` items.

**Example**

```handlebars
<!-- array: ['a', 'b', 'c'] -->
{{after array 1}}
<!-- results in: '["c"]' -->
```

## {{arrayify}}

Cast the given `value` to an array.

**Params**

* `value` **{any}**
* `returns` **{Array}**

**Example**

```handlebars
{{arrayify "foo"}}
<!-- results in: [ "foo" ] -->
```

## {{before}}

Return all of the items in the collection before the specified count. Opposite of [after](#after).

**Params**

* `array` **{Array}**
* `n` **{Number}**
* `returns` **{Array}**: Array excluding items after the given number.

**Example**

```handlebars
<!-- array: ['a', 'b', 'c'] -->
{{before array 2}}
<!-- results in: '["a", "b"]' -->
```

## {{eachIndex}}

**Params**

* `array` **{Array}**
* `options` **{Object}**
* `returns` **{String}**

**Example**

```handlebars
<!-- array: ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'] -->
{{#eachIndex array}}
  {{item}} is {{index}}
{{/eachIndex}}
```

## {{filter}}

Block helper that filters the given array and renders the block for values that evaluate to `true`, otherwise the inverse block is returned.

**Params**

* `array` **{Array}**
* `value` **{any}**
* `options` **{Object}**
* `returns` **{String}**

**Example**

```handlebars
<!-- array: ['a', 'b', 'c'] -->
{{#filter array "foo"}}AAA{{else}}BBB{{/filter}}
<!-- results in: 'BBB' -->
```

## {{first}}

Returns the first item, or first `n` items of an array.

**Params**

* `array` **{Array}**
* `n` **{Number}**: Number of items to return, starting at `0`.
* `returns` **{Array}**

**Example**

```handlebars
{{first "['a', 'b', 'c', 'd', 'e']" 2}}
<!-- results in: '["a", "b"]' -->
```

## {{forEach}}

Iterates over each item in an array and exposes the current item in the array as context to the inner block. In addition to the current array item, the helper exposes the following variables to the inner block:

* `index`
* `total`
* `isFirst`
* `isLast`
Also, `@index` is exposed as a private variable, and additional
private variables may be defined as hash arguments.

**Params**

* `array` **{Array}**
* `returns` **{String}**

**Example**

```handlebars
<!-- accounts = [
{'name': 'John', 'email': 'john@example.com'},
{'name': 'Malcolm', 'email': 'malcolm@example.com'},
{'name': 'David', 'email': 'david@example.com'}
] -->

{{#forEach accounts}}
  <a href="mailto:{{ email }}" title="Send an email to {{ name }}">
    {{ name }}
  </a>{{#unless isLast}}, {{/unless}}
{{/forEach}}
```

## {{inArray}}

Block helper that renders the block if an array has the given `value`. Optionally specify an inverse block to render when the array does not have the given value.

**Params**

* `array` **{Array}**
* `value` **{any}**
* `options` **{Object}**
* `returns` **{String}**

**Example**

```handlebars
<!-- array: ['a', 'b', 'c'] -->
{{#inArray array "d"}}
  foo
{{else}}
  bar
{{/inArray}}
<!-- results in: 'bar' -->
```

## {{isArray}}

Returns true if `value` is an es5 array.

**Params**

* `value` **{any}**: The value to test.
* `returns` **{Boolean}**

**Example**

```handlebars
{{isArray "abc"}}
<!-- results in: false -->

<!-- array: [1, 2, 3] -->
{{isArray array}}
<!-- results in: true -->
```

## {{itemAt}}

Returns the item from `array` at index `idx`.

**Params**

* `array` **{Array}**
* `idx` **{Number}**
* `returns` **{any}** `value`

**Example**

```handlebars
<!-- array: ['a', 'b', 'c'] -->
{{itemAt array 1}}
<!-- results in: 'b' -->
```

## {{join}}

Join all elements of array into a string, optionally using a given separator.

**Params**

* `array` **{Array}**
* `separator` **{String}**: The separator to use. Defaults to `,`.
* `returns` **{String}**

**Example**

```handlebars
<!-- array: ['a', 'b', 'c'] -->
{{join array}}
<!-- results in: 'a, b, c' -->

{{join array '-'}}
<!-- results in: 'a-b-c' -->
```

## {{equalsLength}}

Returns true if the the length of the given `value` is equal
to the given `length`. Can be used as a block or inline helper.

**Params**

* `value` **{Array|String}**
* `length` **{Number}**
* `options` **{Object}**
* `returns` **{String}**

## {{last}}

Returns the last item, or last `n` items of an array or string. Opposite of [first](#first).

**Params**

* `value` **{Array|String}**: Array or string.
* `n` **{Number}**: Number of items to return from the end of the array.
* `returns` **{Array}**

**Example**

```handlebars
<!-- var value = ['a', 'b', 'c', 'd', 'e'] -->

{{last value}}
<!-- results in: ['e'] -->

{{last value 2}}
<!-- results in: ['d', 'e'] -->

{{last value 3}}
<!-- results in: ['c', 'd', 'e'] -->
```

## {{length}}

Returns the length of the given string or array.

**Params**

* `value` **{Array|Object|String}**
* `returns` **{Number}**: The length of the value.

**Example**

```handlebars
{{length '["a", "b", "c"]'}}
<!-- results in: 3 -->

<!-- results in: myArray = ['a', 'b', 'c', 'd', 'e']; -->
{{length myArray}}
<!-- results in: 5 -->

<!-- results in: myObject = {'a': 'a', 'b': 'b'}; -->
{{length myObject}}
<!-- results in: 2 -->
```

## {{lengthEqual}}

Alias for [equalsLength](#equalsLength)

## {{map}}

Returns a new array, created by calling `function` on each element of the given `array`. For example,

**Params**

* `array` **{Array}**
* `fn` **{Function}**
* `returns` **{String}**

**Example**

```handlebars
<!-- array: ['a', 'b', 'c'], and "double" is a
fictitious function that duplicates letters -->
{{map array double}}
<!-- results in: '["aa", "bb", "cc"]' -->
```

## {{pluck}}

Map over the given object or array or objects and create an array of values from the given `prop`. Dot-notation may be used (as a string) to get nested properties.

**Params**

* `collection` **{Array|Object}**
* `prop` **{Function}**
* `returns` **{String}**

**Example**

```handlebars
// {{pluck items "data.title"}}
<!-- results in: '["aa", "bb", "cc"]' -->
```

## {{reverse}}

Reverse the elements in an array, or the characters in a string.

**Params**

* `value` **{Array|String}**
* `returns` **{Array|String}**: Returns the reversed string or array.

**Example**

```handlebars
<!-- value: 'abcd' -->
{{reverse value}}
<!-- results in: 'dcba' -->
<!-- value: ['a', 'b', 'c', 'd'] -->
{{reverse value}}
<!-- results in: ['d', 'c', 'b', 'a'] -->
```

## {{some}}

Block helper that returns the block if the callback returns true for some value in the given array.

**Params**

* `array` **{Array}**
* `iter` **{Function}**: Iteratee
* **{Options}**: Handlebars provided options object
* `returns` **{String}**

**Example**

```handlebars
<!-- array: [1, 'b', 3] -->
{{#some array isString}}
  Render me if the array has a string.
{{else}}
  Render me if it doesn't.
{{/some}}
<!-- results in: 'Render me if the array has a string.' -->
```

## {{sort}}

Sort the given `array`. If an array of objects is passed, you may optionally pass a `key` to sort on as the second argument. You may alternatively pass a sorting function as the second argument.

**Params**

* `array` **{Array}**: the array to sort.
* `key` **{String|Function}**: The object key to sort by, or sorting function.

**Example**

```handlebars
<!-- array: ['b', 'a', 'c'] -->
{{sort array}}
<!-- results in: '["a", "b", "c"]' -->
```

## {{sortBy}}

Sort an `array`. If an array of objects is passed, you may optionally pass a `key` to sort on as the second argument. You may alternatively pass a sorting function as the second argument.

**Params**

* `array` **{Array}**: the array to sort.
* `props` **{String|Function}**: One or more properties to sort by, or sorting functions to use.

**Example**

```handlebars
<!-- array: [{a: 'zzz'}, {a: 'aaa'}] -->
{{sortBy array "a"}}
<!-- results in: '[{"a":"aaa"}, {"a":"zzz"}]' -->
```

## {{withAfter}}

Use the items in the array _after_ the specified index as context inside a block. Opposite of [withBefore](#withBefore).

**Params**

* `array` **{Array}**
* `idx` **{Number}**
* `options` **{Object}**
* `returns` **{Array}**

**Example**

```handlebars
<!-- array: ['a', 'b', 'c', 'd', 'e'] -->
{{#withAfter array 3}}
  {{this}}
{{/withAfter}}
<!-- results in: "de" -->
```

## {{withBefore}}

Use the items in the array _before_ the specified index as context inside a block. Opposite of [withAfter](#withAfter).

**Params**

* `array` **{Array}**
* `idx` **{Number}**
* `options` **{Object}**
* `returns` **{Array}**

**Example**

```handlebars
<!-- array: ['a', 'b', 'c', 'd', 'e'] -->
{{#withBefore array 3}}
  {{this}}
{{/withBefore}}
<!-- results in: 'ab' -->
```

## {{withFirst}}

Use the first item in a collection inside a handlebars block expression. Opposite of [withLast](#withLast).

**Params**

* `array` **{Array}**
* `idx` **{Number}**
* `options` **{Object}**
* `returns` **{String}**

**Example**

```handlebars
<!-- array: ['a', 'b', 'c'] -->
{{#withFirst array}}
  {{this}}
{{/withFirst}}
<!-- results in: 'a' -->
```

## {{withGroup}}

Block helper that groups array elements by given group `size`.

**Params**

* `array` **{Array}**: The array to iterate over
* `size` **{Number}**: The desired length of each array "group"
* `options` **{Object}**: Handlebars options
* `returns` **{String}**

**Example**

```handlebars
<!-- array: ['a','b','c','d','e','f','g','h'] -->
{{#withGroup array 4}}
  {{#each this}}
    {{.}}
  {{each}}
  <br>
{{/withGroup}}
<!-- results in: -->
<!-- 'a','b','c','d'<br> -->
<!-- 'e','f','g','h'<br> -->
```

## {{withLast}}

Use the last item or `n` items in an array as context inside a block. Opposite of [withFirst](#withFirst).

**Params**

* `array` **{Array}**
* `idx` **{Number}**: The starting index.
* `options` **{Object}**
* `returns` **{String}**

**Example**

```handlebars
<!-- array: ['a', 'b', 'c'] -->
{{#withLast array}}
  {{this}}
{{/withLast}}
<!-- results in: 'c' -->
```

## {{withSort}}

Block helper that sorts a collection and exposes the sorted collection as context inside the block.

**Params**

* `array` **{Array}**
* `prop` **{String}**
* `options` **{Object}**: Specify `reverse="true"` to reverse the array.
* `returns` **{String}**

**Example**

```handlebars
<!-- array: ['b', 'a', 'c'] -->
{{#withSort array}}{{this}}{{/withSort}}
<!-- results in: 'abc' -->
```

## {{unique}}

Block helper that return an array with all duplicate values removed. Best used along with a [each](#each) helper.

**Params**

* `array` **{Array}**
* `options` **{Object}**
* `returns` **{Array}**

**Example**

```handlebars
<!-- array: ['a', 'a', 'c', 'b', 'e', 'e'] -->
{{#each (unique array)}}{{.}}{{/each}}
<!-- results in: 'acbe' -->
```

---

## File: docs/en-US/api/handlebars-helpers/comparison.md

# Comparison

## {{and}}

Helper that renders the block if **both** of the given values are truthy. If an inverse block is specified it will be rendered when falsy. Works as a block helper, inline helper or subexpression.

**Params**

* `a` **{any}**
* `b` **{any}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**

**Example**

```handlebars
<!-- {great: true, magnificent: true} -->
{{#and great magnificent}}A{{else}}B{{/and}}
<!-- results in: 'A' -->
```

## {{compare}}

Render a block when a comparison of the first and third
arguments returns true. The second argument is
the [arithemetic operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operators) to use. You may also
optionally specify an inverse block to render when falsy.

**Params**

* `a` **{}**
* `operator` **{}**: The operator to use. Operators must be enclosed in quotes: `">"`, `"="`, `"<="`, and so on.
* `b` **{}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**: Block, or if specified the inverse block is rendered if falsey.

## {{contains}}

Block helper that renders the block if `collection` has the given `value`, using strict equality (`===`) for comparison, otherwise the inverse block is rendered (if specified). If a `startIndex` is specified and is negative, it is used as the offset from the end of the collection.

**Params**

* `collection` **{Array|Object|String}**: The collection to iterate over.
* `value` **{any}**: The value to check for.
* `[startIndex=0]` **{Number}**: Optionally define the starting index.
* `options` **{Object}**: Handlebars provided options object.

**Example**

```handlebars
<!-- array = ['a', 'b', 'c'] -->
{{#contains array "d"}}
  This will not be rendered.
{{else}}
  This will be rendered.
{{/contains}}
```

## {{default}}

Returns the first value that is not undefined, otherwise the "default" value is returned.

**Params**

* `value` **{any}**
* `defaultValue` **{any}**
* `returns` **{String}**

## {{eq}}

Block helper that renders a block if `a` is **equal to** `b`.
If an inverse block is specified it will be rendered when falsy.
You may optionally use the `compare=""` hash argument for the
second value.

**Params**

* `a` **{String}**
* `b` **{String}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**: Block, or inverse block if specified and falsey.

## {{gt}}

Block helper that renders a block if `a` is **greater than** `b`.

If an inverse block is specified it will be rendered when falsy.
You may optionally use the `compare=""` hash argument for the
second value.

**Params**

* `a` **{String}**
* `b` **{String}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**: Block, or inverse block if specified and falsey.

## {{gte}}

Block helper that renders a block if `a` is **greater than or equal to** `b`.

If an inverse block is specified it will be rendered when falsy.
You may optionally use the `compare=""` hash argument for the
second value.

**Params**

* `a` **{String}**
* `b` **{String}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**: Block, or inverse block if specified and falsey.

## {{has}}

Block helper that renders a block if `value` has `pattern`.
If an inverse block is specified it will be rendered when falsy.

**Params**

* `val` **{any}**: The value to check.
* `pattern` **{any}**: The pattern to check for.
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**

## {{isEmpty}}

Inline, subexpression, or block helper that returns true (or the block) if the given collection is empty, or false (or the inverse block, if supplied) if the colleciton is not empty.

**Params**

* `collection` **{Object}**
* `options` **{Object}**
* `returns` **{String}**

**Example**

```handlebars
<!-- array: [] -->
{{#isEmpty array}}AAA{{else}}BBB{{/isEmpty}}
<!-- results in: 'AAA' -->

<!-- array: [] -->
{{isEmpty array}}
<!-- results in: true -->
```

## {{isFalsey}}

Returns true if the given `value` is falsey. Uses the [falsey](https://github.com/jonschlinkert/falsey)
library for comparisons. Please see that library for more information
or to report bugs with this helper.

**Params**

* `val` **{any}**
* `options` **{Options}**
* `returns` **{Boolean}**

## {{isTruthy}}

Returns true if the given `value` is truthy. Uses the [falsey](https://github.com/jonschlinkert/falsey)
library for comparisons. Please see that library for more information
or to report bugs with this helper.

**Params**

* `val` **{any}**
* `options` **{Options}**
* `returns` **{Boolean}**

## {{ifEven}}

Return true if the given value is an even number.

**Params**

* `number` **{Number}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**: Block, or inverse block if specified and falsey.

**Example**

```handlebars
{{#ifEven value}}
  render A
{{else}}
  render B
{{/ifEven}}
```

## {{ifNth}}

Conditionally renders a block if the remainder is zero when
`a` operand is divided by `b`. If an inverse block is specified
it will be rendered when the remainder is **not zero**.

**Params**

* **{}**: {Number}
* **{}**: {Number}
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**: Block, or inverse block if specified and falsey.

## {{ifOdd}}

Block helper that renders a block if `value` is **an odd number**. If an inverse block is specified it will be rendered when falsy.

**Params**

* `value` **{Object}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**: Block, or inverse block if specified and falsey.

**Example**

```handlebars
{{#ifOdd value}}
  render A
{{else}}
  render B
{{/ifOdd}}
```

## {{is}}

Block helper that renders a block if `a` is **equal to** `b`.
If an inverse block is specified it will be rendered when falsy.
Similar to [eq](#eq) but does not do strict equality.

**Params**

* `a` **{any}**
* `b` **{any}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**

## {{isnt}}

Block helper that renders a block if `a` is **not equal to** `b`.
If an inverse block is specified it will be rendered when falsy.
Similar to [unlessEq](#unlesseq) but does not use strict equality for
comparisons.

**Params**

* `a` **{String}**
* `b` **{String}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**

## {{lt}}

Block helper that renders a block if `a` is **less than** `b`.

If an inverse block is specified it will be rendered when falsy.
You may optionally use the `compare=""` hash argument for the
second value.

**Params**

* `context` **{Object}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**: Block, or inverse block if specified and falsey.

## {{lte}}

Block helper that renders a block if `a` is **less than or equal to** `b`.

If an inverse block is specified it will be rendered when falsy.
You may optionally use the `compare=""` hash argument for the
second value.

**Params**

* `a` **{Sring}**
* `b` **{Sring}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**: Block, or inverse block if specified and falsey.

## {{neither}}

Block helper that renders a block if **neither of** the given values
are truthy. If an inverse block is specified it will be rendered
when falsy.

**Params**

* `a` **{any}**
* `b` **{any}**
* `options` **{}**: Handlebars options object
* `returns` **{String}**: Block, or inverse block if specified and falsey.

## {{not}}

Returns true if `val` is falsey. Works as a block or inline helper.

**Params**

* `val` **{String}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**

## {{or}}

Block helper that renders a block if **any of** the given values is truthy. If an inverse block is specified it will be rendered when falsy.

**Params**

* `arguments` **{...any}**: Variable number of arguments
* `options` **{Object}**: Handlebars options object
* `returns` **{String}**: Block, or inverse block if specified and falsey.

**Example**

```handlebars
{{#or a b c}}
  If any value is true this will be rendered.
{{/or}}
```

## {{unlessEq}}

Block helper that always renders the inverse block **unless `a` is
is equal to `b`**.

**Params**

* `a` **{String}**
* `b` **{String}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**: Inverse block by default, or block if falsey.

## {{unlessGt}}

Block helper that always renders the inverse block **unless `a` is
is greater than `b`**.

**Params**

* `a` **{Object}**: The default value
* `b` **{Object}**: The value to compare
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**: Inverse block by default, or block if falsey.

## {{unlessLt}}

Block helper that always renders the inverse block **unless `a` is
is less than `b`**.

**Params**

* `a` **{Object}**: The default value
* `b` **{Object}**: The value to compare
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**: Block, or inverse block if specified and falsey.

## {{unlessGteq}}

Block helper that always renders the inverse block **unless `a` is
is greater than or equal to `b`**.

**Params**

* `a` **{any}**
* `b` **{any}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**: Block, or inverse block if specified and falsey.

## {{unlessLteq}}

Block helper that always renders the inverse block **unless `a` is
is less than or equal to `b`**.

**Params**

* `a` **{any}**
* `b` **{any}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**: Block, or inverse block if specified and falsey.

---

## File: docs/en-US/api/handlebars-helpers/core.md

# Built-in Helpers

https://handlebarsjs.com/guide/builtin-helpers.html

## {{if}}

Renders a block if the given condition is truthy.

**Params**

- `condition` **{Any}**: The condition to evaluate.

**Returns**: The content inside the block if the condition is truthy, otherwise returns nothing.

**Example**

```handlebars
{{#if condition}}
  This will be displayed if the condition is true.
{{/if}}
```

## {{unless}}

Renders a block if the given condition is falsy. This is the opposite of `if`.

**Params**

- `condition` **{Any}**: The condition to evaluate.

**Returns**: The content inside the block if the condition is falsy, otherwise returns nothing.

**Example**

```handlebars
{{#unless condition}}
  This will be displayed if the condition is false.
{{/unless}}
```

---

## {{each}}

Iterates over an array or object and renders a block for each item.

**Params**

- `collection` **{Array|Object}**: The array or object to iterate over.

**Returns**: Renders the block for each item in the collection.

**Example**

```handlebars
{{#each items}}
  <li>{{this}}</li>
{{/each}}
```

## {{with}}

Renders a block with a given context. It allows you to specify a context for the block, simplifying access to deeply nested properties.

**Params**

- `context` **{Any}**: The context to use within the block.

**Returns**: Renders the block with the provided context.

**Example**

```handlebars
{{#with person}}
  <p>Name: {{name}}</p>
  <p>Age: {{age}}</p>
{{/with}}
```

## {{lookup}}

Looks up the value of a specified key in an object. This helper is useful for accessing dynamic keys.

**Params**

- `context` **{Object}**: The object to look up the key from.
- `key` **{String|Number}**: The key to look up.

**Returns**: The value of the specified key in the object.

**Example**

```handlebars
{{lookup person "name"}}
<!-- If person is { name: "Alice", age: 30 }, it results in: "Alice" -->
```

---

## File: docs/en-US/api/handlebars-helpers/date.md

# Date

## {{dateFormat}}

The "dateFormat" helper in Handlebars is used to format a date using the day.js library. It takes two required arguments and an optional third argument for the timezone.

**Params**

* `datetime` **{String}**
* `format` **{String}**
* `timezone` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{dateFormat now "YYYY-MM-DD HH:mm:ss"}}
{{dateFormat now "YYYY-MM-DD HH:mm:ss" "Asia/Tokyo"}}
{{dateFormat now "YYYY-MM-DD HH:mm:ss" "UTC"}}
```

---

## File: docs/en-US/api/handlebars-helpers/html.md

# HTML

## {{qrcode}}

---

## File: docs/en-US/api/handlebars-helpers/i18n.md

# I18n

## {{t}}

**Params**

* `key` **{String}**
* `ns` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{t "Today"}}
{{t "Permissions" "@nocobase/plugin-acl"}}
```

---

## File: docs/en-US/api/handlebars-helpers/index.md

# Handlebars Helpers

| Category       | Description                         |
|-------------|-------------------------------------|
| [Core](./core.md)      | Built-in helpers        |
| [Array](./array.md)       | Operations and methods related to arrays       |
| [Comparison](./comparison.md) | Comparison operators and related methods       |
| [Date](./date.md)        | Operations and methods related to date and time handling |
| [HTML](./html.md)        | Content related to HTML documents and elements  |
| [I18n](./i18n.md)        | Support for internationalization and multilingual handling |
| [Math](./math.md)        | Mathematical functions and calculations       |
| [Number](./number.md)    | Content related to number handling and formatting |
| [Object](./object.md)    | Methods related to object operations and properties |
| [Path](./path.md)        | Path operations and content related to the file system |
| [Regex](./regex.md)      | Regular expressions and their usage            |
| [String](./string.md)    | Methods related to string manipulation and operations |
| [URL](./url.md)          | Content related to URL parsing and construction  |

---

## File: docs/en-US/api/handlebars-helpers/math.md

# Math

## {{abs}}

Return the magnitude of `a`.

**Params**

* `a` **{Number}**
* `returns` **{Number}**

## {{add}}

Return the sum of `a` plus `b`.

**Params**

* `a` **{Number}**
* `b` **{Number}**
* `returns` **{Number}**

## {{avg}}

Returns the average of all numbers in the given array.

**Params**

* `array` **{Array}**: Array of numbers to add up.
* `returns` **{Number}**

**Example**

```handlebars
{{avg "[1, 2, 3, 4, 5]"}}
<!-- results in: '3' -->
```

## {{ceil}}

Get the `Math.ceil()` of the given value.

**Params**

* `value` **{Number}**
* `returns` **{Number}**

## {{divide}}

Divide `a` by `b`

**Params**

* `a` **{Number}**: numerator
* `b` **{Number}**: denominator

## {{floor}}

Get the `Math.floor()` of the given value.

**Params**

* `value` **{Number}**
* `returns` **{Number}**

## {{minus}}

Return the difference of `a` minus `b`.

**Params**

* `a` **{Number}**
* `b` **{Number}**

## {{modulo}}

Get the remainder of a division operation.

**Params**

* `a` **{Number}**
* `b` **{Number}**
* `returns` **{Number}**

## {{multiply}}

Return the product of `a` times `b`.

**Params**

* `a` **{Number}**: factor
* `b` **{Number}**: multiplier
* `returns` **{Number}**

## {{plus}}

Add `a` by `b`.

**Params**

* `a` **{Number}**: factor
* `b` **{Number}**: multiplier

## {{random}}

Generate a random number between two values

**Params**

* `min` **{Number}**
* `max` **{Number}**
* `returns` **{String}**

## {{remainder}}

Get the remainder when `a` is divided by `b`.

**Params**

* `a` **{Number}**: a
* `b` **{Number}**: b

## {{round}}

Round the given number.

**Params**

* `number` **{Number}**
* `returns` **{Number}**

## {{subtract}}

Return the product of `a` minus `b`.

**Params**

* `a` **{Number}**
* `b` **{Number}**
* `returns` **{Number}**

## {{sum}}

Returns the sum of all numbers in the given array.

**Params**

* `array` **{Array}**: Array of numbers to add up.
* `returns` **{Number}**

**Example**

```handlebars
{{sum "[1, 2, 3, 4, 5]"}}
<!-- results in: '15' -->
```

## {{times}}

Multiply number `a` by number `b`.

**Params**

* `a` **{Number}**: factor
* `b` **{Number}**: multiplier
* `returns` **{Number}**

---

## File: docs/en-US/api/handlebars-helpers/number.md

# Number

## {{bytes}}

Format a number to it's equivalent in bytes. If a string is passed, it's length will be formatted and returned.

**Examples:**

* `'foo' => 3 B`
* `13661855 => 13.66 MB`
* `825399 => 825.39 kB`
* `1396 => 1.4 kB`

**Params**

* `number` **{Number|String}**
* `returns` **{String}**

## {{addCommas}}

Add commas to numbers

**Params**

* `num` **{Number}**
* `returns` **{Number}**

## {{phoneNumber}}

Convert a string or number to a formatted phone number.

**Params**

* `num` **{Number|String}**: The phone number to format, e.g. `8005551212`
* `returns` **{Number}**: Formatted phone number: `(800) 555-1212`

## {{toAbbr}}

Abbreviate numbers to the given number of `precision`. This is for
general numbers, not size in bytes.

**Params**

* `number` **{Number}**
* `precision` **{Number}**
* `returns` **{String}**

## {{toExponential}}

Returns a string representing the given number in exponential notation.

**Params**

* `number` **{Number}**
* `fractionDigits` **{Number}**: Optional. An integer specifying the number of digits to use after the decimal point. Defaults to as many digits as necessary to specify the number.
* `returns` **{Number}**

**Example**

```handlebars
{{toExponential number digits}};
```

## {{toFixed}}

Formats the given number using fixed-point notation.

**Params**

* `number` **{Number}**
* `digits` **{Number}**: (Optional) The number of digits to appear after the decimal point; this may be a value between 0 and 20. If this argument is omitted, it is treated as 0.
* `returns` **{String}**: A string representing the given number using fixed-point notation.

**Example**

```handlebars
{{toFixed "1.1234" 2}}
//=> '1.12'
```

## {{toFloat}}

**Params**

* `number` **{Number}**
* `returns` **{Number}**

## {{toInt}}

**Params**

* `number` **{Number}**
* `returns` **{Number}**

## {{toPrecision}}

Returns a string representing the `Number` object to the specified precision.

**Params**

* `number` **{Number}**
* `precision` **{Number}**: (Optional) An integer specifying the number of significant digits. If precison is not between 1 and 100 (inclusive), it will be coerced to `0`.
* `returns` **{String}**: A string representing a Number object in fixed-point or exponential notation rounded to precision significant digits.

**Example**

```handlebars
{{toPrecision "1.1234" 2}}
//=> '1.1'
```

---

## File: docs/en-US/api/handlebars-helpers/object.md

# Object

## {{extend}}

Extend the context with the properties of other objects.
A shallow merge is performed to avoid mutating the context.

**Params**

* `objects` **{Object}**: One or more objects to extend.
* `returns` **{Object}**

## {{forIn}}

Block helper that iterates over the properties of
an object, exposing each key and value on the context.

**Params**

* `context` **{Object}**
* `options` **{Object}**
* `returns` **{String}**

## {{forOwn}}

Block helper that iterates over the **own** properties of
an object, exposing each key and value on the context.

**Params**

* `obj` **{Object}**: The object to iterate over.
* `options` **{Object}**
* `returns` **{String}**

## {{toPath}}

Take arguments and, if they are string or number, convert them to a dot-delineated object property path.

**Params**

* `prop` **{String|Number}**: The property segments to assemble (can be multiple).
* `returns` **{String}**

## {{get}}

Use property paths (`a.b.c`) to get a value or nested value from
the context. Works as a regular helper or block helper.

**Params**

* `prop` **{String}**: The property to get, optionally using dot notation for nested properties.
* `context` **{Object}**: The context object
* `options` **{Object}**: The handlebars options object, if used as a block helper.
* `returns` **{String}**

## {{getObject}}

Use property paths (`a.b.c`) to get an object from
the context. Differs from the `get` helper in that this
helper will return the actual object, including the
given property key. Also, this helper does not work as a
block helper.

**Params**

* `prop` **{String}**: The property to get, optionally using dot notation for nested properties.
* `context` **{Object}**: The context object
* `returns` **{String}**

## {{hasOwn}}

Return true if `key` is an own, enumerable property of the given `context` object.

**Params**

* `key` **{String}**
* `context` **{Object}**: The context object.
* `returns` **{Boolean}**

**Example**

```handlebars
{{hasOwn context key}}
```

## {{isObject}}

Return true if `value` is an object.

**Params**

* `value` **{String}**
* `returns` **{Boolean}**

**Example**

```handlebars
{{isObject "foo"}}
//=> false
```

## {{JSONparse}}

Parses the given string using `JSON.parse`.

**Params**

* `string` **{String}**: The string to parse

**Example**

```handlebars
<!-- string: '{"foo": "bar"}' -->
{{JSONparse string}}
<!-- results in: { foo: 'bar' } -->
```

## {{JSONstringify}}

Stringify an object using `JSON.stringify`.

**Params**

* `obj` **{Object}**: Object to stringify
* `returns` **{String}**

**Example**

```handlebars
<!-- object: { foo: 'bar' } -->
{{JSONstringify object}}
<!-- results in: '{"foo": "bar"}' -->
```

## {{merge}}

Deeply merge the properties of the given `objects` with the
context object.

**Params**

* `object` **{Object}**: The target object. Pass an empty object to shallow clone.
* `objects` **{Object}**
* `returns` **{Object}**

## {{pick}}

Pick properties from the context object.

**Params**

* `properties` **{Array|String}**: One or more properties to pick.
* `context` **{Object}**
* `options` **{Object}**: Handlebars options object.
* `returns` **{Object}**: Returns an object with the picked values. If used as a block helper, the values are passed as context to the inner block. If no values are found, the context is passed to the inverse block.

---

## File: docs/en-US/api/handlebars-helpers/path.md

# Path

## {{absolute}}

Get the directory path segment from the given `filepath`.

**Params**

* `ext` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{absolute "docs/toc.md"}}
<!-- results in: 'docs' -->
```

## {{dirname}}

Get the directory path segment from the given `filepath`.

**Params**

* `ext` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{dirname "docs/toc.md"}}
<!-- results in: 'docs' -->
```

## {{relative}}

Get the relative filepath from `a` to `b`.

**Params**

* `a` **{String}**
* `b` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{relative a b}}
```

## {{basename}}

Get the file extension from the given `filepath`.

**Params**

* `ext` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{basename "docs/toc.md"}}
<!-- results in: 'toc.md' -->
```

## {{stem}}

Get the "stem" from the given `filepath`.

**Params**

* `filepath` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{stem "docs/toc.md"}}
<!-- results in: 'toc' -->
```

## {{extname}}

Get the file extension from the given `filepath`.

**Params**

* `filepath` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{extname "docs/toc.md"}}
<!-- results in: '.md' -->
```

## {{resolve}}

Resolve an absolute path from the given `filepath`.

**Params**

* `filepath` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{resolve "docs/toc.md"}}
<!-- results in: '/User/dev/docs/toc.md' -->
```

## {{segments}}

Get specific (joined) segments of a file path by passing a range of array indices.

**Params**

* `filepath` **{String}**: The file path to split into segments.
* `returns` **{String}**: Returns a single, joined file path.

**Example**

```handlebars
{{segments "a/b/c/d" "2" "3"}}
<!-- results in: 'c/d' -->

{{segments "a/b/c/d" "1" "3"}}
<!-- results in: 'b/c/d' -->

{{segments "a/b/c/d" "1" "2"}}
<!-- results in: 'b/c' -->
```

---

## File: docs/en-US/api/handlebars-helpers/regex.md

# Regex

## {{toRegex}}

Convert the given string to a regular expression.

**Params**

* `str` **{String}**
* `returns` **{RegExp}**

**Example**

```handlebars
{{toRegex "foo"}}
<!-- results in: /foo/ -->
```

## {{test}}

Returns true if the given `str` matches the given regex. A regex can be passed on the context, or using the [toRegex](#toregex) helper as a subexpression.

**Params**

* `str` **{String}**
* `returns` **{RegExp}**

**Example**

```handlebars
{{test "bar" (toRegex "foo")}}
<!-- results in: false -->
{{test "foobar" (toRegex "foo")}}
<!-- results in: true -->
{{test "foobar" (toRegex "^foo$")}}
<!-- results in: false -->
```

---

## File: docs/en-US/api/handlebars-helpers/string.md

# String

## {{append}}

Append the specified `suffix` to the given string.

**Params**

* `str` **{String}**
* `suffix` **{String}**
* `returns` **{String}**

**Example**

```handlebars
<!-- given that "item.stem" is "foo" -->
{{append item.stem ".html"}}
<!-- results in:  'foo.html' -->
```

## {{camelcase}}

camelCase the characters in the given `string`.

**Params**

* `string` **{String}**: The string to camelcase.
* `returns` **{String}**

**Example**

```handlebars
{{camelcase "foo bar baz"}};
<!-- results in:  'fooBarBaz' -->
```

## {{capitalize}}

Capitalize the first word in a sentence.

**Params**

* `str` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{capitalize "foo bar baz"}}
<!-- results in:  "Foo bar baz" -->
```

## {{capitalizeAll}}

Capitalize all words in a string.

**Params**

* `str` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{capitalizeAll "foo bar baz"}}
<!-- results in:  "Foo Bar Baz" -->
```

## {{center}}

Center a string using non-breaking spaces

**Params**

* `str` **{String}**
* `spaces` **{String}**
* `returns` **{String}**

## {{chop}}

Like trim, but removes both extraneous whitespace **and non-word characters** from the beginning and end of a string.

**Params**

* `string` **{String}**: The string to chop.
* `returns` **{String}**

**Example**

```handlebars
{{chop "_ABC_"}}
<!-- results in:  'ABC' -->

{{chop "-ABC-"}}
<!-- results in:  'ABC' -->

{{chop " ABC "}}
<!-- results in:  'ABC' -->
```

## {{dashcase}}

dash-case the characters in `string`. Replaces non-word characters and periods with hyphens.

**Params**

* `string` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{dashcase "a-b-c d_e"}}
<!-- results in:  'a-b-c-d-e' -->
```

## {{dotcase}}

dot.case the characters in `string`.

**Params**

* `string` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{dotcase "a-b-c d_e"}}
<!-- results in:  'a.b.c.d.e' -->
```

## {{downcase}}

Lowercase all of the characters in the given string. Alias for [lowercase](#lowercase).

**Params**

* `string` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{downcase "aBcDeF"}}
<!-- results in:  'abcdef' -->
```

## {{ellipsis}}

Truncates a string to the specified `length`, and appends it with an elipsis, `…`.

**Params**

* `str` **{String}**
* `length` **{Number}**: The desired length of the returned string.
* `returns` **{String}**: The truncated string.

**Example**

```handlebars
{{ellipsis (sanitize "<span>foo bar baz</span>"), 7}}
<!-- results in:  'foo bar…' -->
{{ellipsis "foo bar baz", 7}}
<!-- results in:  'foo bar…' -->
```

## {{hyphenate}}

Replace spaces in a string with hyphens.

**Params**

* `str` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{hyphenate "foo bar baz qux"}}
<!-- results in:  "foo-bar-baz-qux" -->
```

## {{isString}}

Return true if `value` is a string.

**Params**

* `value` **{String}**
* `returns` **{Boolean}**

**Example**

```handlebars
{{isString "foo"}}
<!-- results in:  'true' -->
```

## {{lowercase}}

Lowercase all characters in the given string.

**Params**

* `str` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{lowercase "Foo BAR baZ"}}
<!-- results in:  'foo bar baz' -->
```

## {{occurrences}}

Return the number of occurrences of `substring` within the given `string`.

**Params**

* `str` **{String}**
* `substring` **{String}**
* `returns` **{Number}**: Number of occurrences

**Example**

```handlebars
{{occurrences "foo bar foo bar baz" "foo"}}
<!-- results in:  2 -->
```

## {{pascalcase}}

PascalCase the characters in `string`.

**Params**

* `string` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{pascalcase "foo bar baz"}}
<!-- results in:  'FooBarBaz' -->
```

## {{pathcase}}

path/case the characters in `string`.

**Params**

* `string` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{pathcase "a-b-c d_e"}}
<!-- results in:  'a/b/c/d/e' -->
```

## {{plusify}}

Replace spaces in the given string with pluses.

**Params**

* `str` **{String}**: The input string
* `returns` **{String}**: Input string with spaces replaced by plus signs

**Example**

```handlebars
{{plusify "foo bar baz"}}
<!-- results in:  'foo+bar+baz' -->
```

## {{prepend}}

Prepends the given `string` with the specified `prefix`.

**Params**

* `str` **{String}**
* `prefix` **{String}**
* `returns` **{String}**

**Example**

```handlebars
<!-- given that "val" is "bar" -->
{{prepend val "foo-"}}
<!-- results in:  'foo-bar' -->
```

## {{raw}}

Render a block without processing mustache templates inside the block.

**Params**

* `options` **{Object}**
* `returns` **{String}**

**Example**

```handlebars
{{{{#raw}}}}
{{foo}}
{{{{/raw}}}}
<!-- results in:  '{{foo}}' -->
```

## {{remove}}

Remove all occurrences of `substring` from the given `str`.

**Params**

* `str` **{String}**
* `substring` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{remove "a b a b a b" "a "}}
<!-- results in:  'b b b' -->
```

## {{removeFirst}}

Remove the first occurrence of `substring` from the given `str`.

**Params**

* `str` **{String}**
* `substring` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{remove "a b a b a b" "a"}}
<!-- results in:  ' b a b a b' -->
```

## {{replace}}

Replace all occurrences of substring `a` with substring `b`.

**Params**

* `str` **{String}**
* `a` **{String}**
* `b` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{replace "a b a b a b" "a" "z"}}
<!-- results in:  'z b z b z b' -->
```

## {{replaceFirst}}

Replace the first occurrence of substring `a` with substring `b`.

**Params**

* `str` **{String}**
* `a` **{String}**
* `b` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{replace "a b a b a b" "a" "z"}}
<!-- results in:  'z b a b a b' -->
```

## {{reverse}}

Reverse a string.

**Params**

* `str` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{reverse "abcde"}}
<!-- results in:  'edcba' -->
```

## {{sentence}}

Sentence case the given string

**Params**

* `str` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{sentence "hello world. goodbye world."}}
<!-- results in:  'Hello world. Goodbye world.' -->
```

## {{snakecase}}

snake_case the characters in the given `string`.

**Params**

* `string` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{snakecase "a-b-c d_e"}}
<!-- results in:  'a_b_c_d_e' -->
```

## {{split}}

Split `string` by the given `character`.

**Params**

* `string` **{String}**: The string to split.
* `returns` **{String}** `character`: Default is an empty string.

**Example**

```handlebars
{{split "a,b,c" ","}}
<!-- results in:  ['a', 'b', 'c'] -->
```

## {{startsWith}}

Tests whether a string begins with the given prefix.

**Params**

* `prefix` **{String}**
* `testString` **{String}**
* `options` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{#startsWith "Goodbye" "Hello, world!"}}
  Whoops
{{else}}
  Bro, do you even hello world?
{{/startsWith}}
```

## {{titleize}}

Title case the given string.

**Params**

* `str` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{titleize "this is title case"}}
<!-- results in:  'This Is Title Case' -->
```

## {{trim}}

Removes extraneous whitespace from the beginning and end of a string.

**Params**

* `string` **{String}**: The string to trim.
* `returns` **{String}**

**Example**

```handlebars
{{trim " ABC "}}
<!-- results in:  'ABC' -->
```

## {{trimLeft}}

Removes extraneous whitespace from the beginning of a string.

**Params**

* `string` **{String}**: The string to trim.
* `returns` **{String}**

**Example**

```handlebars
{{trim " ABC "}}
<!-- results in:  'ABC ' -->
```

## {{trimRight}}

Removes extraneous whitespace from the end of a string.

**Params**

* `string` **{String}**: The string to trim.
* `returns` **{String}**

**Example**

```handlebars
{{trimRight " ABC "}}
<!-- results in:  ' ABC' -->
```

## {{truncate}}

Truncate a string to the specified `length`. Also see [ellipsis](#ellipsis).

**Params**

* `str` **{String}**
* `limit` **{Number}**: The desired length of the returned string.
* `suffix` **{String}**: Optionally supply a string to use as a suffix to denote when the string has been truncated. Otherwise an ellipsis (`…`) will be used.
* `returns` **{String}**: The truncated string.

**Example**

```handlebars
truncate("foo bar baz", 7);
<!-- results in:  'foo bar' -->
truncate(sanitize("<span>foo bar baz</span>", 7));
<!-- results in:  'foo bar' -->
```

## {{truncateWords}}

Truncate a string to have the specified number of words. Also see [truncate](#truncate).

**Params**

* `str` **{String}**
* `limit` **{Number}**: The desired length of the returned string.
* `suffix` **{String}**: Optionally supply a string to use as a suffix to denote when the string has been truncated.
* `returns` **{String}**: The truncated string.

**Example**

```handlebars
truncateWords("foo bar baz", 1);
<!-- results in:  'foo…' -->
truncateWords("foo bar baz", 2);
<!-- results in:  'foo bar…' -->
truncateWords("foo bar baz", 3);
<!-- results in:  'foo bar baz' -->
```

## {{upcase}}

Uppercase all of the characters in the given string. Alias for [uppercase](#uppercase).

**Params**

* `string` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{upcase "aBcDeF"}}
<!-- results in:  'ABCDEF' -->
```

## {{uppercase}}

Uppercase all of the characters in the given string. If used as a block helper it will uppercase the entire block. This helper does not support inverse blocks.

**Params**

* `str` **{String}**: The string to uppercase
* `options` **{Object}**: Handlebars options object
* `returns` **{String}**

**Example**

```handlebars
{{uppercase "aBcDeF"}}
<!-- results in:  'ABCDEF' -->
```

---

## File: docs/en-US/api/handlebars-helpers/url.md

# URL

## {{encodeURI}}

Encodes a Uniform Resource Identifier (URI) component
by replacing each instance of certain characters by
one, two, three, or four escape sequences representing
the UTF-8 encoding of the character.

**Params**

* `str` **{String}**: The un-encoded string
* `returns` **{String}**: The endcoded string

## {{escape}}

Escape the given string by replacing characters with escape sequences.
Useful for allowing the string to be used in a URL, etc.

**Params**

* `str` **{String}**
* `returns` **{String}**: Escaped string.

## {{decodeURI}}

Decode a Uniform Resource Identifier (URI) component.

**Params**

* `str` **{String}**
* `returns` **{String}**

## {{url_encode}}

Alias for [encodeURI](#encodeuri).

## {{url_decode}}

Alias for [decodeURI](#decodeuri).

## {{urlResolve}}

Take a base URL, and a href URL, and resolve them as a
browser would for an anchor tag.

**Params**

* `base` **{String}**
* `href` **{String}**
* `returns` **{String}**

## {{urlParse}}

Parses a `url` string into an object.

**Params**

* `str` **{String}**: URL string
* `returns` **{String}**: Returns stringified JSON

## {{stripQuerystring}}

Strip the query string from the given `url`.

**Params**

* `url` **{String}**
* `returns` **{String}**: the url without the queryString

## {{stripProtocol}}

Strip protocol from a `url`. Useful for displaying media that may have an 'http' protocol on secure connections.

**Params**

* `str` **{String}**
* `returns` **{String}**: the url with http protocol stripped

**Example**

```handlebars
<!-- url = 'http://foo.bar' -->
{{stripProtocol url}}
<!-- results in: '//foo.bar' -->
```

---

## File: docs/en-US/api/http/index.md

# Overview

HTTP API of NocoBase is designed based on Resource & Action, a superset of REST API. The operation includes but not limited to create, read, update and delete. Resource Action can be extended arbitrarily in NocoBase.

## Resource

In NocoBase, resource has two expressions:

- `<collection>`
- `<collection>.<association>`

<Alert>

- Collection is the set of all abstract data
- Association is the associated data of collection
- Resource includes both collection and collection.association

</Alert>

### Example

- `posts` Post
- `posts.user` Post user
- `posts.tags` Post tags

## Action

Action on resource is expressed by `:<action>`

- `<collection>:<action>`
- `<collection>.<association>:<action>`

Built-in global actions for collection or association:

- `create`
- `get`
- `list`
- `update`
- `destroy`
- `move`

Built-in association actions for association only:

- `set`
- `add`
- `remove`
- `toggle`

### Example

- `posts:create` Create post
- `posts.user:get` Get post user
- `posts.tags:add` Add tags to post (associate existing tags with post)

## Request URL

```bash
<GET|POST>   /api/<collection>:<action>
<GET|POST>   /api/<collection>:<action>/<collectionIndex>
<GET|POST>   /api/<collection>/<collectionIndex>/<association>:<action>
<GET|POST>   /api/<collection>/<collectionIndex>/<association>:<action>/<associationIndex>
```

### Example

posts resource

```bash
POST  /api/posts:create
GET   /api/posts:list
GET   /api/posts:get/1
POST  /api/posts:update/1
POST  /api/posts:destroy/1
```

posts.comments resource

```bash
POST  /api/posts/1/comments:create
GET   /api/posts/1/comments:list
GET   /api/posts/1/comments:get/1
POST  /api/posts/1/comments:update/1
POST  /api/posts/1/comments:destroy/1
```

posts.tags resource

```bash
POST  /api/posts/1/tags:create
GET   /api/posts/1/tags:get
GET   /api/posts/1/tags:list
POST  /api/posts/1/tags:update
POST  /api/posts/1/tags:destroy
POST  /api/posts/1/tags:add
GET   /api/posts/1/tags:remove
```

## Locate Resource

- Collection resource locates the data to be processed by `collectionIndex`, `collectionIndex` must be unique.
- Association resource locates the data to be processed by `collectionIndex` and `associationIndex` jointly, `associationIndex` may not be unique, but the joint index of `collectionIndex` and `associationIndex` must be unique.

When viewing details of association resource, the requested URL needs to provide both `<collectionIndex>` and `<associationIndex>`, `<collectionIndex>` is necessary as `<associationIndex>` may not be unique.

For example, `tables.fields` represents the fields of a data table:

```bash
GET   /api/tables/table1/fields/title
GET   /api/tables/table2/fields/title
```

Both table1 and table2 have the title field, title is unique in one table, but other tables may also have fields of that name.

## Request Parameters

Request parameters can be placed in the headers, parameters (query string), and body (GET requests do not have a body) of the request.

Some special request parameters:

- `filter` Data filtering, used in actions related to query.
- `filterByTk` Filter by tk field, used in actions to specify details of data.
- `sort` Sorting, used in actions related to query.
- `fields` Date to output, used in actions related to query
- `appends` Fields of additional relationship, used in actions related to query.
- `except` Exclude some fields (not to output), used in actions related to query.
- `whitelist` Fields whitelist, used in actions related to data creation and update.
- `blacklist` Fields blacklist, used in actions related to data creation and update.

### filter

Data filtering.

```bash
# simple
GET /api/posts?filter[status]=publish
# json string format is recommended, which requires encodeURIComponent encoding
GET /api/posts?filter={"status":"published"}

# filter operators
GET /api/posts?filter[status.$eq]=publish
GET /api/posts?filter={"status.$eq":"published"}

# $and
GET /api/posts?filter={"$and": [{"status.$eq":"published"}, {"title.$includes":"a"}]}
# $or
GET /api/posts?filter={"$or": [{"status.$eq":"pending"}, {"status.$eq":"draft"}]}

# association field
GET /api/posts?filter[user.email.$includes]=gmail
GET /api/posts?filter={"user.email.$includes":"gmail"}
```

[Click here for more information about filter operators](http-api/filter-operators)

### filterByTk

Filter by tk field. In the default settings:

- collection resource: tk is the primary key of the data table.
- association resource: tk is the targetKey field of the association.

```bash
GET   /api/posts:get?filterByTk=1&fields=name,title&appends=tags
```

### sort

Sorting. To sort in the descending order, put `-` in front of the field.

```bash
# Sort createAt field in the ascending order
GET /api/posts:get?sort=createdAt
# Sort createAt field in the descending order
GET /api/posts:get?sort=-createdAt
# Sort multiple fields jointly, createAt field descending, title A-Z ascending
GET /api/posts:get?sort=-createdAt,title
```

### fields

Data to output.

```bash
GET   /api/posts:list?fields=name,title

Response 200 (application/json)
{
  "data": [
    {
      "name": "",
      "title": ""
    }
  ],
  "meta": {}
}
```

### appends

Fields of additional relationship.

### except

Exclude some fields (not to output), used in actions related to query.

### whitelist

Whitelist.

```bash
POST  /api/posts:create?whitelist=title

{
  "title": "My first post",
  "date": "2022-05-19"      # The date field will be filtered out and not be written to the database
}
```

### blacklist

Blacklist.

```bash
POST  /api/posts:create?blacklist=date

# The date field will be filtered out and not be written to the database
{
  "title": "My first post"
}
```

## Request Response

Format of the response:

```ts
type ResponseResult = {
  data?: any; // Main data
  meta?: any; // Additional Data
  errors?: ResponseError[]; // Errors
};

type ResponseError = {
  code?: string;
  message: string;
};
```

### Example

View list:

```bash
GET /api/posts:list

Response 200 (application/json)

{
  data: [
    {
      id: 1
    }
  ],
  meta: {
    count: 1
    page: 1,
    pageSize: 1,
    totalPage: 1
  },
}
```

View details:

```bash
GET /api/posts:get/1

Response 200 (application/json)

{
  data: {
    id: 1
  }
}
```

Error:

```bash
POST /api/posts:create

Response 400 (application/json)

{
  errors: [
    {
      message: 'name must be required',
    },
  ],
}
```

---

## File: docs/en-US/api/http/rest-api.md

# REST API

HTTP API of NocoBase is a superset of REST API, and the standard CRUD API also supports the RESTful style.

## Collection Resources

### Create Collection

HTTP API

```bash
POST  /api/<collection>:create

{} # JSON body
```

REST API

```bash
POST  /api/<collection>

{} # JSON body
```

### View Collection List

HTTP API

```bash
GET   /api/<collection>:list
```

REST API

```bash
GET   /api/<collection>
```

### View Collection Details

HTTP API

```bash
GET   /api/<collection>:get?filterByTk=<collectionIndex>
GET   /api/<collection>:get/<collectionIndex>
```

REST API

```bash
GET   /api/<collection>/<collectionIndex>
```

### Update Collection

HTTP API

```bash
POST   /api/<collection>:update?filterByTk=<collectionIndex>

{} # JSON body

# Or
POST   /api/<collection>:update/<collectionIndex>

{} # JSON body
```

REST API

```bash
PUT    /api/<collection>/<collectionIndex>

{} # JSON body
```

### Delete Collection

HTTP API

```bash
POST      /api/<collection>:destroy?filterByTk=<collectionIndex>
# Or
POST      /api/<collection>:destroy/<collectionIndex>
```

REST API

```bash
DELETE    /api/<collection>/<collectionIndex>
```

## Association Resources

### Create Association

HTTP API

```bash
POST    /api/<collection>/<collectionIndex>/<association>:create

{} # JSON body
```

REST API

```bash
POST    /api/<collection>/<collectionIndex>/<association>

{} # JSON body
```

### View Association List

HTTP API

```bash
GET   /api/<collection>/<collectionIndex>/<association>:list
```

REST API

```bash
GET   /api/<collection>/<collectionIndex>/<association>
```

### View Association Details

HTTP API

```bash
GET   /api/<collection>/<collectionIndex>/<association>:get?filterByTk=<associationIndex>
# Or
GET   /api/<collection>/<collectionIndex>/<association>:get/<associationIndex>
```

REST API

```bash
GET   /api/<collection>/<collectionIndex>/<association>:get/<associationIndex>
```

### Update Association

HTTP API

```bash
POST   /api/<collection>/<collectionIndex>/<association>:update?filterByTk=<associationIndex>

{} # JSON body

# Or
POST   /api/<collection>/<collectionIndex>/<association>:update/<associationIndex>

{} # JSON body
```

REST API

```bash
PUT    /api/<collection>/<collectionIndex>/<association>:update/<associationIndex>

{} # JSON
```

### Delete Association

HTTP API

```bash
POST    /api/<collection>/<collectionIndex>/<association>:destroy?filterByTk=<associationIndex>
# Or
POST    /api/<collection>/<collectionIndex>/<association>:destroy/<associationIndex>
```

REST API

```bash
DELETE  /api/<collection>/<collectionIndex>/<association>/<associationIndex>
```

---

## File: docs/en-US/api/resourcer/action.md

# ctx.action

## Overview

After the resource operation request is parsed by [`resourceManager.middleware()`](./resource-manager#middleware), some important request parameters are stored in `ctx.action` for use by subsequent middleware.

## API

### resourceName

`ctx.action.resourceName`

The name of the resource. It can take two forms:

- `a` - Operates on resource `a`.
- `a.b` - Operates on associated object `b` of resource `a`.

### actionName

`ctx.action.actionName`

The name of the action.

### sourceId

`ctx.action.sourceId`

When the operation object is an associated object of the resource, it represents the primary key value of the corresponding resource. For example: when `resourceName` is `a.b`, `sourceId` represents the primary key value of `a`.

### params

Request parameters.

- URL parameters can be directly obtained from `ctx.action.params`.

```ts
const { filterByTk } = ctx.action.params;
```

- Request body parameters can be obtained using `ctx.action.params.values`.

### mergeParams()

Combines parameter content with request parameters.

```ts
ctx.action.mergeParams(
  {
    filter: {
      name: 'foo',
    },
    fields: ['id', 'name'],
    except: ['name'],
    sort: ['id'],
    page: 1,
    pageSize: 10,
    values: {
      name: 'foo',
    },
  },
  {
    filter: 'and',
    fields: 'union',
    except: 'union',
    sort: 'overwrite',
    page: 'overwrite',
    pageSize: 'overwrite',
    values: 'deepMerge',
  },
);

ctx.action.mergeParams(
  {
    filter: {},
  },
  {
    filter: (x, y) => {
      // ...
    },
  },
);
```

#### Signature

- `mergeParams(params: ActionParams, strategies: MergeStrategies = {})`

#### Type

```ts
export interface ActionParams {
  filterByTk?: any;
  fields?: string[];
  appends?: string[];
  except?: string[];
  whitelist?: string[];
  blacklist?: string[];
  filter?: FilterOptions;
  sort?: string[];
  page?: number;
  pageSize?: number;
  values?: any;
  [key: string]: any;
}

type MergeStrategyType =
  | 'merge'
  | 'deepMerge'
  | 'overwrite'
  | 'andMerge'
  | 'orMerge'
  | 'intersect'
  | 'union';
type MergeStrategyFunc = (x: any, y: any) => any;
export type MergeStrategy = MergeStrategyType | MergeStrategyFunc;
export interface MergeStrategies {
  [key: string]: MergeStrategy;
}
```

#### Details

| Property     | Type                                                     | Description                                                   |
| ------------ | -------------------------------------------------------- | ------------------------------------------------------------- |
| `params`     | [`ActionParams`](#actionparams)                          | Request parameters                                            |
| `strategies` | [`{ [key: string]: MergeStrategies }`](#mergestrategies) | Merge strategies for various fields in the request parameters |

Default `strategies`:

```ts
{
  filter: 'andMerge',
  fields: 'intersect',
  appends: 'union',
  except: 'union',
  whitelist: 'intersect',
  blacklist: 'intersect',
  sort: 'overwrite',
};
```

##### ActionParams

| Property        | Type       | Description                                                             |
| --------------- | ---------- | ----------------------------------------------------------------------- |
| `filterByTk`    | `any`      | The primary key value of the operated resource                          |
| `filter`        | `Filter`   | Filtering parameters, refer to [Filter Operators](./database/operators) |
| `fields`        | `string[]` | Fields to retrieve                                                      |
| `except`        | `string[]` | Fields to exclude                                                       |
| `appends`       | `string[]` | Related fields to append                                                |
| `whitelist`     | `string[]` | Field whitelist                                                         |
| `blacklist`     | `string[]` | Field blacklist                                                         |
| `sort`          | `string[]` | Sorting parameters                                                      |
| `page`          | `number`   | Current page                                                            |
| `pageSize`      | `number`   | Number of data items per page                                           |
| `values`        | `any`      | Request body                                                            |
| `[key: string]` | `any`      | Other extended configurations                                           |

##### MergeStrategies

Predefined merge strategies or custom merge functions.

Predefined merge strategies:

| Strategy Name | Description                                       |
| ------------- | ------------------------------------------------- |
| `merge`       | `Object.assign`                                   |
| `deepMerge`   | Deep traversal merge                              |
| `overwrite`   | Overwrite                                         |
| `andMerge`    | Merge filter parameters using the `$and` operator |
| `orMerge`     | Merge filter parameters using the `$or` operator  |
| `intersect`   | Intersection                                      |
| `union`       | Union                                             |

---

## File: docs/en-US/api/resourcer/middleware.md

# Middleware

It is similar to the middleware of Koa, but with more enhanced features for easy extensions.

The defined middleware can be inserted for use in multiple places, such as the resourcer, and it is up to the developer for when to invoke it.

## Constructor

**Signature**

- `constructor(options: Function)`
- `constructor(options: MiddlewareOptions)`

**Parameter**

| Name              | Type                 | Default | Description                            |
| ----------------- | -------------------- | ------- | -------------------------------------- |
| `options`         | `Function`           | -       | Handler function of middlware          |
| `options`         | `MiddlewareOptions ` | -       | Configuration items of middlware       |
| `options.only`    | `string[]`           | -       | Only the specified actions are allowed |
| `options.except`  | `string[]`           | -       | The specified actions are excluded     |
| `options.handler` | `Function`           | -       | Handler function                       |

**Example**

Simple definition:

```ts
const middleware = new Middleware((ctx, next) => {
  await next();
});
```

Definition with relevant parameters:

```ts
const middleware = new Middleware({
  only: ['create', 'update'],
  async handler(ctx, next) {
    await next();
  },
});
```

## Instance Methods

### `getHandler()`

Get the orchestrated handler functions.

**Example**

The following middleware will output `1` and then `2` when requested.

```ts
const middleware = new Middleware((ctx, next) => {
  console.log(1);
  await next();
});

middleware.use(async (ctx, next) => {
  console.log(2);
  await next();
});

app.resourcer.use(middleware.getHandler());
```

### `use()`

Add a middleware function to the current middleware. Used to provide extension points for the middleware. See `getHandler()` for the examples.

**Signature**

- `use(middleware: Function)`

**Parameter**

| Name         | Type       | Default | Description                        |
| ------------ | ---------- | ------- | ---------------------------------- |
| `middleware` | `Function` | -       | Handler function of the middleware |

### `disuse()`

Remove the middleware functions that have been added to the current middleware.

**Signature**

- `disuse(middleware: Function)`

**Parameter**

| Name         | Type       | Default | Description                        |
| ------------ | ---------- | ------- | ---------------------------------- |
| `middleware` | `Function` | -       | Handler function of the middleware |

**Example**

The following example will only output `1` when requested, the output of `2` in fn1 will not be executed.

```ts
const middleware = new Middleware((ctx, next) => {
  console.log(1);
  await next();
});

async function fn1(ctx, next) {
  console.log(2);
  await next();
}

middleware.use(fn1);

app.resourcer.use(middleware.getHandler());

middleware.disuse(fn1);
```

### `canAccess()`

Check whether the current middleware is to be invoked for a specific action, it is usually handled by the resourcer internally.

**Signature**

- `canAccess(name: string): boolean`

**Parameter**

| Name   | Type     | Default | Description        |
| ------ | -------- | ------- | ------------------ |
| `name` | `string` | -       | Name of the action |

## Other Exports

### `branch()`

Create a branch middleware for branching in the middleware.

**Signature**

- `branch(map: { [key: string]: Function }, reducer: Function, options): Function`

**Parameter**

| Name                     | Type                          | Default          | Description                                                                                                       |
| ------------------------ | ----------------------------- | ---------------- | ----------------------------------------------------------------------------------------------------------------- |
| `map`                    | `{ [key: string]: Function }` | -                | Mapping table of the branch handler function, key names are given by subsequent calculation functions when called |
| `reducer`                | `(ctx) => string`             | -                | Calculation function, it is used to calculate the key name of the branch based on the context                     |
| `options?`               | `Object`                      | -                | Configuration items of the branch                                                                                 |
| `options.keyNotFound?`   | `Function`                    | `ctx.throw(404)` | Handler function when key name is not found                                                                       |
| `options.handlerNotSet?` | `Function`                    | `ctx.throw(404)` | The function when no handler function is defined                                                                  |

**Example**

When authenticating user, determine what to do next according to the value of the `authenticator` parameter in the query section of the request URL.

```ts
app.resourcer.use(
  branch(
    {
      password: async (ctx, next) => {
        // ...
      },
      sms: async (ctx, next) => {
        // ...
      },
    },
    (ctx) => {
      return ctx.action.params.authenticator ?? 'password';
    },
  ),
);
```

---

## File: docs/en-US/api/resourcer/resource-manager.md

# ResourceManager

## Overview

`ResourceManager` is the resource management module of NocoBase, used to define resources and register operation methods for resources.

## Class Methods

### `define()`

Defines a resource.

```ts
app.resourceManager.define({
  name: 'auth',
  actions: {
    check: async (ctx, next) => {
      // ...
      await next();
    },
  },
});
```

#### Signature

- `define(options: ResourceOptions): Resource`

#### Type

```ts
export interface ResourceOptions {
  name: string;
  type?: ResourceType;
  actions?: {
    [key: string]: ActionType;
  };
  only?: Array<ActionName>;
  except?: Array<ActionName>;
  middleware?: MiddlewareType;
  middlewares?: MiddlewareType;
}

export type ResourceType =
  | 'single'
  | 'hasOne'
  | 'hasMany'
  | 'belongsTo'
  | 'belongsToMany';

export type ActionType = HandlerType | ActionOptions;
export type HandlerType = (
  ctx: ResourcerContext,
  next: () => Promise<any>,
) => any;
export interface ActionOptions {
  values?: any;
  fields?: string[];
  appends?: string[];
  except?: string[];
  whitelist?: string[];
  blacklist?: string[];
  filter?: FilterOptions;
  sort?: string[];
  page?: number;
  pageSize?: number;
  maxPageSize?: number;
  middleware?: MiddlewareType;
  middlewares?: MiddlewareType;
  handler?: HandlerType;
  [key: string]: any;
}
```

#### Details

##### ResourceOptions

| Property      | Type                                           | Description            | Default  |
| ------------- | ---------------------------------------------- | ---------------------- | -------- |
| `name`        | `string`                                       | Resource name          | -        |
| `type`        | `ResourceType`                                 | Resource type          | `single` |
| `actions`     | [`{ [key: string]: ActionType }`](#actiontype) | Actions                | -        |
| `only`        | `ActionName[]`                                 | Whitelist of `actions` | -        |
| `except`      | `ActionName[]`                                 | Blacklist of `actions` | -        |
| `middleware`  | `MiddlewareType`                               | Middleware             | -        |
| `middlewares` | `MiddlewareType`                               | Middlewares            | -        |

##### ActionType

There are two types of action methods:

- `HandlerType`

This type directly defines the operation method through middleware. Example:

```ts
app.resourceManager.define({
  name: 'users',
  actions: {
    updateProfile: async (ctx, next) => {
      // ...
      await next();
    },
  },
});
```

- `ActionOptions`

This type is mainly used to override the request parameters of a certain existing operation. Example:

```ts
app.resourceManager.define({
  name: 'users',
  actions: {
    list: {
      fields: [],
      filter: {},
      // ...
    },
  },
});
```

| Property        | Type             | Description                                                                 |
| --------------- | ---------------- | --------------------------------------------------------------------------- |
| `values`        | `any`            | Default values for the action request                                       |
| `filter`        | `Filter`         | Filtering parameters, refer to [Filter Operators](../database/operators.md) |
| `fields`        | `string[]`       | Fields to retrieve                                                          |
| `except`        | `string[]`       | Fields to exclude                                                           |
| `appends`       | `string[]`       | Related fields to append                                                    |
| `whitelist`     | `string[]`       | Field whitelist                                                             |
| `blacklist`     | `string[]`       | Field blacklist                                                             |
| `sort`          | `string[]`       | Sorting parameters                                                          |
| `page`          | `number`         | Current page                                                                |
| `pageSize`      | `number`         | Number of data items per page                                               |
| `maxPageSize`   | `number`         | Maximum number of data items per page                                       |
| `middleware`    | `MiddlewareType` | Middleware                                                                  |
| `middlewares`   | `MiddlewareType` | Middlewares                                                                 |
| `handler`       | `HandlerType`    | Method executed for the action                                              |
| `[key: string]` | `any`            | Other extended configurations                                               |

### `registerActionHandlers()`

Registers action methods.

#### Signature

- `registerActionHandler(name: ActionName, handler: HandlerType)`

#### Type

```ts
export type DefaultActionType =
  | 'list'
  | 'create'
  | 'get'
  | 'update'
  | 'destroy'
  | 'set'
  | 'add'
  | 'remove';
export type ActionName = DefaultActionType | Omit<string, DefaultActionType>;

export type HandlerType = (
  ctx: ResourcerContext,
  next: () => Promise<any>,
) => any;
```

#### Details

| Property  | Type          | Description                                                                                                                                                        |
| --------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `name`    | `ActionName`  | Action name.1. As a regular string, registers actions for all resources.2. In the form `<resource>:<action>`, registers actions for specific resources |
| `handler` | `HandlerType` | Middleware for the action                                                                                                                                          |

### `isDefined()`

Checks if a resource is defined.

#### Signature

- `isDefined(name: string)`

#### Details

| Property | Type     | Description   |
| -------- | -------- | ------------- |
| `name`   | `string` | Resource name |

### `import()`

Loads resource configurations from a specified directory.

```ts
// ./resources/demo.ts
export default {
  name: 'demo',
  actions: {
    async list(ctx, next) {
      // ...
      await next();
    },
  },
};

const resourceManager = new ResourceManager();
await resourceManager.import({
  directory: path.resolve(__dirname, 'resources'),
});
```

#### Signature

- `import(options: ImportOptions): Promise<Map<string, Resource>>`

#### Type

```ts
export interface ImportOptions {
  directory: string;
  extensions?: string[];
}
```

#### Details

| Property     | Type       | Description               | Default Value          |
| ------------ | ---------- | ------------------------- | ---------------------- |
| `directory`  | `string`   | Directory path            | -                      |
| `extensions` | `string[]` | Optional, file extensions | `['js', 'ts', 'json']` |

### `use()`

Adds `ResourceManager` middleware.

```ts
resourceManager.use(async () => {
  return async function (ctx, next) {
    // ...
    await next();
  };
});
```

#### Signature

- `use(middlewares: HandlerType | HandlerType[], options: ToposortOptions = {})`

#### Details

Refer to [Middleware](../../development/server/middleware.md).

### `middleware()`

Middleware for `ResourceManager`, parses request parameters (refer to [ctx.action](./action.md)) and executes operation methods.

---

## File: docs/en-US/api/resourcer/resource.md

# Resource

Resource is used to define resource instance. Resource instances managed by resourcer can be accessed through HTTP requests.

## Constructor

To create resource instance. Normally it is not used directly, but replaced by the call of the `define()` interface of resourcer.

**Signature**

- `constructor(options: ResourceOptions, resourcer: Resourcer)`

**Parameter**

| Name                  | Type                                 | Default    | Description                                                                                                     |
| --------------------- | ------------------------------------ | ---------- | --------------------------------------------------------------------------------------------------------------- |
| `options.name`        | `string`                             | -          | Name of the resource, corresponding to the resource address in the route of the URL                             |
| `options.type`        | `string`                             | `'single'` | Type of the resource, options are `'single'`, `'hasOne'`, `'hasMany'`, `'belongsTo'`, `'belongsToMany'`         |
| `options.actions`     | `Object`                             | -          | List of actions that can be taken on the resource, see the example for details                                  |
| `options.middlewares` | `MiddlewareType \| MiddlewareType[]` | -          | List of middlewares for any operational access to the resource that is defining，see the example for details    |
| `options.only`        | `ActionName[]`                       | `[]`       | Whitelist for global actions, only actions contained in the array (if `length > 0`) can be accessed             |
| `options.except`      | `ActionName[]`                       | `[]`       | Blacklist for global actions, all actions except those contained in the array (if `length > 0`) can be accessed |
| `resourcer`           | `Resourcer`                          | -          | The resourcer instance                                                                                          |

**Example**

```ts
app.resourcer.define({
  name: 'books',
  actions: {
    // Extended action
    publish(ctx, next) {
      ctx.body = 'ok';
    },
  },
  middleware: [
    // Extended middleware
    async (ctx, next) => {
      await next();
    },
  ],
});
```

## Instance Members

### `options`

Configuration items for the current resource.

### `resourcer`

The resourcer instance to which the resource belongs.

### `middlewares`

The registered middlewares.

### `actions`

The registered mapping table of actions.

### `except`

Actions that are excluded.

## Instance Methods

### `getName()`

Get the name of the current resource.

**Signature**

- `getName(): string`

**Example**

```ts
const resource = app.resourcer.define({
  name: 'books',
});

resource.getName(); // 'books'
```

### `getAction()`

Get action with the corresponding name.

**Signature**

- `getAction(name: string): Action`

**Parameter**

| Name   | Type     | Default | Description        |
| ------ | -------- | ------- | ------------------ |
| `name` | `string` | -       | Name of the action |

**Example**

```ts
const resource = app.resourcer.define({
  name: 'books',
  actions: {
    publish(ctx, next) {
      ctx.body = 'ok';
    },
  },
});

resource.getAction('publish'); // [Function: publish]
```

---

## File: docs/en-US/api/sdk/auth.md

# Auth

## Overview

The `Auth` class is primarily used for accessing user information on the client-side, as well as requesting user authentication-related APIs.

## Instance Properties

### `locale`

The language used by the current user.

### `role`

The role used by the current user.

### `token`

The API interface token.

### `authenticator`

The authenticator used for current user authentication. Refer to [User Authentication](../../handbook/auth/user.md).

## Class Methods

### `signIn()`

User login.

#### Signature

- `async signIn(values: any, authenticator?: string): Promise<AxiosResponse<any>>`

#### Details

| Parameter       | Type     | Description                             |
| --------------- | -------- | --------------------------------------- |
| `values`        | `any`    | Login API request parameters            |
| `authenticator` | `string` | Authenticator identifier used for login |

### `signUp()`

User registration.

#### Signature

- `async signUp(values: any, authenticator?: string): Promise<AxiosResponse<any>>`

#### Details

| Parameter       | Type     | Description                                    |
| --------------- | -------- | ---------------------------------------------- |
| `values`        | `any`    | Registration API request parameters            |
| `authenticator` | `string` | Authenticator identifier used for registration |

### `signOut()`

Log out.

#### Signature

- `async signOut(values: any, authenticator?: string): Promise<AxiosResponse<any>>`

#### Details

| Parameter       | Type     | Description                              |
| --------------- | -------- | ---------------------------------------- |
| `values`        | `any`    | Logout API request parameters            |
| `authenticator` | `string` | Authenticator identifier used for logout |

## 2. Official Technical Reference & Guides (nocobase/docs)

## File: README.md

# NocoBase V1 Documentation (Archived)

> **This repository is archived and no longer maintained.** V2 documentation lives in the main repository: [nocobase/nocobase](https://github.com/nocobase/nocobase) (under the `docs/` directory). For the latest docs, visit [docs.nocobase.com](https://docs.nocobase.com).

If you need to access the V1 documentation, you can run it locally:

## Local Development

```bash
git clone https://github.com/nocobase/docs.git
cd docs
yarn install

# Run English docs
yarn dev:en

# Run Chinese docs
yarn dev

# Run French docs
yarn dev:fr

# Run Japanese docs
yarn dev:ja

# Run Russian docs
yarn dev:ru
```

## Build

```bash
yarn build
```

Note: `yarn dev` and `yarn dev:en` cannot be run at the same time.

---

## File: package.json

{
  "name": "nocobase-docs",
  "version": "0.0.1",
  "description": "A static site based on dumi",
  "scripts": {
    "start": "npm run dev",
    "dev": "dumi dev",
    "dev:en": "cross-env DOC_LANG=en-US dumi dev",
    "dev:fr": "cross-env DOC_LANG=fr-FR dumi dev",
    "dev:ja": "cross-env DOC_LANG=ja-JP dumi dev",
    "dev:ru": "cross-env DOC_LANG=ru-RU dumi dev",
    "build": "dumi build",
    "build:en": "cross-env DOC_LANG=en-US dumi build",
    "build:fr": "cross-env DOC_LANG=fr-FR dumi build",
    "build:ja": "cross-env DOC_LANG=ja-JP dumi build",
    "build:ru": "cross-env DOC_LANG=ru-RU dumi build",
    "prepare": "husky install && dumi setup"
  },
  "authors": [],
  "license": "MIT",
  "commitlint": {
    "extends": [
      "@commitlint/config-conventional"
    ]
  },
  "lint-staged": {
    "*.{md,json}": [
      "prettier --write --no-error-on-unmatched-pattern"
    ]
  },
  "devDependencies": {
    "@alicloud/cdn20180510": "^4.2.2",
    "@commitlint/cli": "^18.2.0",
    "@commitlint/config-conventional": "^18.1.0",
    "ali-oss": "^6.1.0",
    "cross-env": "^7.0.3",
    "dumi": "^2.2.14",
    "husky": "^8.0.3",
    "lint-staged": "^15.0.2",
    "prettier": "^3.0.3"
  },
  "dependencies": {
    "@formulajs/formulajs": "^4.4.9",
    "@nocobase/client": "^0.21.0-alpha.6",
    "axios-mock-adapter": "1.22.0",
    "cytoscape": "^3.23.0",
    "dumi-theme-nocobase": "^0.2.31",
    "moment": "^2.30.1",
    "sucrase": "^3.0.0",
    "vditor": "^3.10.8"
  },
  "volta": {
    "node": "20.14.0",
    "yarn": "1.22.19"
  },
  "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
}

---

## File: tsconfig.json

{
  "compilerOptions": {
    "jsx": "react",
    "strict": true,
    "skipLibCheck": true,
    "noImplicitAny": false,
    "esModuleInterop": true,
    "baseUrl": "./",
    "paths": {
      "@@/*": [".dumi/tmp/*"]
    }
  },
  "include": [".dumirc.ts"]
}

---

## File: docs/en-US/components.md

# Components

---

## File: docs/en-US/index.md

# Index

<Navigate replace to="/welcome/introduction"></Navigate>

---

## File: docs/en-US/_partials/commercial-installation.md

## Installation

This plugin is a commercial plugin, which needs to be uploaded and activated through the plugin manager：

---

## File: docs/en-US/api/actions.md

# @nocobase/actions

## Overview

The `@nocobase/actions` package encapsulates frequently used CRUD-related methods. By simply registering it with the [ResourceManager](./resourcer/resource-manager), CRUD operation interfaces can be globally added to system resources.

### Basic Usage

```typescript
import * as actions from `@nocobase/actions`;

const resourceManager = new ResourceManager({
  // ...options
});

resourceManager.registerActionHandlers(actions);
```

## Action Methods

### create

Creates a resource. `POST /api/<resource>:create`.

```shell
curl "http://localhost:13000/api/users:create" \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{"username": "admin"}'
```

#### Request Body

| Parameter Name  | Type  | Description                                     |
| --------------- | ----- | ----------------------------------------------- |
| `[key: string]` | `any` | Key-value pairs representing resource fields    |

### list

Retrieves a list of resources. `GET /api/<resource>:list`.

```shell
curl -X GET http://localhost:13000/api/users:list
```

#### Parameters

| Parameter  | Type       | Description                                                        | Default |
| ---------- | ---------- | ------------------------------------------------------------------ | ------- |
| `filter`   | `Filter`   | Filtering parameters, see [Filter Operators](./database/operators) | -       |
| `fields`   | `string[]` | Fields to retrieve                                                 | -       |
| `except`   | `string[]` | Fields to exclude                                                  | -       |
| `appends`  | `string[]` | Related fields to append                                           | -       |
| `sort`     | `string[]` | Sorting parameters                                                 | -       |
| `paginate` | `boolean`  | Whether to use pagination                                          | `true`  |
| `page`     | `number`   | Current page number                                                | `1`     |
| `pageSize` | `number`   | Number of items per page                                           | `20`    |

### get

Retrieves a specific resource. `GET /api/<resource>:get`.

```shell
curl -X GET http://localhost:13000/api/users:get?filterByTk=1
```

#### Parameters

| Parameter    | Type               | Description                                                        | Default |
| ------------ | ------------------ | ------------------------------------------------------------------ | ------- |
| `filterByTk` | `number \| string` | Filter by primary key value                                        | -       |
| `filter`     | `Filter`           | Filtering parameters, see [Filter Operators](./database/operators) | -       |
| `fields`     | `string[]`         | Fields to retrieve                                                 | -       |
| `except`     | `string[]`         | Fields to exclude                                                  | -       |
| `appends`    | `string[]`         | Related fields to append                                           | -       |

### update

Updates one or more resources. `PUT /api/<resource>:update`.

```shell
curl "http://localhost:13000/api/users:update?filterByTk=1" \
  -X PUT \
  -H "Content-Type: application/json" \
  -d '{"username": "admin"}'
```

#### Parameters

| Parameter    | Type               | Description                                                        |
| ------------ | ------------------ | ------------------------------------------------------------------ |
| `filter`     | `Filter`           | Filtering parameters, see [Filter Operators](./database/operators) |
| `filterByTk` | `number \| string` | Filter by primary key value                                        |

*Note: At least one of `filter` or `filterByTk` must be provided.*

#### Request Body

| Parameter Name  | Type  | Description                                     |
| --------------- | ----- | ----------------------------------------------- |
| `[key: string]` | `any` | Key-value pairs representing resource fields    |

### destroy

Deletes one or more resources. `DELETE /api/<resource>:destroy`.

```shell
curl -X DELETE http://localhost:13000/api/users:destroy?filterByTk=1
```

#### Parameters

| Parameter    | Type               | Description                                                        |
| ------------ | ------------------ | ------------------------------------------------------------------ |
| `filter`     | `Filter`           | Filtering parameters, see [Filter Operators](./database/operators) |
| `filterByTk` | `number \| string` | Filter by primary key value                                        |

*Note: At least one of `filter` or `filterByTk` must be provided.*

### firstOrCreate

Retrieves or creates a resource. `POST /api/<resource>:firstOrCreate`.

```shell
curl "http://localhost:13000/api/users:firstOrCreate?filterKeys[]=username" \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{"username": "admin", "nickname": "Admin"}'
```

#### Parameters

| Parameter    | Type       | Description                                                |
| ------------ | ---------- | ---------------------------------------------------------- |
| `filterKeys` | `string[]` | Fields in the request body used to find existing resources |

#### Request Body

| Parameter Name  | Type  | Description                                     |
| --------------- | ----- | ----------------------------------------------- |
| `[key: string]` | `any` | Key-value pairs representing resource fields    |

### updateOrCreate

Updates or creates a resource. `POST /api/<resource>:updateOrCreate`.

```shell
curl "http://localhost:13000/api/users:updateOrCreate?filterKeys[]=username" \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{"username": "admin", "nickname": "Admin"}'
```

#### Parameters

| Parameter    | Type       | Description                                                |
| ------------ | ---------- | ---------------------------------------------------------- |
| `filterKeys` | `string[]` | Fields in the request body used to find existing resources |

#### Request Body

| Parameter Name  | Type  | Description                                     |
| --------------- | ----- | ----------------------------------------------- |
| `[key: string]` | `any` | Key-value pairs representing resource fields    |

### move

Moves resources, adjusting the order. Typically used for drag-and-drop sorting in pages. `POST /api/<resource>:move`.

```shell
curl -X POST "http://localhost:13000/api/users:move?sourceId=1&targetId=2"
```

#### Parameters

| Parameter     | Type                       | Description                                                 | Default |
| ------------- | -------------------------- | ----------------------------------------------------------- | ------- |
| `sourceId`    | `targetKey`                | ID of the element to move                                   | -       |
| `targetId`    | `targetKey`                | ID of the element to swap positions with                    | -       |
| `sortField`   | `string`                   | Name of the field where sorting is stored                   | `sort`  |
| `targetScope` | `string`                   | Sorting scope, a resource can be sorted by different scopes | -       |
| `sticky`      | `boolean`                  | Whether to stick the moved element                          | -       |
| `method`      | `insertAfter` \| `prepend` | Insertion method: whether to insert before                  |

### set

Sets associated objects for a resource. `POST /api/<resource>/<resourceKey>/<association>:set`.

```shell
curl "http://localhost:13000/api/users/1/roles:set" \
  -X POST \
  -H "Content-Type: application/json" \
  -d '["admin", "member"]'
```

#### Request Body

- `TargetKey | TargetKey[]` - Array of primary key values for associated objects.

### add

Adds associated objects to a resource. `POST /api/<resource>/<resourceKey>/<association>:add`.

```shell
curl "http://localhost:13000/api/users/1/roles:add" \
  -X POST \
  -H "Content-Type: application/json" \
  -d '["admin"]'
```

#### Request Body

- `TargetKey | TargetKey[]` - Array of primary key values for associated objects.

### remove

Removes associated objects from a resource. `POST /api/<resource>/<resourceKey>/<association>:remove`.

```shell
curl "http://localhost:13000/api/users/1/roles:remove" \
  -X POST \
  -H "Content-Type: application/json" \
  -d '["admin"]'
```

#### Request Body

- `TargetKey | TargetKey[]` - Array of primary key values for associated objects.

### toggle

Toggles associated objects for a resource, adding them if they don't exist, or removing them if they do. `POST /api/<resource>/<resourceKey>/<association>:toggle`.

```shell
curl "http://localhost:13000/api/users/1/roles:toggle" \
  -X POST \
  -H "Content-Type: application/json" \
  -d '["admin", "member"]'
```

#### Request Body

- `TargetKey | TargetKey[]` - Array of primary key values for associated objects.

---

## File: docs/en-US/api/cli.md

# @nocobase/cli

The NocoBase CLI is designed to help you develop, build, and deploy NocoBase applications.

<Alert>

NocoBase CLI supports *ts-node* and *node* two operation modes.

- ts-node mode (Default): Used for development environment, support real-time compilation, with relatively slow response
- node mode：Used for production environment, with quick response, but you need to execute `yarn nocobase build` to compile the entire source code first

</Alert>

## Instructions For Use

```bash
$ yarn nocobase -h

Usage: nocobase [command] [options]

Options:
  -h, --help

Commands:
  console
  db:auth               Verify if the database is successfully connected
  db:sync               Generate relevant data tables and fields through the configuration of collections
  install               Install
  start                 Start application in production environment
  build                 Compile and package
  clean                 Delete the compiled files
  dev                   Start application for development environment with real-time compilation
  doc                   Documentation development
  test                  Testing
  umi
  upgrade               Upgrade
  migrator              Data migration
  pm                    Plugin manager
  help
```

## Application in Scaffolding

`scripts` in the application scaffolding `package.json` is as below:

```json
{
  "scripts": {
    "dev": "nocobase dev",
    "start": "nocobase start",
    "clean": "nocobase clean",
    "build": "nocobase build",
    "test": "nocobase test",
    "pm": "nocobase pm",
    "postinstall": "nocobase postinstall"
  }
}
```

## Command Line Extensions

NocoBase CLI is built based on [commander](https://github.com/tj/commander.js). You can write the extended commands freely in `app/server/index.ts`:

```ts
const app = new Application(config);

app.command('hello').action(() => {});
```

or in the plugin:

```ts
class MyPlugin extends Plugin {
  beforeLoad() {
    this.app.command('hello').action(() => {});
  }
}
```

Run in the terminal:

```bash
$ yarn nocobase hello
```

## Built-in Commands

Sorted by frequency of use.

### `dev`

Start application and compile code in real time in development environment.

<Alert>
NocoBase is installed automatically if it is not installed (Refer to the `install` command).
</Alert>

```bash
Usage: nocobase dev [options]

Options:
  -p, --port [port]
  --client
  --server
  -h, --help
```

Example:

```bash
# Launch application for development environment, with real-time compilation
yarn nocobase dev
# Start the server side only
yarn nocobase dev --server
# Start the client side only
yarn nocobase dev --client
```

### `start`

Start application in production environment, the code needs *yarn build*.

<Alert>

- NocoBase is installed automatically if it is not installed (Refer to the `install` command).
- The source code needs to be re-packaged if it has any modification (Refer to the `build` command).

</Alert>

```bash
$ yarn nocobase start -h

Usage: nocobase start [options]

Options:
  -p, --port
  -s, --silent
  -h, --help
```

Example:

```bash
# Launch application for production environment
yarn nocobase start
```

### `install`

Install.

```bash
$ yarn nocobase install -h

Usage: nocobase install [options]

Options:
  -f, --force
  -c, --clean
  -s, --silent
  -l, --lang [lang]
  -e, --root-email <rootEmail>
  -p, --root-password <rootPassword>
  -n, --root-nickname [rootNickname]
  -h, --help
```

Example:

```bash
# Initial installation
yarn nocobase install -l zh-CN -e admin@nocobase.com -p admin123
# Delete all data tables from NocoBase and reinstall
yarn nocobase install -f -l zh-CN -e admin@nocobase.com -p admin123
# Clear database and reinstall
yarn nocobase install -c -l zh-CN -e admin@nocobase.com -p admin123
```

<Alert>

Difference between `-f/--force` and `-c/--clean`:

- `-f/--force` Delete data tables of NocoBase
- `-c/--clean` Clear database, all data tables are deleted

</Alert>

### `upgrade`

Upgrade.

```bash
yarn nocobase upgrade
```

### `test`

*jest* test, which supports all [jest-cli](https://jestjs.io/docs/cli) options, also supports `-c, --db-clean`.

```bash
$ yarn nocobase test -h

Usage: nocobase test [options]

Options:
  -c, --db-clean        Clear database before running all tests
  -h, --help
```

Example:

```bash
# Run all test files
yarn nocobase test
# Run all test files in the specified folder
yarn nocobase test packages/core/server
# Run all tests in the specified file
yarn nocobase test packages/core/database/src/__tests__/database.test.ts

# Clear database before running all tests
yarn nocobase test -c
yarn nocobase test packages/core/server -c
```

### `build`

The source code needs to be compiled and packaged before the code is deployed to the production environment; and you need to re-build the code if it has any modification.

```bash
# All packages
yarn nocobase build
# Specified packages
yarn nocobase build app/server app/client
```

### `clean`

Delete the compiled files.

```bash
yarn clean
# Equivalent to
yarn rimraf -rf packages/*/*/{lib,esm,es,dist}
```

### `doc`

Documentation development.

```bash
# Start the documentation
yarn doc  --lang=zh-CN # Equivalent to yarn doc dev
# Build the documentation, and output it to . /docs/dist/ directory by default
yarn doc build
# View the final result of the output documentation of dist
yarn doc serve --lang=zh-CN
```

### `db:auth`

Verify if the database is successfully connected.

```bash
$ yarn nocobase db:auth -h

Usage: nocobase db:auth [options]

Options:
  -r, --retry [retry]   Number of retries
  -h, --help
```

### `db:sync`

Generate relevant data tables and fields through the configuration of collections.

```bash
$ yarn nocobase db:sync -h

Usage: nocobase db:sync [options]

Options:
  -f, --force
  -h, --help   display help for command
```

### `migrator`

Data migration.

```bash
$ yarn nocobase migrator

Positional arguments:
  <command>
    up        Applies pending migrations
    down      Revert migrations
    pending   Lists pending migrations
    executed  Lists executed migrations
    create    Create a migration file
```

### `pm`

Plugin manager.

```bash
# Create plugin
yarn pm create hello
# Register plugin
yarn pm add hello
# Enable plugin
yarn pm enable hello
# Disable plugin
yarn pm disable hello
# Remove plugin
yarn pm remove hello
```

Not achieved yet:

```bash
# Upgrade plugin
yarn pm upgrade hello
# Publish plugin
yarn pm publish hello
```

### `umi`

`app/client` is built based on [umi](https://umijs.org/), you can run other relevant commands through `nocobase umi`.

```bash
# Generate the .umi cache needed for the development environment
yarn nocobase umi generate tmp
```

### `help`

The help command, you can also use the option parameter, `-h` and `--help`.

```bash
# View all cli
yarn nocobase help
# Use -h instead
yarn nocobase -h
# Or --help
yarn nocobase --help
# View options of command db:sync
yarn nocobase db:sync -h
```

---

## File: docs/en-US/api/index.md

# Overview

| Module                                                                                                | Package               | Description                     |
| ----------------------------------------------------------------------------------------------------- | --------------------- | ------------------------------- |
| [Server](/api/server/application)                                                                     | `@nocobase/server`    | Server-side application         |
| [Database](/api/database)                                                                             | `@nocobase/database`  | Database access layer           |
| [Resourcer](/api/resourcer/resource-manager)                                                          | `@nocobase/resourcer` | Resource and route mapping      |
| [ACL](/api/acl/acl)                                                                                   | `@nocobase/acl`       | Access Control                  |
| [Auth](/api/auth/auth-manager)                                                                        | `@nocobase/auth`      | User Authentication             |
| [Client](https://client.docs-cn.nocobase.com/core/application/application) | `@nocobase/client`    | Client-side application         |
| [Cache](/api/cache/cache-manager)                                                                     | `@nocobase/cache`     | Server-side cache               |
| [Logger](/api/logger)                                                                                 | `@nocobase/logger`    | Server-side logging             |
| [Telemetry](/api/telemetry/telemetry)                                                                 | `@nocobase/telemetry` | Server-side telemetry           |
| [CLI](/api/cli)                                                                                       | `@nocobase/cli`       | NocoBase Command Line Interface |
| [SDK](/api/sdk)                                                                                       | `@nocobase/sdk`       | NocoBase SDK                    |
| [Actions](/api/actions)                                                                               | `@nocobase/actions`   | Built-in resource operations    |
| [Test](/api/test/server)                                                                              | `@nocobase/test`      | Automated testing               |

---

## File: docs/en-US/api/logger.md

# @nocobase/logger

## Create Logger

### createLogger()

Creates a custom logger.

#### Signature

- `createLogger(options: LoggerOptions)`

#### Type

```ts
interface LoggerOptions
  extends Omit<winston.LoggerOptions, 'transports' | 'format'> {
  dirname?: string;
  filename?: string;
  format?: 'logfmt' | 'json' | 'delimiter' | 'console' | winston.Logform.Format;
  transports?: ('console' | 'file' | 'dailyRotateFile' | winston.transport)[];
}
```

#### Details

- `dirname`: Log directory
- `filename`: Log file name
- `format`: Log format
- `transports`: Log transports

### createSystemLogger()

Creates system runtime logs printed in a specified method. Refer to [Logger plugin - System log](../plugins/logger/index.md#system-log).

#### Signature

- `createSystemLogger(options: SystemLoggerOptions)`

#### Type

```ts
export interface SystemLoggerOptions extends LoggerOptions {
  seperateError?: boolean; // print error seperately, default true
}
```

#### Details

- `seperateError`: Whether to print `error` level logs separately

### app.createLogger()

#### Definition

```ts
class Application {
  createLogger(options: LoggerOptions) {
    const { dirname } = options;
    return createLogger({
      ...options,
      dirname: getLoggerFilePath(this.name || 'main', dirname || ''),
    });
  }
}
```

When `dirname` is a relative path, the log files will be output to the directory named after the current application.

### plugin.createLogger()

Usage is the same as `app.createLogger()`.

#### Definition

```ts
class Plugin {
  createLogger(options: LoggerOptions) {
    return this.app.createLogger(options);
  }
}
```

## Configuration

### getLoggerLevel()

`getLoggerLevel(): 'debug' | 'info' | 'warn' | 'error'`

Gets the log level currently configured in the system.

### getLoggerFilePath()

`getLoggerFilePath(...paths: string[]): string`

Concatenates directory paths based on the log directory currently configured in the system.

### getLoggerTransports()

`getLoggerTransports(): ('console' | 'file' | 'dailyRotateFile')[]`

Gets the log output methods currently configured in the system.

### getLoggerFormat()

`getLoggerFormat(): 'logfmt' | 'json' | 'delimiter' | 'console'`

Gets the log format currently configured in the system.

## Logger Transports

### Transports

Predefined output methods.

- `Transports.console`
- `Transports.file`
- `Transports.dailyRotateFile`

```ts
import { Transports } from '@nocobase/logger';

const transport = Transports.console({
  //...
});
```

## References

- [Development - Logger](../handbook/logger/index.md)
- [Logger Plugin](../plugins/logger/index.md)

---

## File: docs/en-US/api/acl/acl.md

# ACL

## Overview

`ACL` is the permission management module used in NocoBase, responsible for user role management, permission registration and authorization, as well as permission policy evaluation and access control.

### Concepts

- **Resource**: Collections, or custom resources can be registered. Refer to [`@nocobase/resourcer`](../resourcer/resource-manager.md).
- **Action**: An operation interface for a resource, such as create, read, update, delete, or other custom actions. Refer to [`@nocobase/actions`](../actions).
- **Strategy**: Configures global permissions for roles, such as permissions for resource operations like create, read, update, delete, import, export, and system permissions like configuring the user interface.
- **Snippet**: Defines a collection of operations, enabling unified management of operation permissions. Snippet identifiers can be matched using the [minimatch](https://github.com/isaacs/minimatch) rules.

## Class Methods

### `define()`

Defines a role.

#### Signature

- `define(options: DefineOptions): ACLRole`

#### Type Definitions

```typescript
export interface DefineOptions {
  role: string;
  strategy?: string | AvailableStrategyOptions;
  actions?: ResourceActionsOptions;
  snippets?: string[];
}

export interface AvailableStrategyOptions {
  displayName?: string;
  actions?: false | string | string[];
  allowConfigure?: boolean;
  resource?: '*';
}

export interface ResourceActionsOptions {
  [actionName: string]: RoleActionParams;
}

export interface RoleActionParams {
  fields?: string[];
  filter?: any;
  own?: boolean;
  whitelist?: string[];
  blacklist?: string[];
}
```

#### Details

##### DefineOptions

| Property   | Type                                                                | Description                                                       |
| ---------- | ------------------------------------------------------------------- | ----------------------------------------------------------------- |
| `role`     | `string`                                                            | Unique identifier for the role                                    |
| `strategy` | `string` \| [`AvailableStrategyOptions`](#availablestrategyoptions) | Optional, global access strategy for the role                     |
| `actions`  | [`{ [actionName: string]: RoleActionParams; }`](#roleactionparams)  | Optional, permission configuration for actions                    |
| `snippets` | `string[]`                                                          | Optional, defines snippets that the role has permission to access |

##### AvailableStrategyOptions

| Property         | Type                              | Description                                               |
| ---------------- | --------------------------------- | --------------------------------------------------------- |
| `displayName`    | `string`                          | Optional, display name for the strategy                   |
| `action`         | `false` \| `string` \| `string[]` | Optional, operation interfaces                            |
| `allowConfigure` | `boolean`                         | Optional, whether to allow configuring the user interface |
| `resource`       | `*`                               | Applies to all resources                                  |

##### RoleActionParams

| Property    | Type       | Description                                                                                            |
| ----------- | ---------- | ------------------------------------------------------------------------------------------------------ |
| `fields`    | `string[]` | Optional, fields of the data table to operate on                                                       |
| `filter`    | `any`      | Optional, filter parameters that must be met, only records that meet the conditions can be operated on |
| `own`       | `boolean`  | Optional, whether to operate only on records created by oneself                                        |
| `whitelist` | `string[]` | Optional, whitelist of fields that can be accessed, only fields in the whitelist can be accessed       |
| `blacklist` | `string[]` | Optional, blacklist of fields that cannot be accessed, fields in the blacklist cannot be accessed      |

### `can()`

Determines the permission to execute an action and returns the final action parameters. Returns `null` if no permission.

#### Signature

- `can(options: CanArgs): CanResult | null`

#### Type Definitions

```typescript
interface CanArgs {
  role: string;
  resource: string;
  action: string;
  ctx?: any;
}

interface CanResult {
  role: string;
  resource: string;
  action: string;
  params?: any;
}
```

#### Details

##### CanArgs

| Property   | Type     | Description               |
| ---------- | -------- | ------------------------- |
| `role`     | `string` | Role identifier           |
| `resource` | `string` | Resource identifier       |
| `action`   | `string` | Action identifier         |
| `ctx`      | `any`    | Optional, request context |

##### CanResult

| Property   | Type     | Description                 |
| ---------- | -------- | --------------------------- |
| `role`     | `string` | Role identifier             |
| `resource` | `string` | Resource identifier         |
| `action`   | `string` | Action identifier           |
| `params`   | `any`    | Optional, action parameters |

### `registerSnippet()`

Registers a snippet.

#### Signature

- `registerSnippet(snippet: SnippetOptions)`

#### Type Definitions

```typescript
export type SnippetOptions = {
  name: string;
  actions: string[];
};
```

#### Details

| Property  | Type       | Description                                                                                                                              |
| --------- | ---------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `name`    | `string`   | Snippet identifier, can be matched using the [minimatch](https://github.com/isaacs/minimatch) rules. E.g., `auth.auth` matches `auth.*`. |
| `actions` | `string[]` | Resource operations included in the snippet, in the format `resource:action`. E.g., `users:list`.                                        |

### `setAvailableAction()`

Sets allowed actions.

#### Signature

- `setAvailableAction(name: string, options: AvailableActionOptions = {})`

```typescript
export interface AvailableActionOptions {
  displayName?: string;
  aliases?: string[] | string;
  resource?: string;
  // Perform operations on new data
  onNewRecord?: boolean;
  // Allow configuring fields
  allowConfigureFields?: boolean;
}
```

#### Details

| Property               | Type                   | Description                                                                           |
| ---------------------- | ---------------------- | ------------------------------------------------------------------------------------- |
| `displayName`          | `string`               | Optional, display name for the action                                                 |
| `aliases`              | `string` \| `string[]` | Optional, action aliases. E.g., aliases for `get`, `list` operations are both `view`. |
| `resource`             | `string`               | Optional, resource                                                                    |
| `onNewRecord`          | `boolean`              | Optional, whether the operation applies to new data, such as create operation         |
| `allowConfigureFields` | `boolean`              | Optional, whether to allow configuring fields                                         |

### `setAvailableStrategy()`

Sets allowed strategies for actions.

#### Signature

- `setAvailableStrategy(name: string, options: AvailableStrategyOptions)`

Refer to [AvailableStrategyOptions](#availablestrategyoptions).

### `allow()`

Defines the conditions under which operations are allowed.

```typescript
acl.allow('plugins', '*', 'public');
```

#### Signature

- `allow(resourceName: string, actionNames: string[] | string, condition?: string | ConditionFunc)`

#### Type

```typescript
export type ConditionFunc = (ctx: any) => Promise<boolean> | boolean;
```

#### Details

| Parameter      | Type                        | Description                                                                 | Default  |
| -------------- | --------------------------- | --------------------------------------------------------------------------- | -------- |
| `resourceName` | `string`                    | Resource                                                                    | -        |
| `actionNames`  | `string` \| `string[]`      | Action                                                                      | -        |
| `condition`    | `string` \| `ConditionFunc` | Optional, predefined condition identifier, or condition evaluation function | `public` |

Predefined condition identifiers:

- `public`: Public interface.
- `loggedIn`: Allowed when the user is logged in.
- `allowConfigure`: Allowed when the current user role has permission to configure the user interface.

### `addFixedParams()`

Adds fixed parameters to operations, merging them with current request parameters.

```typescript
acl.addFixedParams('users', 'list', () => {
  return {
    filter: {
      id: {
        $eq: 1,
      },
    },
  };
});
```

#### Signature

- `addFixedParams(resource: string, action: string, merger: Merger)`

#### Type Definitions

```typescript
export type Merger = () => object;
```

#### Details

| Parameter  | Type     | Description                                               |
| ---------- | -------- | --------------------------------------------------------- |
| `resource` | `string` | Resource                                                  |
| `action`   | `string` | Action                                                    |
| `merger`   | `Merger` | Function returning the fixed parameter object to be added |

### `use()`

Adds the `ACL` middleware.

```typescript
acl.use(async () => {
  return async function (ctx, next) {
    // ...
    await next();
  };
});
```

#### Signature

- `use(fn: any, options?: ToposortOptions)`

#### Details

Refer to [Middleware](../../development/server/middleware).

### `middleware()`

NocoBase access control middleware.

---

## File: docs/en-US/api/auth/auth-manager.md

# AuthManager

## Overview

`AuthManager` is the user authentication management module in NocoBase, used for registering different types of user authentication.

### Basic Usage

```ts
const authManager = new AuthManager({
  // Key to retrieve the current authenticator identifier from the request header
  authKey: 'X-Authenticator',
});

// Set methods for storing and retrieving authenticators in AuthManager
authManager.setStorer({
  get: async (name: string) => {
    return db.getRepository('authenticators').find({ filter: { name } });
  },
});

// Register an authentication type
authManager.registerTypes('basic', {
  auth: BasicAuth,
  title: 'Password',
});

// Use authentication middleware
app.resourceManager.use(authManager.middleware());
```

### Concepts

- **Authentication type (`AuthType`)**: Different types of authentication, such as Password, SMS, OIDC, SAML, etc.
- **Authenticator**: An authenticator is a database-stored entity linked to a configuration record for a specific authentication type (`AuthType`). Multiple authenticators can exist for one authentication type, each offering diffrent authentications.
- **Authenticator name**: Unique identifier for an authenticator, used to determine the current authentication employed by the current request.

## Class Methods

### `constructor()`

Constructor, creates an instance of `AuthManager`.

#### Signature

- `constructor(options: AuthManagerOptions)`

#### Types

```ts
export interface JwtOptions {
  secret: string;
  expiresIn?: string;
}

export type AuthManagerOptions = {
  authKey: string;
  default?: string;
  jwt?: JwtOptions;
};
```

#### Details

##### AuthManagerOptions

| Attribute | Type                        | Description                                                                     | Default           |
| --------- | --------------------------- | ------------------------------------------------------------------------------- | ----------------- |
| `authKey` | `string`                    | Optional key to save the current authenticator identifier in the request header | `X-Authenticator` |
| `default` | `string`                    | Optional, default authenticator identifier                                      | `basic`           |
| `jwt`     | [`JwtOptions`](#jwtoptions) | Optional, configure if using JWT for authentication                             | -                 |

##### JwtOptions

| Attribute   | Type     | Description                       | Default           |
| ----------- | -------- | --------------------------------- | ----------------- |
| `secret`    | `string` | Token secret key                  | `X-Authenticator` |
| `expiresIn` | `string` | Optional, token expiration period | `7d`              |

### `setStorer()`

Set methods for storing and retrieving authenticator data.

#### Signature

- `setStorer(storer: Storer)`

#### Types

```ts
export interface Authenticator = {
  authType: string;
  options: Record<string, any>;
  [key: string]: any;
};

export interface Storer {
  get: (name: string) => Promise<Authenticator>;
}
```

#### Details

##### Authenticator

| Attribute  | Type                  | Description                          |
| ---------- | --------------------- | ------------------------------------ |
| `authType` | `string`              | Authentication type                  |
| `options`  | `Record<string, any>` | Authenticator-related configurations |

##### Storer

`Storer` is the interface for authenticator storage, containing one method.

- `get(name: string): Promise<Authenticator>` - Get authenticator by identifier. In NocoBase, the actual returned type is [AuthModel](../../handbook/auth/dev/api#authmodel).

### `registerTypes()`

Register authentication types.

#### Signature

- `registerTypes(authType: string, authConfig: AuthConfig)`

#### Types

```ts
export type AuthExtend<T extends Auth> = new (config: Config) => T;

type AuthConfig = {
  auth: AuthExtend<Auth>; // The authentication class.
  title?: string; // The display name of the authentication type.
};
```

#### Details

| Attribute | Type               | Description                                                          |
| --------- | ------------------ | -------------------------------------------------------------------- |
| `auth`    | `AuthExtend<Auth>` | Authentication type implementation, refer to [Auth](./auth.md)       |
| `title`   | `string`           | Optional. Title of the authentication type displayed on the frontend |

### `listTypes()`

Get a list of registered authentication types.

#### Signature

- `listTypes(): { name: string; title: string }[]`

#### Details

| Attribute | Type     | Description                      |
| --------- | -------- | -------------------------------- |
| `name`    | `string` | Authentication type identifier   |
| `title`   | `string` | Title of the authentication type |

### `get()`

Get authenticator.

#### Signature

- `get(name: string, ctx: Context)`

#### Details

| Attribute | Type      | Description              |
| --------- | --------- | ------------------------ |
| `name`    | `string`  | Authenticator identifier |
| `ctx`     | `Context` | Request context          |

### `middleware()`

Authentication middleware. Get the current authenticator and perform user authentication.

---

## File: docs/en-US/api/auth/auth.md

# Auth

## Overview

`Auth` is an abstract class for user authentication types, defining the interfaces required to complete user authentication. To extend new user authentication types, you need to inherit from the `Auth` class and implement its methods. The basic implementation can be referred to as [BaseAuth](./base-auth.md).

```ts
interface IAuth {
  user: Model;
  // Check the authentication status and return the current user.
  check(): Promise<Model>;
  signIn(): Promise<any>;
  signUp(): Promise<any>;
  signOut(): Promise<any>;
}

export abstract class Auth implements IAuth {
  abstract user: Model;
  abstract check(): Promise<Model>;
  // ...
}

class CustomAuth extends Auth {
  // check: Authentication
  async check() {
    // ...
  }
}
```

## Instance Properties

### `user`

Information of the authenticated user.

#### Signature

- `abstract user: Model`

## Class Methods

### `constructor()`

Constructor, creates an instance of `Auth`.

#### Signature

- `constructor(config: AuthConfig)`

#### Types

```ts
export type AuthConfig = {
  authenticator: Authenticator;
  options: {
    [key: string]: any;
  };
  ctx: Context;
};
```

#### Details

##### AuthConfig

| Attribute       | Type                                            | Description                                                                                                                 |
| --------------- | ----------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
| `authenticator` | [`Authenticator`](./auth-manager#authenticator) | Authenticator data model, the actual type in NocoBase applications is [AuthModel](../../handbook/auth/dev/api.md#authmodel) |
| `options`       | `Record<string, any>`                           | Authenticator-related configurations                                                                                        |
| `ctx`           | `Context`                                       | Request context                                                                                                             |

### `check()`

User authentication, returns user information. This is an abstract method that all authentication types must implement.

#### Signature

- `abstract check(): Promise<Model>`

### `signIn()`

User login.

#### Signature

- `signIn(): Promise<any>`

### `signUp()`

User registration.

#### Signature

- `signUp(): Promise<any>`

### `signOut()`

User logout.

#### Signature

- `signOut(): Promise<any>`

---

## File: docs/en-US/api/auth/base-auth.md

# BaseAuth

## Overview

`BaseAuth` inherits from the abstract class [Auth](./auth.md) and serves as the basic implementation for user authentication types, using JWT as the authentication method. In most cases, extending user authentication types can be achieved by inheriting from `BaseAuth` instead of directly inheriting from the `Auth` abstract class.

```ts
class BasicAuth extends BaseAuth {
  constructor(config: AuthConfig) {
    // Set user collection
    const userCollection = config.ctx.db.getCollection('users');
    super({ ...config, userCollection });
  }

  // User authentication logic, called by `auth.signIn`
  // Returns user data
  async validate() {
    const ctx = this.ctx;
    const { values } = ctx.action.params;
    // ...
    return user;
  }
}
```

## Class Methods

### `constructor()`

Constructor, creates an instance of `BaseAuth`.

#### Signature

- `constructor(config: AuthConfig & { userCollection: Collection })`

#### Details

| Parameter        | Type         | Description                                                                                                  |
| ---------------- | ------------ | ------------------------------------------------------------------------------------------------------------ |
| `config`         | `AuthConfig` | Refer to [Auth - AuthConfig](./auth.md#authconfig)                                                           |
| `userCollection` | `Collection` | User collection, e.g., `db.getCollection('users')`, refer to [DataBase - Collection](../database/collection) |

### `user()`

Accessor for setting and getting user information, defaulting to using the `ctx.state.currentUser` object.

#### Signature

- `set user()`
- `get user()`

### `check()`

Authenticates through the request token and returns user information.

### `signIn()`

User login, generates a token.

### `signUp()`

User registration.

### `signOut()`

User logout, token expiration.

### `validate()` \*

Core authentication logic, called by the `signIn` interface, to determine whether the user can successfully log in.

---

## File: docs/en-US/api/cache/cache-manager.md

# CacheManager

## Overview

CacheManager is based on [node-cache-manager](https://github.com/node-cache-manager/node-cache-manager) and provides caching module management for NocoBase. The built-in cache types are:

- **memory**: Provided by the default lru-cache of node-cache-manager.
- **redis**: Supported by node-cache-manager-redis-yet for Redis caching.

More types can be extended and registered through the API.

### Concepts

- **Store**: Defines a caching method, including a factory method for creating caches and other related configurations. Each caching method has a unique identifier provided during registration. The two built-in caching methods correspond to the unique identifiers `memory` and `redis`.

- **Store Factory Method**: Provided by `node-cache-manager` and related extension packages, used to create caches. Examples include `memory` provided by `node-cache-manager` by default, and `redisStore` provided by `node-cache-manager-redis-yet`. In this context, the object to be provided corresponds to [`StoreOptions`](#storeoptions), which is the first parameter of the `caching` method in `node-cache-manager`.

- **Cache**: A class encapsulated by NocoBase, providing methods related to cache usage. When actually using caching, operations are performed on instances of `Cache`. Each `Cache` instance has a unique identifier, which serves as a namespace for distinguishing different modules.

## Class Methods

### `constructor()`

#### Signature

- `constructor(options?: CacheManagerOptions)`

#### Type

```ts
export type CacheManagerOptions = Partial<{
  defaultStore: string;
  stores: {
    [storeType: string]: StoreOptions;
  };
}>;

type StoreOptions = {
  store?: 'memory' | FactoryStore<Store, any>;
  close?: (store: Store) => Promise<void>;
  // global config
  [key: string]: any;
};
```

#### Details

##### CacheManagerOptions

| Property       | Type                           | Description                                                                                                                                                          |
| -------------- | ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `defaultStore` | `string`                       | Unique identifier for the default cache type.                                                                                                                        |
| `stores`       | `Record<string, StoreOptions>` | Registers cache types. The key is the unique identifier for the cache type, and the value is an object containing the registration method and global configurations. |

##### StoreOptions

| Property        | Type                                   | Description                                                                                                                                                                                              |
| --------------- | -------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `store`         | `memory` \| `FactoryStore<Store, any>` | The store factory method, corresponding to the first parameter of the `caching` method.                                                                                                                  |
| `close`         | `(store: Store) => Promise<void>`      | Optional. For middleware that requires establishing a connection, such as Redis, provide a callback method for closing the connection. The parameter is the object returned by the store factory method. |
| `[key: string]` | `any`                                  | Other global configurations for the store, corresponding to the second parameter of the `caching` method.                                                                                                |

#### Default `options`

```ts
import { redisStore, RedisStore } from 'cache-manager-redis-yet';

const defaultOptions: CacheManagerOptions = {
  defaultStore: 'memory',
  stores: {
    memory: {
      store: 'memory',
      // global config
      max: 2000,
    },
    redis: {
      store: redisStore,
      close: async (redis: RedisStore) => {
        await redis.client.quit();
      },
    },
  },
};
```

The `options` parameter will be merged with the default options. Existing default options can be omitted. For example:

```ts
const cacheManager = new CacheManager({
  stores: {
    defaultStore: 'redis',
    redis: {
      // redisStore is already provided in the default options, so only need to provide redisStore configuration.
      url: 'redis://localhost:6379',
    },
  },
});
```

### `registerStore()`

Register a new caching method. Example:

```ts
import { redisStore } from 'cache-manager-redis-yet';

cacheManager.registerStore({
  // Unique identifier for the store
  name: 'redis',
  // Factory method for creating the store
  store: redisStore,
  // Callback method for closing the store connection
  close: async (redis: RedisStore) => {
    await redis.client.quit();
  },
  // Global configurations
  url: 'xxx',
});
```

#### Signature

- `registerStore(options: { name: string } & StoreOptions)`

### `createCache()`

Create a cache. Example:

```ts
await cacheManager.createCache({
  name: 'default', // Unique identifier for the cache
  store: 'memory', // Unique identifier for the store
  prefix: 'mycache', // Automatically adds the 'mycache:' prefix to cache keys, optional
  // Other store configurations, custom configurations that will be merged with global store configurations
  max: 2000,
});
```

#### Signature

- `createCache(options: { name: string; prefix?: string; store?: string; [key: string]: any }): Promise<Cache>`

#### Details

##### options

| Property        | Type     | Description                                        |
| --------------- | -------- | -------------------------------------------------- |
| `name`          | `string` | Unique identifier for the cache                    |
| `store`         | `string` | Unique identifier for the store                    |
| `prefix`        | `string` | Optional. Prefix automatically added to cache keys |
| `[key: string]` | `any`    | Other custom store configurations                  |

When `store` is omitted, the `defaultStore` will be used. In this case, the caching

---

## File: docs/en-US/api/cache/cache.md

# Cache

## Basic Methods

You can refer to the documentation of [node-cache-manager](https://github.com/node-cache-manager/node-cache-manager).

- `get()`
- `set()`
- `del()`
- `reset()`
- `wrap()`
- `mset()`
- `mget()`
- `mdel()`
- `keys()`
- `ttl()`

## Other Methods

### `wrapWithCondition()`

Similar to `wrap()`, but can decide whether to use caching based on conditions.

```ts
async wrapWithCondition<T>(
  key: string,
  fn: () => T | Promise<T>,
  options?: {
    // External parameter to control whether to use cache results
    useCache?: boolean;
    // Determine whether to cache based on data results
    isCacheable?: (val: unknown) => boolean | Promise<boolean>;
    ttl?: Milliseconds;
  },
): Promise<T> {
```

### `setValueInObject()`

When the cached content is an object, changes the value of a specific key.

```ts
async setValueInObject(key: string, objectKey: string, value: unknown)
```

### `getValueInObject()`

When the cached content is an object, retrieves the value of a specific key.

```ts
async getValueInObject(key: string, objectKey: string)
```

### `delValueInObject()`

When the cached content is an object, deletes a specific key.

```ts
async delValueInObject(key: string, objectKey: string)
```

---

## File: docs/en-US/api/client/application.md

# Application

## Constructor

### `constructor()`

Create an application instance.

**Signature**

- `constructor(options: ApplicationOptions)`

**Example**

```ts
const app = new Application({
  apiClient: {
    baseURL: process.env.API_BASE_URL,
  },
  dynamicImport: (name: string) => {
    return import(`../plugins/${name}`);
  },
});
```

## Methods

### use()

Add Providers, build-in Providers are:

- APIClientProvider
- I18nextProvider
- AntdConfigProvider
- SystemSettingsProvider
- PluginManagerProvider
- SchemaComponentProvider
- SchemaInitializerProvider
- BlockSchemaComponentProvider
- AntdSchemaComponentProvider
- ACLProvider
- RemoteDocumentTitleProvider

### render()

Component to render the App.

```ts
import { Application } from '@nocobase/client';

export const app = new Application({
  apiClient: {
    baseURL: process.env.API_BASE_URL,
  },
  dynamicImport: (name: string) => {
    return import(`../plugins/${name}`);
  },
});

export default app.render();
```

---

## File: docs/en-US/api/client/index.md

# Overview

test

---

## File: docs/en-US/api/client/router.md

# Router

## API

### Initial

```tsx | pure
const app = new Application({
  router: {
    type: 'browser', // type default value is `browser`
  },
});

// or
const app = new Application({
  router: {
    type: 'memory',
    initialEntries: ['/'],
  },
});
```

### add Route

#### basic

```tsx | pure
import { RouteObject } from 'react-router-dom';
const app = new Application();

const Hello = () => {
  return <div>Hello</div>;
};

// first argument is `name` of route, second argument is `RouteObject`
app.router.add('root', {
  path: '/',
  element: <Hello />,
});

app.router.add('root', {
  path: '/',
  Component: Hello,
});
```

#### Component is String

```tsx | pure
app.addComponents({
  Hello,
});
app.router.add('root', {
  path: '/',
  Component: 'Hello',
});
```

#### nested

```tsx | pure
import { Outlet } from 'react-router-dom';

const Layout = () => {
  return (
    <div>
      <Link to="/home">Home</Link>
      <Link to="/about">about</Link>

      <Outlet />
    </div>
  );
};

const Home = () => {
  return <div>Home</div>;
};

const About = () => {
  return <div>About</div>;
};

app.router.add('root', {
  element: <Layout />,
});
app.router.add('root.home', {
  path: '/home',
  element: <Home />,
});
app.router.add('root.about', {
  path: '/about',
  element: <About />,
});
```

It will generate the following routes:

```tsx | pure
{
  element: <Layout />,
  children: [
    {
      path: '/home',
      element: <Home />
    },
    {
      path: '/about',
      element: <About />
    }
  ]
}
```

### remove Route

```tsx | pure
// remove route by name
app.router.remove('root.home');
app.router.remove('hello');
```

#### Router in plugin

```tsx | pure
class MyPlugin extends Plugin {
  async load() {
    // add route
    this.app.router.add('hello', {
      path: '/hello',
      element: <div>hello</div>,
    });

    // remove route
    this.app.router.remove('world');
  }
}
```

## Example

```tsx
/**
 * defaultShowCode: true
 */
import React from 'react';
import { Link, Outlet } from 'react-router-dom';
import { Application } from '@nocobase/client';

const Home = () => <h1>Home</h1>;
const About = () => <h1>About</h1>;

const Layout = () => {
  return (
    <div>
      <div>
        <Link to={'/'}>Home</Link>, <Link to={'/about'}>About</Link>
      </div>
      <Outlet />
    </div>
  );
};

const app = new Application({
  router: {
    type: 'memory',
    initialEntries: ['/'],
  },
});

app.router.add('root', {
  element: <Layout />,
});

app.router.add('root.home', {
  path: '/',
  element: <Home />,
});

app.router.add('root.about', {
  path: '/about',
  element: <About />,
});

export default app.getRootComponent();
```

---

## File: docs/en-US/api/client/extensions/acl.md

# ACL

## Components

### `<ACLProvider />`

### `<ACLRolesCheckProvider />`

### `<ACLCollectionProvider />`

### `<ACLActionProvider />`

### `<ACLCollectionFieldProvider />`

### `<ACLMenuItemProvider />`

## Hooks

### `useACLContext()`

### `useACLRoleContext()`

### `useRoleRecheck()`

---

## File: docs/en-US/api/client/extensions/block-provider.md

# BlockProvider

## Kernel Methods

### ``

### `useBlockRequestContext()`

## Build-in BlockProvider Components

### `<CalendarBlockProvider />`

### ``

### ``

### ``

### `<FormBlockProvider />`

### `<FormFieldProvider />`

### ``

### `<KanbanBlockProvider />`

---

## File: docs/en-US/api/client/extensions/collection-manager.md

# CollectionManager

## Components

### CollectionManagerProvider

```jsx | pure
<CollectionManagerProvider
  interfaces={{}}
  collections={[]}
></CollectionManagerProvider>
```

### CollectionProvider

```jsx | pure
const collection = {
  name: 'tests',
  fields: [
    {
      type: 'string',
      name: 'title',
      interface: 'input',
      uiSchema: {
        type: 'string',
        'x-component': 'Input',
      },
    },
  ],
};
<CollectionProvider collection={collection}></CollectionProvider>;
```

If there is no collection parameter passed in, get the collection from CollectionManagerProvider with the corresponding name.

```jsx | pure
const collections = [
  {
    name: 'tests',
    fields: [
      {
        type: 'string',
        name: 'title',
        interface: 'input',
        uiSchema: {
          type: 'string',
          'x-component': 'Input',
        },
      },
    ],
  },
];
<CollectionManagerProvider collections={collections}>
  <CollectionProvider name={'tests'}></CollectionProvider>
</CollectionManagerProvider>;
```

### CollectionFieldProvider

```jsx | pure
const field = {
  type: 'string',
  name: 'title',
  interface: 'input',
  uiSchema: {
    type: 'string',
    'x-component': 'Input',
  },
};
<CollectionFieldProvider field={field}></CollectionFieldProvider>;
```

If there is no field parameter passed in, get the field from CollectionProvider with the corresponding name.

```jsx | pure
const collection = {
  name: 'tests',
  fields: [
    {
      type: 'string',
      name: 'title',
      interface: 'input',
      uiSchema: {
        type: 'string',
        'x-component': 'Input',
      },
    },
  ],
};
<CollectionProvider collection={collection}>
  <CollectionFieldProvider name={'title'}></CollectionFieldProvider>
</CollectionProvider>;
```

### CollectionField

Universal field component that needs to be used with `<CollectionProvider/>`, but only in schema scenarios. Get the field schema from CollectionProvider with the corresponding name. Extend the configuration via the schema where the CollectionField is located.

```ts
{
  name: 'title',
  'x-decorator': 'FormItem',
  'x-decorator-props': {},
  'x-component': 'CollectionField',
  'x-component-props': {},
  properties: {},
}
```

## Hooks

### useCollectionManager()

Use with `<CollectionManagerProvider/>`.

```jsx | pure
const { collections, get } = useCollectionManager();
```

### useCollection()

Use with `<CollectionProvider/>`.

```jsx | pure
const { name, fields, getField, findField, resource } = useCollection();
```

### useCollectionField()

Use with `<CollectionFieldProvider/>`.

```jsx | pure
const { name, uiSchema, resource } = useCollectionField();
```

The resource needs to be used with `<RecordProvider/>` to provide context of the record of the current data table row.

# CollectionManager

## Components

### CollectionManagerProvider

```jsx | pure
<CollectionManagerProvider
  interfaces={{}}
  collections={[]}
></CollectionManagerProvider>
```

### CollectionProvider

```jsx | pure
const collection = {
  name: 'tests',
  fields: [
    {
      type: 'string',
      name: 'title',
      interface: 'input',
      uiSchema: {
        type: 'string',
        'x-component': 'Input',
      },
    },
  ],
};
<CollectionProvider collection={collection}></CollectionProvider>;
```

If there is no collection parameter passed in, get the collection from CollectionManagerProvider with the corresponding name.

```jsx | pure
const collections = [
  {
    name: 'tests',
    fields: [
      {
        type: 'string',
        name: 'title',
        interface: 'input',
        uiSchema: {
          type: 'string',
          'x-component': 'Input',
        },
      },
    ],
  },
];
<CollectionManagerProvider collections={collections}>
  <CollectionProvider name={'tests'}></CollectionProvider>
</CollectionManagerProvider>;
```

### CollectionFieldProvider

```jsx | pure
const field = {
  type: 'string',
  name: 'title',
  interface: 'input',
  uiSchema: {
    type: 'string',
    'x-component': 'Input',
  },
};
<CollectionFieldProvider field={field}></CollectionFieldProvider>;
```

If there is no field parameter passed in, get the field from CollectionProvider with the corresponding name.

```jsx | pure
const collection = {
  name: 'tests',
  fields: [
    {
      type: 'string',
      name: 'title',
      interface: 'input',
      uiSchema: {
        type: 'string',
        'x-component': 'Input',
      },
    },
  ],
};
<CollectionProvider collection={collection}>
  <CollectionFieldProvider name={'title'}></CollectionFieldProvider>
</CollectionProvider>;
```

### CollectionField

Universal field component that needs to be used with `<CollectionProvider/>`, but only in schema scenarios. Get the field schema from CollectionProvider with the corresponding name. Extend the configuration via the schema where the CollectionField is located.

```ts
{
  name: 'title',
  'x-decorator': 'FormItem',
  'x-decorator-props': {},
  'x-component': 'CollectionField',
  'x-component-props': {},
  properties: {},
}
```

## Hooks

### useCollectionManager()

Use with `<CollectionManagerProvider/>`.

```jsx | pure
const { collections, get } = useCollectionManager();
```

### useCollection()

Use with `<CollectionProvider/>`.

```jsx | pure
const { name, fields, getField, findField, resource } = useCollection();
```

### useCollectionField()

Use with `<CollectionFieldProvider/>`.

```jsx | pure
const { name, uiSchema, resource } = useCollectionField();
```

The resource needs to be used with `<RecordProvider/>` to provide context of the record of the current data table row.

---

## File: docs/en-US/api/client/extensions/schema-component.md

# 适配的 Schema 组件

## Common

- DndContext
- SortableItem

## And Design

- Action
- BlockItem
- Calendar
- CardItem
- Cascader

---

## File: docs/en-US/api/client/schema-designer/schema-component.md

# SchemaComponent

## Core Components

### `<SchemaComponentProvider />`

### `<SchemaComponentOptions>`

### `<SchemaComponent>`

## Core Methods

### `createDesignable()`

### `useDesignable()`

### `useCompile()`

---

## File: docs/en-US/api/client/schema-designer/schema-initializer.md

# SchemaInitializer

Used for the initialization of various schemas. Newly added schema can be inserted anywhere in an existing schema node, including:

```ts
{
  properties: {
    // beforeBegin - Insert in front of the current node
    node1: {
      properties: {
        // afterBegin - Insert in front of the first child node of the current node
        // ...
        // beforeEnd - After the last child node of the current node
      },
    },
    // afterEnd - After the current node
  },
}
```

The core of SchemaInitializer includes `<SchemaInitializer.Button />` and `<SchemaInitializer.Item />` the two components. `<SchemaInitializer.Button />` is used to create the dropdown menu button of schema, and the options of the dropdown menu is `<SchemaInitializer.Item/>`.

### `<SchemaInitializerProvider />`

### `<SchemaInitializer.Button />`

### `<SchemaInitializer.Item/>`

---

## File: docs/en-US/api/client/schema-designer/schema-settings.md

# SchemaSettings

### `<SchemaSettings />`

### `<SchemaSettings.Item />`

### `<SchemaSettings.ItemGroup />`

### `<SchemaSettings.SubMenu />`

### `<SchemaSettings.Divider />`

### `<SchemaSettings.Remove />`

### `<SchemaSettings.SelectItem />`

### `<SchemaSettings.SwitchItem />`

### `<SchemaSettings.ModalItem />`

### `<SchemaSettings.ActionModalItem />`

### `<SchemaSettings.Template />`

### `<SchemaSettings.BlockTitleItem />`

---

## File: docs/en-US/api/data-source-manager/data-source.md

# DataSource (abstract)

The `DataSource` abstract class is used to represent a type of data source, which can be a database, API, etc.

## Members

### collectionManager

The CollectionManager instance of the data source, which needs to implement the [`ICollectionManager`](/api/data-source-manager/i-collection-manager) interface.

### resourceManager

The resourceManager instance of the data source, see: [`resourceManager`](/api/resourcer/resource-manager)

### acl

The ACL instance of the data source, see: [`ACL`](/api/acl/acl)

## API

### constructor()

Constructor, creates a `DataSource` instance.

#### Signature

- `constructor(options: DataSourceOptions)`

### init()

Initialization function, called immediately after `constructor`.

#### Signature

- `init(options: DataSourceOptions)`

### name

#### Signature

- `get name()`

Returns the instance name of the data source.

### middleware()

Gets the middleware of the DataSource, used to mount to the Server to receive requests.

### testConnection()

Static method, called during the test connection operation, can be used for parameter validation, specific logic is implemented by subclasses.

#### Signature

- `static testConnection(options?: any): Promise`

### load()

#### Signature

- `async load(options: any = {})`

The loading operation of the data source, logic is implemented by subclasses.

### createCollectionManager()

#### Signature
- `abstract createCollectionManager(options?: any): ICollectionManager`

Creates a CollectionManager instance for the data source, logic is implemented by subclasses.

### createResourceManager()

Creates a ResourceManager instance for the data source, subclasses can override the implementation, by default creates `ResourceManager` from `@nocobase/resourcer`.

### createACL()

- Creates an ACL instance for the DataSource, subclasses can override the implementation, by default creates `ACL` from `@nocobase/acl`.

---

## File: docs/en-US/api/data-source-manager/i-collection-manager.md

# ICollectionManager

The `ICollectionManager` interface is used to manage `Collection` instances of data sources.

## API

### registerFieldTypes()

Registers the field types in a `Collection`.

#### Signature

- `registerFieldTypes(types: Record<string, any>): void`

### registerFieldInterfaces()

Registers the `Interface` for a `Collection`.

#### Signature

- `registerFieldInterfaces(interfaces: Record<string, any>): void`

### registerCollectionTemplates()

Registers `Collection Templates`.

#### Signature

- `registerCollectionTemplates(templates: Record<string, any>): void`

### registerModels()

Registers `Models`.

#### Signature

- `registerModels(models: Record<string, any>): void`

### registerRepositories()

Registers `Repositories`.

#### Signature

- `registerRepositories(repositories: Record<string, any>): void`

### getRegisteredRepository()

Retrieves an instance of a registered repository.

#### Signature

- `getRegisteredRepository(key: string): IRepository`

### defineCollection()

Defines a `Collection`.

#### Signature

- `defineCollection(options: CollectionOptions): ICollection`

### extendCollection()

Modifies an existing `Collection` property.

#### Signature

- `extendCollection(collectionOptions: CollectionOptions, mergeOptions?: MergeOptions): ICollection`

### hasCollection()

Determines if a `Collection` exists.

#### Signature

- `hasCollection(name: string): boolean`

### getCollection()

Retrieves an instance of a `Collection`.

#### Signature

- `getCollection(name: string): ICollection`

### getCollections()

Retrieves all instances of `Collection`.

#### Signature

- `getCollections(): Array`

### getRepository()

Retrieves an instance of a `Repository`.

#### Signature

- `getRepository(name: string, sourceId?: string | number): IRepository`

### sync()

Synchronizes the data source, with the logic implemented by subclasses.

#### Signature

- `sync(): Promise<void>`

---

## File: docs/en-US/api/data-source-manager/i-collection.md

# ICollection

`ICollection` is an interface for data models, which includes information such as the model's name, fields, associations, etc.

```typescript
export interface ICollection {
  repository: IRepository;

  updateOptions(options: any): void;

  setField(name: string, options: any): IField;

  removeField(name: string): void;

  getFields(): Array<IField>;

  getField(name: string): IField;

  [key: string]: any;
}
```

## Members

### repository

The `Repository` instance to which `ICollection` belongs.

## API

### updateOptions()

Updates the properties of the `Collection`.

#### Signature

- `updateOptions(options: any): void`

### setField()

Sets a field of the `Collection`.

#### Signature

- `setField(name: string, options: any): IField`

### removeField()

Removes a field from the `Collection`.

#### Signature

- `removeField(name: string): void`

### getFields()

Retrieves all fields of the `Collection`.

#### Signature

- `getFields(): Array`

### getField()

Retrieves a field of the `Collection` by name.

#### Signature

- `getField(name: string): IField`

---

## File: docs/en-US/api/data-source-manager/i-field.md

# IField

`IField` defines the interface that fields need to implement.

```typescript
export type FieldOptions = {
  name: string;
  field: string;
  rawType: string;
  type: string;
  description?: string;
  interface?: string;
  uiSchema?: any;
  possibleTypes?: string[];
  defaultValue?: any;
  primaryKey: boolean;
  unique: boolean;
  allowNull?: boolean;
  autoIncrement?: boolean;
  [key: string]: any;
};

export interface IField {
  options: FieldOptions;
}
```


## Properties

### options

- **Type**: `FieldOptions`

---

## File: docs/en-US/api/data-source-manager/i-model.md

# IModel

The `IModel` interface defines the basic properties and methods of a model object.

```typescript
export interface IModel {
  toJSON: () => any;
}
```

## API

### toJSON()

Converts the model object to JSON format.

---

## File: docs/en-US/api/data-source-manager/i-repository.md

# IRepository

The `Repository` interface defines a series of model operation methods for adapting CRUD (Create, Read, Update, Delete) operations on data sources.

## API

### find()

Returns a list of models that match the query parameters.

#### Signature

- `find(options?: any): Promise`

### findOne()

Returns the first model that matches the query parameters. If multiple models match, only the first one is returned.

#### Signature

- `findOne(options?: any): Promise`

### count()

Returns the number of models that match the query parameters.

#### Signature

- `count(options?: any): Promise<Number>`

### findAndCount()

Returns both the list of models and the count of models that match the query parameters.

#### Signature

- `findAndCount(options?: any): Promise<[IModel[], Number]>`

### create()

Creates a model data object.

#### Signature

- `create(options: any): void`

### update()

Updates the model data object based on the query conditions.

#### Signature

- `update(options: any): void`

### destroy()

Deletes the model data object based on the query conditions.

#### Signature

- `destroy(options: any): void`

---

## File: docs/en-US/api/data-source-manager/index.md

# DataSourceManager

`DataSourceManager` is a management class for multiple `dataSource` instances.

## API

### add()
Adds a `dataSource` instance.

#### Signature

- `add(dataSource: DataSource, options: any = {}): Promise<void>`

### use()

Adds a global middleware to the `dataSource` instance.

### middleware()

Retrieves the middleware of the current `dataSourceManager` instance, which can be used to respond to HTTP requests.

### afterAddDataSource()

A hook function that is triggered after a new `dataSource` is added.

#### Signature

- `afterAddDataSource(hook: DataSourceHook)`

```typescript
type DataSourceHook = (dataSource: DataSource) => void;
```

### registerDataSourceType()

Registers the data source type and its class.

#### Signature

- `registerDataSourceType(type: string, dataSourceClass: typeof DataSource)`

### getDataSourceType()

Retrieves the data source class.

#### Signature

- `getDataSourceType(type: string): typeof DataSource`

### buildDataSourceByType()

Creates a data source instance based on the registered data source type and instance parameters.

#### Signature

- `buildDataSourceByType(type: string, options: any): DataSource`

---

## File: docs/en-US/api/database/collection.md

# Collection

## Overview

`Collection` is used to define the data model in the system, such as model name, fields, indexes, associations, and other information. It is usually called through the `collection` method of the `Database` instance as a proxy entry.

```javascript
const { Database } = require('@nocobase/database')

// Create database instance
const db = new Database({...});

// Define data model
db.collection({
  name: 'users',
  // Define model fields
  fields: [
    // Scalar field
    {
      name: 'name',
      type: 'string',
    },

    // Association field
    {
      name: 'profile',
      type: 'hasOne' // 'hasMany', 'belongsTo', 'belongsToMany'
    }
  ],
});
```

Refer to [Fields](/api/database/field) for more field types.

## Constructor

**Signature**

- `constructor(options: CollectionOptions, context: CollectionContext)`

**Parameter**

| Name                  | Type                                                        | Default | Description                                                                                                               |
| --------------------- | ----------------------------------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------- |
| `options.name`        | `string`                                                    | -       | Identifier of the collection                                                                                              |
| `options.tableName?`  | `string`                                                    | -       | Database table name, the value of `options.name` is used if not set                                                       |
| `options.fields?`     | `FieldOptions[]`                                            | -       | Definition of fields, refer to [Field](./field) for details                                                               |
| `options.model?`      | `string \| ModelStatic<Model>`                              | -       | Model type of Sequelize; in case `string` is used, this model name needs to be registered in the db before being called   |
| `options.repository?` | `string \| RepositoryType`                                  | -       | Data repository type; in case `string` is used, this repository type needs to be registered in the db before being called |
| `options.sortable?`   | `string \| boolean \| { name?: string; scopeKey?: string }` | -       | Configure which fields are sortable; not sortable by default                                                              |
| `options.autoGenId?`  | `boolean`                                                   | `true`  | Whether to automatically generate unique primary key; `true` by default                                                   |
| `context.database`    | `Database`                                                  | -       | The context database in which it resides                                                                                  |

**Example**

Create a table *posts*:

```ts
const posts = new Collection(
  {
    name: 'posts',
    fields: [
      {
        type: 'string',
        name: 'title',
      },
      {
        type: 'double',
        name: 'price',
      },
    ],
  },
  {
    // An existing database instance
    database: db,
  },
);
```

## Instance Members

### `options`

Initial parameters for data table configuration, which are consistent with the `options` parameter of the constructor.

### `context`

The contextual environment to which the current data table belongs, currently mainly the database instance.

### `name`

Name of the data table.

### `db`

The database instance to which it belongs.

### `filterTargetKey`

Name of the field that is used as the primary key.

### `isThrough`

Whether it is an intermediate table.

### `model`

Match the Model type of Sequelize.

### `repository`

Data repository instance.

## Field Configuration Methods

### `getField()`

Get a field object whose corresponding name has been defined in the data table.

**Signature**

- `getField(name: string): Field`

**Parameter**

| Name   | Type     | Default | Description       |
| ------ | -------- | ------- | ----------------- |
| `name` | `string` | -       | Name of the field |

**Example**

```ts
const posts = db.collection({
  name: 'posts',
  fields: [
    {
      type: 'string',
      name: 'title',
    },
  ],
});

const field = posts.getField('title');
```

### `setField()`

Set a field to the data table.

**Signature**

- `setField(name: string, options: FieldOptions): Field`

**Parameter**

| Name      | Type           | Default | Description                                                       |
| --------- | -------------- | ------- | ----------------------------------------------------------------- |
| `name`    | `string`       | -       | Name of the field                                                 |
| `options` | `FieldOptions` | -       | Configuration of the field, refer to [Field](./field) for details |

**Example**

```ts
const posts = db.collection({ name: 'posts' });

posts.setField('title', { type: 'string' });
```

### `setFields()`

Set multiple fields to the data table.

**Signature**

- `setFields(fields: FieldOptions[], resetFields = true): Field[]`

**Parameter**

| Name          | Type             | Default | Description                                                        |
| ------------- | ---------------- | ------- | ------------------------------------------------------------------ |
| `fields`      | `FieldOptions[]` | -       | Configuration of the fields, refer to [Field](./field) for details |
| `resetFields` | `boolean`        | `true`  | Whether to reset existing fields                                   |

**Example**

```ts
const posts = db.collection({ name: 'posts' });

posts.setFields([
  { type: 'string', name: 'title' },
  { type: 'double', name: 'price' },
]);
```

### `removeField()`

Remove a field object whose corresponding name has been defined in the data table.

**Signature**

- `removeField(name: string): void | Field`

**Parameter**

| Name   | Type     | Default | Description       |
| ------ | -------- | ------- | ----------------- |
| `name` | `string` | -       | Name of the field |

**Example**

```ts
const posts = db.collection({
  name: 'posts',
  fields: [
    {
      type: 'string',
      name: 'title',
    },
  ],
});

posts.removeField('title');
```

### `resetFields()`

Reset (Empty) fields of the data table.

**Signature**

- `resetFields(): void`

**Example**

```ts
const posts = db.collection({
  name: 'posts',
  fields: [
    {
      type: 'string',
      name: 'title',
    },
  ],
});

posts.resetFields();
```

### `hasField()`

Check if the data table has defined a field object with the corresponding name.

**Signature**

- `hasField(name: string): boolean`

**Parameter**

| Name   | Type     | Default | Description       |
| ------ | -------- | ------- | ----------------- |
| `name` | `string` | -       | Name of the field |

**Example**

```ts
const posts = db.collection({
  name: 'posts',
  fields: [
    {
      type: 'string',
      name: 'title',
    },
  ],
});

posts.hasField('title'); // true
```

### `findField()`

Find field objects in the data table that match the conditions.

**Signature**

- `findField(predicate: (field: Field) => boolean): Field | undefined`

**Parameter**

| Name        | Type                        | Default | Description   |
| ----------- | --------------------------- | ------- | ------------- |
| `predicate` | `(field: Field) => boolean` | -       | The condition |

**Example**

```ts
const posts = db.collection({
  name: 'posts',
  fields: [
    {
      type: 'string',
      name: 'title',
    },
  ],
});

posts.findField((field) => field.name === 'title');
```

### `forEachField()`

Iterate over field objects in the data table.

**Signature**

- `forEachField(callback: (field: Field) => void): void`

**Parameter**

| Name       | Type                     | Default | Description       |
| ---------- | ------------------------ | ------- | ----------------- |
| `callback` | `(field: Field) => void` | -       | Callback function |

**Example**

```ts
const posts = db.collection({
  name: 'posts',
  fields: [
    {
      type: 'string',
      name: 'title',
    },
  ],
});

posts.forEachField((field) => console.log(field.name));
```

## Index Configuration Methods

### `addIndex()`

Add data table index.

**Signature**

- `addIndex(index: string | string[] | { fields: string[], unique?: boolean,[key: string]: any })`

**Parameter**

| Name    | Type                                                         | Default | Description                   |
| ------- | ------------------------------------------------------------ | ------- | ----------------------------- |
| `index` | `string \| string[]`                                         | -       | Names of fields to be indexed |
| `index` | `{ fields: string[], unique?: boolean, [key: string]: any }` | -       | Full configuration            |

**Example**

```ts
const posts = db.collection({
  name: 'posts',
  fields: [
    {
      type: 'string',
      name: 'title',
    },
  ],
});

posts.addIndex({
  fields: ['title'],
  unique: true,
});
```

### `removeIndex()`

Remove data table index.

**Signature**

- `removeIndex(fields: string[])`

**Parameter**

| Name     | Type       | Default | Description                       |
| -------- | ---------- | ------- | --------------------------------- |
| `fields` | `string[]` | -       | Names of fields to remove indexes |

**Example**

```ts
const posts = db.collection({
  name: 'posts',
  fields: [
    {
      type: 'string',
      name: 'title',
    },
  ],
  indexes: [
    {
      fields: ['title'],
      unique: true,
    },
  ],
});

posts.removeIndex(['title']);
```

## Table Configuration Methods

### `remove()`

Remove data table.

**Signature**

- `remove(): void`

**Example**

```ts
const posts = db.collection({
  name: 'posts',
  fields: [
    {
      type: 'string',
      name: 'title',
    },
  ],
});

posts.remove();
```

## Database Operation Methods

### `sync()`

Synchronize the definitions in data table to the database. In addition to the default `Model.sync` logic in Sequelize, the data tables corresponding to the relational fields will also be handled together.

**Signature**

- `sync(): Promise<void>`

**Example**

```ts
const posts = db.collection({
  name: 'posts',
  fields: [
    {
      type: 'string',
      name: 'title',
    },
  ],
});

await posts.sync();
```

### `existsInDb()`

Check whether the data table exists in the database.

**Signature**

- `existsInDb(options?: Transactionable): Promise`

**Parameter**

| Name                   | Type          | Default | Description          |
| ---------------------- | ------------- | ------- | -------------------- |
| `options?.transaction` | `Transaction` | -       | Transaction instance |

**Example**

```ts
const posts = db.collection({
  name: 'posts',
  fields: [
    {
      type: 'string',
      name: 'title',
    },
  ],
});

const existed = await posts.existsInDb();

console.log(existed); // false
```

### `removeFromDb()`

**Signature**

- `removeFromDb(): Promise<void>`

**Example**

```ts
const books = db.collection({
  name: 'books',
});

//  Synchronize the table books to the database
await db.sync();

// Remove the table books from the database
await books.removeFromDb();
```

---

## File: docs/en-US/api/database/field.md

# Field

## Overview

Data table field management class (abstract class). It is also the base class for all field types, and any other field types are implemented by inheriting from this class.

Refer to [Extended Field Types](/development/server/collections-fields#extended-field-types) to see how to customize fields.

## Constructor

It is usually not called directly by the developer, but mainly through the `db.collection({ fields: [] })` method as a proxy entry.

Extended field is implemented mainly by inheriting the `Field` abstract class and registering it to a Database instance.

**Signature**

- `constructor(options: FieldOptions, context: FieldContext)`

**Parameter**

| Name                 | Type           | Default | Description                                                                  |
| -------------------- | -------------- | ------- | ---------------------------------------------------------------------------- |
| `options`            | `FieldOptions` | -       | Field configuration object                                                   |
| `options.name`       | `string`       | -       | Field name                                                                   |
| `options.type`       | `string`       | -       | Field type, corresponding to the name of the field type registered in the db |
| `context`            | `FieldContext` | -       | Field context object                                                         |
| `context.database`   | `Database`     | -       | Database instance                                                            |
| `context.collection` | `Collection`   | -       | Data table instance                                                          |

## Instance Members

### `name`

Field name.

### `type`

Field type.

### `dataType`

Data type of the field.

### `options`

Configuration parameters to initialize the field.

### `context`

Field context object.

## Configuration Methods

### `on()`

Quick definition method based on data table events. It is equivalent to `db.on(this.collection.name + '.' + eventName, listener)`.

It is usually not necessary to override this method when inheriting.

**Signature**

- `on(eventName: string, listener: (...args: any[]) => void)`

**Parameter**

| Name        | Type                       | Default | Description    |
| ----------- | -------------------------- | ------- | -------------- |
| `eventName` | `string`                   | -       | Event name     |
| `listener`  | `(...args: any[]) => void` | -       | Event listener |

### `off()`

Quick removal method based on data table events. It is equivalent to `db.off(this.collection.name + '.' + eventName, listener)`.

It is usually not necessary to override this method when inheriting.

**Signature**

- `off(eventName: string, listener: (...args: any[]) => void)`

**Parameter**

| Name        | Type                       | Default | Description    |
| ----------- | -------------------------- | ------- | -------------- |
| `eventName` | `string`                   | -       | Event name     |
| `listener`  | `(...args: any[]) => void` | -       | Event listener |

### `bind()`

The execution content that is triggered when a field is added to data table. Typically used to add data table event listeners and other processing.

The corresponding `super.bind()` method needs to be called first when inheriting.

**Signature**

- `bind()`

### `unbind()`

The execution content that is triggered when a field is removed from data table. Typically used to remove data table event listeners and other processing.

The corresponding `super.unbind()` method needs to be called first when inheriting.

**Signature**

- `unbind()`

### `get()`

Get the values of a configuration item of the field.

**Signature**

- `get(key: string): any`

**Parameter**

| Name  | Type     | Default | Description                    |
| ----- | -------- | ------- | ------------------------------ |
| `key` | `string` | -       | Name of the configuration item |

**Example**

```ts
const field = db.collection('users').getField('name');

// Get and return the values of the configuration item 'name'
console.log(field.get('name'));
```

### `merge()`

Merge the values of a configuration item of the field.

**Signature**

- `merge(options: { [key: string]: any }): void`

**Parameter**

| Name      | Type                     | Default | Description                     |
| --------- | ------------------------ | ------- | ------------------------------- |
| `options` | `{ [key: string]: any }` | -       | The configuration item to merge |

**Example**

```ts
const field = db.collection('users').getField('name');

field.merge({
  // Add an index configuration
  index: true,
});
```

### `remove()`

Remove a field from data table (from memory only).

**Example**

```ts
const books = db.getCollections('books');

books.getField('isbn').remove();

// really remove from db
await books.sync();
```

## Database Methods

### `removeFromDb()`

Remove a field from the database.

**Signature**

- `removeFromDb(options?: Transactionable): Promise<void>`

**Parameter**

| Name                   | Type          | Default | Description          |
| ---------------------- | ------------- | ------- | -------------------- |
| `options.transaction?` | `Transaction` | -       | Transaction instance |

### `existsInDb()`

Check if a field exists in the database.

**Signature**

- `existsInDb(options?: Transactionable): Promise`

**Parameter**

| Name                   | Type          | Default | Description          |
| ---------------------- | ------------- | ------- | -------------------- |
| `options.transaction?` | `Transaction` | -       | Transaction instance |

## Built-in Field Types

NocoBase has some built-in common field types, the corresponding type name can be used directly to specify the type of field upon definition. Fields of different types are configured differently, please refer to the list below.

The configuration items of all field types are passed through to Sequelize in addition to those described below. Therefore, all field configuration items supported by Sequelize can be used here (e.g. `allowNull`, `defaultValue`, etc.).

Moreover, server-side field types are mainly used for solving the problems of database storage and some algorithms, they are barely relevant to the field display types and the use of components in front-end. The front-end field types can be found in the corresponding tutorials.

### `'boolean'`

Boolean type.

**Example**

```js
db.collection({
  name: 'books',
  fields: [
    {
      type: 'boolean',
      name: 'published',
    },
  ],
});
```

### `'integer'`

Integer type (32 bits).

**Example**

```ts
db.collection({
  name: 'books',
  fields: [
    {
      type: 'integer',
      name: 'pages',
    },
  ],
});
```

### `'bigInt'`

Long integer type (64 bits).

**Example**

```ts
db.collection({
  name: 'books',
  fields: [
    {
      type: 'bigInt',
      name: 'words',
    },
  ],
});
```

### `'double'`

Double-precision floating-point format (64 bits).

**Example**

```ts
db.collection({
  name: 'books',
  fields: [
    {
      type: 'double',
      name: 'price',
    },
  ],
});
```

### `'real'`

Real type (PG only).

### `'decimal'`

Decimal type.

### `'string'`

String type. Equivalent to the `VARCHAR` type for most databases.

**Example**

```ts
db.collection({
  name: 'books',
  fields: [
    {
      type: 'string',
      name: 'title',
    },
  ],
});
```

### `'text'`

Text type. Equivalent to the `TEXT` type for most databases.

**Example**

```ts
db.collection({
  name: 'books',
  fields: [
    {
      type: 'text',
      name: 'content',
    },
  ],
});
```

### `'password'`

Password type (NocoBase extension). Password encryption based on the `scrypt` method of Node.js native crypto packages.

**Example**

```ts
db.collection({
  name: 'users',
  fields: [
    {
      type: 'password',
      name: 'password',
      length: 64, // Length, default is 64
      randomBytesSize: 8, // Length of random bytes, default is 8
    },
  ],
});
```

**Parameter**

| Name              | Type     | Default | Description            |
| ----------------- | -------- | ------- | ---------------------- |
| `length`          | `number` | 64      | Length of characters   |
| `randomBytesSize` | `number` | 8       | Length of random bytes |

### `'date'`

Date type.

### `'time'`

Time type.

### `'array'`

Array type (PG only).

### `'json'`

JSON type.

### `'jsonb'`

JSONB type (PG only, others will be compatible with the `'json'` type).

### `'uuid'`

UUID type.

### `'uid'`

UID type (NocoBase extension). Short random string identifier type.

### `'formula'`

Formula type (NocoBase extension). Mathematical formula calculation can be configured based on [mathjs](https://www.npmjs.com/package/mathjs), and the formula can refer to the values of other columns in the same record to participate in the calculation.

**Example**

```ts
db.collection({
  name: 'orders',
  fields: [
    {
      type: 'double',
      name: 'price',
    },
    {
      type: 'integer',
      name: 'quantity',
    },
    {
      type: 'formula',
      name: 'total',
      expression: 'price * quantity',
    },
  ],
});
```

### `'radio'`

Radio type (NocoBase extension). The field value is 'true' for at most one row of data for the full table, all others are 'false' or 'null'.

**Example**

There is only one user marked as *root* in the entire system, once the *root* value of any other user is changed to `true`, all other records with *root* of `true` will be changed to `false`:

```ts
db.collection({
  name: 'users',
  fields: [
    {
      type: 'radio',
      name: 'root',
    },
  ],
});
```

### `'sort'`

Sorting type (NocoBase extension). Sorting based on integer numbers, automatically generating new serial numbers for new records, and rearranging serial numbers when moving data.

If data table has the `sortable` option defined, the corresponding fields will be generated automatically.

**Example**

Posts are sortable based on the users they belong to.

```ts
db.collection({
  name: 'posts',
  fields: [
    {
      type: 'belongsTo',
      name: 'user',
    },
    {
      type: 'sort',
      name: 'priority',
      scopeKey: 'userId', // Sort data grouped by the values of userId
    },
  ],
});
```

### `'virtual'`

Virtual type. No Data is actually stored, it is used only when special getter/setter is defined.

### `'belongsTo'`

Many-to-one association type. Foreign key is stored in its own table, as opposed to `'hasOne'`/`'hasMany'`.

**Example**

Any post belongs to an author:

```ts
db.collection({
  name: 'posts',
  fields: [
    {
      type: 'belongsTo',
      name: 'author',
      target: 'users', // Default table name is the plural form of <name>
      foreignKey: 'authorId', // Default is '<name> + Id'
      sourceKey: 'id', // Default is id of the <target> table
    },
  ],
});
```

### `'hasOne'`

One-to-one association type. Foreign key is stored in the association table, as opposed to `'belongsTo'`.

**Example**

Any user has a profile:

```ts
db.collection({
  name: 'users',
  fields: [
    {
      type: 'hasOne',
      name: 'profile',
      target: 'profiles', // Can be omitted
    },
  ],
});
```

### `'hasMany'`

One-to-many association type. The foreign key is stored in the association table, as opposed to `'belongsTo'`.

**Example**

Any user can have multiple posts:

```ts
db.collection({
  name: 'users',
  fields: [
    {
      type: 'hasMany',
      name: 'posts',
      foreignKey: 'authorId',
      sourceKey: 'id',
    },
  ],
});
```

### `'belongsToMany'`

Many-to-many association type. Intermediate table is used to store both foreign keys. If no existing table is specified as intermediate table, it will be created automatically.

**Example**

Any post can have multiple tags added to it, and any tag can be added to multiple posts:

```ts
db.collection({
  name: 'posts',
  fields: [
    {
      type: 'belongsToMany',
      name: 'tags',
      target: 'tags', // Can be omitted if name is the same
      through: 'postsTags', // Intermediate table will be generated automatically if not specified
      foreignKey: 'postId', // Foreign key in the intermediate table referring to the table itself
      sourceKey: 'id', // Primary key of the table itself
      otherKey: 'tagId', // Foreign key in the intermediate table referring to the association table
    },
  ],
});

db.collection({
  name: 'tags',
  fields: [
    {
      type: 'belongsToMany',
      name: 'posts',
      through: 'postsTags', // Refer to the same intermediate table in the same set of relation
    },
  ],
});
```

---

## File: docs/en-US/api/database/index.md

# Database

## Overview

Database is the database interaction tool provided by NocoBase, it provides very convenient database interaction features for no-code and low-code applications. The supported databases are:

- SQLite 3.8.8+
- MySQL 8.0.17+
- PostgreSQL 10.0+

### Connect to Database

In `Database` constructor, database connection can be configured by passing the `options` parameter.

```javascript
const { Database } = require('@nocobase/database');

// MySQL database configuration parameters
const database = new Database({
  dialect: 'mysql',
  host: 'localhost',
  port: 3306,
  database: 'nocobase',
  username: 'root',
  password: 'password'
})

// MySQL \ PostgreSQL database configuration parameters
const database = new Database({
  dialect: /* 'postgres' or 'mysql' */,
  database: 'database',
  username: 'username',
  password: 'password',
  host: 'localhost',
  port: 'port'
})

```

Refer to [Constructor](#constructor) for detailed configurations.

### Define Data Structure

`Database` defines database structure through `Collection`, one `Collection` object represents one table in the database.

```javascript
// Define Collection
const UserCollection = database.collection({
  name: 'users',
  fields: [
    {
      name: 'name',
      type: 'string',
    },
    {
      name: 'age',
      type: 'integer',
    },
  ],
});
```

After the database structure is defined, use `sync()` method to synchronize the database structure.

```javascript
await database.sync();
```

Refer to [Collection](/api/database/collection) for detailed usage of `Collection`.

### CRUD Data

`Database` operates data through `Repository`.

```javascript
const UserRepository = UserCollection.repository();

// Create
await UserRepository.create({
  name: 'Mark',
  age: 18,
});

// Query
const user = await UserRepository.findOne({
  filter: {
    name: 'Mark',
  },
});

// Update
await UserRepository.update({
  values: {
    age: 20,
  },
});

// Delete
await UserRepository.destroy(user.id);
```

Refer to [Repository](/api/database/repository) for details of data CRUD.

## Constructor

**Signature**

- `constructor(options: DatabaseOptions)`

Create a database instance.

**Parameter**

| Name                   | Type           | Default       | Description                                                                                                                                         |
| ---------------------- | -------------- | ------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| `options.host`         | `string`       | `'localhost'` | Database host                                                                                                                                       |
| `options.port`         | `number`       | -             | Database service port, default port depends on the type of database used                                                                            |
| `options.username`     | `string`       | -             | Database username                                                                                                                                   |
| `options.password`     | `string`       | -             | Database password                                                                                                                                   |
| `options.database`     | `string`       | -             | Database name                                                                                                                                       |
| `options.dialect`      | `string`       | `'mysql'`     | Database type                                                                                                                                       |
| `options.storage?`     | `string`       | `':memory:'`  | Storage mode for SQLite                                                                                                                             |
| `options.logging?`     | `boolean`      | `false`       | Whether to enable logging                                                                                                                           |
| `options.define?`      | `Object`       | `{}`          | Default table definition parameters                                                                                                                 |
| `options.tablePrefix?` | `string`       | `''`          | NocoBase extension, table prefix                                                                                                                    |
| `options.migrator?`    | `UmzugOptions` | `{}`          | NocoBase extension, parameters for migrator, refer to [Umzug](https://github.com/sequelize/umzug/blob/main/src/types.ts#L15) for the implementation |

## Migration Methods

### `addMigration()`

Add single migration file.

**Signature**

- `addMigration(options: MigrationItem)`

**Parameter**

| Name                 | Type               | Default | Description                         |
| -------------------- | ------------------ | ------- | ----------------------------------- |
| `options.name`       | `string`           | -       | Name of the migration file          |
| `options.context?`   | `string`           | -       | Context of the migration file       |
| `options.migration?` | `typeof Migration` | -       | Custom type of the migration file   |
| `options.up`         | `Function`         | -       | `up` method of the migration file   |
| `options.down`       | `Function`         | -       | `down` method of the migration file |

**Example**

```ts
db.addMigration({
  name: '20220916120411-test-1',
  async up() {
    const queryInterface = this.context.db.sequelize.getQueryInterface();
    await queryInterface.query(/* your migration sqls */);
  },
});
```

### `addMigrations()`

Add the migration files in the specified directory.

**Signature**

- `addMigrations(options: AddMigrationsOptions): void`

**Parameter**

| Name                 | Type       | Default        | Description                                     |
| -------------------- | ---------- | -------------- | ----------------------------------------------- |
| `options.directory`  | `string`   | `''`           | Directory where the migration files are located |
| `options.extensions` | `string[]` | `['js', 'ts']` | File extensions                                 |
| `options.namespace?` | `string`   | `''`           | Namespace                                       |
| `options.context?`   | `Object`   | `{ db }`       | Context of the migration files                  |

**Example**

```ts
db.addMigrations({
  directory: path.resolve(__dirname, './migrations'),
  namespace: 'test',
});
```

## Tool Methods

### `inDialect()`

Check whether the current database type is the specified type.

**Signature**

- `inDialect(dialect: string[]): boolean`

**Parameter**

| Name      | Type       | Default | Description                                                 |
| --------- | ---------- | ------- | ----------------------------------------------------------- |
| `dialect` | `string[]` | -       | Database type, options are `mysql`, `postgres` and `mariadb` |

### `getTablePrefix()`

Get the table name prefix in the configuration.

**Signature**

- `getTablePrefix(): string`

## Data Table Configurations

### `collection()`

Define a data table. This is like the `define` method of Sequelize, which only creates table structure in memory. Call the `sync` method if needs to be persisted to the database.

**Signature**

- `collection(options: CollectionOptions): Collection`

**Parameter**

All configuration parameters of `options` is consistent with the constructor of the `Collection` class, refer to [Collection](/api/database/collection#Constructor).

**Event**

- `'beforeDefineCollection'`: Trigger before defining the table.
- `'afterDefineCollection'`: Trigger after defining the table.

**Example**

```ts
db.collection({
  name: 'books',
  fields: [
    {
      type: 'string',
      name: 'title',
    },
    {
      type: 'float',
      name: 'price',
    },
  ],
});

// sync collection as table to db
await db.sync();
```

### `getCollection()`

Get a defined data table.

**Signature**

- `getCollection(name: string): Collection`

**Parameter**

| Name   | Type     | Default | Description |
| ------ | -------- | ------- | ----------- |
| `name` | `string` | -       | Table name  |

**Example**

```ts
const collection = db.getCollection('books');
```

### `hasCollection()`

Check whether a specified data table is defined.

**Signature**

- `hasCollection(name: string): boolean`

**Parameter**

| Name   | Type     | Default | Description |
| ------ | -------- | ------- | ----------- |
| `name` | `string` | -       | Table name  |

**Example**

```ts
db.collection({ name: 'books' });

db.hasCollection('books'); // true

db.hasCollection('authors'); // false
```

### `removeCollection()`

Remove a defined data table. It is to remove from memory only, call the `sync` method if needs to be persisted to the database.

**Signature**

- `removeCollection(name: string): void`

**Parameter**

| Name   | Type     | Default | Description |
| ------ | -------- | ------- | ----------- |
| `name` | `string` | -       | Table name  |

**Event**

- `'beforeRemoveCollection'`: Trigger before removing the table.
- `'afterRemoveCollection'`: Trigger after removing the table

**Example**

```ts
db.collection({ name: 'books' });

db.removeCollection('books');
```

### `import()`

Load all files in the import file directory into memory as the configuration of collection.

**Signature**

- `async import(options: { directory: string; extensions?: ImportFileExtension[] }): Promise<Map<string, Collection>>`

**Parameter**

| Name                 | Type       | Default        | Description                      |
| -------------------- | ---------- | -------------- | -------------------------------- |
| `options.directory`  | `string`   | -              | Path of directory to be imported |
| `options.extensions` | `string[]` | `['ts', 'js']` | Scan for specific suffixes       |

**Example**

The collection defined by file `./collections/books.ts` is as below:

```ts
export default {
  name: 'books',
  fields: [
    {
      type: 'string',
      name: 'title',
    },
  ],
};
```

Import the relevant configurations when loading the plugin:

```ts
class Plugin {
  async load() {
    await this.app.db.import({
      directory: path.resolve(__dirname, './collections'),
    });
  }
}
```

## Extension Registrations and Acquisitions

### `registerFieldTypes()`

Register custom field type.

**Signature**

- `registerFieldTypes(fieldTypes: MapOf<typeof Field>): void`

**Parameter**

`fieldTypes` is a key-value pair, where key is the field type name, and value is the field type class.

**Example**

```ts
import { Field } from '@nocobase/database';

class MyField extends Field {
  // ...
}

db.registerFieldTypes({
  myField: MyField,
});
```

### `registerModels()`

Register custom data model class.

**Signature**

- `registerModels(models: MapOf<ModelStatic<any>>): void`

**Parameter**

`models` is a key-value pair, where key is the data model name, and value is the data model class.

**Example**

```ts
import { Model } from '@nocobase/database';

class MyModel extends Model {
  // ...
}

db.registerModels({
  myModel: MyModel,
});

db.collection({
  name: 'myCollection',
  model: 'myModel',
});
```

### `registerRepositories()`

Register custom data repository class.

**Signature**

- `registerRepositories(repositories: MapOf<RepositoryType>): void`

**Parameter**

`repositories` is a key-value pair, where key is the data repository name, and value is the data repository class.

**Example**

```ts
import { Repository } from '@nocobase/database';

class MyRepository extends Repository {
  // ...
}

db.registerRepositories({
  myRepository: MyRepository,
});

db.collection({
  name: 'myCollection',
  repository: 'myRepository',
});
```

### `registerOperators()`

Register custom data query operator.

**Signature**

- `registerOperators(operators: MapOf<OperatorFunc>)`

**Parameter**

`operators` is a key-value pair, where key is the operator name, and value is the generating function of the comparison operator statement.

**Example**

```ts
db.registerOperators({
  $dateOn(value) {
    return {
      [Op.and]: [
        { [Op.gte]: stringToDate(value) },
        { [Op.lt]: getNextDay(value) },
      ],
    };
  },
});

db.getRepository('books').count({
  filter: {
    createdAt: {
      // registered operator
      $dateOn: '2020-01-01',
    },
  },
});
```

### `getModel()`

Get the defined data model class. If no custom model class has been registered before, the default model class of Sequelize will be returned. The default name is the same as the name defined by collection.

**Signature**

- `getModel(name: string): Model`

**Parameter**

| Name   | Type     | Default | Description           |
| ------ | -------- | ------- | --------------------- |
| `name` | `string` | -       | Registered model name |

**Example**

```ts
db.registerModels({
  books: class MyModel extends Model {},
});

const ModelClass = db.getModel('books');

console.log(ModelClass.prototype instanceof MyModel); // true
```

Note: The model class retrieved from collection is not strictly equivalent to the model class at registration, but is inherited from the model class at registration. Since the properties of Sequelize's model class are modified during initialization, NocoBase automatically handles this inheritance relationship. All the definitions work fine except that the classes are not equal.

### `getRepository()`

Get the defined data repository class. If no custom data repository class has been registered before, the default data repository class of NocoBase will be returned. The default name is the same as the name defined by collection.

Data repository class is mainly used for the CRUD operations based on data model, refer to [Repository](/api/database/repository).

**Signature**

- `getRepository(name: string): Repository`
- `getRepository(name: string, relationId?: string | number): Repository`

**Parameter**

| Name         | Type                 | Default | Description                           |
| ------------ | -------------------- | ------- | ------------------------------------- |
| `name`       | `string`             | -       | Registered data repository name       |
| `relationId` | `string` \| `number` | -       | Foreign key value for relational data |

When the name contains relationship in the form of `'tables.relactions'`, the related data repository class is returned. If the second parameter is provided, the data repository will be used (query, modify, etc.) based on the foreign key values of the relational data.

**Example**

Suppose there are two data tables *posts* and *authors*, and there is a foreign key in the *posts* table points to the *authors* table:

```ts
const AuthorsRepo = db.getRepository('authors');
const author1 = AuthorsRepo.create({ name: 'author1' });

const PostsRepo = db.getRepository('authors.posts', author1.id);
const post1 = AuthorsRepo.create({ title: 'post1' });
asset(post1.authorId === author1.id); // true
```

## Database Events

### `on()`

Listen for database events.

**Signature**

- `on(event: string, listener: (...args: any[]) => void | Promise<void>): void`

**Parameter**

| Name     | Type     | Default | Description    |
| -------- | -------- | ------- | -------------- |
| event    | string   | -       | Event name     |
| listener | Function | -       | Event listener |

Event name supports Model event of Sequelize by default. Global event is listened to by the name `<sequelize_model_global_event>`, single Model event is listened to by the name `<model_name>. <sequelize_model_event>`.

Refer to the [Built-in Events](#built-in-events) section for parameter descriptions and detailed examples of all built-in event types.

### `off()`

Remove the event listener function.

**Signature**

- `off(name: string, listener: Function)`

**Parameter**

| Name     | Type     | Default | Description    |
| -------- | -------- | ------- | -------------- |
| name     | string   | -       | Event name     |
| listener | Function | -       | Event listener |

**Example**

```ts
const listener = async (model, options) => {
  console.log(model);
};

db.on('afterCreate', listener);

db.off('afterCreate', listener);
```

## Database Operations

### `auth()`

Database connection verification. It can be used to ensure that the application has established connection to the data.

**Signature**

- `auth(options: QueryOptions & { retry?: number } = {}): Promise`

**Parameter**

| Name                   | Type                  | Default | Description                                       |
| ---------------------- | --------------------- | ------- | ------------------------------------------------- |
| `options?`             | `Object`              | -       | Verification option                               |
| `options.retry?`       | `number`              | `10`    | Number of retries in case of verification failure |
| `options.transaction?` | `Transaction`         | -       | Transaction object                                |
| `options.logging?`     | `boolean \| Function` | `false` | Whether to print the log                          |

**Example**

```ts
await db.auth();
```

### `reconnect()`

Reconnect to the database.

**Example**

```ts
await db.reconnect();
```

### `closed()`

Check whether database has closed the connection.

**Signature**

- `closed(): boolean`

### `close()`

Closes database connection. Equivalent to `sequelize.close()`.

### `sync()`

Synchronizes database table structure. Equivalent to `sequelize.sync()`, refer to [Sequelize documentation](https://sequelize.org/api/v6/class/src/sequelize.js~sequelize#instance-method-sync) for parameters.

### `clean()`

Empty the database, it will delete all data tables.

**Signature**

- `clean(options: CleanOptions): Promise<void>`

**Parameter**

| Name                  | Type          | Default | Description                       |
| --------------------- | ------------- | ------- | --------------------------------- |
| `options.drop`        | `boolean`     | `false` | Whether to remove all data tables |
| `options.skip`        | `string[]`    | -       | Names of tables to skip           |
| `options.transaction` | `Transaction` | -       | Transaction object                |

**Example**

Remove all tables except for the `users` table.

```ts
await db.clean({
  drop: true,
  skip: ['users'],
});
```

## Package-Level Export

### `defineCollection()`

Create the configuration content of a data table.

**Signature**

- `defineCollection(name: string, config: CollectionOptions): CollectionOptions`

**Parameter**

| Name                | Type                | Default | Description                                        |
| ------------------- | ------------------- | ------- | -------------------------------------------------- |
| `collectionOptions` | `CollectionOptions` | -       | All parameters are the same with `db.collection()` |

**Example**

For the data table configuration file to be imported by `db.import()`:

```ts
import { defineCollection } from '@nocobase/database';

export default defineCollection({
  name: 'users',
  fields: [
    {
      type: 'string',
      name: 'name',
    },
  ],
});
```

### `extendCollection()`

Extent the configuration content of a data table that is already in memory, mainly for the content of files imported by the `import()` method. This is the top-level package export method of `@nocobase/database`, and is not called through db instance. The `extend` alias can also be used.

**Signature**

- `extendCollection(collectionOptions: CollectionOptions, mergeOptions?: MergeOptions): ExtendedCollectionOptions`

**Parameter**

| Name                | Type                | Default | Description                                                             |
| ------------------- | ------------------- | ------- | ----------------------------------------------------------------------- |
| `collectionOptions` | `CollectionOptions` | -       | All the same with `db.collection()`                                     |
| `mergeOptions?`     | `MergeOptions`      | -       | [deepmerge](https://npmjs.com/package/deepmerge) options of npm package |

**Example**

Original definition of the table *books* (books.ts):

```ts
export default {
  name: 'books',
  fields: [{ name: 'title', type: 'string' }],
};
```

Extend the definition of the table *books* (books.extend.ts):

```ts
import { extend } from '@nocobase/database';

// Extend again
export default extend({
  name: 'books',
  fields: [{ name: 'price', type: 'number' }],
});
```

If the above two files are imported when calling `import()`, after being extended again by `extend()`, the table *books* will have `title` and `price` two fields.

This method is especially useful when extending the table structure that is already defined by existing plugin.

## Built-in Events

The following events will be triggered in the corresponding lifecycle of database, subscribe by the `on()` method and perform specific processing to meet some business needs.

### `'beforeSync'` / `'afterSync'`

Events triggered before or after a new table structure configuration (fields, indexes, etc.) is synchronized to the database. This is usually triggered when executing `collection.sync()` (internal call) for the logical processing of the extension of some special fields.

**Signature**

```ts
on(eventName: `${string}.beforeSync` | 'beforeSync' | `${string}.afterSync` | 'afterSync', listener: SyncListener): this
```

**Type**

```ts
import type { SyncOptions, HookReturn } from 'sequelize/types';

type SyncListener = (options?: SyncOptions) => HookReturn;
```

**Example**

```ts
const users = db.collection({
  name: 'users',
  fields: [{ type: 'string', name: 'username' }],
});

db.on('beforeSync', async (options) => {
  // do something
});

db.on('users.afterSync', async (options) => {
  // do something
});

await users.sync();
```

### `'beforeValidate'` / `'afterValidate'`

Before creating or updating data, there is a validation against the data based on the rules defined by the collection, and the corresponding events are triggered before and after the validation. This is triggered when `repository.create()` or `repository.update()` is called.

**Signature**

```ts
on(eventName: `${string}.beforeValidate` | 'beforeValidate' | `${string}.afterValidate` | 'afterValidate', listener: ValidateListener): this
```

**Type**

```ts
import type { ValidationOptions } from 'sequelize/types/lib/instance-validator';
import type { HookReturn } from 'sequelize/types';
import type { Model } from '@nocobase/database';

type ValidateListener = (
  model: Model,
  options?: ValidationOptions,
) => HookReturn;
```

**Example**

```ts
db.collection({
  name: 'tests',
  fields: [
    {
      type: 'string',
      name: 'email',
      validate: {
        isEmail: true,
      },
    },
  ],
});

// all models
db.on('beforeValidate', async (model, options) => {
  // do something
});
// tests model
db.on('tests.beforeValidate', async (model, options) => {
  // do something
});

// all models
db.on('afterValidate', async (model, options) => {
  // do something
});
// tests model
db.on('tests.afterValidate', async (model, options) => {
  // do something
});

const repository = db.getRepository('tests');
await repository.create({
  values: {
    email: 'abc', // checks for email format
  },
});
// or
await repository.update({
  filterByTk: 1,
  values: {
    email: 'abc', // checks for email format
  },
});
```

### `'beforeCreate'` / `'afterCreate'`

Events triggered before or after creating one piece of data. This is triggered when `repository.create()` is called.

**Signature**

```ts
on(eventName: `${string}.beforeCreate` | 'beforeCreate' | `${string}.afterCreate` | 'afterCreate', listener: CreateListener): this
```

**Type**

```ts
import type { CreateOptions, HookReturn } from 'sequelize/types';
import type { Model } from '@nocobase/database';

export type CreateListener = (
  model: Model,
  options?: CreateOptions,
) => HookReturn;
```

**Example**

```ts
db.on('beforeCreate', async (model, options) => {
  // do something
});

db.on('books.afterCreate', async (model, options) => {
  const { transaction } = options;
  const result = await model.constructor.findByPk(model.id, {
    transaction,
  });
  console.log(result);
});
```

### `'beforeUpdate'` / `'afterUpdate'`

Events triggered before or after updating one piece of data. This is triggered when `repository.update()` is called.

**Signature**

```ts
on(eventName: `${string}.beforeUpdate` | 'beforeUpdate' | `${string}.afterUpdate` | 'afterUpdate', listener: UpdateListener): this
```

**Type**

```ts
import type { UpdateOptions, HookReturn } from 'sequelize/types';
import type { Model } from '@nocobase/database';

export type UpdateListener = (
  model: Model,
  options?: UpdateOptions,
) => HookReturn;
```

**Example**

```ts
db.on('beforeUpdate', async (model, options) => {
  // do something
});

db.on('books.afterUpdate', async (model, options) => {
  // do something
});
```

### `'beforeSave'` / `'afterSave'`

Events triggered before or after creating or updating one piece of data. This is triggered when `repository.create()` or `repository.update()` is called.

**Signature**

```ts
on(eventName: `${string}.beforeSave` | 'beforeSave' | `${string}.afterSave` | 'afterSave', listener: SaveListener): this
```

**Type**

```ts
import type { SaveOptions, HookReturn } from 'sequelize/types';
import type { Model } from '@nocobase/database';

export type SaveListener = (model: Model, options?: SaveOptions) => HookReturn;
```

**Example**

```ts
db.on('beforeSave', async (model, options) => {
  // do something
});

db.on('books.afterSave', async (model, options) => {
  // do something
});
```

### `'beforeDestroy'` / `'afterDestroy'`

Events triggered before or after deleting one piece of data. This is triggered when `repository.destroy()` is called.

**Signature**

```ts
on(eventName: `${string}.beforeDestroy` | 'beforeDestroy' | `${string}.afterDestroy` | 'afterDestroy', listener: DestroyListener): this
```

**Type**

```ts
import type { DestroyOptions, HookReturn } from 'sequelize/types';
import type { Model } from '@nocobase/database';

export type DestroyListener = (
  model: Model,
  options?: DestroyOptions,
) => HookReturn;
```

**Example**

```ts
db.on('beforeDestroy', async (model, options) => {
  // do something
});

db.on('books.afterDestroy', async (model, options) => {
  // do something
});
```

### `'afterCreateWithAssociations'`

Events triggered after creating one piece of data that carries hierarchical data. This is triggered when `repository.create()` is called.

**Signature**

```ts
on(eventName: `${string}.afterCreateWithAssociations` | 'afterCreateWithAssociations', listener: CreateWithAssociationsListener): this
```

**Type**

```ts
import type { CreateOptions, HookReturn } from 'sequelize/types';
import type { Model } from '@nocobase/database';

export type CreateWithAssociationsListener = (
  model: Model,
  options?: CreateOptions,
) => HookReturn;
```

**Example**

```ts
db.on('afterCreateWithAssociations', async (model, options) => {
  // do something
});

db.on('books.afterCreateWithAssociations', async (model, options) => {
  // do something
});
```

### `'afterUpdateWithAssociations'`

Events triggered after updating one piece of data that carries hierarchical data. This is triggered when `repository.update()` is called.

**Signature**

```ts
on(eventName: `${string}.afterUpdateWithAssociations` | 'afterUpdateWithAssociations', listener: CreateWithAssociationsListener): this
```

**Type**

```ts
import type { UpdateOptions, HookReturn } from 'sequelize/types';
import type { Model } from '@nocobase/database';

export type UpdateWithAssociationsListener = (
  model: Model,
  options?: UpdateOptions,
) => HookReturn;
```

**Example**

```ts
db.on('afterUpdateWithAssociations', async (model, options) => {
  // do something
});

db.on('books.afterUpdateWithAssociations', async (model, options) => {
  // do something
});
```

### `'afterSaveWithAssociations'`

Events triggered after creating or updating one piece of data that carries hierarchical data. This is triggered when `repository.create()` or `repository.update()` is called.

**Signature**

```ts
on(eventName: `${string}.afterSaveWithAssociations` | 'afterSaveWithAssociations', listener: SaveWithAssociationsListener): this
```

**Type**

```ts
import type { SaveOptions, HookReturn } from 'sequelize/types';
import type { Model } from '@nocobase/database';

export type SaveWithAssociationsListener = (
  model: Model,
  options?: SaveOptions,
) => HookReturn;
```

**Example**

```ts
db.on('afterSaveWithAssociations', async (model, options) => {
  // do something
});

db.on('books.afterSaveWithAssociations', async (model, options) => {
  // do something
});
```

### `'beforeDefineCollection'`

Events triggered before defining a data table, such as when `db.collection()` is called.

Note: This is a synchronous event.

**Signature**

```ts
on(eventName: 'beforeDefineCollection', listener: BeforeDefineCollectionListener): this
```

**Type**

```ts
import type { CollectionOptions } from '@nocobase/database';

export type BeforeDefineCollectionListener = (
  options: CollectionOptions,
) => void;
```

**Example**

```ts
db.on('beforeDefineCollection', (options) => {
  // do something
});
```

### `'afterDefineCollection'`

Events triggered after defining a data table, such as when `db.collection()` is called.

Note: This is a synchronous event.

**Signature**

```ts
on(eventName: 'afterDefineCollection', listener: AfterDefineCollectionListener): this
```

**Type**

```ts
import type { Collection } from '@nocobase/database';

export type AfterDefineCollectionListener = (options: Collection) => void;
```

**Example**

```ts
db.on('afterDefineCollection', (collection) => {
  // do something
});
```

### `'beforeRemoveCollection'` / `'afterRemoveCollection'`

Events triggered before or after removing a data table from memory, such as when `db.removeCollection()` is called.

Note: This is a synchronous event.

**Signature**

```ts
on(eventName: 'beforeRemoveCollection' | 'afterRemoveCollection', listener: RemoveCollectionListener): this
```

**Type**

```ts
import type { Collection } from '@nocobase/database';

export type RemoveCollectionListener = (options: Collection) => void;
```

**Example**

```ts
db.on('beforeRemoveCollection', (collection) => {
  // do something
});

db.on('afterRemoveCollection', (collection) => {
  // do something
});
```

---

## File: docs/en-US/api/database/operators.md

# Filter Operators

Used in the filter parameters of the `find`, `findOne`, `findAndCount`, `count`, etc. APIs of repository:

```ts
const repository = db.getRepository('books');

repository.find({
  filter: {
    title: {
      $eq: 'Spring and Autumn',
    },
  },
});
```

To support JSON, NocoBase identifies query operators as a string prefixed with $.

Moreover, NocoBase provides API to extend operators. Refer to [`db.registerOperators()`](../database#registeroperators).

## General Operators

### `$eq`

Check if the field value is equal to the specified value. Equivalent to `=` in SQL.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $eq: 'Spring and Autumn',
    },
  },
});
```

Equal to `title: 'Spring and Autumn'`

### `$ne`

Check if the field value is not equal to the specified value. Equivalent to `!=` in SQL.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $ne: 'Spring and Autumn',
    },
  },
});
```

### `$is`

Check if the field value is the specified value. Equivalent to `IS` in SQL.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $is: null,
    },
  },
});
```

### `$not`

Check if the field value is not the specified value. Equivalent to `IS NOT` in SQL.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $not: null,
    },
  },
});
```

### `$col`

Check if the field value is equal to the value of another field. Equivalent to `=` in SQL.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $col: 'name',
    },
  },
});
```

### `$in`

Check if the field value is in the specified array. Equivalent to `IN` in SQL.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $in: ['Spring and Autumn', 'Warring States'],
    },
  },
});
```

### `$notIn`

Check if the field value is not in the specified array. Equivalent to `NOT IN` in SQL.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $notIn: ['Spring and Autumn', 'Warring States'],
    },
  },
});
```

### `$empty`

Check if the general field is empty. For string field, check if it is an empty string; for array field, check if it is an empty array.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $empty: true,
    },
  },
});
```

### `$notEmpty`

Check if the general field is not empty. For string field, check if it is not an empty string; for array field, check if it is not an empty array.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $notEmpty: true,
    },
  },
});
```

## Logical Operators

### `$and`

Logical AND. Equivalent to `AND` in SQL.

**Example**

```ts
repository.find({
  filter: {
    $and: [{ title: 'Book of Songs' }, { isbn: '1234567890' }],
  },
});
```

### `$or`

Logical OR. Equivalent to `OR` in SQL.

**Example**

```ts
repository.find({
  filter: {
    $or: [
      { title: 'Book of Songs' },
      { publishedAt: { $lt: '0000-00-00T00:00:00Z' } },
    ],
  },
});
```

## Boolean Field Operators

For boolean fields: `type: 'boolean'`

### `$isFalsy`

Check if a Boolean field value is false. Boolean field values of `false`, `0` and `NULL` are all judged to be `$isFalsy: true`.

**Example**

```ts
repository.find({
  filter: {
    isPublished: {
      $isFalsy: true,
    },
  },
});
```

### `$isTruly`

Check if a Boolean field value is true. Boolean field values of `true` and `1` are all judged to be `$isTruly: true`.

**Example**

```ts
repository.find({
  filter: {
    isPublished: {
      $isTruly: true,
    },
  },
});
```

## Numeric Type Field Operators

For numeric type fields, including:

- `type: 'integer'`
- `type: 'float'`
- `type: 'double'`
- `type: 'real'`
- `type: 'decimal'`

### `$gt`

Check if the field value is greater than the specified value. Equivalent to `>` in SQL.

**Example**

```ts
repository.find({
  filter: {
    price: {
      $gt: 100,
    },
  },
});
```

### `$gte`

Check if the field value is equal to or greater than the specified value. Equivalent to `>=` in SQL.

**Example**

```ts
repository.find({
  filter: {
    price: {
      $gte: 100,
    },
  },
});
```

### `$lt`

Check if the field value is less than the specified value. Equivalent to `<` in SQL.

**Example**

```ts
repository.find({
  filter: {
    price: {
      $lt: 100,
    },
  },
});
```

### `$lte`

Check if the field value is equal to or less than the specified value. Equivalent to `<=` in SQL.

**Example**

```ts
repository.find({
  filter: {
    price: {
      $lte: 100,
    },
  },
});
```

### `$between`

Check if the field value is between the specified two values. Equivalent to `BETWEEN` in SQL.

**Example**

```ts
repository.find({
  filter: {
    price: {
      $between: [100, 200],
    },
  },
});
```

### `$notBetween`

Check if the field value is not between the specified two values. Equivalent to `NOT BETWEEN` in SQL.

**Example**

```ts
repository.find({
  filter: {
    price: {
      $notBetween: [100, 200],
    },
  },
});
```

## String Type Field Operators

For string type fields, including `string`.

### `$includes`

Check if the string field contains the specified substring.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $includes: 'Three Character Classic',
    },
  },
});
```

### `$notIncludes`

Check if the string field does not contain the specified substring.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $notIncludes: 'Three Character Classic',
    },
  },
});
```

### `$startsWith`

Check if the string field starts with the specified substring.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $startsWith: 'Three Character Classic',
    },
  },
});
```

### `$notStatsWith`

Check if the string field does not start with the specified substring.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $notStatsWith: 'Three Character Classic',
    },
  },
});
```

### `$endsWith`

Check if the string field ends with the specified substring.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $endsWith: 'Three Character Classic',
    },
  },
});
```

### `$notEndsWith`

Check if the string field does not end with the specified substring.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $notEndsWith: 'Three Character Classic',
    },
  },
});
```

### `$like`

Check if the field value contains the specified string. Equivalent to `LIKE` in SQL.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $like: 'Computer',
    },
  },
});
```

### `$notLike`

Check if the field value does not contain the specified string. Equivalent to `NOT LIKE` in SQL.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $notLike: 'Computer',
    },
  },
});
```

### `$iLike`

Check if a field value contains the specified string, case ignored. Equivalent to `ILIKE` in SQL (PG only).

**Example**

```ts
repository.find({
  filter: {
    title: {
      $iLike: 'Computer',
    },
  },
});
```

### `$notILike`

Check if a field value does not contain the specified string, case ignored. Equivalent to `NOT ILIKE` in SQL (PG only).

**Example**

```ts
repository.find({
  filter: {
    title: {
      $notILike: 'Computer',
    },
  },
});
```

### `$regexp`

Check if the field value matches the specified regular expression. Equivalent to `REGEXP` in SQL (PG only).

**Example**

```ts
repository.find({
  filter: {
    title: {
      $regexp: '^Computer',
    },
  },
});
```

### `$notRegexp`

Check if the field value does not match the specified regular expression. Equivalent to `NOT REGEXP` in SQL (PG only).

**Example**

```ts
repository.find({
  filter: {
    title: {
      $notRegexp: '^Computer',
    },
  },
});
```

### `$iRegexp`

Check if the field value matches the specified regular expression, case ignored. Equivalent to `~*` in SQL (PG only).

**Example**

```ts
repository.find({
  filter: {
    title: {
      $iRegexp: '^COMPUTER',
    },
  },
});
```

### `$notIRegexp`

Check if the field value does not match the specified regular expression, case ignored. Equivalent to `!~*` in SQL (PG only).

**Example**

```ts
repository.find({
  filter: {
    title: {
      $notIRegexp: '^COMPUTER',
    },
  },
});
```

## Date Type Field Operators

For date type fields: `type: 'date'`

### `$dateOn`

Check if the date field value is within a certain day.

**Example**

```ts
repository.find({
  filter: {
    createdAt: {
      $dateOn: '2021-01-01',
    },
  },
});
```

### `$dateNotOn`

Check if the date field value is not within a certain day.

**Example**

```ts
repository.find({
  filter: {
    createdAt: {
      $dateNotOn: '2021-01-01',
    },
  },
});
```

### `$dateBefore`

Check if the date field value is before a certain value, i.e., less than the one passed in.

**Example**

```ts
repository.find({
  filter: {
    createdAt: {
      $dateBefore: '2021-01-01T00:00:00.000Z',
    },
  },
});
```

### `$dateNotBefore`

Check if the date field value is not before a certain value, i.e., equal to or greater than the one passed in.

**Example**

```ts
repository.find({
  filter: {
    createdAt: {
      $dateNotBefore: '2021-01-01T00:00:00.000Z',
    },
  },
});
```

### `$dateAfter`

Check if the date field value is after a certain value, i.e., greater than the one passed in.

**Example**

```ts
repository.find({
  filter: {
    createdAt: {
      $dateAfter: '2021-01-01T00:00:00.000Z',
    },
  },
});
```

### `$dateNotAfter`

Check if the date field value is not after a certain value, i.e., equal to or greater than the one passed in.

**Example**

```ts
repository.find({
  filter: {
    createdAt: {
      $dateNotAfter: '2021-01-01T00:00:00.000Z',
    },
  },
});
```

## Array Type Field Operators

For array type fields: `type: 'array'`

### `$match`

Check if the array field values match values of the specified array.

**Example**

```ts
repository.find({
  filter: {
    tags: {
      $match: ['literature', 'history'],
    },
  },
});
```

### `$notMatch`

Check if the array field values do not match values of the specified array.

**Example**

```ts
repository.find({
  filter: {
    tags: {
      $notMatch: ['literature', 'history'],
    },
  },
});
```

### `$anyOf`

Check if the array field values contain any of the values of the specified array.

**Example**

```ts
repository.find({
  filter: {
    tags: {
      $anyOf: ['literature', 'history'],
    },
  },
});
```

### `$noneOf`

Check if the array field values contain none of the values of the specified array.

**Example**

```ts
repository.find({
  filter: {
    tags: {
      $noneOf: ['literature', 'history'],
    },
  },
});
```

### `$arrayEmpty`

Check if the array field is empty.

**Example**

```ts
repository.find({
  filter: {
    tags: {
      $arrayEmpty: true,
    },
  },
});
```

### `$arrayNotEmpty`

Check if the array field is not empty.

**Example**

```ts
repository.find({
  filter: {
    tags: {
      $arrayNotEmpty: true,
    },
  },
});
```

## Relational Field Type Operators

For checking if a relationship exists, field types include:

- `type: 'hasOne'`
- `type: 'hasMany'`
- `type: 'belongsTo'`
- `type: 'belongsToMany'`

### `$exists`

There is relational data existing.

**Example**

```ts
repository.find({
  filter: {
    author: {
      $exists: true,
    },
  },
});
```

### `$notExists`

There is no relational data existing.

**Example**

```ts
repository.find({
  filter: {
    author: {
      $notExists: true,
    },
  },
});
```

---

## File: docs/en-US/api/database/repository.md

# Repository

## Overview

On a given `Collection` object, you can get its `Repository` object to perform read and write operations on the data table.

```javascript
const { UserCollection } = require('./collections');

const UserRepository = UserCollection.repository;

const user = await UserRepository.findOne({
  filter: {
    id: 1,
  },
});

user.name = 'new name';
await user.save();
```

### Query

#### Basic Query

On the `Repository` object, call the `find*` methods to perform query. The `filter` parameter is supported by all query methods to filter the data.

```javascript
// SELECT * FROM users WHERE id = 1
userRepository.find({
  filter: {
    id: 1,
  },
});
```

#### Operator

The `filter` parameter in the `Repository` also provides a variety of operators to perform more diverse queries.

```javascript
// SELECT * FROM users WHERE age > 18
userRepository.find({
  filter: {
    age: {
      $gt: 18,
    },
  },
});

// SELECT * FROM users WHERE age > 18 OR name LIKE '%张%'
userRepository.find({
  filter: {
    $or: [{ age: { $gt: 18 } }, { name: { $like: '%张%' } }],
  },
});
```

Refer to [Filter Operators](/api/database/operators) for more details on operators.

#### Field Control

Control the output fields by the `fields`, `except`, and `appends` parameters when performing query.

- `fields`: Specify output fields
- `except`: Exclude output fields
- `appends`: Append output associated fields

```javascript
// The result contains only the id and name fields
userRepository.find({
  fields: ['id', 'name'],
});

// The result does not contain only the password field
userRepository.find({
  except: ['password'],
});

// The result contains data associated with the posts object
userRepository.find({
  appends: ['posts'],
});
```

#### Associated Field Query

The `filter` parameter supports filtering by associated fields, for example:

```javascript
// Find the user objects whose associated posts have title of "post title"
userRepository.find({
  filter: {
    'posts.title': 'post title',
  },
});
```

Associated fields can also be nested:

```javascript
// Find the user objects whose associated posts have comments containing "keywords"
await userRepository.find({
  filter: {
    'posts.comments.content': {
      $like: '%keywords%',
    },
  },
});
```

#### Sort

Sort query results by the `sort` parameter.

```javascript
// SELECT * FROM users ORDER BY age
await userRepository.find({
  sort: 'age',
});

// SELECT * FROM users ORDER BY age DESC
await userRepository.find({
  sort: '-age',
});

// SELECT * FROM users ORDER BY age DESC, name ASC
await userRepository.find({
  sort: ['-age', 'name'],
});
```

Sort by the field of the associated object is also supported:

```javascript
await userRepository.find({
  sort: 'profile.createdAt',
});
```

### Create

#### Basic Create

Create new data objects via `Repository`.

```javascript
await userRepository.create({
  name: 'Mark',
  age: 18,
});
// INSERT INTO users (name, age) VALUES ('Mark', 18)

// Bulk creation
await userRepository.create([
  {
    name: 'Mark',
    age: 18,
  },
  {
    name: 'Alex',
    age: 20,
  },
]);
```

#### Create Association

Create associated objects at the same time of creating data. Like query, nested use of associated objects is also supported. For example:

```javascript
await userRepository.create({
  name: 'Mark',
  age: 18,
  posts: [
    {
      title: 'post title',
      content: 'post content',
      tags: [
        {
          name: 'tag1',
        },
        {
          name: 'tag2',
        },
      ],
    },
  ],
});
// When creating a user, create a post to associate with the user, and create tags to associate with the post
```

If the associated object is already in the database, you can pass its ID to create an association with it.

```javascript
const tag1 = await tagRepository.findOne({
  filter: {
    name: 'tag1',
  },
});

await userRepository.create({
  name: 'Mark',
  age: 18,
  posts: [
    {
      title: 'post title',
      content: 'post content',
      tags: [
        {
          id: tag1.id, // Create an association with an existing associated object
        },
        {
          name: 'tag2',
        },
      ],
    },
  ],
});
```

### Update

#### Basic Update

After getting the data object, you can modify the properties directly on the data object (`Model`), and then call the `save` method to save the changes.

```javascript
const user = await userRepository.findOne({
  filter: {
    name: 'Mark',
  },
});

user.age = 20;
await user.save();
```

The data object `Model` is inherited from Sequelize Model, refer to [Sequelize Model](https://sequelize.org/master/manual/model-basics.html) for the operations on `Model`.

Or update data via `Repository`:

```javascript
// Update the records that meet the filtering condition
await userRepository.update({
  filter: {
    name: 'Mark',
  },
  values: {
    age: 20,
  },
});
```

Control which fields to update by the `whitelist` and `blacklist` parameters, for example:

```javascript
await userRepository.update({
  filter: {
    name: 'Mark',
  },
  values: {
    age: 20,
    name: 'Alex',
  },
  whitelist: ['age'], // Only update the age field
});
```

#### Update Associated Field

Associated objects can be set while updating, for example:

```javascript
const tag1 = tagRepository.findOne({
  filter: {
    id: 1,
  },
});

await postRepository.update({
  filter: {
    id: 1,
  },
  values: {
    title: 'new post title',
    tags: [
      {
        id: tag1.id, // Associate with tag1
      },
      {
        name: 'tag2', // Create new tag and associate with it
      },
    ],
  },
});

await postRepository.update({
  filter: {
    id: 1,
  },
  values: {
    tags: null, // Disassociate post from tags
  },
});
```

### Delete

Call the `destroy()` method in `Repository` to perform the deletion operation. Filtering condition has to be specified to delete.

```javascript
await userRepository.destroy({
  filter: {
    status: 'blocked',
  },
});
```

## Constructor

It is usually not called directly by the developer, the instantiation is done mainly by specifying a corresponding repository type that is already registered in the parameter of `db.colletion()`. Repository type is registered through `db.registerRepositories()`.

**Signature**

- `constructor(collection: Collection)`

**Example**

```ts
import { Repository } from '@nocobase/database';

class MyRepository extends Repository {
  async myQuery(sql) {
    return this.database.sequelize.query(sql);
  }
}

db.registerRepositories({
  books: MyRepository,
});

db.collection({
  name: 'books',
  // here link to the registered repository
  repository: 'books',
});

await db.sync();

const books = db.getRepository('books') as MyRepository;
await books.myQuery('SELECT * FROM books;');
```

## Instance Members

### `database`

The database management instance where the context is located.

### `collection`

The corresponding data table management instance.

### `model`

The corresponding data model class.

## Instance Methods

### `find()`

Find datasets from the database with the specified filtering conditions and sorting, etc.

**Signature**

- `async find(options?: FindOptions): Promise<Model[]>`

**Type**

```typescript
type Filter = FilterWithOperator | FilterWithValue | FilterAnd | FilterOr;
type Appends = string[];
type Except = string[];
type Fields = string[];
type Sort = string[] | string;

interface SequelizeFindOptions {
  limit?: number;
  offset?: number;
}

interface FilterByTk {
  filterByTk?: TargetKey;
}

interface CommonFindOptions extends Transactionable {
  filter?: Filter;
  fields?: Fields;
  appends?: Appends;
  except?: Except;
  sort?: Sort;
}

type FindOptions = SequelizeFindOptions & CommonFindOptions & FilterByTk;
```

**Detailed Information**

#### `filter: Filter`

Query conditions for filtering data results. In the query parameters that passed in, `key` is the name of the field, `value` is the corresponding value. Operators can be used in conjunction with other filtering conditions.

```typescript
// Find records with name "foo" and age above 18
repository.find({
  filter: {
    name: 'foo',
    age: {
      $gt: 18,
    },
  },
});
```

Refer to [Operators](./operators.md) for more information.

#### `filterByTk: TargetKey`

Query data by `TargetKey`, this is shortcut for the `filter` parameter. The field of `TargetKey` can be [configured](./collection.md#filtertargetkey) in `Collection`, the default is `primaryKey`.

```typescript
// By default, find records with id 1
repository.find({
  filterByTk: 1,
});
```

#### `fields: string[]`

Query columns. It is used to control which data fields to output. With this parameter, only the specified fields will be returned.

#### `except: string[]`

Exclude columns. It is used to control which data fields to output. With this parameter, the specified fields will not be returned.

#### `appends: string[]`

Append columns. It is used to load associated data. With this parameter, the specified associated fields will be returned together.

#### `sort: string[] | string`

Specify the sorting method of the query results. The input parameter is the name of the field, by default is to sort in the ascending order (`asc`); a `-` symbol needs to be added before the field name to sort in the descending order (`desc`). For example, `['-id', 'name']` means to sort by `id desc, name asc`.

#### `limit: number`

Limit the number of results, same as `limit` in `SQL`.

#### `offset: number`

The offset of the query, same as `offset` in `SQL`.

**Example**

```ts
const posts = db.getRepository('posts');

const results = await posts.find({
  filter: {
    createdAt: {
      $gt: '2022-01-01T00:00:00.000Z',
    },
  },
  fields: ['title'],
  appends: ['user'],
});
```

### `findOne()`

Find a single piece of data from the database for specific conditions. Equivalent to `Model.findOne()` in Sequelize.

**Signature**

- `async findOne(options?: FindOneOptions): Promise<Model | null>`



**Example**

```ts
const posts = db.getRepository('posts');

const result = await posts.findOne({
  filterByTk: 1,
});
```

### `count()`

Query a certain amount of data from the database for specific conditions. Equivalent to `Model.count()` in Sequelize.

**Signature**

- `count(options?: CountOptions): Promise<number>`

**Type**

```typescript
interface CountOptions
  extends Omit<SequelizeCountOptions, 'distinct' | 'where' | 'include'>,
    Transactionable {
  filter?: Filter;
}
```

**Example**

```ts
const books = db.getRepository('books');

const count = await books.count({
  filter: {
    title: 'Three character classic',
  },
});
```

### `findAndCount()`

Find datasets from the database with the specified filtering conditions and return the number of results. Equivalent to `Model.findAndCountAll()` in Sequelize.

**Signature**

- `async findAndCount(options?: FindAndCountOptions): Promise<[Model[], number]>`

**Type**

```typescript
type FindAndCountOptions = Omit<
  SequelizeAndCountOptions,
  'where' | 'include' | 'order'
> &
  CommonFindOptions;
```

**Detailed Information**

The query parameters are the same as `find()`. An array is returned with the first element of the query results, and the second element of the total number of results.

### `create()`

Inserts a newly created data into the data table. Equivalent to `Model.create()` in Sequelize. When the data object to be created carries any associated field, the corresponding associated data record is created or updated along with it.

**Signature**

- `async create<M extends Model>(options: CreateOptions): Promise<M>`



**Example**

```ts
const posts = db.getRepository('posts');

const result = await posts.create({
  values: {
    title: 'NocoBase 1.0 Release Notes',
    tags: [
      // Update data when there is a primary key and value of the associated table
      { id: 1 },
      // Create data when there is no primary key and value
      { name: 'NocoBase' },
    ],
  },
});
```

### `createMany()`

Inserts multiple newly created data into the data table. This is equivalent to calling the `create()` method multiple times.

**Signature**

- `createMany(options: CreateManyOptions): Promise<Model[]>`

**Type**

```typescript
interface CreateManyOptions extends BulkCreateOptions {
  records: Values[];
}
```

**Detailed Information**

- `records`: An array of data objects to be created.
- `transaction`: Transaction object. If no transaction parameter is passed, the method will automatically create an internal transaction.

**Example**

```ts
const posts = db.getRepository('posts');

const results = await posts.createMany({
  records: [
    {
      title: 'NocoBase 1.0 Release Notes',
      tags: [
        // Update data when there is a primary key and value of the associated table
        { id: 1 },
        // Create data when there is no primary key and value
        { name: 'NocoBase' },
      ],
    },
    {
      title: 'NocoBase 1.1 Release Notes',
      tags: [{ id: 1 }],
    },
  ],
});
```

### `update()`

Update data in the data table. Equivalent to `Model.update()` in Sequelize. When the data object to be updated carries any associated field, the corresponding associated data record is created or updated along with it.

**Signature**

- `async update<M extends Model>(options: UpdateOptions): Promise<M>`



**Example**

```ts
const posts = db.getRepository('posts');

const result = await posts.update({
  filterByTk: 1,
  values: {
    title: 'NocoBase 1.0 Release Notes',
    tags: [
      // Update data when there is a primary key and value of the associated table
      { id: 1 },
      // Create data when there is no primary key and value
      { name: 'NocoBase' },
    ],
  },
});
```

### `destroy()`

Delete data from the data table. Equivalent to `Model.destroy()` in Sequelize.

**Signature**

- `async destroy(options?: TargetKey | TargetKey[] | DestoryOptions): Promise<number>`

**Type**

```typescript
interface DestroyOptions extends SequelizeDestroyOptions {
  filter?: Filter;
  filterByTk?: TargetKey | TargetKey[];
  truncate?: boolean;
  context?: any;
}
```

**Detailed Information**

- `filter`：Specify the filtering conditions of the records to be deleted. Refer to the [`find()`](#find) method for the detailed usage of the filter.
- `filterByTk`：Specify the filtering conditions by TargetKey.
- `truncate`: Whether to empty the table data, this parameter is valid if no `filter` or `filterByTk` parameter is passed.
- `transaction`: Transaction object. If no transaction parameter is passed, the method will automatically create an internal transaction.

---

## File: docs/en-US/api/database/shared.md

**Parameters**

| Parameter Name         | Type          | Default | Description                                           |
| ---------------------- | ------------- | ------- | ----------------------------------------------------- |
| `options.values`       | `M`           | `{}`    | The data object to be inserted                        |
| `options.whitelist?`   | `string[]`    | -       | Whitelist for the `values` field; only fields in the list will be stored |
| `options.blacklist?`   | `string[]`    | -       | Blacklist for the `values` field; fields in the list will not be stored |
| `options.transaction?` | `Transaction` | -       | Transaction                                            |

---

## File: docs/en-US/api/database/interfaces/base-interface.md

# BaseInterface

## Overview

BaseInterface is the foundational class for all Interface types. Users can extend this class to implement custom Interface logic.

```typescript
class CustomInterface extends BaseInterface {
  async toValue(value: string, ctx?: any): Promise<any> {
    // Custom toValue logic
  }

  toString(value: any, ctx?: any) {
    // Custom toString logic
  }
}
// Register Interface
db.interfaceManager.registerInterfaceType('customInterface', CustomInterface)
```

## Interfaces

### toValue(value: string, ctx?: any): Promise<any>

Converts an external string to the actual value of the interface, which can be directly passed to the Repository for write operations.

### toString(value: any, ctx?: any)

Converts the actual value of the interface to a string type, which can be used for exporting or displaying purposes.

---

## File: docs/en-US/api/database/relation-repository/belongs-to-many-repository.md

# BelongsToManyRepository

`BelongsToManyRepository` is the `Relation Repository` for handling `BelongsToMany` relationships.

Unlike other relationship types, the `BelongsToMany` type of relationship needs to be recorded through an intermediate table. The intermediate table can be created automatically or explicitly specified when defining association relationships in NocoBase.

## Class Methods

### `find()`

Find associated objects.

**Signature**

- `async find(options?: FindOptions): Promise<M[]>`

**Detailed Information**

Query parameters are the same as [`Repository.find()`](../repository.md#find).

### `findOne()`

Find associated objects, only to return one record.

**Signature**

- `async findOne(options?: FindOneOptions): Promise<M>`



### `count()`

Return the number of records matching the query criteria.

**Signature**

- `async count(options?: CountOptions)`

**Type**

```typescript
interface CountOptions
  extends Omit<SequelizeCountOptions, 'distinct' | 'where' | 'include'>,
    Transactionable {
  filter?: Filter;
}
```

### `findAndCount()`

Find datasets from the database with the specified filtering conditions and return the number of results.

**Signature**

- `async findAndCount(options?: FindAndCountOptions): Promise<[any[], number]>`

**Type**

```typescript
type FindAndCountOptions = CommonFindOptions;
```

### `create()`

Create associated objects.

**Signature**

- `async create(options?: CreateOptions): Promise<M>`



### `update()`

Update associated objects that match the conditions.

**Signature**

- `async update(options?: UpdateOptions): Promise<M>`



### `destroy()`

Delete associated objects.

**Signature**

- `async destroy(options?: TargetKey | TargetKey[] | DestroyOptions): Promise`



### `add()`

Add new associated objects.

**Signature**

- `async add(
options: TargetKey | TargetKey[] | PrimaryKeyWithThroughValues | PrimaryKeyWithThroughValues[] | AssociatedOptions
): Promise<void>`

**Type**

```typescript
type PrimaryKeyWithThroughValues = [TargetKey, Values];

interface AssociatedOptions extends Transactionable {
  tk?:
    | TargetKey
    | TargetKey[]
    | PrimaryKeyWithThroughValues
    | PrimaryKeyWithThroughValues[];
}
```

**Detailed Information**

Pass the `targetKey` of the associated object directly, or pass the `targetKey` along with the field values of the intermediate table.

**Example**

```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);

// Pass in the targetKey
PostTagRepository.add([t1.id, t2.id]);

// Pass in intermediate table fields
PostTagRepository.add([
  [t1.id, { tagged_at: '123' }],
  [t2.id, { tagged_at: '456' }],
]);
```

### `set()`

Set the associated objects.

**Signature**

- async set(
  options: TargetKey | TargetKey[] | PrimaryKeyWithThroughValues | PrimaryKeyWithThroughValues[] | AssociatedOptions,
  ): Promise<void>

**Detailed Information**

Parameters are the same as [add()](#add).

### `remove()`

Remove the association with the given objects.

**Signature**

- `async remove(options: TargetKey | TargetKey[] | AssociatedOptions)`

**Type**

```typescript
interface AssociatedOptions extends Transactionable {
  tk?: TargetKey | TargetKey[];
}
```

### `toggle()`

Toggle the associated object.

In some business scenarios, it is often needed to toggle the associated object. For example, user adds a product into collection, and the user cancels the collection and collect it again. Using the `toggle` method can quickly implement similar functions.

**Signature**

- `async toggle(options: TargetKey | { tk?: TargetKey; transaction?: Transaction }): Promise<void>`

**Detailed Information**

The `toggle` method automatically checks whether the associated object already exists, and removes it if it does, or adds it if it does not.

---

## File: docs/en-US/api/database/relation-repository/belongs-to-repository.md

## BelongsToRepository

The interface is the same as [HasOneRepository](./has-one-repository.md). `BelongsToRepository` is the `Repository` for handling `BelongsTo` relationships, and it provides some convenient methods to handle `BelongsTo` relationships.

---

## File: docs/en-US/api/database/relation-repository/has-many-repository.md

# HasManyRepository

`HasManyRepository` is the `Relation Repository` for handling `HasMany` relationships.

## Class Methods

### `find()`

Find associated objects.

**Signature**

- `async find(options?: FindOptions): Promise<M[]>`

**Detailed Information**

Query parameters are the same as [`Repository.find()`](../repository.md#find).

### `findOne()`

Find associated objects, only to return one record.

**Signature**

- `async findOne(options?: FindOneOptions): Promise<M>`



### `count()`

Return the number of records matching the query criteria.

**Signature**

- `async count(options?: CountOptions)`

**Type**

```typescript
interface CountOptions
  extends Omit<SequelizeCountOptions, 'distinct' | 'where' | 'include'>,
    Transactionable {
  filter?: Filter;
}
```

### `findAndCount()`

Find datasets from the database with the specified filtering conditions and return the number of results.

**Signature**

- `async findAndCount(options?: FindAndCountOptions): Promise<[any[], number]>`

**Type**

```typescript
type FindAndCountOptions = CommonFindOptions;
```

### `create()`

Create associated objects.

**Signature**

- `async create(options?: CreateOptions): Promise<M>`



### `update()`

Update associated objects that match the conditions.

**Signature**

- `async update(options?: UpdateOptions): Promise<M>`



### `destroy()`

Delete associated objects.

**Signature**

- `async destroy(options?: TK | DestroyOptions): Promise<M>`



### `add()`

Add association relationships between objects.

**Signature**

- `async add(options: TargetKey | TargetKey[] | AssociatedOptions)`

**Type**

```typescript
interface AssociatedOptions extends Transactionable {
  tk?: TargetKey | TargetKey[];
}
```

**Detailed Information**

- `tk` - The targetKey value of the associated object, either as a single value or an array.
  

### `remove()`

Remove the association with the given objects.

**Signature**

- `async remove(options: TargetKey | TargetKey[] | AssociatedOptions)`

**Detailed Information**

Same parameters as the [`add()`](#add) method.

### `set()`

Set the associated object of the current relationship.

**Signature**

- `async set(options: TargetKey | TargetKey[] | AssociatedOptions)`

**Detailed Information**

Same parameters as the [`add()`](#add) method.

---

## File: docs/en-US/api/database/relation-repository/has-one-repository.md

# HasOneRepository

## Overview

`HasOneRepository` is the associated repository of type `HasOne`.

```typescript
const User = db.collection({
  name: 'users',
  fields: [
    { type: 'hasOne', name: 'profile' },
    { type: 'string', name: 'name' },
  ],
});

const Profile = db.collection({
  name: 'profiles',
  fields: [{ type: 'string', name: 'avatar' }],
});

const user = await User.repository.create({
  values: { name: 'u1' },
});

// Get the associated repository
const userProfileRepository = User.repository
  .relation('profile')
  .of(user.get('id'));

// Or to initialize directly
new HasOneRepository(User, 'profile', user.get('id'));
```

## Class Methods

### `find()`

Find associated objects.

**Signature**

- `async find(options?: SingleRelationFindOption): Promise<Model<any> | null>`

**Type**

```typescript
interface SingleRelationFindOption extends Transactionable {
  fields?: Fields;
  except?: Except;
  appends?: Appends;
  filter?: Filter;
}
```

**Detailed Information**

Query parameters are the same as [`Repository.find()`](../repository.md#find).

**Example**

```typescript
const profile = await UserProfileRepository.find();
// Return null if the associated object does not exist
```

### `create()`

Create associated objects.

**Signature**

- `async create(options?: CreateOptions): Promise<Model>`



**Example**

```typescript
const profile = await UserProfileRepository.create({
  values: { avatar: 'avatar1' },
});

console.log(profile.toJSON());
/*
{
  id: 1,
  avatar: 'avatar1',
  userId: 1,
  updatedAt: 2022-09-24T13:59:40.025Z,
  createdAt: 2022-09-24T13:59:40.025Z
}
*/
```

### `update()`

Update associated objects.

**Signature**

- `async update(options: UpdateOptions): Promise<Model>`



**Example**

```typescript
const profile = await UserProfileRepository.update({
  values: { avatar: 'avatar2' },
});

profile.get('avatar'); // 'avatar2'
```

### `remove()`

Remove associated objects. Only to unassociate, not to delete the associated object.

**Signature**

- `async remove(options?: Transactionable): Promise<void>`

**Detailed Information**

- `transaction`: Transaction object. If no transaction parameter is passed, the method will automatically create an internal transaction.

**Example**

```typescript
await UserProfileRepository.remove();
(await UserProfileRepository.find()) == null; // true

(await Profile.repository.count()) === 1; // true
```

### `destroy()`

Delete associated objects.

**Signature**

- `async destroy(options?: Transactionable): Promise`

**Detailed Information**

- `transaction`: Transaction object. If no transaction parameter is passed, the method will automatically create an internal transaction.

**Example**

```typescript
await UserProfileRepository.destroy();
(await UserProfileRepository.find()) == null; // true
(await Profile.repository.count()) === 0; // true
```

### `set()`

Set associated objects.

**Signature**

- `async set(options: TargetKey | SetOption): Promise<void>`

**Type**

```typescript
interface SetOption extends Transactionable {
  tk?: TargetKey;
}
```

**Detailed Information**

- tk: Set the targetKey of the associated object.
- transaction: Transaction object. If no transaction parameter is passed, the method will automatically create an internal transaction.

**Example**

```typescript
const newProfile = await Profile.repository.create({
  values: { avatar: 'avatar2' },
});

await UserProfileRepository.set(newProfile.get('id'));

(await UserProfileRepository.find()).get('id') === newProfile.get('id'); // true
```

---

## File: docs/en-US/api/database/relation-repository/index.md

# RelationRepository

`RelationRepository` is a `Repository` object for relation types, which allows operations on associated data without loading the associations. Based on `RelationRepository`, each association type derives its corresponding implementation, which are:

- [`HasOneRepository`](#has-one-repository)
- `HasManyRepository`
- `BelongsToRepository`
- `BelongsToManyRepository`

## Constructor

**Signature**

- `constructor(sourceCollection: Collection, association: string, sourceKeyValue: string | number)`

**Parameters**

| Parameter Name     | Type               | Default Value | Description                                               |
| ------------------ | ------------------ | ------------- | --------------------------------------------------------- |
| `sourceCollection` | `Collection`       | -             | The Collection corresponding to the referencing relation in the association |
| `association`      | `string`           | -             | The name of the association                               |
| `sourceKeyValue`   | `string \| number` | -             | The key value corresponding to the referencing relation   |

## Base Class Properties

### `db: Database`

Database object

### `sourceCollection`

The Collection corresponding to the referencing relation in the association

### `targetCollection`

The Collection corresponding to the referenced relation in the association

### `association`

The association object in Sequelize corresponding to the current association

### `associationField`

The field in the Collection corresponding to the current association

### `sourceKeyValue`

The key value corresponding to the referencing relation

---

## File: docs/en-US/api/database/shared/create-options.md

**Type**

```typescript
type WhiteList = string[];
type BlackList = string[];
type AssociationKeysToBeUpdate = string[];

interface CreateOptions extends SequelizeCreateOptions {
  values?: Values;
  whitelist?: WhiteList;
  blacklist?: BlackList;
  updateAssociationValues?: AssociationKeysToBeUpdate;
  context?: any;
}
```

**Details**

- `values`: The data object of the record to be created.
- `whitelist`: Specifies which fields in the data object of the record to be created **can be written**. If this parameter is not passed, all fields are allowed to be written by default.
- `blacklist`: Specifies which fields in the data object of the record to be created **are not allowed to be written**. If this parameter is not passed, all fields are allowed to be written by default.
- `transaction`: The transaction object. If no transaction parameter is passed, the method will automatically create an internal transaction.

---

## File: docs/en-US/api/database/shared/destroy-options.md

**Type**

```typescript
interface DestroyOptions extends SequelizeDestroyOptions {
  filter?: Filter;
  filterByTk?: TargetKey | TargetKey[];
  truncate?: boolean;
  context?: any;
}
```

**Details**

- `filter`: Specifies the filtering conditions for the records to be deleted. For detailed usage of Filter, refer to the [`find()`](#find) method.
- `filterByTk`: Specifies the filtering conditions for the records to be deleted by TargetKey.
- `truncate`: Whether to truncate the table data, effective when no `filter` or `filterByTk` parameters are passed.
- `transaction`: Transaction object. If no transaction parameter is passed, the method will automatically create an internal transaction.

---

## File: docs/en-US/api/database/shared/find-one.md

**Type**

```typescript
type FindOneOptions = Omit<FindOptions, 'limit'>;
```

**Parameters**

Most parameters are the same as those in `find()`. The difference is that `findOne()` returns only a single piece of data, so the `limit` parameter is not needed, and the query is always set to `1`.

---

## File: docs/en-US/api/database/shared/find-options.md

[Empty file]

---

## File: docs/en-US/api/database/shared/transaction.md

- `transaction`: Transaction object. If no transaction parameter is passed, the method will automatically create an internal transaction.

---

## File: docs/en-US/api/database/shared/update-options.md

**Type**

```typescript
interface UpdateOptions extends Omit<SequelizeUpdateOptions, 'where'> {
  values: Values;
  filter?: Filter;
  filterByTk?: TargetKey;
  whitelist?: WhiteList;
  blacklist?: BlackList;
  updateAssociationValues?: AssociationKeysToBeUpdate;
  context?: any;
}
```

**Details**

- `values`: The data object of the records to be updated.
- `filter`: Specifies the filter conditions for the records to be updated. For detailed usage of Filter, refer to the [`find()`](#find) method.
- `filterByTk`: Specifies the filter conditions for the records to be updated by TargetKey.
- `whitelist`: A whitelist for the `values` fields. Only fields listed will be written.
- `blacklist`: A blacklist for the `values` fields. Fields listed will not be written.
- `transaction`: The transaction object. If no transaction parameter is passed, the method will automatically create an internal transaction.

At least one of `filterByTk` or `filter` must be provided.

---

## File: docs/en-US/api/field/markdown-vditor/index.md

# markdown

## Example

This is an embedded Markdown editor:

<MarkdownEditor />

---

## File: docs/en-US/api/handlebars-helpers/array.md

# Array

## {{after}}

Returns all of the items in an array after the specified index. Opposite of [before](#before).

**Params**

* `array` **{Array}**: Collection
* `n` **{Number}**: Starting index (number of items to exclude)
* `returns` **{Array}**: Array exluding `n` items.

**Example**

```handlebars
<!-- array: ['a', 'b', 'c'] -->
{{after array 1}}
<!-- results in: '["c"]' -->
```

## {{arrayify}}

Cast the given `value` to an array.

**Params**

* `value` **{any}**
* `returns` **{Array}**

**Example**

```handlebars
{{arrayify "foo"}}
<!-- results in: [ "foo" ] -->
```

## {{before}}

Return all of the items in the collection before the specified count. Opposite of [after](#after).

**Params**

* `array` **{Array}**
* `n` **{Number}**
* `returns` **{Array}**: Array excluding items after the given number.

**Example**

```handlebars
<!-- array: ['a', 'b', 'c'] -->
{{before array 2}}
<!-- results in: '["a", "b"]' -->
```

## {{eachIndex}}

**Params**

* `array` **{Array}**
* `options` **{Object}**
* `returns` **{String}**

**Example**

```handlebars
<!-- array: ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'] -->
{{#eachIndex array}}
  {{item}} is {{index}}
{{/eachIndex}}
```

## {{filter}}

Block helper that filters the given array and renders the block for values that evaluate to `true`, otherwise the inverse block is returned.

**Params**

* `array` **{Array}**
* `value` **{any}**
* `options` **{Object}**
* `returns` **{String}**

**Example**

```handlebars
<!-- array: ['a', 'b', 'c'] -->
{{#filter array "foo"}}AAA{{else}}BBB{{/filter}}
<!-- results in: 'BBB' -->
```

## {{first}}

Returns the first item, or first `n` items of an array.

**Params**

* `array` **{Array}**
* `n` **{Number}**: Number of items to return, starting at `0`.
* `returns` **{Array}**

**Example**

```handlebars
{{first "['a', 'b', 'c', 'd', 'e']" 2}}
<!-- results in: '["a", "b"]' -->
```

## {{forEach}}

Iterates over each item in an array and exposes the current item in the array as context to the inner block. In addition to the current array item, the helper exposes the following variables to the inner block:

* `index`
* `total`
* `isFirst`
* `isLast`
Also, `@index` is exposed as a private variable, and additional
private variables may be defined as hash arguments.

**Params**

* `array` **{Array}**
* `returns` **{String}**

**Example**

```handlebars
<!-- accounts = [
{'name': 'John', 'email': 'john@example.com'},
{'name': 'Malcolm', 'email': 'malcolm@example.com'},
{'name': 'David', 'email': 'david@example.com'}
] -->

{{#forEach accounts}}
  <a href="mailto:{{ email }}" title="Send an email to {{ name }}">
    {{ name }}
  </a>{{#unless isLast}}, {{/unless}}
{{/forEach}}
```

## {{inArray}}

Block helper that renders the block if an array has the given `value`. Optionally specify an inverse block to render when the array does not have the given value.

**Params**

* `array` **{Array}**
* `value` **{any}**
* `options` **{Object}**
* `returns` **{String}**

**Example**

```handlebars
<!-- array: ['a', 'b', 'c'] -->
{{#inArray array "d"}}
  foo
{{else}}
  bar
{{/inArray}}
<!-- results in: 'bar' -->
```

## {{isArray}}

Returns true if `value` is an es5 array.

**Params**

* `value` **{any}**: The value to test.
* `returns` **{Boolean}**

**Example**

```handlebars
{{isArray "abc"}}
<!-- results in: false -->

<!-- array: [1, 2, 3] -->
{{isArray array}}
<!-- results in: true -->
```

## {{itemAt}}

Returns the item from `array` at index `idx`.

**Params**

* `array` **{Array}**
* `idx` **{Number}**
* `returns` **{any}** `value`

**Example**

```handlebars
<!-- array: ['a', 'b', 'c'] -->
{{itemAt array 1}}
<!-- results in: 'b' -->
```

## {{join}}

Join all elements of array into a string, optionally using a given separator.

**Params**

* `array` **{Array}**
* `separator` **{String}**: The separator to use. Defaults to `,`.
* `returns` **{String}**

**Example**

```handlebars
<!-- array: ['a', 'b', 'c'] -->
{{join array}}
<!-- results in: 'a, b, c' -->

{{join array '-'}}
<!-- results in: 'a-b-c' -->
```

## {{equalsLength}}

Returns true if the the length of the given `value` is equal
to the given `length`. Can be used as a block or inline helper.

**Params**

* `value` **{Array|String}**
* `length` **{Number}**
* `options` **{Object}**
* `returns` **{String}**

## {{last}}

Returns the last item, or last `n` items of an array or string. Opposite of [first](#first).

**Params**

* `value` **{Array|String}**: Array or string.
* `n` **{Number}**: Number of items to return from the end of the array.
* `returns` **{Array}**

**Example**

```handlebars
<!-- var value = ['a', 'b', 'c', 'd', 'e'] -->

{{last value}}
<!-- results in: ['e'] -->

{{last value 2}}
<!-- results in: ['d', 'e'] -->

{{last value 3}}
<!-- results in: ['c', 'd', 'e'] -->
```

## {{length}}

Returns the length of the given string or array.

**Params**

* `value` **{Array|Object|String}**
* `returns` **{Number}**: The length of the value.

**Example**

```handlebars
{{length '["a", "b", "c"]'}}
<!-- results in: 3 -->

<!-- results in: myArray = ['a', 'b', 'c', 'd', 'e']; -->
{{length myArray}}
<!-- results in: 5 -->

<!-- results in: myObject = {'a': 'a', 'b': 'b'}; -->
{{length myObject}}
<!-- results in: 2 -->
```

## {{lengthEqual}}

Alias for [equalsLength](#equalsLength)

## {{map}}

Returns a new array, created by calling `function` on each element of the given `array`. For example,

**Params**

* `array` **{Array}**
* `fn` **{Function}**
* `returns` **{String}**

**Example**

```handlebars
<!-- array: ['a', 'b', 'c'], and "double" is a
fictitious function that duplicates letters -->
{{map array double}}
<!-- results in: '["aa", "bb", "cc"]' -->
```

## {{pluck}}

Map over the given object or array or objects and create an array of values from the given `prop`. Dot-notation may be used (as a string) to get nested properties.

**Params**

* `collection` **{Array|Object}**
* `prop` **{Function}**
* `returns` **{String}**

**Example**

```handlebars
// {{pluck items "data.title"}}
<!-- results in: '["aa", "bb", "cc"]' -->
```

## {{reverse}}

Reverse the elements in an array, or the characters in a string.

**Params**

* `value` **{Array|String}**
* `returns` **{Array|String}**: Returns the reversed string or array.

**Example**

```handlebars
<!-- value: 'abcd' -->
{{reverse value}}
<!-- results in: 'dcba' -->
<!-- value: ['a', 'b', 'c', 'd'] -->
{{reverse value}}
<!-- results in: ['d', 'c', 'b', 'a'] -->
```

## {{some}}

Block helper that returns the block if the callback returns true for some value in the given array.

**Params**

* `array` **{Array}**
* `iter` **{Function}**: Iteratee
* **{Options}**: Handlebars provided options object
* `returns` **{String}**

**Example**

```handlebars
<!-- array: [1, 'b', 3] -->
{{#some array isString}}
  Render me if the array has a string.
{{else}}
  Render me if it doesn't.
{{/some}}
<!-- results in: 'Render me if the array has a string.' -->
```

## {{sort}}

Sort the given `array`. If an array of objects is passed, you may optionally pass a `key` to sort on as the second argument. You may alternatively pass a sorting function as the second argument.

**Params**

* `array` **{Array}**: the array to sort.
* `key` **{String|Function}**: The object key to sort by, or sorting function.

**Example**

```handlebars
<!-- array: ['b', 'a', 'c'] -->
{{sort array}}
<!-- results in: '["a", "b", "c"]' -->
```

## {{sortBy}}

Sort an `array`. If an array of objects is passed, you may optionally pass a `key` to sort on as the second argument. You may alternatively pass a sorting function as the second argument.

**Params**

* `array` **{Array}**: the array to sort.
* `props` **{String|Function}**: One or more properties to sort by, or sorting functions to use.

**Example**

```handlebars
<!-- array: [{a: 'zzz'}, {a: 'aaa'}] -->
{{sortBy array "a"}}
<!-- results in: '[{"a":"aaa"}, {"a":"zzz"}]' -->
```

## {{withAfter}}

Use the items in the array _after_ the specified index as context inside a block. Opposite of [withBefore](#withBefore).

**Params**

* `array` **{Array}**
* `idx` **{Number}**
* `options` **{Object}**
* `returns` **{Array}**

**Example**

```handlebars
<!-- array: ['a', 'b', 'c', 'd', 'e'] -->
{{#withAfter array 3}}
  {{this}}
{{/withAfter}}
<!-- results in: "de" -->
```

## {{withBefore}}

Use the items in the array _before_ the specified index as context inside a block. Opposite of [withAfter](#withAfter).

**Params**

* `array` **{Array}**
* `idx` **{Number}**
* `options` **{Object}**
* `returns` **{Array}**

**Example**

```handlebars
<!-- array: ['a', 'b', 'c', 'd', 'e'] -->
{{#withBefore array 3}}
  {{this}}
{{/withBefore}}
<!-- results in: 'ab' -->
```

## {{withFirst}}

Use the first item in a collection inside a handlebars block expression. Opposite of [withLast](#withLast).

**Params**

* `array` **{Array}**
* `idx` **{Number}**
* `options` **{Object}**
* `returns` **{String}**

**Example**

```handlebars
<!-- array: ['a', 'b', 'c'] -->
{{#withFirst array}}
  {{this}}
{{/withFirst}}
<!-- results in: 'a' -->
```

## {{withGroup}}

Block helper that groups array elements by given group `size`.

**Params**

* `array` **{Array}**: The array to iterate over
* `size` **{Number}**: The desired length of each array "group"
* `options` **{Object}**: Handlebars options
* `returns` **{String}**

**Example**

```handlebars
<!-- array: ['a','b','c','d','e','f','g','h'] -->
{{#withGroup array 4}}
  {{#each this}}
    {{.}}
  {{each}}
  <br>
{{/withGroup}}
<!-- results in: -->
<!-- 'a','b','c','d'<br> -->
<!-- 'e','f','g','h'<br> -->
```

## {{withLast}}

Use the last item or `n` items in an array as context inside a block. Opposite of [withFirst](#withFirst).

**Params**

* `array` **{Array}**
* `idx` **{Number}**: The starting index.
* `options` **{Object}**
* `returns` **{String}**

**Example**

```handlebars
<!-- array: ['a', 'b', 'c'] -->
{{#withLast array}}
  {{this}}
{{/withLast}}
<!-- results in: 'c' -->
```

## {{withSort}}

Block helper that sorts a collection and exposes the sorted collection as context inside the block.

**Params**

* `array` **{Array}**
* `prop` **{String}**
* `options` **{Object}**: Specify `reverse="true"` to reverse the array.
* `returns` **{String}**

**Example**

```handlebars
<!-- array: ['b', 'a', 'c'] -->
{{#withSort array}}{{this}}{{/withSort}}
<!-- results in: 'abc' -->
```

## {{unique}}

Block helper that return an array with all duplicate values removed. Best used along with a [each](#each) helper.

**Params**

* `array` **{Array}**
* `options` **{Object}**
* `returns` **{Array}**

**Example**

```handlebars
<!-- array: ['a', 'a', 'c', 'b', 'e', 'e'] -->
{{#each (unique array)}}{{.}}{{/each}}
<!-- results in: 'acbe' -->
```

---

## File: docs/en-US/api/handlebars-helpers/comparison.md

# Comparison

## {{and}}

Helper that renders the block if **both** of the given values are truthy. If an inverse block is specified it will be rendered when falsy. Works as a block helper, inline helper or subexpression.

**Params**

* `a` **{any}**
* `b` **{any}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**

**Example**

```handlebars
<!-- {great: true, magnificent: true} -->
{{#and great magnificent}}A{{else}}B{{/and}}
<!-- results in: 'A' -->
```

## {{compare}}

Render a block when a comparison of the first and third
arguments returns true. The second argument is
the [arithemetic operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operators) to use. You may also
optionally specify an inverse block to render when falsy.

**Params**

* `a` **{}**
* `operator` **{}**: The operator to use. Operators must be enclosed in quotes: `">"`, `"="`, `"<="`, and so on.
* `b` **{}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**: Block, or if specified the inverse block is rendered if falsey.

## {{contains}}

Block helper that renders the block if `collection` has the given `value`, using strict equality (`===`) for comparison, otherwise the inverse block is rendered (if specified). If a `startIndex` is specified and is negative, it is used as the offset from the end of the collection.

**Params**

* `collection` **{Array|Object|String}**: The collection to iterate over.
* `value` **{any}**: The value to check for.
* `[startIndex=0]` **{Number}**: Optionally define the starting index.
* `options` **{Object}**: Handlebars provided options object.

**Example**

```handlebars
<!-- array = ['a', 'b', 'c'] -->
{{#contains array "d"}}
  This will not be rendered.
{{else}}
  This will be rendered.
{{/contains}}
```

## {{default}}

Returns the first value that is not undefined, otherwise the "default" value is returned.

**Params**

* `value` **{any}**
* `defaultValue` **{any}**
* `returns` **{String}**

## {{eq}}

Block helper that renders a block if `a` is **equal to** `b`.
If an inverse block is specified it will be rendered when falsy.
You may optionally use the `compare=""` hash argument for the
second value.

**Params**

* `a` **{String}**
* `b` **{String}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**: Block, or inverse block if specified and falsey.

## {{gt}}

Block helper that renders a block if `a` is **greater than** `b`.

If an inverse block is specified it will be rendered when falsy.
You may optionally use the `compare=""` hash argument for the
second value.

**Params**

* `a` **{String}**
* `b` **{String}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**: Block, or inverse block if specified and falsey.

## {{gte}}

Block helper that renders a block if `a` is **greater than or equal to** `b`.

If an inverse block is specified it will be rendered when falsy.
You may optionally use the `compare=""` hash argument for the
second value.

**Params**

* `a` **{String}**
* `b` **{String}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**: Block, or inverse block if specified and falsey.

## {{has}}

Block helper that renders a block if `value` has `pattern`.
If an inverse block is specified it will be rendered when falsy.

**Params**

* `val` **{any}**: The value to check.
* `pattern` **{any}**: The pattern to check for.
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**

## {{isEmpty}}

Inline, subexpression, or block helper that returns true (or the block) if the given collection is empty, or false (or the inverse block, if supplied) if the colleciton is not empty.

**Params**

* `collection` **{Object}**
* `options` **{Object}**
* `returns` **{String}**

**Example**

```handlebars
<!-- array: [] -->
{{#isEmpty array}}AAA{{else}}BBB{{/isEmpty}}
<!-- results in: 'AAA' -->

<!-- array: [] -->
{{isEmpty array}}
<!-- results in: true -->
```

## {{isFalsey}}

Returns true if the given `value` is falsey. Uses the [falsey](https://github.com/jonschlinkert/falsey)
library for comparisons. Please see that library for more information
or to report bugs with this helper.

**Params**

* `val` **{any}**
* `options` **{Options}**
* `returns` **{Boolean}**

## {{isTruthy}}

Returns true if the given `value` is truthy. Uses the [falsey](https://github.com/jonschlinkert/falsey)
library for comparisons. Please see that library for more information
or to report bugs with this helper.

**Params**

* `val` **{any}**
* `options` **{Options}**
* `returns` **{Boolean}**

## {{ifEven}}

Return true if the given value is an even number.

**Params**

* `number` **{Number}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**: Block, or inverse block if specified and falsey.

**Example**

```handlebars
{{#ifEven value}}
  render A
{{else}}
  render B
{{/ifEven}}
```

## {{ifNth}}

Conditionally renders a block if the remainder is zero when
`a` operand is divided by `b`. If an inverse block is specified
it will be rendered when the remainder is **not zero**.

**Params**

* **{}**: {Number}
* **{}**: {Number}
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**: Block, or inverse block if specified and falsey.

## {{ifOdd}}

Block helper that renders a block if `value` is **an odd number**. If an inverse block is specified it will be rendered when falsy.

**Params**

* `value` **{Object}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**: Block, or inverse block if specified and falsey.

**Example**

```handlebars
{{#ifOdd value}}
  render A
{{else}}
  render B
{{/ifOdd}}
```

## {{is}}

Block helper that renders a block if `a` is **equal to** `b`.
If an inverse block is specified it will be rendered when falsy.
Similar to [eq](#eq) but does not do strict equality.

**Params**

* `a` **{any}**
* `b` **{any}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**

## {{isnt}}

Block helper that renders a block if `a` is **not equal to** `b`.
If an inverse block is specified it will be rendered when falsy.
Similar to [unlessEq](#unlesseq) but does not use strict equality for
comparisons.

**Params**

* `a` **{String}**
* `b` **{String}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**

## {{lt}}

Block helper that renders a block if `a` is **less than** `b`.

If an inverse block is specified it will be rendered when falsy.
You may optionally use the `compare=""` hash argument for the
second value.

**Params**

* `context` **{Object}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**: Block, or inverse block if specified and falsey.

## {{lte}}

Block helper that renders a block if `a` is **less than or equal to** `b`.

If an inverse block is specified it will be rendered when falsy.
You may optionally use the `compare=""` hash argument for the
second value.

**Params**

* `a` **{Sring}**
* `b` **{Sring}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**: Block, or inverse block if specified and falsey.

## {{neither}}

Block helper that renders a block if **neither of** the given values
are truthy. If an inverse block is specified it will be rendered
when falsy.

**Params**

* `a` **{any}**
* `b` **{any}**
* `options` **{}**: Handlebars options object
* `returns` **{String}**: Block, or inverse block if specified and falsey.

## {{not}}

Returns true if `val` is falsey. Works as a block or inline helper.

**Params**

* `val` **{String}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**

## {{or}}

Block helper that renders a block if **any of** the given values is truthy. If an inverse block is specified it will be rendered when falsy.

**Params**

* `arguments` **{...any}**: Variable number of arguments
* `options` **{Object}**: Handlebars options object
* `returns` **{String}**: Block, or inverse block if specified and falsey.

**Example**

```handlebars
{{#or a b c}}
  If any value is true this will be rendered.
{{/or}}
```

## {{unlessEq}}

Block helper that always renders the inverse block **unless `a` is
is equal to `b`**.

**Params**

* `a` **{String}**
* `b` **{String}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**: Inverse block by default, or block if falsey.

## {{unlessGt}}

Block helper that always renders the inverse block **unless `a` is
is greater than `b`**.

**Params**

* `a` **{Object}**: The default value
* `b` **{Object}**: The value to compare
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**: Inverse block by default, or block if falsey.

## {{unlessLt}}

Block helper that always renders the inverse block **unless `a` is
is less than `b`**.

**Params**

* `a` **{Object}**: The default value
* `b` **{Object}**: The value to compare
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**: Block, or inverse block if specified and falsey.

## {{unlessGteq}}

Block helper that always renders the inverse block **unless `a` is
is greater than or equal to `b`**.

**Params**

* `a` **{any}**
* `b` **{any}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**: Block, or inverse block if specified and falsey.

## {{unlessLteq}}

Block helper that always renders the inverse block **unless `a` is
is less than or equal to `b`**.

**Params**

* `a` **{any}**
* `b` **{any}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**: Block, or inverse block if specified and falsey.

---

## File: docs/en-US/api/handlebars-helpers/core.md

# Built-in Helpers

https://handlebarsjs.com/guide/builtin-helpers.html

## {{if}}

Renders a block if the given condition is truthy.

**Params**

- `condition` **{Any}**: The condition to evaluate.

**Returns**: The content inside the block if the condition is truthy, otherwise returns nothing.

**Example**

```handlebars
{{#if condition}}
  This will be displayed if the condition is true.
{{/if}}
```

## {{unless}}

Renders a block if the given condition is falsy. This is the opposite of `if`.

**Params**

- `condition` **{Any}**: The condition to evaluate.

**Returns**: The content inside the block if the condition is falsy, otherwise returns nothing.

**Example**

```handlebars
{{#unless condition}}
  This will be displayed if the condition is false.
{{/unless}}
```

---

## {{each}}

Iterates over an array or object and renders a block for each item.

**Params**

- `collection` **{Array|Object}**: The array or object to iterate over.

**Returns**: Renders the block for each item in the collection.

**Example**

```handlebars
{{#each items}}
  <li>{{this}}</li>
{{/each}}
```

## {{with}}

Renders a block with a given context. It allows you to specify a context for the block, simplifying access to deeply nested properties.

**Params**

- `context` **{Any}**: The context to use within the block.

**Returns**: Renders the block with the provided context.

**Example**

```handlebars
{{#with person}}
  <p>Name: {{name}}</p>
  <p>Age: {{age}}</p>
{{/with}}
```

## {{lookup}}

Looks up the value of a specified key in an object. This helper is useful for accessing dynamic keys.

**Params**

- `context` **{Object}**: The object to look up the key from.
- `key` **{String|Number}**: The key to look up.

**Returns**: The value of the specified key in the object.

**Example**

```handlebars
{{lookup person "name"}}
<!-- If person is { name: "Alice", age: 30 }, it results in: "Alice" -->
```

---

## File: docs/en-US/api/handlebars-helpers/date.md

# Date

## {{dateFormat}}

The "dateFormat" helper in Handlebars is used to format a date using the day.js library. It takes two required arguments and an optional third argument for the timezone.

**Params**

* `datetime` **{String}**
* `format` **{String}**
* `timezone` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{dateFormat now "YYYY-MM-DD HH:mm:ss"}}
{{dateFormat now "YYYY-MM-DD HH:mm:ss" "Asia/Tokyo"}}
{{dateFormat now "YYYY-MM-DD HH:mm:ss" "UTC"}}
```

---

## File: docs/en-US/api/handlebars-helpers/html.md

# HTML

## {{qrcode}}

---

## File: docs/en-US/api/handlebars-helpers/i18n.md

# I18n

## {{t}}

**Params**

* `key` **{String}**
* `ns` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{t "Today"}}
{{t "Permissions" "@nocobase/plugin-acl"}}
```

---

## File: docs/en-US/api/handlebars-helpers/index.md

# Handlebars Helpers

| Category       | Description                         |
|-------------|-------------------------------------|
| [Core](./core.md)      | Built-in helpers        |
| [Array](./array.md)       | Operations and methods related to arrays       |
| [Comparison](./comparison.md) | Comparison operators and related methods       |
| [Date](./date.md)        | Operations and methods related to date and time handling |
| [HTML](./html.md)        | Content related to HTML documents and elements  |
| [I18n](./i18n.md)        | Support for internationalization and multilingual handling |
| [Math](./math.md)        | Mathematical functions and calculations       |
| [Number](./number.md)    | Content related to number handling and formatting |
| [Object](./object.md)    | Methods related to object operations and properties |
| [Path](./path.md)        | Path operations and content related to the file system |
| [Regex](./regex.md)      | Regular expressions and their usage            |
| [String](./string.md)    | Methods related to string manipulation and operations |
| [URL](./url.md)          | Content related to URL parsing and construction  |

---

## File: docs/en-US/api/handlebars-helpers/math.md

# Math

## {{abs}}

Return the magnitude of `a`.

**Params**

* `a` **{Number}**
* `returns` **{Number}**

## {{add}}

Return the sum of `a` plus `b`.

**Params**

* `a` **{Number}**
* `b` **{Number}**
* `returns` **{Number}**

## {{avg}}

Returns the average of all numbers in the given array.

**Params**

* `array` **{Array}**: Array of numbers to add up.
* `returns` **{Number}**

**Example**

```handlebars
{{avg "[1, 2, 3, 4, 5]"}}
<!-- results in: '3' -->
```

## {{ceil}}

Get the `Math.ceil()` of the given value.

**Params**

* `value` **{Number}**
* `returns` **{Number}**

## {{divide}}

Divide `a` by `b`

**Params**

* `a` **{Number}**: numerator
* `b` **{Number}**: denominator

## {{floor}}

Get the `Math.floor()` of the given value.

**Params**

* `value` **{Number}**
* `returns` **{Number}**

## {{minus}}

Return the difference of `a` minus `b`.

**Params**

* `a` **{Number}**
* `b` **{Number}**

## {{modulo}}

Get the remainder of a division operation.

**Params**

* `a` **{Number}**
* `b` **{Number}**
* `returns` **{Number}**

## {{multiply}}

Return the product of `a` times `b`.

**Params**

* `a` **{Number}**: factor
* `b` **{Number}**: multiplier
* `returns` **{Number}**

## {{plus}}

Add `a` by `b`.

**Params**

* `a` **{Number}**: factor
* `b` **{Number}**: multiplier

## {{random}}

Generate a random number between two values

**Params**

* `min` **{Number}**
* `max` **{Number}**
* `returns` **{String}**

## {{remainder}}

Get the remainder when `a` is divided by `b`.

**Params**

* `a` **{Number}**: a
* `b` **{Number}**: b

## {{round}}

Round the given number.

**Params**

* `number` **{Number}**
* `returns` **{Number}**

## {{subtract}}

Return the product of `a` minus `b`.

**Params**

* `a` **{Number}**
* `b` **{Number}**
* `returns` **{Number}**

## {{sum}}

Returns the sum of all numbers in the given array.

**Params**

* `array` **{Array}**: Array of numbers to add up.
* `returns` **{Number}**

**Example**

```handlebars
{{sum "[1, 2, 3, 4, 5]"}}
<!-- results in: '15' -->
```

## {{times}}

Multiply number `a` by number `b`.

**Params**

* `a` **{Number}**: factor
* `b` **{Number}**: multiplier
* `returns` **{Number}**

---

## File: docs/en-US/api/handlebars-helpers/number.md

# Number

## {{bytes}}

Format a number to it's equivalent in bytes. If a string is passed, it's length will be formatted and returned.

**Examples:**

* `'foo' => 3 B`
* `13661855 => 13.66 MB`
* `825399 => 825.39 kB`
* `1396 => 1.4 kB`

**Params**

* `number` **{Number|String}**
* `returns` **{String}**

## {{addCommas}}

Add commas to numbers

**Params**

* `num` **{Number}**
* `returns` **{Number}**

## {{phoneNumber}}

Convert a string or number to a formatted phone number.

**Params**

* `num` **{Number|String}**: The phone number to format, e.g. `8005551212`
* `returns` **{Number}**: Formatted phone number: `(800) 555-1212`

## {{toAbbr}}

Abbreviate numbers to the given number of `precision`. This is for
general numbers, not size in bytes.

**Params**

* `number` **{Number}**
* `precision` **{Number}**
* `returns` **{String}**

## {{toExponential}}

Returns a string representing the given number in exponential notation.

**Params**

* `number` **{Number}**
* `fractionDigits` **{Number}**: Optional. An integer specifying the number of digits to use after the decimal point. Defaults to as many digits as necessary to specify the number.
* `returns` **{Number}**

**Example**

```handlebars
{{toExponential number digits}};
```

## {{toFixed}}

Formats the given number using fixed-point notation.

**Params**

* `number` **{Number}**
* `digits` **{Number}**: (Optional) The number of digits to appear after the decimal point; this may be a value between 0 and 20. If this argument is omitted, it is treated as 0.
* `returns` **{String}**: A string representing the given number using fixed-point notation.

**Example**

```handlebars
{{toFixed "1.1234" 2}}
//=> '1.12'
```

## {{toFloat}}

**Params**

* `number` **{Number}**
* `returns` **{Number}**

## {{toInt}}

**Params**

* `number` **{Number}**
* `returns` **{Number}**

## {{toPrecision}}

Returns a string representing the `Number` object to the specified precision.

**Params**

* `number` **{Number}**
* `precision` **{Number}**: (Optional) An integer specifying the number of significant digits. If precison is not between 1 and 100 (inclusive), it will be coerced to `0`.
* `returns` **{String}**: A string representing a Number object in fixed-point or exponential notation rounded to precision significant digits.

**Example**

```handlebars
{{toPrecision "1.1234" 2}}
//=> '1.1'
```

---

## File: docs/en-US/api/handlebars-helpers/object.md

# Object

## {{extend}}

Extend the context with the properties of other objects.
A shallow merge is performed to avoid mutating the context.

**Params**

* `objects` **{Object}**: One or more objects to extend.
* `returns` **{Object}**

## {{forIn}}

Block helper that iterates over the properties of
an object, exposing each key and value on the context.

**Params**

* `context` **{Object}**
* `options` **{Object}**
* `returns` **{String}**

## {{forOwn}}

Block helper that iterates over the **own** properties of
an object, exposing each key and value on the context.

**Params**

* `obj` **{Object}**: The object to iterate over.
* `options` **{Object}**
* `returns` **{String}**

## {{toPath}}

Take arguments and, if they are string or number, convert them to a dot-delineated object property path.

**Params**

* `prop` **{String|Number}**: The property segments to assemble (can be multiple).
* `returns` **{String}**

## {{get}}

Use property paths (`a.b.c`) to get a value or nested value from
the context. Works as a regular helper or block helper.

**Params**

* `prop` **{String}**: The property to get, optionally using dot notation for nested properties.
* `context` **{Object}**: The context object
* `options` **{Object}**: The handlebars options object, if used as a block helper.
* `returns` **{String}**

## {{getObject}}

Use property paths (`a.b.c`) to get an object from
the context. Differs from the `get` helper in that this
helper will return the actual object, including the
given property key. Also, this helper does not work as a
block helper.

**Params**

* `prop` **{String}**: The property to get, optionally using dot notation for nested properties.
* `context` **{Object}**: The context object
* `returns` **{String}**

## {{hasOwn}}

Return true if `key` is an own, enumerable property of the given `context` object.

**Params**

* `key` **{String}**
* `context` **{Object}**: The context object.
* `returns` **{Boolean}**

**Example**

```handlebars
{{hasOwn context key}}
```

## {{isObject}}

Return true if `value` is an object.

**Params**

* `value` **{String}**
* `returns` **{Boolean}**

**Example**

```handlebars
{{isObject "foo"}}
//=> false
```

## {{JSONparse}}

Parses the given string using `JSON.parse`.

**Params**

* `string` **{String}**: The string to parse

**Example**

```handlebars
<!-- string: '{"foo": "bar"}' -->
{{JSONparse string}}
<!-- results in: { foo: 'bar' } -->
```

## {{JSONstringify}}

Stringify an object using `JSON.stringify`.

**Params**

* `obj` **{Object}**: Object to stringify
* `returns` **{String}**

**Example**

```handlebars
<!-- object: { foo: 'bar' } -->
{{JSONstringify object}}
<!-- results in: '{"foo": "bar"}' -->
```

## {{merge}}

Deeply merge the properties of the given `objects` with the
context object.

**Params**

* `object` **{Object}**: The target object. Pass an empty object to shallow clone.
* `objects` **{Object}**
* `returns` **{Object}**

## {{pick}}

Pick properties from the context object.

**Params**

* `properties` **{Array|String}**: One or more properties to pick.
* `context` **{Object}**
* `options` **{Object}**: Handlebars options object.
* `returns` **{Object}**: Returns an object with the picked values. If used as a block helper, the values are passed as context to the inner block. If no values are found, the context is passed to the inverse block.

---

## File: docs/en-US/api/handlebars-helpers/path.md

# Path

## {{absolute}}

Get the directory path segment from the given `filepath`.

**Params**

* `ext` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{absolute "docs/toc.md"}}
<!-- results in: 'docs' -->
```

## {{dirname}}

Get the directory path segment from the given `filepath`.

**Params**

* `ext` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{dirname "docs/toc.md"}}
<!-- results in: 'docs' -->
```

## {{relative}}

Get the relative filepath from `a` to `b`.

**Params**

* `a` **{String}**
* `b` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{relative a b}}
```

## {{basename}}

Get the file extension from the given `filepath`.

**Params**

* `ext` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{basename "docs/toc.md"}}
<!-- results in: 'toc.md' -->
```

## {{stem}}

Get the "stem" from the given `filepath`.

**Params**

* `filepath` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{stem "docs/toc.md"}}
<!-- results in: 'toc' -->
```

## {{extname}}

Get the file extension from the given `filepath`.

**Params**

* `filepath` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{extname "docs/toc.md"}}
<!-- results in: '.md' -->
```

## {{resolve}}

Resolve an absolute path from the given `filepath`.

**Params**

* `filepath` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{resolve "docs/toc.md"}}
<!-- results in: '/User/dev/docs/toc.md' -->
```

## {{segments}}

Get specific (joined) segments of a file path by passing a range of array indices.

**Params**

* `filepath` **{String}**: The file path to split into segments.
* `returns` **{String}**: Returns a single, joined file path.

**Example**

```handlebars
{{segments "a/b/c/d" "2" "3"}}
<!-- results in: 'c/d' -->

{{segments "a/b/c/d" "1" "3"}}
<!-- results in: 'b/c/d' -->

{{segments "a/b/c/d" "1" "2"}}
<!-- results in: 'b/c' -->
```

---

## File: docs/en-US/api/handlebars-helpers/regex.md

# Regex

## {{toRegex}}

Convert the given string to a regular expression.

**Params**

* `str` **{String}**
* `returns` **{RegExp}**

**Example**

```handlebars
{{toRegex "foo"}}
<!-- results in: /foo/ -->
```

## {{test}}

Returns true if the given `str` matches the given regex. A regex can be passed on the context, or using the [toRegex](#toregex) helper as a subexpression.

**Params**

* `str` **{String}**
* `returns` **{RegExp}**

**Example**

```handlebars
{{test "bar" (toRegex "foo")}}
<!-- results in: false -->
{{test "foobar" (toRegex "foo")}}
<!-- results in: true -->
{{test "foobar" (toRegex "^foo$")}}
<!-- results in: false -->
```

---

## File: docs/en-US/api/handlebars-helpers/string.md

# String

## {{append}}

Append the specified `suffix` to the given string.

**Params**

* `str` **{String}**
* `suffix` **{String}**
* `returns` **{String}**

**Example**

```handlebars
<!-- given that "item.stem" is "foo" -->
{{append item.stem ".html"}}
<!-- results in:  'foo.html' -->
```

## {{camelcase}}

camelCase the characters in the given `string`.

**Params**

* `string` **{String}**: The string to camelcase.
* `returns` **{String}**

**Example**

```handlebars
{{camelcase "foo bar baz"}};
<!-- results in:  'fooBarBaz' -->
```

## {{capitalize}}

Capitalize the first word in a sentence.

**Params**

* `str` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{capitalize "foo bar baz"}}
<!-- results in:  "Foo bar baz" -->
```

## {{capitalizeAll}}

Capitalize all words in a string.

**Params**

* `str` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{capitalizeAll "foo bar baz"}}
<!-- results in:  "Foo Bar Baz" -->
```

## {{center}}

Center a string using non-breaking spaces

**Params**

* `str` **{String}**
* `spaces` **{String}**
* `returns` **{String}**

## {{chop}}

Like trim, but removes both extraneous whitespace **and non-word characters** from the beginning and end of a string.

**Params**

* `string` **{String}**: The string to chop.
* `returns` **{String}**

**Example**

```handlebars
{{chop "_ABC_"}}
<!-- results in:  'ABC' -->

{{chop "-ABC-"}}
<!-- results in:  'ABC' -->

{{chop " ABC "}}
<!-- results in:  'ABC' -->
```

## {{dashcase}}

dash-case the characters in `string`. Replaces non-word characters and periods with hyphens.

**Params**

* `string` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{dashcase "a-b-c d_e"}}
<!-- results in:  'a-b-c-d-e' -->
```

## {{dotcase}}

dot.case the characters in `string`.

**Params**

* `string` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{dotcase "a-b-c d_e"}}
<!-- results in:  'a.b.c.d.e' -->
```

## {{downcase}}

Lowercase all of the characters in the given string. Alias for [lowercase](#lowercase).

**Params**

* `string` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{downcase "aBcDeF"}}
<!-- results in:  'abcdef' -->
```

## {{ellipsis}}

Truncates a string to the specified `length`, and appends it with an elipsis, `…`.

**Params**

* `str` **{String}**
* `length` **{Number}**: The desired length of the returned string.
* `returns` **{String}**: The truncated string.

**Example**

```handlebars
{{ellipsis (sanitize "<span>foo bar baz</span>"), 7}}
<!-- results in:  'foo bar…' -->
{{ellipsis "foo bar baz", 7}}
<!-- results in:  'foo bar…' -->
```

## {{hyphenate}}

Replace spaces in a string with hyphens.

**Params**

* `str` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{hyphenate "foo bar baz qux"}}
<!-- results in:  "foo-bar-baz-qux" -->
```

## {{isString}}

Return true if `value` is a string.

**Params**

* `value` **{String}**
* `returns` **{Boolean}**

**Example**

```handlebars
{{isString "foo"}}
<!-- results in:  'true' -->
```

## {{lowercase}}

Lowercase all characters in the given string.

**Params**

* `str` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{lowercase "Foo BAR baZ"}}
<!-- results in:  'foo bar baz' -->
```

## {{occurrences}}

Return the number of occurrences of `substring` within the given `string`.

**Params**

* `str` **{String}**
* `substring` **{String}**
* `returns` **{Number}**: Number of occurrences

**Example**

```handlebars
{{occurrences "foo bar foo bar baz" "foo"}}
<!-- results in:  2 -->
```

## {{pascalcase}}

PascalCase the characters in `string`.

**Params**

* `string` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{pascalcase "foo bar baz"}}
<!-- results in:  'FooBarBaz' -->
```

## {{pathcase}}

path/case the characters in `string`.

**Params**

* `string` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{pathcase "a-b-c d_e"}}
<!-- results in:  'a/b/c/d/e' -->
```

## {{plusify}}

Replace spaces in the given string with pluses.

**Params**

* `str` **{String}**: The input string
* `returns` **{String}**: Input string with spaces replaced by plus signs

**Example**

```handlebars
{{plusify "foo bar baz"}}
<!-- results in:  'foo+bar+baz' -->
```

## {{prepend}}

Prepends the given `string` with the specified `prefix`.

**Params**

* `str` **{String}**
* `prefix` **{String}**
* `returns` **{String}**

**Example**

```handlebars
<!-- given that "val" is "bar" -->
{{prepend val "foo-"}}
<!-- results in:  'foo-bar' -->
```

## {{raw}}

Render a block without processing mustache templates inside the block.

**Params**

* `options` **{Object}**
* `returns` **{String}**

**Example**

```handlebars
{{{{#raw}}}}
{{foo}}
{{{{/raw}}}}
<!-- results in:  '{{foo}}' -->
```

## {{remove}}

Remove all occurrences of `substring` from the given `str`.

**Params**

* `str` **{String}**
* `substring` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{remove "a b a b a b" "a "}}
<!-- results in:  'b b b' -->
```

## {{removeFirst}}

Remove the first occurrence of `substring` from the given `str`.

**Params**

* `str` **{String}**
* `substring` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{remove "a b a b a b" "a"}}
<!-- results in:  ' b a b a b' -->
```

## {{replace}}

Replace all occurrences of substring `a` with substring `b`.

**Params**

* `str` **{String}**
* `a` **{String}**
* `b` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{replace "a b a b a b" "a" "z"}}
<!-- results in:  'z b z b z b' -->
```

## {{replaceFirst}}

Replace the first occurrence of substring `a` with substring `b`.

**Params**

* `str` **{String}**
* `a` **{String}**
* `b` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{replace "a b a b a b" "a" "z"}}
<!-- results in:  'z b a b a b' -->
```

## {{reverse}}

Reverse a string.

**Params**

* `str` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{reverse "abcde"}}
<!-- results in:  'edcba' -->
```

## {{sentence}}

Sentence case the given string

**Params**

* `str` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{sentence "hello world. goodbye world."}}
<!-- results in:  'Hello world. Goodbye world.' -->
```

## {{snakecase}}

snake_case the characters in the given `string`.

**Params**

* `string` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{snakecase "a-b-c d_e"}}
<!-- results in:  'a_b_c_d_e' -->
```

## {{split}}

Split `string` by the given `character`.

**Params**

* `string` **{String}**: The string to split.
* `returns` **{String}** `character`: Default is an empty string.

**Example**

```handlebars
{{split "a,b,c" ","}}
<!-- results in:  ['a', 'b', 'c'] -->
```

## {{startsWith}}

Tests whether a string begins with the given prefix.

**Params**

* `prefix` **{String}**
* `testString` **{String}**
* `options` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{#startsWith "Goodbye" "Hello, world!"}}
  Whoops
{{else}}
  Bro, do you even hello world?
{{/startsWith}}
```

## {{titleize}}

Title case the given string.

**Params**

* `str` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{titleize "this is title case"}}
<!-- results in:  'This Is Title Case' -->
```

## {{trim}}

Removes extraneous whitespace from the beginning and end of a string.

**Params**

* `string` **{String}**: The string to trim.
* `returns` **{String}**

**Example**

```handlebars
{{trim " ABC "}}
<!-- results in:  'ABC' -->
```

## {{trimLeft}}

Removes extraneous whitespace from the beginning of a string.

**Params**

* `string` **{String}**: The string to trim.
* `returns` **{String}**

**Example**

```handlebars
{{trim " ABC "}}
<!-- results in:  'ABC ' -->
```

## {{trimRight}}

Removes extraneous whitespace from the end of a string.

**Params**

* `string` **{String}**: The string to trim.
* `returns` **{String}**

**Example**

```handlebars
{{trimRight " ABC "}}
<!-- results in:  ' ABC' -->
```

## {{truncate}}

Truncate a string to the specified `length`. Also see [ellipsis](#ellipsis).

**Params**

* `str` **{String}**
* `limit` **{Number}**: The desired length of the returned string.
* `suffix` **{String}**: Optionally supply a string to use as a suffix to denote when the string has been truncated. Otherwise an ellipsis (`…`) will be used.
* `returns` **{String}**: The truncated string.

**Example**

```handlebars
truncate("foo bar baz", 7);
<!-- results in:  'foo bar' -->
truncate(sanitize("<span>foo bar baz</span>", 7));
<!-- results in:  'foo bar' -->
```

## {{truncateWords}}

Truncate a string to have the specified number of words. Also see [truncate](#truncate).

**Params**

* `str` **{String}**
* `limit` **{Number}**: The desired length of the returned string.
* `suffix` **{String}**: Optionally supply a string to use as a suffix to denote when the string has been truncated.
* `returns` **{String}**: The truncated string.

**Example**

```handlebars
truncateWords("foo bar baz", 1);
<!-- results in:  'foo…' -->
truncateWords("foo bar baz", 2);
<!-- results in:  'foo bar…' -->
truncateWords("foo bar baz", 3);
<!-- results in:  'foo bar baz' -->
```

## {{upcase}}

Uppercase all of the characters in the given string. Alias for [uppercase](#uppercase).

**Params**

* `string` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{upcase "aBcDeF"}}
<!-- results in:  'ABCDEF' -->
```

## {{uppercase}}

Uppercase all of the characters in the given string. If used as a block helper it will uppercase the entire block. This helper does not support inverse blocks.

**Params**

* `str` **{String}**: The string to uppercase
* `options` **{Object}**: Handlebars options object
* `returns` **{String}**

**Example**

```handlebars
{{uppercase "aBcDeF"}}
<!-- results in:  'ABCDEF' -->
```

---

## File: docs/en-US/api/handlebars-helpers/url.md

# URL

## {{encodeURI}}

Encodes a Uniform Resource Identifier (URI) component
by replacing each instance of certain characters by
one, two, three, or four escape sequences representing
the UTF-8 encoding of the character.

**Params**

* `str` **{String}**: The un-encoded string
* `returns` **{String}**: The endcoded string

## {{escape}}

Escape the given string by replacing characters with escape sequences.
Useful for allowing the string to be used in a URL, etc.

**Params**

* `str` **{String}**
* `returns` **{String}**: Escaped string.

## {{decodeURI}}

Decode a Uniform Resource Identifier (URI) component.

**Params**

* `str` **{String}**
* `returns` **{String}**

## {{url_encode}}

Alias for [encodeURI](#encodeuri).

## {{url_decode}}

Alias for [decodeURI](#decodeuri).

## {{urlResolve}}

Take a base URL, and a href URL, and resolve them as a
browser would for an anchor tag.

**Params**

* `base` **{String}**
* `href` **{String}**
* `returns` **{String}**

## {{urlParse}}

Parses a `url` string into an object.

**Params**

* `str` **{String}**: URL string
* `returns` **{String}**: Returns stringified JSON

## {{stripQuerystring}}

Strip the query string from the given `url`.

**Params**

* `url` **{String}**
* `returns` **{String}**: the url without the queryString

## {{stripProtocol}}

Strip protocol from a `url`. Useful for displaying media that may have an 'http' protocol on secure connections.

**Params**

* `str` **{String}**
* `returns` **{String}**: the url with http protocol stripped

**Example**

```handlebars
<!-- url = 'http://foo.bar' -->
{{stripProtocol url}}
<!-- results in: '//foo.bar' -->
```

---

## File: docs/en-US/api/http/index.md

# Overview

HTTP API of NocoBase is designed based on Resource & Action, a superset of REST API. The operation includes but not limited to create, read, update and delete. Resource Action can be extended arbitrarily in NocoBase.

## Resource

In NocoBase, resource has two expressions:

- `<collection>`
- `<collection>.<association>`

<Alert>

- Collection is the set of all abstract data
- Association is the associated data of collection
- Resource includes both collection and collection.association

</Alert>

### Example

- `posts` Post
- `posts.user` Post user
- `posts.tags` Post tags

## Action

Action on resource is expressed by `:<action>`

- `<collection>:<action>`
- `<collection>.<association>:<action>`

Built-in global actions for collection or association:

- `create`
- `get`
- `list`
- `update`
- `destroy`
- `move`

Built-in association actions for association only:

- `set`
- `add`
- `remove`
- `toggle`

### Example

- `posts:create` Create post
- `posts.user:get` Get post user
- `posts.tags:add` Add tags to post (associate existing tags with post)

## Request URL

```bash
<GET|POST>   /api/<collection>:<action>
<GET|POST>   /api/<collection>:<action>/<collectionIndex>
<GET|POST>   /api/<collection>/<collectionIndex>/<association>:<action>
<GET|POST>   /api/<collection>/<collectionIndex>/<association>:<action>/<associationIndex>
```

### Example

posts resource

```bash
POST  /api/posts:create
GET   /api/posts:list
GET   /api/posts:get/1
POST  /api/posts:update/1
POST  /api/posts:destroy/1
```

posts.comments resource

```bash
POST  /api/posts/1/comments:create
GET   /api/posts/1/comments:list
GET   /api/posts/1/comments:get/1
POST  /api/posts/1/comments:update/1
POST  /api/posts/1/comments:destroy/1
```

posts.tags resource

```bash
POST  /api/posts/1/tags:create
GET   /api/posts/1/tags:get
GET   /api/posts/1/tags:list
POST  /api/posts/1/tags:update
POST  /api/posts/1/tags:destroy
POST  /api/posts/1/tags:add
GET   /api/posts/1/tags:remove
```

## Locate Resource

- Collection resource locates the data to be processed by `collectionIndex`, `collectionIndex` must be unique.
- Association resource locates the data to be processed by `collectionIndex` and `associationIndex` jointly, `associationIndex` may not be unique, but the joint index of `collectionIndex` and `associationIndex` must be unique.

When viewing details of association resource, the requested URL needs to provide both `<collectionIndex>` and `<associationIndex>`, `<collectionIndex>` is necessary as `<associationIndex>` may not be unique.

For example, `tables.fields` represents the fields of a data table:

```bash
GET   /api/tables/table1/fields/title
GET   /api/tables/table2/fields/title
```

Both table1 and table2 have the title field, title is unique in one table, but other tables may also have fields of that name.

## Request Parameters

Request parameters can be placed in the headers, parameters (query string), and body (GET requests do not have a body) of the request.

Some special request parameters:

- `filter` Data filtering, used in actions related to query.
- `filterByTk` Filter by tk field, used in actions to specify details of data.
- `sort` Sorting, used in actions related to query.
- `fields` Date to output, used in actions related to query
- `appends` Fields of additional relationship, used in actions related to query.
- `except` Exclude some fields (not to output), used in actions related to query.
- `whitelist` Fields whitelist, used in actions related to data creation and update.
- `blacklist` Fields blacklist, used in actions related to data creation and update.

### filter

Data filtering.

```bash
# simple
GET /api/posts?filter[status]=publish
# json string format is recommended, which requires encodeURIComponent encoding
GET /api/posts?filter={"status":"published"}

# filter operators
GET /api/posts?filter[status.$eq]=publish
GET /api/posts?filter={"status.$eq":"published"}

# $and
GET /api/posts?filter={"$and": [{"status.$eq":"published"}, {"title.$includes":"a"}]}
# $or
GET /api/posts?filter={"$or": [{"status.$eq":"pending"}, {"status.$eq":"draft"}]}

# association field
GET /api/posts?filter[user.email.$includes]=gmail
GET /api/posts?filter={"user.email.$includes":"gmail"}
```

[Click here for more information about filter operators](http-api/filter-operators)

### filterByTk

Filter by tk field. In the default settings:

- collection resource: tk is the primary key of the data table.
- association resource: tk is the targetKey field of the association.

```bash
GET   /api/posts:get?filterByTk=1&fields=name,title&appends=tags
```

### sort

Sorting. To sort in the descending order, put `-` in front of the field.

```bash
# Sort createAt field in the ascending order
GET /api/posts:get?sort=createdAt
# Sort createAt field in the descending order
GET /api/posts:get?sort=-createdAt
# Sort multiple fields jointly, createAt field descending, title A-Z ascending
GET /api/posts:get?sort=-createdAt,title
```

### fields

Data to output.

```bash
GET   /api/posts:list?fields=name,title

Response 200 (application/json)
{
  "data": [
    {
      "name": "",
      "title": ""
    }
  ],
  "meta": {}
}
```

### appends

Fields of additional relationship.

### except

Exclude some fields (not to output), used in actions related to query.

### whitelist

Whitelist.

```bash
POST  /api/posts:create?whitelist=title

{
  "title": "My first post",
  "date": "2022-05-19"      # The date field will be filtered out and not be written to the database
}
```

### blacklist

Blacklist.

```bash
POST  /api/posts:create?blacklist=date

# The date field will be filtered out and not be written to the database
{
  "title": "My first post"
}
```

## Request Response

Format of the response:

```ts
type ResponseResult = {
  data?: any; // Main data
  meta?: any; // Additional Data
  errors?: ResponseError[]; // Errors
};

type ResponseError = {
  code?: string;
  message: string;
};
```

### Example

View list:

```bash
GET /api/posts:list

Response 200 (application/json)

{
  data: [
    {
      id: 1
    }
  ],
  meta: {
    count: 1
    page: 1,
    pageSize: 1,
    totalPage: 1
  },
}
```

View details:

```bash
GET /api/posts:get/1

Response 200 (application/json)

{
  data: {
    id: 1
  }
}
```

Error:

```bash
POST /api/posts:create

Response 400 (application/json)

{
  errors: [
    {
      message: 'name must be required',
    },
  ],
}
```

---

## File: docs/en-US/api/http/rest-api.md

# REST API

HTTP API of NocoBase is a superset of REST API, and the standard CRUD API also supports the RESTful style.

## Collection Resources

### Create Collection

HTTP API

```bash
POST  /api/<collection>:create

{} # JSON body
```

REST API

```bash
POST  /api/<collection>

{} # JSON body
```

### View Collection List

HTTP API

```bash
GET   /api/<collection>:list
```

REST API

```bash
GET   /api/<collection>
```

### View Collection Details

HTTP API

```bash
GET   /api/<collection>:get?filterByTk=<collectionIndex>
GET   /api/<collection>:get/<collectionIndex>
```

REST API

```bash
GET   /api/<collection>/<collectionIndex>
```

### Update Collection

HTTP API

```bash
POST   /api/<collection>:update?filterByTk=<collectionIndex>

{} # JSON body

# Or
POST   /api/<collection>:update/<collectionIndex>

{} # JSON body
```

REST API

```bash
PUT    /api/<collection>/<collectionIndex>

{} # JSON body
```

### Delete Collection

HTTP API

```bash
POST      /api/<collection>:destroy?filterByTk=<collectionIndex>
# Or
POST      /api/<collection>:destroy/<collectionIndex>
```

REST API

```bash
DELETE    /api/<collection>/<collectionIndex>
```

## Association Resources

### Create Association

HTTP API

```bash
POST    /api/<collection>/<collectionIndex>/<association>:create

{} # JSON body
```

REST API

```bash
POST    /api/<collection>/<collectionIndex>/<association>

{} # JSON body
```

### View Association List

HTTP API

```bash
GET   /api/<collection>/<collectionIndex>/<association>:list
```

REST API

```bash
GET   /api/<collection>/<collectionIndex>/<association>
```

### View Association Details

HTTP API

```bash
GET   /api/<collection>/<collectionIndex>/<association>:get?filterByTk=<associationIndex>
# Or
GET   /api/<collection>/<collectionIndex>/<association>:get/<associationIndex>
```

REST API

```bash
GET   /api/<collection>/<collectionIndex>/<association>:get/<associationIndex>
```

### Update Association

HTTP API

```bash
POST   /api/<collection>/<collectionIndex>/<association>:update?filterByTk=<associationIndex>

{} # JSON body

# Or
POST   /api/<collection>/<collectionIndex>/<association>:update/<associationIndex>

{} # JSON body
```

REST API

```bash
PUT    /api/<collection>/<collectionIndex>/<association>:update/<associationIndex>

{} # JSON
```

### Delete Association

HTTP API

```bash
POST    /api/<collection>/<collectionIndex>/<association>:destroy?filterByTk=<associationIndex>
# Or
POST    /api/<collection>/<collectionIndex>/<association>:destroy/<associationIndex>
```

REST API

```bash
DELETE  /api/<collection>/<collectionIndex>/<association>/<associationIndex>
```

---

## File: docs/en-US/api/resourcer/action.md

# ctx.action

## Overview

After the resource operation request is parsed by [`resourceManager.middleware()`](./resource-manager#middleware), some important request parameters are stored in `ctx.action` for use by subsequent middleware.

## API

### resourceName

`ctx.action.resourceName`

The name of the resource. It can take two forms:

- `a` - Operates on resource `a`.
- `a.b` - Operates on associated object `b` of resource `a`.

### actionName

`ctx.action.actionName`

The name of the action.

### sourceId

`ctx.action.sourceId`

When the operation object is an associated object of the resource, it represents the primary key value of the corresponding resource. For example: when `resourceName` is `a.b`, `sourceId` represents the primary key value of `a`.

### params

Request parameters.

- URL parameters can be directly obtained from `ctx.action.params`.

```ts
const { filterByTk } = ctx.action.params;
```

- Request body parameters can be obtained using `ctx.action.params.values`.

### mergeParams()

Combines parameter content with request parameters.

```ts
ctx.action.mergeParams(
  {
    filter: {
      name: 'foo',
    },
    fields: ['id', 'name'],
    except: ['name'],
    sort: ['id'],
    page: 1,
    pageSize: 10,
    values: {
      name: 'foo',
    },
  },
  {
    filter: 'and',
    fields: 'union',
    except: 'union',
    sort: 'overwrite',
    page: 'overwrite',
    pageSize: 'overwrite',
    values: 'deepMerge',
  },
);

ctx.action.mergeParams(
  {
    filter: {},
  },
  {
    filter: (x, y) => {
      // ...
    },
  },
);
```

#### Signature

- `mergeParams(params: ActionParams, strategies: MergeStrategies = {})`

#### Type

```ts
export interface ActionParams {
  filterByTk?: any;
  fields?: string[];
  appends?: string[];
  except?: string[];
  whitelist?: string[];
  blacklist?: string[];
  filter?: FilterOptions;
  sort?: string[];
  page?: number;
  pageSize?: number;
  values?: any;
  [key: string]: any;
}

type MergeStrategyType =
  | 'merge'
  | 'deepMerge'
  | 'overwrite'
  | 'andMerge'
  | 'orMerge'
  | 'intersect'
  | 'union';
type MergeStrategyFunc = (x: any, y: any) => any;
export type MergeStrategy = MergeStrategyType | MergeStrategyFunc;
export interface MergeStrategies {
  [key: string]: MergeStrategy;
}
```

#### Details

| Property     | Type                                                     | Description                                                   |
| ------------ | -------------------------------------------------------- | ------------------------------------------------------------- |
| `params`     | [`ActionParams`](#actionparams)                          | Request parameters                                            |
| `strategies` | [`{ [key: string]: MergeStrategies }`](#mergestrategies) | Merge strategies for various fields in the request parameters |

Default `strategies`:

```ts
{
  filter: 'andMerge',
  fields: 'intersect',
  appends: 'union',
  except: 'union',
  whitelist: 'intersect',
  blacklist: 'intersect',
  sort: 'overwrite',
};
```

##### ActionParams

| Property        | Type       | Description                                                             |
| --------------- | ---------- | ----------------------------------------------------------------------- |
| `filterByTk`    | `any`      | The primary key value of the operated resource                          |
| `filter`        | `Filter`   | Filtering parameters, refer to [Filter Operators](./database/operators) |
| `fields`        | `string[]` | Fields to retrieve                                                      |
| `except`        | `string[]` | Fields to exclude                                                       |
| `appends`       | `string[]` | Related fields to append                                                |
| `whitelist`     | `string[]` | Field whitelist                                                         |
| `blacklist`     | `string[]` | Field blacklist                                                         |
| `sort`          | `string[]` | Sorting parameters                                                      |
| `page`          | `number`   | Current page                                                            |
| `pageSize`      | `number`   | Number of data items per page                                           |
| `values`        | `any`      | Request body                                                            |
| `[key: string]` | `any`      | Other extended configurations                                           |

##### MergeStrategies

Predefined merge strategies or custom merge functions.

Predefined merge strategies:

| Strategy Name | Description                                       |
| ------------- | ------------------------------------------------- |
| `merge`       | `Object.assign`                                   |
| `deepMerge`   | Deep traversal merge                              |
| `overwrite`   | Overwrite                                         |
| `andMerge`    | Merge filter parameters using the `$and` operator |
| `orMerge`     | Merge filter parameters using the `$or` operator  |
| `intersect`   | Intersection                                      |
| `union`       | Union                                             |

---

## File: docs/en-US/api/resourcer/middleware.md

# Middleware

It is similar to the middleware of Koa, but with more enhanced features for easy extensions.

The defined middleware can be inserted for use in multiple places, such as the resourcer, and it is up to the developer for when to invoke it.

## Constructor

**Signature**

- `constructor(options: Function)`
- `constructor(options: MiddlewareOptions)`

**Parameter**

| Name              | Type                 | Default | Description                            |
| ----------------- | -------------------- | ------- | -------------------------------------- |
| `options`         | `Function`           | -       | Handler function of middlware          |
| `options`         | `MiddlewareOptions ` | -       | Configuration items of middlware       |
| `options.only`    | `string[]`           | -       | Only the specified actions are allowed |
| `options.except`  | `string[]`           | -       | The specified actions are excluded     |
| `options.handler` | `Function`           | -       | Handler function                       |

**Example**

Simple definition:

```ts
const middleware = new Middleware((ctx, next) => {
  await next();
});
```

Definition with relevant parameters:

```ts
const middleware = new Middleware({
  only: ['create', 'update'],
  async handler(ctx, next) {
    await next();
  },
});
```

## Instance Methods

### `getHandler()`

Get the orchestrated handler functions.

**Example**

The following middleware will output `1` and then `2` when requested.

```ts
const middleware = new Middleware((ctx, next) => {
  console.log(1);
  await next();
});

middleware.use(async (ctx, next) => {
  console.log(2);
  await next();
});

app.resourcer.use(middleware.getHandler());
```

### `use()`

Add a middleware function to the current middleware. Used to provide extension points for the middleware. See `getHandler()` for the examples.

**Signature**

- `use(middleware: Function)`

**Parameter**

| Name         | Type       | Default | Description                        |
| ------------ | ---------- | ------- | ---------------------------------- |
| `middleware` | `Function` | -       | Handler function of the middleware |

### `disuse()`

Remove the middleware functions that have been added to the current middleware.

**Signature**

- `disuse(middleware: Function)`

**Parameter**

| Name         | Type       | Default | Description                        |
| ------------ | ---------- | ------- | ---------------------------------- |
| `middleware` | `Function` | -       | Handler function of the middleware |

**Example**

The following example will only output `1` when requested, the output of `2` in fn1 will not be executed.

```ts
const middleware = new Middleware((ctx, next) => {
  console.log(1);
  await next();
});

async function fn1(ctx, next) {
  console.log(2);
  await next();
}

middleware.use(fn1);

app.resourcer.use(middleware.getHandler());

middleware.disuse(fn1);
```

### `canAccess()`

Check whether the current middleware is to be invoked for a specific action, it is usually handled by the resourcer internally.

**Signature**

- `canAccess(name: string): boolean`

**Parameter**

| Name   | Type     | Default | Description        |
| ------ | -------- | ------- | ------------------ |
| `name` | `string` | -       | Name of the action |

## Other Exports

### `branch()`

Create a branch middleware for branching in the middleware.

**Signature**

- `branch(map: { [key: string]: Function }, reducer: Function, options): Function`

**Parameter**

| Name                     | Type                          | Default          | Description                                                                                                       |
| ------------------------ | ----------------------------- | ---------------- | ----------------------------------------------------------------------------------------------------------------- |
| `map`                    | `{ [key: string]: Function }` | -                | Mapping table of the branch handler function, key names are given by subsequent calculation functions when called |
| `reducer`                | `(ctx) => string`             | -                | Calculation function, it is used to calculate the key name of the branch based on the context                     |
| `options?`               | `Object`                      | -                | Configuration items of the branch                                                                                 |
| `options.keyNotFound?`   | `Function`                    | `ctx.throw(404)` | Handler function when key name is not found                                                                       |
| `options.handlerNotSet?` | `Function`                    | `ctx.throw(404)` | The function when no handler function is defined                                                                  |

**Example**

When authenticating user, determine what to do next according to the value of the `authenticator` parameter in the query section of the request URL.

```ts
app.resourcer.use(
  branch(
    {
      password: async (ctx, next) => {
        // ...
      },
      sms: async (ctx, next) => {
        // ...
      },
    },
    (ctx) => {
      return ctx.action.params.authenticator ?? 'password';
    },
  ),
);
```

---

## File: docs/en-US/api/resourcer/resource-manager.md

# ResourceManager

## Overview

`ResourceManager` is the resource management module of NocoBase, used to define resources and register operation methods for resources.

## Class Methods

### `define()`

Defines a resource.

```ts
app.resourceManager.define({
  name: 'auth',
  actions: {
    check: async (ctx, next) => {
      // ...
      await next();
    },
  },
});
```

#### Signature

- `define(options: ResourceOptions): Resource`

#### Type

```ts
export interface ResourceOptions {
  name: string;
  type?: ResourceType;
  actions?: {
    [key: string]: ActionType;
  };
  only?: Array<ActionName>;
  except?: Array<ActionName>;
  middleware?: MiddlewareType;
  middlewares?: MiddlewareType;
}

export type ResourceType =
  | 'single'
  | 'hasOne'
  | 'hasMany'
  | 'belongsTo'
  | 'belongsToMany';

export type ActionType = HandlerType | ActionOptions;
export type HandlerType = (
  ctx: ResourcerContext,
  next: () => Promise<any>,
) => any;
export interface ActionOptions {
  values?: any;
  fields?: string[];
  appends?: string[];
  except?: string[];
  whitelist?: string[];
  blacklist?: string[];
  filter?: FilterOptions;
  sort?: string[];
  page?: number;
  pageSize?: number;
  maxPageSize?: number;
  middleware?: MiddlewareType;
  middlewares?: MiddlewareType;
  handler?: HandlerType;
  [key: string]: any;
}
```

#### Details

##### ResourceOptions

| Property      | Type                                           | Description            | Default  |
| ------------- | ---------------------------------------------- | ---------------------- | -------- |
| `name`        | `string`                                       | Resource name          | -        |
| `type`        | `ResourceType`                                 | Resource type          | `single` |
| `actions`     | [`{ [key: string]: ActionType }`](#actiontype) | Actions                | -        |
| `only`        | `ActionName[]`                                 | Whitelist of `actions` | -        |
| `except`      | `ActionName[]`                                 | Blacklist of `actions` | -        |
| `middleware`  | `MiddlewareType`                               | Middleware             | -        |
| `middlewares` | `MiddlewareType`                               | Middlewares            | -        |

##### ActionType

There are two types of action methods:

- `HandlerType`

This type directly defines the operation method through middleware. Example:

```ts
app.resourceManager.define({
  name: 'users',
  actions: {
    updateProfile: async (ctx, next) => {
      // ...
      await next();
    },
  },
});
```

- `ActionOptions`

This type is mainly used to override the request parameters of a certain existing operation. Example:

```ts
app.resourceManager.define({
  name: 'users',
  actions: {
    list: {
      fields: [],
      filter: {},
      // ...
    },
  },
});
```

| Property        | Type             | Description                                                                 |
| --------------- | ---------------- | --------------------------------------------------------------------------- |
| `values`        | `any`            | Default values for the action request                                       |
| `filter`        | `Filter`         | Filtering parameters, refer to [Filter Operators](../database/operators.md) |
| `fields`        | `string[]`       | Fields to retrieve                                                          |
| `except`        | `string[]`       | Fields to exclude                                                           |
| `appends`       | `string[]`       | Related fields to append                                                    |
| `whitelist`     | `string[]`       | Field whitelist                                                             |
| `blacklist`     | `string[]`       | Field blacklist                                                             |
| `sort`          | `string[]`       | Sorting parameters                                                          |
| `page`          | `number`         | Current page                                                                |
| `pageSize`      | `number`         | Number of data items per page                                               |
| `maxPageSize`   | `number`         | Maximum number of data items per page                                       |
| `middleware`    | `MiddlewareType` | Middleware                                                                  |
| `middlewares`   | `MiddlewareType` | Middlewares                                                                 |
| `handler`       | `HandlerType`    | Method executed for the action                                              |
| `[key: string]` | `any`            | Other extended configurations                                               |

### `registerActionHandlers()`

Registers action methods.

#### Signature

- `registerActionHandler(name: ActionName, handler: HandlerType)`

#### Type

```ts
export type DefaultActionType =
  | 'list'
  | 'create'
  | 'get'
  | 'update'
  | 'destroy'
  | 'set'
  | 'add'
  | 'remove';
export type ActionName = DefaultActionType | Omit<string, DefaultActionType>;

export type HandlerType = (
  ctx: ResourcerContext,
  next: () => Promise<any>,
) => any;
```

#### Details

| Property  | Type          | Description                                                                                                                                                        |
| --------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `name`    | `ActionName`  | Action name.1. As a regular string, registers actions for all resources.2. In the form `<resource>:<action>`, registers actions for specific resources |
| `handler` | `HandlerType` | Middleware for the action                                                                                                                                          |

### `isDefined()`

Checks if a resource is defined.

#### Signature

- `isDefined(name: string)`

#### Details

| Property | Type     | Description   |
| -------- | -------- | ------------- |
| `name`   | `string` | Resource name |

### `import()`

Loads resource configurations from a specified directory.

```ts
// ./resources/demo.ts
export default {
  name: 'demo',
  actions: {
    async list(ctx, next) {
      // ...
      await next();
    },
  },
};

const resourceManager = new ResourceManager();
await resourceManager.import({
  directory: path.resolve(__dirname, 'resources'),
});
```

#### Signature

- `import(options: ImportOptions): Promise<Map<string, Resource>>`

#### Type

```ts
export interface ImportOptions {
  directory: string;
  extensions?: string[];
}
```

#### Details

| Property     | Type       | Description               | Default Value          |
| ------------ | ---------- | ------------------------- | ---------------------- |
| `directory`  | `string`   | Directory path            | -                      |
| `extensions` | `string[]` | Optional, file extensions | `['js', 'ts', 'json']` |

### `use()`

Adds `ResourceManager` middleware.

```ts
resourceManager.use(async () => {
  return async function (ctx, next) {
    // ...
    await next();
  };
});
```

#### Signature

- `use(middlewares: HandlerType | HandlerType[], options: ToposortOptions = {})`

#### Details

Refer to [Middleware](../../development/server/middleware.md).

### `middleware()`

Middleware for `ResourceManager`, parses request parameters (refer to [ctx.action](./action.md)) and executes operation methods.

---

## File: docs/en-US/api/resourcer/resource.md

# Resource

Resource is used to define resource instance. Resource instances managed by resourcer can be accessed through HTTP requests.

## Constructor

To create resource instance. Normally it is not used directly, but replaced by the call of the `define()` interface of resourcer.

**Signature**

- `constructor(options: ResourceOptions, resourcer: Resourcer)`

**Parameter**

| Name                  | Type                                 | Default    | Description                                                                                                     |
| --------------------- | ------------------------------------ | ---------- | --------------------------------------------------------------------------------------------------------------- |
| `options.name`        | `string`                             | -          | Name of the resource, corresponding to the resource address in the route of the URL                             |
| `options.type`        | `string`                             | `'single'` | Type of the resource, options are `'single'`, `'hasOne'`, `'hasMany'`, `'belongsTo'`, `'belongsToMany'`         |
| `options.actions`     | `Object`                             | -          | List of actions that can be taken on the resource, see the example for details                                  |
| `options.middlewares` | `MiddlewareType \| MiddlewareType[]` | -          | List of middlewares for any operational access to the resource that is defining，see the example for details    |
| `options.only`        | `ActionName[]`                       | `[]`       | Whitelist for global actions, only actions contained in the array (if `length > 0`) can be accessed             |
| `options.except`      | `ActionName[]`                       | `[]`       | Blacklist for global actions, all actions except those contained in the array (if `length > 0`) can be accessed |
| `resourcer`           | `Resourcer`                          | -          | The resourcer instance                                                                                          |

**Example**

```ts
app.resourcer.define({
  name: 'books',
  actions: {
    // Extended action
    publish(ctx, next) {
      ctx.body = 'ok';
    },
  },
  middleware: [
    // Extended middleware
    async (ctx, next) => {
      await next();
    },
  ],
});
```

## Instance Members

### `options`

Configuration items for the current resource.

### `resourcer`

The resourcer instance to which the resource belongs.

### `middlewares`

The registered middlewares.

### `actions`

The registered mapping table of actions.

### `except`

Actions that are excluded.

## Instance Methods

### `getName()`

Get the name of the current resource.

**Signature**

- `getName(): string`

**Example**

```ts
const resource = app.resourcer.define({
  name: 'books',
});

resource.getName(); // 'books'
```

### `getAction()`

Get action with the corresponding name.

**Signature**

- `getAction(name: string): Action`

**Parameter**

| Name   | Type     | Default | Description        |
| ------ | -------- | ------- | ------------------ |
| `name` | `string` | -       | Name of the action |

**Example**

```ts
const resource = app.resourcer.define({
  name: 'books',
  actions: {
    publish(ctx, next) {
      ctx.body = 'ok';
    },
  },
});

resource.getAction('publish'); // [Function: publish]
```

---

## File: docs/en-US/api/sdk/auth.md

# Auth

## Overview

The `Auth` class is primarily used for accessing user information on the client-side, as well as requesting user authentication-related APIs.

## Instance Properties

### `locale`

The language used by the current user.

### `role`

The role used by the current user.

### `token`

The API interface token.

### `authenticator`

The authenticator used for current user authentication. Refer to [User Authentication](../../handbook/auth/user.md).

## Class Methods

### `signIn()`

User login.

#### Signature

- `async signIn(values: any, authenticator?: string): Promise<AxiosResponse<any>>`

#### Details

| Parameter       | Type     | Description                             |
| --------------- | -------- | --------------------------------------- |
| `values`        | `any`    | Login API request parameters            |
| `authenticator` | `string` | Authenticator identifier used for login |

### `signUp()`

User registration.

#### Signature

- `async signUp(values: any, authenticator?: string): Promise<AxiosResponse<any>>`

#### Details

| Parameter       | Type     | Description                                    |
| --------------- | -------- | ---------------------------------------------- |
| `values`        | `any`    | Registration API request parameters            |
| `authenticator` | `string` | Authenticator identifier used for registration |

### `signOut()`

Log out.

#### Signature

- `async signOut(values: any, authenticator?: string): Promise<AxiosResponse<any>>`

#### Details

| Parameter       | Type     | Description                              |
| --------------- | -------- | ---------------------------------------- |
| `values`        | `any`    | Logout API request parameters            |
| `authenticator` | `string` | Authenticator identifier used for logout |

## 2. Official Technical Reference & Guides (nocobase/docs)

## File: README.md

# NocoBase V1 Documentation (Archived)

> **This repository is archived and no longer maintained.** V2 documentation lives in the main repository: [nocobase/nocobase](https://github.com/nocobase/nocobase) (under the `docs/` directory). For the latest docs, visit [docs.nocobase.com](https://docs.nocobase.com).

If you need to access the V1 documentation, you can run it locally:

## Local Development

```bash
git clone https://github.com/nocobase/docs.git
cd docs
yarn install

# Run English docs
yarn dev:en

# Run Chinese docs
yarn dev

# Run French docs
yarn dev:fr

# Run Japanese docs
yarn dev:ja

# Run Russian docs
yarn dev:ru
```

## Build

```bash
yarn build
```

Note: `yarn dev` and `yarn dev:en` cannot be run at the same time.

---

## File: package.json

{
  "name": "nocobase-docs",
  "version": "0.0.1",
  "description": "A static site based on dumi",
  "scripts": {
    "start": "npm run dev",
    "dev": "dumi dev",
    "dev:en": "cross-env DOC_LANG=en-US dumi dev",
    "dev:fr": "cross-env DOC_LANG=fr-FR dumi dev",
    "dev:ja": "cross-env DOC_LANG=ja-JP dumi dev",
    "dev:ru": "cross-env DOC_LANG=ru-RU dumi dev",
    "build": "dumi build",
    "build:en": "cross-env DOC_LANG=en-US dumi build",
    "build:fr": "cross-env DOC_LANG=fr-FR dumi build",
    "build:ja": "cross-env DOC_LANG=ja-JP dumi build",
    "build:ru": "cross-env DOC_LANG=ru-RU dumi build",
    "prepare": "husky install && dumi setup"
  },
  "authors": [],
  "license": "MIT",
  "commitlint": {
    "extends": [
      "@commitlint/config-conventional"
    ]
  },
  "lint-staged": {
    "*.{md,json}": [
      "prettier --write --no-error-on-unmatched-pattern"
    ]
  },
  "devDependencies": {
    "@alicloud/cdn20180510": "^4.2.2",
    "@commitlint/cli": "^18.2.0",
    "@commitlint/config-conventional": "^18.1.0",
    "ali-oss": "^6.1.0",
    "cross-env": "^7.0.3",
    "dumi": "^2.2.14",
    "husky": "^8.0.3",
    "lint-staged": "^15.0.2",
    "prettier": "^3.0.3"
  },
  "dependencies": {
    "@formulajs/formulajs": "^4.4.9",
    "@nocobase/client": "^0.21.0-alpha.6",
    "axios-mock-adapter": "1.22.0",
    "cytoscape": "^3.23.0",
    "dumi-theme-nocobase": "^0.2.31",
    "moment": "^2.30.1",
    "sucrase": "^3.0.0",
    "vditor": "^3.10.8"
  },
  "volta": {
    "node": "20.14.0",
    "yarn": "1.22.19"
  },
  "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
}

---

## File: tsconfig.json

{
  "compilerOptions": {
    "jsx": "react",
    "strict": true,
    "skipLibCheck": true,
    "noImplicitAny": false,
    "esModuleInterop": true,
    "baseUrl": "./",
    "paths": {
      "@@/*": [".dumi/tmp/*"]
    }
  },
  "include": [".dumirc.ts"]
}

---

## File: docs/en-US/components.md

# Components

---

## File: docs/en-US/index.md

# Index

<Navigate replace to="/welcome/introduction"></Navigate>

---

## File: docs/en-US/_partials/commercial-installation.md

## Installation

This plugin is a commercial plugin, which needs to be uploaded and activated through the plugin manager：

---

## File: docs/en-US/api/actions.md

# @nocobase/actions

## Overview

The `@nocobase/actions` package encapsulates frequently used CRUD-related methods. By simply registering it with the [ResourceManager](./resourcer/resource-manager), CRUD operation interfaces can be globally added to system resources.

### Basic Usage

```typescript
import * as actions from `@nocobase/actions`;

const resourceManager = new ResourceManager({
  // ...options
});

resourceManager.registerActionHandlers(actions);
```

## Action Methods

### create

Creates a resource. `POST /api/<resource>:create`.

```shell
curl "http://localhost:13000/api/users:create" \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{"username": "admin"}'
```

#### Request Body

| Parameter Name  | Type  | Description                                     |
| --------------- | ----- | ----------------------------------------------- |
| `[key: string]` | `any` | Key-value pairs representing resource fields    |

### list

Retrieves a list of resources. `GET /api/<resource>:list`.

```shell
curl -X GET http://localhost:13000/api/users:list
```

#### Parameters

| Parameter  | Type       | Description                                                        | Default |
| ---------- | ---------- | ------------------------------------------------------------------ | ------- |
| `filter`   | `Filter`   | Filtering parameters, see [Filter Operators](./database/operators) | -       |
| `fields`   | `string[]` | Fields to retrieve                                                 | -       |
| `except`   | `string[]` | Fields to exclude                                                  | -       |
| `appends`  | `string[]` | Related fields to append                                           | -       |
| `sort`     | `string[]` | Sorting parameters                                                 | -       |
| `paginate` | `boolean`  | Whether to use pagination                                          | `true`  |
| `page`     | `number`   | Current page number                                                | `1`     |
| `pageSize` | `number`   | Number of items per page                                           | `20`    |

### get

Retrieves a specific resource. `GET /api/<resource>:get`.

```shell
curl -X GET http://localhost:13000/api/users:get?filterByTk=1
```

#### Parameters

| Parameter    | Type               | Description                                                        | Default |
| ------------ | ------------------ | ------------------------------------------------------------------ | ------- |
| `filterByTk` | `number \| string` | Filter by primary key value                                        | -       |
| `filter`     | `Filter`           | Filtering parameters, see [Filter Operators](./database/operators) | -       |
| `fields`     | `string[]`         | Fields to retrieve                                                 | -       |
| `except`     | `string[]`         | Fields to exclude                                                  | -       |
| `appends`    | `string[]`         | Related fields to append                                           | -       |

### update

Updates one or more resources. `PUT /api/<resource>:update`.

```shell
curl "http://localhost:13000/api/users:update?filterByTk=1" \
  -X PUT \
  -H "Content-Type: application/json" \
  -d '{"username": "admin"}'
```

#### Parameters

| Parameter    | Type               | Description                                                        |
| ------------ | ------------------ | ------------------------------------------------------------------ |
| `filter`     | `Filter`           | Filtering parameters, see [Filter Operators](./database/operators) |
| `filterByTk` | `number \| string` | Filter by primary key value                                        |

*Note: At least one of `filter` or `filterByTk` must be provided.*

#### Request Body

| Parameter Name  | Type  | Description                                     |
| --------------- | ----- | ----------------------------------------------- |
| `[key: string]` | `any` | Key-value pairs representing resource fields    |

### destroy

Deletes one or more resources. `DELETE /api/<resource>:destroy`.

```shell
curl -X DELETE http://localhost:13000/api/users:destroy?filterByTk=1
```

#### Parameters

| Parameter    | Type               | Description                                                        |
| ------------ | ------------------ | ------------------------------------------------------------------ |
| `filter`     | `Filter`           | Filtering parameters, see [Filter Operators](./database/operators) |
| `filterByTk` | `number \| string` | Filter by primary key value                                        |

*Note: At least one of `filter` or `filterByTk` must be provided.*

### firstOrCreate

Retrieves or creates a resource. `POST /api/<resource>:firstOrCreate`.

```shell
curl "http://localhost:13000/api/users:firstOrCreate?filterKeys[]=username" \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{"username": "admin", "nickname": "Admin"}'
```

#### Parameters

| Parameter    | Type       | Description                                                |
| ------------ | ---------- | ---------------------------------------------------------- |
| `filterKeys` | `string[]` | Fields in the request body used to find existing resources |

#### Request Body

| Parameter Name  | Type  | Description                                     |
| --------------- | ----- | ----------------------------------------------- |
| `[key: string]` | `any` | Key-value pairs representing resource fields    |

### updateOrCreate

Updates or creates a resource. `POST /api/<resource>:updateOrCreate`.

```shell
curl "http://localhost:13000/api/users:updateOrCreate?filterKeys[]=username" \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{"username": "admin", "nickname": "Admin"}'
```

#### Parameters

| Parameter    | Type       | Description                                                |
| ------------ | ---------- | ---------------------------------------------------------- |
| `filterKeys` | `string[]` | Fields in the request body used to find existing resources |

#### Request Body

| Parameter Name  | Type  | Description                                     |
| --------------- | ----- | ----------------------------------------------- |
| `[key: string]` | `any` | Key-value pairs representing resource fields    |

### move

Moves resources, adjusting the order. Typically used for drag-and-drop sorting in pages. `POST /api/<resource>:move`.

```shell
curl -X POST "http://localhost:13000/api/users:move?sourceId=1&targetId=2"
```

#### Parameters

| Parameter     | Type                       | Description                                                 | Default |
| ------------- | -------------------------- | ----------------------------------------------------------- | ------- |
| `sourceId`    | `targetKey`                | ID of the element to move                                   | -       |
| `targetId`    | `targetKey`                | ID of the element to swap positions with                    | -       |
| `sortField`   | `string`                   | Name of the field where sorting is stored                   | `sort`  |
| `targetScope` | `string`                   | Sorting scope, a resource can be sorted by different scopes | -       |
| `sticky`      | `boolean`                  | Whether to stick the moved element                          | -       |
| `method`      | `insertAfter` \| `prepend` | Insertion method: whether to insert before                  |

### set

Sets associated objects for a resource. `POST /api/<resource>/<resourceKey>/<association>:set`.

```shell
curl "http://localhost:13000/api/users/1/roles:set" \
  -X POST \
  -H "Content-Type: application/json" \
  -d '["admin", "member"]'
```

#### Request Body

- `TargetKey | TargetKey[]` - Array of primary key values for associated objects.

### add

Adds associated objects to a resource. `POST /api/<resource>/<resourceKey>/<association>:add`.

```shell
curl "http://localhost:13000/api/users/1/roles:add" \
  -X POST \
  -H "Content-Type: application/json" \
  -d '["admin"]'
```

#### Request Body

- `TargetKey | TargetKey[]` - Array of primary key values for associated objects.

### remove

Removes associated objects from a resource. `POST /api/<resource>/<resourceKey>/<association>:remove`.

```shell
curl "http://localhost:13000/api/users/1/roles:remove" \
  -X POST \
  -H "Content-Type: application/json" \
  -d '["admin"]'
```

#### Request Body

- `TargetKey | TargetKey[]` - Array of primary key values for associated objects.

### toggle

Toggles associated objects for a resource, adding them if they don't exist, or removing them if they do. `POST /api/<resource>/<resourceKey>/<association>:toggle`.

```shell
curl "http://localhost:13000/api/users/1/roles:toggle" \
  -X POST \
  -H "Content-Type: application/json" \
  -d '["admin", "member"]'
```

#### Request Body

- `TargetKey | TargetKey[]` - Array of primary key values for associated objects.

---

## File: docs/en-US/api/cli.md

# @nocobase/cli

The NocoBase CLI is designed to help you develop, build, and deploy NocoBase applications.

<Alert>

NocoBase CLI supports *ts-node* and *node* two operation modes.

- ts-node mode (Default): Used for development environment, support real-time compilation, with relatively slow response
- node mode：Used for production environment, with quick response, but you need to execute `yarn nocobase build` to compile the entire source code first

</Alert>

## Instructions For Use

```bash
$ yarn nocobase -h

Usage: nocobase [command] [options]

Options:
  -h, --help

Commands:
  console
  db:auth               Verify if the database is successfully connected
  db:sync               Generate relevant data tables and fields through the configuration of collections
  install               Install
  start                 Start application in production environment
  build                 Compile and package
  clean                 Delete the compiled files
  dev                   Start application for development environment with real-time compilation
  doc                   Documentation development
  test                  Testing
  umi
  upgrade               Upgrade
  migrator              Data migration
  pm                    Plugin manager
  help
```

## Application in Scaffolding

`scripts` in the application scaffolding `package.json` is as below:

```json
{
  "scripts": {
    "dev": "nocobase dev",
    "start": "nocobase start",
    "clean": "nocobase clean",
    "build": "nocobase build",
    "test": "nocobase test",
    "pm": "nocobase pm",
    "postinstall": "nocobase postinstall"
  }
}
```

## Command Line Extensions

NocoBase CLI is built based on [commander](https://github.com/tj/commander.js). You can write the extended commands freely in `app/server/index.ts`:

```ts
const app = new Application(config);

app.command('hello').action(() => {});
```

or in the plugin:

```ts
class MyPlugin extends Plugin {
  beforeLoad() {
    this.app.command('hello').action(() => {});
  }
}
```

Run in the terminal:

```bash
$ yarn nocobase hello
```

## Built-in Commands

Sorted by frequency of use.

### `dev`

Start application and compile code in real time in development environment.

<Alert>
NocoBase is installed automatically if it is not installed (Refer to the `install` command).
</Alert>

```bash
Usage: nocobase dev [options]

Options:
  -p, --port [port]
  --client
  --server
  -h, --help
```

Example:

```bash
# Launch application for development environment, with real-time compilation
yarn nocobase dev
# Start the server side only
yarn nocobase dev --server
# Start the client side only
yarn nocobase dev --client
```

### `start`

Start application in production environment, the code needs *yarn build*.

<Alert>

- NocoBase is installed automatically if it is not installed (Refer to the `install` command).
- The source code needs to be re-packaged if it has any modification (Refer to the `build` command).

</Alert>

```bash
$ yarn nocobase start -h

Usage: nocobase start [options]

Options:
  -p, --port
  -s, --silent
  -h, --help
```

Example:

```bash
# Launch application for production environment
yarn nocobase start
```

### `install`

Install.

```bash
$ yarn nocobase install -h

Usage: nocobase install [options]

Options:
  -f, --force
  -c, --clean
  -s, --silent
  -l, --lang [lang]
  -e, --root-email <rootEmail>
  -p, --root-password <rootPassword>
  -n, --root-nickname [rootNickname]
  -h, --help
```

Example:

```bash
# Initial installation
yarn nocobase install -l zh-CN -e admin@nocobase.com -p admin123
# Delete all data tables from NocoBase and reinstall
yarn nocobase install -f -l zh-CN -e admin@nocobase.com -p admin123
# Clear database and reinstall
yarn nocobase install -c -l zh-CN -e admin@nocobase.com -p admin123
```

<Alert>

Difference between `-f/--force` and `-c/--clean`:

- `-f/--force` Delete data tables of NocoBase
- `-c/--clean` Clear database, all data tables are deleted

</Alert>

### `upgrade`

Upgrade.

```bash
yarn nocobase upgrade
```

### `test`

*jest* test, which supports all [jest-cli](https://jestjs.io/docs/cli) options, also supports `-c, --db-clean`.

```bash
$ yarn nocobase test -h

Usage: nocobase test [options]

Options:
  -c, --db-clean        Clear database before running all tests
  -h, --help
```

Example:

```bash
# Run all test files
yarn nocobase test
# Run all test files in the specified folder
yarn nocobase test packages/core/server
# Run all tests in the specified file
yarn nocobase test packages/core/database/src/__tests__/database.test.ts

# Clear database before running all tests
yarn nocobase test -c
yarn nocobase test packages/core/server -c
```

### `build`

The source code needs to be compiled and packaged before the code is deployed to the production environment; and you need to re-build the code if it has any modification.

```bash
# All packages
yarn nocobase build
# Specified packages
yarn nocobase build app/server app/client
```

### `clean`

Delete the compiled files.

```bash
yarn clean
# Equivalent to
yarn rimraf -rf packages/*/*/{lib,esm,es,dist}
```

### `doc`

Documentation development.

```bash
# Start the documentation
yarn doc  --lang=zh-CN # Equivalent to yarn doc dev
# Build the documentation, and output it to . /docs/dist/ directory by default
yarn doc build
# View the final result of the output documentation of dist
yarn doc serve --lang=zh-CN
```

### `db:auth`

Verify if the database is successfully connected.

```bash
$ yarn nocobase db:auth -h

Usage: nocobase db:auth [options]

Options:
  -r, --retry [retry]   Number of retries
  -h, --help
```

### `db:sync`

Generate relevant data tables and fields through the configuration of collections.

```bash
$ yarn nocobase db:sync -h

Usage: nocobase db:sync [options]

Options:
  -f, --force
  -h, --help   display help for command
```

### `migrator`

Data migration.

```bash
$ yarn nocobase migrator

Positional arguments:
  <command>
    up        Applies pending migrations
    down      Revert migrations
    pending   Lists pending migrations
    executed  Lists executed migrations
    create    Create a migration file
```

### `pm`

Plugin manager.

```bash
# Create plugin
yarn pm create hello
# Register plugin
yarn pm add hello
# Enable plugin
yarn pm enable hello
# Disable plugin
yarn pm disable hello
# Remove plugin
yarn pm remove hello
```

Not achieved yet:

```bash
# Upgrade plugin
yarn pm upgrade hello
# Publish plugin
yarn pm publish hello
```

### `umi`

`app/client` is built based on [umi](https://umijs.org/), you can run other relevant commands through `nocobase umi`.

```bash
# Generate the .umi cache needed for the development environment
yarn nocobase umi generate tmp
```

### `help`

The help command, you can also use the option parameter, `-h` and `--help`.

```bash
# View all cli
yarn nocobase help
# Use -h instead
yarn nocobase -h
# Or --help
yarn nocobase --help
# View options of command db:sync
yarn nocobase db:sync -h
```

---

## File: docs/en-US/api/index.md

# Overview

| Module                                                                                                | Package               | Description                     |
| ----------------------------------------------------------------------------------------------------- | --------------------- | ------------------------------- |
| [Server](/api/server/application)                                                                     | `@nocobase/server`    | Server-side application         |
| [Database](/api/database)                                                                             | `@nocobase/database`  | Database access layer           |
| [Resourcer](/api/resourcer/resource-manager)                                                          | `@nocobase/resourcer` | Resource and route mapping      |
| [ACL](/api/acl/acl)                                                                                   | `@nocobase/acl`       | Access Control                  |
| [Auth](/api/auth/auth-manager)                                                                        | `@nocobase/auth`      | User Authentication             |
| [Client](https://client.docs-cn.nocobase.com/core/application/application) | `@nocobase/client`    | Client-side application         |
| [Cache](/api/cache/cache-manager)                                                                     | `@nocobase/cache`     | Server-side cache               |
| [Logger](/api/logger)                                                                                 | `@nocobase/logger`    | Server-side logging             |
| [Telemetry](/api/telemetry/telemetry)                                                                 | `@nocobase/telemetry` | Server-side telemetry           |
| [CLI](/api/cli)                                                                                       | `@nocobase/cli`       | NocoBase Command Line Interface |
| [SDK](/api/sdk)                                                                                       | `@nocobase/sdk`       | NocoBase SDK                    |
| [Actions](/api/actions)                                                                               | `@nocobase/actions`   | Built-in resource operations    |
| [Test](/api/test/server)                                                                              | `@nocobase/test`      | Automated testing               |

---

## File: docs/en-US/api/logger.md

# @nocobase/logger

## Create Logger

### createLogger()

Creates a custom logger.

#### Signature

- `createLogger(options: LoggerOptions)`

#### Type

```ts
interface LoggerOptions
  extends Omit<winston.LoggerOptions, 'transports' | 'format'> {
  dirname?: string;
  filename?: string;
  format?: 'logfmt' | 'json' | 'delimiter' | 'console' | winston.Logform.Format;
  transports?: ('console' | 'file' | 'dailyRotateFile' | winston.transport)[];
}
```

#### Details

- `dirname`: Log directory
- `filename`: Log file name
- `format`: Log format
- `transports`: Log transports

### createSystemLogger()

Creates system runtime logs printed in a specified method. Refer to [Logger plugin - System log](../plugins/logger/index.md#system-log).

#### Signature

- `createSystemLogger(options: SystemLoggerOptions)`

#### Type

```ts
export interface SystemLoggerOptions extends LoggerOptions {
  seperateError?: boolean; // print error seperately, default true
}
```

#### Details

- `seperateError`: Whether to print `error` level logs separately

### app.createLogger()

#### Definition

```ts
class Application {
  createLogger(options: LoggerOptions) {
    const { dirname } = options;
    return createLogger({
      ...options,
      dirname: getLoggerFilePath(this.name || 'main', dirname || ''),
    });
  }
}
```

When `dirname` is a relative path, the log files will be output to the directory named after the current application.

### plugin.createLogger()

Usage is the same as `app.createLogger()`.

#### Definition

```ts
class Plugin {
  createLogger(options: LoggerOptions) {
    return this.app.createLogger(options);
  }
}
```

## Configuration

### getLoggerLevel()

`getLoggerLevel(): 'debug' | 'info' | 'warn' | 'error'`

Gets the log level currently configured in the system.

### getLoggerFilePath()

`getLoggerFilePath(...paths: string[]): string`

Concatenates directory paths based on the log directory currently configured in the system.

### getLoggerTransports()

`getLoggerTransports(): ('console' | 'file' | 'dailyRotateFile')[]`

Gets the log output methods currently configured in the system.

### getLoggerFormat()

`getLoggerFormat(): 'logfmt' | 'json' | 'delimiter' | 'console'`

Gets the log format currently configured in the system.

## Logger Transports

### Transports

Predefined output methods.

- `Transports.console`
- `Transports.file`
- `Transports.dailyRotateFile`

```ts
import { Transports } from '@nocobase/logger';

const transport = Transports.console({
  //...
});
```

## References

- [Development - Logger](../handbook/logger/index.md)
- [Logger Plugin](../plugins/logger/index.md)

---

## File: docs/en-US/api/acl/acl.md

# ACL

## Overview

`ACL` is the permission management module used in NocoBase, responsible for user role management, permission registration and authorization, as well as permission policy evaluation and access control.

### Concepts

- **Resource**: Collections, or custom resources can be registered. Refer to [`@nocobase/resourcer`](../resourcer/resource-manager.md).
- **Action**: An operation interface for a resource, such as create, read, update, delete, or other custom actions. Refer to [`@nocobase/actions`](../actions).
- **Strategy**: Configures global permissions for roles, such as permissions for resource operations like create, read, update, delete, import, export, and system permissions like configuring the user interface.
- **Snippet**: Defines a collection of operations, enabling unified management of operation permissions. Snippet identifiers can be matched using the [minimatch](https://github.com/isaacs/minimatch) rules.

## Class Methods

### `define()`

Defines a role.

#### Signature

- `define(options: DefineOptions): ACLRole`

#### Type Definitions

```typescript
export interface DefineOptions {
  role: string;
  strategy?: string | AvailableStrategyOptions;
  actions?: ResourceActionsOptions;
  snippets?: string[];
}

export interface AvailableStrategyOptions {
  displayName?: string;
  actions?: false | string | string[];
  allowConfigure?: boolean;
  resource?: '*';
}

export interface ResourceActionsOptions {
  [actionName: string]: RoleActionParams;
}

export interface RoleActionParams {
  fields?: string[];
  filter?: any;
  own?: boolean;
  whitelist?: string[];
  blacklist?: string[];
}
```

#### Details

##### DefineOptions

| Property   | Type                                                                | Description                                                       |
| ---------- | ------------------------------------------------------------------- | ----------------------------------------------------------------- |
| `role`     | `string`                                                            | Unique identifier for the role                                    |
| `strategy` | `string` \| [`AvailableStrategyOptions`](#availablestrategyoptions) | Optional, global access strategy for the role                     |
| `actions`  | [`{ [actionName: string]: RoleActionParams; }`](#roleactionparams)  | Optional, permission configuration for actions                    |
| `snippets` | `string[]`                                                          | Optional, defines snippets that the role has permission to access |

##### AvailableStrategyOptions

| Property         | Type                              | Description                                               |
| ---------------- | --------------------------------- | --------------------------------------------------------- |
| `displayName`    | `string`                          | Optional, display name for the strategy                   |
| `action`         | `false` \| `string` \| `string[]` | Optional, operation interfaces                            |
| `allowConfigure` | `boolean`                         | Optional, whether to allow configuring the user interface |
| `resource`       | `*`                               | Applies to all resources                                  |

##### RoleActionParams

| Property    | Type       | Description                                                                                            |
| ----------- | ---------- | ------------------------------------------------------------------------------------------------------ |
| `fields`    | `string[]` | Optional, fields of the data table to operate on                                                       |
| `filter`    | `any`      | Optional, filter parameters that must be met, only records that meet the conditions can be operated on |
| `own`       | `boolean`  | Optional, whether to operate only on records created by oneself                                        |
| `whitelist` | `string[]` | Optional, whitelist of fields that can be accessed, only fields in the whitelist can be accessed       |
| `blacklist` | `string[]` | Optional, blacklist of fields that cannot be accessed, fields in the blacklist cannot be accessed      |

### `can()`

Determines the permission to execute an action and returns the final action parameters. Returns `null` if no permission.

#### Signature

- `can(options: CanArgs): CanResult | null`

#### Type Definitions

```typescript
interface CanArgs {
  role: string;
  resource: string;
  action: string;
  ctx?: any;
}

interface CanResult {
  role: string;
  resource: string;
  action: string;
  params?: any;
}
```

#### Details

##### CanArgs

| Property   | Type     | Description               |
| ---------- | -------- | ------------------------- |
| `role`     | `string` | Role identifier           |
| `resource` | `string` | Resource identifier       |
| `action`   | `string` | Action identifier         |
| `ctx`      | `any`    | Optional, request context |

##### CanResult

| Property   | Type     | Description                 |
| ---------- | -------- | --------------------------- |
| `role`     | `string` | Role identifier             |
| `resource` | `string` | Resource identifier         |
| `action`   | `string` | Action identifier           |
| `params`   | `any`    | Optional, action parameters |

### `registerSnippet()`

Registers a snippet.

#### Signature

- `registerSnippet(snippet: SnippetOptions)`

#### Type Definitions

```typescript
export type SnippetOptions = {
  name: string;
  actions: string[];
};
```

#### Details

| Property  | Type       | Description                                                                                                                              |
| --------- | ---------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `name`    | `string`   | Snippet identifier, can be matched using the [minimatch](https://github.com/isaacs/minimatch) rules. E.g., `auth.auth` matches `auth.*`. |
| `actions` | `string[]` | Resource operations included in the snippet, in the format `resource:action`. E.g., `users:list`.                                        |

### `setAvailableAction()`

Sets allowed actions.

#### Signature

- `setAvailableAction(name: string, options: AvailableActionOptions = {})`

```typescript
export interface AvailableActionOptions {
  displayName?: string;
  aliases?: string[] | string;
  resource?: string;
  // Perform operations on new data
  onNewRecord?: boolean;
  // Allow configuring fields
  allowConfigureFields?: boolean;
}
```

#### Details

| Property               | Type                   | Description                                                                           |
| ---------------------- | ---------------------- | ------------------------------------------------------------------------------------- |
| `displayName`          | `string`               | Optional, display name for the action                                                 |
| `aliases`              | `string` \| `string[]` | Optional, action aliases. E.g., aliases for `get`, `list` operations are both `view`. |
| `resource`             | `string`               | Optional, resource                                                                    |
| `onNewRecord`          | `boolean`              | Optional, whether the operation applies to new data, such as create operation         |
| `allowConfigureFields` | `boolean`              | Optional, whether to allow configuring fields                                         |

### `setAvailableStrategy()`

Sets allowed strategies for actions.

#### Signature

- `setAvailableStrategy(name: string, options: AvailableStrategyOptions)`

Refer to [AvailableStrategyOptions](#availablestrategyoptions).

### `allow()`

Defines the conditions under which operations are allowed.

```typescript
acl.allow('plugins', '*', 'public');
```

#### Signature

- `allow(resourceName: string, actionNames: string[] | string, condition?: string | ConditionFunc)`

#### Type

```typescript
export type ConditionFunc = (ctx: any) => Promise<boolean> | boolean;
```

#### Details

| Parameter      | Type                        | Description                                                                 | Default  |
| -------------- | --------------------------- | --------------------------------------------------------------------------- | -------- |
| `resourceName` | `string`                    | Resource                                                                    | -        |
| `actionNames`  | `string` \| `string[]`      | Action                                                                      | -        |
| `condition`    | `string` \| `ConditionFunc` | Optional, predefined condition identifier, or condition evaluation function | `public` |

Predefined condition identifiers:

- `public`: Public interface.
- `loggedIn`: Allowed when the user is logged in.
- `allowConfigure`: Allowed when the current user role has permission to configure the user interface.

### `addFixedParams()`

Adds fixed parameters to operations, merging them with current request parameters.

```typescript
acl.addFixedParams('users', 'list', () => {
  return {
    filter: {
      id: {
        $eq: 1,
      },
    },
  };
});
```

#### Signature

- `addFixedParams(resource: string, action: string, merger: Merger)`

#### Type Definitions

```typescript
export type Merger = () => object;
```

#### Details

| Parameter  | Type     | Description                                               |
| ---------- | -------- | --------------------------------------------------------- |
| `resource` | `string` | Resource                                                  |
| `action`   | `string` | Action                                                    |
| `merger`   | `Merger` | Function returning the fixed parameter object to be added |

### `use()`

Adds the `ACL` middleware.

```typescript
acl.use(async () => {
  return async function (ctx, next) {
    // ...
    await next();
  };
});
```

#### Signature

- `use(fn: any, options?: ToposortOptions)`

#### Details

Refer to [Middleware](../../development/server/middleware).

### `middleware()`

NocoBase access control middleware.

---

## File: docs/en-US/api/auth/auth-manager.md

# AuthManager

## Overview

`AuthManager` is the user authentication management module in NocoBase, used for registering different types of user authentication.

### Basic Usage

```ts
const authManager = new AuthManager({
  // Key to retrieve the current authenticator identifier from the request header
  authKey: 'X-Authenticator',
});

// Set methods for storing and retrieving authenticators in AuthManager
authManager.setStorer({
  get: async (name: string) => {
    return db.getRepository('authenticators').find({ filter: { name } });
  },
});

// Register an authentication type
authManager.registerTypes('basic', {
  auth: BasicAuth,
  title: 'Password',
});

// Use authentication middleware
app.resourceManager.use(authManager.middleware());
```

### Concepts

- **Authentication type (`AuthType`)**: Different types of authentication, such as Password, SMS, OIDC, SAML, etc.
- **Authenticator**: An authenticator is a database-stored entity linked to a configuration record for a specific authentication type (`AuthType`). Multiple authenticators can exist for one authentication type, each offering diffrent authentications.
- **Authenticator name**: Unique identifier for an authenticator, used to determine the current authentication employed by the current request.

## Class Methods

### `constructor()`

Constructor, creates an instance of `AuthManager`.

#### Signature

- `constructor(options: AuthManagerOptions)`

#### Types

```ts
export interface JwtOptions {
  secret: string;
  expiresIn?: string;
}

export type AuthManagerOptions = {
  authKey: string;
  default?: string;
  jwt?: JwtOptions;
};
```

#### Details

##### AuthManagerOptions

| Attribute | Type                        | Description                                                                     | Default           |
| --------- | --------------------------- | ------------------------------------------------------------------------------- | ----------------- |
| `authKey` | `string`                    | Optional key to save the current authenticator identifier in the request header | `X-Authenticator` |
| `default` | `string`                    | Optional, default authenticator identifier                                      | `basic`           |
| `jwt`     | [`JwtOptions`](#jwtoptions) | Optional, configure if using JWT for authentication                             | -                 |

##### JwtOptions

| Attribute   | Type     | Description                       | Default           |
| ----------- | -------- | --------------------------------- | ----------------- |
| `secret`    | `string` | Token secret key                  | `X-Authenticator` |
| `expiresIn` | `string` | Optional, token expiration period | `7d`              |

### `setStorer()`

Set methods for storing and retrieving authenticator data.

#### Signature

- `setStorer(storer: Storer)`

#### Types

```ts
export interface Authenticator = {
  authType: string;
  options: Record<string, any>;
  [key: string]: any;
};

export interface Storer {
  get: (name: string) => Promise<Authenticator>;
}
```

#### Details

##### Authenticator

| Attribute  | Type                  | Description                          |
| ---------- | --------------------- | ------------------------------------ |
| `authType` | `string`              | Authentication type                  |
| `options`  | `Record<string, any>` | Authenticator-related configurations |

##### Storer

`Storer` is the interface for authenticator storage, containing one method.

- `get(name: string): Promise<Authenticator>` - Get authenticator by identifier. In NocoBase, the actual returned type is [AuthModel](../../handbook/auth/dev/api#authmodel).

### `registerTypes()`

Register authentication types.

#### Signature

- `registerTypes(authType: string, authConfig: AuthConfig)`

#### Types

```ts
export type AuthExtend<T extends Auth> = new (config: Config) => T;

type AuthConfig = {
  auth: AuthExtend<Auth>; // The authentication class.
  title?: string; // The display name of the authentication type.
};
```

#### Details

| Attribute | Type               | Description                                                          |
| --------- | ------------------ | -------------------------------------------------------------------- |
| `auth`    | `AuthExtend<Auth>` | Authentication type implementation, refer to [Auth](./auth.md)       |
| `title`   | `string`           | Optional. Title of the authentication type displayed on the frontend |

### `listTypes()`

Get a list of registered authentication types.

#### Signature

- `listTypes(): { name: string; title: string }[]`

#### Details

| Attribute | Type     | Description                      |
| --------- | -------- | -------------------------------- |
| `name`    | `string` | Authentication type identifier   |
| `title`   | `string` | Title of the authentication type |

### `get()`

Get authenticator.

#### Signature

- `get(name: string, ctx: Context)`

#### Details

| Attribute | Type      | Description              |
| --------- | --------- | ------------------------ |
| `name`    | `string`  | Authenticator identifier |
| `ctx`     | `Context` | Request context          |

### `middleware()`

Authentication middleware. Get the current authenticator and perform user authentication.

---

## File: docs/en-US/api/auth/auth.md

# Auth

## Overview

`Auth` is an abstract class for user authentication types, defining the interfaces required to complete user authentication. To extend new user authentication types, you need to inherit from the `Auth` class and implement its methods. The basic implementation can be referred to as [BaseAuth](./base-auth.md).

```ts
interface IAuth {
  user: Model;
  // Check the authentication status and return the current user.
  check(): Promise<Model>;
  signIn(): Promise<any>;
  signUp(): Promise<any>;
  signOut(): Promise<any>;
}

export abstract class Auth implements IAuth {
  abstract user: Model;
  abstract check(): Promise<Model>;
  // ...
}

class CustomAuth extends Auth {
  // check: Authentication
  async check() {
    // ...
  }
}
```

## Instance Properties

### `user`

Information of the authenticated user.

#### Signature

- `abstract user: Model`

## Class Methods

### `constructor()`

Constructor, creates an instance of `Auth`.

#### Signature

- `constructor(config: AuthConfig)`

#### Types

```ts
export type AuthConfig = {
  authenticator: Authenticator;
  options: {
    [key: string]: any;
  };
  ctx: Context;
};
```

#### Details

##### AuthConfig

| Attribute       | Type                                            | Description                                                                                                                 |
| --------------- | ----------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
| `authenticator` | [`Authenticator`](./auth-manager#authenticator) | Authenticator data model, the actual type in NocoBase applications is [AuthModel](../../handbook/auth/dev/api.md#authmodel) |
| `options`       | `Record<string, any>`                           | Authenticator-related configurations                                                                                        |
| `ctx`           | `Context`                                       | Request context                                                                                                             |

### `check()`

User authentication, returns user information. This is an abstract method that all authentication types must implement.

#### Signature

- `abstract check(): Promise<Model>`

### `signIn()`

User login.

#### Signature

- `signIn(): Promise<any>`

### `signUp()`

User registration.

#### Signature

- `signUp(): Promise<any>`

### `signOut()`

User logout.

#### Signature

- `signOut(): Promise<any>`

---

## File: docs/en-US/api/auth/base-auth.md

# BaseAuth

## Overview

`BaseAuth` inherits from the abstract class [Auth](./auth.md) and serves as the basic implementation for user authentication types, using JWT as the authentication method. In most cases, extending user authentication types can be achieved by inheriting from `BaseAuth` instead of directly inheriting from the `Auth` abstract class.

```ts
class BasicAuth extends BaseAuth {
  constructor(config: AuthConfig) {
    // Set user collection
    const userCollection = config.ctx.db.getCollection('users');
    super({ ...config, userCollection });
  }

  // User authentication logic, called by `auth.signIn`
  // Returns user data
  async validate() {
    const ctx = this.ctx;
    const { values } = ctx.action.params;
    // ...
    return user;
  }
}
```

## Class Methods

### `constructor()`

Constructor, creates an instance of `BaseAuth`.

#### Signature

- `constructor(config: AuthConfig & { userCollection: Collection })`

#### Details

| Parameter        | Type         | Description                                                                                                  |
| ---------------- | ------------ | ------------------------------------------------------------------------------------------------------------ |
| `config`         | `AuthConfig` | Refer to [Auth - AuthConfig](./auth.md#authconfig)                                                           |
| `userCollection` | `Collection` | User collection, e.g., `db.getCollection('users')`, refer to [DataBase - Collection](../database/collection) |

### `user()`

Accessor for setting and getting user information, defaulting to using the `ctx.state.currentUser` object.

#### Signature

- `set user()`
- `get user()`

### `check()`

Authenticates through the request token and returns user information.

### `signIn()`

User login, generates a token.

### `signUp()`

User registration.

### `signOut()`

User logout, token expiration.

### `validate()` \*

Core authentication logic, called by the `signIn` interface, to determine whether the user can successfully log in.

---

## File: docs/en-US/api/cache/cache-manager.md

# CacheManager

## Overview

CacheManager is based on [node-cache-manager](https://github.com/node-cache-manager/node-cache-manager) and provides caching module management for NocoBase. The built-in cache types are:

- **memory**: Provided by the default lru-cache of node-cache-manager.
- **redis**: Supported by node-cache-manager-redis-yet for Redis caching.

More types can be extended and registered through the API.

### Concepts

- **Store**: Defines a caching method, including a factory method for creating caches and other related configurations. Each caching method has a unique identifier provided during registration. The two built-in caching methods correspond to the unique identifiers `memory` and `redis`.

- **Store Factory Method**: Provided by `node-cache-manager` and related extension packages, used to create caches. Examples include `memory` provided by `node-cache-manager` by default, and `redisStore` provided by `node-cache-manager-redis-yet`. In this context, the object to be provided corresponds to [`StoreOptions`](#storeoptions), which is the first parameter of the `caching` method in `node-cache-manager`.

- **Cache**: A class encapsulated by NocoBase, providing methods related to cache usage. When actually using caching, operations are performed on instances of `Cache`. Each `Cache` instance has a unique identifier, which serves as a namespace for distinguishing different modules.

## Class Methods

### `constructor()`

#### Signature

- `constructor(options?: CacheManagerOptions)`

#### Type

```ts
export type CacheManagerOptions = Partial<{
  defaultStore: string;
  stores: {
    [storeType: string]: StoreOptions;
  };
}>;

type StoreOptions = {
  store?: 'memory' | FactoryStore<Store, any>;
  close?: (store: Store) => Promise<void>;
  // global config
  [key: string]: any;
};
```

#### Details

##### CacheManagerOptions

| Property       | Type                           | Description                                                                                                                                                          |
| -------------- | ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `defaultStore` | `string`                       | Unique identifier for the default cache type.                                                                                                                        |
| `stores`       | `Record<string, StoreOptions>` | Registers cache types. The key is the unique identifier for the cache type, and the value is an object containing the registration method and global configurations. |

##### StoreOptions

| Property        | Type                                   | Description                                                                                                                                                                                              |
| --------------- | -------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `store`         | `memory` \| `FactoryStore<Store, any>` | The store factory method, corresponding to the first parameter of the `caching` method.                                                                                                                  |
| `close`         | `(store: Store) => Promise<void>`      | Optional. For middleware that requires establishing a connection, such as Redis, provide a callback method for closing the connection. The parameter is the object returned by the store factory method. |
| `[key: string]` | `any`                                  | Other global configurations for the store, corresponding to the second parameter of the `caching` method.                                                                                                |

#### Default `options`

```ts
import { redisStore, RedisStore } from 'cache-manager-redis-yet';

const defaultOptions: CacheManagerOptions = {
  defaultStore: 'memory',
  stores: {
    memory: {
      store: 'memory',
      // global config
      max: 2000,
    },
    redis: {
      store: redisStore,
      close: async (redis: RedisStore) => {
        await redis.client.quit();
      },
    },
  },
};
```

The `options` parameter will be merged with the default options. Existing default options can be omitted. For example:

```ts
const cacheManager = new CacheManager({
  stores: {
    defaultStore: 'redis',
    redis: {
      // redisStore is already provided in the default options, so only need to provide redisStore configuration.
      url: 'redis://localhost:6379',
    },
  },
});
```

### `registerStore()`

Register a new caching method. Example:

```ts
import { redisStore } from 'cache-manager-redis-yet';

cacheManager.registerStore({
  // Unique identifier for the store
  name: 'redis',
  // Factory method for creating the store
  store: redisStore,
  // Callback method for closing the store connection
  close: async (redis: RedisStore) => {
    await redis.client.quit();
  },
  // Global configurations
  url: 'xxx',
});
```

#### Signature

- `registerStore(options: { name: string } & StoreOptions)`

### `createCache()`

Create a cache. Example:

```ts
await cacheManager.createCache({
  name: 'default', // Unique identifier for the cache
  store: 'memory', // Unique identifier for the store
  prefix: 'mycache', // Automatically adds the 'mycache:' prefix to cache keys, optional
  // Other store configurations, custom configurations that will be merged with global store configurations
  max: 2000,
});
```

#### Signature

- `createCache(options: { name: string; prefix?: string; store?: string; [key: string]: any }): Promise<Cache>`

#### Details

##### options

| Property        | Type     | Description                                        |
| --------------- | -------- | -------------------------------------------------- |
| `name`          | `string` | Unique identifier for the cache                    |
| `store`         | `string` | Unique identifier for the store                    |
| `prefix`        | `string` | Optional. Prefix automatically added to cache keys |
| `[key: string]` | `any`    | Other custom store configurations                  |

When `store` is omitted, the `defaultStore` will be used. In this case, the caching

---

## File: docs/en-US/api/cache/cache.md

# Cache

## Basic Methods

You can refer to the documentation of [node-cache-manager](https://github.com/node-cache-manager/node-cache-manager).

- `get()`
- `set()`
- `del()`
- `reset()`
- `wrap()`
- `mset()`
- `mget()`
- `mdel()`
- `keys()`
- `ttl()`

## Other Methods

### `wrapWithCondition()`

Similar to `wrap()`, but can decide whether to use caching based on conditions.

```ts
async wrapWithCondition<T>(
  key: string,
  fn: () => T | Promise<T>,
  options?: {
    // External parameter to control whether to use cache results
    useCache?: boolean;
    // Determine whether to cache based on data results
    isCacheable?: (val: unknown) => boolean | Promise<boolean>;
    ttl?: Milliseconds;
  },
): Promise<T> {
```

### `setValueInObject()`

When the cached content is an object, changes the value of a specific key.

```ts
async setValueInObject(key: string, objectKey: string, value: unknown)
```

### `getValueInObject()`

When the cached content is an object, retrieves the value of a specific key.

```ts
async getValueInObject(key: string, objectKey: string)
```

### `delValueInObject()`

When the cached content is an object, deletes a specific key.

```ts
async delValueInObject(key: string, objectKey: string)
```

---

## File: docs/en-US/api/client/application.md

# Application

## Constructor

### `constructor()`

Create an application instance.

**Signature**

- `constructor(options: ApplicationOptions)`

**Example**

```ts
const app = new Application({
  apiClient: {
    baseURL: process.env.API_BASE_URL,
  },
  dynamicImport: (name: string) => {
    return import(`../plugins/${name}`);
  },
});
```

## Methods

### use()

Add Providers, build-in Providers are:

- APIClientProvider
- I18nextProvider
- AntdConfigProvider
- SystemSettingsProvider
- PluginManagerProvider
- SchemaComponentProvider
- SchemaInitializerProvider
- BlockSchemaComponentProvider
- AntdSchemaComponentProvider
- ACLProvider
- RemoteDocumentTitleProvider

### render()

Component to render the App.

```ts
import { Application } from '@nocobase/client';

export const app = new Application({
  apiClient: {
    baseURL: process.env.API_BASE_URL,
  },
  dynamicImport: (name: string) => {
    return import(`../plugins/${name}`);
  },
});

export default app.render();
```

---

## File: docs/en-US/api/client/index.md

# Overview

test

---

## File: docs/en-US/api/client/router.md

# Router

## API

### Initial

```tsx | pure
const app = new Application({
  router: {
    type: 'browser', // type default value is `browser`
  },
});

// or
const app = new Application({
  router: {
    type: 'memory',
    initialEntries: ['/'],
  },
});
```

### add Route

#### basic

```tsx | pure
import { RouteObject } from 'react-router-dom';
const app = new Application();

const Hello = () => {
  return <div>Hello</div>;
};

// first argument is `name` of route, second argument is `RouteObject`
app.router.add('root', {
  path: '/',
  element: <Hello />,
});

app.router.add('root', {
  path: '/',
  Component: Hello,
});
```

#### Component is String

```tsx | pure
app.addComponents({
  Hello,
});
app.router.add('root', {
  path: '/',
  Component: 'Hello',
});
```

#### nested

```tsx | pure
import { Outlet } from 'react-router-dom';

const Layout = () => {
  return (
    <div>
      <Link to="/home">Home</Link>
      <Link to="/about">about</Link>

      <Outlet />
    </div>
  );
};

const Home = () => {
  return <div>Home</div>;
};

const About = () => {
  return <div>About</div>;
};

app.router.add('root', {
  element: <Layout />,
});
app.router.add('root.home', {
  path: '/home',
  element: <Home />,
});
app.router.add('root.about', {
  path: '/about',
  element: <About />,
});
```

It will generate the following routes:

```tsx | pure
{
  element: <Layout />,
  children: [
    {
      path: '/home',
      element: <Home />
    },
    {
      path: '/about',
      element: <About />
    }
  ]
}
```

### remove Route

```tsx | pure
// remove route by name
app.router.remove('root.home');
app.router.remove('hello');
```

#### Router in plugin

```tsx | pure
class MyPlugin extends Plugin {
  async load() {
    // add route
    this.app.router.add('hello', {
      path: '/hello',
      element: <div>hello</div>,
    });

    // remove route
    this.app.router.remove('world');
  }
}
```

## Example

```tsx
/**
 * defaultShowCode: true
 */
import React from 'react';
import { Link, Outlet } from 'react-router-dom';
import { Application } from '@nocobase/client';

const Home = () => <h1>Home</h1>;
const About = () => <h1>About</h1>;

const Layout = () => {
  return (
    <div>
      <div>
        <Link to={'/'}>Home</Link>, <Link to={'/about'}>About</Link>
      </div>
      <Outlet />
    </div>
  );
};

const app = new Application({
  router: {
    type: 'memory',
    initialEntries: ['/'],
  },
});

app.router.add('root', {
  element: <Layout />,
});

app.router.add('root.home', {
  path: '/',
  element: <Home />,
});

app.router.add('root.about', {
  path: '/about',
  element: <About />,
});

export default app.getRootComponent();
```

---

## File: docs/en-US/api/client/extensions/acl.md

# ACL

## Components

### `<ACLProvider />`

### `<ACLRolesCheckProvider />`

### `<ACLCollectionProvider />`

### `<ACLActionProvider />`

### `<ACLCollectionFieldProvider />`

### `<ACLMenuItemProvider />`

## Hooks

### `useACLContext()`

### `useACLRoleContext()`

### `useRoleRecheck()`

---

## File: docs/en-US/api/client/extensions/block-provider.md

# BlockProvider

## Kernel Methods

### ``

### `useBlockRequestContext()`

## Build-in BlockProvider Components

### `<CalendarBlockProvider />`

### ``

### ``

### ``

### `<FormBlockProvider />`

### `<FormFieldProvider />`

### ``

### `<KanbanBlockProvider />`

---

## File: docs/en-US/api/client/extensions/collection-manager.md

# CollectionManager

## Components

### CollectionManagerProvider

```jsx | pure
<CollectionManagerProvider
  interfaces={{}}
  collections={[]}
></CollectionManagerProvider>
```

### CollectionProvider

```jsx | pure
const collection = {
  name: 'tests',
  fields: [
    {
      type: 'string',
      name: 'title',
      interface: 'input',
      uiSchema: {
        type: 'string',
        'x-component': 'Input',
      },
    },
  ],
};
<CollectionProvider collection={collection}></CollectionProvider>;
```

If there is no collection parameter passed in, get the collection from CollectionManagerProvider with the corresponding name.

```jsx | pure
const collections = [
  {
    name: 'tests',
    fields: [
      {
        type: 'string',
        name: 'title',
        interface: 'input',
        uiSchema: {
          type: 'string',
          'x-component': 'Input',
        },
      },
    ],
  },
];
<CollectionManagerProvider collections={collections}>
  <CollectionProvider name={'tests'}></CollectionProvider>
</CollectionManagerProvider>;
```

### CollectionFieldProvider

```jsx | pure
const field = {
  type: 'string',
  name: 'title',
  interface: 'input',
  uiSchema: {
    type: 'string',
    'x-component': 'Input',
  },
};
<CollectionFieldProvider field={field}></CollectionFieldProvider>;
```

If there is no field parameter passed in, get the field from CollectionProvider with the corresponding name.

```jsx | pure
const collection = {
  name: 'tests',
  fields: [
    {
      type: 'string',
      name: 'title',
      interface: 'input',
      uiSchema: {
        type: 'string',
        'x-component': 'Input',
      },
    },
  ],
};
<CollectionProvider collection={collection}>
  <CollectionFieldProvider name={'title'}></CollectionFieldProvider>
</CollectionProvider>;
```

### CollectionField

Universal field component that needs to be used with `<CollectionProvider/>`, but only in schema scenarios. Get the field schema from CollectionProvider with the corresponding name. Extend the configuration via the schema where the CollectionField is located.

```ts
{
  name: 'title',
  'x-decorator': 'FormItem',
  'x-decorator-props': {},
  'x-component': 'CollectionField',
  'x-component-props': {},
  properties: {},
}
```

## Hooks

### useCollectionManager()

Use with `<CollectionManagerProvider/>`.

```jsx | pure
const { collections, get } = useCollectionManager();
```

### useCollection()

Use with `<CollectionProvider/>`.

```jsx | pure
const { name, fields, getField, findField, resource } = useCollection();
```

### useCollectionField()

Use with `<CollectionFieldProvider/>`.

```jsx | pure
const { name, uiSchema, resource } = useCollectionField();
```

The resource needs to be used with `<RecordProvider/>` to provide context of the record of the current data table row.

# CollectionManager

## Components

### CollectionManagerProvider

```jsx | pure
<CollectionManagerProvider
  interfaces={{}}
  collections={[]}
></CollectionManagerProvider>
```

### CollectionProvider

```jsx | pure
const collection = {
  name: 'tests',
  fields: [
    {
      type: 'string',
      name: 'title',
      interface: 'input',
      uiSchema: {
        type: 'string',
        'x-component': 'Input',
      },
    },
  ],
};
<CollectionProvider collection={collection}></CollectionProvider>;
```

If there is no collection parameter passed in, get the collection from CollectionManagerProvider with the corresponding name.

```jsx | pure
const collections = [
  {
    name: 'tests',
    fields: [
      {
        type: 'string',
        name: 'title',
        interface: 'input',
        uiSchema: {
          type: 'string',
          'x-component': 'Input',
        },
      },
    ],
  },
];
<CollectionManagerProvider collections={collections}>
  <CollectionProvider name={'tests'}></CollectionProvider>
</CollectionManagerProvider>;
```

### CollectionFieldProvider

```jsx | pure
const field = {
  type: 'string',
  name: 'title',
  interface: 'input',
  uiSchema: {
    type: 'string',
    'x-component': 'Input',
  },
};
<CollectionFieldProvider field={field}></CollectionFieldProvider>;
```

If there is no field parameter passed in, get the field from CollectionProvider with the corresponding name.

```jsx | pure
const collection = {
  name: 'tests',
  fields: [
    {
      type: 'string',
      name: 'title',
      interface: 'input',
      uiSchema: {
        type: 'string',
        'x-component': 'Input',
      },
    },
  ],
};
<CollectionProvider collection={collection}>
  <CollectionFieldProvider name={'title'}></CollectionFieldProvider>
</CollectionProvider>;
```

### CollectionField

Universal field component that needs to be used with `<CollectionProvider/>`, but only in schema scenarios. Get the field schema from CollectionProvider with the corresponding name. Extend the configuration via the schema where the CollectionField is located.

```ts
{
  name: 'title',
  'x-decorator': 'FormItem',
  'x-decorator-props': {},
  'x-component': 'CollectionField',
  'x-component-props': {},
  properties: {},
}
```

## Hooks

### useCollectionManager()

Use with `<CollectionManagerProvider/>`.

```jsx | pure
const { collections, get } = useCollectionManager();
```

### useCollection()

Use with `<CollectionProvider/>`.

```jsx | pure
const { name, fields, getField, findField, resource } = useCollection();
```

### useCollectionField()

Use with `<CollectionFieldProvider/>`.

```jsx | pure
const { name, uiSchema, resource } = useCollectionField();
```

The resource needs to be used with `<RecordProvider/>` to provide context of the record of the current data table row.

---

## File: docs/en-US/api/client/extensions/schema-component.md

# 适配的 Schema 组件

## Common

- DndContext
- SortableItem

## And Design

- Action
- BlockItem
- Calendar
- CardItem
- Cascader

---

## File: docs/en-US/api/client/schema-designer/schema-component.md

# SchemaComponent

## Core Components

### `<SchemaComponentProvider />`

### `<SchemaComponentOptions>`

### `<SchemaComponent>`

## Core Methods

### `createDesignable()`

### `useDesignable()`

### `useCompile()`

---

## File: docs/en-US/api/client/schema-designer/schema-initializer.md

# SchemaInitializer

Used for the initialization of various schemas. Newly added schema can be inserted anywhere in an existing schema node, including:

```ts
{
  properties: {
    // beforeBegin - Insert in front of the current node
    node1: {
      properties: {
        // afterBegin - Insert in front of the first child node of the current node
        // ...
        // beforeEnd - After the last child node of the current node
      },
    },
    // afterEnd - After the current node
  },
}
```

The core of SchemaInitializer includes `<SchemaInitializer.Button />` and `<SchemaInitializer.Item />` the two components. `<SchemaInitializer.Button />` is used to create the dropdown menu button of schema, and the options of the dropdown menu is `<SchemaInitializer.Item/>`.

### `<SchemaInitializerProvider />`

### `<SchemaInitializer.Button />`

### `<SchemaInitializer.Item/>`

---

## File: docs/en-US/api/client/schema-designer/schema-settings.md

# SchemaSettings

### `<SchemaSettings />`

### `<SchemaSettings.Item />`

### `<SchemaSettings.ItemGroup />`

### `<SchemaSettings.SubMenu />`

### `<SchemaSettings.Divider />`

### `<SchemaSettings.Remove />`

### `<SchemaSettings.SelectItem />`

### `<SchemaSettings.SwitchItem />`

### `<SchemaSettings.ModalItem />`

### `<SchemaSettings.ActionModalItem />`

### `<SchemaSettings.Template />`

### `<SchemaSettings.BlockTitleItem />`

---

## File: docs/en-US/api/data-source-manager/data-source.md

# DataSource (abstract)

The `DataSource` abstract class is used to represent a type of data source, which can be a database, API, etc.

## Members

### collectionManager

The CollectionManager instance of the data source, which needs to implement the [`ICollectionManager`](/api/data-source-manager/i-collection-manager) interface.

### resourceManager

The resourceManager instance of the data source, see: [`resourceManager`](/api/resourcer/resource-manager)

### acl

The ACL instance of the data source, see: [`ACL`](/api/acl/acl)

## API

### constructor()

Constructor, creates a `DataSource` instance.

#### Signature

- `constructor(options: DataSourceOptions)`

### init()

Initialization function, called immediately after `constructor`.

#### Signature

- `init(options: DataSourceOptions)`

### name

#### Signature

- `get name()`

Returns the instance name of the data source.

### middleware()

Gets the middleware of the DataSource, used to mount to the Server to receive requests.

### testConnection()

Static method, called during the test connection operation, can be used for parameter validation, specific logic is implemented by subclasses.

#### Signature

- `static testConnection(options?: any): Promise`

### load()

#### Signature

- `async load(options: any = {})`

The loading operation of the data source, logic is implemented by subclasses.

### createCollectionManager()

#### Signature
- `abstract createCollectionManager(options?: any): ICollectionManager`

Creates a CollectionManager instance for the data source, logic is implemented by subclasses.

### createResourceManager()

Creates a ResourceManager instance for the data source, subclasses can override the implementation, by default creates `ResourceManager` from `@nocobase/resourcer`.

### createACL()

- Creates an ACL instance for the DataSource, subclasses can override the implementation, by default creates `ACL` from `@nocobase/acl`.

---

## File: docs/en-US/api/data-source-manager/i-collection-manager.md

# ICollectionManager

The `ICollectionManager` interface is used to manage `Collection` instances of data sources.

## API

### registerFieldTypes()

Registers the field types in a `Collection`.

#### Signature

- `registerFieldTypes(types: Record<string, any>): void`

### registerFieldInterfaces()

Registers the `Interface` for a `Collection`.

#### Signature

- `registerFieldInterfaces(interfaces: Record<string, any>): void`

### registerCollectionTemplates()

Registers `Collection Templates`.

#### Signature

- `registerCollectionTemplates(templates: Record<string, any>): void`

### registerModels()

Registers `Models`.

#### Signature

- `registerModels(models: Record<string, any>): void`

### registerRepositories()

Registers `Repositories`.

#### Signature

- `registerRepositories(repositories: Record<string, any>): void`

### getRegisteredRepository()

Retrieves an instance of a registered repository.

#### Signature

- `getRegisteredRepository(key: string): IRepository`

### defineCollection()

Defines a `Collection`.

#### Signature

- `defineCollection(options: CollectionOptions): ICollection`

### extendCollection()

Modifies an existing `Collection` property.

#### Signature

- `extendCollection(collectionOptions: CollectionOptions, mergeOptions?: MergeOptions): ICollection`

### hasCollection()

Determines if a `Collection` exists.

#### Signature

- `hasCollection(name: string): boolean`

### getCollection()

Retrieves an instance of a `Collection`.

#### Signature

- `getCollection(name: string): ICollection`

### getCollections()

Retrieves all instances of `Collection`.

#### Signature

- `getCollections(): Array`

### getRepository()

Retrieves an instance of a `Repository`.

#### Signature

- `getRepository(name: string, sourceId?: string | number): IRepository`

### sync()

Synchronizes the data source, with the logic implemented by subclasses.

#### Signature

- `sync(): Promise<void>`

---

## File: docs/en-US/api/data-source-manager/i-collection.md

# ICollection

`ICollection` is an interface for data models, which includes information such as the model's name, fields, associations, etc.

```typescript
export interface ICollection {
  repository: IRepository;

  updateOptions(options: any): void;

  setField(name: string, options: any): IField;

  removeField(name: string): void;

  getFields(): Array<IField>;

  getField(name: string): IField;

  [key: string]: any;
}
```

## Members

### repository

The `Repository` instance to which `ICollection` belongs.

## API

### updateOptions()

Updates the properties of the `Collection`.

#### Signature

- `updateOptions(options: any): void`

### setField()

Sets a field of the `Collection`.

#### Signature

- `setField(name: string, options: any): IField`

### removeField()

Removes a field from the `Collection`.

#### Signature

- `removeField(name: string): void`

### getFields()

Retrieves all fields of the `Collection`.

#### Signature

- `getFields(): Array`

### getField()

Retrieves a field of the `Collection` by name.

#### Signature

- `getField(name: string): IField`

---

## File: docs/en-US/api/data-source-manager/i-field.md

# IField

`IField` defines the interface that fields need to implement.

```typescript
export type FieldOptions = {
  name: string;
  field: string;
  rawType: string;
  type: string;
  description?: string;
  interface?: string;
  uiSchema?: any;
  possibleTypes?: string[];
  defaultValue?: any;
  primaryKey: boolean;
  unique: boolean;
  allowNull?: boolean;
  autoIncrement?: boolean;
  [key: string]: any;
};

export interface IField {
  options: FieldOptions;
}
```


## Properties

### options

- **Type**: `FieldOptions`

---

## File: docs/en-US/api/data-source-manager/i-model.md

# IModel

The `IModel` interface defines the basic properties and methods of a model object.

```typescript
export interface IModel {
  toJSON: () => any;
}
```

## API

### toJSON()

Converts the model object to JSON format.

---

## File: docs/en-US/api/data-source-manager/i-repository.md

# IRepository

The `Repository` interface defines a series of model operation methods for adapting CRUD (Create, Read, Update, Delete) operations on data sources.

## API

### find()

Returns a list of models that match the query parameters.

#### Signature

- `find(options?: any): Promise`

### findOne()

Returns the first model that matches the query parameters. If multiple models match, only the first one is returned.

#### Signature

- `findOne(options?: any): Promise`

### count()

Returns the number of models that match the query parameters.

#### Signature

- `count(options?: any): Promise<Number>`

### findAndCount()

Returns both the list of models and the count of models that match the query parameters.

#### Signature

- `findAndCount(options?: any): Promise<[IModel[], Number]>`

### create()

Creates a model data object.

#### Signature

- `create(options: any): void`

### update()

Updates the model data object based on the query conditions.

#### Signature

- `update(options: any): void`

### destroy()

Deletes the model data object based on the query conditions.

#### Signature

- `destroy(options: any): void`

---

## File: docs/en-US/api/data-source-manager/index.md

# DataSourceManager

`DataSourceManager` is a management class for multiple `dataSource` instances.

## API

### add()
Adds a `dataSource` instance.

#### Signature

- `add(dataSource: DataSource, options: any = {}): Promise<void>`

### use()

Adds a global middleware to the `dataSource` instance.

### middleware()

Retrieves the middleware of the current `dataSourceManager` instance, which can be used to respond to HTTP requests.

### afterAddDataSource()

A hook function that is triggered after a new `dataSource` is added.

#### Signature

- `afterAddDataSource(hook: DataSourceHook)`

```typescript
type DataSourceHook = (dataSource: DataSource) => void;
```

### registerDataSourceType()

Registers the data source type and its class.

#### Signature

- `registerDataSourceType(type: string, dataSourceClass: typeof DataSource)`

### getDataSourceType()

Retrieves the data source class.

#### Signature

- `getDataSourceType(type: string): typeof DataSource`

### buildDataSourceByType()

Creates a data source instance based on the registered data source type and instance parameters.

#### Signature

- `buildDataSourceByType(type: string, options: any): DataSource`

---

## File: docs/en-US/api/database/collection.md

# Collection

## Overview

`Collection` is used to define the data model in the system, such as model name, fields, indexes, associations, and other information. It is usually called through the `collection` method of the `Database` instance as a proxy entry.

```javascript
const { Database } = require('@nocobase/database')

// Create database instance
const db = new Database({...});

// Define data model
db.collection({
  name: 'users',
  // Define model fields
  fields: [
    // Scalar field
    {
      name: 'name',
      type: 'string',
    },

    // Association field
    {
      name: 'profile',
      type: 'hasOne' // 'hasMany', 'belongsTo', 'belongsToMany'
    }
  ],
});
```

Refer to [Fields](/api/database/field) for more field types.

## Constructor

**Signature**

- `constructor(options: CollectionOptions, context: CollectionContext)`

**Parameter**

| Name                  | Type                                                        | Default | Description                                                                                                               |
| --------------------- | ----------------------------------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------- |
| `options.name`        | `string`                                                    | -       | Identifier of the collection                                                                                              |
| `options.tableName?`  | `string`                                                    | -       | Database table name, the value of `options.name` is used if not set                                                       |
| `options.fields?`     | `FieldOptions[]`                                            | -       | Definition of fields, refer to [Field](./field) for details                                                               |
| `options.model?`      | `string \| ModelStatic<Model>`                              | -       | Model type of Sequelize; in case `string` is used, this model name needs to be registered in the db before being called   |
| `options.repository?` | `string \| RepositoryType`                                  | -       | Data repository type; in case `string` is used, this repository type needs to be registered in the db before being called |
| `options.sortable?`   | `string \| boolean \| { name?: string; scopeKey?: string }` | -       | Configure which fields are sortable; not sortable by default                                                              |
| `options.autoGenId?`  | `boolean`                                                   | `true`  | Whether to automatically generate unique primary key; `true` by default                                                   |
| `context.database`    | `Database`                                                  | -       | The context database in which it resides                                                                                  |

**Example**

Create a table *posts*:

```ts
const posts = new Collection(
  {
    name: 'posts',
    fields: [
      {
        type: 'string',
        name: 'title',
      },
      {
        type: 'double',
        name: 'price',
      },
    ],
  },
  {
    // An existing database instance
    database: db,
  },
);
```

## Instance Members

### `options`

Initial parameters for data table configuration, which are consistent with the `options` parameter of the constructor.

### `context`

The contextual environment to which the current data table belongs, currently mainly the database instance.

### `name`

Name of the data table.

### `db`

The database instance to which it belongs.

### `filterTargetKey`

Name of the field that is used as the primary key.

### `isThrough`

Whether it is an intermediate table.

### `model`

Match the Model type of Sequelize.

### `repository`

Data repository instance.

## Field Configuration Methods

### `getField()`

Get a field object whose corresponding name has been defined in the data table.

**Signature**

- `getField(name: string): Field`

**Parameter**

| Name   | Type     | Default | Description       |
| ------ | -------- | ------- | ----------------- |
| `name` | `string` | -       | Name of the field |

**Example**

```ts
const posts = db.collection({
  name: 'posts',
  fields: [
    {
      type: 'string',
      name: 'title',
    },
  ],
});

const field = posts.getField('title');
```

### `setField()`

Set a field to the data table.

**Signature**

- `setField(name: string, options: FieldOptions): Field`

**Parameter**

| Name      | Type           | Default | Description                                                       |
| --------- | -------------- | ------- | ----------------------------------------------------------------- |
| `name`    | `string`       | -       | Name of the field                                                 |
| `options` | `FieldOptions` | -       | Configuration of the field, refer to [Field](./field) for details |

**Example**

```ts
const posts = db.collection({ name: 'posts' });

posts.setField('title', { type: 'string' });
```

### `setFields()`

Set multiple fields to the data table.

**Signature**

- `setFields(fields: FieldOptions[], resetFields = true): Field[]`

**Parameter**

| Name          | Type             | Default | Description                                                        |
| ------------- | ---------------- | ------- | ------------------------------------------------------------------ |
| `fields`      | `FieldOptions[]` | -       | Configuration of the fields, refer to [Field](./field) for details |
| `resetFields` | `boolean`        | `true`  | Whether to reset existing fields                                   |

**Example**

```ts
const posts = db.collection({ name: 'posts' });

posts.setFields([
  { type: 'string', name: 'title' },
  { type: 'double', name: 'price' },
]);
```

### `removeField()`

Remove a field object whose corresponding name has been defined in the data table.

**Signature**

- `removeField(name: string): void | Field`

**Parameter**

| Name   | Type     | Default | Description       |
| ------ | -------- | ------- | ----------------- |
| `name` | `string` | -       | Name of the field |

**Example**

```ts
const posts = db.collection({
  name: 'posts',
  fields: [
    {
      type: 'string',
      name: 'title',
    },
  ],
});

posts.removeField('title');
```

### `resetFields()`

Reset (Empty) fields of the data table.

**Signature**

- `resetFields(): void`

**Example**

```ts
const posts = db.collection({
  name: 'posts',
  fields: [
    {
      type: 'string',
      name: 'title',
    },
  ],
});

posts.resetFields();
```

### `hasField()`

Check if the data table has defined a field object with the corresponding name.

**Signature**

- `hasField(name: string): boolean`

**Parameter**

| Name   | Type     | Default | Description       |
| ------ | -------- | ------- | ----------------- |
| `name` | `string` | -       | Name of the field |

**Example**

```ts
const posts = db.collection({
  name: 'posts',
  fields: [
    {
      type: 'string',
      name: 'title',
    },
  ],
});

posts.hasField('title'); // true
```

### `findField()`

Find field objects in the data table that match the conditions.

**Signature**

- `findField(predicate: (field: Field) => boolean): Field | undefined`

**Parameter**

| Name        | Type                        | Default | Description   |
| ----------- | --------------------------- | ------- | ------------- |
| `predicate` | `(field: Field) => boolean` | -       | The condition |

**Example**

```ts
const posts = db.collection({
  name: 'posts',
  fields: [
    {
      type: 'string',
      name: 'title',
    },
  ],
});

posts.findField((field) => field.name === 'title');
```

### `forEachField()`

Iterate over field objects in the data table.

**Signature**

- `forEachField(callback: (field: Field) => void): void`

**Parameter**

| Name       | Type                     | Default | Description       |
| ---------- | ------------------------ | ------- | ----------------- |
| `callback` | `(field: Field) => void` | -       | Callback function |

**Example**

```ts
const posts = db.collection({
  name: 'posts',
  fields: [
    {
      type: 'string',
      name: 'title',
    },
  ],
});

posts.forEachField((field) => console.log(field.name));
```

## Index Configuration Methods

### `addIndex()`

Add data table index.

**Signature**

- `addIndex(index: string | string[] | { fields: string[], unique?: boolean,[key: string]: any })`

**Parameter**

| Name    | Type                                                         | Default | Description                   |
| ------- | ------------------------------------------------------------ | ------- | ----------------------------- |
| `index` | `string \| string[]`                                         | -       | Names of fields to be indexed |
| `index` | `{ fields: string[], unique?: boolean, [key: string]: any }` | -       | Full configuration            |

**Example**

```ts
const posts = db.collection({
  name: 'posts',
  fields: [
    {
      type: 'string',
      name: 'title',
    },
  ],
});

posts.addIndex({
  fields: ['title'],
  unique: true,
});
```

### `removeIndex()`

Remove data table index.

**Signature**

- `removeIndex(fields: string[])`

**Parameter**

| Name     | Type       | Default | Description                       |
| -------- | ---------- | ------- | --------------------------------- |
| `fields` | `string[]` | -       | Names of fields to remove indexes |

**Example**

```ts
const posts = db.collection({
  name: 'posts',
  fields: [
    {
      type: 'string',
      name: 'title',
    },
  ],
  indexes: [
    {
      fields: ['title'],
      unique: true,
    },
  ],
});

posts.removeIndex(['title']);
```

## Table Configuration Methods

### `remove()`

Remove data table.

**Signature**

- `remove(): void`

**Example**

```ts
const posts = db.collection({
  name: 'posts',
  fields: [
    {
      type: 'string',
      name: 'title',
    },
  ],
});

posts.remove();
```

## Database Operation Methods

### `sync()`

Synchronize the definitions in data table to the database. In addition to the default `Model.sync` logic in Sequelize, the data tables corresponding to the relational fields will also be handled together.

**Signature**

- `sync(): Promise<void>`

**Example**

```ts
const posts = db.collection({
  name: 'posts',
  fields: [
    {
      type: 'string',
      name: 'title',
    },
  ],
});

await posts.sync();
```

### `existsInDb()`

Check whether the data table exists in the database.

**Signature**

- `existsInDb(options?: Transactionable): Promise`

**Parameter**

| Name                   | Type          | Default | Description          |
| ---------------------- | ------------- | ------- | -------------------- |
| `options?.transaction` | `Transaction` | -       | Transaction instance |

**Example**

```ts
const posts = db.collection({
  name: 'posts',
  fields: [
    {
      type: 'string',
      name: 'title',
    },
  ],
});

const existed = await posts.existsInDb();

console.log(existed); // false
```

### `removeFromDb()`

**Signature**

- `removeFromDb(): Promise<void>`

**Example**

```ts
const books = db.collection({
  name: 'books',
});

//  Synchronize the table books to the database
await db.sync();

// Remove the table books from the database
await books.removeFromDb();
```

---

## File: docs/en-US/api/database/field.md

# Field

## Overview

Data table field management class (abstract class). It is also the base class for all field types, and any other field types are implemented by inheriting from this class.

Refer to [Extended Field Types](/development/server/collections-fields#extended-field-types) to see how to customize fields.

## Constructor

It is usually not called directly by the developer, but mainly through the `db.collection({ fields: [] })` method as a proxy entry.

Extended field is implemented mainly by inheriting the `Field` abstract class and registering it to a Database instance.

**Signature**

- `constructor(options: FieldOptions, context: FieldContext)`

**Parameter**

| Name                 | Type           | Default | Description                                                                  |
| -------------------- | -------------- | ------- | ---------------------------------------------------------------------------- |
| `options`            | `FieldOptions` | -       | Field configuration object                                                   |
| `options.name`       | `string`       | -       | Field name                                                                   |
| `options.type`       | `string`       | -       | Field type, corresponding to the name of the field type registered in the db |
| `context`            | `FieldContext` | -       | Field context object                                                         |
| `context.database`   | `Database`     | -       | Database instance                                                            |
| `context.collection` | `Collection`   | -       | Data table instance                                                          |

## Instance Members

### `name`

Field name.

### `type`

Field type.

### `dataType`

Data type of the field.

### `options`

Configuration parameters to initialize the field.

### `context`

Field context object.

## Configuration Methods

### `on()`

Quick definition method based on data table events. It is equivalent to `db.on(this.collection.name + '.' + eventName, listener)`.

It is usually not necessary to override this method when inheriting.

**Signature**

- `on(eventName: string, listener: (...args: any[]) => void)`

**Parameter**

| Name        | Type                       | Default | Description    |
| ----------- | -------------------------- | ------- | -------------- |
| `eventName` | `string`                   | -       | Event name     |
| `listener`  | `(...args: any[]) => void` | -       | Event listener |

### `off()`

Quick removal method based on data table events. It is equivalent to `db.off(this.collection.name + '.' + eventName, listener)`.

It is usually not necessary to override this method when inheriting.

**Signature**

- `off(eventName: string, listener: (...args: any[]) => void)`

**Parameter**

| Name        | Type                       | Default | Description    |
| ----------- | -------------------------- | ------- | -------------- |
| `eventName` | `string`                   | -       | Event name     |
| `listener`  | `(...args: any[]) => void` | -       | Event listener |

### `bind()`

The execution content that is triggered when a field is added to data table. Typically used to add data table event listeners and other processing.

The corresponding `super.bind()` method needs to be called first when inheriting.

**Signature**

- `bind()`

### `unbind()`

The execution content that is triggered when a field is removed from data table. Typically used to remove data table event listeners and other processing.

The corresponding `super.unbind()` method needs to be called first when inheriting.

**Signature**

- `unbind()`

### `get()`

Get the values of a configuration item of the field.

**Signature**

- `get(key: string): any`

**Parameter**

| Name  | Type     | Default | Description                    |
| ----- | -------- | ------- | ------------------------------ |
| `key` | `string` | -       | Name of the configuration item |

**Example**

```ts
const field = db.collection('users').getField('name');

// Get and return the values of the configuration item 'name'
console.log(field.get('name'));
```

### `merge()`

Merge the values of a configuration item of the field.

**Signature**

- `merge(options: { [key: string]: any }): void`

**Parameter**

| Name      | Type                     | Default | Description                     |
| --------- | ------------------------ | ------- | ------------------------------- |
| `options` | `{ [key: string]: any }` | -       | The configuration item to merge |

**Example**

```ts
const field = db.collection('users').getField('name');

field.merge({
  // Add an index configuration
  index: true,
});
```

### `remove()`

Remove a field from data table (from memory only).

**Example**

```ts
const books = db.getCollections('books');

books.getField('isbn').remove();

// really remove from db
await books.sync();
```

## Database Methods

### `removeFromDb()`

Remove a field from the database.

**Signature**

- `removeFromDb(options?: Transactionable): Promise<void>`

**Parameter**

| Name                   | Type          | Default | Description          |
| ---------------------- | ------------- | ------- | -------------------- |
| `options.transaction?` | `Transaction` | -       | Transaction instance |

### `existsInDb()`

Check if a field exists in the database.

**Signature**

- `existsInDb(options?: Transactionable): Promise`

**Parameter**

| Name                   | Type          | Default | Description          |
| ---------------------- | ------------- | ------- | -------------------- |
| `options.transaction?` | `Transaction` | -       | Transaction instance |

## Built-in Field Types

NocoBase has some built-in common field types, the corresponding type name can be used directly to specify the type of field upon definition. Fields of different types are configured differently, please refer to the list below.

The configuration items of all field types are passed through to Sequelize in addition to those described below. Therefore, all field configuration items supported by Sequelize can be used here (e.g. `allowNull`, `defaultValue`, etc.).

Moreover, server-side field types are mainly used for solving the problems of database storage and some algorithms, they are barely relevant to the field display types and the use of components in front-end. The front-end field types can be found in the corresponding tutorials.

### `'boolean'`

Boolean type.

**Example**

```js
db.collection({
  name: 'books',
  fields: [
    {
      type: 'boolean',
      name: 'published',
    },
  ],
});
```

### `'integer'`

Integer type (32 bits).

**Example**

```ts
db.collection({
  name: 'books',
  fields: [
    {
      type: 'integer',
      name: 'pages',
    },
  ],
});
```

### `'bigInt'`

Long integer type (64 bits).

**Example**

```ts
db.collection({
  name: 'books',
  fields: [
    {
      type: 'bigInt',
      name: 'words',
    },
  ],
});
```

### `'double'`

Double-precision floating-point format (64 bits).

**Example**

```ts
db.collection({
  name: 'books',
  fields: [
    {
      type: 'double',
      name: 'price',
    },
  ],
});
```

### `'real'`

Real type (PG only).

### `'decimal'`

Decimal type.

### `'string'`

String type. Equivalent to the `VARCHAR` type for most databases.

**Example**

```ts
db.collection({
  name: 'books',
  fields: [
    {
      type: 'string',
      name: 'title',
    },
  ],
});
```

### `'text'`

Text type. Equivalent to the `TEXT` type for most databases.

**Example**

```ts
db.collection({
  name: 'books',
  fields: [
    {
      type: 'text',
      name: 'content',
    },
  ],
});
```

### `'password'`

Password type (NocoBase extension). Password encryption based on the `scrypt` method of Node.js native crypto packages.

**Example**

```ts
db.collection({
  name: 'users',
  fields: [
    {
      type: 'password',
      name: 'password',
      length: 64, // Length, default is 64
      randomBytesSize: 8, // Length of random bytes, default is 8
    },
  ],
});
```

**Parameter**

| Name              | Type     | Default | Description            |
| ----------------- | -------- | ------- | ---------------------- |
| `length`          | `number` | 64      | Length of characters   |
| `randomBytesSize` | `number` | 8       | Length of random bytes |

### `'date'`

Date type.

### `'time'`

Time type.

### `'array'`

Array type (PG only).

### `'json'`

JSON type.

### `'jsonb'`

JSONB type (PG only, others will be compatible with the `'json'` type).

### `'uuid'`

UUID type.

### `'uid'`

UID type (NocoBase extension). Short random string identifier type.

### `'formula'`

Formula type (NocoBase extension). Mathematical formula calculation can be configured based on [mathjs](https://www.npmjs.com/package/mathjs), and the formula can refer to the values of other columns in the same record to participate in the calculation.

**Example**

```ts
db.collection({
  name: 'orders',
  fields: [
    {
      type: 'double',
      name: 'price',
    },
    {
      type: 'integer',
      name: 'quantity',
    },
    {
      type: 'formula',
      name: 'total',
      expression: 'price * quantity',
    },
  ],
});
```

### `'radio'`

Radio type (NocoBase extension). The field value is 'true' for at most one row of data for the full table, all others are 'false' or 'null'.

**Example**

There is only one user marked as *root* in the entire system, once the *root* value of any other user is changed to `true`, all other records with *root* of `true` will be changed to `false`:

```ts
db.collection({
  name: 'users',
  fields: [
    {
      type: 'radio',
      name: 'root',
    },
  ],
});
```

### `'sort'`

Sorting type (NocoBase extension). Sorting based on integer numbers, automatically generating new serial numbers for new records, and rearranging serial numbers when moving data.

If data table has the `sortable` option defined, the corresponding fields will be generated automatically.

**Example**

Posts are sortable based on the users they belong to.

```ts
db.collection({
  name: 'posts',
  fields: [
    {
      type: 'belongsTo',
      name: 'user',
    },
    {
      type: 'sort',
      name: 'priority',
      scopeKey: 'userId', // Sort data grouped by the values of userId
    },
  ],
});
```

### `'virtual'`

Virtual type. No Data is actually stored, it is used only when special getter/setter is defined.

### `'belongsTo'`

Many-to-one association type. Foreign key is stored in its own table, as opposed to `'hasOne'`/`'hasMany'`.

**Example**

Any post belongs to an author:

```ts
db.collection({
  name: 'posts',
  fields: [
    {
      type: 'belongsTo',
      name: 'author',
      target: 'users', // Default table name is the plural form of <name>
      foreignKey: 'authorId', // Default is '<name> + Id'
      sourceKey: 'id', // Default is id of the <target> table
    },
  ],
});
```

### `'hasOne'`

One-to-one association type. Foreign key is stored in the association table, as opposed to `'belongsTo'`.

**Example**

Any user has a profile:

```ts
db.collection({
  name: 'users',
  fields: [
    {
      type: 'hasOne',
      name: 'profile',
      target: 'profiles', // Can be omitted
    },
  ],
});
```

### `'hasMany'`

One-to-many association type. The foreign key is stored in the association table, as opposed to `'belongsTo'`.

**Example**

Any user can have multiple posts:

```ts
db.collection({
  name: 'users',
  fields: [
    {
      type: 'hasMany',
      name: 'posts',
      foreignKey: 'authorId',
      sourceKey: 'id',
    },
  ],
});
```

### `'belongsToMany'`

Many-to-many association type. Intermediate table is used to store both foreign keys. If no existing table is specified as intermediate table, it will be created automatically.

**Example**

Any post can have multiple tags added to it, and any tag can be added to multiple posts:

```ts
db.collection({
  name: 'posts',
  fields: [
    {
      type: 'belongsToMany',
      name: 'tags',
      target: 'tags', // Can be omitted if name is the same
      through: 'postsTags', // Intermediate table will be generated automatically if not specified
      foreignKey: 'postId', // Foreign key in the intermediate table referring to the table itself
      sourceKey: 'id', // Primary key of the table itself
      otherKey: 'tagId', // Foreign key in the intermediate table referring to the association table
    },
  ],
});

db.collection({
  name: 'tags',
  fields: [
    {
      type: 'belongsToMany',
      name: 'posts',
      through: 'postsTags', // Refer to the same intermediate table in the same set of relation
    },
  ],
});
```

---

## File: docs/en-US/api/database/index.md

# Database

## Overview

Database is the database interaction tool provided by NocoBase, it provides very convenient database interaction features for no-code and low-code applications. The supported databases are:

- SQLite 3.8.8+
- MySQL 8.0.17+
- PostgreSQL 10.0+

### Connect to Database

In `Database` constructor, database connection can be configured by passing the `options` parameter.

```javascript
const { Database } = require('@nocobase/database');

// MySQL database configuration parameters
const database = new Database({
  dialect: 'mysql',
  host: 'localhost',
  port: 3306,
  database: 'nocobase',
  username: 'root',
  password: 'password'
})

// MySQL \ PostgreSQL database configuration parameters
const database = new Database({
  dialect: /* 'postgres' or 'mysql' */,
  database: 'database',
  username: 'username',
  password: 'password',
  host: 'localhost',
  port: 'port'
})

```

Refer to [Constructor](#constructor) for detailed configurations.

### Define Data Structure

`Database` defines database structure through `Collection`, one `Collection` object represents one table in the database.

```javascript
// Define Collection
const UserCollection = database.collection({
  name: 'users',
  fields: [
    {
      name: 'name',
      type: 'string',
    },
    {
      name: 'age',
      type: 'integer',
    },
  ],
});
```

After the database structure is defined, use `sync()` method to synchronize the database structure.

```javascript
await database.sync();
```

Refer to [Collection](/api/database/collection) for detailed usage of `Collection`.

### CRUD Data

`Database` operates data through `Repository`.

```javascript
const UserRepository = UserCollection.repository();

// Create
await UserRepository.create({
  name: 'Mark',
  age: 18,
});

// Query
const user = await UserRepository.findOne({
  filter: {
    name: 'Mark',
  },
});

// Update
await UserRepository.update({
  values: {
    age: 20,
  },
});

// Delete
await UserRepository.destroy(user.id);
```

Refer to [Repository](/api/database/repository) for details of data CRUD.

## Constructor

**Signature**

- `constructor(options: DatabaseOptions)`

Create a database instance.

**Parameter**

| Name                   | Type           | Default       | Description                                                                                                                                         |
| ---------------------- | -------------- | ------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| `options.host`         | `string`       | `'localhost'` | Database host                                                                                                                                       |
| `options.port`         | `number`       | -             | Database service port, default port depends on the type of database used                                                                            |
| `options.username`     | `string`       | -             | Database username                                                                                                                                   |
| `options.password`     | `string`       | -             | Database password                                                                                                                                   |
| `options.database`     | `string`       | -             | Database name                                                                                                                                       |
| `options.dialect`      | `string`       | `'mysql'`     | Database type                                                                                                                                       |
| `options.storage?`     | `string`       | `':memory:'`  | Storage mode for SQLite                                                                                                                             |
| `options.logging?`     | `boolean`      | `false`       | Whether to enable logging                                                                                                                           |
| `options.define?`      | `Object`       | `{}`          | Default table definition parameters                                                                                                                 |
| `options.tablePrefix?` | `string`       | `''`          | NocoBase extension, table prefix                                                                                                                    |
| `options.migrator?`    | `UmzugOptions` | `{}`          | NocoBase extension, parameters for migrator, refer to [Umzug](https://github.com/sequelize/umzug/blob/main/src/types.ts#L15) for the implementation |

## Migration Methods

### `addMigration()`

Add single migration file.

**Signature**

- `addMigration(options: MigrationItem)`

**Parameter**

| Name                 | Type               | Default | Description                         |
| -------------------- | ------------------ | ------- | ----------------------------------- |
| `options.name`       | `string`           | -       | Name of the migration file          |
| `options.context?`   | `string`           | -       | Context of the migration file       |
| `options.migration?` | `typeof Migration` | -       | Custom type of the migration file   |
| `options.up`         | `Function`         | -       | `up` method of the migration file   |
| `options.down`       | `Function`         | -       | `down` method of the migration file |

**Example**

```ts
db.addMigration({
  name: '20220916120411-test-1',
  async up() {
    const queryInterface = this.context.db.sequelize.getQueryInterface();
    await queryInterface.query(/* your migration sqls */);
  },
});
```

### `addMigrations()`

Add the migration files in the specified directory.

**Signature**

- `addMigrations(options: AddMigrationsOptions): void`

**Parameter**

| Name                 | Type       | Default        | Description                                     |
| -------------------- | ---------- | -------------- | ----------------------------------------------- |
| `options.directory`  | `string`   | `''`           | Directory where the migration files are located |
| `options.extensions` | `string[]` | `['js', 'ts']` | File extensions                                 |
| `options.namespace?` | `string`   | `''`           | Namespace                                       |
| `options.context?`   | `Object`   | `{ db }`       | Context of the migration files                  |

**Example**

```ts
db.addMigrations({
  directory: path.resolve(__dirname, './migrations'),
  namespace: 'test',
});
```

## Tool Methods

### `inDialect()`

Check whether the current database type is the specified type.

**Signature**

- `inDialect(dialect: string[]): boolean`

**Parameter**

| Name      | Type       | Default | Description                                                 |
| --------- | ---------- | ------- | ----------------------------------------------------------- |
| `dialect` | `string[]` | -       | Database type, options are `mysql`, `postgres` and `mariadb` |

### `getTablePrefix()`

Get the table name prefix in the configuration.

**Signature**

- `getTablePrefix(): string`

## Data Table Configurations

### `collection()`

Define a data table. This is like the `define` method of Sequelize, which only creates table structure in memory. Call the `sync` method if needs to be persisted to the database.

**Signature**

- `collection(options: CollectionOptions): Collection`

**Parameter**

All configuration parameters of `options` is consistent with the constructor of the `Collection` class, refer to [Collection](/api/database/collection#Constructor).

**Event**

- `'beforeDefineCollection'`: Trigger before defining the table.
- `'afterDefineCollection'`: Trigger after defining the table.

**Example**

```ts
db.collection({
  name: 'books',
  fields: [
    {
      type: 'string',
      name: 'title',
    },
    {
      type: 'float',
      name: 'price',
    },
  ],
});

// sync collection as table to db
await db.sync();
```

### `getCollection()`

Get a defined data table.

**Signature**

- `getCollection(name: string): Collection`

**Parameter**

| Name   | Type     | Default | Description |
| ------ | -------- | ------- | ----------- |
| `name` | `string` | -       | Table name  |

**Example**

```ts
const collection = db.getCollection('books');
```

### `hasCollection()`

Check whether a specified data table is defined.

**Signature**

- `hasCollection(name: string): boolean`

**Parameter**

| Name   | Type     | Default | Description |
| ------ | -------- | ------- | ----------- |
| `name` | `string` | -       | Table name  |

**Example**

```ts
db.collection({ name: 'books' });

db.hasCollection('books'); // true

db.hasCollection('authors'); // false
```

### `removeCollection()`

Remove a defined data table. It is to remove from memory only, call the `sync` method if needs to be persisted to the database.

**Signature**

- `removeCollection(name: string): void`

**Parameter**

| Name   | Type     | Default | Description |
| ------ | -------- | ------- | ----------- |
| `name` | `string` | -       | Table name  |

**Event**

- `'beforeRemoveCollection'`: Trigger before removing the table.
- `'afterRemoveCollection'`: Trigger after removing the table

**Example**

```ts
db.collection({ name: 'books' });

db.removeCollection('books');
```

### `import()`

Load all files in the import file directory into memory as the configuration of collection.

**Signature**

- `async import(options: { directory: string; extensions?: ImportFileExtension[] }): Promise<Map<string, Collection>>`

**Parameter**

| Name                 | Type       | Default        | Description                      |
| -------------------- | ---------- | -------------- | -------------------------------- |
| `options.directory`  | `string`   | -              | Path of directory to be imported |
| `options.extensions` | `string[]` | `['ts', 'js']` | Scan for specific suffixes       |

**Example**

The collection defined by file `./collections/books.ts` is as below:

```ts
export default {
  name: 'books',
  fields: [
    {
      type: 'string',
      name: 'title',
    },
  ],
};
```

Import the relevant configurations when loading the plugin:

```ts
class Plugin {
  async load() {
    await this.app.db.import({
      directory: path.resolve(__dirname, './collections'),
    });
  }
}
```

## Extension Registrations and Acquisitions

### `registerFieldTypes()`

Register custom field type.

**Signature**

- `registerFieldTypes(fieldTypes: MapOf<typeof Field>): void`

**Parameter**

`fieldTypes` is a key-value pair, where key is the field type name, and value is the field type class.

**Example**

```ts
import { Field } from '@nocobase/database';

class MyField extends Field {
  // ...
}

db.registerFieldTypes({
  myField: MyField,
});
```

### `registerModels()`

Register custom data model class.

**Signature**

- `registerModels(models: MapOf<ModelStatic<any>>): void`

**Parameter**

`models` is a key-value pair, where key is the data model name, and value is the data model class.

**Example**

```ts
import { Model } from '@nocobase/database';

class MyModel extends Model {
  // ...
}

db.registerModels({
  myModel: MyModel,
});

db.collection({
  name: 'myCollection',
  model: 'myModel',
});
```

### `registerRepositories()`

Register custom data repository class.

**Signature**

- `registerRepositories(repositories: MapOf<RepositoryType>): void`

**Parameter**

`repositories` is a key-value pair, where key is the data repository name, and value is the data repository class.

**Example**

```ts
import { Repository } from '@nocobase/database';

class MyRepository extends Repository {
  // ...
}

db.registerRepositories({
  myRepository: MyRepository,
});

db.collection({
  name: 'myCollection',
  repository: 'myRepository',
});
```

### `registerOperators()`

Register custom data query operator.

**Signature**

- `registerOperators(operators: MapOf<OperatorFunc>)`

**Parameter**

`operators` is a key-value pair, where key is the operator name, and value is the generating function of the comparison operator statement.

**Example**

```ts
db.registerOperators({
  $dateOn(value) {
    return {
      [Op.and]: [
        { [Op.gte]: stringToDate(value) },
        { [Op.lt]: getNextDay(value) },
      ],
    };
  },
});

db.getRepository('books').count({
  filter: {
    createdAt: {
      // registered operator
      $dateOn: '2020-01-01',
    },
  },
});
```

### `getModel()`

Get the defined data model class. If no custom model class has been registered before, the default model class of Sequelize will be returned. The default name is the same as the name defined by collection.

**Signature**

- `getModel(name: string): Model`

**Parameter**

| Name   | Type     | Default | Description           |
| ------ | -------- | ------- | --------------------- |
| `name` | `string` | -       | Registered model name |

**Example**

```ts
db.registerModels({
  books: class MyModel extends Model {},
});

const ModelClass = db.getModel('books');

console.log(ModelClass.prototype instanceof MyModel); // true
```

Note: The model class retrieved from collection is not strictly equivalent to the model class at registration, but is inherited from the model class at registration. Since the properties of Sequelize's model class are modified during initialization, NocoBase automatically handles this inheritance relationship. All the definitions work fine except that the classes are not equal.

### `getRepository()`

Get the defined data repository class. If no custom data repository class has been registered before, the default data repository class of NocoBase will be returned. The default name is the same as the name defined by collection.

Data repository class is mainly used for the CRUD operations based on data model, refer to [Repository](/api/database/repository).

**Signature**

- `getRepository(name: string): Repository`
- `getRepository(name: string, relationId?: string | number): Repository`

**Parameter**

| Name         | Type                 | Default | Description                           |
| ------------ | -------------------- | ------- | ------------------------------------- |
| `name`       | `string`             | -       | Registered data repository name       |
| `relationId` | `string` \| `number` | -       | Foreign key value for relational data |

When the name contains relationship in the form of `'tables.relactions'`, the related data repository class is returned. If the second parameter is provided, the data repository will be used (query, modify, etc.) based on the foreign key values of the relational data.

**Example**

Suppose there are two data tables *posts* and *authors*, and there is a foreign key in the *posts* table points to the *authors* table:

```ts
const AuthorsRepo = db.getRepository('authors');
const author1 = AuthorsRepo.create({ name: 'author1' });

const PostsRepo = db.getRepository('authors.posts', author1.id);
const post1 = AuthorsRepo.create({ title: 'post1' });
asset(post1.authorId === author1.id); // true
```

## Database Events

### `on()`

Listen for database events.

**Signature**

- `on(event: string, listener: (...args: any[]) => void | Promise<void>): void`

**Parameter**

| Name     | Type     | Default | Description    |
| -------- | -------- | ------- | -------------- |
| event    | string   | -       | Event name     |
| listener | Function | -       | Event listener |

Event name supports Model event of Sequelize by default. Global event is listened to by the name `<sequelize_model_global_event>`, single Model event is listened to by the name `<model_name>. <sequelize_model_event>`.

Refer to the [Built-in Events](#built-in-events) section for parameter descriptions and detailed examples of all built-in event types.

### `off()`

Remove the event listener function.

**Signature**

- `off(name: string, listener: Function)`

**Parameter**

| Name     | Type     | Default | Description    |
| -------- | -------- | ------- | -------------- |
| name     | string   | -       | Event name     |
| listener | Function | -       | Event listener |

**Example**

```ts
const listener = async (model, options) => {
  console.log(model);
};

db.on('afterCreate', listener);

db.off('afterCreate', listener);
```

## Database Operations

### `auth()`

Database connection verification. It can be used to ensure that the application has established connection to the data.

**Signature**

- `auth(options: QueryOptions & { retry?: number } = {}): Promise`

**Parameter**

| Name                   | Type                  | Default | Description                                       |
| ---------------------- | --------------------- | ------- | ------------------------------------------------- |
| `options?`             | `Object`              | -       | Verification option                               |
| `options.retry?`       | `number`              | `10`    | Number of retries in case of verification failure |
| `options.transaction?` | `Transaction`         | -       | Transaction object                                |
| `options.logging?`     | `boolean \| Function` | `false` | Whether to print the log                          |

**Example**

```ts
await db.auth();
```

### `reconnect()`

Reconnect to the database.

**Example**

```ts
await db.reconnect();
```

### `closed()`

Check whether database has closed the connection.

**Signature**

- `closed(): boolean`

### `close()`

Closes database connection. Equivalent to `sequelize.close()`.

### `sync()`

Synchronizes database table structure. Equivalent to `sequelize.sync()`, refer to [Sequelize documentation](https://sequelize.org/api/v6/class/src/sequelize.js~sequelize#instance-method-sync) for parameters.

### `clean()`

Empty the database, it will delete all data tables.

**Signature**

- `clean(options: CleanOptions): Promise<void>`

**Parameter**

| Name                  | Type          | Default | Description                       |
| --------------------- | ------------- | ------- | --------------------------------- |
| `options.drop`        | `boolean`     | `false` | Whether to remove all data tables |
| `options.skip`        | `string[]`    | -       | Names of tables to skip           |
| `options.transaction` | `Transaction` | -       | Transaction object                |

**Example**

Remove all tables except for the `users` table.

```ts
await db.clean({
  drop: true,
  skip: ['users'],
});
```

## Package-Level Export

### `defineCollection()`

Create the configuration content of a data table.

**Signature**

- `defineCollection(name: string, config: CollectionOptions): CollectionOptions`

**Parameter**

| Name                | Type                | Default | Description                                        |
| ------------------- | ------------------- | ------- | -------------------------------------------------- |
| `collectionOptions` | `CollectionOptions` | -       | All parameters are the same with `db.collection()` |

**Example**

For the data table configuration file to be imported by `db.import()`:

```ts
import { defineCollection } from '@nocobase/database';

export default defineCollection({
  name: 'users',
  fields: [
    {
      type: 'string',
      name: 'name',
    },
  ],
});
```

### `extendCollection()`

Extent the configuration content of a data table that is already in memory, mainly for the content of files imported by the `import()` method. This is the top-level package export method of `@nocobase/database`, and is not called through db instance. The `extend` alias can also be used.

**Signature**

- `extendCollection(collectionOptions: CollectionOptions, mergeOptions?: MergeOptions): ExtendedCollectionOptions`

**Parameter**

| Name                | Type                | Default | Description                                                             |
| ------------------- | ------------------- | ------- | ----------------------------------------------------------------------- |
| `collectionOptions` | `CollectionOptions` | -       | All the same with `db.collection()`                                     |
| `mergeOptions?`     | `MergeOptions`      | -       | [deepmerge](https://npmjs.com/package/deepmerge) options of npm package |

**Example**

Original definition of the table *books* (books.ts):

```ts
export default {
  name: 'books',
  fields: [{ name: 'title', type: 'string' }],
};
```

Extend the definition of the table *books* (books.extend.ts):

```ts
import { extend } from '@nocobase/database';

// Extend again
export default extend({
  name: 'books',
  fields: [{ name: 'price', type: 'number' }],
});
```

If the above two files are imported when calling `import()`, after being extended again by `extend()`, the table *books* will have `title` and `price` two fields.

This method is especially useful when extending the table structure that is already defined by existing plugin.

## Built-in Events

The following events will be triggered in the corresponding lifecycle of database, subscribe by the `on()` method and perform specific processing to meet some business needs.

### `'beforeSync'` / `'afterSync'`

Events triggered before or after a new table structure configuration (fields, indexes, etc.) is synchronized to the database. This is usually triggered when executing `collection.sync()` (internal call) for the logical processing of the extension of some special fields.

**Signature**

```ts
on(eventName: `${string}.beforeSync` | 'beforeSync' | `${string}.afterSync` | 'afterSync', listener: SyncListener): this
```

**Type**

```ts
import type { SyncOptions, HookReturn } from 'sequelize/types';

type SyncListener = (options?: SyncOptions) => HookReturn;
```

**Example**

```ts
const users = db.collection({
  name: 'users',
  fields: [{ type: 'string', name: 'username' }],
});

db.on('beforeSync', async (options) => {
  // do something
});

db.on('users.afterSync', async (options) => {
  // do something
});

await users.sync();
```

### `'beforeValidate'` / `'afterValidate'`

Before creating or updating data, there is a validation against the data based on the rules defined by the collection, and the corresponding events are triggered before and after the validation. This is triggered when `repository.create()` or `repository.update()` is called.

**Signature**

```ts
on(eventName: `${string}.beforeValidate` | 'beforeValidate' | `${string}.afterValidate` | 'afterValidate', listener: ValidateListener): this
```

**Type**

```ts
import type { ValidationOptions } from 'sequelize/types/lib/instance-validator';
import type { HookReturn } from 'sequelize/types';
import type { Model } from '@nocobase/database';

type ValidateListener = (
  model: Model,
  options?: ValidationOptions,
) => HookReturn;
```

**Example**

```ts
db.collection({
  name: 'tests',
  fields: [
    {
      type: 'string',
      name: 'email',
      validate: {
        isEmail: true,
      },
    },
  ],
});

// all models
db.on('beforeValidate', async (model, options) => {
  // do something
});
// tests model
db.on('tests.beforeValidate', async (model, options) => {
  // do something
});

// all models
db.on('afterValidate', async (model, options) => {
  // do something
});
// tests model
db.on('tests.afterValidate', async (model, options) => {
  // do something
});

const repository = db.getRepository('tests');
await repository.create({
  values: {
    email: 'abc', // checks for email format
  },
});
// or
await repository.update({
  filterByTk: 1,
  values: {
    email: 'abc', // checks for email format
  },
});
```

### `'beforeCreate'` / `'afterCreate'`

Events triggered before or after creating one piece of data. This is triggered when `repository.create()` is called.

**Signature**

```ts
on(eventName: `${string}.beforeCreate` | 'beforeCreate' | `${string}.afterCreate` | 'afterCreate', listener: CreateListener): this
```

**Type**

```ts
import type { CreateOptions, HookReturn } from 'sequelize/types';
import type { Model } from '@nocobase/database';

export type CreateListener = (
  model: Model,
  options?: CreateOptions,
) => HookReturn;
```

**Example**

```ts
db.on('beforeCreate', async (model, options) => {
  // do something
});

db.on('books.afterCreate', async (model, options) => {
  const { transaction } = options;
  const result = await model.constructor.findByPk(model.id, {
    transaction,
  });
  console.log(result);
});
```

### `'beforeUpdate'` / `'afterUpdate'`

Events triggered before or after updating one piece of data. This is triggered when `repository.update()` is called.

**Signature**

```ts
on(eventName: `${string}.beforeUpdate` | 'beforeUpdate' | `${string}.afterUpdate` | 'afterUpdate', listener: UpdateListener): this
```

**Type**

```ts
import type { UpdateOptions, HookReturn } from 'sequelize/types';
import type { Model } from '@nocobase/database';

export type UpdateListener = (
  model: Model,
  options?: UpdateOptions,
) => HookReturn;
```

**Example**

```ts
db.on('beforeUpdate', async (model, options) => {
  // do something
});

db.on('books.afterUpdate', async (model, options) => {
  // do something
});
```

### `'beforeSave'` / `'afterSave'`

Events triggered before or after creating or updating one piece of data. This is triggered when `repository.create()` or `repository.update()` is called.

**Signature**

```ts
on(eventName: `${string}.beforeSave` | 'beforeSave' | `${string}.afterSave` | 'afterSave', listener: SaveListener): this
```

**Type**

```ts
import type { SaveOptions, HookReturn } from 'sequelize/types';
import type { Model } from '@nocobase/database';

export type SaveListener = (model: Model, options?: SaveOptions) => HookReturn;
```

**Example**

```ts
db.on('beforeSave', async (model, options) => {
  // do something
});

db.on('books.afterSave', async (model, options) => {
  // do something
});
```

### `'beforeDestroy'` / `'afterDestroy'`

Events triggered before or after deleting one piece of data. This is triggered when `repository.destroy()` is called.

**Signature**

```ts
on(eventName: `${string}.beforeDestroy` | 'beforeDestroy' | `${string}.afterDestroy` | 'afterDestroy', listener: DestroyListener): this
```

**Type**

```ts
import type { DestroyOptions, HookReturn } from 'sequelize/types';
import type { Model } from '@nocobase/database';

export type DestroyListener = (
  model: Model,
  options?: DestroyOptions,
) => HookReturn;
```

**Example**

```ts
db.on('beforeDestroy', async (model, options) => {
  // do something
});

db.on('books.afterDestroy', async (model, options) => {
  // do something
});
```

### `'afterCreateWithAssociations'`

Events triggered after creating one piece of data that carries hierarchical data. This is triggered when `repository.create()` is called.

**Signature**

```ts
on(eventName: `${string}.afterCreateWithAssociations` | 'afterCreateWithAssociations', listener: CreateWithAssociationsListener): this
```

**Type**

```ts
import type { CreateOptions, HookReturn } from 'sequelize/types';
import type { Model } from '@nocobase/database';

export type CreateWithAssociationsListener = (
  model: Model,
  options?: CreateOptions,
) => HookReturn;
```

**Example**

```ts
db.on('afterCreateWithAssociations', async (model, options) => {
  // do something
});

db.on('books.afterCreateWithAssociations', async (model, options) => {
  // do something
});
```

### `'afterUpdateWithAssociations'`

Events triggered after updating one piece of data that carries hierarchical data. This is triggered when `repository.update()` is called.

**Signature**

```ts
on(eventName: `${string}.afterUpdateWithAssociations` | 'afterUpdateWithAssociations', listener: CreateWithAssociationsListener): this
```

**Type**

```ts
import type { UpdateOptions, HookReturn } from 'sequelize/types';
import type { Model } from '@nocobase/database';

export type UpdateWithAssociationsListener = (
  model: Model,
  options?: UpdateOptions,
) => HookReturn;
```

**Example**

```ts
db.on('afterUpdateWithAssociations', async (model, options) => {
  // do something
});

db.on('books.afterUpdateWithAssociations', async (model, options) => {
  // do something
});
```

### `'afterSaveWithAssociations'`

Events triggered after creating or updating one piece of data that carries hierarchical data. This is triggered when `repository.create()` or `repository.update()` is called.

**Signature**

```ts
on(eventName: `${string}.afterSaveWithAssociations` | 'afterSaveWithAssociations', listener: SaveWithAssociationsListener): this
```

**Type**

```ts
import type { SaveOptions, HookReturn } from 'sequelize/types';
import type { Model } from '@nocobase/database';

export type SaveWithAssociationsListener = (
  model: Model,
  options?: SaveOptions,
) => HookReturn;
```

**Example**

```ts
db.on('afterSaveWithAssociations', async (model, options) => {
  // do something
});

db.on('books.afterSaveWithAssociations', async (model, options) => {
  // do something
});
```

### `'beforeDefineCollection'`

Events triggered before defining a data table, such as when `db.collection()` is called.

Note: This is a synchronous event.

**Signature**

```ts
on(eventName: 'beforeDefineCollection', listener: BeforeDefineCollectionListener): this
```

**Type**

```ts
import type { CollectionOptions } from '@nocobase/database';

export type BeforeDefineCollectionListener = (
  options: CollectionOptions,
) => void;
```

**Example**

```ts
db.on('beforeDefineCollection', (options) => {
  // do something
});
```

### `'afterDefineCollection'`

Events triggered after defining a data table, such as when `db.collection()` is called.

Note: This is a synchronous event.

**Signature**

```ts
on(eventName: 'afterDefineCollection', listener: AfterDefineCollectionListener): this
```

**Type**

```ts
import type { Collection } from '@nocobase/database';

export type AfterDefineCollectionListener = (options: Collection) => void;
```

**Example**

```ts
db.on('afterDefineCollection', (collection) => {
  // do something
});
```

### `'beforeRemoveCollection'` / `'afterRemoveCollection'`

Events triggered before or after removing a data table from memory, such as when `db.removeCollection()` is called.

Note: This is a synchronous event.

**Signature**

```ts
on(eventName: 'beforeRemoveCollection' | 'afterRemoveCollection', listener: RemoveCollectionListener): this
```

**Type**

```ts
import type { Collection } from '@nocobase/database';

export type RemoveCollectionListener = (options: Collection) => void;
```

**Example**

```ts
db.on('beforeRemoveCollection', (collection) => {
  // do something
});

db.on('afterRemoveCollection', (collection) => {
  // do something
});
```

---

## File: docs/en-US/api/database/operators.md

# Filter Operators

Used in the filter parameters of the `find`, `findOne`, `findAndCount`, `count`, etc. APIs of repository:

```ts
const repository = db.getRepository('books');

repository.find({
  filter: {
    title: {
      $eq: 'Spring and Autumn',
    },
  },
});
```

To support JSON, NocoBase identifies query operators as a string prefixed with $.

Moreover, NocoBase provides API to extend operators. Refer to [`db.registerOperators()`](../database#registeroperators).

## General Operators

### `$eq`

Check if the field value is equal to the specified value. Equivalent to `=` in SQL.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $eq: 'Spring and Autumn',
    },
  },
});
```

Equal to `title: 'Spring and Autumn'`

### `$ne`

Check if the field value is not equal to the specified value. Equivalent to `!=` in SQL.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $ne: 'Spring and Autumn',
    },
  },
});
```

### `$is`

Check if the field value is the specified value. Equivalent to `IS` in SQL.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $is: null,
    },
  },
});
```

### `$not`

Check if the field value is not the specified value. Equivalent to `IS NOT` in SQL.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $not: null,
    },
  },
});
```

### `$col`

Check if the field value is equal to the value of another field. Equivalent to `=` in SQL.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $col: 'name',
    },
  },
});
```

### `$in`

Check if the field value is in the specified array. Equivalent to `IN` in SQL.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $in: ['Spring and Autumn', 'Warring States'],
    },
  },
});
```

### `$notIn`

Check if the field value is not in the specified array. Equivalent to `NOT IN` in SQL.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $notIn: ['Spring and Autumn', 'Warring States'],
    },
  },
});
```

### `$empty`

Check if the general field is empty. For string field, check if it is an empty string; for array field, check if it is an empty array.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $empty: true,
    },
  },
});
```

### `$notEmpty`

Check if the general field is not empty. For string field, check if it is not an empty string; for array field, check if it is not an empty array.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $notEmpty: true,
    },
  },
});
```

## Logical Operators

### `$and`

Logical AND. Equivalent to `AND` in SQL.

**Example**

```ts
repository.find({
  filter: {
    $and: [{ title: 'Book of Songs' }, { isbn: '1234567890' }],
  },
});
```

### `$or`

Logical OR. Equivalent to `OR` in SQL.

**Example**

```ts
repository.find({
  filter: {
    $or: [
      { title: 'Book of Songs' },
      { publishedAt: { $lt: '0000-00-00T00:00:00Z' } },
    ],
  },
});
```

## Boolean Field Operators

For boolean fields: `type: 'boolean'`

### `$isFalsy`

Check if a Boolean field value is false. Boolean field values of `false`, `0` and `NULL` are all judged to be `$isFalsy: true`.

**Example**

```ts
repository.find({
  filter: {
    isPublished: {
      $isFalsy: true,
    },
  },
});
```

### `$isTruly`

Check if a Boolean field value is true. Boolean field values of `true` and `1` are all judged to be `$isTruly: true`.

**Example**

```ts
repository.find({
  filter: {
    isPublished: {
      $isTruly: true,
    },
  },
});
```

## Numeric Type Field Operators

For numeric type fields, including:

- `type: 'integer'`
- `type: 'float'`
- `type: 'double'`
- `type: 'real'`
- `type: 'decimal'`

### `$gt`

Check if the field value is greater than the specified value. Equivalent to `>` in SQL.

**Example**

```ts
repository.find({
  filter: {
    price: {
      $gt: 100,
    },
  },
});
```

### `$gte`

Check if the field value is equal to or greater than the specified value. Equivalent to `>=` in SQL.

**Example**

```ts
repository.find({
  filter: {
    price: {
      $gte: 100,
    },
  },
});
```

### `$lt`

Check if the field value is less than the specified value. Equivalent to `<` in SQL.

**Example**

```ts
repository.find({
  filter: {
    price: {
      $lt: 100,
    },
  },
});
```

### `$lte`

Check if the field value is equal to or less than the specified value. Equivalent to `<=` in SQL.

**Example**

```ts
repository.find({
  filter: {
    price: {
      $lte: 100,
    },
  },
});
```

### `$between`

Check if the field value is between the specified two values. Equivalent to `BETWEEN` in SQL.

**Example**

```ts
repository.find({
  filter: {
    price: {
      $between: [100, 200],
    },
  },
});
```

### `$notBetween`

Check if the field value is not between the specified two values. Equivalent to `NOT BETWEEN` in SQL.

**Example**

```ts
repository.find({
  filter: {
    price: {
      $notBetween: [100, 200],
    },
  },
});
```

## String Type Field Operators

For string type fields, including `string`.

### `$includes`

Check if the string field contains the specified substring.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $includes: 'Three Character Classic',
    },
  },
});
```

### `$notIncludes`

Check if the string field does not contain the specified substring.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $notIncludes: 'Three Character Classic',
    },
  },
});
```

### `$startsWith`

Check if the string field starts with the specified substring.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $startsWith: 'Three Character Classic',
    },
  },
});
```

### `$notStatsWith`

Check if the string field does not start with the specified substring.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $notStatsWith: 'Three Character Classic',
    },
  },
});
```

### `$endsWith`

Check if the string field ends with the specified substring.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $endsWith: 'Three Character Classic',
    },
  },
});
```

### `$notEndsWith`

Check if the string field does not end with the specified substring.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $notEndsWith: 'Three Character Classic',
    },
  },
});
```

### `$like`

Check if the field value contains the specified string. Equivalent to `LIKE` in SQL.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $like: 'Computer',
    },
  },
});
```

### `$notLike`

Check if the field value does not contain the specified string. Equivalent to `NOT LIKE` in SQL.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $notLike: 'Computer',
    },
  },
});
```

### `$iLike`

Check if a field value contains the specified string, case ignored. Equivalent to `ILIKE` in SQL (PG only).

**Example**

```ts
repository.find({
  filter: {
    title: {
      $iLike: 'Computer',
    },
  },
});
```

### `$notILike`

Check if a field value does not contain the specified string, case ignored. Equivalent to `NOT ILIKE` in SQL (PG only).

**Example**

```ts
repository.find({
  filter: {
    title: {
      $notILike: 'Computer',
    },
  },
});
```

### `$regexp`

Check if the field value matches the specified regular expression. Equivalent to `REGEXP` in SQL (PG only).

**Example**

```ts
repository.find({
  filter: {
    title: {
      $regexp: '^Computer',
    },
  },
});
```

### `$notRegexp`

Check if the field value does not match the specified regular expression. Equivalent to `NOT REGEXP` in SQL (PG only).

**Example**

```ts
repository.find({
  filter: {
    title: {
      $notRegexp: '^Computer',
    },
  },
});
```

### `$iRegexp`

Check if the field value matches the specified regular expression, case ignored. Equivalent to `~*` in SQL (PG only).

**Example**

```ts
repository.find({
  filter: {
    title: {
      $iRegexp: '^COMPUTER',
    },
  },
});
```

### `$notIRegexp`

Check if the field value does not match the specified regular expression, case ignored. Equivalent to `!~*` in SQL (PG only).

**Example**

```ts
repository.find({
  filter: {
    title: {
      $notIRegexp: '^COMPUTER',
    },
  },
});
```

## Date Type Field Operators

For date type fields: `type: 'date'`

### `$dateOn`

Check if the date field value is within a certain day.

**Example**

```ts
repository.find({
  filter: {
    createdAt: {
      $dateOn: '2021-01-01',
    },
  },
});
```

### `$dateNotOn`

Check if the date field value is not within a certain day.

**Example**

```ts
repository.find({
  filter: {
    createdAt: {
      $dateNotOn: '2021-01-01',
    },
  },
});
```

### `$dateBefore`

Check if the date field value is before a certain value, i.e., less than the one passed in.

**Example**

```ts
repository.find({
  filter: {
    createdAt: {
      $dateBefore: '2021-01-01T00:00:00.000Z',
    },
  },
});
```

### `$dateNotBefore`

Check if the date field value is not before a certain value, i.e., equal to or greater than the one passed in.

**Example**

```ts
repository.find({
  filter: {
    createdAt: {
      $dateNotBefore: '2021-01-01T00:00:00.000Z',
    },
  },
});
```

### `$dateAfter`

Check if the date field value is after a certain value, i.e., greater than the one passed in.

**Example**

```ts
repository.find({
  filter: {
    createdAt: {
      $dateAfter: '2021-01-01T00:00:00.000Z',
    },
  },
});
```

### `$dateNotAfter`

Check if the date field value is not after a certain value, i.e., equal to or greater than the one passed in.

**Example**

```ts
repository.find({
  filter: {
    createdAt: {
      $dateNotAfter: '2021-01-01T00:00:00.000Z',
    },
  },
});
```

## Array Type Field Operators

For array type fields: `type: 'array'`

### `$match`

Check if the array field values match values of the specified array.

**Example**

```ts
repository.find({
  filter: {
    tags: {
      $match: ['literature', 'history'],
    },
  },
});
```

### `$notMatch`

Check if the array field values do not match values of the specified array.

**Example**

```ts
repository.find({
  filter: {
    tags: {
      $notMatch: ['literature', 'history'],
    },
  },
});
```

### `$anyOf`

Check if the array field values contain any of the values of the specified array.

**Example**

```ts
repository.find({
  filter: {
    tags: {
      $anyOf: ['literature', 'history'],
    },
  },
});
```

### `$noneOf`

Check if the array field values contain none of the values of the specified array.

**Example**

```ts
repository.find({
  filter: {
    tags: {
      $noneOf: ['literature', 'history'],
    },
  },
});
```

### `$arrayEmpty`

Check if the array field is empty.

**Example**

```ts
repository.find({
  filter: {
    tags: {
      $arrayEmpty: true,
    },
  },
});
```

### `$arrayNotEmpty`

Check if the array field is not empty.

**Example**

```ts
repository.find({
  filter: {
    tags: {
      $arrayNotEmpty: true,
    },
  },
});
```

## Relational Field Type Operators

For checking if a relationship exists, field types include:

- `type: 'hasOne'`
- `type: 'hasMany'`
- `type: 'belongsTo'`
- `type: 'belongsToMany'`

### `$exists`

There is relational data existing.

**Example**

```ts
repository.find({
  filter: {
    author: {
      $exists: true,
    },
  },
});
```

### `$notExists`

There is no relational data existing.

**Example**

```ts
repository.find({
  filter: {
    author: {
      $notExists: true,
    },
  },
});
```

---

## File: docs/en-US/api/database/repository.md

# Repository

## Overview

On a given `Collection` object, you can get its `Repository` object to perform read and write operations on the data table.

```javascript
const { UserCollection } = require('./collections');

const UserRepository = UserCollection.repository;

const user = await UserRepository.findOne({
  filter: {
    id: 1,
  },
});

user.name = 'new name';
await user.save();
```

### Query

#### Basic Query

On the `Repository` object, call the `find*` methods to perform query. The `filter` parameter is supported by all query methods to filter the data.

```javascript
// SELECT * FROM users WHERE id = 1
userRepository.find({
  filter: {
    id: 1,
  },
});
```

#### Operator

The `filter` parameter in the `Repository` also provides a variety of operators to perform more diverse queries.

```javascript
// SELECT * FROM users WHERE age > 18
userRepository.find({
  filter: {
    age: {
      $gt: 18,
    },
  },
});

// SELECT * FROM users WHERE age > 18 OR name LIKE '%张%'
userRepository.find({
  filter: {
    $or: [{ age: { $gt: 18 } }, { name: { $like: '%张%' } }],
  },
});
```

Refer to [Filter Operators](/api/database/operators) for more details on operators.

#### Field Control

Control the output fields by the `fields`, `except`, and `appends` parameters when performing query.

- `fields`: Specify output fields
- `except`: Exclude output fields
- `appends`: Append output associated fields

```javascript
// The result contains only the id and name fields
userRepository.find({
  fields: ['id', 'name'],
});

// The result does not contain only the password field
userRepository.find({
  except: ['password'],
});

// The result contains data associated with the posts object
userRepository.find({
  appends: ['posts'],
});
```

#### Associated Field Query

The `filter` parameter supports filtering by associated fields, for example:

```javascript
// Find the user objects whose associated posts have title of "post title"
userRepository.find({
  filter: {
    'posts.title': 'post title',
  },
});
```

Associated fields can also be nested:

```javascript
// Find the user objects whose associated posts have comments containing "keywords"
await userRepository.find({
  filter: {
    'posts.comments.content': {
      $like: '%keywords%',
    },
  },
});
```

#### Sort

Sort query results by the `sort` parameter.

```javascript
// SELECT * FROM users ORDER BY age
await userRepository.find({
  sort: 'age',
});

// SELECT * FROM users ORDER BY age DESC
await userRepository.find({
  sort: '-age',
});

// SELECT * FROM users ORDER BY age DESC, name ASC
await userRepository.find({
  sort: ['-age', 'name'],
});
```

Sort by the field of the associated object is also supported:

```javascript
await userRepository.find({
  sort: 'profile.createdAt',
});
```

### Create

#### Basic Create

Create new data objects via `Repository`.

```javascript
await userRepository.create({
  name: 'Mark',
  age: 18,
});
// INSERT INTO users (name, age) VALUES ('Mark', 18)

// Bulk creation
await userRepository.create([
  {
    name: 'Mark',
    age: 18,
  },
  {
    name: 'Alex',
    age: 20,
  },
]);
```

#### Create Association

Create associated objects at the same time of creating data. Like query, nested use of associated objects is also supported. For example:

```javascript
await userRepository.create({
  name: 'Mark',
  age: 18,
  posts: [
    {
      title: 'post title',
      content: 'post content',
      tags: [
        {
          name: 'tag1',
        },
        {
          name: 'tag2',
        },
      ],
    },
  ],
});
// When creating a user, create a post to associate with the user, and create tags to associate with the post
```

If the associated object is already in the database, you can pass its ID to create an association with it.

```javascript
const tag1 = await tagRepository.findOne({
  filter: {
    name: 'tag1',
  },
});

await userRepository.create({
  name: 'Mark',
  age: 18,
  posts: [
    {
      title: 'post title',
      content: 'post content',
      tags: [
        {
          id: tag1.id, // Create an association with an existing associated object
        },
        {
          name: 'tag2',
        },
      ],
    },
  ],
});
```

### Update

#### Basic Update

After getting the data object, you can modify the properties directly on the data object (`Model`), and then call the `save` method to save the changes.

```javascript
const user = await userRepository.findOne({
  filter: {
    name: 'Mark',
  },
});

user.age = 20;
await user.save();
```

The data object `Model` is inherited from Sequelize Model, refer to [Sequelize Model](https://sequelize.org/master/manual/model-basics.html) for the operations on `Model`.

Or update data via `Repository`:

```javascript
// Update the records that meet the filtering condition
await userRepository.update({
  filter: {
    name: 'Mark',
  },
  values: {
    age: 20,
  },
});
```

Control which fields to update by the `whitelist` and `blacklist` parameters, for example:

```javascript
await userRepository.update({
  filter: {
    name: 'Mark',
  },
  values: {
    age: 20,
    name: 'Alex',
  },
  whitelist: ['age'], // Only update the age field
});
```

#### Update Associated Field

Associated objects can be set while updating, for example:

```javascript
const tag1 = tagRepository.findOne({
  filter: {
    id: 1,
  },
});

await postRepository.update({
  filter: {
    id: 1,
  },
  values: {
    title: 'new post title',
    tags: [
      {
        id: tag1.id, // Associate with tag1
      },
      {
        name: 'tag2', // Create new tag and associate with it
      },
    ],
  },
});

await postRepository.update({
  filter: {
    id: 1,
  },
  values: {
    tags: null, // Disassociate post from tags
  },
});
```

### Delete

Call the `destroy()` method in `Repository` to perform the deletion operation. Filtering condition has to be specified to delete.

```javascript
await userRepository.destroy({
  filter: {
    status: 'blocked',
  },
});
```

## Constructor

It is usually not called directly by the developer, the instantiation is done mainly by specifying a corresponding repository type that is already registered in the parameter of `db.colletion()`. Repository type is registered through `db.registerRepositories()`.

**Signature**

- `constructor(collection: Collection)`

**Example**

```ts
import { Repository } from '@nocobase/database';

class MyRepository extends Repository {
  async myQuery(sql) {
    return this.database.sequelize.query(sql);
  }
}

db.registerRepositories({
  books: MyRepository,
});

db.collection({
  name: 'books',
  // here link to the registered repository
  repository: 'books',
});

await db.sync();

const books = db.getRepository('books') as MyRepository;
await books.myQuery('SELECT * FROM books;');
```

## Instance Members

### `database`

The database management instance where the context is located.

### `collection`

The corresponding data table management instance.

### `model`

The corresponding data model class.

## Instance Methods

### `find()`

Find datasets from the database with the specified filtering conditions and sorting, etc.

**Signature**

- `async find(options?: FindOptions): Promise<Model[]>`

**Type**

```typescript
type Filter = FilterWithOperator | FilterWithValue | FilterAnd | FilterOr;
type Appends = string[];
type Except = string[];
type Fields = string[];
type Sort = string[] | string;

interface SequelizeFindOptions {
  limit?: number;
  offset?: number;
}

interface FilterByTk {
  filterByTk?: TargetKey;
}

interface CommonFindOptions extends Transactionable {
  filter?: Filter;
  fields?: Fields;
  appends?: Appends;
  except?: Except;
  sort?: Sort;
}

type FindOptions = SequelizeFindOptions & CommonFindOptions & FilterByTk;
```

**Detailed Information**

#### `filter: Filter`

Query conditions for filtering data results. In the query parameters that passed in, `key` is the name of the field, `value` is the corresponding value. Operators can be used in conjunction with other filtering conditions.

```typescript
// Find records with name "foo" and age above 18
repository.find({
  filter: {
    name: 'foo',
    age: {
      $gt: 18,
    },
  },
});
```

Refer to [Operators](./operators.md) for more information.

#### `filterByTk: TargetKey`

Query data by `TargetKey`, this is shortcut for the `filter` parameter. The field of `TargetKey` can be [configured](./collection.md#filtertargetkey) in `Collection`, the default is `primaryKey`.

```typescript
// By default, find records with id 1
repository.find({
  filterByTk: 1,
});
```

#### `fields: string[]`

Query columns. It is used to control which data fields to output. With this parameter, only the specified fields will be returned.

#### `except: string[]`

Exclude columns. It is used to control which data fields to output. With this parameter, the specified fields will not be returned.

#### `appends: string[]`

Append columns. It is used to load associated data. With this parameter, the specified associated fields will be returned together.

#### `sort: string[] | string`

Specify the sorting method of the query results. The input parameter is the name of the field, by default is to sort in the ascending order (`asc`); a `-` symbol needs to be added before the field name to sort in the descending order (`desc`). For example, `['-id', 'name']` means to sort by `id desc, name asc`.

#### `limit: number`

Limit the number of results, same as `limit` in `SQL`.

#### `offset: number`

The offset of the query, same as `offset` in `SQL`.

**Example**

```ts
const posts = db.getRepository('posts');

const results = await posts.find({
  filter: {
    createdAt: {
      $gt: '2022-01-01T00:00:00.000Z',
    },
  },
  fields: ['title'],
  appends: ['user'],
});
```

### `findOne()`

Find a single piece of data from the database for specific conditions. Equivalent to `Model.findOne()` in Sequelize.

**Signature**

- `async findOne(options?: FindOneOptions): Promise<Model | null>`



**Example**

```ts
const posts = db.getRepository('posts');

const result = await posts.findOne({
  filterByTk: 1,
});
```

### `count()`

Query a certain amount of data from the database for specific conditions. Equivalent to `Model.count()` in Sequelize.

**Signature**

- `count(options?: CountOptions): Promise<number>`

**Type**

```typescript
interface CountOptions
  extends Omit<SequelizeCountOptions, 'distinct' | 'where' | 'include'>,
    Transactionable {
  filter?: Filter;
}
```

**Example**

```ts
const books = db.getRepository('books');

const count = await books.count({
  filter: {
    title: 'Three character classic',
  },
});
```

### `findAndCount()`

Find datasets from the database with the specified filtering conditions and return the number of results. Equivalent to `Model.findAndCountAll()` in Sequelize.

**Signature**

- `async findAndCount(options?: FindAndCountOptions): Promise<[Model[], number]>`

**Type**

```typescript
type FindAndCountOptions = Omit<
  SequelizeAndCountOptions,
  'where' | 'include' | 'order'
> &
  CommonFindOptions;
```

**Detailed Information**

The query parameters are the same as `find()`. An array is returned with the first element of the query results, and the second element of the total number of results.

### `create()`

Inserts a newly created data into the data table. Equivalent to `Model.create()` in Sequelize. When the data object to be created carries any associated field, the corresponding associated data record is created or updated along with it.

**Signature**

- `async create<M extends Model>(options: CreateOptions): Promise<M>`



**Example**

```ts
const posts = db.getRepository('posts');

const result = await posts.create({
  values: {
    title: 'NocoBase 1.0 Release Notes',
    tags: [
      // Update data when there is a primary key and value of the associated table
      { id: 1 },
      // Create data when there is no primary key and value
      { name: 'NocoBase' },
    ],
  },
});
```

### `createMany()`

Inserts multiple newly created data into the data table. This is equivalent to calling the `create()` method multiple times.

**Signature**

- `createMany(options: CreateManyOptions): Promise<Model[]>`

**Type**

```typescript
interface CreateManyOptions extends BulkCreateOptions {
  records: Values[];
}
```

**Detailed Information**

- `records`: An array of data objects to be created.
- `transaction`: Transaction object. If no transaction parameter is passed, the method will automatically create an internal transaction.

**Example**

```ts
const posts = db.getRepository('posts');

const results = await posts.createMany({
  records: [
    {
      title: 'NocoBase 1.0 Release Notes',
      tags: [
        // Update data when there is a primary key and value of the associated table
        { id: 1 },
        // Create data when there is no primary key and value
        { name: 'NocoBase' },
      ],
    },
    {
      title: 'NocoBase 1.1 Release Notes',
      tags: [{ id: 1 }],
    },
  ],
});
```

### `update()`

Update data in the data table. Equivalent to `Model.update()` in Sequelize. When the data object to be updated carries any associated field, the corresponding associated data record is created or updated along with it.

**Signature**

- `async update<M extends Model>(options: UpdateOptions): Promise<M>`



**Example**

```ts
const posts = db.getRepository('posts');

const result = await posts.update({
  filterByTk: 1,
  values: {
    title: 'NocoBase 1.0 Release Notes',
    tags: [
      // Update data when there is a primary key and value of the associated table
      { id: 1 },
      // Create data when there is no primary key and value
      { name: 'NocoBase' },
    ],
  },
});
```

### `destroy()`

Delete data from the data table. Equivalent to `Model.destroy()` in Sequelize.

**Signature**

- `async destroy(options?: TargetKey | TargetKey[] | DestoryOptions): Promise<number>`

**Type**

```typescript
interface DestroyOptions extends SequelizeDestroyOptions {
  filter?: Filter;
  filterByTk?: TargetKey | TargetKey[];
  truncate?: boolean;
  context?: any;
}
```

**Detailed Information**

- `filter`：Specify the filtering conditions of the records to be deleted. Refer to the [`find()`](#find) method for the detailed usage of the filter.
- `filterByTk`：Specify the filtering conditions by TargetKey.
- `truncate`: Whether to empty the table data, this parameter is valid if no `filter` or `filterByTk` parameter is passed.
- `transaction`: Transaction object. If no transaction parameter is passed, the method will automatically create an internal transaction.

---

## File: docs/en-US/api/database/shared.md

**Parameters**

| Parameter Name         | Type          | Default | Description                                           |
| ---------------------- | ------------- | ------- | ----------------------------------------------------- |
| `options.values`       | `M`           | `{}`    | The data object to be inserted                        |
| `options.whitelist?`   | `string[]`    | -       | Whitelist for the `values` field; only fields in the list will be stored |
| `options.blacklist?`   | `string[]`    | -       | Blacklist for the `values` field; fields in the list will not be stored |
| `options.transaction?` | `Transaction` | -       | Transaction                                            |

---

## File: docs/en-US/api/database/interfaces/base-interface.md

# BaseInterface

## Overview

BaseInterface is the foundational class for all Interface types. Users can extend this class to implement custom Interface logic.

```typescript
class CustomInterface extends BaseInterface {
  async toValue(value: string, ctx?: any): Promise<any> {
    // Custom toValue logic
  }

  toString(value: any, ctx?: any) {
    // Custom toString logic
  }
}
// Register Interface
db.interfaceManager.registerInterfaceType('customInterface', CustomInterface)
```

## Interfaces

### toValue(value: string, ctx?: any): Promise<any>

Converts an external string to the actual value of the interface, which can be directly passed to the Repository for write operations.

### toString(value: any, ctx?: any)

Converts the actual value of the interface to a string type, which can be used for exporting or displaying purposes.

---

## File: docs/en-US/api/database/relation-repository/belongs-to-many-repository.md

# BelongsToManyRepository

`BelongsToManyRepository` is the `Relation Repository` for handling `BelongsToMany` relationships.

Unlike other relationship types, the `BelongsToMany` type of relationship needs to be recorded through an intermediate table. The intermediate table can be created automatically or explicitly specified when defining association relationships in NocoBase.

## Class Methods

### `find()`

Find associated objects.

**Signature**

- `async find(options?: FindOptions): Promise<M[]>`

**Detailed Information**

Query parameters are the same as [`Repository.find()`](../repository.md#find).

### `findOne()`

Find associated objects, only to return one record.

**Signature**

- `async findOne(options?: FindOneOptions): Promise<M>`



### `count()`

Return the number of records matching the query criteria.

**Signature**

- `async count(options?: CountOptions)`

**Type**

```typescript
interface CountOptions
  extends Omit<SequelizeCountOptions, 'distinct' | 'where' | 'include'>,
    Transactionable {
  filter?: Filter;
}
```

### `findAndCount()`

Find datasets from the database with the specified filtering conditions and return the number of results.

**Signature**

- `async findAndCount(options?: FindAndCountOptions): Promise<[any[], number]>`

**Type**

```typescript
type FindAndCountOptions = CommonFindOptions;
```

### `create()`

Create associated objects.

**Signature**

- `async create(options?: CreateOptions): Promise<M>`



### `update()`

Update associated objects that match the conditions.

**Signature**

- `async update(options?: UpdateOptions): Promise<M>`



### `destroy()`

Delete associated objects.

**Signature**

- `async destroy(options?: TargetKey | TargetKey[] | DestroyOptions): Promise`



### `add()`

Add new associated objects.

**Signature**

- `async add(
options: TargetKey | TargetKey[] | PrimaryKeyWithThroughValues | PrimaryKeyWithThroughValues[] | AssociatedOptions
): Promise<void>`

**Type**

```typescript
type PrimaryKeyWithThroughValues = [TargetKey, Values];

interface AssociatedOptions extends Transactionable {
  tk?:
    | TargetKey
    | TargetKey[]
    | PrimaryKeyWithThroughValues
    | PrimaryKeyWithThroughValues[];
}
```

**Detailed Information**

Pass the `targetKey` of the associated object directly, or pass the `targetKey` along with the field values of the intermediate table.

**Example**

```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);

// Pass in the targetKey
PostTagRepository.add([t1.id, t2.id]);

// Pass in intermediate table fields
PostTagRepository.add([
  [t1.id, { tagged_at: '123' }],
  [t2.id, { tagged_at: '456' }],
]);
```

### `set()`

Set the associated objects.

**Signature**

- async set(
  options: TargetKey | TargetKey[] | PrimaryKeyWithThroughValues | PrimaryKeyWithThroughValues[] | AssociatedOptions,
  ): Promise<void>

**Detailed Information**

Parameters are the same as [add()](#add).

### `remove()`

Remove the association with the given objects.

**Signature**

- `async remove(options: TargetKey | TargetKey[] | AssociatedOptions)`

**Type**

```typescript
interface AssociatedOptions extends Transactionable {
  tk?: TargetKey | TargetKey[];
}
```

### `toggle()`

Toggle the associated object.

In some business scenarios, it is often needed to toggle the associated object. For example, user adds a product into collection, and the user cancels the collection and collect it again. Using the `toggle` method can quickly implement similar functions.

**Signature**

- `async toggle(options: TargetKey | { tk?: TargetKey; transaction?: Transaction }): Promise<void>`

**Detailed Information**

The `toggle` method automatically checks whether the associated object already exists, and removes it if it does, or adds it if it does not.

---

## File: docs/en-US/api/database/relation-repository/belongs-to-repository.md

## BelongsToRepository

The interface is the same as [HasOneRepository](./has-one-repository.md). `BelongsToRepository` is the `Repository` for handling `BelongsTo` relationships, and it provides some convenient methods to handle `BelongsTo` relationships.

---

## File: docs/en-US/api/database/relation-repository/has-many-repository.md

# HasManyRepository

`HasManyRepository` is the `Relation Repository` for handling `HasMany` relationships.

## Class Methods

### `find()`

Find associated objects.

**Signature**

- `async find(options?: FindOptions): Promise<M[]>`

**Detailed Information**

Query parameters are the same as [`Repository.find()`](../repository.md#find).

### `findOne()`

Find associated objects, only to return one record.

**Signature**

- `async findOne(options?: FindOneOptions): Promise<M>`



### `count()`

Return the number of records matching the query criteria.

**Signature**

- `async count(options?: CountOptions)`

**Type**

```typescript
interface CountOptions
  extends Omit<SequelizeCountOptions, 'distinct' | 'where' | 'include'>,
    Transactionable {
  filter?: Filter;
}
```

### `findAndCount()`

Find datasets from the database with the specified filtering conditions and return the number of results.

**Signature**

- `async findAndCount(options?: FindAndCountOptions): Promise<[any[], number]>`

**Type**

```typescript
type FindAndCountOptions = CommonFindOptions;
```

### `create()`

Create associated objects.

**Signature**

- `async create(options?: CreateOptions): Promise<M>`



### `update()`

Update associated objects that match the conditions.

**Signature**

- `async update(options?: UpdateOptions): Promise<M>`



### `destroy()`

Delete associated objects.

**Signature**

- `async destroy(options?: TK | DestroyOptions): Promise<M>`



### `add()`

Add association relationships between objects.

**Signature**

- `async add(options: TargetKey | TargetKey[] | AssociatedOptions)`

**Type**

```typescript
interface AssociatedOptions extends Transactionable {
  tk?: TargetKey | TargetKey[];
}
```

**Detailed Information**

- `tk` - The targetKey value of the associated object, either as a single value or an array.
  

### `remove()`

Remove the association with the given objects.

**Signature**

- `async remove(options: TargetKey | TargetKey[] | AssociatedOptions)`

**Detailed Information**

Same parameters as the [`add()`](#add) method.

### `set()`

Set the associated object of the current relationship.

**Signature**

- `async set(options: TargetKey | TargetKey[] | AssociatedOptions)`

**Detailed Information**

Same parameters as the [`add()`](#add) method.

---

## File: docs/en-US/api/database/relation-repository/has-one-repository.md

# HasOneRepository

## Overview

`HasOneRepository` is the associated repository of type `HasOne`.

```typescript
const User = db.collection({
  name: 'users',
  fields: [
    { type: 'hasOne', name: 'profile' },
    { type: 'string', name: 'name' },
  ],
});

const Profile = db.collection({
  name: 'profiles',
  fields: [{ type: 'string', name: 'avatar' }],
});

const user = await User.repository.create({
  values: { name: 'u1' },
});

// Get the associated repository
const userProfileRepository = User.repository
  .relation('profile')
  .of(user.get('id'));

// Or to initialize directly
new HasOneRepository(User, 'profile', user.get('id'));
```

## Class Methods

### `find()`

Find associated objects.

**Signature**

- `async find(options?: SingleRelationFindOption): Promise<Model<any> | null>`

**Type**

```typescript
interface SingleRelationFindOption extends Transactionable {
  fields?: Fields;
  except?: Except;
  appends?: Appends;
  filter?: Filter;
}
```

**Detailed Information**

Query parameters are the same as [`Repository.find()`](../repository.md#find).

**Example**

```typescript
const profile = await UserProfileRepository.find();
// Return null if the associated object does not exist
```

### `create()`

Create associated objects.

**Signature**

- `async create(options?: CreateOptions): Promise<Model>`



**Example**

```typescript
const profile = await UserProfileRepository.create({
  values: { avatar: 'avatar1' },
});

console.log(profile.toJSON());
/*
{
  id: 1,
  avatar: 'avatar1',
  userId: 1,
  updatedAt: 2022-09-24T13:59:40.025Z,
  createdAt: 2022-09-24T13:59:40.025Z
}
*/
```

### `update()`

Update associated objects.

**Signature**

- `async update(options: UpdateOptions): Promise<Model>`



**Example**

```typescript
const profile = await UserProfileRepository.update({
  values: { avatar: 'avatar2' },
});

profile.get('avatar'); // 'avatar2'
```

### `remove()`

Remove associated objects. Only to unassociate, not to delete the associated object.

**Signature**

- `async remove(options?: Transactionable): Promise<void>`

**Detailed Information**

- `transaction`: Transaction object. If no transaction parameter is passed, the method will automatically create an internal transaction.

**Example**

```typescript
await UserProfileRepository.remove();
(await UserProfileRepository.find()) == null; // true

(await Profile.repository.count()) === 1; // true
```

### `destroy()`

Delete associated objects.

**Signature**

- `async destroy(options?: Transactionable): Promise`

**Detailed Information**

- `transaction`: Transaction object. If no transaction parameter is passed, the method will automatically create an internal transaction.

**Example**

```typescript
await UserProfileRepository.destroy();
(await UserProfileRepository.find()) == null; // true
(await Profile.repository.count()) === 0; // true
```

### `set()`

Set associated objects.

**Signature**

- `async set(options: TargetKey | SetOption): Promise<void>`

**Type**

```typescript
interface SetOption extends Transactionable {
  tk?: TargetKey;
}
```

**Detailed Information**

- tk: Set the targetKey of the associated object.
- transaction: Transaction object. If no transaction parameter is passed, the method will automatically create an internal transaction.

**Example**

```typescript
const newProfile = await Profile.repository.create({
  values: { avatar: 'avatar2' },
});

await UserProfileRepository.set(newProfile.get('id'));

(await UserProfileRepository.find()).get('id') === newProfile.get('id'); // true
```

---

## File: docs/en-US/api/database/relation-repository/index.md

# RelationRepository

`RelationRepository` is a `Repository` object for relation types, which allows operations on associated data without loading the associations. Based on `RelationRepository`, each association type derives its corresponding implementation, which are:

- [`HasOneRepository`](#has-one-repository)
- `HasManyRepository`
- `BelongsToRepository`
- `BelongsToManyRepository`

## Constructor

**Signature**

- `constructor(sourceCollection: Collection, association: string, sourceKeyValue: string | number)`

**Parameters**

| Parameter Name     | Type               | Default Value | Description                                               |
| ------------------ | ------------------ | ------------- | --------------------------------------------------------- |
| `sourceCollection` | `Collection`       | -             | The Collection corresponding to the referencing relation in the association |
| `association`      | `string`           | -             | The name of the association                               |
| `sourceKeyValue`   | `string \| number` | -             | The key value corresponding to the referencing relation   |

## Base Class Properties

### `db: Database`

Database object

### `sourceCollection`

The Collection corresponding to the referencing relation in the association

### `targetCollection`

The Collection corresponding to the referenced relation in the association

### `association`

The association object in Sequelize corresponding to the current association

### `associationField`

The field in the Collection corresponding to the current association

### `sourceKeyValue`

The key value corresponding to the referencing relation

---

## File: docs/en-US/api/database/shared/create-options.md

**Type**

```typescript
type WhiteList = string[];
type BlackList = string[];
type AssociationKeysToBeUpdate = string[];

interface CreateOptions extends SequelizeCreateOptions {
  values?: Values;
  whitelist?: WhiteList;
  blacklist?: BlackList;
  updateAssociationValues?: AssociationKeysToBeUpdate;
  context?: any;
}
```

**Details**

- `values`: The data object of the record to be created.
- `whitelist`: Specifies which fields in the data object of the record to be created **can be written**. If this parameter is not passed, all fields are allowed to be written by default.
- `blacklist`: Specifies which fields in the data object of the record to be created **are not allowed to be written**. If this parameter is not passed, all fields are allowed to be written by default.
- `transaction`: The transaction object. If no transaction parameter is passed, the method will automatically create an internal transaction.

---

## File: docs/en-US/api/database/shared/destroy-options.md

**Type**

```typescript
interface DestroyOptions extends SequelizeDestroyOptions {
  filter?: Filter;
  filterByTk?: TargetKey | TargetKey[];
  truncate?: boolean;
  context?: any;
}
```

**Details**

- `filter`: Specifies the filtering conditions for the records to be deleted. For detailed usage of Filter, refer to the [`find()`](#find) method.
- `filterByTk`: Specifies the filtering conditions for the records to be deleted by TargetKey.
- `truncate`: Whether to truncate the table data, effective when no `filter` or `filterByTk` parameters are passed.
- `transaction`: Transaction object. If no transaction parameter is passed, the method will automatically create an internal transaction.

---

## File: docs/en-US/api/database/shared/find-one.md

**Type**

```typescript
type FindOneOptions = Omit<FindOptions, 'limit'>;
```

**Parameters**

Most parameters are the same as those in `find()`. The difference is that `findOne()` returns only a single piece of data, so the `limit` parameter is not needed, and the query is always set to `1`.

---

## File: docs/en-US/api/database/shared/find-options.md

[Empty file]

---

## File: docs/en-US/api/database/shared/transaction.md

- `transaction`: Transaction object. If no transaction parameter is passed, the method will automatically create an internal transaction.

---

## File: docs/en-US/api/database/shared/update-options.md

**Type**

```typescript
interface UpdateOptions extends Omit<SequelizeUpdateOptions, 'where'> {
  values: Values;
  filter?: Filter;
  filterByTk?: TargetKey;
  whitelist?: WhiteList;
  blacklist?: BlackList;
  updateAssociationValues?: AssociationKeysToBeUpdate;
  context?: any;
}
```

**Details**

- `values`: The data object of the records to be updated.
- `filter`: Specifies the filter conditions for the records to be updated. For detailed usage of Filter, refer to the [`find()`](#find) method.
- `filterByTk`: Specifies the filter conditions for the records to be updated by TargetKey.
- `whitelist`: A whitelist for the `values` fields. Only fields listed will be written.
- `blacklist`: A blacklist for the `values` fields. Fields listed will not be written.
- `transaction`: The transaction object. If no transaction parameter is passed, the method will automatically create an internal transaction.

At least one of `filterByTk` or `filter` must be provided.

---

## File: docs/en-US/api/field/markdown-vditor/index.md

# markdown

## Example

This is an embedded Markdown editor:

<MarkdownEditor />

---

## File: docs/en-US/api/handlebars-helpers/array.md

# Array

## {{after}}

Returns all of the items in an array after the specified index. Opposite of [before](#before).

**Params**

* `array` **{Array}**: Collection
* `n` **{Number}**: Starting index (number of items to exclude)
* `returns` **{Array}**: Array exluding `n` items.

**Example**

```handlebars
<!-- array: ['a', 'b', 'c'] -->
{{after array 1}}
<!-- results in: '["c"]' -->
```

## {{arrayify}}

Cast the given `value` to an array.

**Params**

* `value` **{any}**
* `returns` **{Array}**

**Example**

```handlebars
{{arrayify "foo"}}
<!-- results in: [ "foo" ] -->
```

## {{before}}

Return all of the items in the collection before the specified count. Opposite of [after](#after).

**Params**

* `array` **{Array}**
* `n` **{Number}**
* `returns` **{Array}**: Array excluding items after the given number.

**Example**

```handlebars
<!-- array: ['a', 'b', 'c'] -->
{{before array 2}}
<!-- results in: '["a", "b"]' -->
```

## {{eachIndex}}

**Params**

* `array` **{Array}**
* `options` **{Object}**
* `returns` **{String}**

**Example**

```handlebars
<!-- array: ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'] -->
{{#eachIndex array}}
  {{item}} is {{index}}
{{/eachIndex}}
```

## {{filter}}

Block helper that filters the given array and renders the block for values that evaluate to `true`, otherwise the inverse block is returned.

**Params**

* `array` **{Array}**
* `value` **{any}**
* `options` **{Object}**
* `returns` **{String}**

**Example**

```handlebars
<!-- array: ['a', 'b', 'c'] -->
{{#filter array "foo"}}AAA{{else}}BBB{{/filter}}
<!-- results in: 'BBB' -->
```

## {{first}}

Returns the first item, or first `n` items of an array.

**Params**

* `array` **{Array}**
* `n` **{Number}**: Number of items to return, starting at `0`.
* `returns` **{Array}**

**Example**

```handlebars
{{first "['a', 'b', 'c', 'd', 'e']" 2}}
<!-- results in: '["a", "b"]' -->
```

## {{forEach}}

Iterates over each item in an array and exposes the current item in the array as context to the inner block. In addition to the current array item, the helper exposes the following variables to the inner block:

* `index`
* `total`
* `isFirst`
* `isLast`
Also, `@index` is exposed as a private variable, and additional
private variables may be defined as hash arguments.

**Params**

* `array` **{Array}**
* `returns` **{String}**

**Example**

```handlebars
<!-- accounts = [
{'name': 'John', 'email': 'john@example.com'},
{'name': 'Malcolm', 'email': 'malcolm@example.com'},
{'name': 'David', 'email': 'david@example.com'}
] -->

{{#forEach accounts}}
  <a href="mailto:{{ email }}" title="Send an email to {{ name }}">
    {{ name }}
  </a>{{#unless isLast}}, {{/unless}}
{{/forEach}}
```

## {{inArray}}

Block helper that renders the block if an array has the given `value`. Optionally specify an inverse block to render when the array does not have the given value.

**Params**

* `array` **{Array}**
* `value` **{any}**
* `options` **{Object}**
* `returns` **{String}**

**Example**

```handlebars
<!-- array: ['a', 'b', 'c'] -->
{{#inArray array "d"}}
  foo
{{else}}
  bar
{{/inArray}}
<!-- results in: 'bar' -->
```

## {{isArray}}

Returns true if `value` is an es5 array.

**Params**

* `value` **{any}**: The value to test.
* `returns` **{Boolean}**

**Example**

```handlebars
{{isArray "abc"}}
<!-- results in: false -->

<!-- array: [1, 2, 3] -->
{{isArray array}}
<!-- results in: true -->
```

## {{itemAt}}

Returns the item from `array` at index `idx`.

**Params**

* `array` **{Array}**
* `idx` **{Number}**
* `returns` **{any}** `value`

**Example**

```handlebars
<!-- array: ['a', 'b', 'c'] -->
{{itemAt array 1}}
<!-- results in: 'b' -->
```

## {{join}}

Join all elements of array into a string, optionally using a given separator.

**Params**

* `array` **{Array}**
* `separator` **{String}**: The separator to use. Defaults to `,`.
* `returns` **{String}**

**Example**

```handlebars
<!-- array: ['a', 'b', 'c'] -->
{{join array}}
<!-- results in: 'a, b, c' -->

{{join array '-'}}
<!-- results in: 'a-b-c' -->
```

## {{equalsLength}}

Returns true if the the length of the given `value` is equal
to the given `length`. Can be used as a block or inline helper.

**Params**

* `value` **{Array|String}**
* `length` **{Number}**
* `options` **{Object}**
* `returns` **{String}**

## {{last}}

Returns the last item, or last `n` items of an array or string. Opposite of [first](#first).

**Params**

* `value` **{Array|String}**: Array or string.
* `n` **{Number}**: Number of items to return from the end of the array.
* `returns` **{Array}**

**Example**

```handlebars
<!-- var value = ['a', 'b', 'c', 'd', 'e'] -->

{{last value}}
<!-- results in: ['e'] -->

{{last value 2}}
<!-- results in: ['d', 'e'] -->

{{last value 3}}
<!-- results in: ['c', 'd', 'e'] -->
```

## {{length}}

Returns the length of the given string or array.

**Params**

* `value` **{Array|Object|String}**
* `returns` **{Number}**: The length of the value.

**Example**

```handlebars
{{length '["a", "b", "c"]'}}
<!-- results in: 3 -->

<!-- results in: myArray = ['a', 'b', 'c', 'd', 'e']; -->
{{length myArray}}
<!-- results in: 5 -->

<!-- results in: myObject = {'a': 'a', 'b': 'b'}; -->
{{length myObject}}
<!-- results in: 2 -->
```

## {{lengthEqual}}

Alias for [equalsLength](#equalsLength)

## {{map}}

Returns a new array, created by calling `function` on each element of the given `array`. For example,

**Params**

* `array` **{Array}**
* `fn` **{Function}**
* `returns` **{String}**

**Example**

```handlebars
<!-- array: ['a', 'b', 'c'], and "double" is a
fictitious function that duplicates letters -->
{{map array double}}
<!-- results in: '["aa", "bb", "cc"]' -->
```

## {{pluck}}

Map over the given object or array or objects and create an array of values from the given `prop`. Dot-notation may be used (as a string) to get nested properties.

**Params**

* `collection` **{Array|Object}**
* `prop` **{Function}**
* `returns` **{String}**

**Example**

```handlebars
// {{pluck items "data.title"}}
<!-- results in: '["aa", "bb", "cc"]' -->
```

## {{reverse}}

Reverse the elements in an array, or the characters in a string.

**Params**

* `value` **{Array|String}**
* `returns` **{Array|String}**: Returns the reversed string or array.

**Example**

```handlebars
<!-- value: 'abcd' -->
{{reverse value}}
<!-- results in: 'dcba' -->
<!-- value: ['a', 'b', 'c', 'd'] -->
{{reverse value}}
<!-- results in: ['d', 'c', 'b', 'a'] -->
```

## {{some}}

Block helper that returns the block if the callback returns true for some value in the given array.

**Params**

* `array` **{Array}**
* `iter` **{Function}**: Iteratee
* **{Options}**: Handlebars provided options object
* `returns` **{String}**

**Example**

```handlebars
<!-- array: [1, 'b', 3] -->
{{#some array isString}}
  Render me if the array has a string.
{{else}}
  Render me if it doesn't.
{{/some}}
<!-- results in: 'Render me if the array has a string.' -->
```

## {{sort}}

Sort the given `array`. If an array of objects is passed, you may optionally pass a `key` to sort on as the second argument. You may alternatively pass a sorting function as the second argument.

**Params**

* `array` **{Array}**: the array to sort.
* `key` **{String|Function}**: The object key to sort by, or sorting function.

**Example**

```handlebars
<!-- array: ['b', 'a', 'c'] -->
{{sort array}}
<!-- results in: '["a", "b", "c"]' -->
```

## {{sortBy}}

Sort an `array`. If an array of objects is passed, you may optionally pass a `key` to sort on as the second argument. You may alternatively pass a sorting function as the second argument.

**Params**

* `array` **{Array}**: the array to sort.
* `props` **{String|Function}**: One or more properties to sort by, or sorting functions to use.

**Example**

```handlebars
<!-- array: [{a: 'zzz'}, {a: 'aaa'}] -->
{{sortBy array "a"}}
<!-- results in: '[{"a":"aaa"}, {"a":"zzz"}]' -->
```

## {{withAfter}}

Use the items in the array _after_ the specified index as context inside a block. Opposite of [withBefore](#withBefore).

**Params**

* `array` **{Array}**
* `idx` **{Number}**
* `options` **{Object}**
* `returns` **{Array}**

**Example**

```handlebars
<!-- array: ['a', 'b', 'c', 'd', 'e'] -->
{{#withAfter array 3}}
  {{this}}
{{/withAfter}}
<!-- results in: "de" -->
```

## {{withBefore}}

Use the items in the array _before_ the specified index as context inside a block. Opposite of [withAfter](#withAfter).

**Params**

* `array` **{Array}**
* `idx` **{Number}**
* `options` **{Object}**
* `returns` **{Array}**

**Example**

```handlebars
<!-- array: ['a', 'b', 'c', 'd', 'e'] -->
{{#withBefore array 3}}
  {{this}}
{{/withBefore}}
<!-- results in: 'ab' -->
```

## {{withFirst}}

Use the first item in a collection inside a handlebars block expression. Opposite of [withLast](#withLast).

**Params**

* `array` **{Array}**
* `idx` **{Number}**
* `options` **{Object}**
* `returns` **{String}**

**Example**

```handlebars
<!-- array: ['a', 'b', 'c'] -->
{{#withFirst array}}
  {{this}}
{{/withFirst}}
<!-- results in: 'a' -->
```

## {{withGroup}}

Block helper that groups array elements by given group `size`.

**Params**

* `array` **{Array}**: The array to iterate over
* `size` **{Number}**: The desired length of each array "group"
* `options` **{Object}**: Handlebars options
* `returns` **{String}**

**Example**

```handlebars
<!-- array: ['a','b','c','d','e','f','g','h'] -->
{{#withGroup array 4}}
  {{#each this}}
    {{.}}
  {{each}}
  <br>
{{/withGroup}}
<!-- results in: -->
<!-- 'a','b','c','d'<br> -->
<!-- 'e','f','g','h'<br> -->
```

## {{withLast}}

Use the last item or `n` items in an array as context inside a block. Opposite of [withFirst](#withFirst).

**Params**

* `array` **{Array}**
* `idx` **{Number}**: The starting index.
* `options` **{Object}**
* `returns` **{String}**

**Example**

```handlebars
<!-- array: ['a', 'b', 'c'] -->
{{#withLast array}}
  {{this}}
{{/withLast}}
<!-- results in: 'c' -->
```

## {{withSort}}

Block helper that sorts a collection and exposes the sorted collection as context inside the block.

**Params**

* `array` **{Array}**
* `prop` **{String}**
* `options` **{Object}**: Specify `reverse="true"` to reverse the array.
* `returns` **{String}**

**Example**

```handlebars
<!-- array: ['b', 'a', 'c'] -->
{{#withSort array}}{{this}}{{/withSort}}
<!-- results in: 'abc' -->
```

## {{unique}}

Block helper that return an array with all duplicate values removed. Best used along with a [each](#each) helper.

**Params**

* `array` **{Array}**
* `options` **{Object}**
* `returns` **{Array}**

**Example**

```handlebars
<!-- array: ['a', 'a', 'c', 'b', 'e', 'e'] -->
{{#each (unique array)}}{{.}}{{/each}}
<!-- results in: 'acbe' -->
```

---

## File: docs/en-US/api/handlebars-helpers/comparison.md

# Comparison

## {{and}}

Helper that renders the block if **both** of the given values are truthy. If an inverse block is specified it will be rendered when falsy. Works as a block helper, inline helper or subexpression.

**Params**

* `a` **{any}**
* `b` **{any}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**

**Example**

```handlebars
<!-- {great: true, magnificent: true} -->
{{#and great magnificent}}A{{else}}B{{/and}}
<!-- results in: 'A' -->
```

## {{compare}}

Render a block when a comparison of the first and third
arguments returns true. The second argument is
the [arithemetic operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operators) to use. You may also
optionally specify an inverse block to render when falsy.

**Params**

* `a` **{}**
* `operator` **{}**: The operator to use. Operators must be enclosed in quotes: `">"`, `"="`, `"<="`, and so on.
* `b` **{}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**: Block, or if specified the inverse block is rendered if falsey.

## {{contains}}

Block helper that renders the block if `collection` has the given `value`, using strict equality (`===`) for comparison, otherwise the inverse block is rendered (if specified). If a `startIndex` is specified and is negative, it is used as the offset from the end of the collection.

**Params**

* `collection` **{Array|Object|String}**: The collection to iterate over.
* `value` **{any}**: The value to check for.
* `[startIndex=0]` **{Number}**: Optionally define the starting index.
* `options` **{Object}**: Handlebars provided options object.

**Example**

```handlebars
<!-- array = ['a', 'b', 'c'] -->
{{#contains array "d"}}
  This will not be rendered.
{{else}}
  This will be rendered.
{{/contains}}
```

## {{default}}

Returns the first value that is not undefined, otherwise the "default" value is returned.

**Params**

* `value` **{any}**
* `defaultValue` **{any}**
* `returns` **{String}**

## {{eq}}

Block helper that renders a block if `a` is **equal to** `b`.
If an inverse block is specified it will be rendered when falsy.
You may optionally use the `compare=""` hash argument for the
second value.

**Params**

* `a` **{String}**
* `b` **{String}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**: Block, or inverse block if specified and falsey.

## {{gt}}

Block helper that renders a block if `a` is **greater than** `b`.

If an inverse block is specified it will be rendered when falsy.
You may optionally use the `compare=""` hash argument for the
second value.

**Params**

* `a` **{String}**
* `b` **{String}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**: Block, or inverse block if specified and falsey.

## {{gte}}

Block helper that renders a block if `a` is **greater than or equal to** `b`.

If an inverse block is specified it will be rendered when falsy.
You may optionally use the `compare=""` hash argument for the
second value.

**Params**

* `a` **{String}**
* `b` **{String}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**: Block, or inverse block if specified and falsey.

## {{has}}

Block helper that renders a block if `value` has `pattern`.
If an inverse block is specified it will be rendered when falsy.

**Params**

* `val` **{any}**: The value to check.
* `pattern` **{any}**: The pattern to check for.
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**

## {{isEmpty}}

Inline, subexpression, or block helper that returns true (or the block) if the given collection is empty, or false (or the inverse block, if supplied) if the colleciton is not empty.

**Params**

* `collection` **{Object}**
* `options` **{Object}**
* `returns` **{String}**

**Example**

```handlebars
<!-- array: [] -->
{{#isEmpty array}}AAA{{else}}BBB{{/isEmpty}}
<!-- results in: 'AAA' -->

<!-- array: [] -->
{{isEmpty array}}
<!-- results in: true -->
```

## {{isFalsey}}

Returns true if the given `value` is falsey. Uses the [falsey](https://github.com/jonschlinkert/falsey)
library for comparisons. Please see that library for more information
or to report bugs with this helper.

**Params**

* `val` **{any}**
* `options` **{Options}**
* `returns` **{Boolean}**

## {{isTruthy}}

Returns true if the given `value` is truthy. Uses the [falsey](https://github.com/jonschlinkert/falsey)
library for comparisons. Please see that library for more information
or to report bugs with this helper.

**Params**

* `val` **{any}**
* `options` **{Options}**
* `returns` **{Boolean}**

## {{ifEven}}

Return true if the given value is an even number.

**Params**

* `number` **{Number}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**: Block, or inverse block if specified and falsey.

**Example**

```handlebars
{{#ifEven value}}
  render A
{{else}}
  render B
{{/ifEven}}
```

## {{ifNth}}

Conditionally renders a block if the remainder is zero when
`a` operand is divided by `b`. If an inverse block is specified
it will be rendered when the remainder is **not zero**.

**Params**

* **{}**: {Number}
* **{}**: {Number}
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**: Block, or inverse block if specified and falsey.

## {{ifOdd}}

Block helper that renders a block if `value` is **an odd number**. If an inverse block is specified it will be rendered when falsy.

**Params**

* `value` **{Object}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**: Block, or inverse block if specified and falsey.

**Example**

```handlebars
{{#ifOdd value}}
  render A
{{else}}
  render B
{{/ifOdd}}
```

## {{is}}

Block helper that renders a block if `a` is **equal to** `b`.
If an inverse block is specified it will be rendered when falsy.
Similar to [eq](#eq) but does not do strict equality.

**Params**

* `a` **{any}**
* `b` **{any}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**

## {{isnt}}

Block helper that renders a block if `a` is **not equal to** `b`.
If an inverse block is specified it will be rendered when falsy.
Similar to [unlessEq](#unlesseq) but does not use strict equality for
comparisons.

**Params**

* `a` **{String}**
* `b` **{String}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**

## {{lt}}

Block helper that renders a block if `a` is **less than** `b`.

If an inverse block is specified it will be rendered when falsy.
You may optionally use the `compare=""` hash argument for the
second value.

**Params**

* `context` **{Object}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**: Block, or inverse block if specified and falsey.

## {{lte}}

Block helper that renders a block if `a` is **less than or equal to** `b`.

If an inverse block is specified it will be rendered when falsy.
You may optionally use the `compare=""` hash argument for the
second value.

**Params**

* `a` **{Sring}**
* `b` **{Sring}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**: Block, or inverse block if specified and falsey.

## {{neither}}

Block helper that renders a block if **neither of** the given values
are truthy. If an inverse block is specified it will be rendered
when falsy.

**Params**

* `a` **{any}**
* `b` **{any}**
* `options` **{}**: Handlebars options object
* `returns` **{String}**: Block, or inverse block if specified and falsey.

## {{not}}

Returns true if `val` is falsey. Works as a block or inline helper.

**Params**

* `val` **{String}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**

## {{or}}

Block helper that renders a block if **any of** the given values is truthy. If an inverse block is specified it will be rendered when falsy.

**Params**

* `arguments` **{...any}**: Variable number of arguments
* `options` **{Object}**: Handlebars options object
* `returns` **{String}**: Block, or inverse block if specified and falsey.

**Example**

```handlebars
{{#or a b c}}
  If any value is true this will be rendered.
{{/or}}
```

## {{unlessEq}}

Block helper that always renders the inverse block **unless `a` is
is equal to `b`**.

**Params**

* `a` **{String}**
* `b` **{String}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**: Inverse block by default, or block if falsey.

## {{unlessGt}}

Block helper that always renders the inverse block **unless `a` is
is greater than `b`**.

**Params**

* `a` **{Object}**: The default value
* `b` **{Object}**: The value to compare
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**: Inverse block by default, or block if falsey.

## {{unlessLt}}

Block helper that always renders the inverse block **unless `a` is
is less than `b`**.

**Params**

* `a` **{Object}**: The default value
* `b` **{Object}**: The value to compare
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**: Block, or inverse block if specified and falsey.

## {{unlessGteq}}

Block helper that always renders the inverse block **unless `a` is
is greater than or equal to `b`**.

**Params**

* `a` **{any}**
* `b` **{any}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**: Block, or inverse block if specified and falsey.

## {{unlessLteq}}

Block helper that always renders the inverse block **unless `a` is
is less than or equal to `b`**.

**Params**

* `a` **{any}**
* `b` **{any}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**: Block, or inverse block if specified and falsey.

---

## File: docs/en-US/api/handlebars-helpers/core.md

# Built-in Helpers

https://handlebarsjs.com/guide/builtin-helpers.html

## {{if}}

Renders a block if the given condition is truthy.

**Params**

- `condition` **{Any}**: The condition to evaluate.

**Returns**: The content inside the block if the condition is truthy, otherwise returns nothing.

**Example**

```handlebars
{{#if condition}}
  This will be displayed if the condition is true.
{{/if}}
```

## {{unless}}

Renders a block if the given condition is falsy. This is the opposite of `if`.

**Params**

- `condition` **{Any}**: The condition to evaluate.

**Returns**: The content inside the block if the condition is falsy, otherwise returns nothing.

**Example**

```handlebars
{{#unless condition}}
  This will be displayed if the condition is false.
{{/unless}}
```

---

## {{each}}

Iterates over an array or object and renders a block for each item.

**Params**

- `collection` **{Array|Object}**: The array or object to iterate over.

**Returns**: Renders the block for each item in the collection.

**Example**

```handlebars
{{#each items}}
  <li>{{this}}</li>
{{/each}}
```

## {{with}}

Renders a block with a given context. It allows you to specify a context for the block, simplifying access to deeply nested properties.

**Params**

- `context` **{Any}**: The context to use within the block.

**Returns**: Renders the block with the provided context.

**Example**

```handlebars
{{#with person}}
  <p>Name: {{name}}</p>
  <p>Age: {{age}}</p>
{{/with}}
```

## {{lookup}}

Looks up the value of a specified key in an object. This helper is useful for accessing dynamic keys.

**Params**

- `context` **{Object}**: The object to look up the key from.
- `key` **{String|Number}**: The key to look up.

**Returns**: The value of the specified key in the object.

**Example**

```handlebars
{{lookup person "name"}}
<!-- If person is { name: "Alice", age: 30 }, it results in: "Alice" -->
```

---

## File: docs/en-US/api/handlebars-helpers/date.md

# Date

## {{dateFormat}}

The "dateFormat" helper in Handlebars is used to format a date using the day.js library. It takes two required arguments and an optional third argument for the timezone.

**Params**

* `datetime` **{String}**
* `format` **{String}**
* `timezone` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{dateFormat now "YYYY-MM-DD HH:mm:ss"}}
{{dateFormat now "YYYY-MM-DD HH:mm:ss" "Asia/Tokyo"}}
{{dateFormat now "YYYY-MM-DD HH:mm:ss" "UTC"}}
```

---

## File: docs/en-US/api/handlebars-helpers/html.md

# HTML

## {{qrcode}}

---

## File: docs/en-US/api/handlebars-helpers/i18n.md

# I18n

## {{t}}

**Params**

* `key` **{String}**
* `ns` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{t "Today"}}
{{t "Permissions" "@nocobase/plugin-acl"}}
```

---

## File: docs/en-US/api/handlebars-helpers/index.md

# Handlebars Helpers

| Category       | Description                         |
|-------------|-------------------------------------|
| [Core](./core.md)      | Built-in helpers        |
| [Array](./array.md)       | Operations and methods related to arrays       |
| [Comparison](./comparison.md) | Comparison operators and related methods       |
| [Date](./date.md)        | Operations and methods related to date and time handling |
| [HTML](./html.md)        | Content related to HTML documents and elements  |
| [I18n](./i18n.md)        | Support for internationalization and multilingual handling |
| [Math](./math.md)        | Mathematical functions and calculations       |
| [Number](./number.md)    | Content related to number handling and formatting |
| [Object](./object.md)    | Methods related to object operations and properties |
| [Path](./path.md)        | Path operations and content related to the file system |
| [Regex](./regex.md)      | Regular expressions and their usage            |
| [String](./string.md)    | Methods related to string manipulation and operations |
| [URL](./url.md)          | Content related to URL parsing and construction  |

---

## File: docs/en-US/api/handlebars-helpers/math.md

# Math

## {{abs}}

Return the magnitude of `a`.

**Params**

* `a` **{Number}**
* `returns` **{Number}**

## {{add}}

Return the sum of `a` plus `b`.

**Params**

* `a` **{Number}**
* `b` **{Number}**
* `returns` **{Number}**

## {{avg}}

Returns the average of all numbers in the given array.

**Params**

* `array` **{Array}**: Array of numbers to add up.
* `returns` **{Number}**

**Example**

```handlebars
{{avg "[1, 2, 3, 4, 5]"}}
<!-- results in: '3' -->
```

## {{ceil}}

Get the `Math.ceil()` of the given value.

**Params**

* `value` **{Number}**
* `returns` **{Number}**

## {{divide}}

Divide `a` by `b`

**Params**

* `a` **{Number}**: numerator
* `b` **{Number}**: denominator

## {{floor}}

Get the `Math.floor()` of the given value.

**Params**

* `value` **{Number}**
* `returns` **{Number}**

## {{minus}}

Return the difference of `a` minus `b`.

**Params**

* `a` **{Number}**
* `b` **{Number}**

## {{modulo}}

Get the remainder of a division operation.

**Params**

* `a` **{Number}**
* `b` **{Number}**
* `returns` **{Number}**

## {{multiply}}

Return the product of `a` times `b`.

**Params**

* `a` **{Number}**: factor
* `b` **{Number}**: multiplier
* `returns` **{Number}**

## {{plus}}

Add `a` by `b`.

**Params**

* `a` **{Number}**: factor
* `b` **{Number}**: multiplier

## {{random}}

Generate a random number between two values

**Params**

* `min` **{Number}**
* `max` **{Number}**
* `returns` **{String}**

## {{remainder}}

Get the remainder when `a` is divided by `b`.

**Params**

* `a` **{Number}**: a
* `b` **{Number}**: b

## {{round}}

Round the given number.

**Params**

* `number` **{Number}**
* `returns` **{Number}**

## {{subtract}}

Return the product of `a` minus `b`.

**Params**

* `a` **{Number}**
* `b` **{Number}**
* `returns` **{Number}**

## {{sum}}

Returns the sum of all numbers in the given array.

**Params**

* `array` **{Array}**: Array of numbers to add up.
* `returns` **{Number}**

**Example**

```handlebars
{{sum "[1, 2, 3, 4, 5]"}}
<!-- results in: '15' -->
```

## {{times}}

Multiply number `a` by number `b`.

**Params**

* `a` **{Number}**: factor
* `b` **{Number}**: multiplier
* `returns` **{Number}**

---

## File: docs/en-US/api/handlebars-helpers/number.md

# Number

## {{bytes}}

Format a number to it's equivalent in bytes. If a string is passed, it's length will be formatted and returned.

**Examples:**

* `'foo' => 3 B`
* `13661855 => 13.66 MB`
* `825399 => 825.39 kB`
* `1396 => 1.4 kB`

**Params**

* `number` **{Number|String}**
* `returns` **{String}**

## {{addCommas}}

Add commas to numbers

**Params**

* `num` **{Number}**
* `returns` **{Number}**

## {{phoneNumber}}

Convert a string or number to a formatted phone number.

**Params**

* `num` **{Number|String}**: The phone number to format, e.g. `8005551212`
* `returns` **{Number}**: Formatted phone number: `(800) 555-1212`

## {{toAbbr}}

Abbreviate numbers to the given number of `precision`. This is for
general numbers, not size in bytes.

**Params**

* `number` **{Number}**
* `precision` **{Number}**
* `returns` **{String}**

## {{toExponential}}

Returns a string representing the given number in exponential notation.

**Params**

* `number` **{Number}**
* `fractionDigits` **{Number}**: Optional. An integer specifying the number of digits to use after the decimal point. Defaults to as many digits as necessary to specify the number.
* `returns` **{Number}**

**Example**

```handlebars
{{toExponential number digits}};
```

## {{toFixed}}

Formats the given number using fixed-point notation.

**Params**

* `number` **{Number}**
* `digits` **{Number}**: (Optional) The number of digits to appear after the decimal point; this may be a value between 0 and 20. If this argument is omitted, it is treated as 0.
* `returns` **{String}**: A string representing the given number using fixed-point notation.

**Example**

```handlebars
{{toFixed "1.1234" 2}}
//=> '1.12'
```

## {{toFloat}}

**Params**

* `number` **{Number}**
* `returns` **{Number}**

## {{toInt}}

**Params**

* `number` **{Number}**
* `returns` **{Number}**

## {{toPrecision}}

Returns a string representing the `Number` object to the specified precision.

**Params**

* `number` **{Number}**
* `precision` **{Number}**: (Optional) An integer specifying the number of significant digits. If precison is not between 1 and 100 (inclusive), it will be coerced to `0`.
* `returns` **{String}**: A string representing a Number object in fixed-point or exponential notation rounded to precision significant digits.

**Example**

```handlebars
{{toPrecision "1.1234" 2}}
//=> '1.1'
```

---

## File: docs/en-US/api/handlebars-helpers/object.md

# Object

## {{extend}}

Extend the context with the properties of other objects.
A shallow merge is performed to avoid mutating the context.

**Params**

* `objects` **{Object}**: One or more objects to extend.
* `returns` **{Object}**

## {{forIn}}

Block helper that iterates over the properties of
an object, exposing each key and value on the context.

**Params**

* `context` **{Object}**
* `options` **{Object}**
* `returns` **{String}**

## {{forOwn}}

Block helper that iterates over the **own** properties of
an object, exposing each key and value on the context.

**Params**

* `obj` **{Object}**: The object to iterate over.
* `options` **{Object}**
* `returns` **{String}**

## {{toPath}}

Take arguments and, if they are string or number, convert them to a dot-delineated object property path.

**Params**

* `prop` **{String|Number}**: The property segments to assemble (can be multiple).
* `returns` **{String}**

## {{get}}

Use property paths (`a.b.c`) to get a value or nested value from
the context. Works as a regular helper or block helper.

**Params**

* `prop` **{String}**: The property to get, optionally using dot notation for nested properties.
* `context` **{Object}**: The context object
* `options` **{Object}**: The handlebars options object, if used as a block helper.
* `returns` **{String}**

## {{getObject}}

Use property paths (`a.b.c`) to get an object from
the context. Differs from the `get` helper in that this
helper will return the actual object, including the
given property key. Also, this helper does not work as a
block helper.

**Params**

* `prop` **{String}**: The property to get, optionally using dot notation for nested properties.
* `context` **{Object}**: The context object
* `returns` **{String}**

## {{hasOwn}}

Return true if `key` is an own, enumerable property of the given `context` object.

**Params**

* `key` **{String}**
* `context` **{Object}**: The context object.
* `returns` **{Boolean}**

**Example**

```handlebars
{{hasOwn context key}}
```

## {{isObject}}

Return true if `value` is an object.

**Params**

* `value` **{String}**
* `returns` **{Boolean}**

**Example**

```handlebars
{{isObject "foo"}}
//=> false
```

## {{JSONparse}}

Parses the given string using `JSON.parse`.

**Params**

* `string` **{String}**: The string to parse

**Example**

```handlebars
<!-- string: '{"foo": "bar"}' -->
{{JSONparse string}}
<!-- results in: { foo: 'bar' } -->
```

## {{JSONstringify}}

Stringify an object using `JSON.stringify`.

**Params**

* `obj` **{Object}**: Object to stringify
* `returns` **{String}**

**Example**

```handlebars
<!-- object: { foo: 'bar' } -->
{{JSONstringify object}}
<!-- results in: '{"foo": "bar"}' -->
```

## {{merge}}

Deeply merge the properties of the given `objects` with the
context object.

**Params**

* `object` **{Object}**: The target object. Pass an empty object to shallow clone.
* `objects` **{Object}**
* `returns` **{Object}**

## {{pick}}

Pick properties from the context object.

**Params**

* `properties` **{Array|String}**: One or more properties to pick.
* `context` **{Object}**
* `options` **{Object}**: Handlebars options object.
* `returns` **{Object}**: Returns an object with the picked values. If used as a block helper, the values are passed as context to the inner block. If no values are found, the context is passed to the inverse block.

---

## File: docs/en-US/api/handlebars-helpers/path.md

# Path

## {{absolute}}

Get the directory path segment from the given `filepath`.

**Params**

* `ext` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{absolute "docs/toc.md"}}
<!-- results in: 'docs' -->
```

## {{dirname}}

Get the directory path segment from the given `filepath`.

**Params**

* `ext` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{dirname "docs/toc.md"}}
<!-- results in: 'docs' -->
```

## {{relative}}

Get the relative filepath from `a` to `b`.

**Params**

* `a` **{String}**
* `b` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{relative a b}}
```

## {{basename}}

Get the file extension from the given `filepath`.

**Params**

* `ext` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{basename "docs/toc.md"}}
<!-- results in: 'toc.md' -->
```

## {{stem}}

Get the "stem" from the given `filepath`.

**Params**

* `filepath` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{stem "docs/toc.md"}}
<!-- results in: 'toc' -->
```

## {{extname}}

Get the file extension from the given `filepath`.

**Params**

* `filepath` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{extname "docs/toc.md"}}
<!-- results in: '.md' -->
```

## {{resolve}}

Resolve an absolute path from the given `filepath`.

**Params**

* `filepath` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{resolve "docs/toc.md"}}
<!-- results in: '/User/dev/docs/toc.md' -->
```

## {{segments}}

Get specific (joined) segments of a file path by passing a range of array indices.

**Params**

* `filepath` **{String}**: The file path to split into segments.
* `returns` **{String}**: Returns a single, joined file path.

**Example**

```handlebars
{{segments "a/b/c/d" "2" "3"}}
<!-- results in: 'c/d' -->

{{segments "a/b/c/d" "1" "3"}}
<!-- results in: 'b/c/d' -->

{{segments "a/b/c/d" "1" "2"}}
<!-- results in: 'b/c' -->
```

---

## File: docs/en-US/api/handlebars-helpers/regex.md

# Regex

## {{toRegex}}

Convert the given string to a regular expression.

**Params**

* `str` **{String}**
* `returns` **{RegExp}**

**Example**

```handlebars
{{toRegex "foo"}}
<!-- results in: /foo/ -->
```

## {{test}}

Returns true if the given `str` matches the given regex. A regex can be passed on the context, or using the [toRegex](#toregex) helper as a subexpression.

**Params**

* `str` **{String}**
* `returns` **{RegExp}**

**Example**

```handlebars
{{test "bar" (toRegex "foo")}}
<!-- results in: false -->
{{test "foobar" (toRegex "foo")}}
<!-- results in: true -->
{{test "foobar" (toRegex "^foo$")}}
<!-- results in: false -->
```

---

## File: docs/en-US/api/handlebars-helpers/string.md

# String

## {{append}}

Append the specified `suffix` to the given string.

**Params**

* `str` **{String}**
* `suffix` **{String}**
* `returns` **{String}**

**Example**

```handlebars
<!-- given that "item.stem" is "foo" -->
{{append item.stem ".html"}}
<!-- results in:  'foo.html' -->
```

## {{camelcase}}

camelCase the characters in the given `string`.

**Params**

* `string` **{String}**: The string to camelcase.
* `returns` **{String}**

**Example**

```handlebars
{{camelcase "foo bar baz"}};
<!-- results in:  'fooBarBaz' -->
```

## {{capitalize}}

Capitalize the first word in a sentence.

**Params**

* `str` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{capitalize "foo bar baz"}}
<!-- results in:  "Foo bar baz" -->
```

## {{capitalizeAll}}

Capitalize all words in a string.

**Params**

* `str` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{capitalizeAll "foo bar baz"}}
<!-- results in:  "Foo Bar Baz" -->
```

## {{center}}

Center a string using non-breaking spaces

**Params**

* `str` **{String}**
* `spaces` **{String}**
* `returns` **{String}**

## {{chop}}

Like trim, but removes both extraneous whitespace **and non-word characters** from the beginning and end of a string.

**Params**

* `string` **{String}**: The string to chop.
* `returns` **{String}**

**Example**

```handlebars
{{chop "_ABC_"}}
<!-- results in:  'ABC' -->

{{chop "-ABC-"}}
<!-- results in:  'ABC' -->

{{chop " ABC "}}
<!-- results in:  'ABC' -->
```

## {{dashcase}}

dash-case the characters in `string`. Replaces non-word characters and periods with hyphens.

**Params**

* `string` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{dashcase "a-b-c d_e"}}
<!-- results in:  'a-b-c-d-e' -->
```

## {{dotcase}}

dot.case the characters in `string`.

**Params**

* `string` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{dotcase "a-b-c d_e"}}
<!-- results in:  'a.b.c.d.e' -->
```

## {{downcase}}

Lowercase all of the characters in the given string. Alias for [lowercase](#lowercase).

**Params**

* `string` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{downcase "aBcDeF"}}
<!-- results in:  'abcdef' -->
```

## {{ellipsis}}

Truncates a string to the specified `length`, and appends it with an elipsis, `…`.

**Params**

* `str` **{String}**
* `length` **{Number}**: The desired length of the returned string.
* `returns` **{String}**: The truncated string.

**Example**

```handlebars
{{ellipsis (sanitize "<span>foo bar baz</span>"), 7}}
<!-- results in:  'foo bar…' -->
{{ellipsis "foo bar baz", 7}}
<!-- results in:  'foo bar…' -->
```

## {{hyphenate}}

Replace spaces in a string with hyphens.

**Params**

* `str` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{hyphenate "foo bar baz qux"}}
<!-- results in:  "foo-bar-baz-qux" -->
```

## {{isString}}

Return true if `value` is a string.

**Params**

* `value` **{String}**
* `returns` **{Boolean}**

**Example**

```handlebars
{{isString "foo"}}
<!-- results in:  'true' -->
```

## {{lowercase}}

Lowercase all characters in the given string.

**Params**

* `str` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{lowercase "Foo BAR baZ"}}
<!-- results in:  'foo bar baz' -->
```

## {{occurrences}}

Return the number of occurrences of `substring` within the given `string`.

**Params**

* `str` **{String}**
* `substring` **{String}**
* `returns` **{Number}**: Number of occurrences

**Example**

```handlebars
{{occurrences "foo bar foo bar baz" "foo"}}
<!-- results in:  2 -->
```

## {{pascalcase}}

PascalCase the characters in `string`.

**Params**

* `string` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{pascalcase "foo bar baz"}}
<!-- results in:  'FooBarBaz' -->
```

## {{pathcase}}

path/case the characters in `string`.

**Params**

* `string` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{pathcase "a-b-c d_e"}}
<!-- results in:  'a/b/c/d/e' -->
```

## {{plusify}}

Replace spaces in the given string with pluses.

**Params**

* `str` **{String}**: The input string
* `returns` **{String}**: Input string with spaces replaced by plus signs

**Example**

```handlebars
{{plusify "foo bar baz"}}
<!-- results in:  'foo+bar+baz' -->
```

## {{prepend}}

Prepends the given `string` with the specified `prefix`.

**Params**

* `str` **{String}**
* `prefix` **{String}**
* `returns` **{String}**

**Example**

```handlebars
<!-- given that "val" is "bar" -->
{{prepend val "foo-"}}
<!-- results in:  'foo-bar' -->
```

## {{raw}}

Render a block without processing mustache templates inside the block.

**Params**

* `options` **{Object}**
* `returns` **{String}**

**Example**

```handlebars
{{{{#raw}}}}
{{foo}}
{{{{/raw}}}}
<!-- results in:  '{{foo}}' -->
```

## {{remove}}

Remove all occurrences of `substring` from the given `str`.

**Params**

* `str` **{String}**
* `substring` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{remove "a b a b a b" "a "}}
<!-- results in:  'b b b' -->
```

## {{removeFirst}}

Remove the first occurrence of `substring` from the given `str`.

**Params**

* `str` **{String}**
* `substring` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{remove "a b a b a b" "a"}}
<!-- results in:  ' b a b a b' -->
```

## {{replace}}

Replace all occurrences of substring `a` with substring `b`.

**Params**

* `str` **{String}**
* `a` **{String}**
* `b` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{replace "a b a b a b" "a" "z"}}
<!-- results in:  'z b z b z b' -->
```

## {{replaceFirst}}

Replace the first occurrence of substring `a` with substring `b`.

**Params**

* `str` **{String}**
* `a` **{String}**
* `b` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{replace "a b a b a b" "a" "z"}}
<!-- results in:  'z b a b a b' -->
```

## {{reverse}}

Reverse a string.

**Params**

* `str` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{reverse "abcde"}}
<!-- results in:  'edcba' -->
```

## {{sentence}}

Sentence case the given string

**Params**

* `str` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{sentence "hello world. goodbye world."}}
<!-- results in:  'Hello world. Goodbye world.' -->
```

## {{snakecase}}

snake_case the characters in the given `string`.

**Params**

* `string` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{snakecase "a-b-c d_e"}}
<!-- results in:  'a_b_c_d_e' -->
```

## {{split}}

Split `string` by the given `character`.

**Params**

* `string` **{String}**: The string to split.
* `returns` **{String}** `character`: Default is an empty string.

**Example**

```handlebars
{{split "a,b,c" ","}}
<!-- results in:  ['a', 'b', 'c'] -->
```

## {{startsWith}}

Tests whether a string begins with the given prefix.

**Params**

* `prefix` **{String}**
* `testString` **{String}**
* `options` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{#startsWith "Goodbye" "Hello, world!"}}
  Whoops
{{else}}
  Bro, do you even hello world?
{{/startsWith}}
```

## {{titleize}}

Title case the given string.

**Params**

* `str` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{titleize "this is title case"}}
<!-- results in:  'This Is Title Case' -->
```

## {{trim}}

Removes extraneous whitespace from the beginning and end of a string.

**Params**

* `string` **{String}**: The string to trim.
* `returns` **{String}**

**Example**

```handlebars
{{trim " ABC "}}
<!-- results in:  'ABC' -->
```

## {{trimLeft}}

Removes extraneous whitespace from the beginning of a string.

**Params**

* `string` **{String}**: The string to trim.
* `returns` **{String}**

**Example**

```handlebars
{{trim " ABC "}}
<!-- results in:  'ABC ' -->
```

## {{trimRight}}

Removes extraneous whitespace from the end of a string.

**Params**

* `string` **{String}**: The string to trim.
* `returns` **{String}**

**Example**

```handlebars
{{trimRight " ABC "}}
<!-- results in:  ' ABC' -->
```

## {{truncate}}

Truncate a string to the specified `length`. Also see [ellipsis](#ellipsis).

**Params**

* `str` **{String}**
* `limit` **{Number}**: The desired length of the returned string.
* `suffix` **{String}**: Optionally supply a string to use as a suffix to denote when the string has been truncated. Otherwise an ellipsis (`…`) will be used.
* `returns` **{String}**: The truncated string.

**Example**

```handlebars
truncate("foo bar baz", 7);
<!-- results in:  'foo bar' -->
truncate(sanitize("<span>foo bar baz</span>", 7));
<!-- results in:  'foo bar' -->
```

## {{truncateWords}}

Truncate a string to have the specified number of words. Also see [truncate](#truncate).

**Params**

* `str` **{String}**
* `limit` **{Number}**: The desired length of the returned string.
* `suffix` **{String}**: Optionally supply a string to use as a suffix to denote when the string has been truncated.
* `returns` **{String}**: The truncated string.

**Example**

```handlebars
truncateWords("foo bar baz", 1);
<!-- results in:  'foo…' -->
truncateWords("foo bar baz", 2);
<!-- results in:  'foo bar…' -->
truncateWords("foo bar baz", 3);
<!-- results in:  'foo bar baz' -->
```

## {{upcase}}

Uppercase all of the characters in the given string. Alias for [uppercase](#uppercase).

**Params**

* `string` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{upcase "aBcDeF"}}
<!-- results in:  'ABCDEF' -->
```

## {{uppercase}}

Uppercase all of the characters in the given string. If used as a block helper it will uppercase the entire block. This helper does not support inverse blocks.

**Params**

* `str` **{String}**: The string to uppercase
* `options` **{Object}**: Handlebars options object
* `returns` **{String}**

**Example**

```handlebars
{{uppercase "aBcDeF"}}
<!-- results in:  'ABCDEF' -->
```

---

## File: docs/en-US/api/handlebars-helpers/url.md

# URL

## {{encodeURI}}

Encodes a Uniform Resource Identifier (URI) component
by replacing each instance of certain characters by
one, two, three, or four escape sequences representing
the UTF-8 encoding of the character.

**Params**

* `str` **{String}**: The un-encoded string
* `returns` **{String}**: The endcoded string

## {{escape}}

Escape the given string by replacing characters with escape sequences.
Useful for allowing the string to be used in a URL, etc.

**Params**

* `str` **{String}**
* `returns` **{String}**: Escaped string.

## {{decodeURI}}

Decode a Uniform Resource Identifier (URI) component.

**Params**

* `str` **{String}**
* `returns` **{String}**

## {{url_encode}}

Alias for [encodeURI](#encodeuri).

## {{url_decode}}

Alias for [decodeURI](#decodeuri).

## {{urlResolve}}

Take a base URL, and a href URL, and resolve them as a
browser would for an anchor tag.

**Params**

* `base` **{String}**
* `href` **{String}**
* `returns` **{String}**

## {{urlParse}}

Parses a `url` string into an object.

**Params**

* `str` **{String}**: URL string
* `returns` **{String}**: Returns stringified JSON

## {{stripQuerystring}}

Strip the query string from the given `url`.

**Params**

* `url` **{String}**
* `returns` **{String}**: the url without the queryString

## {{stripProtocol}}

Strip protocol from a `url`. Useful for displaying media that may have an 'http' protocol on secure connections.

**Params**

* `str` **{String}**
* `returns` **{String}**: the url with http protocol stripped

**Example**

```handlebars
<!-- url = 'http://foo.bar' -->
{{stripProtocol url}}
<!-- results in: '//foo.bar' -->
```

---

## File: docs/en-US/api/http/index.md

# Overview

HTTP API of NocoBase is designed based on Resource & Action, a superset of REST API. The operation includes but not limited to create, read, update and delete. Resource Action can be extended arbitrarily in NocoBase.

## Resource

In NocoBase, resource has two expressions:

- `<collection>`
- `<collection>.<association>`

<Alert>

- Collection is the set of all abstract data
- Association is the associated data of collection
- Resource includes both collection and collection.association

</Alert>

### Example

- `posts` Post
- `posts.user` Post user
- `posts.tags` Post tags

## Action

Action on resource is expressed by `:<action>`

- `<collection>:<action>`
- `<collection>.<association>:<action>`

Built-in global actions for collection or association:

- `create`
- `get`
- `list`
- `update`
- `destroy`
- `move`

Built-in association actions for association only:

- `set`
- `add`
- `remove`
- `toggle`

### Example

- `posts:create` Create post
- `posts.user:get` Get post user
- `posts.tags:add` Add tags to post (associate existing tags with post)

## Request URL

```bash
<GET|POST>   /api/<collection>:<action>
<GET|POST>   /api/<collection>:<action>/<collectionIndex>
<GET|POST>   /api/<collection>/<collectionIndex>/<association>:<action>
<GET|POST>   /api/<collection>/<collectionIndex>/<association>:<action>/<associationIndex>
```

### Example

posts resource

```bash
POST  /api/posts:create
GET   /api/posts:list
GET   /api/posts:get/1
POST  /api/posts:update/1
POST  /api/posts:destroy/1
```

posts.comments resource

```bash
POST  /api/posts/1/comments:create
GET   /api/posts/1/comments:list
GET   /api/posts/1/comments:get/1
POST  /api/posts/1/comments:update/1
POST  /api/posts/1/comments:destroy/1
```

posts.tags resource

```bash
POST  /api/posts/1/tags:create
GET   /api/posts/1/tags:get
GET   /api/posts/1/tags:list
POST  /api/posts/1/tags:update
POST  /api/posts/1/tags:destroy
POST  /api/posts/1/tags:add
GET   /api/posts/1/tags:remove
```

## Locate Resource

- Collection resource locates the data to be processed by `collectionIndex`, `collectionIndex` must be unique.
- Association resource locates the data to be processed by `collectionIndex` and `associationIndex` jointly, `associationIndex` may not be unique, but the joint index of `collectionIndex` and `associationIndex` must be unique.

When viewing details of association resource, the requested URL needs to provide both `<collectionIndex>` and `<associationIndex>`, `<collectionIndex>` is necessary as `<associationIndex>` may not be unique.

For example, `tables.fields` represents the fields of a data table:

```bash
GET   /api/tables/table1/fields/title
GET   /api/tables/table2/fields/title
```

Both table1 and table2 have the title field, title is unique in one table, but other tables may also have fields of that name.

## Request Parameters

Request parameters can be placed in the headers, parameters (query string), and body (GET requests do not have a body) of the request.

Some special request parameters:

- `filter` Data filtering, used in actions related to query.
- `filterByTk` Filter by tk field, used in actions to specify details of data.
- `sort` Sorting, used in actions related to query.
- `fields` Date to output, used in actions related to query
- `appends` Fields of additional relationship, used in actions related to query.
- `except` Exclude some fields (not to output), used in actions related to query.
- `whitelist` Fields whitelist, used in actions related to data creation and update.
- `blacklist` Fields blacklist, used in actions related to data creation and update.

### filter

Data filtering.

```bash
# simple
GET /api/posts?filter[status]=publish
# json string format is recommended, which requires encodeURIComponent encoding
GET /api/posts?filter={"status":"published"}

# filter operators
GET /api/posts?filter[status.$eq]=publish
GET /api/posts?filter={"status.$eq":"published"}

# $and
GET /api/posts?filter={"$and": [{"status.$eq":"published"}, {"title.$includes":"a"}]}
# $or
GET /api/posts?filter={"$or": [{"status.$eq":"pending"}, {"status.$eq":"draft"}]}

# association field
GET /api/posts?filter[user.email.$includes]=gmail
GET /api/posts?filter={"user.email.$includes":"gmail"}
```

[Click here for more information about filter operators](http-api/filter-operators)

### filterByTk

Filter by tk field. In the default settings:

- collection resource: tk is the primary key of the data table.
- association resource: tk is the targetKey field of the association.

```bash
GET   /api/posts:get?filterByTk=1&fields=name,title&appends=tags
```

### sort

Sorting. To sort in the descending order, put `-` in front of the field.

```bash
# Sort createAt field in the ascending order
GET /api/posts:get?sort=createdAt
# Sort createAt field in the descending order
GET /api/posts:get?sort=-createdAt
# Sort multiple fields jointly, createAt field descending, title A-Z ascending
GET /api/posts:get?sort=-createdAt,title
```

### fields

Data to output.

```bash
GET   /api/posts:list?fields=name,title

Response 200 (application/json)
{
  "data": [
    {
      "name": "",
      "title": ""
    }
  ],
  "meta": {}
}
```

### appends

Fields of additional relationship.

### except

Exclude some fields (not to output), used in actions related to query.

### whitelist

Whitelist.

```bash
POST  /api/posts:create?whitelist=title

{
  "title": "My first post",
  "date": "2022-05-19"      # The date field will be filtered out and not be written to the database
}
```

### blacklist

Blacklist.

```bash
POST  /api/posts:create?blacklist=date

# The date field will be filtered out and not be written to the database
{
  "title": "My first post"
}
```

## Request Response

Format of the response:

```ts
type ResponseResult = {
  data?: any; // Main data
  meta?: any; // Additional Data
  errors?: ResponseError[]; // Errors
};

type ResponseError = {
  code?: string;
  message: string;
};
```

### Example

View list:

```bash
GET /api/posts:list

Response 200 (application/json)

{
  data: [
    {
      id: 1
    }
  ],
  meta: {
    count: 1
    page: 1,
    pageSize: 1,
    totalPage: 1
  },
}
```

View details:

```bash
GET /api/posts:get/1

Response 200 (application/json)

{
  data: {
    id: 1
  }
}
```

Error:

```bash
POST /api/posts:create

Response 400 (application/json)

{
  errors: [
    {
      message: 'name must be required',
    },
  ],
}
```

---

## File: docs/en-US/api/http/rest-api.md

# REST API

HTTP API of NocoBase is a superset of REST API, and the standard CRUD API also supports the RESTful style.

## Collection Resources

### Create Collection

HTTP API

```bash
POST  /api/<collection>:create

{} # JSON body
```

REST API

```bash
POST  /api/<collection>

{} # JSON body
```

### View Collection List

HTTP API

```bash
GET   /api/<collection>:list
```

REST API

```bash
GET   /api/<collection>
```

### View Collection Details

HTTP API

```bash
GET   /api/<collection>:get?filterByTk=<collectionIndex>
GET   /api/<collection>:get/<collectionIndex>
```

REST API

```bash
GET   /api/<collection>/<collectionIndex>
```

### Update Collection

HTTP API

```bash
POST   /api/<collection>:update?filterByTk=<collectionIndex>

{} # JSON body

# Or
POST   /api/<collection>:update/<collectionIndex>

{} # JSON body
```

REST API

```bash
PUT    /api/<collection>/<collectionIndex>

{} # JSON body
```

### Delete Collection

HTTP API

```bash
POST      /api/<collection>:destroy?filterByTk=<collectionIndex>
# Or
POST      /api/<collection>:destroy/<collectionIndex>
```

REST API

```bash
DELETE    /api/<collection>/<collectionIndex>
```

## Association Resources

### Create Association

HTTP API

```bash
POST    /api/<collection>/<collectionIndex>/<association>:create

{} # JSON body
```

REST API

```bash
POST    /api/<collection>/<collectionIndex>/<association>

{} # JSON body
```

### View Association List

HTTP API

```bash
GET   /api/<collection>/<collectionIndex>/<association>:list
```

REST API

```bash
GET   /api/<collection>/<collectionIndex>/<association>
```

### View Association Details

HTTP API

```bash
GET   /api/<collection>/<collectionIndex>/<association>:get?filterByTk=<associationIndex>
# Or
GET   /api/<collection>/<collectionIndex>/<association>:get/<associationIndex>
```

REST API

```bash
GET   /api/<collection>/<collectionIndex>/<association>:get/<associationIndex>
```

### Update Association

HTTP API

```bash
POST   /api/<collection>/<collectionIndex>/<association>:update?filterByTk=<associationIndex>

{} # JSON body

# Or
POST   /api/<collection>/<collectionIndex>/<association>:update/<associationIndex>

{} # JSON body
```

REST API

```bash
PUT    /api/<collection>/<collectionIndex>/<association>:update/<associationIndex>

{} # JSON
```

### Delete Association

HTTP API

```bash
POST    /api/<collection>/<collectionIndex>/<association>:destroy?filterByTk=<associationIndex>
# Or
POST    /api/<collection>/<collectionIndex>/<association>:destroy/<associationIndex>
```

REST API

```bash
DELETE  /api/<collection>/<collectionIndex>/<association>/<associationIndex>
```

---

## File: docs/en-US/api/resourcer/action.md

# ctx.action

## Overview

After the resource operation request is parsed by [`resourceManager.middleware()`](./resource-manager#middleware), some important request parameters are stored in `ctx.action` for use by subsequent middleware.

## API

### resourceName

`ctx.action.resourceName`

The name of the resource. It can take two forms:

- `a` - Operates on resource `a`.
- `a.b` - Operates on associated object `b` of resource `a`.

### actionName

`ctx.action.actionName`

The name of the action.

### sourceId

`ctx.action.sourceId`

When the operation object is an associated object of the resource, it represents the primary key value of the corresponding resource. For example: when `resourceName` is `a.b`, `sourceId` represents the primary key value of `a`.

### params

Request parameters.

- URL parameters can be directly obtained from `ctx.action.params`.

```ts
const { filterByTk } = ctx.action.params;
```

- Request body parameters can be obtained using `ctx.action.params.values`.

### mergeParams()

Combines parameter content with request parameters.

```ts
ctx.action.mergeParams(
  {
    filter: {
      name: 'foo',
    },
    fields: ['id', 'name'],
    except: ['name'],
    sort: ['id'],
    page: 1,
    pageSize: 10,
    values: {
      name: 'foo',
    },
  },
  {
    filter: 'and',
    fields: 'union',
    except: 'union',
    sort: 'overwrite',
    page: 'overwrite',
    pageSize: 'overwrite',
    values: 'deepMerge',
  },
);

ctx.action.mergeParams(
  {
    filter: {},
  },
  {
    filter: (x, y) => {
      // ...
    },
  },
);
```

#### Signature

- `mergeParams(params: ActionParams, strategies: MergeStrategies = {})`

#### Type

```ts
export interface ActionParams {
  filterByTk?: any;
  fields?: string[];
  appends?: string[];
  except?: string[];
  whitelist?: string[];
  blacklist?: string[];
  filter?: FilterOptions;
  sort?: string[];
  page?: number;
  pageSize?: number;
  values?: any;
  [key: string]: any;
}

type MergeStrategyType =
  | 'merge'
  | 'deepMerge'
  | 'overwrite'
  | 'andMerge'
  | 'orMerge'
  | 'intersect'
  | 'union';
type MergeStrategyFunc = (x: any, y: any) => any;
export type MergeStrategy = MergeStrategyType | MergeStrategyFunc;
export interface MergeStrategies {
  [key: string]: MergeStrategy;
}
```

#### Details

| Property     | Type                                                     | Description                                                   |
| ------------ | -------------------------------------------------------- | ------------------------------------------------------------- |
| `params`     | [`ActionParams`](#actionparams)                          | Request parameters                                            |
| `strategies` | [`{ [key: string]: MergeStrategies }`](#mergestrategies) | Merge strategies for various fields in the request parameters |

Default `strategies`:

```ts
{
  filter: 'andMerge',
  fields: 'intersect',
  appends: 'union',
  except: 'union',
  whitelist: 'intersect',
  blacklist: 'intersect',
  sort: 'overwrite',
};
```

##### ActionParams

| Property        | Type       | Description                                                             |
| --------------- | ---------- | ----------------------------------------------------------------------- |
| `filterByTk`    | `any`      | The primary key value of the operated resource                          |
| `filter`        | `Filter`   | Filtering parameters, refer to [Filter Operators](./database/operators) |
| `fields`        | `string[]` | Fields to retrieve                                                      |
| `except`        | `string[]` | Fields to exclude                                                       |
| `appends`       | `string[]` | Related fields to append                                                |
| `whitelist`     | `string[]` | Field whitelist                                                         |
| `blacklist`     | `string[]` | Field blacklist                                                         |
| `sort`          | `string[]` | Sorting parameters                                                      |
| `page`          | `number`   | Current page                                                            |
| `pageSize`      | `number`   | Number of data items per page                                           |
| `values`        | `any`      | Request body                                                            |
| `[key: string]` | `any`      | Other extended configurations                                           |

##### MergeStrategies

Predefined merge strategies or custom merge functions.

Predefined merge strategies:

| Strategy Name | Description                                       |
| ------------- | ------------------------------------------------- |
| `merge`       | `Object.assign`                                   |
| `deepMerge`   | Deep traversal merge                              |
| `overwrite`   | Overwrite                                         |
| `andMerge`    | Merge filter parameters using the `$and` operator |
| `orMerge`     | Merge filter parameters using the `$or` operator  |
| `intersect`   | Intersection                                      |
| `union`       | Union                                             |

---

## File: docs/en-US/api/resourcer/middleware.md

# Middleware

It is similar to the middleware of Koa, but with more enhanced features for easy extensions.

The defined middleware can be inserted for use in multiple places, such as the resourcer, and it is up to the developer for when to invoke it.

## Constructor

**Signature**

- `constructor(options: Function)`
- `constructor(options: MiddlewareOptions)`

**Parameter**

| Name              | Type                 | Default | Description                            |
| ----------------- | -------------------- | ------- | -------------------------------------- |
| `options`         | `Function`           | -       | Handler function of middlware          |
| `options`         | `MiddlewareOptions ` | -       | Configuration items of middlware       |
| `options.only`    | `string[]`           | -       | Only the specified actions are allowed |
| `options.except`  | `string[]`           | -       | The specified actions are excluded     |
| `options.handler` | `Function`           | -       | Handler function                       |

**Example**

Simple definition:

```ts
const middleware = new Middleware((ctx, next) => {
  await next();
});
```

Definition with relevant parameters:

```ts
const middleware = new Middleware({
  only: ['create', 'update'],
  async handler(ctx, next) {
    await next();
  },
});
```

## Instance Methods

### `getHandler()`

Get the orchestrated handler functions.

**Example**

The following middleware will output `1` and then `2` when requested.

```ts
const middleware = new Middleware((ctx, next) => {
  console.log(1);
  await next();
});

middleware.use(async (ctx, next) => {
  console.log(2);
  await next();
});

app.resourcer.use(middleware.getHandler());
```

### `use()`

Add a middleware function to the current middleware. Used to provide extension points for the middleware. See `getHandler()` for the examples.

**Signature**

- `use(middleware: Function)`

**Parameter**

| Name         | Type       | Default | Description                        |
| ------------ | ---------- | ------- | ---------------------------------- |
| `middleware` | `Function` | -       | Handler function of the middleware |

### `disuse()`

Remove the middleware functions that have been added to the current middleware.

**Signature**

- `disuse(middleware: Function)`

**Parameter**

| Name         | Type       | Default | Description                        |
| ------------ | ---------- | ------- | ---------------------------------- |
| `middleware` | `Function` | -       | Handler function of the middleware |

**Example**

The following example will only output `1` when requested, the output of `2` in fn1 will not be executed.

```ts
const middleware = new Middleware((ctx, next) => {
  console.log(1);
  await next();
});

async function fn1(ctx, next) {
  console.log(2);
  await next();
}

middleware.use(fn1);

app.resourcer.use(middleware.getHandler());

middleware.disuse(fn1);
```

### `canAccess()`

Check whether the current middleware is to be invoked for a specific action, it is usually handled by the resourcer internally.

**Signature**

- `canAccess(name: string): boolean`

**Parameter**

| Name   | Type     | Default | Description        |
| ------ | -------- | ------- | ------------------ |
| `name` | `string` | -       | Name of the action |

## Other Exports

### `branch()`

Create a branch middleware for branching in the middleware.

**Signature**

- `branch(map: { [key: string]: Function }, reducer: Function, options): Function`

**Parameter**

| Name                     | Type                          | Default          | Description                                                                                                       |
| ------------------------ | ----------------------------- | ---------------- | ----------------------------------------------------------------------------------------------------------------- |
| `map`                    | `{ [key: string]: Function }` | -                | Mapping table of the branch handler function, key names are given by subsequent calculation functions when called |
| `reducer`                | `(ctx) => string`             | -                | Calculation function, it is used to calculate the key name of the branch based on the context                     |
| `options?`               | `Object`                      | -                | Configuration items of the branch                                                                                 |
| `options.keyNotFound?`   | `Function`                    | `ctx.throw(404)` | Handler function when key name is not found                                                                       |
| `options.handlerNotSet?` | `Function`                    | `ctx.throw(404)` | The function when no handler function is defined                                                                  |

**Example**

When authenticating user, determine what to do next according to the value of the `authenticator` parameter in the query section of the request URL.

```ts
app.resourcer.use(
  branch(
    {
      password: async (ctx, next) => {
        // ...
      },
      sms: async (ctx, next) => {
        // ...
      },
    },
    (ctx) => {
      return ctx.action.params.authenticator ?? 'password';
    },
  ),
);
```

---

## File: docs/en-US/api/resourcer/resource-manager.md

# ResourceManager

## Overview

`ResourceManager` is the resource management module of NocoBase, used to define resources and register operation methods for resources.

## Class Methods

### `define()`

Defines a resource.

```ts
app.resourceManager.define({
  name: 'auth',
  actions: {
    check: async (ctx, next) => {
      // ...
      await next();
    },
  },
});
```

#### Signature

- `define(options: ResourceOptions): Resource`

#### Type

```ts
export interface ResourceOptions {
  name: string;
  type?: ResourceType;
  actions?: {
    [key: string]: ActionType;
  };
  only?: Array<ActionName>;
  except?: Array<ActionName>;
  middleware?: MiddlewareType;
  middlewares?: MiddlewareType;
}

export type ResourceType =
  | 'single'
  | 'hasOne'
  | 'hasMany'
  | 'belongsTo'
  | 'belongsToMany';

export type ActionType = HandlerType | ActionOptions;
export type HandlerType = (
  ctx: ResourcerContext,
  next: () => Promise<any>,
) => any;
export interface ActionOptions {
  values?: any;
  fields?: string[];
  appends?: string[];
  except?: string[];
  whitelist?: string[];
  blacklist?: string[];
  filter?: FilterOptions;
  sort?: string[];
  page?: number;
  pageSize?: number;
  maxPageSize?: number;
  middleware?: MiddlewareType;
  middlewares?: MiddlewareType;
  handler?: HandlerType;
  [key: string]: any;
}
```

#### Details

##### ResourceOptions

| Property      | Type                                           | Description            | Default  |
| ------------- | ---------------------------------------------- | ---------------------- | -------- |
| `name`        | `string`                                       | Resource name          | -        |
| `type`        | `ResourceType`                                 | Resource type          | `single` |
| `actions`     | [`{ [key: string]: ActionType }`](#actiontype) | Actions                | -        |
| `only`        | `ActionName[]`                                 | Whitelist of `actions` | -        |
| `except`      | `ActionName[]`                                 | Blacklist of `actions` | -        |
| `middleware`  | `MiddlewareType`                               | Middleware             | -        |
| `middlewares` | `MiddlewareType`                               | Middlewares            | -        |

##### ActionType

There are two types of action methods:

- `HandlerType`

This type directly defines the operation method through middleware. Example:

```ts
app.resourceManager.define({
  name: 'users',
  actions: {
    updateProfile: async (ctx, next) => {
      // ...
      await next();
    },
  },
});
```

- `ActionOptions`

This type is mainly used to override the request parameters of a certain existing operation. Example:

```ts
app.resourceManager.define({
  name: 'users',
  actions: {
    list: {
      fields: [],
      filter: {},
      // ...
    },
  },
});
```

| Property        | Type             | Description                                                                 |
| --------------- | ---------------- | --------------------------------------------------------------------------- |
| `values`        | `any`            | Default values for the action request                                       |
| `filter`        | `Filter`         | Filtering parameters, refer to [Filter Operators](../database/operators.md) |
| `fields`        | `string[]`       | Fields to retrieve                                                          |
| `except`        | `string[]`       | Fields to exclude                                                           |
| `appends`       | `string[]`       | Related fields to append                                                    |
| `whitelist`     | `string[]`       | Field whitelist                                                             |
| `blacklist`     | `string[]`       | Field blacklist                                                             |
| `sort`          | `string[]`       | Sorting parameters                                                          |
| `page`          | `number`         | Current page                                                                |
| `pageSize`      | `number`         | Number of data items per page                                               |
| `maxPageSize`   | `number`         | Maximum number of data items per page                                       |
| `middleware`    | `MiddlewareType` | Middleware                                                                  |
| `middlewares`   | `MiddlewareType` | Middlewares                                                                 |
| `handler`       | `HandlerType`    | Method executed for the action                                              |
| `[key: string]` | `any`            | Other extended configurations                                               |

### `registerActionHandlers()`

Registers action methods.

#### Signature

- `registerActionHandler(name: ActionName, handler: HandlerType)`

#### Type

```ts
export type DefaultActionType =
  | 'list'
  | 'create'
  | 'get'
  | 'update'
  | 'destroy'
  | 'set'
  | 'add'
  | 'remove';
export type ActionName = DefaultActionType | Omit<string, DefaultActionType>;

export type HandlerType = (
  ctx: ResourcerContext,
  next: () => Promise<any>,
) => any;
```

#### Details

| Property  | Type          | Description                                                                                                                                                        |
| --------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `name`    | `ActionName`  | Action name.1. As a regular string, registers actions for all resources.2. In the form `<resource>:<action>`, registers actions for specific resources |
| `handler` | `HandlerType` | Middleware for the action                                                                                                                                          |

### `isDefined()`

Checks if a resource is defined.

#### Signature

- `isDefined(name: string)`

#### Details

| Property | Type     | Description   |
| -------- | -------- | ------------- |
| `name`   | `string` | Resource name |

### `import()`

Loads resource configurations from a specified directory.

```ts
// ./resources/demo.ts
export default {
  name: 'demo',
  actions: {
    async list(ctx, next) {
      // ...
      await next();
    },
  },
};

const resourceManager = new ResourceManager();
await resourceManager.import({
  directory: path.resolve(__dirname, 'resources'),
});
```

#### Signature

- `import(options: ImportOptions): Promise<Map<string, Resource>>`

#### Type

```ts
export interface ImportOptions {
  directory: string;
  extensions?: string[];
}
```

#### Details

| Property     | Type       | Description               | Default Value          |
| ------------ | ---------- | ------------------------- | ---------------------- |
| `directory`  | `string`   | Directory path            | -                      |
| `extensions` | `string[]` | Optional, file extensions | `['js', 'ts', 'json']` |

### `use()`

Adds `ResourceManager` middleware.

```ts
resourceManager.use(async () => {
  return async function (ctx, next) {
    // ...
    await next();
  };
});
```

#### Signature

- `use(middlewares: HandlerType | HandlerType[], options: ToposortOptions = {})`

#### Details

Refer to [Middleware](../../development/server/middleware.md).

### `middleware()`

Middleware for `ResourceManager`, parses request parameters (refer to [ctx.action](./action.md)) and executes operation methods.

---

## File: docs/en-US/api/resourcer/resource.md

# Resource

Resource is used to define resource instance. Resource instances managed by resourcer can be accessed through HTTP requests.

## Constructor

To create resource instance. Normally it is not used directly, but replaced by the call of the `define()` interface of resourcer.

**Signature**

- `constructor(options: ResourceOptions, resourcer: Resourcer)`

**Parameter**

| Name                  | Type                                 | Default    | Description                                                                                                     |
| --------------------- | ------------------------------------ | ---------- | --------------------------------------------------------------------------------------------------------------- |
| `options.name`        | `string`                             | -          | Name of the resource, corresponding to the resource address in the route of the URL                             |
| `options.type`        | `string`                             | `'single'` | Type of the resource, options are `'single'`, `'hasOne'`, `'hasMany'`, `'belongsTo'`, `'belongsToMany'`         |
| `options.actions`     | `Object`                             | -          | List of actions that can be taken on the resource, see the example for details                                  |
| `options.middlewares` | `MiddlewareType \| MiddlewareType[]` | -          | List of middlewares for any operational access to the resource that is defining，see the example for details    |
| `options.only`        | `ActionName[]`                       | `[]`       | Whitelist for global actions, only actions contained in the array (if `length > 0`) can be accessed             |
| `options.except`      | `ActionName[]`                       | `[]`       | Blacklist for global actions, all actions except those contained in the array (if `length > 0`) can be accessed |
| `resourcer`           | `Resourcer`                          | -          | The resourcer instance                                                                                          |

**Example**

```ts
app.resourcer.define({
  name: 'books',
  actions: {
    // Extended action
    publish(ctx, next) {
      ctx.body = 'ok';
    },
  },
  middleware: [
    // Extended middleware
    async (ctx, next) => {
      await next();
    },
  ],
});
```

## Instance Members

### `options`

Configuration items for the current resource.

### `resourcer`

The resourcer instance to which the resource belongs.

### `middlewares`

The registered middlewares.

### `actions`

The registered mapping table of actions.

### `except`

Actions that are excluded.

## Instance Methods

### `getName()`

Get the name of the current resource.

**Signature**

- `getName(): string`

**Example**

```ts
const resource = app.resourcer.define({
  name: 'books',
});

resource.getName(); // 'books'
```

### `getAction()`

Get action with the corresponding name.

**Signature**

- `getAction(name: string): Action`

**Parameter**

| Name   | Type     | Default | Description        |
| ------ | -------- | ------- | ------------------ |
| `name` | `string` | -       | Name of the action |

**Example**

```ts
const resource = app.resourcer.define({
  name: 'books',
  actions: {
    publish(ctx, next) {
      ctx.body = 'ok';
    },
  },
});

resource.getAction('publish'); // [Function: publish]
```

---

## File: docs/en-US/api/sdk/auth.md

# Auth

## Overview

The `Auth` class is primarily used for accessing user information on the client-side, as well as requesting user authentication-related APIs.

## Instance Properties

### `locale`

The language used by the current user.

### `role`

The role used by the current user.

### `token`

The API interface token.

### `authenticator`

The authenticator used for current user authentication. Refer to [User Authentication](../../handbook/auth/user.md).

## Class Methods

### `signIn()`

User login.

#### Signature

- `async signIn(values: any, authenticator?: string): Promise<AxiosResponse<any>>`

#### Details

| Parameter       | Type     | Description                             |
| --------------- | -------- | --------------------------------------- |
| `values`        | `any`    | Login API request parameters            |
| `authenticator` | `string` | Authenticator identifier used for login |

### `signUp()`

User registration.

#### Signature

- `async signUp(values: any, authenticator?: string): Promise<AxiosResponse<any>>`

#### Details

| Parameter       | Type     | Description                                    |
| --------------- | -------- | ---------------------------------------------- |
| `values`        | `any`    | Registration API request parameters            |
| `authenticator` | `string` | Authenticator identifier used for registration |

### `signOut()`

Log out.

#### Signature

- `async signOut(values: any, authenticator?: string): Promise<AxiosResponse<any>>`

#### Details

| Parameter       | Type     | Description                              |
| --------------- | -------- | ---------------------------------------- |
| `values`        | `any`    | Logout API request parameters            |
| `authenticator` | `string` | Authenticator identifier used for logout |

## 2. Official Technical Reference & Guides (nocobase/docs)

## File: README.md

# NocoBase V1 Documentation (Archived)

> **This repository is archived and no longer maintained.** V2 documentation lives in the main repository: [nocobase/nocobase](https://github.com/nocobase/nocobase) (under the `docs/` directory). For the latest docs, visit [docs.nocobase.com](https://docs.nocobase.com).

If you need to access the V1 documentation, you can run it locally:

## Local Development

```bash
git clone https://github.com/nocobase/docs.git
cd docs
yarn install

# Run English docs
yarn dev:en

# Run Chinese docs
yarn dev

# Run French docs
yarn dev:fr

# Run Japanese docs
yarn dev:ja

# Run Russian docs
yarn dev:ru
```

## Build

```bash
yarn build
```

Note: `yarn dev` and `yarn dev:en` cannot be run at the same time.

---

## File: package.json

{
  "name": "nocobase-docs",
  "version": "0.0.1",
  "description": "A static site based on dumi",
  "scripts": {
    "start": "npm run dev",
    "dev": "dumi dev",
    "dev:en": "cross-env DOC_LANG=en-US dumi dev",
    "dev:fr": "cross-env DOC_LANG=fr-FR dumi dev",
    "dev:ja": "cross-env DOC_LANG=ja-JP dumi dev",
    "dev:ru": "cross-env DOC_LANG=ru-RU dumi dev",
    "build": "dumi build",
    "build:en": "cross-env DOC_LANG=en-US dumi build",
    "build:fr": "cross-env DOC_LANG=fr-FR dumi build",
    "build:ja": "cross-env DOC_LANG=ja-JP dumi build",
    "build:ru": "cross-env DOC_LANG=ru-RU dumi build",
    "prepare": "husky install && dumi setup"
  },
  "authors": [],
  "license": "MIT",
  "commitlint": {
    "extends": [
      "@commitlint/config-conventional"
    ]
  },
  "lint-staged": {
    "*.{md,json}": [
      "prettier --write --no-error-on-unmatched-pattern"
    ]
  },
  "devDependencies": {
    "@alicloud/cdn20180510": "^4.2.2",
    "@commitlint/cli": "^18.2.0",
    "@commitlint/config-conventional": "^18.1.0",
    "ali-oss": "^6.1.0",
    "cross-env": "^7.0.3",
    "dumi": "^2.2.14",
    "husky": "^8.0.3",
    "lint-staged": "^15.0.2",
    "prettier": "^3.0.3"
  },
  "dependencies": {
    "@formulajs/formulajs": "^4.4.9",
    "@nocobase/client": "^0.21.0-alpha.6",
    "axios-mock-adapter": "1.22.0",
    "cytoscape": "^3.23.0",
    "dumi-theme-nocobase": "^0.2.31",
    "moment": "^2.30.1",
    "sucrase": "^3.0.0",
    "vditor": "^3.10.8"
  },
  "volta": {
    "node": "20.14.0",
    "yarn": "1.22.19"
  },
  "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
}

---

## File: tsconfig.json

{
  "compilerOptions": {
    "jsx": "react",
    "strict": true,
    "skipLibCheck": true,
    "noImplicitAny": false,
    "esModuleInterop": true,
    "baseUrl": "./",
    "paths": {
      "@@/*": [".dumi/tmp/*"]
    }
  },
  "include": [".dumirc.ts"]
}

---

## File: docs/en-US/components.md

# Components

---

## File: docs/en-US/index.md

# Index

<Navigate replace to="/welcome/introduction"></Navigate>

---

## File: docs/en-US/_partials/commercial-installation.md

## Installation

This plugin is a commercial plugin, which needs to be uploaded and activated through the plugin manager：

---

## File: docs/en-US/api/actions.md

# @nocobase/actions

## Overview

The `@nocobase/actions` package encapsulates frequently used CRUD-related methods. By simply registering it with the [ResourceManager](./resourcer/resource-manager), CRUD operation interfaces can be globally added to system resources.

### Basic Usage

```typescript
import * as actions from `@nocobase/actions`;

const resourceManager = new ResourceManager({
  // ...options
});

resourceManager.registerActionHandlers(actions);
```

## Action Methods

### create

Creates a resource. `POST /api/<resource>:create`.

```shell
curl "http://localhost:13000/api/users:create" \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{"username": "admin"}'
```

#### Request Body

| Parameter Name  | Type  | Description                                     |
| --------------- | ----- | ----------------------------------------------- |
| `[key: string]` | `any` | Key-value pairs representing resource fields    |

### list

Retrieves a list of resources. `GET /api/<resource>:list`.

```shell
curl -X GET http://localhost:13000/api/users:list
```

#### Parameters

| Parameter  | Type       | Description                                                        | Default |
| ---------- | ---------- | ------------------------------------------------------------------ | ------- |
| `filter`   | `Filter`   | Filtering parameters, see [Filter Operators](./database/operators) | -       |
| `fields`   | `string[]` | Fields to retrieve                                                 | -       |
| `except`   | `string[]` | Fields to exclude                                                  | -       |
| `appends`  | `string[]` | Related fields to append                                           | -       |
| `sort`     | `string[]` | Sorting parameters                                                 | -       |
| `paginate` | `boolean`  | Whether to use pagination                                          | `true`  |
| `page`     | `number`   | Current page number                                                | `1`     |
| `pageSize` | `number`   | Number of items per page                                           | `20`    |

### get

Retrieves a specific resource. `GET /api/<resource>:get`.

```shell
curl -X GET http://localhost:13000/api/users:get?filterByTk=1
```

#### Parameters

| Parameter    | Type               | Description                                                        | Default |
| ------------ | ------------------ | ------------------------------------------------------------------ | ------- |
| `filterByTk` | `number \| string` | Filter by primary key value                                        | -       |
| `filter`     | `Filter`           | Filtering parameters, see [Filter Operators](./database/operators) | -       |
| `fields`     | `string[]`         | Fields to retrieve                                                 | -       |
| `except`     | `string[]`         | Fields to exclude                                                  | -       |
| `appends`    | `string[]`         | Related fields to append                                           | -       |

### update

Updates one or more resources. `PUT /api/<resource>:update`.

```shell
curl "http://localhost:13000/api/users:update?filterByTk=1" \
  -X PUT \
  -H "Content-Type: application/json" \
  -d '{"username": "admin"}'
```

#### Parameters

| Parameter    | Type               | Description                                                        |
| ------------ | ------------------ | ------------------------------------------------------------------ |
| `filter`     | `Filter`           | Filtering parameters, see [Filter Operators](./database/operators) |
| `filterByTk` | `number \| string` | Filter by primary key value                                        |

*Note: At least one of `filter` or `filterByTk` must be provided.*

#### Request Body

| Parameter Name  | Type  | Description                                     |
| --------------- | ----- | ----------------------------------------------- |
| `[key: string]` | `any` | Key-value pairs representing resource fields    |

### destroy

Deletes one or more resources. `DELETE /api/<resource>:destroy`.

```shell
curl -X DELETE http://localhost:13000/api/users:destroy?filterByTk=1
```

#### Parameters

| Parameter    | Type               | Description                                                        |
| ------------ | ------------------ | ------------------------------------------------------------------ |
| `filter`     | `Filter`           | Filtering parameters, see [Filter Operators](./database/operators) |
| `filterByTk` | `number \| string` | Filter by primary key value                                        |

*Note: At least one of `filter` or `filterByTk` must be provided.*

### firstOrCreate

Retrieves or creates a resource. `POST /api/<resource>:firstOrCreate`.

```shell
curl "http://localhost:13000/api/users:firstOrCreate?filterKeys[]=username" \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{"username": "admin", "nickname": "Admin"}'
```

#### Parameters

| Parameter    | Type       | Description                                                |
| ------------ | ---------- | ---------------------------------------------------------- |
| `filterKeys` | `string[]` | Fields in the request body used to find existing resources |

#### Request Body

| Parameter Name  | Type  | Description                                     |
| --------------- | ----- | ----------------------------------------------- |
| `[key: string]` | `any` | Key-value pairs representing resource fields    |

### updateOrCreate

Updates or creates a resource. `POST /api/<resource>:updateOrCreate`.

```shell
curl "http://localhost:13000/api/users:updateOrCreate?filterKeys[]=username" \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{"username": "admin", "nickname": "Admin"}'
```

#### Parameters

| Parameter    | Type       | Description                                                |
| ------------ | ---------- | ---------------------------------------------------------- |
| `filterKeys` | `string[]` | Fields in the request body used to find existing resources |

#### Request Body

| Parameter Name  | Type  | Description                                     |
| --------------- | ----- | ----------------------------------------------- |
| `[key: string]` | `any` | Key-value pairs representing resource fields    |

### move

Moves resources, adjusting the order. Typically used for drag-and-drop sorting in pages. `POST /api/<resource>:move`.

```shell
curl -X POST "http://localhost:13000/api/users:move?sourceId=1&targetId=2"
```

#### Parameters

| Parameter     | Type                       | Description                                                 | Default |
| ------------- | -------------------------- | ----------------------------------------------------------- | ------- |
| `sourceId`    | `targetKey`                | ID of the element to move                                   | -       |
| `targetId`    | `targetKey`                | ID of the element to swap positions with                    | -       |
| `sortField`   | `string`                   | Name of the field where sorting is stored                   | `sort`  |
| `targetScope` | `string`                   | Sorting scope, a resource can be sorted by different scopes | -       |
| `sticky`      | `boolean`                  | Whether to stick the moved element                          | -       |
| `method`      | `insertAfter` \| `prepend` | Insertion method: whether to insert before                  |

### set

Sets associated objects for a resource. `POST /api/<resource>/<resourceKey>/<association>:set`.

```shell
curl "http://localhost:13000/api/users/1/roles:set" \
  -X POST \
  -H "Content-Type: application/json" \
  -d '["admin", "member"]'
```

#### Request Body

- `TargetKey | TargetKey[]` - Array of primary key values for associated objects.

### add

Adds associated objects to a resource. `POST /api/<resource>/<resourceKey>/<association>:add`.

```shell
curl "http://localhost:13000/api/users/1/roles:add" \
  -X POST \
  -H "Content-Type: application/json" \
  -d '["admin"]'
```

#### Request Body

- `TargetKey | TargetKey[]` - Array of primary key values for associated objects.

### remove

Removes associated objects from a resource. `POST /api/<resource>/<resourceKey>/<association>:remove`.

```shell
curl "http://localhost:13000/api/users/1/roles:remove" \
  -X POST \
  -H "Content-Type: application/json" \
  -d '["admin"]'
```

#### Request Body

- `TargetKey | TargetKey[]` - Array of primary key values for associated objects.

### toggle

Toggles associated objects for a resource, adding them if they don't exist, or removing them if they do. `POST /api/<resource>/<resourceKey>/<association>:toggle`.

```shell
curl "http://localhost:13000/api/users/1/roles:toggle" \
  -X POST \
  -H "Content-Type: application/json" \
  -d '["admin", "member"]'
```

#### Request Body

- `TargetKey | TargetKey[]` - Array of primary key values for associated objects.

---

## File: docs/en-US/api/cli.md

# @nocobase/cli

The NocoBase CLI is designed to help you develop, build, and deploy NocoBase applications.

<Alert>

NocoBase CLI supports *ts-node* and *node* two operation modes.

- ts-node mode (Default): Used for development environment, support real-time compilation, with relatively slow response
- node mode：Used for production environment, with quick response, but you need to execute `yarn nocobase build` to compile the entire source code first

</Alert>

## Instructions For Use

```bash
$ yarn nocobase -h

Usage: nocobase [command] [options]

Options:
  -h, --help

Commands:
  console
  db:auth               Verify if the database is successfully connected
  db:sync               Generate relevant data tables and fields through the configuration of collections
  install               Install
  start                 Start application in production environment
  build                 Compile and package
  clean                 Delete the compiled files
  dev                   Start application for development environment with real-time compilation
  doc                   Documentation development
  test                  Testing
  umi
  upgrade               Upgrade
  migrator              Data migration
  pm                    Plugin manager
  help
```

## Application in Scaffolding

`scripts` in the application scaffolding `package.json` is as below:

```json
{
  "scripts": {
    "dev": "nocobase dev",
    "start": "nocobase start",
    "clean": "nocobase clean",
    "build": "nocobase build",
    "test": "nocobase test",
    "pm": "nocobase pm",
    "postinstall": "nocobase postinstall"
  }
}
```

## Command Line Extensions

NocoBase CLI is built based on [commander](https://github.com/tj/commander.js). You can write the extended commands freely in `app/server/index.ts`:

```ts
const app = new Application(config);

app.command('hello').action(() => {});
```

or in the plugin:

```ts
class MyPlugin extends Plugin {
  beforeLoad() {
    this.app.command('hello').action(() => {});
  }
}
```

Run in the terminal:

```bash
$ yarn nocobase hello
```

## Built-in Commands

Sorted by frequency of use.

### `dev`

Start application and compile code in real time in development environment.

<Alert>
NocoBase is installed automatically if it is not installed (Refer to the `install` command).
</Alert>

```bash
Usage: nocobase dev [options]

Options:
  -p, --port [port]
  --client
  --server
  -h, --help
```

Example:

```bash
# Launch application for development environment, with real-time compilation
yarn nocobase dev
# Start the server side only
yarn nocobase dev --server
# Start the client side only
yarn nocobase dev --client
```

### `start`

Start application in production environment, the code needs *yarn build*.

<Alert>

- NocoBase is installed automatically if it is not installed (Refer to the `install` command).
- The source code needs to be re-packaged if it has any modification (Refer to the `build` command).

</Alert>

```bash
$ yarn nocobase start -h

Usage: nocobase start [options]

Options:
  -p, --port
  -s, --silent
  -h, --help
```

Example:

```bash
# Launch application for production environment
yarn nocobase start
```

### `install`

Install.

```bash
$ yarn nocobase install -h

Usage: nocobase install [options]

Options:
  -f, --force
  -c, --clean
  -s, --silent
  -l, --lang [lang]
  -e, --root-email <rootEmail>
  -p, --root-password <rootPassword>
  -n, --root-nickname [rootNickname]
  -h, --help
```

Example:

```bash
# Initial installation
yarn nocobase install -l zh-CN -e admin@nocobase.com -p admin123
# Delete all data tables from NocoBase and reinstall
yarn nocobase install -f -l zh-CN -e admin@nocobase.com -p admin123
# Clear database and reinstall
yarn nocobase install -c -l zh-CN -e admin@nocobase.com -p admin123
```

<Alert>

Difference between `-f/--force` and `-c/--clean`:

- `-f/--force` Delete data tables of NocoBase
- `-c/--clean` Clear database, all data tables are deleted

</Alert>

### `upgrade`

Upgrade.

```bash
yarn nocobase upgrade
```

### `test`

*jest* test, which supports all [jest-cli](https://jestjs.io/docs/cli) options, also supports `-c, --db-clean`.

```bash
$ yarn nocobase test -h

Usage: nocobase test [options]

Options:
  -c, --db-clean        Clear database before running all tests
  -h, --help
```

Example:

```bash
# Run all test files
yarn nocobase test
# Run all test files in the specified folder
yarn nocobase test packages/core/server
# Run all tests in the specified file
yarn nocobase test packages/core/database/src/__tests__/database.test.ts

# Clear database before running all tests
yarn nocobase test -c
yarn nocobase test packages/core/server -c
```

### `build`

The source code needs to be compiled and packaged before the code is deployed to the production environment; and you need to re-build the code if it has any modification.

```bash
# All packages
yarn nocobase build
# Specified packages
yarn nocobase build app/server app/client
```

### `clean`

Delete the compiled files.

```bash
yarn clean
# Equivalent to
yarn rimraf -rf packages/*/*/{lib,esm,es,dist}
```

### `doc`

Documentation development.

```bash
# Start the documentation
yarn doc  --lang=zh-CN # Equivalent to yarn doc dev
# Build the documentation, and output it to . /docs/dist/ directory by default
yarn doc build
# View the final result of the output documentation of dist
yarn doc serve --lang=zh-CN
```

### `db:auth`

Verify if the database is successfully connected.

```bash
$ yarn nocobase db:auth -h

Usage: nocobase db:auth [options]

Options:
  -r, --retry [retry]   Number of retries
  -h, --help
```

### `db:sync`

Generate relevant data tables and fields through the configuration of collections.

```bash
$ yarn nocobase db:sync -h

Usage: nocobase db:sync [options]

Options:
  -f, --force
  -h, --help   display help for command
```

### `migrator`

Data migration.

```bash
$ yarn nocobase migrator

Positional arguments:
  <command>
    up        Applies pending migrations
    down      Revert migrations
    pending   Lists pending migrations
    executed  Lists executed migrations
    create    Create a migration file
```

### `pm`

Plugin manager.

```bash
# Create plugin
yarn pm create hello
# Register plugin
yarn pm add hello
# Enable plugin
yarn pm enable hello
# Disable plugin
yarn pm disable hello
# Remove plugin
yarn pm remove hello
```

Not achieved yet:

```bash
# Upgrade plugin
yarn pm upgrade hello
# Publish plugin
yarn pm publish hello
```

### `umi`

`app/client` is built based on [umi](https://umijs.org/), you can run other relevant commands through `nocobase umi`.

```bash
# Generate the .umi cache needed for the development environment
yarn nocobase umi generate tmp
```

### `help`

The help command, you can also use the option parameter, `-h` and `--help`.

```bash
# View all cli
yarn nocobase help
# Use -h instead
yarn nocobase -h
# Or --help
yarn nocobase --help
# View options of command db:sync
yarn nocobase db:sync -h
```

---

## File: docs/en-US/api/index.md

# Overview

| Module                                                                                                | Package               | Description                     |
| ----------------------------------------------------------------------------------------------------- | --------------------- | ------------------------------- |
| [Server](/api/server/application)                                                                     | `@nocobase/server`    | Server-side application         |
| [Database](/api/database)                                                                             | `@nocobase/database`  | Database access layer           |
| [Resourcer](/api/resourcer/resource-manager)                                                          | `@nocobase/resourcer` | Resource and route mapping      |
| [ACL](/api/acl/acl)                                                                                   | `@nocobase/acl`       | Access Control                  |
| [Auth](/api/auth/auth-manager)                                                                        | `@nocobase/auth`      | User Authentication             |
| [Client](https://client.docs-cn.nocobase.com/core/application/application) | `@nocobase/client`    | Client-side application         |
| [Cache](/api/cache/cache-manager)                                                                     | `@nocobase/cache`     | Server-side cache               |
| [Logger](/api/logger)                                                                                 | `@nocobase/logger`    | Server-side logging             |
| [Telemetry](/api/telemetry/telemetry)                                                                 | `@nocobase/telemetry` | Server-side telemetry           |
| [CLI](/api/cli)                                                                                       | `@nocobase/cli`       | NocoBase Command Line Interface |
| [SDK](/api/sdk)                                                                                       | `@nocobase/sdk`       | NocoBase SDK                    |
| [Actions](/api/actions)                                                                               | `@nocobase/actions`   | Built-in resource operations    |
| [Test](/api/test/server)                                                                              | `@nocobase/test`      | Automated testing               |

---

## File: docs/en-US/api/logger.md

# @nocobase/logger

## Create Logger

### createLogger()

Creates a custom logger.

#### Signature

- `createLogger(options: LoggerOptions)`

#### Type

```ts
interface LoggerOptions
  extends Omit<winston.LoggerOptions, 'transports' | 'format'> {
  dirname?: string;
  filename?: string;
  format?: 'logfmt' | 'json' | 'delimiter' | 'console' | winston.Logform.Format;
  transports?: ('console' | 'file' | 'dailyRotateFile' | winston.transport)[];
}
```

#### Details

- `dirname`: Log directory
- `filename`: Log file name
- `format`: Log format
- `transports`: Log transports

### createSystemLogger()

Creates system runtime logs printed in a specified method. Refer to [Logger plugin - System log](../plugins/logger/index.md#system-log).

#### Signature

- `createSystemLogger(options: SystemLoggerOptions)`

#### Type

```ts
export interface SystemLoggerOptions extends LoggerOptions {
  seperateError?: boolean; // print error seperately, default true
}
```

#### Details

- `seperateError`: Whether to print `error` level logs separately

### app.createLogger()

#### Definition

```ts
class Application {
  createLogger(options: LoggerOptions) {
    const { dirname } = options;
    return createLogger({
      ...options,
      dirname: getLoggerFilePath(this.name || 'main', dirname || ''),
    });
  }
}
```

When `dirname` is a relative path, the log files will be output to the directory named after the current application.

### plugin.createLogger()

Usage is the same as `app.createLogger()`.

#### Definition

```ts
class Plugin {
  createLogger(options: LoggerOptions) {
    return this.app.createLogger(options);
  }
}
```

## Configuration

### getLoggerLevel()

`getLoggerLevel(): 'debug' | 'info' | 'warn' | 'error'`

Gets the log level currently configured in the system.

### getLoggerFilePath()

`getLoggerFilePath(...paths: string[]): string`

Concatenates directory paths based on the log directory currently configured in the system.

### getLoggerTransports()

`getLoggerTransports(): ('console' | 'file' | 'dailyRotateFile')[]`

Gets the log output methods currently configured in the system.

### getLoggerFormat()

`getLoggerFormat(): 'logfmt' | 'json' | 'delimiter' | 'console'`

Gets the log format currently configured in the system.

## Logger Transports

### Transports

Predefined output methods.

- `Transports.console`
- `Transports.file`
- `Transports.dailyRotateFile`

```ts
import { Transports } from '@nocobase/logger';

const transport = Transports.console({
  //...
});
```

## References

- [Development - Logger](../handbook/logger/index.md)
- [Logger Plugin](../plugins/logger/index.md)

---

## File: docs/en-US/api/acl/acl.md

# ACL

## Overview

`ACL` is the permission management module used in NocoBase, responsible for user role management, permission registration and authorization, as well as permission policy evaluation and access control.

### Concepts

- **Resource**: Collections, or custom resources can be registered. Refer to [`@nocobase/resourcer`](../resourcer/resource-manager.md).
- **Action**: An operation interface for a resource, such as create, read, update, delete, or other custom actions. Refer to [`@nocobase/actions`](../actions).
- **Strategy**: Configures global permissions for roles, such as permissions for resource operations like create, read, update, delete, import, export, and system permissions like configuring the user interface.
- **Snippet**: Defines a collection of operations, enabling unified management of operation permissions. Snippet identifiers can be matched using the [minimatch](https://github.com/isaacs/minimatch) rules.

## Class Methods

### `define()`

Defines a role.

#### Signature

- `define(options: DefineOptions): ACLRole`

#### Type Definitions

```typescript
export interface DefineOptions {
  role: string;
  strategy?: string | AvailableStrategyOptions;
  actions?: ResourceActionsOptions;
  snippets?: string[];
}

export interface AvailableStrategyOptions {
  displayName?: string;
  actions?: false | string | string[];
  allowConfigure?: boolean;
  resource?: '*';
}

export interface ResourceActionsOptions {
  [actionName: string]: RoleActionParams;
}

export interface RoleActionParams {
  fields?: string[];
  filter?: any;
  own?: boolean;
  whitelist?: string[];
  blacklist?: string[];
}
```

#### Details

##### DefineOptions

| Property   | Type                                                                | Description                                                       |
| ---------- | ------------------------------------------------------------------- | ----------------------------------------------------------------- |
| `role`     | `string`                                                            | Unique identifier for the role                                    |
| `strategy` | `string` \| [`AvailableStrategyOptions`](#availablestrategyoptions) | Optional, global access strategy for the role                     |
| `actions`  | [`{ [actionName: string]: RoleActionParams; }`](#roleactionparams)  | Optional, permission configuration for actions                    |
| `snippets` | `string[]`                                                          | Optional, defines snippets that the role has permission to access |

##### AvailableStrategyOptions

| Property         | Type                              | Description                                               |
| ---------------- | --------------------------------- | --------------------------------------------------------- |
| `displayName`    | `string`                          | Optional, display name for the strategy                   |
| `action`         | `false` \| `string` \| `string[]` | Optional, operation interfaces                            |
| `allowConfigure` | `boolean`                         | Optional, whether to allow configuring the user interface |
| `resource`       | `*`                               | Applies to all resources                                  |

##### RoleActionParams

| Property    | Type       | Description                                                                                            |
| ----------- | ---------- | ------------------------------------------------------------------------------------------------------ |
| `fields`    | `string[]` | Optional, fields of the data table to operate on                                                       |
| `filter`    | `any`      | Optional, filter parameters that must be met, only records that meet the conditions can be operated on |
| `own`       | `boolean`  | Optional, whether to operate only on records created by oneself                                        |
| `whitelist` | `string[]` | Optional, whitelist of fields that can be accessed, only fields in the whitelist can be accessed       |
| `blacklist` | `string[]` | Optional, blacklist of fields that cannot be accessed, fields in the blacklist cannot be accessed      |

### `can()`

Determines the permission to execute an action and returns the final action parameters. Returns `null` if no permission.

#### Signature

- `can(options: CanArgs): CanResult | null`

#### Type Definitions

```typescript
interface CanArgs {
  role: string;
  resource: string;
  action: string;
  ctx?: any;
}

interface CanResult {
  role: string;
  resource: string;
  action: string;
  params?: any;
}
```

#### Details

##### CanArgs

| Property   | Type     | Description               |
| ---------- | -------- | ------------------------- |
| `role`     | `string` | Role identifier           |
| `resource` | `string` | Resource identifier       |
| `action`   | `string` | Action identifier         |
| `ctx`      | `any`    | Optional, request context |

##### CanResult

| Property   | Type     | Description                 |
| ---------- | -------- | --------------------------- |
| `role`     | `string` | Role identifier             |
| `resource` | `string` | Resource identifier         |
| `action`   | `string` | Action identifier           |
| `params`   | `any`    | Optional, action parameters |

### `registerSnippet()`

Registers a snippet.

#### Signature

- `registerSnippet(snippet: SnippetOptions)`

#### Type Definitions

```typescript
export type SnippetOptions = {
  name: string;
  actions: string[];
};
```

#### Details

| Property  | Type       | Description                                                                                                                              |
| --------- | ---------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `name`    | `string`   | Snippet identifier, can be matched using the [minimatch](https://github.com/isaacs/minimatch) rules. E.g., `auth.auth` matches `auth.*`. |
| `actions` | `string[]` | Resource operations included in the snippet, in the format `resource:action`. E.g., `users:list`.                                        |

### `setAvailableAction()`

Sets allowed actions.

#### Signature

- `setAvailableAction(name: string, options: AvailableActionOptions = {})`

```typescript
export interface AvailableActionOptions {
  displayName?: string;
  aliases?: string[] | string;
  resource?: string;
  // Perform operations on new data
  onNewRecord?: boolean;
  // Allow configuring fields
  allowConfigureFields?: boolean;
}
```

#### Details

| Property               | Type                   | Description                                                                           |
| ---------------------- | ---------------------- | ------------------------------------------------------------------------------------- |
| `displayName`          | `string`               | Optional, display name for the action                                                 |
| `aliases`              | `string` \| `string[]` | Optional, action aliases. E.g., aliases for `get`, `list` operations are both `view`. |
| `resource`             | `string`               | Optional, resource                                                                    |
| `onNewRecord`          | `boolean`              | Optional, whether the operation applies to new data, such as create operation         |
| `allowConfigureFields` | `boolean`              | Optional, whether to allow configuring fields                                         |

### `setAvailableStrategy()`

Sets allowed strategies for actions.

#### Signature

- `setAvailableStrategy(name: string, options: AvailableStrategyOptions)`

Refer to [AvailableStrategyOptions](#availablestrategyoptions).

### `allow()`

Defines the conditions under which operations are allowed.

```typescript
acl.allow('plugins', '*', 'public');
```

#### Signature

- `allow(resourceName: string, actionNames: string[] | string, condition?: string | ConditionFunc)`

#### Type

```typescript
export type ConditionFunc = (ctx: any) => Promise<boolean> | boolean;
```

#### Details

| Parameter      | Type                        | Description                                                                 | Default  |
| -------------- | --------------------------- | --------------------------------------------------------------------------- | -------- |
| `resourceName` | `string`                    | Resource                                                                    | -        |
| `actionNames`  | `string` \| `string[]`      | Action                                                                      | -        |
| `condition`    | `string` \| `ConditionFunc` | Optional, predefined condition identifier, or condition evaluation function | `public` |

Predefined condition identifiers:

- `public`: Public interface.
- `loggedIn`: Allowed when the user is logged in.
- `allowConfigure`: Allowed when the current user role has permission to configure the user interface.

### `addFixedParams()`

Adds fixed parameters to operations, merging them with current request parameters.

```typescript
acl.addFixedParams('users', 'list', () => {
  return {
    filter: {
      id: {
        $eq: 1,
      },
    },
  };
});
```

#### Signature

- `addFixedParams(resource: string, action: string, merger: Merger)`

#### Type Definitions

```typescript
export type Merger = () => object;
```

#### Details

| Parameter  | Type     | Description                                               |
| ---------- | -------- | --------------------------------------------------------- |
| `resource` | `string` | Resource                                                  |
| `action`   | `string` | Action                                                    |
| `merger`   | `Merger` | Function returning the fixed parameter object to be added |

### `use()`

Adds the `ACL` middleware.

```typescript
acl.use(async () => {
  return async function (ctx, next) {
    // ...
    await next();
  };
});
```

#### Signature

- `use(fn: any, options?: ToposortOptions)`

#### Details

Refer to [Middleware](../../development/server/middleware).

### `middleware()`

NocoBase access control middleware.

---

## File: docs/en-US/api/auth/auth-manager.md

# AuthManager

## Overview

`AuthManager` is the user authentication management module in NocoBase, used for registering different types of user authentication.

### Basic Usage

```ts
const authManager = new AuthManager({
  // Key to retrieve the current authenticator identifier from the request header
  authKey: 'X-Authenticator',
});

// Set methods for storing and retrieving authenticators in AuthManager
authManager.setStorer({
  get: async (name: string) => {
    return db.getRepository('authenticators').find({ filter: { name } });
  },
});

// Register an authentication type
authManager.registerTypes('basic', {
  auth: BasicAuth,
  title: 'Password',
});

// Use authentication middleware
app.resourceManager.use(authManager.middleware());
```

### Concepts

- **Authentication type (`AuthType`)**: Different types of authentication, such as Password, SMS, OIDC, SAML, etc.
- **Authenticator**: An authenticator is a database-stored entity linked to a configuration record for a specific authentication type (`AuthType`). Multiple authenticators can exist for one authentication type, each offering diffrent authentications.
- **Authenticator name**: Unique identifier for an authenticator, used to determine the current authentication employed by the current request.

## Class Methods

### `constructor()`

Constructor, creates an instance of `AuthManager`.

#### Signature

- `constructor(options: AuthManagerOptions)`

#### Types

```ts
export interface JwtOptions {
  secret: string;
  expiresIn?: string;
}

export type AuthManagerOptions = {
  authKey: string;
  default?: string;
  jwt?: JwtOptions;
};
```

#### Details

##### AuthManagerOptions

| Attribute | Type                        | Description                                                                     | Default           |
| --------- | --------------------------- | ------------------------------------------------------------------------------- | ----------------- |
| `authKey` | `string`                    | Optional key to save the current authenticator identifier in the request header | `X-Authenticator` |
| `default` | `string`                    | Optional, default authenticator identifier                                      | `basic`           |
| `jwt`     | [`JwtOptions`](#jwtoptions) | Optional, configure if using JWT for authentication                             | -                 |

##### JwtOptions

| Attribute   | Type     | Description                       | Default           |
| ----------- | -------- | --------------------------------- | ----------------- |
| `secret`    | `string` | Token secret key                  | `X-Authenticator` |
| `expiresIn` | `string` | Optional, token expiration period | `7d`              |

### `setStorer()`

Set methods for storing and retrieving authenticator data.

#### Signature

- `setStorer(storer: Storer)`

#### Types

```ts
export interface Authenticator = {
  authType: string;
  options: Record<string, any>;
  [key: string]: any;
};

export interface Storer {
  get: (name: string) => Promise<Authenticator>;
}
```

#### Details

##### Authenticator

| Attribute  | Type                  | Description                          |
| ---------- | --------------------- | ------------------------------------ |
| `authType` | `string`              | Authentication type                  |
| `options`  | `Record<string, any>` | Authenticator-related configurations |

##### Storer

`Storer` is the interface for authenticator storage, containing one method.

- `get(name: string): Promise<Authenticator>` - Get authenticator by identifier. In NocoBase, the actual returned type is [AuthModel](../../handbook/auth/dev/api#authmodel).

### `registerTypes()`

Register authentication types.

#### Signature

- `registerTypes(authType: string, authConfig: AuthConfig)`

#### Types

```ts
export type AuthExtend<T extends Auth> = new (config: Config) => T;

type AuthConfig = {
  auth: AuthExtend<Auth>; // The authentication class.
  title?: string; // The display name of the authentication type.
};
```

#### Details

| Attribute | Type               | Description                                                          |
| --------- | ------------------ | -------------------------------------------------------------------- |
| `auth`    | `AuthExtend<Auth>` | Authentication type implementation, refer to [Auth](./auth.md)       |
| `title`   | `string`           | Optional. Title of the authentication type displayed on the frontend |

### `listTypes()`

Get a list of registered authentication types.

#### Signature

- `listTypes(): { name: string; title: string }[]`

#### Details

| Attribute | Type     | Description                      |
| --------- | -------- | -------------------------------- |
| `name`    | `string` | Authentication type identifier   |
| `title`   | `string` | Title of the authentication type |

### `get()`

Get authenticator.

#### Signature

- `get(name: string, ctx: Context)`

#### Details

| Attribute | Type      | Description              |
| --------- | --------- | ------------------------ |
| `name`    | `string`  | Authenticator identifier |
| `ctx`     | `Context` | Request context          |

### `middleware()`

Authentication middleware. Get the current authenticator and perform user authentication.

---

## File: docs/en-US/api/auth/auth.md

# Auth

## Overview

`Auth` is an abstract class for user authentication types, defining the interfaces required to complete user authentication. To extend new user authentication types, you need to inherit from the `Auth` class and implement its methods. The basic implementation can be referred to as [BaseAuth](./base-auth.md).

```ts
interface IAuth {
  user: Model;
  // Check the authentication status and return the current user.
  check(): Promise<Model>;
  signIn(): Promise<any>;
  signUp(): Promise<any>;
  signOut(): Promise<any>;
}

export abstract class Auth implements IAuth {
  abstract user: Model;
  abstract check(): Promise<Model>;
  // ...
}

class CustomAuth extends Auth {
  // check: Authentication
  async check() {
    // ...
  }
}
```

## Instance Properties

### `user`

Information of the authenticated user.

#### Signature

- `abstract user: Model`

## Class Methods

### `constructor()`

Constructor, creates an instance of `Auth`.

#### Signature

- `constructor(config: AuthConfig)`

#### Types

```ts
export type AuthConfig = {
  authenticator: Authenticator;
  options: {
    [key: string]: any;
  };
  ctx: Context;
};
```

#### Details

##### AuthConfig

| Attribute       | Type                                            | Description                                                                                                                 |
| --------------- | ----------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
| `authenticator` | [`Authenticator`](./auth-manager#authenticator) | Authenticator data model, the actual type in NocoBase applications is [AuthModel](../../handbook/auth/dev/api.md#authmodel) |
| `options`       | `Record<string, any>`                           | Authenticator-related configurations                                                                                        |
| `ctx`           | `Context`                                       | Request context                                                                                                             |

### `check()`

User authentication, returns user information. This is an abstract method that all authentication types must implement.

#### Signature

- `abstract check(): Promise<Model>`

### `signIn()`

User login.

#### Signature

- `signIn(): Promise<any>`

### `signUp()`

User registration.

#### Signature

- `signUp(): Promise<any>`

### `signOut()`

User logout.

#### Signature

- `signOut(): Promise<any>`

---

## File: docs/en-US/api/auth/base-auth.md

# BaseAuth

## Overview

`BaseAuth` inherits from the abstract class [Auth](./auth.md) and serves as the basic implementation for user authentication types, using JWT as the authentication method. In most cases, extending user authentication types can be achieved by inheriting from `BaseAuth` instead of directly inheriting from the `Auth` abstract class.

```ts
class BasicAuth extends BaseAuth {
  constructor(config: AuthConfig) {
    // Set user collection
    const userCollection = config.ctx.db.getCollection('users');
    super({ ...config, userCollection });
  }

  // User authentication logic, called by `auth.signIn`
  // Returns user data
  async validate() {
    const ctx = this.ctx;
    const { values } = ctx.action.params;
    // ...
    return user;
  }
}
```

## Class Methods

### `constructor()`

Constructor, creates an instance of `BaseAuth`.

#### Signature

- `constructor(config: AuthConfig & { userCollection: Collection })`

#### Details

| Parameter        | Type         | Description                                                                                                  |
| ---------------- | ------------ | ------------------------------------------------------------------------------------------------------------ |
| `config`         | `AuthConfig` | Refer to [Auth - AuthConfig](./auth.md#authconfig)                                                           |
| `userCollection` | `Collection` | User collection, e.g., `db.getCollection('users')`, refer to [DataBase - Collection](../database/collection) |

### `user()`

Accessor for setting and getting user information, defaulting to using the `ctx.state.currentUser` object.

#### Signature

- `set user()`
- `get user()`

### `check()`

Authenticates through the request token and returns user information.

### `signIn()`

User login, generates a token.

### `signUp()`

User registration.

### `signOut()`

User logout, token expiration.

### `validate()` \*

Core authentication logic, called by the `signIn` interface, to determine whether the user can successfully log in.

---

## File: docs/en-US/api/cache/cache-manager.md

# CacheManager

## Overview

CacheManager is based on [node-cache-manager](https://github.com/node-cache-manager/node-cache-manager) and provides caching module management for NocoBase. The built-in cache types are:

- **memory**: Provided by the default lru-cache of node-cache-manager.
- **redis**: Supported by node-cache-manager-redis-yet for Redis caching.

More types can be extended and registered through the API.

### Concepts

- **Store**: Defines a caching method, including a factory method for creating caches and other related configurations. Each caching method has a unique identifier provided during registration. The two built-in caching methods correspond to the unique identifiers `memory` and `redis`.

- **Store Factory Method**: Provided by `node-cache-manager` and related extension packages, used to create caches. Examples include `memory` provided by `node-cache-manager` by default, and `redisStore` provided by `node-cache-manager-redis-yet`. In this context, the object to be provided corresponds to [`StoreOptions`](#storeoptions), which is the first parameter of the `caching` method in `node-cache-manager`.

- **Cache**: A class encapsulated by NocoBase, providing methods related to cache usage. When actually using caching, operations are performed on instances of `Cache`. Each `Cache` instance has a unique identifier, which serves as a namespace for distinguishing different modules.

## Class Methods

### `constructor()`

#### Signature

- `constructor(options?: CacheManagerOptions)`

#### Type

```ts
export type CacheManagerOptions = Partial<{
  defaultStore: string;
  stores: {
    [storeType: string]: StoreOptions;
  };
}>;

type StoreOptions = {
  store?: 'memory' | FactoryStore<Store, any>;
  close?: (store: Store) => Promise<void>;
  // global config
  [key: string]: any;
};
```

#### Details

##### CacheManagerOptions

| Property       | Type                           | Description                                                                                                                                                          |
| -------------- | ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `defaultStore` | `string`                       | Unique identifier for the default cache type.                                                                                                                        |
| `stores`       | `Record<string, StoreOptions>` | Registers cache types. The key is the unique identifier for the cache type, and the value is an object containing the registration method and global configurations. |

##### StoreOptions

| Property        | Type                                   | Description                                                                                                                                                                                              |
| --------------- | -------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `store`         | `memory` \| `FactoryStore<Store, any>` | The store factory method, corresponding to the first parameter of the `caching` method.                                                                                                                  |
| `close`         | `(store: Store) => Promise<void>`      | Optional. For middleware that requires establishing a connection, such as Redis, provide a callback method for closing the connection. The parameter is the object returned by the store factory method. |
| `[key: string]` | `any`                                  | Other global configurations for the store, corresponding to the second parameter of the `caching` method.                                                                                                |

#### Default `options`

```ts
import { redisStore, RedisStore } from 'cache-manager-redis-yet';

const defaultOptions: CacheManagerOptions = {
  defaultStore: 'memory',
  stores: {
    memory: {
      store: 'memory',
      // global config
      max: 2000,
    },
    redis: {
      store: redisStore,
      close: async (redis: RedisStore) => {
        await redis.client.quit();
      },
    },
  },
};
```

The `options` parameter will be merged with the default options. Existing default options can be omitted. For example:

```ts
const cacheManager = new CacheManager({
  stores: {
    defaultStore: 'redis',
    redis: {
      // redisStore is already provided in the default options, so only need to provide redisStore configuration.
      url: 'redis://localhost:6379',
    },
  },
});
```

### `registerStore()`

Register a new caching method. Example:

```ts
import { redisStore } from 'cache-manager-redis-yet';

cacheManager.registerStore({
  // Unique identifier for the store
  name: 'redis',
  // Factory method for creating the store
  store: redisStore,
  // Callback method for closing the store connection
  close: async (redis: RedisStore) => {
    await redis.client.quit();
  },
  // Global configurations
  url: 'xxx',
});
```

#### Signature

- `registerStore(options: { name: string } & StoreOptions)`

### `createCache()`

Create a cache. Example:

```ts
await cacheManager.createCache({
  name: 'default', // Unique identifier for the cache
  store: 'memory', // Unique identifier for the store
  prefix: 'mycache', // Automatically adds the 'mycache:' prefix to cache keys, optional
  // Other store configurations, custom configurations that will be merged with global store configurations
  max: 2000,
});
```

#### Signature

- `createCache(options: { name: string; prefix?: string; store?: string; [key: string]: any }): Promise<Cache>`

#### Details

##### options

| Property        | Type     | Description                                        |
| --------------- | -------- | -------------------------------------------------- |
| `name`          | `string` | Unique identifier for the cache                    |
| `store`         | `string` | Unique identifier for the store                    |
| `prefix`        | `string` | Optional. Prefix automatically added to cache keys |
| `[key: string]` | `any`    | Other custom store configurations                  |

When `store` is omitted, the `defaultStore` will be used. In this case, the caching

---

## File: docs/en-US/api/cache/cache.md

# Cache

## Basic Methods

You can refer to the documentation of [node-cache-manager](https://github.com/node-cache-manager/node-cache-manager).

- `get()`
- `set()`
- `del()`
- `reset()`
- `wrap()`
- `mset()`
- `mget()`
- `mdel()`
- `keys()`
- `ttl()`

## Other Methods

### `wrapWithCondition()`

Similar to `wrap()`, but can decide whether to use caching based on conditions.

```ts
async wrapWithCondition<T>(
  key: string,
  fn: () => T | Promise<T>,
  options?: {
    // External parameter to control whether to use cache results
    useCache?: boolean;
    // Determine whether to cache based on data results
    isCacheable?: (val: unknown) => boolean | Promise<boolean>;
    ttl?: Milliseconds;
  },
): Promise<T> {
```

### `setValueInObject()`

When the cached content is an object, changes the value of a specific key.

```ts
async setValueInObject(key: string, objectKey: string, value: unknown)
```

### `getValueInObject()`

When the cached content is an object, retrieves the value of a specific key.

```ts
async getValueInObject(key: string, objectKey: string)
```

### `delValueInObject()`

When the cached content is an object, deletes a specific key.

```ts
async delValueInObject(key: string, objectKey: string)
```

---

## File: docs/en-US/api/client/application.md

# Application

## Constructor

### `constructor()`

Create an application instance.

**Signature**

- `constructor(options: ApplicationOptions)`

**Example**

```ts
const app = new Application({
  apiClient: {
    baseURL: process.env.API_BASE_URL,
  },
  dynamicImport: (name: string) => {
    return import(`../plugins/${name}`);
  },
});
```

## Methods

### use()

Add Providers, build-in Providers are:

- APIClientProvider
- I18nextProvider
- AntdConfigProvider
- SystemSettingsProvider
- PluginManagerProvider
- SchemaComponentProvider
- SchemaInitializerProvider
- BlockSchemaComponentProvider
- AntdSchemaComponentProvider
- ACLProvider
- RemoteDocumentTitleProvider

### render()

Component to render the App.

```ts
import { Application } from '@nocobase/client';

export const app = new Application({
  apiClient: {
    baseURL: process.env.API_BASE_URL,
  },
  dynamicImport: (name: string) => {
    return import(`../plugins/${name}`);
  },
});

export default app.render();
```

---

## File: docs/en-US/api/client/index.md

# Overview

test

---

## File: docs/en-US/api/client/router.md

# Router

## API

### Initial

```tsx | pure
const app = new Application({
  router: {
    type: 'browser', // type default value is `browser`
  },
});

// or
const app = new Application({
  router: {
    type: 'memory',
    initialEntries: ['/'],
  },
});
```

### add Route

#### basic

```tsx | pure
import { RouteObject } from 'react-router-dom';
const app = new Application();

const Hello = () => {
  return <div>Hello</div>;
};

// first argument is `name` of route, second argument is `RouteObject`
app.router.add('root', {
  path: '/',
  element: <Hello />,
});

app.router.add('root', {
  path: '/',
  Component: Hello,
});
```

#### Component is String

```tsx | pure
app.addComponents({
  Hello,
});
app.router.add('root', {
  path: '/',
  Component: 'Hello',
});
```

#### nested

```tsx | pure
import { Outlet } from 'react-router-dom';

const Layout = () => {
  return (
    <div>
      <Link to="/home">Home</Link>
      <Link to="/about">about</Link>

      <Outlet />
    </div>
  );
};

const Home = () => {
  return <div>Home</div>;
};

const About = () => {
  return <div>About</div>;
};

app.router.add('root', {
  element: <Layout />,
});
app.router.add('root.home', {
  path: '/home',
  element: <Home />,
});
app.router.add('root.about', {
  path: '/about',
  element: <About />,
});
```

It will generate the following routes:

```tsx | pure
{
  element: <Layout />,
  children: [
    {
      path: '/home',
      element: <Home />
    },
    {
      path: '/about',
      element: <About />
    }
  ]
}
```

### remove Route

```tsx | pure
// remove route by name
app.router.remove('root.home');
app.router.remove('hello');
```

#### Router in plugin

```tsx | pure
class MyPlugin extends Plugin {
  async load() {
    // add route
    this.app.router.add('hello', {
      path: '/hello',
      element: <div>hello</div>,
    });

    // remove route
    this.app.router.remove('world');
  }
}
```

## Example

```tsx
/**
 * defaultShowCode: true
 */
import React from 'react';
import { Link, Outlet } from 'react-router-dom';
import { Application } from '@nocobase/client';

const Home = () => <h1>Home</h1>;
const About = () => <h1>About</h1>;

const Layout = () => {
  return (
    <div>
      <div>
        <Link to={'/'}>Home</Link>, <Link to={'/about'}>About</Link>
      </div>
      <Outlet />
    </div>
  );
};

const app = new Application({
  router: {
    type: 'memory',
    initialEntries: ['/'],
  },
});

app.router.add('root', {
  element: <Layout />,
});

app.router.add('root.home', {
  path: '/',
  element: <Home />,
});

app.router.add('root.about', {
  path: '/about',
  element: <About />,
});

export default app.getRootComponent();
```

---

## File: docs/en-US/api/client/extensions/acl.md

# ACL

## Components

### `<ACLProvider />`

### `<ACLRolesCheckProvider />`

### `<ACLCollectionProvider />`

### `<ACLActionProvider />`

### `<ACLCollectionFieldProvider />`

### `<ACLMenuItemProvider />`

## Hooks

### `useACLContext()`

### `useACLRoleContext()`

### `useRoleRecheck()`

---

## File: docs/en-US/api/client/extensions/block-provider.md

# BlockProvider

## Kernel Methods

### ``

### `useBlockRequestContext()`

## Build-in BlockProvider Components

### `<CalendarBlockProvider />`

### ``

### ``

### ``

### `<FormBlockProvider />`

### `<FormFieldProvider />`

### ``

### `<KanbanBlockProvider />`

---

## File: docs/en-US/api/client/extensions/collection-manager.md

# CollectionManager

## Components

### CollectionManagerProvider

```jsx | pure
<CollectionManagerProvider
  interfaces={{}}
  collections={[]}
></CollectionManagerProvider>
```

### CollectionProvider

```jsx | pure
const collection = {
  name: 'tests',
  fields: [
    {
      type: 'string',
      name: 'title',
      interface: 'input',
      uiSchema: {
        type: 'string',
        'x-component': 'Input',
      },
    },
  ],
};
<CollectionProvider collection={collection}></CollectionProvider>;
```

If there is no collection parameter passed in, get the collection from CollectionManagerProvider with the corresponding name.

```jsx | pure
const collections = [
  {
    name: 'tests',
    fields: [
      {
        type: 'string',
        name: 'title',
        interface: 'input',
        uiSchema: {
          type: 'string',
          'x-component': 'Input',
        },
      },
    ],
  },
];
<CollectionManagerProvider collections={collections}>
  <CollectionProvider name={'tests'}></CollectionProvider>
</CollectionManagerProvider>;
```

### CollectionFieldProvider

```jsx | pure
const field = {
  type: 'string',
  name: 'title',
  interface: 'input',
  uiSchema: {
    type: 'string',
    'x-component': 'Input',
  },
};
<CollectionFieldProvider field={field}></CollectionFieldProvider>;
```

If there is no field parameter passed in, get the field from CollectionProvider with the corresponding name.

```jsx | pure
const collection = {
  name: 'tests',
  fields: [
    {
      type: 'string',
      name: 'title',
      interface: 'input',
      uiSchema: {
        type: 'string',
        'x-component': 'Input',
      },
    },
  ],
};
<CollectionProvider collection={collection}>
  <CollectionFieldProvider name={'title'}></CollectionFieldProvider>
</CollectionProvider>;
```

### CollectionField

Universal field component that needs to be used with `<CollectionProvider/>`, but only in schema scenarios. Get the field schema from CollectionProvider with the corresponding name. Extend the configuration via the schema where the CollectionField is located.

```ts
{
  name: 'title',
  'x-decorator': 'FormItem',
  'x-decorator-props': {},
  'x-component': 'CollectionField',
  'x-component-props': {},
  properties: {},
}
```

## Hooks

### useCollectionManager()

Use with `<CollectionManagerProvider/>`.

```jsx | pure
const { collections, get } = useCollectionManager();
```

### useCollection()

Use with `<CollectionProvider/>`.

```jsx | pure
const { name, fields, getField, findField, resource } = useCollection();
```

### useCollectionField()

Use with `<CollectionFieldProvider/>`.

```jsx | pure
const { name, uiSchema, resource } = useCollectionField();
```

The resource needs to be used with `<RecordProvider/>` to provide context of the record of the current data table row.

# CollectionManager

## Components

### CollectionManagerProvider

```jsx | pure
<CollectionManagerProvider
  interfaces={{}}
  collections={[]}
></CollectionManagerProvider>
```

### CollectionProvider

```jsx | pure
const collection = {
  name: 'tests',
  fields: [
    {
      type: 'string',
      name: 'title',
      interface: 'input',
      uiSchema: {
        type: 'string',
        'x-component': 'Input',
      },
    },
  ],
};
<CollectionProvider collection={collection}></CollectionProvider>;
```

If there is no collection parameter passed in, get the collection from CollectionManagerProvider with the corresponding name.

```jsx | pure
const collections = [
  {
    name: 'tests',
    fields: [
      {
        type: 'string',
        name: 'title',
        interface: 'input',
        uiSchema: {
          type: 'string',
          'x-component': 'Input',
        },
      },
    ],
  },
];
<CollectionManagerProvider collections={collections}>
  <CollectionProvider name={'tests'}></CollectionProvider>
</CollectionManagerProvider>;
```

### CollectionFieldProvider

```jsx | pure
const field = {
  type: 'string',
  name: 'title',
  interface: 'input',
  uiSchema: {
    type: 'string',
    'x-component': 'Input',
  },
};
<CollectionFieldProvider field={field}></CollectionFieldProvider>;
```

If there is no field parameter passed in, get the field from CollectionProvider with the corresponding name.

```jsx | pure
const collection = {
  name: 'tests',
  fields: [
    {
      type: 'string',
      name: 'title',
      interface: 'input',
      uiSchema: {
        type: 'string',
        'x-component': 'Input',
      },
    },
  ],
};
<CollectionProvider collection={collection}>
  <CollectionFieldProvider name={'title'}></CollectionFieldProvider>
</CollectionProvider>;
```

### CollectionField

Universal field component that needs to be used with `<CollectionProvider/>`, but only in schema scenarios. Get the field schema from CollectionProvider with the corresponding name. Extend the configuration via the schema where the CollectionField is located.

```ts
{
  name: 'title',
  'x-decorator': 'FormItem',
  'x-decorator-props': {},
  'x-component': 'CollectionField',
  'x-component-props': {},
  properties: {},
}
```

## Hooks

### useCollectionManager()

Use with `<CollectionManagerProvider/>`.

```jsx | pure
const { collections, get } = useCollectionManager();
```

### useCollection()

Use with `<CollectionProvider/>`.

```jsx | pure
const { name, fields, getField, findField, resource } = useCollection();
```

### useCollectionField()

Use with `<CollectionFieldProvider/>`.

```jsx | pure
const { name, uiSchema, resource } = useCollectionField();
```

The resource needs to be used with `<RecordProvider/>` to provide context of the record of the current data table row.

---

## File: docs/en-US/api/client/extensions/schema-component.md

# 适配的 Schema 组件

## Common

- DndContext
- SortableItem

## And Design

- Action
- BlockItem
- Calendar
- CardItem
- Cascader

---

## File: docs/en-US/api/client/schema-designer/schema-component.md

# SchemaComponent

## Core Components

### `<SchemaComponentProvider />`

### `<SchemaComponentOptions>`

### `<SchemaComponent>`

## Core Methods

### `createDesignable()`

### `useDesignable()`

### `useCompile()`

---

## File: docs/en-US/api/client/schema-designer/schema-initializer.md

# SchemaInitializer

Used for the initialization of various schemas. Newly added schema can be inserted anywhere in an existing schema node, including:

```ts
{
  properties: {
    // beforeBegin - Insert in front of the current node
    node1: {
      properties: {
        // afterBegin - Insert in front of the first child node of the current node
        // ...
        // beforeEnd - After the last child node of the current node
      },
    },
    // afterEnd - After the current node
  },
}
```

The core of SchemaInitializer includes `<SchemaInitializer.Button />` and `<SchemaInitializer.Item />` the two components. `<SchemaInitializer.Button />` is used to create the dropdown menu button of schema, and the options of the dropdown menu is `<SchemaInitializer.Item/>`.

### `<SchemaInitializerProvider />`

### `<SchemaInitializer.Button />`

### `<SchemaInitializer.Item/>`

---

## File: docs/en-US/api/client/schema-designer/schema-settings.md

# SchemaSettings

### `<SchemaSettings />`

### `<SchemaSettings.Item />`

### `<SchemaSettings.ItemGroup />`

### `<SchemaSettings.SubMenu />`

### `<SchemaSettings.Divider />`

### `<SchemaSettings.Remove />`

### `<SchemaSettings.SelectItem />`

### `<SchemaSettings.SwitchItem />`

### `<SchemaSettings.ModalItem />`

### `<SchemaSettings.ActionModalItem />`

### `<SchemaSettings.Template />`

### `<SchemaSettings.BlockTitleItem />`

---

## File: docs/en-US/api/data-source-manager/data-source.md

# DataSource (abstract)

The `DataSource` abstract class is used to represent a type of data source, which can be a database, API, etc.

## Members

### collectionManager

The CollectionManager instance of the data source, which needs to implement the [`ICollectionManager`](/api/data-source-manager/i-collection-manager) interface.

### resourceManager

The resourceManager instance of the data source, see: [`resourceManager`](/api/resourcer/resource-manager)

### acl

The ACL instance of the data source, see: [`ACL`](/api/acl/acl)

## API

### constructor()

Constructor, creates a `DataSource` instance.

#### Signature

- `constructor(options: DataSourceOptions)`

### init()

Initialization function, called immediately after `constructor`.

#### Signature

- `init(options: DataSourceOptions)`

### name

#### Signature

- `get name()`

Returns the instance name of the data source.

### middleware()

Gets the middleware of the DataSource, used to mount to the Server to receive requests.

### testConnection()

Static method, called during the test connection operation, can be used for parameter validation, specific logic is implemented by subclasses.

#### Signature

- `static testConnection(options?: any): Promise`

### load()

#### Signature

- `async load(options: any = {})`

The loading operation of the data source, logic is implemented by subclasses.

### createCollectionManager()

#### Signature
- `abstract createCollectionManager(options?: any): ICollectionManager`

Creates a CollectionManager instance for the data source, logic is implemented by subclasses.

### createResourceManager()

Creates a ResourceManager instance for the data source, subclasses can override the implementation, by default creates `ResourceManager` from `@nocobase/resourcer`.

### createACL()

- Creates an ACL instance for the DataSource, subclasses can override the implementation, by default creates `ACL` from `@nocobase/acl`.

---

## File: docs/en-US/api/data-source-manager/i-collection-manager.md

# ICollectionManager

The `ICollectionManager` interface is used to manage `Collection` instances of data sources.

## API

### registerFieldTypes()

Registers the field types in a `Collection`.

#### Signature

- `registerFieldTypes(types: Record<string, any>): void`

### registerFieldInterfaces()

Registers the `Interface` for a `Collection`.

#### Signature

- `registerFieldInterfaces(interfaces: Record<string, any>): void`

### registerCollectionTemplates()

Registers `Collection Templates`.

#### Signature

- `registerCollectionTemplates(templates: Record<string, any>): void`

### registerModels()

Registers `Models`.

#### Signature

- `registerModels(models: Record<string, any>): void`

### registerRepositories()

Registers `Repositories`.

#### Signature

- `registerRepositories(repositories: Record<string, any>): void`

### getRegisteredRepository()

Retrieves an instance of a registered repository.

#### Signature

- `getRegisteredRepository(key: string): IRepository`

### defineCollection()

Defines a `Collection`.

#### Signature

- `defineCollection(options: CollectionOptions): ICollection`

### extendCollection()

Modifies an existing `Collection` property.

#### Signature

- `extendCollection(collectionOptions: CollectionOptions, mergeOptions?: MergeOptions): ICollection`

### hasCollection()

Determines if a `Collection` exists.

#### Signature

- `hasCollection(name: string): boolean`

### getCollection()

Retrieves an instance of a `Collection`.

#### Signature

- `getCollection(name: string): ICollection`

### getCollections()

Retrieves all instances of `Collection`.

#### Signature

- `getCollections(): Array`

### getRepository()

Retrieves an instance of a `Repository`.

#### Signature

- `getRepository(name: string, sourceId?: string | number): IRepository`

### sync()

Synchronizes the data source, with the logic implemented by subclasses.

#### Signature

- `sync(): Promise<void>`

---

## File: docs/en-US/api/data-source-manager/i-collection.md

# ICollection

`ICollection` is an interface for data models, which includes information such as the model's name, fields, associations, etc.

```typescript
export interface ICollection {
  repository: IRepository;

  updateOptions(options: any): void;

  setField(name: string, options: any): IField;

  removeField(name: string): void;

  getFields(): Array<IField>;

  getField(name: string): IField;

  [key: string]: any;
}
```

## Members

### repository

The `Repository` instance to which `ICollection` belongs.

## API

### updateOptions()

Updates the properties of the `Collection`.

#### Signature

- `updateOptions(options: any): void`

### setField()

Sets a field of the `Collection`.

#### Signature

- `setField(name: string, options: any): IField`

### removeField()

Removes a field from the `Collection`.

#### Signature

- `removeField(name: string): void`

### getFields()

Retrieves all fields of the `Collection`.

#### Signature

- `getFields(): Array`

### getField()

Retrieves a field of the `Collection` by name.

#### Signature

- `getField(name: string): IField`

---

## File: docs/en-US/api/data-source-manager/i-field.md

# IField

`IField` defines the interface that fields need to implement.

```typescript
export type FieldOptions = {
  name: string;
  field: string;
  rawType: string;
  type: string;
  description?: string;
  interface?: string;
  uiSchema?: any;
  possibleTypes?: string[];
  defaultValue?: any;
  primaryKey: boolean;
  unique: boolean;
  allowNull?: boolean;
  autoIncrement?: boolean;
  [key: string]: any;
};

export interface IField {
  options: FieldOptions;
}
```


## Properties

### options

- **Type**: `FieldOptions`

---

## File: docs/en-US/api/data-source-manager/i-model.md

# IModel

The `IModel` interface defines the basic properties and methods of a model object.

```typescript
export interface IModel {
  toJSON: () => any;
}
```

## API

### toJSON()

Converts the model object to JSON format.

---

## File: docs/en-US/api/data-source-manager/i-repository.md

# IRepository

The `Repository` interface defines a series of model operation methods for adapting CRUD (Create, Read, Update, Delete) operations on data sources.

## API

### find()

Returns a list of models that match the query parameters.

#### Signature

- `find(options?: any): Promise`

### findOne()

Returns the first model that matches the query parameters. If multiple models match, only the first one is returned.

#### Signature

- `findOne(options?: any): Promise`

### count()

Returns the number of models that match the query parameters.

#### Signature

- `count(options?: any): Promise<Number>`

### findAndCount()

Returns both the list of models and the count of models that match the query parameters.

#### Signature

- `findAndCount(options?: any): Promise<[IModel[], Number]>`

### create()

Creates a model data object.

#### Signature

- `create(options: any): void`

### update()

Updates the model data object based on the query conditions.

#### Signature

- `update(options: any): void`

### destroy()

Deletes the model data object based on the query conditions.

#### Signature

- `destroy(options: any): void`

---

## File: docs/en-US/api/data-source-manager/index.md

# DataSourceManager

`DataSourceManager` is a management class for multiple `dataSource` instances.

## API

### add()
Adds a `dataSource` instance.

#### Signature

- `add(dataSource: DataSource, options: any = {}): Promise<void>`

### use()

Adds a global middleware to the `dataSource` instance.

### middleware()

Retrieves the middleware of the current `dataSourceManager` instance, which can be used to respond to HTTP requests.

### afterAddDataSource()

A hook function that is triggered after a new `dataSource` is added.

#### Signature

- `afterAddDataSource(hook: DataSourceHook)`

```typescript
type DataSourceHook = (dataSource: DataSource) => void;
```

### registerDataSourceType()

Registers the data source type and its class.

#### Signature

- `registerDataSourceType(type: string, dataSourceClass: typeof DataSource)`

### getDataSourceType()

Retrieves the data source class.

#### Signature

- `getDataSourceType(type: string): typeof DataSource`

### buildDataSourceByType()

Creates a data source instance based on the registered data source type and instance parameters.

#### Signature

- `buildDataSourceByType(type: string, options: any): DataSource`

---

## File: docs/en-US/api/database/collection.md

# Collection

## Overview

`Collection` is used to define the data model in the system, such as model name, fields, indexes, associations, and other information. It is usually called through the `collection` method of the `Database` instance as a proxy entry.

```javascript
const { Database } = require('@nocobase/database')

// Create database instance
const db = new Database({...});

// Define data model
db.collection({
  name: 'users',
  // Define model fields
  fields: [
    // Scalar field
    {
      name: 'name',
      type: 'string',
    },

    // Association field
    {
      name: 'profile',
      type: 'hasOne' // 'hasMany', 'belongsTo', 'belongsToMany'
    }
  ],
});
```

Refer to [Fields](/api/database/field) for more field types.

## Constructor

**Signature**

- `constructor(options: CollectionOptions, context: CollectionContext)`

**Parameter**

| Name                  | Type                                                        | Default | Description                                                                                                               |
| --------------------- | ----------------------------------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------- |
| `options.name`        | `string`                                                    | -       | Identifier of the collection                                                                                              |
| `options.tableName?`  | `string`                                                    | -       | Database table name, the value of `options.name` is used if not set                                                       |
| `options.fields?`     | `FieldOptions[]`                                            | -       | Definition of fields, refer to [Field](./field) for details                                                               |
| `options.model?`      | `string \| ModelStatic<Model>`                              | -       | Model type of Sequelize; in case `string` is used, this model name needs to be registered in the db before being called   |
| `options.repository?` | `string \| RepositoryType`                                  | -       | Data repository type; in case `string` is used, this repository type needs to be registered in the db before being called |
| `options.sortable?`   | `string \| boolean \| { name?: string; scopeKey?: string }` | -       | Configure which fields are sortable; not sortable by default                                                              |
| `options.autoGenId?`  | `boolean`                                                   | `true`  | Whether to automatically generate unique primary key; `true` by default                                                   |
| `context.database`    | `Database`                                                  | -       | The context database in which it resides                                                                                  |

**Example**

Create a table *posts*:

```ts
const posts = new Collection(
  {
    name: 'posts',
    fields: [
      {
        type: 'string',
        name: 'title',
      },
      {
        type: 'double',
        name: 'price',
      },
    ],
  },
  {
    // An existing database instance
    database: db,
  },
);
```

## Instance Members

### `options`

Initial parameters for data table configuration, which are consistent with the `options` parameter of the constructor.

### `context`

The contextual environment to which the current data table belongs, currently mainly the database instance.

### `name`

Name of the data table.

### `db`

The database instance to which it belongs.

### `filterTargetKey`

Name of the field that is used as the primary key.

### `isThrough`

Whether it is an intermediate table.

### `model`

Match the Model type of Sequelize.

### `repository`

Data repository instance.

## Field Configuration Methods

### `getField()`

Get a field object whose corresponding name has been defined in the data table.

**Signature**

- `getField(name: string): Field`

**Parameter**

| Name   | Type     | Default | Description       |
| ------ | -------- | ------- | ----------------- |
| `name` | `string` | -       | Name of the field |

**Example**

```ts
const posts = db.collection({
  name: 'posts',
  fields: [
    {
      type: 'string',
      name: 'title',
    },
  ],
});

const field = posts.getField('title');
```

### `setField()`

Set a field to the data table.

**Signature**

- `setField(name: string, options: FieldOptions): Field`

**Parameter**

| Name      | Type           | Default | Description                                                       |
| --------- | -------------- | ------- | ----------------------------------------------------------------- |
| `name`    | `string`       | -       | Name of the field                                                 |
| `options` | `FieldOptions` | -       | Configuration of the field, refer to [Field](./field) for details |

**Example**

```ts
const posts = db.collection({ name: 'posts' });

posts.setField('title', { type: 'string' });
```

### `setFields()`

Set multiple fields to the data table.

**Signature**

- `setFields(fields: FieldOptions[], resetFields = true): Field[]`

**Parameter**

| Name          | Type             | Default | Description                                                        |
| ------------- | ---------------- | ------- | ------------------------------------------------------------------ |
| `fields`      | `FieldOptions[]` | -       | Configuration of the fields, refer to [Field](./field) for details |
| `resetFields` | `boolean`        | `true`  | Whether to reset existing fields                                   |

**Example**

```ts
const posts = db.collection({ name: 'posts' });

posts.setFields([
  { type: 'string', name: 'title' },
  { type: 'double', name: 'price' },
]);
```

### `removeField()`

Remove a field object whose corresponding name has been defined in the data table.

**Signature**

- `removeField(name: string): void | Field`

**Parameter**

| Name   | Type     | Default | Description       |
| ------ | -------- | ------- | ----------------- |
| `name` | `string` | -       | Name of the field |

**Example**

```ts
const posts = db.collection({
  name: 'posts',
  fields: [
    {
      type: 'string',
      name: 'title',
    },
  ],
});

posts.removeField('title');
```

### `resetFields()`

Reset (Empty) fields of the data table.

**Signature**

- `resetFields(): void`

**Example**

```ts
const posts = db.collection({
  name: 'posts',
  fields: [
    {
      type: 'string',
      name: 'title',
    },
  ],
});

posts.resetFields();
```

### `hasField()`

Check if the data table has defined a field object with the corresponding name.

**Signature**

- `hasField(name: string): boolean`

**Parameter**

| Name   | Type     | Default | Description       |
| ------ | -------- | ------- | ----------------- |
| `name` | `string` | -       | Name of the field |

**Example**

```ts
const posts = db.collection({
  name: 'posts',
  fields: [
    {
      type: 'string',
      name: 'title',
    },
  ],
});

posts.hasField('title'); // true
```

### `findField()`

Find field objects in the data table that match the conditions.

**Signature**

- `findField(predicate: (field: Field) => boolean): Field | undefined`

**Parameter**

| Name        | Type                        | Default | Description   |
| ----------- | --------------------------- | ------- | ------------- |
| `predicate` | `(field: Field) => boolean` | -       | The condition |

**Example**

```ts
const posts = db.collection({
  name: 'posts',
  fields: [
    {
      type: 'string',
      name: 'title',
    },
  ],
});

posts.findField((field) => field.name === 'title');
```

### `forEachField()`

Iterate over field objects in the data table.

**Signature**

- `forEachField(callback: (field: Field) => void): void`

**Parameter**

| Name       | Type                     | Default | Description       |
| ---------- | ------------------------ | ------- | ----------------- |
| `callback` | `(field: Field) => void` | -       | Callback function |

**Example**

```ts
const posts = db.collection({
  name: 'posts',
  fields: [
    {
      type: 'string',
      name: 'title',
    },
  ],
});

posts.forEachField((field) => console.log(field.name));
```

## Index Configuration Methods

### `addIndex()`

Add data table index.

**Signature**

- `addIndex(index: string | string[] | { fields: string[], unique?: boolean,[key: string]: any })`

**Parameter**

| Name    | Type                                                         | Default | Description                   |
| ------- | ------------------------------------------------------------ | ------- | ----------------------------- |
| `index` | `string \| string[]`                                         | -       | Names of fields to be indexed |
| `index` | `{ fields: string[], unique?: boolean, [key: string]: any }` | -       | Full configuration            |

**Example**

```ts
const posts = db.collection({
  name: 'posts',
  fields: [
    {
      type: 'string',
      name: 'title',
    },
  ],
});

posts.addIndex({
  fields: ['title'],
  unique: true,
});
```

### `removeIndex()`

Remove data table index.

**Signature**

- `removeIndex(fields: string[])`

**Parameter**

| Name     | Type       | Default | Description                       |
| -------- | ---------- | ------- | --------------------------------- |
| `fields` | `string[]` | -       | Names of fields to remove indexes |

**Example**

```ts
const posts = db.collection({
  name: 'posts',
  fields: [
    {
      type: 'string',
      name: 'title',
    },
  ],
  indexes: [
    {
      fields: ['title'],
      unique: true,
    },
  ],
});

posts.removeIndex(['title']);
```

## Table Configuration Methods

### `remove()`

Remove data table.

**Signature**

- `remove(): void`

**Example**

```ts
const posts = db.collection({
  name: 'posts',
  fields: [
    {
      type: 'string',
      name: 'title',
    },
  ],
});

posts.remove();
```

## Database Operation Methods

### `sync()`

Synchronize the definitions in data table to the database. In addition to the default `Model.sync` logic in Sequelize, the data tables corresponding to the relational fields will also be handled together.

**Signature**

- `sync(): Promise<void>`

**Example**

```ts
const posts = db.collection({
  name: 'posts',
  fields: [
    {
      type: 'string',
      name: 'title',
    },
  ],
});

await posts.sync();
```

### `existsInDb()`

Check whether the data table exists in the database.

**Signature**

- `existsInDb(options?: Transactionable): Promise`

**Parameter**

| Name                   | Type          | Default | Description          |
| ---------------------- | ------------- | ------- | -------------------- |
| `options?.transaction` | `Transaction` | -       | Transaction instance |

**Example**

```ts
const posts = db.collection({
  name: 'posts',
  fields: [
    {
      type: 'string',
      name: 'title',
    },
  ],
});

const existed = await posts.existsInDb();

console.log(existed); // false
```

### `removeFromDb()`

**Signature**

- `removeFromDb(): Promise<void>`

**Example**

```ts
const books = db.collection({
  name: 'books',
});

//  Synchronize the table books to the database
await db.sync();

// Remove the table books from the database
await books.removeFromDb();
```

---

## File: docs/en-US/api/database/field.md

# Field

## Overview

Data table field management class (abstract class). It is also the base class for all field types, and any other field types are implemented by inheriting from this class.

Refer to [Extended Field Types](/development/server/collections-fields#extended-field-types) to see how to customize fields.

## Constructor

It is usually not called directly by the developer, but mainly through the `db.collection({ fields: [] })` method as a proxy entry.

Extended field is implemented mainly by inheriting the `Field` abstract class and registering it to a Database instance.

**Signature**

- `constructor(options: FieldOptions, context: FieldContext)`

**Parameter**

| Name                 | Type           | Default | Description                                                                  |
| -------------------- | -------------- | ------- | ---------------------------------------------------------------------------- |
| `options`            | `FieldOptions` | -       | Field configuration object                                                   |
| `options.name`       | `string`       | -       | Field name                                                                   |
| `options.type`       | `string`       | -       | Field type, corresponding to the name of the field type registered in the db |
| `context`            | `FieldContext` | -       | Field context object                                                         |
| `context.database`   | `Database`     | -       | Database instance                                                            |
| `context.collection` | `Collection`   | -       | Data table instance                                                          |

## Instance Members

### `name`

Field name.

### `type`

Field type.

### `dataType`

Data type of the field.

### `options`

Configuration parameters to initialize the field.

### `context`

Field context object.

## Configuration Methods

### `on()`

Quick definition method based on data table events. It is equivalent to `db.on(this.collection.name + '.' + eventName, listener)`.

It is usually not necessary to override this method when inheriting.

**Signature**

- `on(eventName: string, listener: (...args: any[]) => void)`

**Parameter**

| Name        | Type                       | Default | Description    |
| ----------- | -------------------------- | ------- | -------------- |
| `eventName` | `string`                   | -       | Event name     |
| `listener`  | `(...args: any[]) => void` | -       | Event listener |

### `off()`

Quick removal method based on data table events. It is equivalent to `db.off(this.collection.name + '.' + eventName, listener)`.

It is usually not necessary to override this method when inheriting.

**Signature**

- `off(eventName: string, listener: (...args: any[]) => void)`

**Parameter**

| Name        | Type                       | Default | Description    |
| ----------- | -------------------------- | ------- | -------------- |
| `eventName` | `string`                   | -       | Event name     |
| `listener`  | `(...args: any[]) => void` | -       | Event listener |

### `bind()`

The execution content that is triggered when a field is added to data table. Typically used to add data table event listeners and other processing.

The corresponding `super.bind()` method needs to be called first when inheriting.

**Signature**

- `bind()`

### `unbind()`

The execution content that is triggered when a field is removed from data table. Typically used to remove data table event listeners and other processing.

The corresponding `super.unbind()` method needs to be called first when inheriting.

**Signature**

- `unbind()`

### `get()`

Get the values of a configuration item of the field.

**Signature**

- `get(key: string): any`

**Parameter**

| Name  | Type     | Default | Description                    |
| ----- | -------- | ------- | ------------------------------ |
| `key` | `string` | -       | Name of the configuration item |

**Example**

```ts
const field = db.collection('users').getField('name');

// Get and return the values of the configuration item 'name'
console.log(field.get('name'));
```

### `merge()`

Merge the values of a configuration item of the field.

**Signature**

- `merge(options: { [key: string]: any }): void`

**Parameter**

| Name      | Type                     | Default | Description                     |
| --------- | ------------------------ | ------- | ------------------------------- |
| `options` | `{ [key: string]: any }` | -       | The configuration item to merge |

**Example**

```ts
const field = db.collection('users').getField('name');

field.merge({
  // Add an index configuration
  index: true,
});
```

### `remove()`

Remove a field from data table (from memory only).

**Example**

```ts
const books = db.getCollections('books');

books.getField('isbn').remove();

// really remove from db
await books.sync();
```

## Database Methods

### `removeFromDb()`

Remove a field from the database.

**Signature**

- `removeFromDb(options?: Transactionable): Promise<void>`

**Parameter**

| Name                   | Type          | Default | Description          |
| ---------------------- | ------------- | ------- | -------------------- |
| `options.transaction?` | `Transaction` | -       | Transaction instance |

### `existsInDb()`

Check if a field exists in the database.

**Signature**

- `existsInDb(options?: Transactionable): Promise`

**Parameter**

| Name                   | Type          | Default | Description          |
| ---------------------- | ------------- | ------- | -------------------- |
| `options.transaction?` | `Transaction` | -       | Transaction instance |

## Built-in Field Types

NocoBase has some built-in common field types, the corresponding type name can be used directly to specify the type of field upon definition. Fields of different types are configured differently, please refer to the list below.

The configuration items of all field types are passed through to Sequelize in addition to those described below. Therefore, all field configuration items supported by Sequelize can be used here (e.g. `allowNull`, `defaultValue`, etc.).

Moreover, server-side field types are mainly used for solving the problems of database storage and some algorithms, they are barely relevant to the field display types and the use of components in front-end. The front-end field types can be found in the corresponding tutorials.

### `'boolean'`

Boolean type.

**Example**

```js
db.collection({
  name: 'books',
  fields: [
    {
      type: 'boolean',
      name: 'published',
    },
  ],
});
```

### `'integer'`

Integer type (32 bits).

**Example**

```ts
db.collection({
  name: 'books',
  fields: [
    {
      type: 'integer',
      name: 'pages',
    },
  ],
});
```

### `'bigInt'`

Long integer type (64 bits).

**Example**

```ts
db.collection({
  name: 'books',
  fields: [
    {
      type: 'bigInt',
      name: 'words',
    },
  ],
});
```

### `'double'`

Double-precision floating-point format (64 bits).

**Example**

```ts
db.collection({
  name: 'books',
  fields: [
    {
      type: 'double',
      name: 'price',
    },
  ],
});
```

### `'real'`

Real type (PG only).

### `'decimal'`

Decimal type.

### `'string'`

String type. Equivalent to the `VARCHAR` type for most databases.

**Example**

```ts
db.collection({
  name: 'books',
  fields: [
    {
      type: 'string',
      name: 'title',
    },
  ],
});
```

### `'text'`

Text type. Equivalent to the `TEXT` type for most databases.

**Example**

```ts
db.collection({
  name: 'books',
  fields: [
    {
      type: 'text',
      name: 'content',
    },
  ],
});
```

### `'password'`

Password type (NocoBase extension). Password encryption based on the `scrypt` method of Node.js native crypto packages.

**Example**

```ts
db.collection({
  name: 'users',
  fields: [
    {
      type: 'password',
      name: 'password',
      length: 64, // Length, default is 64
      randomBytesSize: 8, // Length of random bytes, default is 8
    },
  ],
});
```

**Parameter**

| Name              | Type     | Default | Description            |
| ----------------- | -------- | ------- | ---------------------- |
| `length`          | `number` | 64      | Length of characters   |
| `randomBytesSize` | `number` | 8       | Length of random bytes |

### `'date'`

Date type.

### `'time'`

Time type.

### `'array'`

Array type (PG only).

### `'json'`

JSON type.

### `'jsonb'`

JSONB type (PG only, others will be compatible with the `'json'` type).

### `'uuid'`

UUID type.

### `'uid'`

UID type (NocoBase extension). Short random string identifier type.

### `'formula'`

Formula type (NocoBase extension). Mathematical formula calculation can be configured based on [mathjs](https://www.npmjs.com/package/mathjs), and the formula can refer to the values of other columns in the same record to participate in the calculation.

**Example**

```ts
db.collection({
  name: 'orders',
  fields: [
    {
      type: 'double',
      name: 'price',
    },
    {
      type: 'integer',
      name: 'quantity',
    },
    {
      type: 'formula',
      name: 'total',
      expression: 'price * quantity',
    },
  ],
});
```

### `'radio'`

Radio type (NocoBase extension). The field value is 'true' for at most one row of data for the full table, all others are 'false' or 'null'.

**Example**

There is only one user marked as *root* in the entire system, once the *root* value of any other user is changed to `true`, all other records with *root* of `true` will be changed to `false`:

```ts
db.collection({
  name: 'users',
  fields: [
    {
      type: 'radio',
      name: 'root',
    },
  ],
});
```

### `'sort'`

Sorting type (NocoBase extension). Sorting based on integer numbers, automatically generating new serial numbers for new records, and rearranging serial numbers when moving data.

If data table has the `sortable` option defined, the corresponding fields will be generated automatically.

**Example**

Posts are sortable based on the users they belong to.

```ts
db.collection({
  name: 'posts',
  fields: [
    {
      type: 'belongsTo',
      name: 'user',
    },
    {
      type: 'sort',
      name: 'priority',
      scopeKey: 'userId', // Sort data grouped by the values of userId
    },
  ],
});
```

### `'virtual'`

Virtual type. No Data is actually stored, it is used only when special getter/setter is defined.

### `'belongsTo'`

Many-to-one association type. Foreign key is stored in its own table, as opposed to `'hasOne'`/`'hasMany'`.

**Example**

Any post belongs to an author:

```ts
db.collection({
  name: 'posts',
  fields: [
    {
      type: 'belongsTo',
      name: 'author',
      target: 'users', // Default table name is the plural form of <name>
      foreignKey: 'authorId', // Default is '<name> + Id'
      sourceKey: 'id', // Default is id of the <target> table
    },
  ],
});
```

### `'hasOne'`

One-to-one association type. Foreign key is stored in the association table, as opposed to `'belongsTo'`.

**Example**

Any user has a profile:

```ts
db.collection({
  name: 'users',
  fields: [
    {
      type: 'hasOne',
      name: 'profile',
      target: 'profiles', // Can be omitted
    },
  ],
});
```

### `'hasMany'`

One-to-many association type. The foreign key is stored in the association table, as opposed to `'belongsTo'`.

**Example**

Any user can have multiple posts:

```ts
db.collection({
  name: 'users',
  fields: [
    {
      type: 'hasMany',
      name: 'posts',
      foreignKey: 'authorId',
      sourceKey: 'id',
    },
  ],
});
```

### `'belongsToMany'`

Many-to-many association type. Intermediate table is used to store both foreign keys. If no existing table is specified as intermediate table, it will be created automatically.

**Example**

Any post can have multiple tags added to it, and any tag can be added to multiple posts:

```ts
db.collection({
  name: 'posts',
  fields: [
    {
      type: 'belongsToMany',
      name: 'tags',
      target: 'tags', // Can be omitted if name is the same
      through: 'postsTags', // Intermediate table will be generated automatically if not specified
      foreignKey: 'postId', // Foreign key in the intermediate table referring to the table itself
      sourceKey: 'id', // Primary key of the table itself
      otherKey: 'tagId', // Foreign key in the intermediate table referring to the association table
    },
  ],
});

db.collection({
  name: 'tags',
  fields: [
    {
      type: 'belongsToMany',
      name: 'posts',
      through: 'postsTags', // Refer to the same intermediate table in the same set of relation
    },
  ],
});
```

---

## File: docs/en-US/api/database/index.md

# Database

## Overview

Database is the database interaction tool provided by NocoBase, it provides very convenient database interaction features for no-code and low-code applications. The supported databases are:

- SQLite 3.8.8+
- MySQL 8.0.17+
- PostgreSQL 10.0+

### Connect to Database

In `Database` constructor, database connection can be configured by passing the `options` parameter.

```javascript
const { Database } = require('@nocobase/database');

// MySQL database configuration parameters
const database = new Database({
  dialect: 'mysql',
  host: 'localhost',
  port: 3306,
  database: 'nocobase',
  username: 'root',
  password: 'password'
})

// MySQL \ PostgreSQL database configuration parameters
const database = new Database({
  dialect: /* 'postgres' or 'mysql' */,
  database: 'database',
  username: 'username',
  password: 'password',
  host: 'localhost',
  port: 'port'
})

```

Refer to [Constructor](#constructor) for detailed configurations.

### Define Data Structure

`Database` defines database structure through `Collection`, one `Collection` object represents one table in the database.

```javascript
// Define Collection
const UserCollection = database.collection({
  name: 'users',
  fields: [
    {
      name: 'name',
      type: 'string',
    },
    {
      name: 'age',
      type: 'integer',
    },
  ],
});
```

After the database structure is defined, use `sync()` method to synchronize the database structure.

```javascript
await database.sync();
```

Refer to [Collection](/api/database/collection) for detailed usage of `Collection`.

### CRUD Data

`Database` operates data through `Repository`.

```javascript
const UserRepository = UserCollection.repository();

// Create
await UserRepository.create({
  name: 'Mark',
  age: 18,
});

// Query
const user = await UserRepository.findOne({
  filter: {
    name: 'Mark',
  },
});

// Update
await UserRepository.update({
  values: {
    age: 20,
  },
});

// Delete
await UserRepository.destroy(user.id);
```

Refer to [Repository](/api/database/repository) for details of data CRUD.

## Constructor

**Signature**

- `constructor(options: DatabaseOptions)`

Create a database instance.

**Parameter**

| Name                   | Type           | Default       | Description                                                                                                                                         |
| ---------------------- | -------------- | ------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| `options.host`         | `string`       | `'localhost'` | Database host                                                                                                                                       |
| `options.port`         | `number`       | -             | Database service port, default port depends on the type of database used                                                                            |
| `options.username`     | `string`       | -             | Database username                                                                                                                                   |
| `options.password`     | `string`       | -             | Database password                                                                                                                                   |
| `options.database`     | `string`       | -             | Database name                                                                                                                                       |
| `options.dialect`      | `string`       | `'mysql'`     | Database type                                                                                                                                       |
| `options.storage?`     | `string`       | `':memory:'`  | Storage mode for SQLite                                                                                                                             |
| `options.logging?`     | `boolean`      | `false`       | Whether to enable logging                                                                                                                           |
| `options.define?`      | `Object`       | `{}`          | Default table definition parameters                                                                                                                 |
| `options.tablePrefix?` | `string`       | `''`          | NocoBase extension, table prefix                                                                                                                    |
| `options.migrator?`    | `UmzugOptions` | `{}`          | NocoBase extension, parameters for migrator, refer to [Umzug](https://github.com/sequelize/umzug/blob/main/src/types.ts#L15) for the implementation |

## Migration Methods

### `addMigration()`

Add single migration file.

**Signature**

- `addMigration(options: MigrationItem)`

**Parameter**

| Name                 | Type               | Default | Description                         |
| -------------------- | ------------------ | ------- | ----------------------------------- |
| `options.name`       | `string`           | -       | Name of the migration file          |
| `options.context?`   | `string`           | -       | Context of the migration file       |
| `options.migration?` | `typeof Migration` | -       | Custom type of the migration file   |
| `options.up`         | `Function`         | -       | `up` method of the migration file   |
| `options.down`       | `Function`         | -       | `down` method of the migration file |

**Example**

```ts
db.addMigration({
  name: '20220916120411-test-1',
  async up() {
    const queryInterface = this.context.db.sequelize.getQueryInterface();
    await queryInterface.query(/* your migration sqls */);
  },
});
```

### `addMigrations()`

Add the migration files in the specified directory.

**Signature**

- `addMigrations(options: AddMigrationsOptions): void`

**Parameter**

| Name                 | Type       | Default        | Description                                     |
| -------------------- | ---------- | -------------- | ----------------------------------------------- |
| `options.directory`  | `string`   | `''`           | Directory where the migration files are located |
| `options.extensions` | `string[]` | `['js', 'ts']` | File extensions                                 |
| `options.namespace?` | `string`   | `''`           | Namespace                                       |
| `options.context?`   | `Object`   | `{ db }`       | Context of the migration files                  |

**Example**

```ts
db.addMigrations({
  directory: path.resolve(__dirname, './migrations'),
  namespace: 'test',
});
```

## Tool Methods

### `inDialect()`

Check whether the current database type is the specified type.

**Signature**

- `inDialect(dialect: string[]): boolean`

**Parameter**

| Name      | Type       | Default | Description                                                 |
| --------- | ---------- | ------- | ----------------------------------------------------------- |
| `dialect` | `string[]` | -       | Database type, options are `mysql`, `postgres` and `mariadb` |

### `getTablePrefix()`

Get the table name prefix in the configuration.

**Signature**

- `getTablePrefix(): string`

## Data Table Configurations

### `collection()`

Define a data table. This is like the `define` method of Sequelize, which only creates table structure in memory. Call the `sync` method if needs to be persisted to the database.

**Signature**

- `collection(options: CollectionOptions): Collection`

**Parameter**

All configuration parameters of `options` is consistent with the constructor of the `Collection` class, refer to [Collection](/api/database/collection#Constructor).

**Event**

- `'beforeDefineCollection'`: Trigger before defining the table.
- `'afterDefineCollection'`: Trigger after defining the table.

**Example**

```ts
db.collection({
  name: 'books',
  fields: [
    {
      type: 'string',
      name: 'title',
    },
    {
      type: 'float',
      name: 'price',
    },
  ],
});

// sync collection as table to db
await db.sync();
```

### `getCollection()`

Get a defined data table.

**Signature**

- `getCollection(name: string): Collection`

**Parameter**

| Name   | Type     | Default | Description |
| ------ | -------- | ------- | ----------- |
| `name` | `string` | -       | Table name  |

**Example**

```ts
const collection = db.getCollection('books');
```

### `hasCollection()`

Check whether a specified data table is defined.

**Signature**

- `hasCollection(name: string): boolean`

**Parameter**

| Name   | Type     | Default | Description |
| ------ | -------- | ------- | ----------- |
| `name` | `string` | -       | Table name  |

**Example**

```ts
db.collection({ name: 'books' });

db.hasCollection('books'); // true

db.hasCollection('authors'); // false
```

### `removeCollection()`

Remove a defined data table. It is to remove from memory only, call the `sync` method if needs to be persisted to the database.

**Signature**

- `removeCollection(name: string): void`

**Parameter**

| Name   | Type     | Default | Description |
| ------ | -------- | ------- | ----------- |
| `name` | `string` | -       | Table name  |

**Event**

- `'beforeRemoveCollection'`: Trigger before removing the table.
- `'afterRemoveCollection'`: Trigger after removing the table

**Example**

```ts
db.collection({ name: 'books' });

db.removeCollection('books');
```

### `import()`

Load all files in the import file directory into memory as the configuration of collection.

**Signature**

- `async import(options: { directory: string; extensions?: ImportFileExtension[] }): Promise<Map<string, Collection>>`

**Parameter**

| Name                 | Type       | Default        | Description                      |
| -------------------- | ---------- | -------------- | -------------------------------- |
| `options.directory`  | `string`   | -              | Path of directory to be imported |
| `options.extensions` | `string[]` | `['ts', 'js']` | Scan for specific suffixes       |

**Example**

The collection defined by file `./collections/books.ts` is as below:

```ts
export default {
  name: 'books',
  fields: [
    {
      type: 'string',
      name: 'title',
    },
  ],
};
```

Import the relevant configurations when loading the plugin:

```ts
class Plugin {
  async load() {
    await this.app.db.import({
      directory: path.resolve(__dirname, './collections'),
    });
  }
}
```

## Extension Registrations and Acquisitions

### `registerFieldTypes()`

Register custom field type.

**Signature**

- `registerFieldTypes(fieldTypes: MapOf<typeof Field>): void`

**Parameter**

`fieldTypes` is a key-value pair, where key is the field type name, and value is the field type class.

**Example**

```ts
import { Field } from '@nocobase/database';

class MyField extends Field {
  // ...
}

db.registerFieldTypes({
  myField: MyField,
});
```

### `registerModels()`

Register custom data model class.

**Signature**

- `registerModels(models: MapOf<ModelStatic<any>>): void`

**Parameter**

`models` is a key-value pair, where key is the data model name, and value is the data model class.

**Example**

```ts
import { Model } from '@nocobase/database';

class MyModel extends Model {
  // ...
}

db.registerModels({
  myModel: MyModel,
});

db.collection({
  name: 'myCollection',
  model: 'myModel',
});
```

### `registerRepositories()`

Register custom data repository class.

**Signature**

- `registerRepositories(repositories: MapOf<RepositoryType>): void`

**Parameter**

`repositories` is a key-value pair, where key is the data repository name, and value is the data repository class.

**Example**

```ts
import { Repository } from '@nocobase/database';

class MyRepository extends Repository {
  // ...
}

db.registerRepositories({
  myRepository: MyRepository,
});

db.collection({
  name: 'myCollection',
  repository: 'myRepository',
});
```

### `registerOperators()`

Register custom data query operator.

**Signature**

- `registerOperators(operators: MapOf<OperatorFunc>)`

**Parameter**

`operators` is a key-value pair, where key is the operator name, and value is the generating function of the comparison operator statement.

**Example**

```ts
db.registerOperators({
  $dateOn(value) {
    return {
      [Op.and]: [
        { [Op.gte]: stringToDate(value) },
        { [Op.lt]: getNextDay(value) },
      ],
    };
  },
});

db.getRepository('books').count({
  filter: {
    createdAt: {
      // registered operator
      $dateOn: '2020-01-01',
    },
  },
});
```

### `getModel()`

Get the defined data model class. If no custom model class has been registered before, the default model class of Sequelize will be returned. The default name is the same as the name defined by collection.

**Signature**

- `getModel(name: string): Model`

**Parameter**

| Name   | Type     | Default | Description           |
| ------ | -------- | ------- | --------------------- |
| `name` | `string` | -       | Registered model name |

**Example**

```ts
db.registerModels({
  books: class MyModel extends Model {},
});

const ModelClass = db.getModel('books');

console.log(ModelClass.prototype instanceof MyModel); // true
```

Note: The model class retrieved from collection is not strictly equivalent to the model class at registration, but is inherited from the model class at registration. Since the properties of Sequelize's model class are modified during initialization, NocoBase automatically handles this inheritance relationship. All the definitions work fine except that the classes are not equal.

### `getRepository()`

Get the defined data repository class. If no custom data repository class has been registered before, the default data repository class of NocoBase will be returned. The default name is the same as the name defined by collection.

Data repository class is mainly used for the CRUD operations based on data model, refer to [Repository](/api/database/repository).

**Signature**

- `getRepository(name: string): Repository`
- `getRepository(name: string, relationId?: string | number): Repository`

**Parameter**

| Name         | Type                 | Default | Description                           |
| ------------ | -------------------- | ------- | ------------------------------------- |
| `name`       | `string`             | -       | Registered data repository name       |
| `relationId` | `string` \| `number` | -       | Foreign key value for relational data |

When the name contains relationship in the form of `'tables.relactions'`, the related data repository class is returned. If the second parameter is provided, the data repository will be used (query, modify, etc.) based on the foreign key values of the relational data.

**Example**

Suppose there are two data tables *posts* and *authors*, and there is a foreign key in the *posts* table points to the *authors* table:

```ts
const AuthorsRepo = db.getRepository('authors');
const author1 = AuthorsRepo.create({ name: 'author1' });

const PostsRepo = db.getRepository('authors.posts', author1.id);
const post1 = AuthorsRepo.create({ title: 'post1' });
asset(post1.authorId === author1.id); // true
```

## Database Events

### `on()`

Listen for database events.

**Signature**

- `on(event: string, listener: (...args: any[]) => void | Promise<void>): void`

**Parameter**

| Name     | Type     | Default | Description    |
| -------- | -------- | ------- | -------------- |
| event    | string   | -       | Event name     |
| listener | Function | -       | Event listener |

Event name supports Model event of Sequelize by default. Global event is listened to by the name `<sequelize_model_global_event>`, single Model event is listened to by the name `<model_name>. <sequelize_model_event>`.

Refer to the [Built-in Events](#built-in-events) section for parameter descriptions and detailed examples of all built-in event types.

### `off()`

Remove the event listener function.

**Signature**

- `off(name: string, listener: Function)`

**Parameter**

| Name     | Type     | Default | Description    |
| -------- | -------- | ------- | -------------- |
| name     | string   | -       | Event name     |
| listener | Function | -       | Event listener |

**Example**

```ts
const listener = async (model, options) => {
  console.log(model);
};

db.on('afterCreate', listener);

db.off('afterCreate', listener);
```

## Database Operations

### `auth()`

Database connection verification. It can be used to ensure that the application has established connection to the data.

**Signature**

- `auth(options: QueryOptions & { retry?: number } = {}): Promise`

**Parameter**

| Name                   | Type                  | Default | Description                                       |
| ---------------------- | --------------------- | ------- | ------------------------------------------------- |
| `options?`             | `Object`              | -       | Verification option                               |
| `options.retry?`       | `number`              | `10`    | Number of retries in case of verification failure |
| `options.transaction?` | `Transaction`         | -       | Transaction object                                |
| `options.logging?`     | `boolean \| Function` | `false` | Whether to print the log                          |

**Example**

```ts
await db.auth();
```

### `reconnect()`

Reconnect to the database.

**Example**

```ts
await db.reconnect();
```

### `closed()`

Check whether database has closed the connection.

**Signature**

- `closed(): boolean`

### `close()`

Closes database connection. Equivalent to `sequelize.close()`.

### `sync()`

Synchronizes database table structure. Equivalent to `sequelize.sync()`, refer to [Sequelize documentation](https://sequelize.org/api/v6/class/src/sequelize.js~sequelize#instance-method-sync) for parameters.

### `clean()`

Empty the database, it will delete all data tables.

**Signature**

- `clean(options: CleanOptions): Promise<void>`

**Parameter**

| Name                  | Type          | Default | Description                       |
| --------------------- | ------------- | ------- | --------------------------------- |
| `options.drop`        | `boolean`     | `false` | Whether to remove all data tables |
| `options.skip`        | `string[]`    | -       | Names of tables to skip           |
| `options.transaction` | `Transaction` | -       | Transaction object                |

**Example**

Remove all tables except for the `users` table.

```ts
await db.clean({
  drop: true,
  skip: ['users'],
});
```

## Package-Level Export

### `defineCollection()`

Create the configuration content of a data table.

**Signature**

- `defineCollection(name: string, config: CollectionOptions): CollectionOptions`

**Parameter**

| Name                | Type                | Default | Description                                        |
| ------------------- | ------------------- | ------- | -------------------------------------------------- |
| `collectionOptions` | `CollectionOptions` | -       | All parameters are the same with `db.collection()` |

**Example**

For the data table configuration file to be imported by `db.import()`:

```ts
import { defineCollection } from '@nocobase/database';

export default defineCollection({
  name: 'users',
  fields: [
    {
      type: 'string',
      name: 'name',
    },
  ],
});
```

### `extendCollection()`

Extent the configuration content of a data table that is already in memory, mainly for the content of files imported by the `import()` method. This is the top-level package export method of `@nocobase/database`, and is not called through db instance. The `extend` alias can also be used.

**Signature**

- `extendCollection(collectionOptions: CollectionOptions, mergeOptions?: MergeOptions): ExtendedCollectionOptions`

**Parameter**

| Name                | Type                | Default | Description                                                             |
| ------------------- | ------------------- | ------- | ----------------------------------------------------------------------- |
| `collectionOptions` | `CollectionOptions` | -       | All the same with `db.collection()`                                     |
| `mergeOptions?`     | `MergeOptions`      | -       | [deepmerge](https://npmjs.com/package/deepmerge) options of npm package |

**Example**

Original definition of the table *books* (books.ts):

```ts
export default {
  name: 'books',
  fields: [{ name: 'title', type: 'string' }],
};
```

Extend the definition of the table *books* (books.extend.ts):

```ts
import { extend } from '@nocobase/database';

// Extend again
export default extend({
  name: 'books',
  fields: [{ name: 'price', type: 'number' }],
});
```

If the above two files are imported when calling `import()`, after being extended again by `extend()`, the table *books* will have `title` and `price` two fields.

This method is especially useful when extending the table structure that is already defined by existing plugin.

## Built-in Events

The following events will be triggered in the corresponding lifecycle of database, subscribe by the `on()` method and perform specific processing to meet some business needs.

### `'beforeSync'` / `'afterSync'`

Events triggered before or after a new table structure configuration (fields, indexes, etc.) is synchronized to the database. This is usually triggered when executing `collection.sync()` (internal call) for the logical processing of the extension of some special fields.

**Signature**

```ts
on(eventName: `${string}.beforeSync` | 'beforeSync' | `${string}.afterSync` | 'afterSync', listener: SyncListener): this
```

**Type**

```ts
import type { SyncOptions, HookReturn } from 'sequelize/types';

type SyncListener = (options?: SyncOptions) => HookReturn;
```

**Example**

```ts
const users = db.collection({
  name: 'users',
  fields: [{ type: 'string', name: 'username' }],
});

db.on('beforeSync', async (options) => {
  // do something
});

db.on('users.afterSync', async (options) => {
  // do something
});

await users.sync();
```

### `'beforeValidate'` / `'afterValidate'`

Before creating or updating data, there is a validation against the data based on the rules defined by the collection, and the corresponding events are triggered before and after the validation. This is triggered when `repository.create()` or `repository.update()` is called.

**Signature**

```ts
on(eventName: `${string}.beforeValidate` | 'beforeValidate' | `${string}.afterValidate` | 'afterValidate', listener: ValidateListener): this
```

**Type**

```ts
import type { ValidationOptions } from 'sequelize/types/lib/instance-validator';
import type { HookReturn } from 'sequelize/types';
import type { Model } from '@nocobase/database';

type ValidateListener = (
  model: Model,
  options?: ValidationOptions,
) => HookReturn;
```

**Example**

```ts
db.collection({
  name: 'tests',
  fields: [
    {
      type: 'string',
      name: 'email',
      validate: {
        isEmail: true,
      },
    },
  ],
});

// all models
db.on('beforeValidate', async (model, options) => {
  // do something
});
// tests model
db.on('tests.beforeValidate', async (model, options) => {
  // do something
});

// all models
db.on('afterValidate', async (model, options) => {
  // do something
});
// tests model
db.on('tests.afterValidate', async (model, options) => {
  // do something
});

const repository = db.getRepository('tests');
await repository.create({
  values: {
    email: 'abc', // checks for email format
  },
});
// or
await repository.update({
  filterByTk: 1,
  values: {
    email: 'abc', // checks for email format
  },
});
```

### `'beforeCreate'` / `'afterCreate'`

Events triggered before or after creating one piece of data. This is triggered when `repository.create()` is called.

**Signature**

```ts
on(eventName: `${string}.beforeCreate` | 'beforeCreate' | `${string}.afterCreate` | 'afterCreate', listener: CreateListener): this
```

**Type**

```ts
import type { CreateOptions, HookReturn } from 'sequelize/types';
import type { Model } from '@nocobase/database';

export type CreateListener = (
  model: Model,
  options?: CreateOptions,
) => HookReturn;
```

**Example**

```ts
db.on('beforeCreate', async (model, options) => {
  // do something
});

db.on('books.afterCreate', async (model, options) => {
  const { transaction } = options;
  const result = await model.constructor.findByPk(model.id, {
    transaction,
  });
  console.log(result);
});
```

### `'beforeUpdate'` / `'afterUpdate'`

Events triggered before or after updating one piece of data. This is triggered when `repository.update()` is called.

**Signature**

```ts
on(eventName: `${string}.beforeUpdate` | 'beforeUpdate' | `${string}.afterUpdate` | 'afterUpdate', listener: UpdateListener): this
```

**Type**

```ts
import type { UpdateOptions, HookReturn } from 'sequelize/types';
import type { Model } from '@nocobase/database';

export type UpdateListener = (
  model: Model,
  options?: UpdateOptions,
) => HookReturn;
```

**Example**

```ts
db.on('beforeUpdate', async (model, options) => {
  // do something
});

db.on('books.afterUpdate', async (model, options) => {
  // do something
});
```

### `'beforeSave'` / `'afterSave'`

Events triggered before or after creating or updating one piece of data. This is triggered when `repository.create()` or `repository.update()` is called.

**Signature**

```ts
on(eventName: `${string}.beforeSave` | 'beforeSave' | `${string}.afterSave` | 'afterSave', listener: SaveListener): this
```

**Type**

```ts
import type { SaveOptions, HookReturn } from 'sequelize/types';
import type { Model } from '@nocobase/database';

export type SaveListener = (model: Model, options?: SaveOptions) => HookReturn;
```

**Example**

```ts
db.on('beforeSave', async (model, options) => {
  // do something
});

db.on('books.afterSave', async (model, options) => {
  // do something
});
```

### `'beforeDestroy'` / `'afterDestroy'`

Events triggered before or after deleting one piece of data. This is triggered when `repository.destroy()` is called.

**Signature**

```ts
on(eventName: `${string}.beforeDestroy` | 'beforeDestroy' | `${string}.afterDestroy` | 'afterDestroy', listener: DestroyListener): this
```

**Type**

```ts
import type { DestroyOptions, HookReturn } from 'sequelize/types';
import type { Model } from '@nocobase/database';

export type DestroyListener = (
  model: Model,
  options?: DestroyOptions,
) => HookReturn;
```

**Example**

```ts
db.on('beforeDestroy', async (model, options) => {
  // do something
});

db.on('books.afterDestroy', async (model, options) => {
  // do something
});
```

### `'afterCreateWithAssociations'`

Events triggered after creating one piece of data that carries hierarchical data. This is triggered when `repository.create()` is called.

**Signature**

```ts
on(eventName: `${string}.afterCreateWithAssociations` | 'afterCreateWithAssociations', listener: CreateWithAssociationsListener): this
```

**Type**

```ts
import type { CreateOptions, HookReturn } from 'sequelize/types';
import type { Model } from '@nocobase/database';

export type CreateWithAssociationsListener = (
  model: Model,
  options?: CreateOptions,
) => HookReturn;
```

**Example**

```ts
db.on('afterCreateWithAssociations', async (model, options) => {
  // do something
});

db.on('books.afterCreateWithAssociations', async (model, options) => {
  // do something
});
```

### `'afterUpdateWithAssociations'`

Events triggered after updating one piece of data that carries hierarchical data. This is triggered when `repository.update()` is called.

**Signature**

```ts
on(eventName: `${string}.afterUpdateWithAssociations` | 'afterUpdateWithAssociations', listener: CreateWithAssociationsListener): this
```

**Type**

```ts
import type { UpdateOptions, HookReturn } from 'sequelize/types';
import type { Model } from '@nocobase/database';

export type UpdateWithAssociationsListener = (
  model: Model,
  options?: UpdateOptions,
) => HookReturn;
```

**Example**

```ts
db.on('afterUpdateWithAssociations', async (model, options) => {
  // do something
});

db.on('books.afterUpdateWithAssociations', async (model, options) => {
  // do something
});
```

### `'afterSaveWithAssociations'`

Events triggered after creating or updating one piece of data that carries hierarchical data. This is triggered when `repository.create()` or `repository.update()` is called.

**Signature**

```ts
on(eventName: `${string}.afterSaveWithAssociations` | 'afterSaveWithAssociations', listener: SaveWithAssociationsListener): this
```

**Type**

```ts
import type { SaveOptions, HookReturn } from 'sequelize/types';
import type { Model } from '@nocobase/database';

export type SaveWithAssociationsListener = (
  model: Model,
  options?: SaveOptions,
) => HookReturn;
```

**Example**

```ts
db.on('afterSaveWithAssociations', async (model, options) => {
  // do something
});

db.on('books.afterSaveWithAssociations', async (model, options) => {
  // do something
});
```

### `'beforeDefineCollection'`

Events triggered before defining a data table, such as when `db.collection()` is called.

Note: This is a synchronous event.

**Signature**

```ts
on(eventName: 'beforeDefineCollection', listener: BeforeDefineCollectionListener): this
```

**Type**

```ts
import type { CollectionOptions } from '@nocobase/database';

export type BeforeDefineCollectionListener = (
  options: CollectionOptions,
) => void;
```

**Example**

```ts
db.on('beforeDefineCollection', (options) => {
  // do something
});
```

### `'afterDefineCollection'`

Events triggered after defining a data table, such as when `db.collection()` is called.

Note: This is a synchronous event.

**Signature**

```ts
on(eventName: 'afterDefineCollection', listener: AfterDefineCollectionListener): this
```

**Type**

```ts
import type { Collection } from '@nocobase/database';

export type AfterDefineCollectionListener = (options: Collection) => void;
```

**Example**

```ts
db.on('afterDefineCollection', (collection) => {
  // do something
});
```

### `'beforeRemoveCollection'` / `'afterRemoveCollection'`

Events triggered before or after removing a data table from memory, such as when `db.removeCollection()` is called.

Note: This is a synchronous event.

**Signature**

```ts
on(eventName: 'beforeRemoveCollection' | 'afterRemoveCollection', listener: RemoveCollectionListener): this
```

**Type**

```ts
import type { Collection } from '@nocobase/database';

export type RemoveCollectionListener = (options: Collection) => void;
```

**Example**

```ts
db.on('beforeRemoveCollection', (collection) => {
  // do something
});

db.on('afterRemoveCollection', (collection) => {
  // do something
});
```

---

## File: docs/en-US/api/database/operators.md

# Filter Operators

Used in the filter parameters of the `find`, `findOne`, `findAndCount`, `count`, etc. APIs of repository:

```ts
const repository = db.getRepository('books');

repository.find({
  filter: {
    title: {
      $eq: 'Spring and Autumn',
    },
  },
});
```

To support JSON, NocoBase identifies query operators as a string prefixed with $.

Moreover, NocoBase provides API to extend operators. Refer to [`db.registerOperators()`](../database#registeroperators).

## General Operators

### `$eq`

Check if the field value is equal to the specified value. Equivalent to `=` in SQL.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $eq: 'Spring and Autumn',
    },
  },
});
```

Equal to `title: 'Spring and Autumn'`

### `$ne`

Check if the field value is not equal to the specified value. Equivalent to `!=` in SQL.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $ne: 'Spring and Autumn',
    },
  },
});
```

### `$is`

Check if the field value is the specified value. Equivalent to `IS` in SQL.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $is: null,
    },
  },
});
```

### `$not`

Check if the field value is not the specified value. Equivalent to `IS NOT` in SQL.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $not: null,
    },
  },
});
```

### `$col`

Check if the field value is equal to the value of another field. Equivalent to `=` in SQL.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $col: 'name',
    },
  },
});
```

### `$in`

Check if the field value is in the specified array. Equivalent to `IN` in SQL.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $in: ['Spring and Autumn', 'Warring States'],
    },
  },
});
```

### `$notIn`

Check if the field value is not in the specified array. Equivalent to `NOT IN` in SQL.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $notIn: ['Spring and Autumn', 'Warring States'],
    },
  },
});
```

### `$empty`

Check if the general field is empty. For string field, check if it is an empty string; for array field, check if it is an empty array.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $empty: true,
    },
  },
});
```

### `$notEmpty`

Check if the general field is not empty. For string field, check if it is not an empty string; for array field, check if it is not an empty array.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $notEmpty: true,
    },
  },
});
```

## Logical Operators

### `$and`

Logical AND. Equivalent to `AND` in SQL.

**Example**

```ts
repository.find({
  filter: {
    $and: [{ title: 'Book of Songs' }, { isbn: '1234567890' }],
  },
});
```

### `$or`

Logical OR. Equivalent to `OR` in SQL.

**Example**

```ts
repository.find({
  filter: {
    $or: [
      { title: 'Book of Songs' },
      { publishedAt: { $lt: '0000-00-00T00:00:00Z' } },
    ],
  },
});
```

## Boolean Field Operators

For boolean fields: `type: 'boolean'`

### `$isFalsy`

Check if a Boolean field value is false. Boolean field values of `false`, `0` and `NULL` are all judged to be `$isFalsy: true`.

**Example**

```ts
repository.find({
  filter: {
    isPublished: {
      $isFalsy: true,
    },
  },
});
```

### `$isTruly`

Check if a Boolean field value is true. Boolean field values of `true` and `1` are all judged to be `$isTruly: true`.

**Example**

```ts
repository.find({
  filter: {
    isPublished: {
      $isTruly: true,
    },
  },
});
```

## Numeric Type Field Operators

For numeric type fields, including:

- `type: 'integer'`
- `type: 'float'`
- `type: 'double'`
- `type: 'real'`
- `type: 'decimal'`

### `$gt`

Check if the field value is greater than the specified value. Equivalent to `>` in SQL.

**Example**

```ts
repository.find({
  filter: {
    price: {
      $gt: 100,
    },
  },
});
```

### `$gte`

Check if the field value is equal to or greater than the specified value. Equivalent to `>=` in SQL.

**Example**

```ts
repository.find({
  filter: {
    price: {
      $gte: 100,
    },
  },
});
```

### `$lt`

Check if the field value is less than the specified value. Equivalent to `<` in SQL.

**Example**

```ts
repository.find({
  filter: {
    price: {
      $lt: 100,
    },
  },
});
```

### `$lte`

Check if the field value is equal to or less than the specified value. Equivalent to `<=` in SQL.

**Example**

```ts
repository.find({
  filter: {
    price: {
      $lte: 100,
    },
  },
});
```

### `$between`

Check if the field value is between the specified two values. Equivalent to `BETWEEN` in SQL.

**Example**

```ts
repository.find({
  filter: {
    price: {
      $between: [100, 200],
    },
  },
});
```

### `$notBetween`

Check if the field value is not between the specified two values. Equivalent to `NOT BETWEEN` in SQL.

**Example**

```ts
repository.find({
  filter: {
    price: {
      $notBetween: [100, 200],
    },
  },
});
```

## String Type Field Operators

For string type fields, including `string`.

### `$includes`

Check if the string field contains the specified substring.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $includes: 'Three Character Classic',
    },
  },
});
```

### `$notIncludes`

Check if the string field does not contain the specified substring.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $notIncludes: 'Three Character Classic',
    },
  },
});
```

### `$startsWith`

Check if the string field starts with the specified substring.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $startsWith: 'Three Character Classic',
    },
  },
});
```

### `$notStatsWith`

Check if the string field does not start with the specified substring.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $notStatsWith: 'Three Character Classic',
    },
  },
});
```

### `$endsWith`

Check if the string field ends with the specified substring.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $endsWith: 'Three Character Classic',
    },
  },
});
```

### `$notEndsWith`

Check if the string field does not end with the specified substring.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $notEndsWith: 'Three Character Classic',
    },
  },
});
```

### `$like`

Check if the field value contains the specified string. Equivalent to `LIKE` in SQL.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $like: 'Computer',
    },
  },
});
```

### `$notLike`

Check if the field value does not contain the specified string. Equivalent to `NOT LIKE` in SQL.

**Example**

```ts
repository.find({
  filter: {
    title: {
      $notLike: 'Computer',
    },
  },
});
```

### `$iLike`

Check if a field value contains the specified string, case ignored. Equivalent to `ILIKE` in SQL (PG only).

**Example**

```ts
repository.find({
  filter: {
    title: {
      $iLike: 'Computer',
    },
  },
});
```

### `$notILike`

Check if a field value does not contain the specified string, case ignored. Equivalent to `NOT ILIKE` in SQL (PG only).

**Example**

```ts
repository.find({
  filter: {
    title: {
      $notILike: 'Computer',
    },
  },
});
```

### `$regexp`

Check if the field value matches the specified regular expression. Equivalent to `REGEXP` in SQL (PG only).

**Example**

```ts
repository.find({
  filter: {
    title: {
      $regexp: '^Computer',
    },
  },
});
```

### `$notRegexp`

Check if the field value does not match the specified regular expression. Equivalent to `NOT REGEXP` in SQL (PG only).

**Example**

```ts
repository.find({
  filter: {
    title: {
      $notRegexp: '^Computer',
    },
  },
});
```

### `$iRegexp`

Check if the field value matches the specified regular expression, case ignored. Equivalent to `~*` in SQL (PG only).

**Example**

```ts
repository.find({
  filter: {
    title: {
      $iRegexp: '^COMPUTER',
    },
  },
});
```

### `$notIRegexp`

Check if the field value does not match the specified regular expression, case ignored. Equivalent to `!~*` in SQL (PG only).

**Example**

```ts
repository.find({
  filter: {
    title: {
      $notIRegexp: '^COMPUTER',
    },
  },
});
```

## Date Type Field Operators

For date type fields: `type: 'date'`

### `$dateOn`

Check if the date field value is within a certain day.

**Example**

```ts
repository.find({
  filter: {
    createdAt: {
      $dateOn: '2021-01-01',
    },
  },
});
```

### `$dateNotOn`

Check if the date field value is not within a certain day.

**Example**

```ts
repository.find({
  filter: {
    createdAt: {
      $dateNotOn: '2021-01-01',
    },
  },
});
```

### `$dateBefore`

Check if the date field value is before a certain value, i.e., less than the one passed in.

**Example**

```ts
repository.find({
  filter: {
    createdAt: {
      $dateBefore: '2021-01-01T00:00:00.000Z',
    },
  },
});
```

### `$dateNotBefore`

Check if the date field value is not before a certain value, i.e., equal to or greater than the one passed in.

**Example**

```ts
repository.find({
  filter: {
    createdAt: {
      $dateNotBefore: '2021-01-01T00:00:00.000Z',
    },
  },
});
```

### `$dateAfter`

Check if the date field value is after a certain value, i.e., greater than the one passed in.

**Example**

```ts
repository.find({
  filter: {
    createdAt: {
      $dateAfter: '2021-01-01T00:00:00.000Z',
    },
  },
});
```

### `$dateNotAfter`

Check if the date field value is not after a certain value, i.e., equal to or greater than the one passed in.

**Example**

```ts
repository.find({
  filter: {
    createdAt: {
      $dateNotAfter: '2021-01-01T00:00:00.000Z',
    },
  },
});
```

## Array Type Field Operators

For array type fields: `type: 'array'`

### `$match`

Check if the array field values match values of the specified array.

**Example**

```ts
repository.find({
  filter: {
    tags: {
      $match: ['literature', 'history'],
    },
  },
});
```

### `$notMatch`

Check if the array field values do not match values of the specified array.

**Example**

```ts
repository.find({
  filter: {
    tags: {
      $notMatch: ['literature', 'history'],
    },
  },
});
```

### `$anyOf`

Check if the array field values contain any of the values of the specified array.

**Example**

```ts
repository.find({
  filter: {
    tags: {
      $anyOf: ['literature', 'history'],
    },
  },
});
```

### `$noneOf`

Check if the array field values contain none of the values of the specified array.

**Example**

```ts
repository.find({
  filter: {
    tags: {
      $noneOf: ['literature', 'history'],
    },
  },
});
```

### `$arrayEmpty`

Check if the array field is empty.

**Example**

```ts
repository.find({
  filter: {
    tags: {
      $arrayEmpty: true,
    },
  },
});
```

### `$arrayNotEmpty`

Check if the array field is not empty.

**Example**

```ts
repository.find({
  filter: {
    tags: {
      $arrayNotEmpty: true,
    },
  },
});
```

## Relational Field Type Operators

For checking if a relationship exists, field types include:

- `type: 'hasOne'`
- `type: 'hasMany'`
- `type: 'belongsTo'`
- `type: 'belongsToMany'`

### `$exists`

There is relational data existing.

**Example**

```ts
repository.find({
  filter: {
    author: {
      $exists: true,
    },
  },
});
```

### `$notExists`

There is no relational data existing.

**Example**

```ts
repository.find({
  filter: {
    author: {
      $notExists: true,
    },
  },
});
```

---

## File: docs/en-US/api/database/repository.md

# Repository

## Overview

On a given `Collection` object, you can get its `Repository` object to perform read and write operations on the data table.

```javascript
const { UserCollection } = require('./collections');

const UserRepository = UserCollection.repository;

const user = await UserRepository.findOne({
  filter: {
    id: 1,
  },
});

user.name = 'new name';
await user.save();
```

### Query

#### Basic Query

On the `Repository` object, call the `find*` methods to perform query. The `filter` parameter is supported by all query methods to filter the data.

```javascript
// SELECT * FROM users WHERE id = 1
userRepository.find({
  filter: {
    id: 1,
  },
});
```

#### Operator

The `filter` parameter in the `Repository` also provides a variety of operators to perform more diverse queries.

```javascript
// SELECT * FROM users WHERE age > 18
userRepository.find({
  filter: {
    age: {
      $gt: 18,
    },
  },
});

// SELECT * FROM users WHERE age > 18 OR name LIKE '%张%'
userRepository.find({
  filter: {
    $or: [{ age: { $gt: 18 } }, { name: { $like: '%张%' } }],
  },
});
```

Refer to [Filter Operators](/api/database/operators) for more details on operators.

#### Field Control

Control the output fields by the `fields`, `except`, and `appends` parameters when performing query.

- `fields`: Specify output fields
- `except`: Exclude output fields
- `appends`: Append output associated fields

```javascript
// The result contains only the id and name fields
userRepository.find({
  fields: ['id', 'name'],
});

// The result does not contain only the password field
userRepository.find({
  except: ['password'],
});

// The result contains data associated with the posts object
userRepository.find({
  appends: ['posts'],
});
```

#### Associated Field Query

The `filter` parameter supports filtering by associated fields, for example:

```javascript
// Find the user objects whose associated posts have title of "post title"
userRepository.find({
  filter: {
    'posts.title': 'post title',
  },
});
```

Associated fields can also be nested:

```javascript
// Find the user objects whose associated posts have comments containing "keywords"
await userRepository.find({
  filter: {
    'posts.comments.content': {
      $like: '%keywords%',
    },
  },
});
```

#### Sort

Sort query results by the `sort` parameter.

```javascript
// SELECT * FROM users ORDER BY age
await userRepository.find({
  sort: 'age',
});

// SELECT * FROM users ORDER BY age DESC
await userRepository.find({
  sort: '-age',
});

// SELECT * FROM users ORDER BY age DESC, name ASC
await userRepository.find({
  sort: ['-age', 'name'],
});
```

Sort by the field of the associated object is also supported:

```javascript
await userRepository.find({
  sort: 'profile.createdAt',
});
```

### Create

#### Basic Create

Create new data objects via `Repository`.

```javascript
await userRepository.create({
  name: 'Mark',
  age: 18,
});
// INSERT INTO users (name, age) VALUES ('Mark', 18)

// Bulk creation
await userRepository.create([
  {
    name: 'Mark',
    age: 18,
  },
  {
    name: 'Alex',
    age: 20,
  },
]);
```

#### Create Association

Create associated objects at the same time of creating data. Like query, nested use of associated objects is also supported. For example:

```javascript
await userRepository.create({
  name: 'Mark',
  age: 18,
  posts: [
    {
      title: 'post title',
      content: 'post content',
      tags: [
        {
          name: 'tag1',
        },
        {
          name: 'tag2',
        },
      ],
    },
  ],
});
// When creating a user, create a post to associate with the user, and create tags to associate with the post
```

If the associated object is already in the database, you can pass its ID to create an association with it.

```javascript
const tag1 = await tagRepository.findOne({
  filter: {
    name: 'tag1',
  },
});

await userRepository.create({
  name: 'Mark',
  age: 18,
  posts: [
    {
      title: 'post title',
      content: 'post content',
      tags: [
        {
          id: tag1.id, // Create an association with an existing associated object
        },
        {
          name: 'tag2',
        },
      ],
    },
  ],
});
```

### Update

#### Basic Update

After getting the data object, you can modify the properties directly on the data object (`Model`), and then call the `save` method to save the changes.

```javascript
const user = await userRepository.findOne({
  filter: {
    name: 'Mark',
  },
});

user.age = 20;
await user.save();
```

The data object `Model` is inherited from Sequelize Model, refer to [Sequelize Model](https://sequelize.org/master/manual/model-basics.html) for the operations on `Model`.

Or update data via `Repository`:

```javascript
// Update the records that meet the filtering condition
await userRepository.update({
  filter: {
    name: 'Mark',
  },
  values: {
    age: 20,
  },
});
```

Control which fields to update by the `whitelist` and `blacklist` parameters, for example:

```javascript
await userRepository.update({
  filter: {
    name: 'Mark',
  },
  values: {
    age: 20,
    name: 'Alex',
  },
  whitelist: ['age'], // Only update the age field
});
```

#### Update Associated Field

Associated objects can be set while updating, for example:

```javascript
const tag1 = tagRepository.findOne({
  filter: {
    id: 1,
  },
});

await postRepository.update({
  filter: {
    id: 1,
  },
  values: {
    title: 'new post title',
    tags: [
      {
        id: tag1.id, // Associate with tag1
      },
      {
        name: 'tag2', // Create new tag and associate with it
      },
    ],
  },
});

await postRepository.update({
  filter: {
    id: 1,
  },
  values: {
    tags: null, // Disassociate post from tags
  },
});
```

### Delete

Call the `destroy()` method in `Repository` to perform the deletion operation. Filtering condition has to be specified to delete.

```javascript
await userRepository.destroy({
  filter: {
    status: 'blocked',
  },
});
```

## Constructor

It is usually not called directly by the developer, the instantiation is done mainly by specifying a corresponding repository type that is already registered in the parameter of `db.colletion()`. Repository type is registered through `db.registerRepositories()`.

**Signature**

- `constructor(collection: Collection)`

**Example**

```ts
import { Repository } from '@nocobase/database';

class MyRepository extends Repository {
  async myQuery(sql) {
    return this.database.sequelize.query(sql);
  }
}

db.registerRepositories({
  books: MyRepository,
});

db.collection({
  name: 'books',
  // here link to the registered repository
  repository: 'books',
});

await db.sync();

const books = db.getRepository('books') as MyRepository;
await books.myQuery('SELECT * FROM books;');
```

## Instance Members

### `database`

The database management instance where the context is located.

### `collection`

The corresponding data table management instance.

### `model`

The corresponding data model class.

## Instance Methods

### `find()`

Find datasets from the database with the specified filtering conditions and sorting, etc.

**Signature**

- `async find(options?: FindOptions): Promise<Model[]>`

**Type**

```typescript
type Filter = FilterWithOperator | FilterWithValue | FilterAnd | FilterOr;
type Appends = string[];
type Except = string[];
type Fields = string[];
type Sort = string[] | string;

interface SequelizeFindOptions {
  limit?: number;
  offset?: number;
}

interface FilterByTk {
  filterByTk?: TargetKey;
}

interface CommonFindOptions extends Transactionable {
  filter?: Filter;
  fields?: Fields;
  appends?: Appends;
  except?: Except;
  sort?: Sort;
}

type FindOptions = SequelizeFindOptions & CommonFindOptions & FilterByTk;
```

**Detailed Information**

#### `filter: Filter`

Query conditions for filtering data results. In the query parameters that passed in, `key` is the name of the field, `value` is the corresponding value. Operators can be used in conjunction with other filtering conditions.

```typescript
// Find records with name "foo" and age above 18
repository.find({
  filter: {
    name: 'foo',
    age: {
      $gt: 18,
    },
  },
});
```

Refer to [Operators](./operators.md) for more information.

#### `filterByTk: TargetKey`

Query data by `TargetKey`, this is shortcut for the `filter` parameter. The field of `TargetKey` can be [configured](./collection.md#filtertargetkey) in `Collection`, the default is `primaryKey`.

```typescript
// By default, find records with id 1
repository.find({
  filterByTk: 1,
});
```

#### `fields: string[]`

Query columns. It is used to control which data fields to output. With this parameter, only the specified fields will be returned.

#### `except: string[]`

Exclude columns. It is used to control which data fields to output. With this parameter, the specified fields will not be returned.

#### `appends: string[]`

Append columns. It is used to load associated data. With this parameter, the specified associated fields will be returned together.

#### `sort: string[] | string`

Specify the sorting method of the query results. The input parameter is the name of the field, by default is to sort in the ascending order (`asc`); a `-` symbol needs to be added before the field name to sort in the descending order (`desc`). For example, `['-id', 'name']` means to sort by `id desc, name asc`.

#### `limit: number`

Limit the number of results, same as `limit` in `SQL`.

#### `offset: number`

The offset of the query, same as `offset` in `SQL`.

**Example**

```ts
const posts = db.getRepository('posts');

const results = await posts.find({
  filter: {
    createdAt: {
      $gt: '2022-01-01T00:00:00.000Z',
    },
  },
  fields: ['title'],
  appends: ['user'],
});
```

### `findOne()`

Find a single piece of data from the database for specific conditions. Equivalent to `Model.findOne()` in Sequelize.

**Signature**

- `async findOne(options?: FindOneOptions): Promise<Model | null>`



**Example**

```ts
const posts = db.getRepository('posts');

const result = await posts.findOne({
  filterByTk: 1,
});
```

### `count()`

Query a certain amount of data from the database for specific conditions. Equivalent to `Model.count()` in Sequelize.

**Signature**

- `count(options?: CountOptions): Promise<number>`

**Type**

```typescript
interface CountOptions
  extends Omit<SequelizeCountOptions, 'distinct' | 'where' | 'include'>,
    Transactionable {
  filter?: Filter;
}
```

**Example**

```ts
const books = db.getRepository('books');

const count = await books.count({
  filter: {
    title: 'Three character classic',
  },
});
```

### `findAndCount()`

Find datasets from the database with the specified filtering conditions and return the number of results. Equivalent to `Model.findAndCountAll()` in Sequelize.

**Signature**

- `async findAndCount(options?: FindAndCountOptions): Promise<[Model[], number]>`

**Type**

```typescript
type FindAndCountOptions = Omit<
  SequelizeAndCountOptions,
  'where' | 'include' | 'order'
> &
  CommonFindOptions;
```

**Detailed Information**

The query parameters are the same as `find()`. An array is returned with the first element of the query results, and the second element of the total number of results.

### `create()`

Inserts a newly created data into the data table. Equivalent to `Model.create()` in Sequelize. When the data object to be created carries any associated field, the corresponding associated data record is created or updated along with it.

**Signature**

- `async create<M extends Model>(options: CreateOptions): Promise<M>`



**Example**

```ts
const posts = db.getRepository('posts');

const result = await posts.create({
  values: {
    title: 'NocoBase 1.0 Release Notes',
    tags: [
      // Update data when there is a primary key and value of the associated table
      { id: 1 },
      // Create data when there is no primary key and value
      { name: 'NocoBase' },
    ],
  },
});
```

### `createMany()`

Inserts multiple newly created data into the data table. This is equivalent to calling the `create()` method multiple times.

**Signature**

- `createMany(options: CreateManyOptions): Promise<Model[]>`

**Type**

```typescript
interface CreateManyOptions extends BulkCreateOptions {
  records: Values[];
}
```

**Detailed Information**

- `records`: An array of data objects to be created.
- `transaction`: Transaction object. If no transaction parameter is passed, the method will automatically create an internal transaction.

**Example**

```ts
const posts = db.getRepository('posts');

const results = await posts.createMany({
  records: [
    {
      title: 'NocoBase 1.0 Release Notes',
      tags: [
        // Update data when there is a primary key and value of the associated table
        { id: 1 },
        // Create data when there is no primary key and value
        { name: 'NocoBase' },
      ],
    },
    {
      title: 'NocoBase 1.1 Release Notes',
      tags: [{ id: 1 }],
    },
  ],
});
```

### `update()`

Update data in the data table. Equivalent to `Model.update()` in Sequelize. When the data object to be updated carries any associated field, the corresponding associated data record is created or updated along with it.

**Signature**

- `async update<M extends Model>(options: UpdateOptions): Promise<M>`



**Example**

```ts
const posts = db.getRepository('posts');

const result = await posts.update({
  filterByTk: 1,
  values: {
    title: 'NocoBase 1.0 Release Notes',
    tags: [
      // Update data when there is a primary key and value of the associated table
      { id: 1 },
      // Create data when there is no primary key and value
      { name: 'NocoBase' },
    ],
  },
});
```

### `destroy()`

Delete data from the data table. Equivalent to `Model.destroy()` in Sequelize.

**Signature**

- `async destroy(options?: TargetKey | TargetKey[] | DestoryOptions): Promise<number>`

**Type**

```typescript
interface DestroyOptions extends SequelizeDestroyOptions {
  filter?: Filter;
  filterByTk?: TargetKey | TargetKey[];
  truncate?: boolean;
  context?: any;
}
```

**Detailed Information**

- `filter`：Specify the filtering conditions of the records to be deleted. Refer to the [`find()`](#find) method for the detailed usage of the filter.
- `filterByTk`：Specify the filtering conditions by TargetKey.
- `truncate`: Whether to empty the table data, this parameter is valid if no `filter` or `filterByTk` parameter is passed.
- `transaction`: Transaction object. If no transaction parameter is passed, the method will automatically create an internal transaction.

---

## File: docs/en-US/api/database/shared.md

**Parameters**

| Parameter Name         | Type          | Default | Description                                           |
| ---------------------- | ------------- | ------- | ----------------------------------------------------- |
| `options.values`       | `M`           | `{}`    | The data object to be inserted                        |
| `options.whitelist?`   | `string[]`    | -       | Whitelist for the `values` field; only fields in the list will be stored |
| `options.blacklist?`   | `string[]`    | -       | Blacklist for the `values` field; fields in the list will not be stored |
| `options.transaction?` | `Transaction` | -       | Transaction                                            |

---

## File: docs/en-US/api/database/interfaces/base-interface.md

# BaseInterface

## Overview

BaseInterface is the foundational class for all Interface types. Users can extend this class to implement custom Interface logic.

```typescript
class CustomInterface extends BaseInterface {
  async toValue(value: string, ctx?: any): Promise<any> {
    // Custom toValue logic
  }

  toString(value: any, ctx?: any) {
    // Custom toString logic
  }
}
// Register Interface
db.interfaceManager.registerInterfaceType('customInterface', CustomInterface)
```

## Interfaces

### toValue(value: string, ctx?: any): Promise<any>

Converts an external string to the actual value of the interface, which can be directly passed to the Repository for write operations.

### toString(value: any, ctx?: any)

Converts the actual value of the interface to a string type, which can be used for exporting or displaying purposes.

---

## File: docs/en-US/api/database/relation-repository/belongs-to-many-repository.md

# BelongsToManyRepository

`BelongsToManyRepository` is the `Relation Repository` for handling `BelongsToMany` relationships.

Unlike other relationship types, the `BelongsToMany` type of relationship needs to be recorded through an intermediate table. The intermediate table can be created automatically or explicitly specified when defining association relationships in NocoBase.

## Class Methods

### `find()`

Find associated objects.

**Signature**

- `async find(options?: FindOptions): Promise<M[]>`

**Detailed Information**

Query parameters are the same as [`Repository.find()`](../repository.md#find).

### `findOne()`

Find associated objects, only to return one record.

**Signature**

- `async findOne(options?: FindOneOptions): Promise<M>`



### `count()`

Return the number of records matching the query criteria.

**Signature**

- `async count(options?: CountOptions)`

**Type**

```typescript
interface CountOptions
  extends Omit<SequelizeCountOptions, 'distinct' | 'where' | 'include'>,
    Transactionable {
  filter?: Filter;
}
```

### `findAndCount()`

Find datasets from the database with the specified filtering conditions and return the number of results.

**Signature**

- `async findAndCount(options?: FindAndCountOptions): Promise<[any[], number]>`

**Type**

```typescript
type FindAndCountOptions = CommonFindOptions;
```

### `create()`

Create associated objects.

**Signature**

- `async create(options?: CreateOptions): Promise<M>`



### `update()`

Update associated objects that match the conditions.

**Signature**

- `async update(options?: UpdateOptions): Promise<M>`



### `destroy()`

Delete associated objects.

**Signature**

- `async destroy(options?: TargetKey | TargetKey[] | DestroyOptions): Promise`



### `add()`

Add new associated objects.

**Signature**

- `async add(
options: TargetKey | TargetKey[] | PrimaryKeyWithThroughValues | PrimaryKeyWithThroughValues[] | AssociatedOptions
): Promise<void>`

**Type**

```typescript
type PrimaryKeyWithThroughValues = [TargetKey, Values];

interface AssociatedOptions extends Transactionable {
  tk?:
    | TargetKey
    | TargetKey[]
    | PrimaryKeyWithThroughValues
    | PrimaryKeyWithThroughValues[];
}
```

**Detailed Information**

Pass the `targetKey` of the associated object directly, or pass the `targetKey` along with the field values of the intermediate table.

**Example**

```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);

// Pass in the targetKey
PostTagRepository.add([t1.id, t2.id]);

// Pass in intermediate table fields
PostTagRepository.add([
  [t1.id, { tagged_at: '123' }],
  [t2.id, { tagged_at: '456' }],
]);
```

### `set()`

Set the associated objects.

**Signature**

- async set(
  options: TargetKey | TargetKey[] | PrimaryKeyWithThroughValues | PrimaryKeyWithThroughValues[] | AssociatedOptions,
  ): Promise<void>

**Detailed Information**

Parameters are the same as [add()](#add).

### `remove()`

Remove the association with the given objects.

**Signature**

- `async remove(options: TargetKey | TargetKey[] | AssociatedOptions)`

**Type**

```typescript
interface AssociatedOptions extends Transactionable {
  tk?: TargetKey | TargetKey[];
}
```

### `toggle()`

Toggle the associated object.

In some business scenarios, it is often needed to toggle the associated object. For example, user adds a product into collection, and the user cancels the collection and collect it again. Using the `toggle` method can quickly implement similar functions.

**Signature**

- `async toggle(options: TargetKey | { tk?: TargetKey; transaction?: Transaction }): Promise<void>`

**Detailed Information**

The `toggle` method automatically checks whether the associated object already exists, and removes it if it does, or adds it if it does not.

---

## File: docs/en-US/api/database/relation-repository/belongs-to-repository.md

## BelongsToRepository

The interface is the same as [HasOneRepository](./has-one-repository.md). `BelongsToRepository` is the `Repository` for handling `BelongsTo` relationships, and it provides some convenient methods to handle `BelongsTo` relationships.

---

## File: docs/en-US/api/database/relation-repository/has-many-repository.md

# HasManyRepository

`HasManyRepository` is the `Relation Repository` for handling `HasMany` relationships.

## Class Methods

### `find()`

Find associated objects.

**Signature**

- `async find(options?: FindOptions): Promise<M[]>`

**Detailed Information**

Query parameters are the same as [`Repository.find()`](../repository.md#find).

### `findOne()`

Find associated objects, only to return one record.

**Signature**

- `async findOne(options?: FindOneOptions): Promise<M>`



### `count()`

Return the number of records matching the query criteria.

**Signature**

- `async count(options?: CountOptions)`

**Type**

```typescript
interface CountOptions
  extends Omit<SequelizeCountOptions, 'distinct' | 'where' | 'include'>,
    Transactionable {
  filter?: Filter;
}
```

### `findAndCount()`

Find datasets from the database with the specified filtering conditions and return the number of results.

**Signature**

- `async findAndCount(options?: FindAndCountOptions): Promise<[any[], number]>`

**Type**

```typescript
type FindAndCountOptions = CommonFindOptions;
```

### `create()`

Create associated objects.

**Signature**

- `async create(options?: CreateOptions): Promise<M>`



### `update()`

Update associated objects that match the conditions.

**Signature**

- `async update(options?: UpdateOptions): Promise<M>`



### `destroy()`

Delete associated objects.

**Signature**

- `async destroy(options?: TK | DestroyOptions): Promise<M>`



### `add()`

Add association relationships between objects.

**Signature**

- `async add(options: TargetKey | TargetKey[] | AssociatedOptions)`

**Type**

```typescript
interface AssociatedOptions extends Transactionable {
  tk?: TargetKey | TargetKey[];
}
```

**Detailed Information**

- `tk` - The targetKey value of the associated object, either as a single value or an array.
  

### `remove()`

Remove the association with the given objects.

**Signature**

- `async remove(options: TargetKey | TargetKey[] | AssociatedOptions)`

**Detailed Information**

Same parameters as the [`add()`](#add) method.

### `set()`

Set the associated object of the current relationship.

**Signature**

- `async set(options: TargetKey | TargetKey[] | AssociatedOptions)`

**Detailed Information**

Same parameters as the [`add()`](#add) method.

---

## File: docs/en-US/api/database/relation-repository/has-one-repository.md

# HasOneRepository

## Overview

`HasOneRepository` is the associated repository of type `HasOne`.

```typescript
const User = db.collection({
  name: 'users',
  fields: [
    { type: 'hasOne', name: 'profile' },
    { type: 'string', name: 'name' },
  ],
});

const Profile = db.collection({
  name: 'profiles',
  fields: [{ type: 'string', name: 'avatar' }],
});

const user = await User.repository.create({
  values: { name: 'u1' },
});

// Get the associated repository
const userProfileRepository = User.repository
  .relation('profile')
  .of(user.get('id'));

// Or to initialize directly
new HasOneRepository(User, 'profile', user.get('id'));
```

## Class Methods

### `find()`

Find associated objects.

**Signature**

- `async find(options?: SingleRelationFindOption): Promise<Model<any> | null>`

**Type**

```typescript
interface SingleRelationFindOption extends Transactionable {
  fields?: Fields;
  except?: Except;
  appends?: Appends;
  filter?: Filter;
}
```

**Detailed Information**

Query parameters are the same as [`Repository.find()`](../repository.md#find).

**Example**

```typescript
const profile = await UserProfileRepository.find();
// Return null if the associated object does not exist
```

### `create()`

Create associated objects.

**Signature**

- `async create(options?: CreateOptions): Promise<Model>`



**Example**

```typescript
const profile = await UserProfileRepository.create({
  values: { avatar: 'avatar1' },
});

console.log(profile.toJSON());
/*
{
  id: 1,
  avatar: 'avatar1',
  userId: 1,
  updatedAt: 2022-09-24T13:59:40.025Z,
  createdAt: 2022-09-24T13:59:40.025Z
}
*/
```

### `update()`

Update associated objects.

**Signature**

- `async update(options: UpdateOptions): Promise<Model>`



**Example**

```typescript
const profile = await UserProfileRepository.update({
  values: { avatar: 'avatar2' },
});

profile.get('avatar'); // 'avatar2'
```

### `remove()`

Remove associated objects. Only to unassociate, not to delete the associated object.

**Signature**

- `async remove(options?: Transactionable): Promise<void>`

**Detailed Information**

- `transaction`: Transaction object. If no transaction parameter is passed, the method will automatically create an internal transaction.

**Example**

```typescript
await UserProfileRepository.remove();
(await UserProfileRepository.find()) == null; // true

(await Profile.repository.count()) === 1; // true
```

### `destroy()`

Delete associated objects.

**Signature**

- `async destroy(options?: Transactionable): Promise`

**Detailed Information**

- `transaction`: Transaction object. If no transaction parameter is passed, the method will automatically create an internal transaction.

**Example**

```typescript
await UserProfileRepository.destroy();
(await UserProfileRepository.find()) == null; // true
(await Profile.repository.count()) === 0; // true
```

### `set()`

Set associated objects.

**Signature**

- `async set(options: TargetKey | SetOption): Promise<void>`

**Type**

```typescript
interface SetOption extends Transactionable {
  tk?: TargetKey;
}
```

**Detailed Information**

- tk: Set the targetKey of the associated object.
- transaction: Transaction object. If no transaction parameter is passed, the method will automatically create an internal transaction.

**Example**

```typescript
const newProfile = await Profile.repository.create({
  values: { avatar: 'avatar2' },
});

await UserProfileRepository.set(newProfile.get('id'));

(await UserProfileRepository.find()).get('id') === newProfile.get('id'); // true
```

---

## File: docs/en-US/api/database/relation-repository/index.md

# RelationRepository

`RelationRepository` is a `Repository` object for relation types, which allows operations on associated data without loading the associations. Based on `RelationRepository`, each association type derives its corresponding implementation, which are:

- [`HasOneRepository`](#has-one-repository)
- `HasManyRepository`
- `BelongsToRepository`
- `BelongsToManyRepository`

## Constructor

**Signature**

- `constructor(sourceCollection: Collection, association: string, sourceKeyValue: string | number)`

**Parameters**

| Parameter Name     | Type               | Default Value | Description                                               |
| ------------------ | ------------------ | ------------- | --------------------------------------------------------- |
| `sourceCollection` | `Collection`       | -             | The Collection corresponding to the referencing relation in the association |
| `association`      | `string`           | -             | The name of the association                               |
| `sourceKeyValue`   | `string \| number` | -             | The key value corresponding to the referencing relation   |

## Base Class Properties

### `db: Database`

Database object

### `sourceCollection`

The Collection corresponding to the referencing relation in the association

### `targetCollection`

The Collection corresponding to the referenced relation in the association

### `association`

The association object in Sequelize corresponding to the current association

### `associationField`

The field in the Collection corresponding to the current association

### `sourceKeyValue`

The key value corresponding to the referencing relation

---

## File: docs/en-US/api/database/shared/create-options.md

**Type**

```typescript
type WhiteList = string[];
type BlackList = string[];
type AssociationKeysToBeUpdate = string[];

interface CreateOptions extends SequelizeCreateOptions {
  values?: Values;
  whitelist?: WhiteList;
  blacklist?: BlackList;
  updateAssociationValues?: AssociationKeysToBeUpdate;
  context?: any;
}
```

**Details**

- `values`: The data object of the record to be created.
- `whitelist`: Specifies which fields in the data object of the record to be created **can be written**. If this parameter is not passed, all fields are allowed to be written by default.
- `blacklist`: Specifies which fields in the data object of the record to be created **are not allowed to be written**. If this parameter is not passed, all fields are allowed to be written by default.
- `transaction`: The transaction object. If no transaction parameter is passed, the method will automatically create an internal transaction.

---

## File: docs/en-US/api/database/shared/destroy-options.md

**Type**

```typescript
interface DestroyOptions extends SequelizeDestroyOptions {
  filter?: Filter;
  filterByTk?: TargetKey | TargetKey[];
  truncate?: boolean;
  context?: any;
}
```

**Details**

- `filter`: Specifies the filtering conditions for the records to be deleted. For detailed usage of Filter, refer to the [`find()`](#find) method.
- `filterByTk`: Specifies the filtering conditions for the records to be deleted by TargetKey.
- `truncate`: Whether to truncate the table data, effective when no `filter` or `filterByTk` parameters are passed.
- `transaction`: Transaction object. If no transaction parameter is passed, the method will automatically create an internal transaction.

---

## File: docs/en-US/api/database/shared/find-one.md

**Type**

```typescript
type FindOneOptions = Omit<FindOptions, 'limit'>;
```

**Parameters**

Most parameters are the same as those in `find()`. The difference is that `findOne()` returns only a single piece of data, so the `limit` parameter is not needed, and the query is always set to `1`.

---

## File: docs/en-US/api/database/shared/find-options.md

[Empty file]

---

## File: docs/en-US/api/database/shared/transaction.md

- `transaction`: Transaction object. If no transaction parameter is passed, the method will automatically create an internal transaction.

---

## File: docs/en-US/api/database/shared/update-options.md

**Type**

```typescript
interface UpdateOptions extends Omit<SequelizeUpdateOptions, 'where'> {
  values: Values;
  filter?: Filter;
  filterByTk?: TargetKey;
  whitelist?: WhiteList;
  blacklist?: BlackList;
  updateAssociationValues?: AssociationKeysToBeUpdate;
  context?: any;
}
```

**Details**

- `values`: The data object of the records to be updated.
- `filter`: Specifies the filter conditions for the records to be updated. For detailed usage of Filter, refer to the [`find()`](#find) method.
- `filterByTk`: Specifies the filter conditions for the records to be updated by TargetKey.
- `whitelist`: A whitelist for the `values` fields. Only fields listed will be written.
- `blacklist`: A blacklist for the `values` fields. Fields listed will not be written.
- `transaction`: The transaction object. If no transaction parameter is passed, the method will automatically create an internal transaction.

At least one of `filterByTk` or `filter` must be provided.

---

## File: docs/en-US/api/field/markdown-vditor/index.md

# markdown

## Example

This is an embedded Markdown editor:

<MarkdownEditor />

---

## File: docs/en-US/api/handlebars-helpers/array.md

# Array

## {{after}}

Returns all of the items in an array after the specified index. Opposite of [before](#before).

**Params**

* `array` **{Array}**: Collection
* `n` **{Number}**: Starting index (number of items to exclude)
* `returns` **{Array}**: Array exluding `n` items.

**Example**

```handlebars
<!-- array: ['a', 'b', 'c'] -->
{{after array 1}}
<!-- results in: '["c"]' -->
```

## {{arrayify}}

Cast the given `value` to an array.

**Params**

* `value` **{any}**
* `returns` **{Array}**

**Example**

```handlebars
{{arrayify "foo"}}
<!-- results in: [ "foo" ] -->
```

## {{before}}

Return all of the items in the collection before the specified count. Opposite of [after](#after).

**Params**

* `array` **{Array}**
* `n` **{Number}**
* `returns` **{Array}**: Array excluding items after the given number.

**Example**

```handlebars
<!-- array: ['a', 'b', 'c'] -->
{{before array 2}}
<!-- results in: '["a", "b"]' -->
```

## {{eachIndex}}

**Params**

* `array` **{Array}**
* `options` **{Object}**
* `returns` **{String}**

**Example**

```handlebars
<!-- array: ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'] -->
{{#eachIndex array}}
  {{item}} is {{index}}
{{/eachIndex}}
```

## {{filter}}

Block helper that filters the given array and renders the block for values that evaluate to `true`, otherwise the inverse block is returned.

**Params**

* `array` **{Array}**
* `value` **{any}**
* `options` **{Object}**
* `returns` **{String}**

**Example**

```handlebars
<!-- array: ['a', 'b', 'c'] -->
{{#filter array "foo"}}AAA{{else}}BBB{{/filter}}
<!-- results in: 'BBB' -->
```

## {{first}}

Returns the first item, or first `n` items of an array.

**Params**

* `array` **{Array}**
* `n` **{Number}**: Number of items to return, starting at `0`.
* `returns` **{Array}**

**Example**

```handlebars
{{first "['a', 'b', 'c', 'd', 'e']" 2}}
<!-- results in: '["a", "b"]' -->
```

## {{forEach}}

Iterates over each item in an array and exposes the current item in the array as context to the inner block. In addition to the current array item, the helper exposes the following variables to the inner block:

* `index`
* `total`
* `isFirst`
* `isLast`
Also, `@index` is exposed as a private variable, and additional
private variables may be defined as hash arguments.

**Params**

* `array` **{Array}**
* `returns` **{String}**

**Example**

```handlebars
<!-- accounts = [
{'name': 'John', 'email': 'john@example.com'},
{'name': 'Malcolm', 'email': 'malcolm@example.com'},
{'name': 'David', 'email': 'david@example.com'}
] -->

{{#forEach accounts}}
  <a href="mailto:{{ email }}" title="Send an email to {{ name }}">
    {{ name }}
  </a>{{#unless isLast}}, {{/unless}}
{{/forEach}}
```

## {{inArray}}

Block helper that renders the block if an array has the given `value`. Optionally specify an inverse block to render when the array does not have the given value.

**Params**

* `array` **{Array}**
* `value` **{any}**
* `options` **{Object}**
* `returns` **{String}**

**Example**

```handlebars
<!-- array: ['a', 'b', 'c'] -->
{{#inArray array "d"}}
  foo
{{else}}
  bar
{{/inArray}}
<!-- results in: 'bar' -->
```

## {{isArray}}

Returns true if `value` is an es5 array.

**Params**

* `value` **{any}**: The value to test.
* `returns` **{Boolean}**

**Example**

```handlebars
{{isArray "abc"}}
<!-- results in: false -->

<!-- array: [1, 2, 3] -->
{{isArray array}}
<!-- results in: true -->
```

## {{itemAt}}

Returns the item from `array` at index `idx`.

**Params**

* `array` **{Array}**
* `idx` **{Number}**
* `returns` **{any}** `value`

**Example**

```handlebars
<!-- array: ['a', 'b', 'c'] -->
{{itemAt array 1}}
<!-- results in: 'b' -->
```

## {{join}}

Join all elements of array into a string, optionally using a given separator.

**Params**

* `array` **{Array}**
* `separator` **{String}**: The separator to use. Defaults to `,`.
* `returns` **{String}**

**Example**

```handlebars
<!-- array: ['a', 'b', 'c'] -->
{{join array}}
<!-- results in: 'a, b, c' -->

{{join array '-'}}
<!-- results in: 'a-b-c' -->
```

## {{equalsLength}}

Returns true if the the length of the given `value` is equal
to the given `length`. Can be used as a block or inline helper.

**Params**

* `value` **{Array|String}**
* `length` **{Number}**
* `options` **{Object}**
* `returns` **{String}**

## {{last}}

Returns the last item, or last `n` items of an array or string. Opposite of [first](#first).

**Params**

* `value` **{Array|String}**: Array or string.
* `n` **{Number}**: Number of items to return from the end of the array.
* `returns` **{Array}**

**Example**

```handlebars
<!-- var value = ['a', 'b', 'c', 'd', 'e'] -->

{{last value}}
<!-- results in: ['e'] -->

{{last value 2}}
<!-- results in: ['d', 'e'] -->

{{last value 3}}
<!-- results in: ['c', 'd', 'e'] -->
```

## {{length}}

Returns the length of the given string or array.

**Params**

* `value` **{Array|Object|String}**
* `returns` **{Number}**: The length of the value.

**Example**

```handlebars
{{length '["a", "b", "c"]'}}
<!-- results in: 3 -->

<!-- results in: myArray = ['a', 'b', 'c', 'd', 'e']; -->
{{length myArray}}
<!-- results in: 5 -->

<!-- results in: myObject = {'a': 'a', 'b': 'b'}; -->
{{length myObject}}
<!-- results in: 2 -->
```

## {{lengthEqual}}

Alias for [equalsLength](#equalsLength)

## {{map}}

Returns a new array, created by calling `function` on each element of the given `array`. For example,

**Params**

* `array` **{Array}**
* `fn` **{Function}**
* `returns` **{String}**

**Example**

```handlebars
<!-- array: ['a', 'b', 'c'], and "double" is a
fictitious function that duplicates letters -->
{{map array double}}
<!-- results in: '["aa", "bb", "cc"]' -->
```

## {{pluck}}

Map over the given object or array or objects and create an array of values from the given `prop`. Dot-notation may be used (as a string) to get nested properties.

**Params**

* `collection` **{Array|Object}**
* `prop` **{Function}**
* `returns` **{String}**

**Example**

```handlebars
// {{pluck items "data.title"}}
<!-- results in: '["aa", "bb", "cc"]' -->
```

## {{reverse}}

Reverse the elements in an array, or the characters in a string.

**Params**

* `value` **{Array|String}**
* `returns` **{Array|String}**: Returns the reversed string or array.

**Example**

```handlebars
<!-- value: 'abcd' -->
{{reverse value}}
<!-- results in: 'dcba' -->
<!-- value: ['a', 'b', 'c', 'd'] -->
{{reverse value}}
<!-- results in: ['d', 'c', 'b', 'a'] -->
```

## {{some}}

Block helper that returns the block if the callback returns true for some value in the given array.

**Params**

* `array` **{Array}**
* `iter` **{Function}**: Iteratee
* **{Options}**: Handlebars provided options object
* `returns` **{String}**

**Example**

```handlebars
<!-- array: [1, 'b', 3] -->
{{#some array isString}}
  Render me if the array has a string.
{{else}}
  Render me if it doesn't.
{{/some}}
<!-- results in: 'Render me if the array has a string.' -->
```

## {{sort}}

Sort the given `array`. If an array of objects is passed, you may optionally pass a `key` to sort on as the second argument. You may alternatively pass a sorting function as the second argument.

**Params**

* `array` **{Array}**: the array to sort.
* `key` **{String|Function}**: The object key to sort by, or sorting function.

**Example**

```handlebars
<!-- array: ['b', 'a', 'c'] -->
{{sort array}}
<!-- results in: '["a", "b", "c"]' -->
```

## {{sortBy}}

Sort an `array`. If an array of objects is passed, you may optionally pass a `key` to sort on as the second argument. You may alternatively pass a sorting function as the second argument.

**Params**

* `array` **{Array}**: the array to sort.
* `props` **{String|Function}**: One or more properties to sort by, or sorting functions to use.

**Example**

```handlebars
<!-- array: [{a: 'zzz'}, {a: 'aaa'}] -->
{{sortBy array "a"}}
<!-- results in: '[{"a":"aaa"}, {"a":"zzz"}]' -->
```

## {{withAfter}}

Use the items in the array _after_ the specified index as context inside a block. Opposite of [withBefore](#withBefore).

**Params**

* `array` **{Array}**
* `idx` **{Number}**
* `options` **{Object}**
* `returns` **{Array}**

**Example**

```handlebars
<!-- array: ['a', 'b', 'c', 'd', 'e'] -->
{{#withAfter array 3}}
  {{this}}
{{/withAfter}}
<!-- results in: "de" -->
```

## {{withBefore}}

Use the items in the array _before_ the specified index as context inside a block. Opposite of [withAfter](#withAfter).

**Params**

* `array` **{Array}**
* `idx` **{Number}**
* `options` **{Object}**
* `returns` **{Array}**

**Example**

```handlebars
<!-- array: ['a', 'b', 'c', 'd', 'e'] -->
{{#withBefore array 3}}
  {{this}}
{{/withBefore}}
<!-- results in: 'ab' -->
```

## {{withFirst}}

Use the first item in a collection inside a handlebars block expression. Opposite of [withLast](#withLast).

**Params**

* `array` **{Array}**
* `idx` **{Number}**
* `options` **{Object}**
* `returns` **{String}**

**Example**

```handlebars
<!-- array: ['a', 'b', 'c'] -->
{{#withFirst array}}
  {{this}}
{{/withFirst}}
<!-- results in: 'a' -->
```

## {{withGroup}}

Block helper that groups array elements by given group `size`.

**Params**

* `array` **{Array}**: The array to iterate over
* `size` **{Number}**: The desired length of each array "group"
* `options` **{Object}**: Handlebars options
* `returns` **{String}**

**Example**

```handlebars
<!-- array: ['a','b','c','d','e','f','g','h'] -->
{{#withGroup array 4}}
  {{#each this}}
    {{.}}
  {{each}}
  <br>
{{/withGroup}}
<!-- results in: -->
<!-- 'a','b','c','d'<br> -->
<!-- 'e','f','g','h'<br> -->
```

## {{withLast}}

Use the last item or `n` items in an array as context inside a block. Opposite of [withFirst](#withFirst).

**Params**

* `array` **{Array}**
* `idx` **{Number}**: The starting index.
* `options` **{Object}**
* `returns` **{String}**

**Example**

```handlebars
<!-- array: ['a', 'b', 'c'] -->
{{#withLast array}}
  {{this}}
{{/withLast}}
<!-- results in: 'c' -->
```

## {{withSort}}

Block helper that sorts a collection and exposes the sorted collection as context inside the block.

**Params**

* `array` **{Array}**
* `prop` **{String}**
* `options` **{Object}**: Specify `reverse="true"` to reverse the array.
* `returns` **{String}**

**Example**

```handlebars
<!-- array: ['b', 'a', 'c'] -->
{{#withSort array}}{{this}}{{/withSort}}
<!-- results in: 'abc' -->
```

## {{unique}}

Block helper that return an array with all duplicate values removed. Best used along with a [each](#each) helper.

**Params**

* `array` **{Array}**
* `options` **{Object}**
* `returns` **{Array}**

**Example**

```handlebars
<!-- array: ['a', 'a', 'c', 'b', 'e', 'e'] -->
{{#each (unique array)}}{{.}}{{/each}}
<!-- results in: 'acbe' -->
```

---

## File: docs/en-US/api/handlebars-helpers/comparison.md

# Comparison

## {{and}}

Helper that renders the block if **both** of the given values are truthy. If an inverse block is specified it will be rendered when falsy. Works as a block helper, inline helper or subexpression.

**Params**

* `a` **{any}**
* `b` **{any}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**

**Example**

```handlebars
<!-- {great: true, magnificent: true} -->
{{#and great magnificent}}A{{else}}B{{/and}}
<!-- results in: 'A' -->
```

## {{compare}}

Render a block when a comparison of the first and third
arguments returns true. The second argument is
the [arithemetic operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operators) to use. You may also
optionally specify an inverse block to render when falsy.

**Params**

* `a` **{}**
* `operator` **{}**: The operator to use. Operators must be enclosed in quotes: `">"`, `"="`, `"<="`, and so on.
* `b` **{}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**: Block, or if specified the inverse block is rendered if falsey.

## {{contains}}

Block helper that renders the block if `collection` has the given `value`, using strict equality (`===`) for comparison, otherwise the inverse block is rendered (if specified). If a `startIndex` is specified and is negative, it is used as the offset from the end of the collection.

**Params**

* `collection` **{Array|Object|String}**: The collection to iterate over.
* `value` **{any}**: The value to check for.
* `[startIndex=0]` **{Number}**: Optionally define the starting index.
* `options` **{Object}**: Handlebars provided options object.

**Example**

```handlebars
<!-- array = ['a', 'b', 'c'] -->
{{#contains array "d"}}
  This will not be rendered.
{{else}}
  This will be rendered.
{{/contains}}
```

## {{default}}

Returns the first value that is not undefined, otherwise the "default" value is returned.

**Params**

* `value` **{any}**
* `defaultValue` **{any}**
* `returns` **{String}**

## {{eq}}

Block helper that renders a block if `a` is **equal to** `b`.
If an inverse block is specified it will be rendered when falsy.
You may optionally use the `compare=""` hash argument for the
second value.

**Params**

* `a` **{String}**
* `b` **{String}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**: Block, or inverse block if specified and falsey.

## {{gt}}

Block helper that renders a block if `a` is **greater than** `b`.

If an inverse block is specified it will be rendered when falsy.
You may optionally use the `compare=""` hash argument for the
second value.

**Params**

* `a` **{String}**
* `b` **{String}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**: Block, or inverse block if specified and falsey.

## {{gte}}

Block helper that renders a block if `a` is **greater than or equal to** `b`.

If an inverse block is specified it will be rendered when falsy.
You may optionally use the `compare=""` hash argument for the
second value.

**Params**

* `a` **{String}**
* `b` **{String}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**: Block, or inverse block if specified and falsey.

## {{has}}

Block helper that renders a block if `value` has `pattern`.
If an inverse block is specified it will be rendered when falsy.

**Params**

* `val` **{any}**: The value to check.
* `pattern` **{any}**: The pattern to check for.
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**

## {{isEmpty}}

Inline, subexpression, or block helper that returns true (or the block) if the given collection is empty, or false (or the inverse block, if supplied) if the colleciton is not empty.

**Params**

* `collection` **{Object}**
* `options` **{Object}**
* `returns` **{String}**

**Example**

```handlebars
<!-- array: [] -->
{{#isEmpty array}}AAA{{else}}BBB{{/isEmpty}}
<!-- results in: 'AAA' -->

<!-- array: [] -->
{{isEmpty array}}
<!-- results in: true -->
```

## {{isFalsey}}

Returns true if the given `value` is falsey. Uses the [falsey](https://github.com/jonschlinkert/falsey)
library for comparisons. Please see that library for more information
or to report bugs with this helper.

**Params**

* `val` **{any}**
* `options` **{Options}**
* `returns` **{Boolean}**

## {{isTruthy}}

Returns true if the given `value` is truthy. Uses the [falsey](https://github.com/jonschlinkert/falsey)
library for comparisons. Please see that library for more information
or to report bugs with this helper.

**Params**

* `val` **{any}**
* `options` **{Options}**
* `returns` **{Boolean}**

## {{ifEven}}

Return true if the given value is an even number.

**Params**

* `number` **{Number}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**: Block, or inverse block if specified and falsey.

**Example**

```handlebars
{{#ifEven value}}
  render A
{{else}}
  render B
{{/ifEven}}
```

## {{ifNth}}

Conditionally renders a block if the remainder is zero when
`a` operand is divided by `b`. If an inverse block is specified
it will be rendered when the remainder is **not zero**.

**Params**

* **{}**: {Number}
* **{}**: {Number}
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**: Block, or inverse block if specified and falsey.

## {{ifOdd}}

Block helper that renders a block if `value` is **an odd number**. If an inverse block is specified it will be rendered when falsy.

**Params**

* `value` **{Object}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**: Block, or inverse block if specified and falsey.

**Example**

```handlebars
{{#ifOdd value}}
  render A
{{else}}
  render B
{{/ifOdd}}
```

## {{is}}

Block helper that renders a block if `a` is **equal to** `b`.
If an inverse block is specified it will be rendered when falsy.
Similar to [eq](#eq) but does not do strict equality.

**Params**

* `a` **{any}**
* `b` **{any}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**

## {{isnt}}

Block helper that renders a block if `a` is **not equal to** `b`.
If an inverse block is specified it will be rendered when falsy.
Similar to [unlessEq](#unlesseq) but does not use strict equality for
comparisons.

**Params**

* `a` **{String}**
* `b` **{String}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**

## {{lt}}

Block helper that renders a block if `a` is **less than** `b`.

If an inverse block is specified it will be rendered when falsy.
You may optionally use the `compare=""` hash argument for the
second value.

**Params**

* `context` **{Object}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**: Block, or inverse block if specified and falsey.

## {{lte}}

Block helper that renders a block if `a` is **less than or equal to** `b`.

If an inverse block is specified it will be rendered when falsy.
You may optionally use the `compare=""` hash argument for the
second value.

**Params**

* `a` **{Sring}**
* `b` **{Sring}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**: Block, or inverse block if specified and falsey.

## {{neither}}

Block helper that renders a block if **neither of** the given values
are truthy. If an inverse block is specified it will be rendered
when falsy.

**Params**

* `a` **{any}**
* `b` **{any}**
* `options` **{}**: Handlebars options object
* `returns` **{String}**: Block, or inverse block if specified and falsey.

## {{not}}

Returns true if `val` is falsey. Works as a block or inline helper.

**Params**

* `val` **{String}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**

## {{or}}

Block helper that renders a block if **any of** the given values is truthy. If an inverse block is specified it will be rendered when falsy.

**Params**

* `arguments` **{...any}**: Variable number of arguments
* `options` **{Object}**: Handlebars options object
* `returns` **{String}**: Block, or inverse block if specified and falsey.

**Example**

```handlebars
{{#or a b c}}
  If any value is true this will be rendered.
{{/or}}
```

## {{unlessEq}}

Block helper that always renders the inverse block **unless `a` is
is equal to `b`**.

**Params**

* `a` **{String}**
* `b` **{String}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**: Inverse block by default, or block if falsey.

## {{unlessGt}}

Block helper that always renders the inverse block **unless `a` is
is greater than `b`**.

**Params**

* `a` **{Object}**: The default value
* `b` **{Object}**: The value to compare
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**: Inverse block by default, or block if falsey.

## {{unlessLt}}

Block helper that always renders the inverse block **unless `a` is
is less than `b`**.

**Params**

* `a` **{Object}**: The default value
* `b` **{Object}**: The value to compare
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**: Block, or inverse block if specified and falsey.

## {{unlessGteq}}

Block helper that always renders the inverse block **unless `a` is
is greater than or equal to `b`**.

**Params**

* `a` **{any}**
* `b` **{any}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**: Block, or inverse block if specified and falsey.

## {{unlessLteq}}

Block helper that always renders the inverse block **unless `a` is
is less than or equal to `b`**.

**Params**

* `a` **{any}**
* `b` **{any}**
* `options` **{Object}**: Handlebars provided options object
* `returns` **{String}**: Block, or inverse block if specified and falsey.

---

## File: docs/en-US/api/handlebars-helpers/core.md

# Built-in Helpers

https://handlebarsjs.com/guide/builtin-helpers.html

## {{if}}

Renders a block if the given condition is truthy.

**Params**

- `condition` **{Any}**: The condition to evaluate.

**Returns**: The content inside the block if the condition is truthy, otherwise returns nothing.

**Example**

```handlebars
{{#if condition}}
  This will be displayed if the condition is true.
{{/if}}
```

## {{unless}}

Renders a block if the given condition is falsy. This is the opposite of `if`.

**Params**

- `condition` **{Any}**: The condition to evaluate.

**Returns**: The content inside the block if the condition is falsy, otherwise returns nothing.

**Example**

```handlebars
{{#unless condition}}
  This will be displayed if the condition is false.
{{/unless}}
```

---

## {{each}}

Iterates over an array or object and renders a block for each item.

**Params**

- `collection` **{Array|Object}**: The array or object to iterate over.

**Returns**: Renders the block for each item in the collection.

**Example**

```handlebars
{{#each items}}
  <li>{{this}}</li>
{{/each}}
```

## {{with}}

Renders a block with a given context. It allows you to specify a context for the block, simplifying access to deeply nested properties.

**Params**

- `context` **{Any}**: The context to use within the block.

**Returns**: Renders the block with the provided context.

**Example**

```handlebars
{{#with person}}
  <p>Name: {{name}}</p>
  <p>Age: {{age}}</p>
{{/with}}
```

## {{lookup}}

Looks up the value of a specified key in an object. This helper is useful for accessing dynamic keys.

**Params**

- `context` **{Object}**: The object to look up the key from.
- `key` **{String|Number}**: The key to look up.

**Returns**: The value of the specified key in the object.

**Example**

```handlebars
{{lookup person "name"}}
<!-- If person is { name: "Alice", age: 30 }, it results in: "Alice" -->
```

---

## File: docs/en-US/api/handlebars-helpers/date.md

# Date

## {{dateFormat}}

The "dateFormat" helper in Handlebars is used to format a date using the day.js library. It takes two required arguments and an optional third argument for the timezone.

**Params**

* `datetime` **{String}**
* `format` **{String}**
* `timezone` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{dateFormat now "YYYY-MM-DD HH:mm:ss"}}
{{dateFormat now "YYYY-MM-DD HH:mm:ss" "Asia/Tokyo"}}
{{dateFormat now "YYYY-MM-DD HH:mm:ss" "UTC"}}
```

---

## File: docs/en-US/api/handlebars-helpers/html.md

# HTML

## {{qrcode}}

---

## File: docs/en-US/api/handlebars-helpers/i18n.md

# I18n

## {{t}}

**Params**

* `key` **{String}**
* `ns` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{t "Today"}}
{{t "Permissions" "@nocobase/plugin-acl"}}
```

---

## File: docs/en-US/api/handlebars-helpers/index.md

# Handlebars Helpers

| Category       | Description                         |
|-------------|-------------------------------------|
| [Core](./core.md)      | Built-in helpers        |
| [Array](./array.md)       | Operations and methods related to arrays       |
| [Comparison](./comparison.md) | Comparison operators and related methods       |
| [Date](./date.md)        | Operations and methods related to date and time handling |
| [HTML](./html.md)        | Content related to HTML documents and elements  |
| [I18n](./i18n.md)        | Support for internationalization and multilingual handling |
| [Math](./math.md)        | Mathematical functions and calculations       |
| [Number](./number.md)    | Content related to number handling and formatting |
| [Object](./object.md)    | Methods related to object operations and properties |
| [Path](./path.md)        | Path operations and content related to the file system |
| [Regex](./regex.md)      | Regular expressions and their usage            |
| [String](./string.md)    | Methods related to string manipulation and operations |
| [URL](./url.md)          | Content related to URL parsing and construction  |

---

## File: docs/en-US/api/handlebars-helpers/math.md

# Math

## {{abs}}

Return the magnitude of `a`.

**Params**

* `a` **{Number}**
* `returns` **{Number}**

## {{add}}

Return the sum of `a` plus `b`.

**Params**

* `a` **{Number}**
* `b` **{Number}**
* `returns` **{Number}**

## {{avg}}

Returns the average of all numbers in the given array.

**Params**

* `array` **{Array}**: Array of numbers to add up.
* `returns` **{Number}**

**Example**

```handlebars
{{avg "[1, 2, 3, 4, 5]"}}
<!-- results in: '3' -->
```

## {{ceil}}

Get the `Math.ceil()` of the given value.

**Params**

* `value` **{Number}**
* `returns` **{Number}**

## {{divide}}

Divide `a` by `b`

**Params**

* `a` **{Number}**: numerator
* `b` **{Number}**: denominator

## {{floor}}

Get the `Math.floor()` of the given value.

**Params**

* `value` **{Number}**
* `returns` **{Number}**

## {{minus}}

Return the difference of `a` minus `b`.

**Params**

* `a` **{Number}**
* `b` **{Number}**

## {{modulo}}

Get the remainder of a division operation.

**Params**

* `a` **{Number}**
* `b` **{Number}**
* `returns` **{Number}**

## {{multiply}}

Return the product of `a` times `b`.

**Params**

* `a` **{Number}**: factor
* `b` **{Number}**: multiplier
* `returns` **{Number}**

## {{plus}}

Add `a` by `b`.

**Params**

* `a` **{Number}**: factor
* `b` **{Number}**: multiplier

## {{random}}

Generate a random number between two values

**Params**

* `min` **{Number}**
* `max` **{Number}**
* `returns` **{String}**

## {{remainder}}

Get the remainder when `a` is divided by `b`.

**Params**

* `a` **{Number}**: a
* `b` **{Number}**: b

## {{round}}

Round the given number.

**Params**

* `number` **{Number}**
* `returns` **{Number}**

## {{subtract}}

Return the product of `a` minus `b`.

**Params**

* `a` **{Number}**
* `b` **{Number}**
* `returns` **{Number}**

## {{sum}}

Returns the sum of all numbers in the given array.

**Params**

* `array` **{Array}**: Array of numbers to add up.
* `returns` **{Number}**

**Example**

```handlebars
{{sum "[1, 2, 3, 4, 5]"}}
<!-- results in: '15' -->
```

## {{times}}

Multiply number `a` by number `b`.

**Params**

* `a` **{Number}**: factor
* `b` **{Number}**: multiplier
* `returns` **{Number}**

---

## File: docs/en-US/api/handlebars-helpers/number.md

# Number

## {{bytes}}

Format a number to it's equivalent in bytes. If a string is passed, it's length will be formatted and returned.

**Examples:**

* `'foo' => 3 B`
* `13661855 => 13.66 MB`
* `825399 => 825.39 kB`
* `1396 => 1.4 kB`

**Params**

* `number` **{Number|String}**
* `returns` **{String}**

## {{addCommas}}

Add commas to numbers

**Params**

* `num` **{Number}**
* `returns` **{Number}**

## {{phoneNumber}}

Convert a string or number to a formatted phone number.

**Params**

* `num` **{Number|String}**: The phone number to format, e.g. `8005551212`
* `returns` **{Number}**: Formatted phone number: `(800) 555-1212`

## {{toAbbr}}

Abbreviate numbers to the given number of `precision`. This is for
general numbers, not size in bytes.

**Params**

* `number` **{Number}**
* `precision` **{Number}**
* `returns` **{String}**

## {{toExponential}}

Returns a string representing the given number in exponential notation.

**Params**

* `number` **{Number}**
* `fractionDigits` **{Number}**: Optional. An integer specifying the number of digits to use after the decimal point. Defaults to as many digits as necessary to specify the number.
* `returns` **{Number}**

**Example**

```handlebars
{{toExponential number digits}};
```

## {{toFixed}}

Formats the given number using fixed-point notation.

**Params**

* `number` **{Number}**
* `digits` **{Number}**: (Optional) The number of digits to appear after the decimal point; this may be a value between 0 and 20. If this argument is omitted, it is treated as 0.
* `returns` **{String}**: A string representing the given number using fixed-point notation.

**Example**

```handlebars
{{toFixed "1.1234" 2}}
//=> '1.12'
```

## {{toFloat}}

**Params**

* `number` **{Number}**
* `returns` **{Number}**

## {{toInt}}

**Params**

* `number` **{Number}**
* `returns` **{Number}**

## {{toPrecision}}

Returns a string representing the `Number` object to the specified precision.

**Params**

* `number` **{Number}**
* `precision` **{Number}**: (Optional) An integer specifying the number of significant digits. If precison is not between 1 and 100 (inclusive), it will be coerced to `0`.
* `returns` **{String}**: A string representing a Number object in fixed-point or exponential notation rounded to precision significant digits.

**Example**

```handlebars
{{toPrecision "1.1234" 2}}
//=> '1.1'
```

---

## File: docs/en-US/api/handlebars-helpers/object.md

# Object

## {{extend}}

Extend the context with the properties of other objects.
A shallow merge is performed to avoid mutating the context.

**Params**

* `objects` **{Object}**: One or more objects to extend.
* `returns` **{Object}**

## {{forIn}}

Block helper that iterates over the properties of
an object, exposing each key and value on the context.

**Params**

* `context` **{Object}**
* `options` **{Object}**
* `returns` **{String}**

## {{forOwn}}

Block helper that iterates over the **own** properties of
an object, exposing each key and value on the context.

**Params**

* `obj` **{Object}**: The object to iterate over.
* `options` **{Object}**
* `returns` **{String}**

## {{toPath}}

Take arguments and, if they are string or number, convert them to a dot-delineated object property path.

**Params**

* `prop` **{String|Number}**: The property segments to assemble (can be multiple).
* `returns` **{String}**

## {{get}}

Use property paths (`a.b.c`) to get a value or nested value from
the context. Works as a regular helper or block helper.

**Params**

* `prop` **{String}**: The property to get, optionally using dot notation for nested properties.
* `context` **{Object}**: The context object
* `options` **{Object}**: The handlebars options object, if used as a block helper.
* `returns` **{String}**

## {{getObject}}

Use property paths (`a.b.c`) to get an object from
the context. Differs from the `get` helper in that this
helper will return the actual object, including the
given property key. Also, this helper does not work as a
block helper.

**Params**

* `prop` **{String}**: The property to get, optionally using dot notation for nested properties.
* `context` **{Object}**: The context object
* `returns` **{String}**

## {{hasOwn}}

Return true if `key` is an own, enumerable property of the given `context` object.

**Params**

* `key` **{String}**
* `context` **{Object}**: The context object.
* `returns` **{Boolean}**

**Example**

```handlebars
{{hasOwn context key}}
```

## {{isObject}}

Return true if `value` is an object.

**Params**

* `value` **{String}**
* `returns` **{Boolean}**

**Example**

```handlebars
{{isObject "foo"}}
//=> false
```

## {{JSONparse}}

Parses the given string using `JSON.parse`.

**Params**

* `string` **{String}**: The string to parse

**Example**

```handlebars
<!-- string: '{"foo": "bar"}' -->
{{JSONparse string}}
<!-- results in: { foo: 'bar' } -->
```

## {{JSONstringify}}

Stringify an object using `JSON.stringify`.

**Params**

* `obj` **{Object}**: Object to stringify
* `returns` **{String}**

**Example**

```handlebars
<!-- object: { foo: 'bar' } -->
{{JSONstringify object}}
<!-- results in: '{"foo": "bar"}' -->
```

## {{merge}}

Deeply merge the properties of the given `objects` with the
context object.

**Params**

* `object` **{Object}**: The target object. Pass an empty object to shallow clone.
* `objects` **{Object}**
* `returns` **{Object}**

## {{pick}}

Pick properties from the context object.

**Params**

* `properties` **{Array|String}**: One or more properties to pick.
* `context` **{Object}**
* `options` **{Object}**: Handlebars options object.
* `returns` **{Object}**: Returns an object with the picked values. If used as a block helper, the values are passed as context to the inner block. If no values are found, the context is passed to the inverse block.

---

## File: docs/en-US/api/handlebars-helpers/path.md

# Path

## {{absolute}}

Get the directory path segment from the given `filepath`.

**Params**

* `ext` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{absolute "docs/toc.md"}}
<!-- results in: 'docs' -->
```

## {{dirname}}

Get the directory path segment from the given `filepath`.

**Params**

* `ext` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{dirname "docs/toc.md"}}
<!-- results in: 'docs' -->
```

## {{relative}}

Get the relative filepath from `a` to `b`.

**Params**

* `a` **{String}**
* `b` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{relative a b}}
```

## {{basename}}

Get the file extension from the given `filepath`.

**Params**

* `ext` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{basename "docs/toc.md"}}
<!-- results in: 'toc.md' -->
```

## {{stem}}

Get the "stem" from the given `filepath`.

**Params**

* `filepath` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{stem "docs/toc.md"}}
<!-- results in: 'toc' -->
```

## {{extname}}

Get the file extension from the given `filepath`.

**Params**

* `filepath` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{extname "docs/toc.md"}}
<!-- results in: '.md' -->
```

## {{resolve}}

Resolve an absolute path from the given `filepath`.

**Params**

* `filepath` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{resolve "docs/toc.md"}}
<!-- results in: '/User/dev/docs/toc.md' -->
```

## {{segments}}

Get specific (joined) segments of a file path by passing a range of array indices.

**Params**

* `filepath` **{String}**: The file path to split into segments.
* `returns` **{String}**: Returns a single, joined file path.

**Example**

```handlebars
{{segments "a/b/c/d" "2" "3"}}
<!-- results in: 'c/d' -->

{{segments "a/b/c/d" "1" "3"}}
<!-- results in: 'b/c/d' -->

{{segments "a/b/c/d" "1" "2"}}
<!-- results in: 'b/c' -->
```

---

## File: docs/en-US/api/handlebars-helpers/regex.md

# Regex

## {{toRegex}}

Convert the given string to a regular expression.

**Params**

* `str` **{String}**
* `returns` **{RegExp}**

**Example**

```handlebars
{{toRegex "foo"}}
<!-- results in: /foo/ -->
```

## {{test}}

Returns true if the given `str` matches the given regex. A regex can be passed on the context, or using the [toRegex](#toregex) helper as a subexpression.

**Params**

* `str` **{String}**
* `returns` **{RegExp}**

**Example**

```handlebars
{{test "bar" (toRegex "foo")}}
<!-- results in: false -->
{{test "foobar" (toRegex "foo")}}
<!-- results in: true -->
{{test "foobar" (toRegex "^foo$")}}
<!-- results in: false -->
```

---

## File: docs/en-US/api/handlebars-helpers/string.md

# String

## {{append}}

Append the specified `suffix` to the given string.

**Params**

* `str` **{String}**
* `suffix` **{String}**
* `returns` **{String}**

**Example**

```handlebars
<!-- given that "item.stem" is "foo" -->
{{append item.stem ".html"}}
<!-- results in:  'foo.html' -->
```

## {{camelcase}}

camelCase the characters in the given `string`.

**Params**

* `string` **{String}**: The string to camelcase.
* `returns` **{String}**

**Example**

```handlebars
{{camelcase "foo bar baz"}};
<!-- results in:  'fooBarBaz' -->
```

## {{capitalize}}

Capitalize the first word in a sentence.

**Params**

* `str` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{capitalize "foo bar baz"}}
<!-- results in:  "Foo bar baz" -->
```

## {{capitalizeAll}}

Capitalize all words in a string.

**Params**

* `str` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{capitalizeAll "foo bar baz"}}
<!-- results in:  "Foo Bar Baz" -->
```

## {{center}}

Center a string using non-breaking spaces

**Params**

* `str` **{String}**
* `spaces` **{String}**
* `returns` **{String}**

## {{chop}}

Like trim, but removes both extraneous whitespace **and non-word characters** from the beginning and end of a string.

**Params**

* `string` **{String}**: The string to chop.
* `returns` **{String}**

**Example**

```handlebars
{{chop "_ABC_"}}
<!-- results in:  'ABC' -->

{{chop "-ABC-"}}
<!-- results in:  'ABC' -->

{{chop " ABC "}}
<!-- results in:  'ABC' -->
```

## {{dashcase}}

dash-case the characters in `string`. Replaces non-word characters and periods with hyphens.

**Params**

* `string` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{dashcase "a-b-c d_e"}}
<!-- results in:  'a-b-c-d-e' -->
```

## {{dotcase}}

dot.case the characters in `string`.

**Params**

* `string` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{dotcase "a-b-c d_e"}}
<!-- results in:  'a.b.c.d.e' -->
```

## {{downcase}}

Lowercase all of the characters in the given string. Alias for [lowercase](#lowercase).

**Params**

* `string` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{downcase "aBcDeF"}}
<!-- results in:  'abcdef' -->
```

## {{ellipsis}}

Truncates a string to the specified `length`, and appends it with an elipsis, `…`.

**Params**

* `str` **{String}**
* `length` **{Number}**: The desired length of the returned string.
* `returns` **{String}**: The truncated string.

**Example**

```handlebars
{{ellipsis (sanitize "<span>foo bar baz</span>"), 7}}
<!-- results in:  'foo bar…' -->
{{ellipsis "foo bar baz", 7}}
<!-- results in:  'foo bar…' -->
```

## {{hyphenate}}

Replace spaces in a string with hyphens.

**Params**

* `str` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{hyphenate "foo bar baz qux"}}
<!-- results in:  "foo-bar-baz-qux" -->
```

## {{isString}}

Return true if `value` is a string.

**Params**

* `value` **{String}**
* `returns` **{Boolean}**

**Example**

```handlebars
{{isString "foo"}}
<!-- results in:  'true' -->
```

## {{lowercase}}

Lowercase all characters in the given string.

**Params**

* `str` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{lowercase "Foo BAR baZ"}}
<!-- results in:  'foo bar baz' -->
```

## {{occurrences}}

Return the number of occurrences of `substring` within the given `string`.

**Params**

* `str` **{String}**
* `substring` **{String}**
* `returns` **{Number}**: Number of occurrences

**Example**

```handlebars
{{occurrences "foo bar foo bar baz" "foo"}}
<!-- results in:  2 -->
```

## {{pascalcase}}

PascalCase the characters in `string`.

**Params**

* `string` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{pascalcase "foo bar baz"}}
<!-- results in:  'FooBarBaz' -->
```

## {{pathcase}}

path/case the characters in `string`.

**Params**

* `string` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{pathcase "a-b-c d_e"}}
<!-- results in:  'a/b/c/d/e' -->
```

## {{plusify}}

Replace spaces in the given string with pluses.

**Params**

* `str` **{String}**: The input string
* `returns` **{String}**: Input string with spaces replaced by plus signs

**Example**

```handlebars
{{plusify "foo bar baz"}}
<!-- results in:  'foo+bar+baz' -->
```

## {{prepend}}

Prepends the given `string` with the specified `prefix`.

**Params**

* `str` **{String}**
* `prefix` **{String}**
* `returns` **{String}**

**Example**

```handlebars
<!-- given that "val" is "bar" -->
{{prepend val "foo-"}}
<!-- results in:  'foo-bar' -->
```

## {{raw}}

Render a block without processing mustache templates inside the block.

**Params**

* `options` **{Object}**
* `returns` **{String}**

**Example**

```handlebars
{{{{#raw}}}}
{{foo}}
{{{{/raw}}}}
<!-- results in:  '{{foo}}' -->
```

## {{remove}}

Remove all occurrences of `substring` from the given `str`.

**Params**

* `str` **{String}**
* `substring` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{remove "a b a b a b" "a "}}
<!-- results in:  'b b b' -->
```

## {{removeFirst}}

Remove the first occurrence of `substring` from the given `str`.

**Params**

* `str` **{String}**
* `substring` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{remove "a b a b a b" "a"}}
<!-- results in:  ' b a b a b' -->
```

## {{replace}}

Replace all occurrences of substring `a` with substring `b`.

**Params**

* `str` **{String}**
* `a` **{String}**
* `b` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{replace "a b a b a b" "a" "z"}}
<!-- results in:  'z b z b z b' -->
```

## {{replaceFirst}}

Replace the first occurrence of substring `a` with substring `b`.

**Params**

* `str` **{String}**
* `a` **{String}**
* `b` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{replace "a b a b a b" "a" "z"}}
<!-- results in:  'z b a b a b' -->
```

## {{reverse}}

Reverse a string.

**Params**

* `str` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{reverse "abcde"}}
<!-- results in:  'edcba' -->
```

## {{sentence}}

Sentence case the given string

**Params**

* `str` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{sentence "hello world. goodbye world."}}
<!-- results in:  'Hello world. Goodbye world.' -->
```

## {{snakecase}}

snake_case the characters in the given `string`.

**Params**

* `string` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{snakecase "a-b-c d_e"}}
<!-- results in:  'a_b_c_d_e' -->
```

## {{split}}

Split `string` by the given `character`.

**Params**

* `string` **{String}**: The string to split.
* `returns` **{String}** `character`: Default is an empty string.

**Example**

```handlebars
{{split "a,b,c" ","}}
<!-- results in:  ['a', 'b', 'c'] -->
```

## {{startsWith}}

Tests whether a string begins with the given prefix.

**Params**

* `prefix` **{String}**
* `testString` **{String}**
* `options` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{#startsWith "Goodbye" "Hello, world!"}}
  Whoops
{{else}}
  Bro, do you even hello world?
{{/startsWith}}
```

## {{titleize}}

Title case the given string.

**Params**

* `str` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{titleize "this is title case"}}
<!-- results in:  'This Is Title Case' -->
```

## {{trim}}

Removes extraneous whitespace from the beginning and end of a string.

**Params**

* `string` **{String}**: The string to trim.
* `returns` **{String}**

**Example**

```handlebars
{{trim " ABC "}}
<!-- results in:  'ABC' -->
```

## {{trimLeft}}

Removes extraneous whitespace from the beginning of a string.

**Params**

* `string` **{String}**: The string to trim.
* `returns` **{String}**

**Example**

```handlebars
{{trim " ABC "}}
<!-- results in:  'ABC ' -->
```

## {{trimRight}}

Removes extraneous whitespace from the end of a string.

**Params**

* `string` **{String}**: The string to trim.
* `returns` **{String}**

**Example**

```handlebars
{{trimRight " ABC "}}
<!-- results in:  ' ABC' -->
```

## {{truncate}}

Truncate a string to the specified `length`. Also see [ellipsis](#ellipsis).

**Params**

* `str` **{String}**
* `limit` **{Number}**: The desired length of the returned string.
* `suffix` **{String}**: Optionally supply a string to use as a suffix to denote when the string has been truncated. Otherwise an ellipsis (`…`) will be used.
* `returns` **{String}**: The truncated string.

**Example**

```handlebars
truncate("foo bar baz", 7);
<!-- results in:  'foo bar' -->
truncate(sanitize("<span>foo bar baz</span>", 7));
<!-- results in:  'foo bar' -->
```

## {{truncateWords}}

Truncate a string to have the specified number of words. Also see [truncate](#truncate).

**Params**

* `str` **{String}**
* `limit` **{Number}**: The desired length of the returned string.
* `suffix` **{String}**: Optionally supply a string to use as a suffix to denote when the string has been truncated.
* `returns` **{String}**: The truncated string.

**Example**

```handlebars
truncateWords("foo bar baz", 1);
<!-- results in:  'foo…' -->
truncateWords("foo bar baz", 2);
<!-- results in:  'foo bar…' -->
truncateWords("foo bar baz", 3);
<!-- results in:  'foo bar baz' -->
```

## {{upcase}}

Uppercase all of the characters in the given string. Alias for [uppercase](#uppercase).

**Params**

* `string` **{String}**
* `returns` **{String}**

**Example**

```handlebars
{{upcase "aBcDeF"}}
<!-- results in:  'ABCDEF' -->
```

## {{uppercase}}

Uppercase all of the characters in the given string. If used as a block helper it will uppercase the entire block. This helper does not support inverse blocks.

**Params**

* `str` **{String}**: The string to uppercase
* `options` **{Object}**: Handlebars options object
* `returns` **{String}**

**Example**

```handlebars
{{uppercase "aBcDeF"}}
<!-- results in:  'ABCDEF' -->
```

---

## File: docs/en-US/api/handlebars-helpers/url.md

# URL

## {{encodeURI}}

Encodes a Uniform Resource Identifier (URI) component
by replacing each instance of certain characters by
one, two, three, or four escape sequences representing
the UTF-8 encoding of the character.

**Params**

* `str` **{String}**: The un-encoded string
* `returns` **{String}**: The endcoded string

## {{escape}}

Escape the given string by replacing characters with escape sequences.
Useful for allowing the string to be used in a URL, etc.

**Params**

* `str` **{String}**
* `returns` **{String}**: Escaped string.

## {{decodeURI}}

Decode a Uniform Resource Identifier (URI) component.

**Params**

* `str` **{String}**
* `returns` **{String}**

## {{url_encode}}

Alias for [encodeURI](#encodeuri).

## {{url_decode}}

Alias for [decodeURI](#decodeuri).

## {{urlResolve}}

Take a base URL, and a href URL, and resolve them as a
browser would for an anchor tag.

**Params**

* `base` **{String}**
* `href` **{String}**
* `returns` **{String}**

## {{urlParse}}

Parses a `url` string into an object.

**Params**

* `str` **{String}**: URL string
* `returns` **{String}**: Returns stringified JSON

## {{stripQuerystring}}

Strip the query string from the given `url`.

**Params**

* `url` **{String}**
* `returns` **{String}**: the url without the queryString

## {{stripProtocol}}

Strip protocol from a `url`. Useful for displaying media that may have an 'http' protocol on secure connections.

**Params**

* `str` **{String}**
* `returns` **{String}**: the url with http protocol stripped

**Example**

```handlebars
<!-- url = 'http://foo.bar' -->
{{stripProtocol url}}
<!-- results in: '//foo.bar' -->
```

---

## File: docs/en-US/api/http/index.md

# Overview

HTTP API of NocoBase is designed based on Resource & Action, a superset of REST API. The operation includes but not limited to create, read, update and delete. Resource Action can be extended arbitrarily in NocoBase.

## Resource

In NocoBase, resource has two expressions:

- `<collection>`
- `<collection>.<association>`

<Alert>

- Collection is the set of all abstract data
- Association is the associated data of collection
- Resource includes both collection and collection.association

</Alert>

### Example

- `posts` Post
- `posts.user` Post user
- `posts.tags` Post tags

## Action

Action on resource is expressed by `:<action>`

- `<collection>:<action>`
- `<collection>.<association>:<action>`

Built-in global actions for collection or association:

- `create`
- `get`
- `list`
- `update`
- `destroy`
- `move`

Built-in association actions for association only:

- `set`
- `add`
- `remove`
- `toggle`

### Example

- `posts:create` Create post
- `posts.user:get` Get post user
- `posts.tags:add` Add tags to post (associate existing tags with post)

## Request URL

```bash
<GET|POST>   /api/<collection>:<action>
<GET|POST>   /api/<collection>:<action>/<collectionIndex>
<GET|POST>   /api/<collection>/<collectionIndex>/<association>:<action>
<GET|POST>   /api/<collection>/<collectionIndex>/<association>:<action>/<associationIndex>
```

### Example

posts resource

```bash
POST  /api/posts:create
GET   /api/posts:list
GET   /api/posts:get/1
POST  /api/posts:update/1
POST  /api/posts:destroy/1
```

posts.comments resource

```bash
POST  /api/posts/1/comments:create
GET   /api/posts/1/comments:list
GET   /api/posts/1/comments:get/1
POST  /api/posts/1/comments:update/1
POST  /api/posts/1/comments:destroy/1
```

posts.tags resource

```bash
POST  /api/posts/1/tags:create
GET   /api/posts/1/tags:get
GET   /api/posts/1/tags:list
POST  /api/posts/1/tags:update
POST  /api/posts/1/tags:destroy
POST  /api/posts/1/tags:add
GET   /api/posts/1/tags:remove
```

## Locate Resource

- Collection resource locates the data to be processed by `collectionIndex`, `collectionIndex` must be unique.
- Association resource locates the data to be processed by `collectionIndex` and `associationIndex` jointly, `associationIndex` may not be unique, but the joint index of `collectionIndex` and `associationIndex` must be unique.

When viewing details of association resource, the requested URL needs to provide both `<collectionIndex>` and `<associationIndex>`, `<collectionIndex>` is necessary as `<associationIndex>` may not be unique.

For example, `tables.fields` represents the fields of a data table:

```bash
GET   /api/tables/table1/fields/title
GET   /api/tables/table2/fields/title
```

Both table1 and table2 have the title field, title is unique in one table, but other tables may also have fields of that name.

## Request Parameters

Request parameters can be placed in the headers, parameters (query string), and body (GET requests do not have a body) of the request.

Some special request parameters:

- `filter` Data filtering, used in actions related to query.
- `filterByTk` Filter by tk field, used in actions to specify details of data.
- `sort` Sorting, used in actions related to query.
- `fields` Date to output, used in actions related to query
- `appends` Fields of additional relationship, used in actions related to query.
- `except` Exclude some fields (not to output), used in actions related to query.
- `whitelist` Fields whitelist, used in actions related to data creation and update.
- `blacklist` Fields blacklist, used in actions related to data creation and update.

### filter

Data filtering.

```bash
# simple
GET /api/posts?filter[status]=publish
# json string format is recommended, which requires encodeURIComponent encoding
GET /api/posts?filter={"status":"published"}

# filter operators
GET /api/posts?filter[status.$eq]=publish
GET /api/posts?filter={"status.$eq":"published"}

# $and
GET /api/posts?filter={"$and": [{"status.$eq":"published"}, {"title.$includes":"a"}]}
# $or
GET /api/posts?filter={"$or": [{"status.$eq":"pending"}, {"status.$eq":"draft"}]}

# association field
GET /api/posts?filter[user.email.$includes]=gmail
GET /api/posts?filter={"user.email.$includes":"gmail"}
```

[Click here for more information about filter operators](http-api/filter-operators)

### filterByTk

Filter by tk field. In the default settings:

- collection resource: tk is the primary key of the data table.
- association resource: tk is the targetKey field of the association.

```bash
GET   /api/posts:get?filterByTk=1&fields=name,title&appends=tags
```

### sort

Sorting. To sort in the descending order, put `-` in front of the field.

```bash
# Sort createAt field in the ascending order
GET /api/posts:get?sort=createdAt
# Sort createAt field in the descending order
GET /api/posts:get?sort=-createdAt
# Sort multiple fields jointly, createAt field descending, title A-Z ascending
GET /api/posts:get?sort=-createdAt,title
```

### fields

Data to output.

```bash
GET   /api/posts:list?fields=name,title

Response 200 (application/json)
{
  "data": [
    {
      "name": "",
      "title": ""
    }
  ],
  "meta": {}
}
```

### appends

Fields of additional relationship.

### except

Exclude some fields (not to output), used in actions related to query.

### whitelist

Whitelist.

```bash
POST  /api/posts:create?whitelist=title

{
  "title": "My first post",
  "date": "2022-05-19"      # The date field will be filtered out and not be written to the database
}
```

### blacklist

Blacklist.

```bash
POST  /api/posts:create?blacklist=date

# The date field will be filtered out and not be written to the database
{
  "title": "My first post"
}
```

## Request Response

Format of the response:

```ts
type ResponseResult = {
  data?: any; // Main data
  meta?: any; // Additional Data
  errors?: ResponseError[]; // Errors
};

type ResponseError = {
  code?: string;
  message: string;
};
```

### Example

View list:

```bash
GET /api/posts:list

Response 200 (application/json)

{
  data: [
    {
      id: 1
    }
  ],
  meta: {
    count: 1
    page: 1,
    pageSize: 1,
    totalPage: 1
  },
}
```

View details:

```bash
GET /api/posts:get/1

Response 200 (application/json)

{
  data: {
    id: 1
  }
}
```

Error:

```bash
POST /api/posts:create

Response 400 (application/json)

{
  errors: [
    {
      message: 'name must be required',
    },
  ],
}
```

---

## File: docs/en-US/api/http/rest-api.md

# REST API

HTTP API of NocoBase is a superset of REST API, and the standard CRUD API also supports the RESTful style.

## Collection Resources

### Create Collection

HTTP API

```bash
POST  /api/<collection>:create

{} # JSON body
```

REST API

```bash
POST  /api/<collection>

{} # JSON body
```

### View Collection List

HTTP API

```bash
GET   /api/<collection>:list
```

REST API

```bash
GET   /api/<collection>
```

### View Collection Details

HTTP API

```bash
GET   /api/<collection>:get?filterByTk=<collectionIndex>
GET   /api/<collection>:get/<collectionIndex>
```

REST API

```bash
GET   /api/<collection>/<collectionIndex>
```

### Update Collection

HTTP API

```bash
POST   /api/<collection>:update?filterByTk=<collectionIndex>

{} # JSON body

# Or
POST   /api/<collection>:update/<collectionIndex>

{} # JSON body
```

REST API

```bash
PUT    /api/<collection>/<collectionIndex>

{} # JSON body
```

### Delete Collection

HTTP API

```bash
POST      /api/<collection>:destroy?filterByTk=<collectionIndex>
# Or
POST      /api/<collection>:destroy/<collectionIndex>
```

REST API

```bash
DELETE    /api/<collection>/<collectionIndex>
```

## Association Resources

### Create Association

HTTP API

```bash
POST    /api/<collection>/<collectionIndex>/<association>:create

{} # JSON body
```

REST API

```bash
POST    /api/<collection>/<collectionIndex>/<association>

{} # JSON body
```

### View Association List

HTTP API

```bash
GET   /api/<collection>/<collectionIndex>/<association>:list
```

REST API

```bash
GET   /api/<collection>/<collectionIndex>/<association>
```

### View Association Details

HTTP API

```bash
GET   /api/<collection>/<collectionIndex>/<association>:get?filterByTk=<associationIndex>
# Or
GET   /api/<collection>/<collectionIndex>/<association>:get/<associationIndex>
```

REST API

```bash
GET   /api/<collection>/<collectionIndex>/<association>:get/<associationIndex>
```

### Update Association

HTTP API

```bash
POST   /api/<collection>/<collectionIndex>/<association>:update?filterByTk=<associationIndex>

{} # JSON body

# Or
POST   /api/<collection>/<collectionIndex>/<association>:update/<associationIndex>

{} # JSON body
```

REST API

```bash
PUT    /api/<collection>/<collectionIndex>/<association>:update/<associationIndex>

{} # JSON
```

### Delete Association

HTTP API

```bash
POST    /api/<collection>/<collectionIndex>/<association>:destroy?filterByTk=<associationIndex>
# Or
POST    /api/<collection>/<collectionIndex>/<association>:destroy/<associationIndex>
```

REST API

```bash
DELETE  /api/<collection>/<collectionIndex>/<association>/<associationIndex>
```

---

## File: docs/en-US/api/resourcer/action.md

# ctx.action

## Overview

After the resource operation request is parsed by [`resourceManager.middleware()`](./resource-manager#middleware), some important request parameters are stored in `ctx.action` for use by subsequent middleware.

## API

### resourceName

`ctx.action.resourceName`

The name of the resource. It can take two forms:

- `a` - Operates on resource `a`.
- `a.b` - Operates on associated object `b` of resource `a`.

### actionName

`ctx.action.actionName`

The name of the action.

### sourceId

`ctx.action.sourceId`

When the operation object is an associated object of the resource, it represents the primary key value of the corresponding resource. For example: when `resourceName` is `a.b`, `sourceId` represents the primary key value of `a`.

### params

Request parameters.

- URL parameters can be directly obtained from `ctx.action.params`.

```ts
const { filterByTk } = ctx.action.params;
```

- Request body parameters can be obtained using `ctx.action.params.values`.

### mergeParams()

Combines parameter content with request parameters.

```ts
ctx.action.mergeParams(
  {
    filter: {
      name: 'foo',
    },
    fields: ['id', 'name'],
    except: ['name'],
    sort: ['id'],
    page: 1,
    pageSize: 10,
    values: {
      name: 'foo',
    },
  },
  {
    filter: 'and',
    fields: 'union',
    except: 'union',
    sort: 'overwrite',
    page: 'overwrite',
    pageSize: 'overwrite',
    values: 'deepMerge',
  },
);

ctx.action.mergeParams(
  {
    filter: {},
  },
  {
    filter: (x, y) => {
      // ...
    },
  },
);
```

#### Signature

- `mergeParams(params: ActionParams, strategies: MergeStrategies = {})`

#### Type

```ts
export interface ActionParams {
  filterByTk?: any;
  fields?: string[];
  appends?: string[];
  except?: string[];
  whitelist?: string[];
  blacklist?: string[];
  filter?: FilterOptions;
  sort?: string[];
  page?: number;
  pageSize?: number;
  values?: any;
  [key: string]: any;
}

type MergeStrategyType =
  | 'merge'
  | 'deepMerge'
  | 'overwrite'
  | 'andMerge'
  | 'orMerge'
  | 'intersect'
  | 'union';
type MergeStrategyFunc = (x: any, y: any) => any;
export type MergeStrategy = MergeStrategyType | MergeStrategyFunc;
export interface MergeStrategies {
  [key: string]: MergeStrategy;
}
```

#### Details

| Property     | Type                                                     | Description                                                   |
| ------------ | -------------------------------------------------------- | ------------------------------------------------------------- |
| `params`     | [`ActionParams`](#actionparams)                          | Request parameters                                            |
| `strategies` | [`{ [key: string]: MergeStrategies }`](#mergestrategies) | Merge strategies for various fields in the request parameters |

Default `strategies`:

```ts
{
  filter: 'andMerge',
  fields: 'intersect',
  appends: 'union',
  except: 'union',
  whitelist: 'intersect',
  blacklist: 'intersect',
  sort: 'overwrite',
};
```

##### ActionParams

| Property        | Type       | Description                                                             |
| --------------- | ---------- | ----------------------------------------------------------------------- |
| `filterByTk`    | `any`      | The primary key value of the operated resource                          |
| `filter`        | `Filter`   | Filtering parameters, refer to [Filter Operators](./database/operators) |
| `fields`        | `string[]` | Fields to retrieve                                                      |
| `except`        | `string[]` | Fields to exclude                                                       |
| `appends`       | `string[]` | Related fields to append                                                |
| `whitelist`     | `string[]` | Field whitelist                                                         |
| `blacklist`     | `string[]` | Field blacklist                                                         |
| `sort`          | `string[]` | Sorting parameters                                                      |
| `page`          | `number`   | Current page                                                            |
| `pageSize`      | `number`   | Number of data items per page                                           |
| `values`        | `any`      | Request body                                                            |
| `[key: string]` | `any`      | Other extended configurations                                           |

##### MergeStrategies

Predefined merge strategies or custom merge functions.

Predefined merge strategies:

| Strategy Name | Description                                       |
| ------------- | ------------------------------------------------- |
| `merge`       | `Object.assign`                                   |
| `deepMerge`   | Deep traversal merge                              |
| `overwrite`   | Overwrite                                         |
| `andMerge`    | Merge filter parameters using the `$and` operator |
| `orMerge`     | Merge filter parameters using the `$or` operator  |
| `intersect`   | Intersection                                      |
| `union`       | Union                                             |

---

## File: docs/en-US/api/resourcer/middleware.md

# Middleware

It is similar to the middleware of Koa, but with more enhanced features for easy extensions.

The defined middleware can be inserted for use in multiple places, such as the resourcer, and it is up to the developer for when to invoke it.

## Constructor

**Signature**

- `constructor(options: Function)`
- `constructor(options: MiddlewareOptions)`

**Parameter**

| Name              | Type                 | Default | Description                            |
| ----------------- | -------------------- | ------- | -------------------------------------- |
| `options`         | `Function`           | -       | Handler function of middlware          |
| `options`         | `MiddlewareOptions ` | -       | Configuration items of middlware       |
| `options.only`    | `string[]`           | -       | Only the specified actions are allowed |
| `options.except`  | `string[]`           | -       | The specified actions are excluded     |
| `options.handler` | `Function`           | -       | Handler function                       |

**Example**

Simple definition:

```ts
const middleware = new Middleware((ctx, next) => {
  await next();
});
```

Definition with relevant parameters:

```ts
const middleware = new Middleware({
  only: ['create', 'update'],
  async handler(ctx, next) {
    await next();
  },
});
```

## Instance Methods

### `getHandler()`

Get the orchestrated handler functions.

**Example**

The following middleware will output `1` and then `2` when requested.

```ts
const middleware = new Middleware((ctx, next) => {
  console.log(1);
  await next();
});

middleware.use(async (ctx, next) => {
  console.log(2);
  await next();
});

app.resourcer.use(middleware.getHandler());
```

### `use()`

Add a middleware function to the current middleware. Used to provide extension points for the middleware. See `getHandler()` for the examples.

**Signature**

- `use(middleware: Function)`

**Parameter**

| Name         | Type       | Default | Description                        |
| ------------ | ---------- | ------- | ---------------------------------- |
| `middleware` | `Function` | -       | Handler function of the middleware |

### `disuse()`

Remove the middleware functions that have been added to the current middleware.

**Signature**

- `disuse(middleware: Function)`

**Parameter**

| Name         | Type       | Default | Description                        |
| ------------ | ---------- | ------- | ---------------------------------- |
| `middleware` | `Function` | -       | Handler function of the middleware |

**Example**

The following example will only output `1` when requested, the output of `2` in fn1 will not be executed.

```ts
const middleware = new Middleware((ctx, next) => {
  console.log(1);
  await next();
});

async function fn1(ctx, next) {
  console.log(2);
  await next();
}

middleware.use(fn1);

app.resourcer.use(middleware.getHandler());

middleware.disuse(fn1);
```

### `canAccess()`

Check whether the current middleware is to be invoked for a specific action, it is usually handled by the resourcer internally.

**Signature**

- `canAccess(name: string): boolean`

**Parameter**

| Name   | Type     | Default | Description        |
| ------ | -------- | ------- | ------------------ |
| `name` | `string` | -       | Name of the action |

## Other Exports

### `branch()`

Create a branch middleware for branching in the middleware.

**Signature**

- `branch(map: { [key: string]: Function }, reducer: Function, options): Function`

**Parameter**

| Name                     | Type                          | Default          | Description                                                                                                       |
| ------------------------ | ----------------------------- | ---------------- | ----------------------------------------------------------------------------------------------------------------- |
| `map`                    | `{ [key: string]: Function }` | -                | Mapping table of the branch handler function, key names are given by subsequent calculation functions when called |
| `reducer`                | `(ctx) => string`             | -                | Calculation function, it is used to calculate the key name of the branch based on the context                     |
| `options?`               | `Object`                      | -                | Configuration items of the branch                                                                                 |
| `options.keyNotFound?`   | `Function`                    | `ctx.throw(404)` | Handler function when key name is not found                                                                       |
| `options.handlerNotSet?` | `Function`                    | `ctx.throw(404)` | The function when no handler function is defined                                                                  |

**Example**

When authenticating user, determine what to do next according to the value of the `authenticator` parameter in the query section of the request URL.

```ts
app.resourcer.use(
  branch(
    {
      password: async (ctx, next) => {
        // ...
      },
      sms: async (ctx, next) => {
        // ...
      },
    },
    (ctx) => {
      return ctx.action.params.authenticator ?? 'password';
    },
  ),
);
```

---

## File: docs/en-US/api/resourcer/resource-manager.md

# ResourceManager

## Overview

`ResourceManager` is the resource management module of NocoBase, used to define resources and register operation methods for resources.

## Class Methods

### `define()`

Defines a resource.

```ts
app.resourceManager.define({
  name: 'auth',
  actions: {
    check: async (ctx, next) => {
      // ...
      await next();
    },
  },
});
```

#### Signature

- `define(options: ResourceOptions): Resource`

#### Type

```ts
export interface ResourceOptions {
  name: string;
  type?: ResourceType;
  actions?: {
    [key: string]: ActionType;
  };
  only?: Array<ActionName>;
  except?: Array<ActionName>;
  middleware?: MiddlewareType;
  middlewares?: MiddlewareType;
}

export type ResourceType =
  | 'single'
  | 'hasOne'
  | 'hasMany'
  | 'belongsTo'
  | 'belongsToMany';

export type ActionType = HandlerType | ActionOptions;
export type HandlerType = (
  ctx: ResourcerContext,
  next: () => Promise<any>,
) => any;
export interface ActionOptions {
  values?: any;
  fields?: string[];
  appends?: string[];
  except?: string[];
  whitelist?: string[];
  blacklist?: string[];
  filter?: FilterOptions;
  sort?: string[];
  page?: number;
  pageSize?: number;
  maxPageSize?: number;
  middleware?: MiddlewareType;
  middlewares?: MiddlewareType;
  handler?: HandlerType;
  [key: string]: any;
}
```

#### Details

##### ResourceOptions

| Property      | Type                                           | Description            | Default  |
| ------------- | ---------------------------------------------- | ---------------------- | -------- |
| `name`        | `string`                                       | Resource name          | -        |
| `type`        | `ResourceType`                                 | Resource type          | `single` |
| `actions`     | [`{ [key: string]: ActionType }`](#actiontype) | Actions                | -        |
| `only`        | `ActionName[]`                                 | Whitelist of `actions` | -        |
| `except`      | `ActionName[]`                                 | Blacklist of `actions` | -        |
| `middleware`  | `MiddlewareType`                               | Middleware             | -        |
| `middlewares` | `MiddlewareType`                               | Middlewares            | -        |

##### ActionType

There are two types of action methods:

- `HandlerType`

This type directly defines the operation method through middleware. Example:

```ts
app.resourceManager.define({
  name: 'users',
  actions: {
    updateProfile: async (ctx, next) => {
      // ...
      await next();
    },
  },
});
```

- `ActionOptions`

This type is mainly used to override the request parameters of a certain existing operation. Example:

```ts
app.resourceManager.define({
  name: 'users',
  actions: {
    list: {
      fields: [],
      filter: {},
      // ...
    },
  },
});
```

| Property        | Type             | Description                                                                 |
| --------------- | ---------------- | --------------------------------------------------------------------------- |
| `values`        | `any`            | Default values for the action request                                       |
| `filter`        | `Filter`         | Filtering parameters, refer to [Filter Operators](../database/operators.md) |
| `fields`        | `string[]`       | Fields to retrieve                                                          |
| `except`        | `string[]`       | Fields to exclude                                                           |
| `appends`       | `string[]`       | Related fields to append                                                    |
| `whitelist`     | `string[]`       | Field whitelist                                                             |
| `blacklist`     | `string[]`       | Field blacklist                                                             |
| `sort`          | `string[]`       | Sorting parameters                                                          |
| `page`          | `number`         | Current page                                                                |
| `pageSize`      | `number`         | Number of data items per page                                               |
| `maxPageSize`   | `number`         | Maximum number of data items per page                                       |
| `middleware`    | `MiddlewareType` | Middleware                                                                  |
| `middlewares`   | `MiddlewareType` | Middlewares                                                                 |
| `handler`       | `HandlerType`    | Method executed for the action                                              |
| `[key: string]` | `any`            | Other extended configurations                                               |

### `registerActionHandlers()`

Registers action methods.

#### Signature

- `registerActionHandler(name: ActionName, handler: HandlerType)`

#### Type

```ts
export type DefaultActionType =
  | 'list'
  | 'create'
  | 'get'
  | 'update'
  | 'destroy'
  | 'set'
  | 'add'
  | 'remove';
export type ActionName = DefaultActionType | Omit<string, DefaultActionType>;

export type HandlerType = (
  ctx: ResourcerContext,
  next: () => Promise<any>,
) => any;
```

#### Details

| Property  | Type          | Description                                                                                                                                                        |
| --------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `name`    | `ActionName`  | Action name.1. As a regular string, registers actions for all resources.2. In the form `<resource>:<action>`, registers actions for specific resources |
| `handler` | `HandlerType` | Middleware for the action                                                                                                                                          |

### `isDefined()`

Checks if a resource is defined.

#### Signature

- `isDefined(name: string)`

#### Details

| Property | Type     | Description   |
| -------- | -------- | ------------- |
| `name`   | `string` | Resource name |

### `import()`

Loads resource configurations from a specified directory.

```ts
// ./resources/demo.ts
export default {
  name: 'demo',
  actions: {
    async list(ctx, next) {
      // ...
      await next();
    },
  },
};

const resourceManager = new ResourceManager();
await resourceManager.import({
  directory: path.resolve(__dirname, 'resources'),
});
```

#### Signature

- `import(options: ImportOptions): Promise<Map<string, Resource>>`

#### Type

```ts
export interface ImportOptions {
  directory: string;
  extensions?: string[];
}
```

#### Details

| Property     | Type       | Description               | Default Value          |
| ------------ | ---------- | ------------------------- | ---------------------- |
| `directory`  | `string`   | Directory path            | -                      |
| `extensions` | `string[]` | Optional, file extensions | `['js', 'ts', 'json']` |

### `use()`

Adds `ResourceManager` middleware.

```ts
resourceManager.use(async () => {
  return async function (ctx, next) {
    // ...
    await next();
  };
});
```

#### Signature

- `use(middlewares: HandlerType | HandlerType[], options: ToposortOptions = {})`

#### Details

Refer to [Middleware](../../development/server/middleware.md).

### `middleware()`

Middleware for `ResourceManager`, parses request parameters (refer to [ctx.action](./action.md)) and executes operation methods.

---

## File: docs/en-US/api/resourcer/resource.md

# Resource

Resource is used to define resource instance. Resource instances managed by resourcer can be accessed through HTTP requests.

## Constructor

To create resource instance. Normally it is not used directly, but replaced by the call of the `define()` interface of resourcer.

**Signature**

- `constructor(options: ResourceOptions, resourcer: Resourcer)`

**Parameter**

| Name                  | Type                                 | Default    | Description                                                                                                     |
| --------------------- | ------------------------------------ | ---------- | --------------------------------------------------------------------------------------------------------------- |
| `options.name`        | `string`                             | -          | Name of the resource, corresponding to the resource address in the route of the URL                             |
| `options.type`        | `string`                             | `'single'` | Type of the resource, options are `'single'`, `'hasOne'`, `'hasMany'`, `'belongsTo'`, `'belongsToMany'`         |
| `options.actions`     | `Object`                             | -          | List of actions that can be taken on the resource, see the example for details                                  |
| `options.middlewares` | `MiddlewareType \| MiddlewareType[]` | -          | List of middlewares for any operational access to the resource that is defining，see the example for details    |
| `options.only`        | `ActionName[]`                       | `[]`       | Whitelist for global actions, only actions contained in the array (if `length > 0`) can be accessed             |
| `options.except`      | `ActionName[]`                       | `[]`       | Blacklist for global actions, all actions except those contained in the array (if `length > 0`) can be accessed |
| `resourcer`           | `Resourcer`                          | -          | The resourcer instance                                                                                          |

**Example**

```ts
app.resourcer.define({
  name: 'books',
  actions: {
    // Extended action
    publish(ctx, next) {
      ctx.body = 'ok';
    },
  },
  middleware: [
    // Extended middleware
    async (ctx, next) => {
      await next();
    },
  ],
});
```

## Instance Members

### `options`

Configuration items for the current resource.

### `resourcer`

The resourcer instance to which the resource belongs.

### `middlewares`

The registered middlewares.

### `actions`

The registered mapping table of actions.

### `except`

Actions that are excluded.

## Instance Methods

### `getName()`

Get the name of the current resource.

**Signature**

- `getName(): string`

**Example**

```ts
const resource = app.resourcer.define({
  name: 'books',
});

resource.getName(); // 'books'
```

### `getAction()`

Get action with the corresponding name.

**Signature**

- `getAction(name: string): Action`

**Parameter**

| Name   | Type     | Default | Description        |
| ------ | -------- | ------- | ------------------ |
| `name` | `string` | -       | Name of the action |

**Example**

```ts
const resource = app.resourcer.define({
  name: 'books',
  actions: {
    publish(ctx, next) {
      ctx.body = 'ok';
    },
  },
});

resource.getAction('publish'); // [Function: publish]
```

---

## File: docs/en-US/api/sdk/auth.md

# Auth

## Overview

The `Auth` class is primarily used for accessing user information on the client-side, as well as requesting user authentication-related APIs.

## Instance Properties

### `locale`

The language used by the current user.

### `role`

The role used by the current user.

### `token`

The API interface token.

### `authenticator`

The authenticator used for current user authentication. Refer to [User Authentication](../../handbook/auth/user.md).

## Class Methods

### `signIn()`

User login.

#### Signature

- `async signIn(values: any, authenticator?: string): Promise<AxiosResponse<any>>`

#### Details

| Parameter       | Type     | Description                             |
| --------------- | -------- | --------------------------------------- |
| `values`        | `any`    | Login API request parameters            |
| `authenticator` | `string` | Authenticator identifier used for login |

### `signUp()`

User registration.

#### Signature

- `async signUp(values: any, authenticator?: string): Promise<AxiosResponse<any>>`

#### Details

| Parameter       | Type     | Description                                    |
| --------------- | -------- | ---------------------------------------------- |
| `values`        | `any`    | Registration API request parameters            |
| `authenticator` | `string` | Authenticator identifier used for registration |

### `signOut()`

Log out.

#### Signature

- `async signOut(values: any, authenticator?: string): Promise<AxiosResponse<any>>`

#### Details

| Parameter       | Type     | Description                              |
| --------------- | -------- | ---------------------------------------- |
| `values`        | `any`    | Logout API request parameters            |
| `authenticator` | `string` | Authenticator identifier used for logout |