lakutata 3.0.0 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +50 -30
- package/README.zh-CN.md +130 -0
- package/dist/cjs/exports/QueueComponent.d.ts +1 -0
- package/dist/cjs/exports/QueueComponent.js +20 -0
- package/dist/esm/exports/QueueComponent.js +1 -0
- package/dist/types/exports/QueueComponent.d.ts +1 -0
- package/doc/en/Application.md +107 -0
- package/doc/en/CLI.md +274 -0
- package/doc/en/Cache.md +379 -0
- package/doc/en/Command.md +110 -0
- package/doc/en/ContainerdIntegration.md +17 -16
- package/doc/en/Controllers.md +256 -0
- package/doc/en/DBus.md +291 -0
- package/doc/en/DTOValidation.md +72 -43
- package/doc/en/Database.md +188 -0
- package/doc/en/DatabaseDrivers.md +287 -0
- package/doc/en/Decorator.md +52 -40
- package/doc/en/DockerIntegration.md +7 -6
- package/doc/en/Entities.md +240 -0
- package/doc/en/Entrypoint.md +216 -0
- package/doc/en/Exceptions.md +174 -0
- package/doc/en/GRPC.md +251 -0
- package/doc/en/GettingStarted.md +165 -0
- package/doc/en/HTTP.md +507 -0
- package/doc/en/HelperFunctions.md +11 -11
- package/doc/en/I18n.md +119 -115
- package/doc/en/Injection.md +144 -0
- package/doc/en/Installers.md +280 -0
- package/doc/en/Logger.md +206 -0
- package/doc/en/MCP.md +293 -0
- package/doc/en/Middlewares.md +213 -0
- package/doc/en/Migrations.md +202 -0
- package/doc/en/MongoEmbedded.md +149 -0
- package/doc/en/Monitor.md +164 -0
- package/doc/en/Mutex.md +27 -25
- package/doc/en/NATS.md +246 -0
- package/doc/en/NativeAddons.md +212 -0
- package/doc/en/Objects.md +143 -0
- package/doc/en/Overview.md +62 -85
- package/doc/en/Packaging.md +193 -0
- package/doc/en/ProjectStructure.md +124 -0
- package/doc/en/Queue.md +269 -0
- package/doc/en/Schedules.md +217 -0
- package/doc/en/Security.md +10 -9
- package/doc/en/ServiceCalls.md +504 -0
- package/doc/en/Time.md +19 -20
- package/doc/en/UpgradingFrom1.md +435 -0
- package/doc/en/UpgradingFrom2.md +315 -0
- package/doc/en/Workspaces.md +189 -0
- package/doc/en/examples/BackgroundJobs.md +677 -0
- package/doc/en/examples/CommandLineTool.md +664 -0
- package/doc/en/examples/DesktopApp.md +809 -0
- package/doc/en/examples/DeviceService.md +607 -0
- package/doc/en/examples/MCPServer.md +653 -0
- package/doc/en/examples/README.md +16 -0
- package/doc/en/examples/RestAPI.md +490 -0
- package/doc/en/examples/ServiceCalls.md +829 -0
- package/doc/en/examples/WebApp.md +568 -0
- package/doc/zh/Application.md +75 -0
- package/doc/zh/CLI.md +250 -0
- package/doc/zh/Cache.md +328 -0
- package/doc/zh/Command.md +78 -0
- package/doc/zh/ContainerdIntegration.md +9 -9
- package/doc/zh/Controllers.md +228 -0
- package/doc/zh/DBus.md +257 -0
- package/doc/zh/DTOValidation.md +49 -19
- package/doc/zh/Database.md +175 -0
- package/doc/zh/DatabaseDrivers.md +261 -0
- package/doc/zh/Decorator.md +25 -18
- package/doc/zh/DockerIntegration.md +6 -6
- package/doc/zh/Entities.md +224 -0
- package/doc/zh/Entrypoint.md +193 -0
- package/doc/zh/Exceptions.md +158 -0
- package/doc/zh/GRPC.md +226 -0
- package/doc/zh/GettingStarted.md +148 -0
- package/doc/zh/HTTP.md +445 -0
- package/doc/zh/HelperFunctions.md +2 -2
- package/doc/zh/I18n.md +26 -26
- package/doc/zh/Injection.md +129 -0
- package/doc/zh/Installers.md +232 -0
- package/doc/zh/Logger.md +188 -0
- package/doc/zh/MCP.md +265 -0
- package/doc/zh/Middlewares.md +198 -0
- package/doc/zh/Migrations.md +178 -0
- package/doc/zh/MongoEmbedded.md +118 -0
- package/doc/zh/Monitor.md +145 -0
- package/doc/zh/Mutex.md +10 -10
- package/doc/zh/NATS.md +207 -0
- package/doc/zh/NativeAddons.md +180 -0
- package/doc/zh/Objects.md +119 -0
- package/doc/zh/Overview.md +46 -71
- package/doc/zh/Packaging.md +154 -0
- package/doc/zh/ProjectStructure.md +102 -0
- package/doc/zh/Queue.md +214 -0
- package/doc/zh/Schedules.md +193 -0
- package/doc/zh/Security.md +6 -6
- package/doc/zh/ServiceCalls.md +459 -0
- package/doc/zh/Time.md +2 -2
- package/doc/zh/UpgradingFrom1.md +347 -0
- package/doc/zh/UpgradingFrom2.md +230 -0
- package/doc/zh/Workspaces.md +150 -0
- package/doc/zh/examples/BackgroundJobs.md +618 -0
- package/doc/zh/examples/CommandLineTool.md +618 -0
- package/doc/zh/examples/DesktopApp.md +748 -0
- package/doc/zh/examples/DeviceService.md +546 -0
- package/doc/zh/examples/MCPServer.md +604 -0
- package/doc/zh/examples/README.md +14 -0
- package/doc/zh/examples/RestAPI.md +458 -0
- package/doc/zh/examples/ServiceCalls.md +765 -0
- package/doc/zh/examples/WebApp.md +520 -0
- package/package.json +46 -17
- package/doc/en/ActionPattern.md +0 -408
- package/doc/en/Core.md +0 -312
- package/doc/en/ORMIntegration.md +0 -341
- package/doc/zh/ActionPattern.md +0 -334
- package/doc/zh/Core.md +0 -256
- package/doc/zh/ORMIntegration.md +0 -319
package/doc/zh/DTOValidation.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Lakutata DTO 与数据校验
|
|
2
2
|
|
|
3
|
-
**DTO
|
|
3
|
+
**DTO**(数据传输对象)是用校验规则声明属性的类。框架用 DTO 校验对象的选项(`@Configurable`)、方法的参数和返回值(`@Accept`、`@Return`)以及控制器动作的输入。`DTO` 由 `lakutata` 导出,相关装饰器由 `lakutata/decorator/dto` 导出;校验引擎是框架自带的,API 与 joi 相同(并扩展了 bigint 和下文的数值类型)。
|
|
4
4
|
|
|
5
5
|
## 1. 定义 DTO
|
|
6
6
|
|
|
@@ -40,23 +40,35 @@ class CustomerDTO extends DTO {
|
|
|
40
40
|
|
|
41
41
|
校验规则由 `DTO` 的静态方法构建:`DTO.String()`、`DTO.Number()`、`DTO.BigInt()`、`DTO.Boolean()`、`DTO.Date()`、`DTO.Binary()`、`DTO.Symbol()`、`DTO.Object()`、`DTO.Array()`、`DTO.Alternatives()`、`DTO.Any()`、`DTO.Function()`、`DTO.AsyncFunction()`、`DTO.Class()`、`DTO.InstanceOf()`、`DTO.Cron()`、`DTO.Glob()`、`DTO.Ref()`、`DTO.Link()` 等。规则方法与 joi 相同(`.required()`、`.optional()`、`.default()`、`.valid()`、`.min()`、`.max()`、`.pattern()`、`.email()`、`.uri()` 等)。
|
|
42
42
|
|
|
43
|
-
- **默认严格**:类型不对的值会被拒绝,而不是被转换(字符串 `'5'` 不是数字 5)。需要转换时调用 `.strict(false)`,例如 HTTP
|
|
43
|
+
- **默认严格**:类型不对的值会被拒绝,而不是被转换(字符串 `'5'` 不是数字 5)。需要转换时调用 `.strict(false)`,例如 HTTP 的查询参数和路由参数,它们总是字符串。
|
|
44
44
|
- **数值类型**:`DTO.Number()` 提供整数类型 `int8`、`uint8`、`int16`、`uint16`、`int32`、`uint32`、`int64` 和 `uint64`(64 位类型限于 JavaScript 的安全整数范围),以及浮点类型 `float`(32 位范围)和 `double`。
|
|
45
|
-
- **校验选项**:默认在遇到第一个错误时停止(`abortEarly`),并移除未知字段(`stripUnknown
|
|
45
|
+
- **校验选项**:默认在遇到第一个错误时停止(`abortEarly`),并移除未知字段(`stripUnknown`)。`MyDTO.options({...})` 返回使用其他选项的 DTO 校验规则。
|
|
46
46
|
- **DTO 类作为校验规则**:`MyDTO.Schema()` 是它的对象校验规则,`MyDTO.required()` 和 `MyDTO.optional()` 是标记为必填或可选的同一规则。凡是需要校验规则的地方(`@Accept`、`@Return`、动作装饰器)都可以直接使用 DTO 类。
|
|
47
47
|
|
|
48
48
|
## 2. 校验
|
|
49
49
|
|
|
50
50
|
```typescript
|
|
51
|
+
import {DTO} from 'lakutata'
|
|
52
|
+
import {Expect} from 'lakutata/decorator/dto'
|
|
53
|
+
|
|
54
|
+
class CustomerDTO extends DTO {
|
|
55
|
+
@Expect(DTO.String().min(2).required())
|
|
56
|
+
public name: string
|
|
57
|
+
|
|
58
|
+
@Expect(DTO.Number().integer().min(0).default(0))
|
|
59
|
+
public credit: number
|
|
60
|
+
}
|
|
61
|
+
|
|
51
62
|
//构造时校验:填充默认值,移除未知字段 "note";数据不合法时抛出 InvalidValueException
|
|
52
|
-
const customer: CustomerDTO = new CustomerDTO({name: 'Ada',
|
|
63
|
+
const customer: CustomerDTO = new CustomerDTO({name: 'Ada', note: 'vip'})
|
|
53
64
|
|
|
54
65
|
//DTO 实例会校验对其属性的每次修改:不合法的修改会抛出异常并被撤销
|
|
55
66
|
customer.credit = 10
|
|
56
67
|
|
|
57
|
-
|
|
58
|
-
const
|
|
59
|
-
const
|
|
68
|
+
//不创建实例直接校验:返回校验后的数据(普通对象),或抛出 InvalidValueException
|
|
69
|
+
const received: any = JSON.parse('{"name": "Ada"}')
|
|
70
|
+
const data: CustomerDTO = CustomerDTO.validate(received)
|
|
71
|
+
const later: CustomerDTO = await CustomerDTO.validateAsync(received)
|
|
60
72
|
|
|
61
73
|
//只检查,不抛出异常
|
|
62
74
|
const valid: boolean = CustomerDTO.isValid({name: ''})
|
|
@@ -72,11 +84,11 @@ const port: number = DTO.validate(8080, DTO.Number().port().required())
|
|
|
72
84
|
| 装饰器 | 作用对象 | 效果 |
|
|
73
85
|
|---|---|---|
|
|
74
86
|
| `@Expect(schema)` | DTO 的属性 | 声明属性的校验规则 |
|
|
75
|
-
| `@IndexSignature(schema)` | DTO 类 | 保留没有 `@Expect`
|
|
87
|
+
| `@IndexSignature(schema)` | DTO 类 | 保留没有 `@Expect` 规则的字段,并按这条规则校验它们,而不是移除 |
|
|
76
88
|
| `@Accept(...schemas)` | 方法 | 每次调用时按位置校验参数;失败时抛出 `InvalidMethodAcceptException` |
|
|
77
89
|
| `@Return(schema)` | 方法 | 每次调用时校验返回值(异步方法会等待其结果);失败时抛出 `InvalidMethodReturnException` |
|
|
78
90
|
|
|
79
|
-
`@Accept` 和 `@Return`
|
|
91
|
+
`@Accept` 和 `@Return` 把校验后的值交给方法(或调用方):默认值已填充,未知字段已移除。用 DTO 类校验参数或返回值时,得到的是普通对象,而不是该类的实例。缺少的参数会被接受,除非它的规则是必填的(`MyDTO.required()`)。
|
|
80
92
|
|
|
81
93
|
```typescript
|
|
82
94
|
import {Component, DTO} from 'lakutata'
|
|
@@ -124,8 +136,8 @@ class Bank extends Component {
|
|
|
124
136
|
|
|
125
137
|
## 4. 框架中的 DTO
|
|
126
138
|
|
|
127
|
-
- **对象选项**:`@Configurable(schema)`(来自 `lakutata/decorator/di
|
|
128
|
-
- **控制器动作**:传给 `@GET`、`@POST`、`@CLIAction`、`@ServiceAction` 等的 DTO 校验动作的输入;输入不合法时以状态码 400 响应。见 [
|
|
139
|
+
- **对象选项**:`@Configurable(schema)`(来自 `lakutata/decorator/di`)校验组件或提供者的选项;见 [Injection](Injection.md)。
|
|
140
|
+
- **控制器动作**:传给 `@GET`、`@POST`、`@CLIAction`、`@ServiceAction` 等的 DTO 校验动作的输入;输入不合法时以状态码 400 响应。见 [Controllers](Controllers.md)。
|
|
129
141
|
- **分页**(`lakutata/dtos`):`PaginationSearchDTO` 和 `PaginationResultDTO` 是分页动作的输入和结果,`paginator` 负责计算分页;`FlexibleDTO` 是接受任意字段的 DTO。
|
|
130
142
|
- **校验消息**:错误消息支持多语言;`lakutata` 中的 `registerValidationMessages`、`runInValidationLanguage` 和 `currentValidationLanguage` 管理其语言,I18n 组件的语言中间件为每个请求设置语言(见 [I18n](I18n.md))。
|
|
131
143
|
|
|
@@ -137,36 +149,54 @@ DTO 和校验规则可以与 JSON Schema(draft 04、06、07、2019-09 和 2020
|
|
|
137
149
|
|
|
138
150
|
```typescript
|
|
139
151
|
import {DTO} from 'lakutata'
|
|
152
|
+
import {Expect} from 'lakutata/decorator/dto'
|
|
140
153
|
import {toJsonSchema} from 'lakutata/dtos'
|
|
141
154
|
|
|
155
|
+
class UserDTO extends DTO {
|
|
156
|
+
@Expect(DTO.Number().integer().required())
|
|
157
|
+
public id: number
|
|
158
|
+
|
|
159
|
+
@Expect(DTO.String().required())
|
|
160
|
+
public name: string
|
|
161
|
+
}
|
|
162
|
+
|
|
142
163
|
UserDTO.toJsonSchema() //JSON Schema 2020-12(默认)
|
|
143
164
|
UserDTO.toJsonSchema('draft-07') //'draft-2020-12' | 'draft-2019-09' | 'draft-07' | 'draft-04'
|
|
144
165
|
UserDTO.toOpenAPIJsonSchema() //OpenAPI 3.1(默认),或 '3.0'
|
|
145
166
|
toJsonSchema(DTO.String().email(), {target: 'openapi-3.0'}) //任意校验规则,或 DTO 类
|
|
146
167
|
```
|
|
147
168
|
|
|
148
|
-
- 生成的 JSON Schema
|
|
149
|
-
- 未知字段遵循校验选项:在 lakutata 的默认选项(`allowUnknown`、`stripUnknown
|
|
150
|
-
- 数值类型转换为整数边界(`int8` 到 `uint64
|
|
169
|
+
- 生成的 JSON Schema 描述的是校验规则在不做转换时接受的值,ajv(配合 ajv-formats)等校验器接受的也是这些值。JSON Schema 无法表达的内容(自定义规则、对其他值的引用、类型转换)会被省略,所以 JSON Schema 可能接受原规则拒绝的值,但不会拒绝原规则接受的值。
|
|
170
|
+
- 未知字段遵循校验选项:在 lakutata 的默认选项(`allowUnknown`、`stripUnknown`)下,对象接受未知字段;要按其他选项转换,通过 `preferences` 传入这些选项。
|
|
171
|
+
- 数值类型转换为整数边界(`int8` 到 `uint64`)和浮点范围;在 OpenAPI 中还会带上 `int32`、`int64`、`float` 和 `double` 格式。
|
|
151
172
|
|
|
152
173
|
### 5.2 导入
|
|
153
174
|
|
|
154
175
|
```typescript
|
|
155
|
-
import {
|
|
176
|
+
import {readFileSync} from 'node:fs'
|
|
177
|
+
import {DTO, type JSONSchema} from 'lakutata'
|
|
156
178
|
import {fromJsonSchema} from 'lakutata/dtos'
|
|
157
179
|
|
|
158
|
-
const
|
|
180
|
+
const userJsonSchema: JSONSchema = {
|
|
181
|
+
type: 'object',
|
|
182
|
+
properties: {id: {type: 'integer'}, name: {type: 'string'}},
|
|
183
|
+
required: ['id']
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
//校验规则
|
|
187
|
+
const schema = fromJsonSchema(userJsonSchema)
|
|
159
188
|
DTO.validate({id: 1}, schema)
|
|
160
189
|
|
|
161
|
-
//生成 DTO
|
|
190
|
+
//生成 DTO 类,它是调用 fromJsonSchema() 的那个类的子类
|
|
162
191
|
const UserDTO = DTO.fromJsonSchema(userJsonSchema)
|
|
163
192
|
const user = new UserDTO({id: 1, name: 'Alice'})
|
|
164
193
|
|
|
165
194
|
//OpenAPI 文档中各对象 schema(components.schemas)对应的 DTO 类,按名称取用
|
|
195
|
+
const openApiDocument: Record<string, unknown> = JSON.parse(readFileSync('openapi.json', 'utf8'))
|
|
166
196
|
const {Pet, Person} = DTO.fromOpenAPI(openApiDocument)
|
|
167
197
|
```
|
|
168
198
|
|
|
169
|
-
- 导入的校验规则按 JSON Schema
|
|
199
|
+
- 导入的校验规则按 JSON Schema 的语义校验:不转换值(除非传入 `convert: true`),未知字段遵循 `additionalProperties`,格式校验与 ajv-formats 一致,并会填充默认值。
|
|
170
200
|
- 引用通过 JSON pointer、`$anchor` 和 `$id` 解析(其他文档通过 `schemas` 传入,OpenAPI 文档通过 `document` 传入);支持递归引用。
|
|
171
201
|
- 版本从 `$schema` 读取,或通过 `dialect` 指定(默认 2020-12)。
|
|
172
|
-
-
|
|
202
|
+
- 把 lakutata 的校验规则转换为 JSON Schema 会丢失信息(自定义规则、类型转换):要原样存储并恢复校验规则,请保存它的 `describe()` 输出(不含函数时是一个 JSON 值),再用 `DTO.Build(description)` 重建。
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
# Lakutata 数据库
|
|
2
|
+
|
|
3
|
+
lakutata 的数据库层是 `@lakutata/orm` 包,基于 [TypeORM](https://typeorm.io) 1 构建。TypeORM 的源码已经包含在这个包里,所以不会再安装 `typeorm` 包。`lakutata` 通过四个子路径重新导出它:
|
|
4
|
+
|
|
5
|
+
| 子路径 | 提供的内容 |
|
|
6
|
+
|---|---|
|
|
7
|
+
| `lakutata/com/database` | `Database` 组件(整个应用共享的连接)和 `buildDatabaseOptions` |
|
|
8
|
+
| `lakutata/provider/database` | `Database` 提供者(每次解析都有自己的连接) |
|
|
9
|
+
| `lakutata/decorator/orm` | 实体的装饰器(`@Entity`、`@Column`、各种关系……) |
|
|
10
|
+
| `lakutata/orm` | TypeORM 的 API:仓储、实体管理器、查询操作符、迁移、错误 |
|
|
11
|
+
|
|
12
|
+
数据库驱动需要另外安装,见 [DatabaseDrivers](DatabaseDrivers.md)。实体、查询和事务见 [Entities](Entities.md),表结构的变更见 [Migrations](Migrations.md)。
|
|
13
|
+
|
|
14
|
+
## 1. Database 组件
|
|
15
|
+
|
|
16
|
+
`buildDatabaseOptions` 用 TypeORM 的连接选项声明一个 `Database` 组件:
|
|
17
|
+
|
|
18
|
+
```typescript
|
|
19
|
+
import {Application, Component} from 'lakutata'
|
|
20
|
+
import {Inject} from 'lakutata/decorator/di'
|
|
21
|
+
import {buildDatabaseOptions, Database} from 'lakutata/com/database'
|
|
22
|
+
import {Column, Entity, PrimaryGeneratedColumn} from 'lakutata/decorator/orm'
|
|
23
|
+
|
|
24
|
+
@Entity('users')
|
|
25
|
+
class User {
|
|
26
|
+
@PrimaryGeneratedColumn()
|
|
27
|
+
public id: number
|
|
28
|
+
|
|
29
|
+
@Column({type: 'varchar', length: 100})
|
|
30
|
+
public name: string
|
|
31
|
+
|
|
32
|
+
@Column({unique: true})
|
|
33
|
+
public email: string
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
class Users extends Component {
|
|
37
|
+
//声明为 "db" 的组件
|
|
38
|
+
@Inject('db')
|
|
39
|
+
protected readonly db: Database
|
|
40
|
+
|
|
41
|
+
public async register(name: string, email: string): Promise<User> {
|
|
42
|
+
return await this.db.getRepository(User).save({name: name, email: email})
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
public async find(id: number): Promise<User | null> {
|
|
46
|
+
return await this.db.getRepository(User).findOneBy({id: id})
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
Application
|
|
51
|
+
.run(() => ({
|
|
52
|
+
id: 'users.app',
|
|
53
|
+
name: 'Users',
|
|
54
|
+
components: {
|
|
55
|
+
db: buildDatabaseOptions({
|
|
56
|
+
type: 'postgres',
|
|
57
|
+
url: process.env.DATABASE_URL,
|
|
58
|
+
entities: [User],
|
|
59
|
+
//只用于开发:表结构跟随实体变化。生产环境请使用迁移
|
|
60
|
+
synchronize: true
|
|
61
|
+
}),
|
|
62
|
+
users: {class: Users}
|
|
63
|
+
},
|
|
64
|
+
bootstrap: ['db']
|
|
65
|
+
}))
|
|
66
|
+
.onLaunched(async (app: Application): Promise<void> => {
|
|
67
|
+
const users: Users = await app.getObject<Users>('users')
|
|
68
|
+
await users.register('Ada', 'ada@example.com')
|
|
69
|
+
})
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
- 组件在创建时连接数据库。列在 `bootstrap` 里时,它在应用启动过程中连接,连接失败会让启动失败;否则在第一次被用到时才连接。
|
|
73
|
+
- 应用停止时,它会断开连接。
|
|
74
|
+
- 其他对象按名字注入它(`@Inject('db')`),或者用 `getObject('db')` 获取。
|
|
75
|
+
|
|
76
|
+
## 2. 连接选项
|
|
77
|
+
|
|
78
|
+
这些选项就是 TypeORM 的选项,会原样交给 TypeORM。各驱动特有的选项见 [DatabaseDrivers](DatabaseDrivers.md),通用的选项有:
|
|
79
|
+
|
|
80
|
+
| 选项 | 默认值 | 含义 |
|
|
81
|
+
|---|---|---|
|
|
82
|
+
| `type` | 必填 | 驱动:`'postgres'`、`'mysql'`、`'better-sqlite3'`…… |
|
|
83
|
+
| `entities` | | 实体类、`EntitySchema`,或者编译后文件的 glob(`'build/entities/*.js'`) |
|
|
84
|
+
| `synchronize` | `false` | 每次连接时按实体更新表结构。只用于开发 |
|
|
85
|
+
| `logging` | `false` | TypeORM 记录什么:`true`,或者 `'query'`、`'error'`、`'schema'`、`'warn'`、`'info'`、`'log'` 组成的列表 |
|
|
86
|
+
| `logger` | | TypeORM 的日志写到哪里:`'advanced-console'`、`'simple-console'`、`'file'`、`'debug'`,或者自己实现的日志记录器 |
|
|
87
|
+
| `maxQueryExecutionTime` | | 记录比这个时间(毫秒)慢的查询 |
|
|
88
|
+
| `poolSize` | | 连接池的连接数 |
|
|
89
|
+
| `extra` | | 传给驱动客户端的选项 |
|
|
90
|
+
| `migrations`、`migrationsRun`、`migrationsTableName`、`migrationsTransactionMode` | | 迁移(见 [Migrations](Migrations.md)) |
|
|
91
|
+
| `subscribers` | | 实体订阅者 |
|
|
92
|
+
| `namingStrategy` | | 表、列和索引的命名方式 |
|
|
93
|
+
| `cache` | | 查询结果的缓存:`true`(存在数据库的一张表里),或者 `{type: 'redis', options}` |
|
|
94
|
+
| `invalidWhereValuesBehavior` | `{null: 'ignore', undefined: 'ignore'}` | where 条件中的 `null` 和 `undefined` 如何处理(见下文) |
|
|
95
|
+
|
|
96
|
+
**条件中的 `null` 和 `undefined`。** 默认情况下,where 条件中值为 `null` 或 `undefined` 的属性会被忽略,这与 TypeORM 0.3 相同;TypeORM 1 的默认行为则是抛出错误。所以 `findOneBy({id: undefined})` 会查到表里的第一行:用请求中的值查询之前要先检查它们,或者设置 `invalidWhereValuesBehavior: {undefined: 'throw'}`,让这类值抛出错误(给出的每个键会替换它的默认值)。
|
|
97
|
+
|
|
98
|
+
**用 TypeORM 0.3 创建的数据库。** 如果表名或列名中有非 ASCII 字符,TypeORM 1 给它们的索引和约束起的名字会不同,生成的迁移就会重命名它们。`namingStrategy: new NamingStrategyV03()`(来自 `lakutata/orm`)可以保持 TypeORM 0.3 的命名。
|
|
99
|
+
|
|
100
|
+
**存在 Redis 中的查询缓存**(`cache: {type: 'redis'}` 或 `'ioredis'`)需要安装 `redis` 或 `ioredis` 包。
|
|
101
|
+
|
|
102
|
+
## 3. 组件提供的功能
|
|
103
|
+
|
|
104
|
+
组件提供 TypeORM 数据源的 API:
|
|
105
|
+
|
|
106
|
+
| 方法或属性 | 作用 |
|
|
107
|
+
|---|---|
|
|
108
|
+
| `getRepository(Entity)` | 实体的仓储(在 MongoDB 上是 `MongoRepository`) |
|
|
109
|
+
| `getMongoRepository(Entity)`、`getTreeRepository(Entity)` | MongoDB 的仓储、树形实体的仓储 |
|
|
110
|
+
| `manager` | 实体管理器 |
|
|
111
|
+
| `transaction(fn)`、`transaction(isolationLevel, fn)` | 在事务中执行一个函数 |
|
|
112
|
+
| `query(sql, parameters)` | 执行 SQL;占位符在 PostgreSQL 上是 `$1, $2…`,在 MySQL 和 SQLite 上是 `?` |
|
|
113
|
+
| `createQueryBuilder(Entity, alias)` | 查询构造器 |
|
|
114
|
+
| `createQueryRunner(mode)` | 连接池中的一个连接,用来手动控制事务;`'slave'` 从副本读取 |
|
|
115
|
+
| `synchronize()` | 按实体更新表结构 |
|
|
116
|
+
| `runMigrations()`、`undoLastMigration()`、`showMigrations()` | 执行、回退和列出迁移 |
|
|
117
|
+
| `hasMetadata(Entity)`、`getMetadata(Entity)` | 是否认识某个实体,以及它的元数据 |
|
|
118
|
+
|
|
119
|
+
## 4. Database 提供者
|
|
120
|
+
|
|
121
|
+
`lakutata/provider/database` 中的 `Database` 有同样的 API,但它是**瞬态**的:每次解析(`@Inject`、`getObject()`)都会创建一个新实例,打开自己的连接池;它随创建它的对象或容器一起销毁时,连接池也会关闭。它适合短时的任务(一个作业、一个脚本、每个客户一个数据库),而应用中的请求共享组件。
|
|
122
|
+
|
|
123
|
+
```typescript
|
|
124
|
+
import {Application} from 'lakutata'
|
|
125
|
+
import {buildDatabaseOptions, Database} from 'lakutata/provider/database'
|
|
126
|
+
import {Column, Entity, PrimaryGeneratedColumn} from 'lakutata/decorator/orm'
|
|
127
|
+
|
|
128
|
+
@Entity('reports')
|
|
129
|
+
class Report {
|
|
130
|
+
@PrimaryGeneratedColumn()
|
|
131
|
+
public id: number
|
|
132
|
+
|
|
133
|
+
@Column()
|
|
134
|
+
public title: string
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
Application
|
|
138
|
+
.run(() => ({
|
|
139
|
+
id: 'reports.app',
|
|
140
|
+
name: 'Reports',
|
|
141
|
+
providers: {
|
|
142
|
+
reports: {
|
|
143
|
+
...buildDatabaseOptions({type: 'postgres', url: process.env.REPORTS_URL}),
|
|
144
|
+
//加到连接选项的实体中
|
|
145
|
+
entities: [Report]
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}))
|
|
149
|
+
.onLaunched(async (app: Application): Promise<void> => {
|
|
150
|
+
//在这里打开连接,随应用一起关闭
|
|
151
|
+
const database: Database = await app.getObject<Database>('reports')
|
|
152
|
+
console.log(await database.getRepository(Report).count())
|
|
153
|
+
})
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## 5. 多个数据库
|
|
157
|
+
|
|
158
|
+
每个数据库都是一个独立的组件,按各自的名字注入:
|
|
159
|
+
|
|
160
|
+
```typescript
|
|
161
|
+
import {Application} from 'lakutata'
|
|
162
|
+
import {buildDatabaseOptions} from 'lakutata/com/database'
|
|
163
|
+
|
|
164
|
+
Application.run(() => ({
|
|
165
|
+
id: 'shop.app',
|
|
166
|
+
name: 'Shop',
|
|
167
|
+
components: {
|
|
168
|
+
db: buildDatabaseOptions({type: 'postgres', url: process.env.DATABASE_URL, entities: []}),
|
|
169
|
+
analytics: buildDatabaseOptions({type: 'mysql', url: process.env.ANALYTICS_URL, entities: []})
|
|
170
|
+
},
|
|
171
|
+
bootstrap: ['db', 'analytics']
|
|
172
|
+
}))
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
一个实体可以属于多个数据库。它的仓储来自调用 `getRepository()` 的那个数据库。
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
# Lakutata 数据库驱动
|
|
2
|
+
|
|
3
|
+
数据库的 `type` 选项决定使用哪个驱动。安装 `lakutata` 时不会安装驱动包:根据你的数据库,另外安装对应的驱动。
|
|
4
|
+
|
|
5
|
+
| 数据库 | `type` | 需要安装 |
|
|
6
|
+
|---|---|---|
|
|
7
|
+
| PostgreSQL | `postgres` | `pg`(8.5 或更高) |
|
|
8
|
+
| CockroachDB | `cockroachdb` | `pg` |
|
|
9
|
+
| MySQL、MariaDB | `mysql`、`mariadb` | `mysql2`(3.15.3 或更高) |
|
|
10
|
+
| SQLite | `better-sqlite3` | `better-sqlite3`(12) |
|
|
11
|
+
| WebAssembly 版的 SQLite | `sqljs` | `sql.js`(1.4 或更高) |
|
|
12
|
+
| Microsoft SQL Server | `mssql` | `mssql`(12) |
|
|
13
|
+
| Oracle | `oracle` | `oracledb`(6.3 或更高,或 7) |
|
|
14
|
+
| MongoDB | `mongodb` | `mongodb`(7) |
|
|
15
|
+
| 嵌入应用内的 MongoDB | `mongo-embedded` | `mingo`(7.2 或更高)和 `bson`(7);见 [MongoEmbedded](MongoEmbedded.md) |
|
|
16
|
+
| SAP HANA | `sap` | `@sap/hana-client`(2.14 或更高) |
|
|
17
|
+
| Google Cloud Spanner | `spanner` | `@google-cloud/spanner`(8) |
|
|
18
|
+
| 通过 Data API 访问的 Amazon Aurora | `aurora-mysql`、`aurora-postgres` | `typeorm-aurora-data-api-driver`(3) |
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install lakutata pg
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
没有 `sqlite` 这个类型:SQLite 文件使用 `better-sqlite3`;在无法运行原生模块的环境中使用 `sqljs`。TypeORM 还有面向移动平台的驱动(`capacitor`、`cordova`、`expo`、`nativescript`、`react-native`),lakutata 不以这些平台为目标。
|
|
25
|
+
|
|
26
|
+
## 所有驱动通用的规则
|
|
27
|
+
|
|
28
|
+
- 连接选项会原样交给 TypeORM,TypeORM 不会检查它们:缺少主机或密码时,由驱动在连接数据库时报错。
|
|
29
|
+
- `extra` 会传给驱动的客户端(连接池、连接),放在其他选项之后:用它设置 TypeORM 没有提供选项的配置。
|
|
30
|
+
- `driver` 直接给出驱动模块本身(`driver: require('pg')`),不由 lakutata 去加载驱动包。
|
|
31
|
+
- 下面的每个示例都声明一个 `Database` 组件。`Database` 提供者的选项相同(见 [Database](Database.md))。
|
|
32
|
+
|
|
33
|
+
## PostgreSQL
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
import {buildDatabaseOptions} from 'lakutata/com/database'
|
|
37
|
+
|
|
38
|
+
export const db = buildDatabaseOptions({
|
|
39
|
+
type: 'postgres',
|
|
40
|
+
host: 'localhost',
|
|
41
|
+
port: 5432,
|
|
42
|
+
username: 'app',
|
|
43
|
+
password: process.env.DB_PASSWORD,
|
|
44
|
+
database: 'app',
|
|
45
|
+
//或者一次给出全部:url: 'postgres://app:secret@localhost:5432/app'
|
|
46
|
+
entities: []
|
|
47
|
+
})
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
| 选项 | 默认值 | 含义 |
|
|
51
|
+
|---|---|---|
|
|
52
|
+
| `url` | | 连接 URL,代替下面这些选项 |
|
|
53
|
+
| `host`、`port`、`username`、`password`、`database` | | 服务器和数据库;`password` 可以是函数(同步或异步),用于读取会轮换的密钥 |
|
|
54
|
+
| `ssl` | | `true`,或 Node.js 的 TLS 选项(`{ca, rejectUnauthorized}`) |
|
|
55
|
+
| `schema` | 服务器的 `search_path`(通常是 `public`) | 表所在的 schema |
|
|
56
|
+
| `poolSize` | 10(`pg` 的默认值) | 连接池的连接数 |
|
|
57
|
+
| `connectTimeoutMS` | 不限 | 连接的超时时间 |
|
|
58
|
+
| `applicationName` | | 在服务器活动列表中显示的名字 |
|
|
59
|
+
| `uuidExtension` | `'uuid-ossp'` | UUID 列使用的扩展:`'uuid-ossp'` 或 `'pgcrypto'` |
|
|
60
|
+
| `replication` | | `{master, slaves}`:读操作发往副本 |
|
|
61
|
+
|
|
62
|
+
- **`bigint` 和 `numeric` 列以字符串返回**,以保持精度(`'9007199254740993'`、`'12.50'`)。如果数字就够用,可以用列的 `transformer` 转换。`parseInt8: true` 会让 `bigint` 列返回数字,但它修改的是 `pg` 在整个进程中的设置。
|
|
63
|
+
- 安装了 `pg-native` 时会使用 `pg` 的原生客户端。流式查询(查询构造器的 `stream()`)需要 `pg-query-stream`。
|
|
64
|
+
|
|
65
|
+
**CockroachDB** 使用同一个驱动,`type: 'cockroachdb'`,连接选项相同。必须给出它的 `timeTravelQueries` 选项(读操作是否使用 follower reads);因冲突失败的事务会重试 5 次(`maxTransactionRetries`)。
|
|
66
|
+
|
|
67
|
+
## MySQL 与 MariaDB
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
import {buildDatabaseOptions} from 'lakutata/com/database'
|
|
71
|
+
|
|
72
|
+
export const db = buildDatabaseOptions({
|
|
73
|
+
type: 'mysql',
|
|
74
|
+
host: 'localhost',
|
|
75
|
+
port: 3306,
|
|
76
|
+
username: 'app',
|
|
77
|
+
password: process.env.DB_PASSWORD,
|
|
78
|
+
database: 'app',
|
|
79
|
+
charset: 'utf8mb4',
|
|
80
|
+
entities: []
|
|
81
|
+
})
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
| 选项 | 默认值 | 含义 |
|
|
85
|
+
|---|---|---|
|
|
86
|
+
| `url`、`host`、`port`、`username`、`password` | | 服务器 |
|
|
87
|
+
| `database` | | 数据库。必填,除非每个实体都指定了自己的数据库 |
|
|
88
|
+
| `socketPath` | | 用 unix socket 代替主机和端口 |
|
|
89
|
+
| `ssl` | | TLS 选项,或 TLS 配置文件的名字 |
|
|
90
|
+
| `charset` | `'UTF8_GENERAL_CI'` | 字符集和排序规则:要支持完整的 Unicode(包括 emoji),用 `'utf8mb4'` |
|
|
91
|
+
| `timezone` | `'local'` | 日期如何读写:`'local'`、`'Z'` 或偏移量(`'+08:00'`) |
|
|
92
|
+
| `poolSize` | 10(`mysql2` 的默认值) | 连接池的连接数 |
|
|
93
|
+
| `connectTimeout`、`acquireTimeout` | `10000` | 连接的超时时间,以及从连接池获取连接的超时时间 |
|
|
94
|
+
| `replication` | | `{master, slaves}`:读操作发往副本 |
|
|
95
|
+
|
|
96
|
+
- MariaDB 使用 `type: 'mariadb'`,选项相同。MariaDB 从 10.7 开始支持 `uuid` 列类型。
|
|
97
|
+
- **`bigint` 和 `decimal` 列以字符串返回**,与 PostgreSQL 相同。
|
|
98
|
+
- 一张表最多有一个自增列。在 TypeORM 的表结构同步中,MySQL 不支持 check 约束。
|
|
99
|
+
- 只支持 `mysql2`,不支持旧的 `mysql` 包。
|
|
100
|
+
|
|
101
|
+
## SQLite:better-sqlite3
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
import {buildDatabaseOptions} from 'lakutata/com/database'
|
|
105
|
+
|
|
106
|
+
export const db = buildDatabaseOptions({
|
|
107
|
+
type: 'better-sqlite3',
|
|
108
|
+
//一个文件(会自动创建它所在的目录),或 ':memory:'
|
|
109
|
+
database: 'data/app.sqlite',
|
|
110
|
+
enableWAL: true,
|
|
111
|
+
entities: []
|
|
112
|
+
})
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
| 选项 | 默认值 | 含义 |
|
|
116
|
+
|---|---|---|
|
|
117
|
+
| `database` | 必填 | 数据库文件,或 `':memory:'` |
|
|
118
|
+
| `enableWAL` | `false` | 预写日志(WAL):读操作不再等待写操作 |
|
|
119
|
+
| `timeout` | `5000` | 语句等待被其他连接锁住的数据库的时间,单位毫秒 |
|
|
120
|
+
| `readonly`、`fileMustExist` | `false` | 以只读方式打开文件;文件不存在时报错 |
|
|
121
|
+
| `key` | | 加密密钥,用于带 SQLCipher 的 SQLite |
|
|
122
|
+
| `prepareDatabase` | | `(db) => …`,连接打开后用 better-sqlite3 的连接调用它:设置 pragma、注册函数 |
|
|
123
|
+
| `nativeBinding` | | 编译好的模块 `better_sqlite3.node` 的路径 |
|
|
124
|
+
|
|
125
|
+
- 外键约束是生效的(`PRAGMA foreign_keys = ON`)。只有一个连接:不支持 `poolSize`。
|
|
126
|
+
- **`bigint` 列以数字返回**:超过 2^53 的值会丢失精度。这类值请存在文本列中。
|
|
127
|
+
- `better-sqlite3` 是原生模块,针对某个 Node.js 版本编译。Electron 应用需要针对它的 Electron 版本的构建(`electron-rebuild`,或 better-sqlite3 为 Electron 提供的预编译文件);Bun 无法加载它(在 Bun 上使用 `sqljs`)。
|
|
128
|
+
|
|
129
|
+
## SQLite:sql.js
|
|
130
|
+
|
|
131
|
+
`sql.js` 是编译成 WebAssembly 的 SQLite:没有原生模块,所以在 Node.js、Bun、Electron 和浏览器中的表现都一样。整个数据库保存在内存中,发生变化时写入文件。
|
|
132
|
+
|
|
133
|
+
```typescript
|
|
134
|
+
import {buildDatabaseOptions} from 'lakutata/com/database'
|
|
135
|
+
|
|
136
|
+
export const db = buildDatabaseOptions({
|
|
137
|
+
type: 'sqljs',
|
|
138
|
+
//连接时加载(如果文件存在),每次变化后写入
|
|
139
|
+
location: 'data/app.sqlite',
|
|
140
|
+
autoSave: true,
|
|
141
|
+
entities: []
|
|
142
|
+
})
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
| 选项 | 默认值 | 含义 |
|
|
146
|
+
|---|---|---|
|
|
147
|
+
| `location` | | 加载和保存的文件(在浏览器中是 `localStorage` 的键) |
|
|
148
|
+
| `autoSave` | `false` | 每次变化后保存。需要 `location` 或 `autoSaveCallback` |
|
|
149
|
+
| `autoSaveCallback` | | `(data: Uint8Array) => …`,代替写入 `location` |
|
|
150
|
+
| `database` | | 要加载的数据库内容(`Uint8Array`),代替 `location` |
|
|
151
|
+
| `useLocalForage` | `false` | 在浏览器中保存到 IndexedDB(通过 `localforage`),而不是 `localStorage` |
|
|
152
|
+
| `sqlJsConfig` | | sql.js 初始化的选项(用 `locateFile` 指定它的 `.wasm` 文件) |
|
|
153
|
+
|
|
154
|
+
- 没有 `autoSave` 时,在调用实体管理器(`SqljsEntityManager`)的 `saveDatabase()` 之前,什么都不会写到磁盘。有 `autoSave` 时,事务中的变化在事务提交后保存。
|
|
155
|
+
- 每次保存都会写入整个文件:sql.js 适合小型数据库。
|
|
156
|
+
- 与 better-sqlite3 相同,外键约束生效,`bigint` 列以数字返回。
|
|
157
|
+
|
|
158
|
+
## Microsoft SQL Server
|
|
159
|
+
|
|
160
|
+
```typescript
|
|
161
|
+
import {buildDatabaseOptions} from 'lakutata/com/database'
|
|
162
|
+
|
|
163
|
+
export const db = buildDatabaseOptions({
|
|
164
|
+
type: 'mssql',
|
|
165
|
+
host: 'localhost',
|
|
166
|
+
port: 1433,
|
|
167
|
+
username: 'sa',
|
|
168
|
+
password: process.env.DB_PASSWORD,
|
|
169
|
+
database: 'app',
|
|
170
|
+
options: {
|
|
171
|
+
//服务器使用自签名证书,比如开发环境
|
|
172
|
+
trustServerCertificate: true
|
|
173
|
+
},
|
|
174
|
+
entities: []
|
|
175
|
+
})
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
| 选项 | 默认值 | 含义 |
|
|
179
|
+
|---|---|---|
|
|
180
|
+
| `url`、`host`、`port`、`username`、`password`、`database` | | 服务器和数据库 |
|
|
181
|
+
| `authentication` | | 用户名密码以外的认证方式:`{type: 'ntlm', ...}`、`{type: 'azure-active-directory-default', ...}`…… |
|
|
182
|
+
| `schema` | 用户的默认 schema | 表所在的 schema |
|
|
183
|
+
| `options.encrypt` | `true` | 加密连接 |
|
|
184
|
+
| `options.trustServerCertificate` | `false` | 接受不是由受信任机构签发的证书 |
|
|
185
|
+
| `options.instanceName` | | 命名实例 |
|
|
186
|
+
| `pool` | | 连接池:`max`、`min`、`idleTimeoutMillis`(默认 30000)……(不支持 `poolSize`) |
|
|
187
|
+
| `connectionTimeout`、`requestTimeout` | `15000` | 连接的超时时间,以及查询的超时时间 |
|
|
188
|
+
|
|
189
|
+
- 由于 `encrypt` 默认开启,使用自签名证书的服务器(本地服务器、容器)会拒绝连接,除非 `trustServerCertificate` 为 `true`。
|
|
190
|
+
- 事务不能嵌套。
|
|
191
|
+
|
|
192
|
+
## Oracle
|
|
193
|
+
|
|
194
|
+
```typescript
|
|
195
|
+
import {buildDatabaseOptions} from 'lakutata/com/database'
|
|
196
|
+
|
|
197
|
+
export const db = buildDatabaseOptions({
|
|
198
|
+
type: 'oracle',
|
|
199
|
+
host: 'localhost',
|
|
200
|
+
port: 1521,
|
|
201
|
+
serviceName: 'FREEPDB1',
|
|
202
|
+
username: 'app',
|
|
203
|
+
password: process.env.DB_PASSWORD,
|
|
204
|
+
entities: []
|
|
205
|
+
})
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
| 选项 | 默认值 | 含义 |
|
|
209
|
+
|---|---|---|
|
|
210
|
+
| `host`、`port`、`username`、`password` | | 服务器 |
|
|
211
|
+
| `serviceName` 或 `sid` | | 数据库服务 |
|
|
212
|
+
| `connectString` | 由上面的选项生成 | 连接字符串(`'localhost:1521/FREEPDB1'`、TNS 条目),代替上面的选项 |
|
|
213
|
+
| `thickMode` | `false` | `oracledb` 的 thick 模式(使用 Oracle Client 库):`true`,或 `{libDir, configDir}` |
|
|
214
|
+
| `useUTC` | `false` | 以 UTC 读写日期 |
|
|
215
|
+
| `poolSize` | | 连接池的连接数 |
|
|
216
|
+
|
|
217
|
+
- `oracledb` 6 及以后的版本默认运行在 thin 模式下,不需要 Oracle Client。需要 thick 模式的功能时再设置 `thickMode`。
|
|
218
|
+
- 表在用户自己的 schema 中。`useUTC` 会设置整个进程所有会话的时区(环境变量 `ORA_SDTZ`)。
|
|
219
|
+
|
|
220
|
+
## MongoDB
|
|
221
|
+
|
|
222
|
+
```typescript
|
|
223
|
+
import {buildDatabaseOptions} from 'lakutata/com/database'
|
|
224
|
+
import {Column, Entity, ObjectIdColumn} from 'lakutata/decorator/orm'
|
|
225
|
+
import type {ObjectId} from 'lakutata/orm'
|
|
226
|
+
|
|
227
|
+
@Entity('users')
|
|
228
|
+
export class User {
|
|
229
|
+
@ObjectIdColumn()
|
|
230
|
+
public id: ObjectId
|
|
231
|
+
|
|
232
|
+
@Column()
|
|
233
|
+
public name: string
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
export const db = buildDatabaseOptions({
|
|
237
|
+
type: 'mongodb',
|
|
238
|
+
url: 'mongodb://localhost:27017/app',
|
|
239
|
+
entities: [User]
|
|
240
|
+
})
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
| 选项 | 默认值 | 含义 |
|
|
244
|
+
|---|---|---|
|
|
245
|
+
| `url` | | 连接 URL |
|
|
246
|
+
| `host`、`port`、`username`、`password`、`database` | `127.0.0.1`、`27017` | 没有 `url` 时的服务器 |
|
|
247
|
+
| `authSource`、`replicaSet`、`tls`、`readPreference`、`writeConcern`…… | | MongoDB 客户端的选项 |
|
|
248
|
+
| `poolSize` | | 最大连接数(`maxPoolSize`) |
|
|
249
|
+
|
|
250
|
+
- 实体要有一个 `@ObjectIdColumn()`,即它的 `_id`。它的类型是 `lakutata/orm` 中的 `ObjectId`:在 ES 模块中 `import {ObjectId} from 'bson'` 得到的是另一个类,实体的 id 不是它的实例。
|
|
251
|
+
- `getRepository()` 返回 `MongoRepository`,它带有 MongoDB 的方法(使用 MongoDB 操作符的 `find`、`aggregate`、`createCursor`……)。
|
|
252
|
+
- TypeORM 对 MongoDB 不支持:查询构造器、`query()`、关系和级联、树形仓储、流式查询。**`transaction()` 会在没有事务的情况下执行它的函数**:函数失败时,已经写入的内容不会撤销。
|
|
253
|
+
- `synchronize` 只创建索引。迁移需要手写(见 [Migrations](Migrations.md))。
|
|
254
|
+
|
|
255
|
+
## SAP HANA、Google Cloud Spanner 与 Amazon Aurora
|
|
256
|
+
|
|
257
|
+
这些驱动原样来自 TypeORM:
|
|
258
|
+
|
|
259
|
+
- **SAP HANA**(`sap`):`host`、`port`、`username`、`password`、`database`、`schema`,加密连接的 `encrypt` 以及 `key`、`cert`、`ca`,还有 `pool`(`maxConnectedOrPooled`,默认 10)。
|
|
260
|
+
- **Google Cloud Spanner**(`spanner`):`projectId`、`instanceId`、`databaseId`,以及 `credentials`(`client_email`、`private_key`),不给出时使用运行环境中的凭据。它的类型中从 MySQL 复制来的其他选项不会被读取。
|
|
261
|
+
- **通过 Data API 访问的 Amazon Aurora**(`aurora-mysql`、`aurora-postgres`):`region`、`secretArn`、`resourceArn` 和 `database` 为必填;查询通过 AWS 的 HTTP API 发送,而不是通过数据库连接。
|