tachybase_todo/docs/zh-CN/api/database/index.md
Junyi 796e73ae5a
refactor(doc): change to new structure (#804)
* refactor(doc): change to new structure

* docs: add database docs

* docs: add collection docs

* docs: add db field examples

* docs(api): fix filename and menu path

* docs: add database docs

* docs: add db operators doc

* docs: add resourcer menu

* docs: add resourcer docs

* docs: fix api docs

* docs: refactor api menu structure

* feat: update docs (#830)

* feat: updates

* feat: update docs

* chore: ignore docs from ci

Co-authored-by: Junyi <mytharcher@users.noreply.github.com>
Co-authored-by: mytharcher <mytharcher@gmail.com>

* docs: add database methods docs

* docs: add missed api

* docs: fix api docs

* feat: update development docs (#833)

* feat: update development docs

* feat: update docs

* feat: update docs

* docs: add first plugin example (#834)

* feat: update docs

* feat: update docs

* docs: fix typo

Co-authored-by: chenos <chenlinxh@gmail.com>
2022-09-19 09:23:01 +08:00

17 KiB
Raw Blame History

Database

NocoBase 内置的数据库访问类,通过封装 Sequelize 提供了更加简单的数据库访问接口和统一化的 JSON 数据库表配置方式,同时也提供了扩展字段类型和查询操作符的能力。

Database 类继承自 EventEmitter可以通过 db.on('event', callback) 监听数据库事件,以及 db.off('event', callback) 移除监听。

包结构

可通过以下方式引入相关实体:

import Database, {
  Field,
  Collection,
  Repository,
  RelationRepository,
  extend
} from '@nocobase/database';

构造函数

签名

  • constructor(options: DatabaseOptions)

创建一个数据库实例。

参数

options 参数与 Sequelize 的构造参数一致的部分会透传至 Sequelize同时 NocoBase 也会使用一些额外的参数:

参数名 类型 默认值 描述
options.host string 'localhost' 数据库主机
options.port number - 数据库服务端口,根据使用的数据库有对应默认端口
options.username string - 数据库用户名
options.password string - 数据库密码
options.database string - 数据库名称
options.dialect string 'mysql' 数据库类型
options.storage? string ':memory:' SQLite 的存储模式
options.logging? boolean false 是否开启日志
options.define? Object {} 默认的表定义参数
options.tablePrefix? string '' NocoBase 扩展,表名前缀
options.migrator? UmzugOptions {} NocoBase 扩展,迁移管理器相关参数,参考 Umzug 实现

示例

import Database from '@nocobase/database';

const app = new Database({
  dialect: 'mysql',
  host: 'localhost',
  port: 3306,
  username: 'root',
  password: '123456',
  database: 'test',
  tablePrefix: 'my_'
});

实例成员

sequelize

初始化后的 Sequelize 实例,在需要使用 sequelize 底层方法时可以调用,相关信息可以直接参考 sequelize 的文档。

options

初始化的配置参数,包含了 Sequelize 的配置参数和 NocoBase 的额外配置参数。

version

连接的数据库的版本信息对象,可通过 await db.version.satisfies(<sem_ver>) 检查是否满足特定数据库版本要求。

示例

const r = await this.db.version.satisfies({
  mysql: '>=8.0.17',
  sqlite: '3.x',
  postgres: '>=10',
});

迁移相关方法

addMigration()

添加单个迁移文件。

签名

  • addMigration(options: MigrationItem)

参数

参数名 类型 默认值 描述
options.name string - 迁移文件名称
options.context? string - 迁移文件的 up 方法
options.migration? typeof Migration - 迁移文件的自定义类
options.up Function - 迁移文件的 up 方法
options.down Function - 迁移文件的 down 方法

示例

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

addMigrations()

添加指定目录下的迁移文件。

签名

  • addMigrations(options: AddMigrationsOptions): void

参数

参数名 类型 默认值 描述
options.directory string '' 迁移文件所在目录
options.extensions string[] ['js', 'ts'] 文件扩展名
options.namespace? string '' 命名空间
options.context? Object { db } 迁移文件的上下文

示例

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

工具方法

inDialect()

判断当前数据库类型是否为指定类型。

签名

  • inDialect(dialect: string[]): boolean

参数

参数名 类型 默认值 描述
dialect string[] - 数据库类型,可选值为 mysql/postgres/sqlite

getTablePrefix()

获取配置中的表名前缀。

签名

  • getTablePrefix(): string

数据表配置

collection()

定义一个数据表。该调用类似与 Sequelize 的 define 方法,只在内存中创建表结构,如需持久化到数据库,需要调用 sync 方法。

签名

  • collection(options: CollectionOptions): Collection

参数

options 所有配置参数与 Collection 类的构造函数一致,参考 Collection

事件

  • 'beforeDefineCollection':在定义表之前触发。
  • 'afterDefineCollection':在定义表之后触发。

示例

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

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

getCollection()

获取已定义的数据表。

签名

  • getCollection(name: string): Collection

参数

参数名 类型 默认值 描述
name string - 表名

示例

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

hasCollection()

判断是否已定义指定的数据表。

签名

  • hasCollection(name: string): boolean

参数

参数名 类型 默认值 描述
name string - 表名

示例

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

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

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

removeCollection()

移除已定义的数据表。仅在内存中移除,如需持久化,需要调用 sync 方法。

签名

  • removeCollection(name: string): void

参数

参数名 类型 默认值 描述
name string - 表名

事件

  • 'beforeRemoveCollection':在移除表之前触发。
  • 'afterRemoveCollection':在移除表之后触发。

示例

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

db.removeCollection('books');

import()

导入文件目录下所有文件作为 collection 配置载入内存。

签名

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

参数

参数名 类型 默认值 描述
options.directory string - 要导入的目录路径
options.extensions string[] ['ts', 'js'] 扫描特定后缀

示例

./collections/books.ts 文件定义的 collection 如下:

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

在插件加载时导入相关配置:

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

扩展注册与获取

registerFieldTypes()

注册自定义字段类型。

签名

  • registerFieldTypes(fieldTypes: MapOf<typeof Field>): void

参数

fieldTypes 是一个键值对,键为字段类型名称,值为字段类型类。

示例

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

class MyField extends Field {
  // ...
}

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

registerModels()

注册自定义数据模型类。

签名

  • registerModels(models: MapOf<ModelCtor<any>>): void

参数

models 是一个键值对,键为数据模型名称,值为数据模型类。

示例

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

class MyModel extends Model {
  // ...
}

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

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

registerRepositories()

注册自定义数据仓库类。

签名

  • registerRepositories(repositories: MapOf<RepositoryType>): void

参数

repositories 是一个键值对,键为数据仓库名称,值为数据仓库类。

示例

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

class MyRepository extends Repository {
  // ...
}

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

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

registerOperators()

注册自定义数据查询操作符。

签名

  • registerOperators(operators: MapOf<OperatorFunc>)

参数

operators 是一个键值对,键为操作符名称,值为操作符比较语句生成函数。

示例

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()

获取已定义的数据模型类。如果没有在之前注册自定义模型类,将返回 Sequelize 默认的模型类。默认名称与 collection 定义的名称相同。

签名

  • getModel(name: string): Model

参数

参数名 类型 默认值 描述
name string - 已注册的模型名

示例

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

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

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

注:从 collection 中获取的模型类并不与注册时的模型类严格相等,而是继承自注册时的模型类。由于 Sequelize 的模型类在初始化过程中属性会被修改,所以 NocoBase 自动处理了这个继承关系。除类不相等以外,其他所有定义都可以正常使用。

getRepository()

获取自定义的数据仓库类。如果没有在之前注册自定义数据仓库类,将返回 NocoBase 默认的数据仓库类。默认名称与 collection 定义的名称相同。

数据仓库类主要用于基于数据模型的增删改查等操作,参考 数据仓库

签名

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

参数

参数名 类型 默认值 描述
name string - 已注册的数据仓库名
relationId string | number - 关系数据的外键值

当名称是形如 'tables.relactions' 的带关联的名称时,将返回关联的数据仓库类。如果提供了第二个参数,数据仓库在使用时(查询、修改等)会基于关系数据的外键值。

示例

假设有两张数据表_文章_与_作者_并且文章表中有一个外键指向作者表

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

数据库事件

on()

监听数据库事件。

Database 除了对 sequelize 原生的事件封装以外,还提供以下可监听事件类型:

事件名称 描述
'beforeDefineCollection' 定义 collection 之前触发
'afterDefineCollection' 定义 collection 之后触发
'beforeRemoveCollection' 移除 collection 之前触发
'afterRemoveCollection' 移除 collection 之后触发
<sequelize_model_global_event> 所有 sequelize 的全局事件均可通过此方式监听,详见示例部分
<model_name>.<sequelize_model_event> 所有 sequelize model 的事件均可通过此方式监听,详见示例部分
<model_name>.afterCreateWithAssociations NocoBase 扩展的当连同关联数据一并创建记录成功后触发的事件(使用 Repository 的 create 方法会触发)
<model_name>.afterUpdateWithAssociations NocoBase 扩展的当连同关联数据一并更新记录成功后触发的事件(使用 Repository 的 update 方法会触发)
<model_name>.afterSaveWithAssociations NocoBase 扩展的当连同关联数据一并创建或更新记录成功后触发的事件(使用 Repository 的 create/update 方法都会触发)

签名

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

参数

参数名 类型 默认值 描述
event string - 事件名称
listener Function - 事件监听器

示例

监听 books 表事件,当创建新记录成功后触发:

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

监听 books 表,当连同关联数据一并创建成功后触发的事件:

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

监听任意表的删除事件:

db.on('afterDestroy', async (model, options) => {
  console.log(model);
});

off()

移除事件监听函数。

签名

  • off(name: string, listener: Function)
参数名 类型 默认值 描述
name string - 事件名称
listener Function - 事件监听器

示例

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

db.on('afterCreate', listener);

db.off('afterCreate', listener);

数据库操作

auth()

数据库连接验证。可以用于确保应用与数据已建立连接。

签名

  • auth(options: QueryOptions & { retry?: number } = {}): Promise<boolean>

参数

参数名 类型 默认值 描述
options? Object - 验证选项
options.retry? number 10 验证失败时重试次数
options.transaction? Transaction - 事务对象
options.logging? boolean | Function false 是否打印日志

示例

await db.auth();

reconnect()

重新连接数据库。

示例

await db.reconnect();

closed()

判断数据库是否已关闭连接。

签名

  • closed(): boolean

close()

关闭数据库连接。等同于 sequelize.close()

sync()

同步数据库表结构。等同于 sequelize.sync(),参数参考 Sequelize 文档

clean()

清空数据库,将删除所有数据表。

签名

  • clean(options: CleanOptions): Promise<void>

参数

参数名 类型 默认值 描述
options.drop boolean false 是否移除所有数据表
options.skip string[] - 跳过的表名配置
options.transaction Transaction - 事务对象

示例

移除除 users 表以外的所有表。

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

包级导出

defineCollection()

创建一个数据表的配置内容。

签名

  • defineCollection(name: string, config: CollectionOptions): CollectionOptions

参数

参数名 类型 默认值 描述
collectionOptions CollectionOptions - 与所有 db.collection() 的参数相同

示例

对于要被 db.import() 导入的数据表配置文件:

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

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

extendCollection()

扩展已在内存中的表结构配置内容,主要用于 import() 方法导入的文件内容。该方法是 @nocobase/database 包导出的顶级方法,不通过 db 实例调用。也可以使用 extend 别名。

签名

  • extendCollection(collectionOptions: CollectionOptions, mergeOptions?: MergeOptions): ExtendedCollectionOptions

参数

参数名 类型 默认值 描述
collectionOptions CollectionOptions - 与所有 db.collection() 的参数相同
mergeOptions? MergeOptions - npm 包 deepmerge 的参数

示例

原始 books 表定义books.ts

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

扩展 books 表定义books.extend.ts

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

// 再次扩展
export default extend({
  name: 'books',
  fields: [
    { name: 'price', type: 'number' }
  ]
});

以上两个文件如在调用 import() 时导入,通过 extend() 再次扩展以后books 表将拥有 titleprice 两个字段。

此方法在扩展已有插件已定义的表结构时非常有用。