From 35739f9f42edd983ff207172740576c906f28e51 Mon Sep 17 00:00:00 2001 From: chenos Date: Thu, 11 Nov 2021 17:44:13 +0800 Subject: [PATCH] feat(docs): add model api doc --- docs/reference/model.md | 327 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 327 insertions(+) create mode 100644 docs/reference/model.md diff --git a/docs/reference/model.md b/docs/reference/model.md new file mode 100644 index 000000000..b09720b85 --- /dev/null +++ b/docs/reference/model.md @@ -0,0 +1,327 @@ +--- +toc: menu +--- + +# Model + +## `model.updateAssociations()` + +用于更新 model 的关系,目前主要有四种基础关系 + +- hasOne +- hasMany +- belongsTo +- belongsToMany + +##### Definition + +```ts +interface updateAssociations { + (values: UpdateAssociationValues, options?: UpdateAssociationOptions): Promise; +} + +interface UpdateAssociationOptions { + transaction?: Transaction | null; + updateAssociationValues?: string[]; +} + +interface UpdateAssociationValues { + [key: string]: any; +} +``` + +##### Examples + +### HasOne + +以用户个人资料 user.profile 为例: + +可以传 profile instance + +```ts +const User = db.collection({ + name: 'users'; + fields: [ + { type: 'hasOne', name: 'profile' }, + ], +}); + +const Profile = db.collection({ + name: 'profiles'; + fields: [ + { type: 'string', name: 'gender' }, + ], +}); + +const user = await User.model.create(); +const profile = await Profile.model.create(); + +await user.updateAssociations({ + profile, +}); +``` + +也可以直接传 profile 的 id 值 + +```ts +const user = await User.model.create(); +const profile = await Profile.model.create(); + +await user.updateAssociations({ + profile: profile.id, +}); +``` + +也可以传 object,如果 object 不含 pk,直接创建并关联 + +```ts +const user = await User.model.create(); + +await user.updateAssociations({ + profile: { + gender: 'male', + }, +}); +``` + +如果 object 的 key 带 pk,只关联,不修改关联数据(默认) + +```ts +const user = await User.model.create(); +const profile = await Profile.model.create({ + gender: 'male', +}); +await user.updateAssociations({ + profile: { + id: profile.id, + gender: 'female', // 这里虽然改了,但是不修改 + }, +}); +``` + +如果要修改关联数据,需要指定 `updateAssociationValues` 路径,如: + +```ts +const user = await User.model.create(); +const profile = await Profile.model.create({ + gender: 'male', +}); +await user.updateAssociations({ + profile: { + id: profile.id, + gender: 'female', // updateAssociationValues 包含 profile,所以 gender 会被修改 + }, +}, { + // 对 profile 的 values 进行更新 + updateAssociationValues: ['profile'], +}); +``` + + +修改关联数据的使用频率较低,用不好破坏性很大,默认只关联并不更新关联数据。如果 JSON 不包含 pk,需要创建并关联处理。 + + +如果已经存在关联,解除关联,但不删除关联数据,并与新的数据建立关联 + +```ts +const user = await User.model.create(); +const profile1 = await Profile.model.create(); +const profile2 = await Profile.model.create(); +await user.updateAssociations({ + profile: profile1, +}); + +// 与 profile1 解除关联,并与 profile2 建立关联,profile1 数据还存在 +await user.updateAssociations({ + profile: profile2, +}); +``` + +## BelongsTo + +与 HasOne 的处理机制类似,不过多了个 targetKey 的情况,当 targetKey 不为 id 时,会有些区别: + +以文章作者 post.user 为例: + +```ts +const Post = db.collection({ + name: 'posts'; + fields: [ + { type: 'belongsTo', name: 'user', targetKey: 'uid' }, + ], +}); + +const User = db.collection({ + name: 'users'; + fields: [ + { type: 'uid', name: 'uid', unique: true } + ], +}); + +const post = Post.model.create(); +const user = User.model.create({ uid: 'uid123' }); + +// 可以传 uid 值,而不一定是 id +await post.updateAssociations({ + user: 'uid123', +}); +``` + +## HasMany + +可以传 instance + +```ts +const comment = await Comment.model.create(); +await post.updateAssociations({ + // 自动转换为 [comment] + comments: comment, +}); + +// 等同于 +await post.updateAssociations({ + comments: [comment], +}); +``` + +也可以传 pk 值 + +```ts +const comment = await Comment.model.create(); +await post.updateAssociations({ + // 自动转换为 [comment.id] + comments: comment.id, +}); + +// 等同于 +await post.updateAssociations({ + comments: [comment.id] +}); +``` + +可以是 object + +```ts +await post.updateAssociations({ + comments: { + content: 'comment 1' + }, +}); +``` + +或者是 array + +```ts +await post.updateAssociations({ + comments: [ + { + content: 'comment 1' + }, + { + content: 'comment 2' + }, + ], +}); +``` + +或者是混合的元素 + +```ts +await post.updateAssociations({ + comments: [ + 1, + comment, + { + id: 3, + content: 'comment 3' + }, + ], +}); +``` + +多层内嵌的情况,订单商品详情 order.details + +```ts +db.collection({ + name: 'orders', + fields: [ + { type: 'hasMany', name: 'details', target: 'order_details' } + ], +}); + +db.collection({ + name: 'order_details', + fields: [ + { type: 'belongsTo', name: 'product' }, + { type: 'integer', name: 'qty' }, + { type: 'integer', name: 'price' }, + ], +}); + +db.collection({ + name: 'products', + fields: [ + ], +}); + +const order = Order.model.create(); + +await order.updateAssociations({ + details: [ + { + product: 1, + qty: 3, + price: 200, + }, + { + product: 2, + qty: 3, + price: 200, + }, + ], +}); +``` + +## BelongsToMany + +常规写法与 HasMany 类似,不过有两个特殊参数 targetKey 和 through。targetKey 与 BelongsTo 类似。through 为实体表时,需要可以更新 through 数据。 + +```ts +const Foo = db.collection({ + name: 'foos', + fields: [ + { type: 'belongsToMany', name: 'bars' }, + ], +}); + +const Bar = db.collection({ + name: 'bars', + fields: [ + { type: 'string', name: 'title' }, + ], +}); + +db.collection({ + name: 'bars_foos', + fields: [ + { type: 'string', name: 'status' }, + ], +}); + +await foo.updateAssociations({ + bars: [ + { + title: 'title1', + bars_foos: { + status: 'publish', + }, + }, + { + title: 'title2', + bars_foos: { + status: 'draft', + }, + }, + ], +}) +```