From 062318b606fb16fb7ef611693af74783ae6d767d Mon Sep 17 00:00:00 2001 From: chenos Date: Tue, 9 Nov 2021 15:08:24 +0800 Subject: [PATCH] feat(docs): update api doc --- docs/reference/application.md | 52 ++++- docs/reference/cli.md | 41 +++- docs/reference/context.md | 34 +++ docs/reference/database.md | 377 ++++++++++++++++++++++++++++++++-- 4 files changed, 481 insertions(+), 23 deletions(-) diff --git a/docs/reference/application.md b/docs/reference/application.md index 5e1fcc812..a50a8af71 100644 --- a/docs/reference/application.md +++ b/docs/reference/application.md @@ -7,9 +7,25 @@ toc: menu # Application -## app.db +## `app.db` -数据库实例 +数据库实例,详情见 [Database API](database) + +##### Definition + +```ts +class Application { + public db: Database; +} +``` + +##### Examples + +```ts +app.db.on('xxx', () => { + +}); +``` ## app.resourcer @@ -17,11 +33,39 @@ toc: menu ## app.pm -插件管理器 +插件管理器,详情见 [Plugin Manager](plugin-manager) + +##### Definition + +```ts +class Application { + public pm: PluginManager; +} +``` + +##### Examples + +```ts +app.pm.enable(['plugin-name']); +``` ## app.i18n -国际化 +国际化,i18next 实例,详情见 [I18next API](https://www.i18next.com/overview/api),在 Middleware 里请使用 [ctx.i18n](context#ctxi18n) + +##### Definition + +```ts +class Application { + public i18n: I18next.i18n; +} +``` + +##### Examples + +```ts +app.i18n.t('Hello'); +``` ## app.constructor() diff --git a/docs/reference/cli.md b/docs/reference/cli.md index ce6086430..07e86d160 100644 --- a/docs/reference/cli.md +++ b/docs/reference/cli.md @@ -4,10 +4,37 @@ toc: menu # CLI -## init -## start -## db:sync -## pm:download -## pm:enable -## pm:disable -## pm:remove +这里的 CLI 指的是通过 app.cli 提供的默认的 commands。 + +## `init` + +初始化安装,支持参数有: + +- `--import-demo` +- `--lang=zh-CN|en-US` + +## `start` + +启动 APP。 + +## `db:sync` + +更新所有数据库结构,支持参数有: + +- `--force` 删除重建 + +## `pm:download` + +下载插件 + +## `pm:enable` + +激活插件 + +## `pm:disable` + +禁用插件 + +## `pm:remove` + +移除插件 diff --git a/docs/reference/context.md b/docs/reference/context.md index 82b41dd76..295318bfc 100644 --- a/docs/reference/context.md +++ b/docs/reference/context.md @@ -6,11 +6,45 @@ toc: menu ## ctx.db +##### Definition + +```ts +interface Context { + db: Database; +} +``` + +##### Examples + +```ts +async (ctx, next) { + const User = ctx.db.getCollection('users'); +} +``` + ## ctx.resourcer ## ctx.action ## ctx.i18n +app.i18n 的 cloneInstance。详情见 [I18next API](https://www.i18next.com/overview/api) + +##### Definition + +```ts +interface Context { + i18n: I18next.I18n; +} +``` + +##### Examples + +```ts +async (ctx, next) { + await ctx.i18n.changeLanguage('zh-CN'); +} +``` + ## ctx.t() diff --git a/docs/reference/database.md b/docs/reference/database.md index 06dc10c1a..7f060b035 100644 --- a/docs/reference/database.md +++ b/docs/reference/database.md @@ -4,15 +4,368 @@ toc: menu # Database -## db.constructor() -## db.collection() -## db.sync() -## db.close() -## db.registerFieldTypes() -## db.import() -## db.on() -## db.emitAsync() -## db.emit() -## db.registerModels() -## db.registerRepositories() -## db.registerOperators() +## `db.sequelize` + +Sequelize 实例 + +##### Definition + +```ts +class Database { + public sequelize: Sequelize; +} +``` + +##### Examples + +直接调用 sequelize api + +```ts +db.sequelize.close(); +``` + +## `db.constructor()` + +##### Definition + +```ts +class Database { + constructor (options: DatabaseOptions) => void; +} + +type DatabaseOptions = Sequelize.Options | Sequelize; +``` + +##### Examples + +配置 options 与 Sequelize.Options 一致,如: + +```ts +const db = new Database({ + dialect: 'sqlite', + storage: 'path/to/database.sqlite' +}); +``` + +也可以直接传 sequelize 实例 + +```ts +const sequelize = new Sequelize('sqlite::memory:'); +const db = new Database(sequelize); +``` + +注意,new Sequelize() 会有针对参数的 try catch 处理,Database 如果要捕获异常,也需要在 new 的时候 try catch,如: + +```ts +try { + const db = new Database({ + dialect: 'sqlite', + storage: 'path/to/database.sqlite' + }); +} catch(error) { + +} +``` + +## `db.collection()` + +配置数据表、字段和索引等,更多字段配置查看 [Field Types](field-types) + +##### Definition + +```ts +class Database { + collection(options: CollectionOptions) : Collection; +} + +interface CollectionOptions { + name: string; + title?: string; + // 自定义 model + model?: string; + // 自定义 repository + repository?: string; + // 字段配置 + fields?: FieldOptions; +} + +// TODO,需要提供完善的 types,用于配置时提示 +type FieldOptions; +``` + +##### Examples + +配置 fields + +```ts +const Post = db.collection({ + name: 'posts', + fields: [ + { type: 'string', name: 'name' }, + ], +}); +``` + +自定义 model 见 [db.registerModels()](#dbregistermodels) + +自定义 repository 见 [db.registerRepositories()](#dbregisterrepositories) + +## `db.sync()` + +将所有定义的 Collections 同步给数据库。 + +##### Definition + +```ts +class Database { + sync(options?: Sequelize.SyncOptions): Promise; +} +``` + +##### Examples + +```ts +await db.sync(); +await db.sync({force: true}); +``` + +## `db.close()` + +断开数据库连接 + +##### Definition + +```ts +class Database { + close(): Promise; +} +``` + +##### Examples + +```ts +await db.close(); +``` + +## `db.registerFieldTypes()` + +自定义字段存储类型,更多字段类型查看 [Field Types](field-types) + +##### Definition + +```ts +class Database { + registerFieldTypes(types: RegisterFieldTypes): void; +} + +interface RegisterFieldTypes { + [key: string]: Field; +} +``` + +##### Examples + +```ts +class CustomField extends Field { + get dataType() { + return DataTypes.STRING; + } +} + +db.registerFieldTypes({ custom: CustomField }); + +db.collection({ + name: 'tests', + fields: [ + { type: 'custom', name: 'customName' }, + ], +}); +``` + +## `db.import()` + +##### Definition + +```ts +class Database { + import(options: ImportOptions): Map; +} + +interface ImportOptions { + // 配置所在文件夹 + directory: string; + // 配置后置 + // @default ['js', 'ts', 'json'] + extensions?: string[]; +} +``` + +##### Examples + +导入某文件夹下的所有 Collection 配置 + +```ts +db.import({ + directory: '/path/to/collections', + extensions: ['js', 'ts', 'json'], +}); +``` + +## `db.on()` + +##### Definition + +##### Examples + +## `db.emitAsync()` + +异步事件触发 + +##### Definition + +##### Examples + +## `db.emit()` + +同步事件触发 + +##### Definition + +##### Examples + +## `db.registerModels()` + +自定义 Model + +##### Definition + +```ts +class Database { + registerModels(models: RegisterModels): void; +} + +interface RegisterModels { + [key: string]: Sequelize.Model; +} +``` + +##### Examples + +```ts +class CustomModel extends Model { + customMethod() { + console.log('custom method'); + } +} + +db.registerModels({ + CustomModel, +}); + +const Test = db.collection({ + name: 'tests', + model: 'CustomModel', +}); + +const test = Test.model.create(); +test.customMethod(); +``` + +## `db.registerRepositories()` + +自定义 Repository + +##### Examples + +```ts +class CustomRepository extends Repository { + customMethod() { + console.log('custom method'); + } +} + +db.registerModels({ + CustomRepository, +}); + +const Test = db.collection({ + name: 'tests', + repository: 'CustomRepository', +}); + +Test.repository.customMethod(); +``` + +## `db.registerOperators()` + +自定义筛选条件 + +##### Definition + +```ts +class Database { + registerOperators(operators: RegisterOperators): any; +} + +interface RegisterOperators { + [key: string]: (value: any, ctx?: RegisterOperatorsContext) => any; +} + +interface RegisterOperatorsContext { + db?: Database; + path?: string; + field?: Field; +} +``` + +##### Examples + +大部分自定义 Operator,可以直接转换,如: + +```ts +db.registerOperators({ + includes: (value, ctx) => { + const dialect = ctx.db.sequelize.getDialect(); + return { + [dialect === 'postgres' ? Op.iLike : Op.like]: `%${value}%`, + } + }, +}); + +repository.find({ + filter: { + 'attr.$includes': 'abc', + }, +}); +``` + +但是也有少量 Operator 比较复杂 + +```ts +db.registerOperators({ + anyOf: (value: any[], ctx) => { + if (!values) { + return Sequelize.literal(''); + } + values = Array.isArray(values) ? values : [values]; + if (values.length === 0) { + return Sequelize.literal(''); + } + const { path } = ctx; + const column = path + .split('.') + .map((name) => `"${name}"`) + .join('.'); + const sql = values + .map((value) => `(${column})::jsonb @> '${JSON.stringify(value)}'`) + .join(' OR '); + return Sequelize.literal(sql); + }, +}); + +repository.find({ + filter: { + 'attr.$anyOf': ['val1', 'val2'], + }, +}); +```