@h-ai/reldb 0.1.0-alpha9 → 1.0.0-beta.2
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.en.md +661 -0
- package/README.ja.md +661 -0
- package/README.md +258 -58
- package/dist/chunk-SDS2ZT3V.js +132 -0
- package/dist/chunk-SDS2ZT3V.js.map +1 -0
- package/dist/index.d.ts +648 -549
- package/dist/index.js +1285 -357
- package/dist/index.js.map +1 -1
- package/dist/providers/sqlite/reldb-sqlite-worker.mjs +143 -0
- package/dist/schemas.d.ts +490 -0
- package/dist/schemas.js +3 -0
- package/dist/schemas.js.map +1 -0
- package/package.json +25 -16
package/dist/index.d.ts
CHANGED
|
@@ -1,295 +1,14 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { DbType, ReldbConfigInput, ReldbConfig } from './schemas.js';
|
|
2
|
+
export { MysqlConfig, MysqlConfigSchema, MysqlOptionsSchema, MysqlPoolConfig, MysqlPoolConfigSchema, MysqlSslConfigSchema, PoolConfig, PoolConfigSchema, PostgresqlConfig, PostgresqlConfigSchema, ReldbConfigSchema, ReldbOperationLogConfig, ReldbOperationLogConfigSchema, ReldbTypeSchema, SqliteConfig, SqliteConfigSchema, SqliteOptionsSchema, SslConfig, SslConfigSchema } from './schemas.js';
|
|
2
3
|
import * as _h_ai_core from '@h-ai/core';
|
|
3
4
|
import { HaiResult, PaginationOptionsInput, PaginatedResult, PaginationOptions } from '@h-ai/core';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* @h-ai/reldb — 数据库配置 Schema
|
|
7
|
-
*
|
|
8
|
-
* 本文件定义数据库模块的配置结构,使用 Zod 进行运行时校验。
|
|
9
|
-
* @module reldb-config
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* 数据库类型枚举
|
|
14
|
-
*
|
|
15
|
-
* 支持的数据库类型:
|
|
16
|
-
* - `sqlite` - SQLite 嵌入式数据库(使用 better-sqlite3)
|
|
17
|
-
* - `postgresql` - PostgreSQL 数据库(使用 pg)
|
|
18
|
-
* - `mysql` - MySQL 数据库(使用 mysql2)
|
|
19
|
-
*/
|
|
20
|
-
declare const ReldbTypeSchema: z.ZodEnum<{
|
|
21
|
-
sqlite: "sqlite";
|
|
22
|
-
postgresql: "postgresql";
|
|
23
|
-
mysql: "mysql";
|
|
24
|
-
}>;
|
|
25
|
-
/** 数据库类型 */
|
|
26
|
-
type DbType = z.infer<typeof ReldbTypeSchema>;
|
|
27
|
-
/**
|
|
28
|
-
* 连接池配置 Schema
|
|
29
|
-
*
|
|
30
|
-
* 用于 PostgreSQL 和 MySQL 的连接池管理。
|
|
31
|
-
* SQLite 为嵌入式数据库,不使用连接池。
|
|
32
|
-
*
|
|
33
|
-
* @example
|
|
34
|
-
* ```ts
|
|
35
|
-
* const poolConfig = {
|
|
36
|
-
* min: 2,
|
|
37
|
-
* max: 20,
|
|
38
|
-
* idleTimeout: 30000,
|
|
39
|
-
* acquireTimeout: 10000
|
|
40
|
-
* }
|
|
41
|
-
* ```
|
|
42
|
-
*/
|
|
43
|
-
declare const PoolConfigSchema: z.ZodObject<{
|
|
44
|
-
min: z.ZodDefault<z.ZodNumber>;
|
|
45
|
-
max: z.ZodDefault<z.ZodNumber>;
|
|
46
|
-
idleTimeout: z.ZodDefault<z.ZodNumber>;
|
|
47
|
-
acquireTimeout: z.ZodDefault<z.ZodNumber>;
|
|
48
|
-
}, z.core.$strip>;
|
|
49
|
-
/** 连接池配置类型 */
|
|
50
|
-
type PoolConfig = z.infer<typeof PoolConfigSchema>;
|
|
51
|
-
/**
|
|
52
|
-
* SSL 配置 Schema
|
|
53
|
-
*
|
|
54
|
-
* 支持多种配置方式:
|
|
55
|
-
* - `true/false` - 简单开关
|
|
56
|
-
* - `'require'/'prefer'/'allow'/'disable'` - SSL 模式
|
|
57
|
-
* - 自定义对象 - 详细 SSL 配置
|
|
58
|
-
*
|
|
59
|
-
* @example
|
|
60
|
-
* ```ts
|
|
61
|
-
* // 简单开关
|
|
62
|
-
* ssl: true
|
|
63
|
-
*
|
|
64
|
-
* // SSL 模式
|
|
65
|
-
* ssl: 'require'
|
|
66
|
-
*
|
|
67
|
-
* // 自定义配置
|
|
68
|
-
* ssl: { rejectUnauthorized: false }
|
|
69
|
-
* ```
|
|
70
|
-
*/
|
|
71
|
-
declare const SslConfigSchema: z.ZodUnion<readonly [z.ZodBoolean, z.ZodEnum<{
|
|
72
|
-
require: "require";
|
|
73
|
-
prefer: "prefer";
|
|
74
|
-
allow: "allow";
|
|
75
|
-
disable: "disable";
|
|
76
|
-
}>, z.ZodRecord<z.ZodString, z.ZodUnknown>]>;
|
|
77
|
-
/** SSL 配置类型 */
|
|
78
|
-
type SslConfig = z.infer<typeof SslConfigSchema>;
|
|
79
|
-
/**
|
|
80
|
-
* SQLite 特定选项 Schema
|
|
81
|
-
*
|
|
82
|
-
* @example
|
|
83
|
-
* ```ts
|
|
84
|
-
* sqlite: {
|
|
85
|
-
* walMode: true, // 启用 WAL 模式,提高并发性能
|
|
86
|
-
* readonly: false // 只读模式
|
|
87
|
-
* }
|
|
88
|
-
* ```
|
|
89
|
-
*/
|
|
90
|
-
declare const SqliteOptionsSchema: z.ZodObject<{
|
|
91
|
-
walMode: z.ZodDefault<z.ZodBoolean>;
|
|
92
|
-
readonly: z.ZodDefault<z.ZodBoolean>;
|
|
93
|
-
}, z.core.$strip>;
|
|
94
|
-
/**
|
|
95
|
-
* MySQL 特定选项 Schema
|
|
96
|
-
*
|
|
97
|
-
* @example
|
|
98
|
-
* ```ts
|
|
99
|
-
* mysql: {
|
|
100
|
-
* charset: 'utf8mb4',
|
|
101
|
-
* timezone: '+08:00'
|
|
102
|
-
* }
|
|
103
|
-
* ```
|
|
104
|
-
*/
|
|
105
|
-
declare const MysqlOptionsSchema: z.ZodObject<{
|
|
106
|
-
charset: z.ZodDefault<z.ZodString>;
|
|
107
|
-
timezone: z.ZodOptional<z.ZodString>;
|
|
108
|
-
}, z.core.$strip>;
|
|
109
|
-
/**
|
|
110
|
-
* SQLite 配置 Schema
|
|
111
|
-
*
|
|
112
|
-
* @example
|
|
113
|
-
* ```ts
|
|
114
|
-
* // 文件数据库
|
|
115
|
-
* { type: 'sqlite', database: './data.db' }
|
|
116
|
-
*
|
|
117
|
-
* // 内存数据库(用于测试)
|
|
118
|
-
* { type: 'sqlite', database: ':memory:' }
|
|
119
|
-
* ```
|
|
120
|
-
*/
|
|
121
|
-
declare const SqliteConfigSchema: z.ZodObject<{
|
|
122
|
-
type: z.ZodLiteral<"sqlite">;
|
|
123
|
-
database: z.ZodString;
|
|
124
|
-
sqlite: z.ZodOptional<z.ZodObject<{
|
|
125
|
-
walMode: z.ZodDefault<z.ZodBoolean>;
|
|
126
|
-
readonly: z.ZodDefault<z.ZodBoolean>;
|
|
127
|
-
}, z.core.$strip>>;
|
|
128
|
-
}, z.core.$strip>;
|
|
129
|
-
/**
|
|
130
|
-
* PostgreSQL 配置 Schema
|
|
131
|
-
*
|
|
132
|
-
* @example
|
|
133
|
-
* ```ts
|
|
134
|
-
* // 使用连接字符串
|
|
135
|
-
* { type: 'postgresql', url: 'postgres://user:pass@localhost:5432/mydb' }
|
|
136
|
-
*
|
|
137
|
-
* // 使用分开的字段
|
|
138
|
-
* {
|
|
139
|
-
* type: 'postgresql',
|
|
140
|
-
* host: 'localhost',
|
|
141
|
-
* port: 5432,
|
|
142
|
-
* database: 'mydb',
|
|
143
|
-
* user: 'admin',
|
|
144
|
-
* password: 'secret',
|
|
145
|
-
* pool: { max: 20 }
|
|
146
|
-
* }
|
|
147
|
-
* ```
|
|
148
|
-
*/
|
|
149
|
-
declare const PostgresqlConfigSchema: z.ZodObject<{
|
|
150
|
-
url: z.ZodOptional<z.ZodString>;
|
|
151
|
-
host: z.ZodDefault<z.ZodString>;
|
|
152
|
-
port: z.ZodOptional<z.ZodNumber>;
|
|
153
|
-
database: z.ZodString;
|
|
154
|
-
user: z.ZodOptional<z.ZodString>;
|
|
155
|
-
password: z.ZodOptional<z.ZodString>;
|
|
156
|
-
ssl: z.ZodOptional<z.ZodUnion<readonly [z.ZodBoolean, z.ZodEnum<{
|
|
157
|
-
require: "require";
|
|
158
|
-
prefer: "prefer";
|
|
159
|
-
allow: "allow";
|
|
160
|
-
disable: "disable";
|
|
161
|
-
}>, z.ZodRecord<z.ZodString, z.ZodUnknown>]>>;
|
|
162
|
-
pool: z.ZodOptional<z.ZodObject<{
|
|
163
|
-
min: z.ZodDefault<z.ZodNumber>;
|
|
164
|
-
max: z.ZodDefault<z.ZodNumber>;
|
|
165
|
-
idleTimeout: z.ZodDefault<z.ZodNumber>;
|
|
166
|
-
acquireTimeout: z.ZodDefault<z.ZodNumber>;
|
|
167
|
-
}, z.core.$strip>>;
|
|
168
|
-
type: z.ZodLiteral<"postgresql">;
|
|
169
|
-
}, z.core.$strip>;
|
|
170
|
-
/**
|
|
171
|
-
* MySQL 配置 Schema
|
|
172
|
-
*
|
|
173
|
-
* @example
|
|
174
|
-
* ```ts
|
|
175
|
-
* // 使用连接字符串
|
|
176
|
-
* { type: 'mysql', url: 'mysql://user:pass@localhost:3306/mydb' }
|
|
177
|
-
*
|
|
178
|
-
* // 使用分开的字段
|
|
179
|
-
* {
|
|
180
|
-
* type: 'mysql',
|
|
181
|
-
* host: 'localhost',
|
|
182
|
-
* port: 3306,
|
|
183
|
-
* database: 'mydb',
|
|
184
|
-
* user: 'admin',
|
|
185
|
-
* password: 'secret',
|
|
186
|
-
* mysql: { charset: 'utf8mb4' }
|
|
187
|
-
* }
|
|
188
|
-
* ```
|
|
189
|
-
*/
|
|
190
|
-
declare const MysqlConfigSchema: z.ZodObject<{
|
|
191
|
-
url: z.ZodOptional<z.ZodString>;
|
|
192
|
-
host: z.ZodDefault<z.ZodString>;
|
|
193
|
-
port: z.ZodOptional<z.ZodNumber>;
|
|
194
|
-
database: z.ZodString;
|
|
195
|
-
user: z.ZodOptional<z.ZodString>;
|
|
196
|
-
password: z.ZodOptional<z.ZodString>;
|
|
197
|
-
ssl: z.ZodOptional<z.ZodUnion<readonly [z.ZodBoolean, z.ZodEnum<{
|
|
198
|
-
require: "require";
|
|
199
|
-
prefer: "prefer";
|
|
200
|
-
allow: "allow";
|
|
201
|
-
disable: "disable";
|
|
202
|
-
}>, z.ZodRecord<z.ZodString, z.ZodUnknown>]>>;
|
|
203
|
-
pool: z.ZodOptional<z.ZodObject<{
|
|
204
|
-
min: z.ZodDefault<z.ZodNumber>;
|
|
205
|
-
max: z.ZodDefault<z.ZodNumber>;
|
|
206
|
-
idleTimeout: z.ZodDefault<z.ZodNumber>;
|
|
207
|
-
acquireTimeout: z.ZodDefault<z.ZodNumber>;
|
|
208
|
-
}, z.core.$strip>>;
|
|
209
|
-
type: z.ZodLiteral<"mysql">;
|
|
210
|
-
mysql: z.ZodOptional<z.ZodObject<{
|
|
211
|
-
charset: z.ZodDefault<z.ZodString>;
|
|
212
|
-
timezone: z.ZodOptional<z.ZodString>;
|
|
213
|
-
}, z.core.$strip>>;
|
|
214
|
-
}, z.core.$strip>;
|
|
215
|
-
/**
|
|
216
|
-
* 统一数据库配置 Schema(判别联合体)
|
|
217
|
-
*
|
|
218
|
-
* 根据 `type` 字段区分不同数据库类型的配置。
|
|
219
|
-
*/
|
|
220
|
-
declare const ReldbConfigSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
221
|
-
type: z.ZodLiteral<"sqlite">;
|
|
222
|
-
database: z.ZodString;
|
|
223
|
-
sqlite: z.ZodOptional<z.ZodObject<{
|
|
224
|
-
walMode: z.ZodDefault<z.ZodBoolean>;
|
|
225
|
-
readonly: z.ZodDefault<z.ZodBoolean>;
|
|
226
|
-
}, z.core.$strip>>;
|
|
227
|
-
}, z.core.$strip>, z.ZodObject<{
|
|
228
|
-
url: z.ZodOptional<z.ZodString>;
|
|
229
|
-
host: z.ZodDefault<z.ZodString>;
|
|
230
|
-
port: z.ZodOptional<z.ZodNumber>;
|
|
231
|
-
database: z.ZodString;
|
|
232
|
-
user: z.ZodOptional<z.ZodString>;
|
|
233
|
-
password: z.ZodOptional<z.ZodString>;
|
|
234
|
-
ssl: z.ZodOptional<z.ZodUnion<readonly [z.ZodBoolean, z.ZodEnum<{
|
|
235
|
-
require: "require";
|
|
236
|
-
prefer: "prefer";
|
|
237
|
-
allow: "allow";
|
|
238
|
-
disable: "disable";
|
|
239
|
-
}>, z.ZodRecord<z.ZodString, z.ZodUnknown>]>>;
|
|
240
|
-
pool: z.ZodOptional<z.ZodObject<{
|
|
241
|
-
min: z.ZodDefault<z.ZodNumber>;
|
|
242
|
-
max: z.ZodDefault<z.ZodNumber>;
|
|
243
|
-
idleTimeout: z.ZodDefault<z.ZodNumber>;
|
|
244
|
-
acquireTimeout: z.ZodDefault<z.ZodNumber>;
|
|
245
|
-
}, z.core.$strip>>;
|
|
246
|
-
type: z.ZodLiteral<"postgresql">;
|
|
247
|
-
}, z.core.$strip>, z.ZodObject<{
|
|
248
|
-
url: z.ZodOptional<z.ZodString>;
|
|
249
|
-
host: z.ZodDefault<z.ZodString>;
|
|
250
|
-
port: z.ZodOptional<z.ZodNumber>;
|
|
251
|
-
database: z.ZodString;
|
|
252
|
-
user: z.ZodOptional<z.ZodString>;
|
|
253
|
-
password: z.ZodOptional<z.ZodString>;
|
|
254
|
-
ssl: z.ZodOptional<z.ZodUnion<readonly [z.ZodBoolean, z.ZodEnum<{
|
|
255
|
-
require: "require";
|
|
256
|
-
prefer: "prefer";
|
|
257
|
-
allow: "allow";
|
|
258
|
-
disable: "disable";
|
|
259
|
-
}>, z.ZodRecord<z.ZodString, z.ZodUnknown>]>>;
|
|
260
|
-
pool: z.ZodOptional<z.ZodObject<{
|
|
261
|
-
min: z.ZodDefault<z.ZodNumber>;
|
|
262
|
-
max: z.ZodDefault<z.ZodNumber>;
|
|
263
|
-
idleTimeout: z.ZodDefault<z.ZodNumber>;
|
|
264
|
-
acquireTimeout: z.ZodDefault<z.ZodNumber>;
|
|
265
|
-
}, z.core.$strip>>;
|
|
266
|
-
type: z.ZodLiteral<"mysql">;
|
|
267
|
-
mysql: z.ZodOptional<z.ZodObject<{
|
|
268
|
-
charset: z.ZodDefault<z.ZodString>;
|
|
269
|
-
timezone: z.ZodOptional<z.ZodString>;
|
|
270
|
-
}, z.core.$strip>>;
|
|
271
|
-
}, z.core.$strip>], "type">;
|
|
272
|
-
/** 数据库配置类型(判别联合体) */
|
|
273
|
-
type ReldbConfig = z.infer<typeof ReldbConfigSchema>;
|
|
274
|
-
/** SQLite 配置类型 */
|
|
275
|
-
type SqliteConfig = z.infer<typeof SqliteConfigSchema>;
|
|
276
|
-
/** PostgreSQL 配置类型 */
|
|
277
|
-
type PostgresqlConfig = z.infer<typeof PostgresqlConfigSchema>;
|
|
278
|
-
/** MySQL 配置类型 */
|
|
279
|
-
type MysqlConfig = z.infer<typeof MysqlConfigSchema>;
|
|
280
|
-
/**
|
|
281
|
-
* 数据库配置输入类型(用于 init 等入口)
|
|
282
|
-
*
|
|
283
|
-
* 说明:Zod 的 default 会让输入端字段可省略,但输出端字段为必填。
|
|
284
|
-
* 因此对外 API(如 reldb.init)更适合接收 ReldbConfigInput。
|
|
285
|
-
*/
|
|
286
|
-
type ReldbConfigInput = z.input<typeof ReldbConfigSchema>;
|
|
5
|
+
import 'zod';
|
|
287
6
|
|
|
288
7
|
/**
|
|
289
8
|
* @h-ai/reldb — JSON 操作 SQL 构建器
|
|
290
9
|
*
|
|
291
10
|
* 为不同数据库后端提供统一的 JSON 路径操作 SQL 表达式构建能力。
|
|
292
|
-
*
|
|
11
|
+
* 路径支持简单点号与方括号路径(`$.key` / `$.key.subkey` / `$[0]`),不是完整 SQL/JSON Path 校验器。
|
|
293
12
|
*
|
|
294
13
|
* 各数据库后端映射:
|
|
295
14
|
*
|
|
@@ -299,7 +18,7 @@ type ReldbConfigInput = z.input<typeof ReldbConfigSchema>;
|
|
|
299
18
|
* | set | json_set + json() | jsonb_set + ::jsonb | JSON_SET + CAST AS JSON |
|
|
300
19
|
* | insert | json_insert + json() | jsonb_insert + ::jsonb | JSON_INSERT + CAST AS JSON |
|
|
301
20
|
* | remove | json_remove | #- (text[]) | JSON_REMOVE |
|
|
302
|
-
* | merge | json_patch |
|
|
21
|
+
* | merge | json_patch | 参数化递归 CTE | JSON_MERGE_PATCH + CAST |
|
|
303
22
|
*
|
|
304
23
|
* @module reldb-json
|
|
305
24
|
*/
|
|
@@ -308,15 +27,12 @@ type ReldbConfigInput = z.input<typeof ReldbConfigSchema>;
|
|
|
308
27
|
*
|
|
309
28
|
* 包含可嵌入 SQL 语句的表达式片段与对应参数列表。
|
|
310
29
|
* 参数占位符统一使用 `?`,各 Provider 会在执行前自动转换。
|
|
311
|
-
*
|
|
312
30
|
* @example
|
|
313
31
|
* ```ts
|
|
314
|
-
*
|
|
315
|
-
*
|
|
316
|
-
*
|
|
317
|
-
*
|
|
318
|
-
* [...params, userId],
|
|
319
|
-
* )
|
|
32
|
+
* import { createJsonOps, type JsonSqlExpr } from '@h-ai/reldb'
|
|
33
|
+
*
|
|
34
|
+
* const expression: JsonSqlExpr = createJsonOps('postgresql').set('settings', '$.theme', 'dark')
|
|
35
|
+
* void [expression.sql, expression.params]
|
|
320
36
|
* ```
|
|
321
37
|
*/
|
|
322
38
|
interface JsonSqlExpr {
|
|
@@ -331,25 +47,16 @@ interface JsonSqlExpr {
|
|
|
331
47
|
* 提供跨数据库统一的 JSON 路径操作 SQL 构建能力。
|
|
332
48
|
* 所有方法返回 `JsonSqlExpr`,可嵌入 `reldb.sql.query` / `reldb.sql.execute` 等调用。
|
|
333
49
|
*
|
|
334
|
-
*
|
|
50
|
+
* 路径使用以下简单形式,建议以 `$` 开头:
|
|
335
51
|
* - 对象字段:`$.key`、`$.key.subkey`
|
|
336
52
|
* - 数组元素:`$[0]`、`$.items[1]`
|
|
337
|
-
*
|
|
338
53
|
* @example
|
|
339
54
|
* ```ts
|
|
340
|
-
*
|
|
341
|
-
*
|
|
342
|
-
* const
|
|
343
|
-
*
|
|
344
|
-
*
|
|
345
|
-
* )
|
|
346
|
-
*
|
|
347
|
-
* // 设置 JSON 字段的某个路径(用于 UPDATE SET)
|
|
348
|
-
* const { sql, params } = reldb.json.set('settings', '$.theme', 'dark')
|
|
349
|
-
* await reldb.sql.execute(
|
|
350
|
-
* `UPDATE users SET settings = ${sql} WHERE id = ?`,
|
|
351
|
-
* [...params, userId],
|
|
352
|
-
* )
|
|
55
|
+
* import { createJsonOps, type ReldbJsonOps } from '@h-ai/reldb'
|
|
56
|
+
*
|
|
57
|
+
* const json: ReldbJsonOps = createJsonOps('postgresql')
|
|
58
|
+
* const patch = json.merge('settings', { theme: 'dark', obsolete: null })
|
|
59
|
+
* void patch // 作为同一次 UPDATE 的 SQL 表达式执行,值在 params。
|
|
353
60
|
* ```
|
|
354
61
|
*/
|
|
355
62
|
interface ReldbJsonOps {
|
|
@@ -362,55 +69,52 @@ interface ReldbJsonOps {
|
|
|
362
69
|
* @param column - 列名(或 SQL 列表达式,开发者负责安全性,禁止传入用户输入)
|
|
363
70
|
* @param path - JSON 路径(如 `$.status`、`$.user.name`、`$[0]`)
|
|
364
71
|
* @returns SQL 表达式与参数
|
|
365
|
-
*
|
|
366
72
|
* @example
|
|
367
73
|
* ```ts
|
|
368
|
-
*
|
|
369
|
-
*
|
|
370
|
-
*
|
|
371
|
-
*
|
|
74
|
+
* import { reldb } from '@h-ai/reldb'
|
|
75
|
+
*
|
|
76
|
+
* const expression = reldb.json.extract('settings', '$.theme')
|
|
77
|
+
* void [expression.sql, expression.params]
|
|
372
78
|
* ```
|
|
373
79
|
*/
|
|
374
80
|
extract: (column: string, path: string) => JsonSqlExpr;
|
|
375
81
|
/**
|
|
376
82
|
* JSON 路径设置表达式(创建或替换)
|
|
377
83
|
*
|
|
378
|
-
*
|
|
84
|
+
* 设置指定路径的值;PostgreSQL 要求父路径存在,其他后端按原生 JSON 函数处理缺失父路径。
|
|
379
85
|
* 返回修改后的完整 JSON 值,通常用于 `UPDATE SET col = ...`。
|
|
380
86
|
*
|
|
381
87
|
* @param column - 列名(开发者负责安全性,禁止传入用户输入)
|
|
382
88
|
* @param path - JSON 路径
|
|
383
89
|
* @param value - 要设置的值(支持任意 JSON 兼容类型)
|
|
384
90
|
* @returns SQL 表达式与参数
|
|
385
|
-
*
|
|
386
91
|
* @example
|
|
387
92
|
* ```ts
|
|
388
|
-
*
|
|
389
|
-
*
|
|
390
|
-
*
|
|
391
|
-
*
|
|
392
|
-
* )
|
|
93
|
+
* import { reldb } from '@h-ai/reldb'
|
|
94
|
+
*
|
|
95
|
+
* const expression = reldb.json.set('settings', '$.theme', 'dark')
|
|
96
|
+
* const result = await reldb.sql.execute(`UPDATE users SET settings = ${expression.sql} WHERE id = ?`, [...expression.params, 'u1'])
|
|
97
|
+
* if (!result.success) throw new Error(result.error.message)
|
|
393
98
|
* ```
|
|
394
99
|
*/
|
|
395
100
|
set: (column: string, path: string, value: unknown) => JsonSqlExpr;
|
|
396
101
|
/**
|
|
397
102
|
* JSON 路径插入表达式(仅当路径不存在时)
|
|
398
103
|
*
|
|
399
|
-
*
|
|
104
|
+
* 使用后端原生插入语义:SQLite/MySQL 不覆盖已有值;PostgreSQL 对已有对象键报错,数组路径按 jsonb_insert 插入。
|
|
400
105
|
* 返回修改后的完整 JSON 值。
|
|
401
106
|
*
|
|
402
107
|
* @param column - 列名(开发者负责安全性,禁止传入用户输入)
|
|
403
108
|
* @param path - JSON 路径
|
|
404
109
|
* @param value - 要插入的值
|
|
405
110
|
* @returns SQL 表达式与参数
|
|
406
|
-
*
|
|
407
111
|
* @example
|
|
408
112
|
* ```ts
|
|
409
|
-
*
|
|
410
|
-
*
|
|
411
|
-
*
|
|
412
|
-
*
|
|
413
|
-
* )
|
|
113
|
+
* import { reldb } from '@h-ai/reldb'
|
|
114
|
+
*
|
|
115
|
+
* const expression = reldb.json.insert('settings', '$.newField', 'value')
|
|
116
|
+
* const result = await reldb.sql.execute(`UPDATE users SET settings = ${expression.sql} WHERE id = ?`, [...expression.params, 'u1'])
|
|
117
|
+
* if (!result.success) throw new Error(result.error.message)
|
|
414
118
|
* ```
|
|
415
119
|
*/
|
|
416
120
|
insert: (column: string, path: string, value: unknown) => JsonSqlExpr;
|
|
@@ -423,14 +127,13 @@ interface ReldbJsonOps {
|
|
|
423
127
|
* @param column - 列名(开发者负责安全性,禁止传入用户输入)
|
|
424
128
|
* @param path - JSON 路径
|
|
425
129
|
* @returns SQL 表达式与参数
|
|
426
|
-
*
|
|
427
130
|
* @example
|
|
428
131
|
* ```ts
|
|
429
|
-
*
|
|
430
|
-
*
|
|
431
|
-
*
|
|
432
|
-
*
|
|
433
|
-
* )
|
|
132
|
+
* import { reldb } from '@h-ai/reldb'
|
|
133
|
+
*
|
|
134
|
+
* const expression = reldb.json.remove('settings', '$.obsolete')
|
|
135
|
+
* const result = await reldb.sql.execute(`UPDATE users SET settings = ${expression.sql} WHERE id = ?`, [...expression.params, 'u1'])
|
|
136
|
+
* if (!result.success) throw new Error(result.error.message)
|
|
434
137
|
* ```
|
|
435
138
|
*/
|
|
436
139
|
remove: (column: string, path: string) => JsonSqlExpr;
|
|
@@ -447,14 +150,13 @@ interface ReldbJsonOps {
|
|
|
447
150
|
* @param column - 列名(开发者负责安全性,禁止传入用户输入)
|
|
448
151
|
* @param patch - 要合并的 JSON 对象
|
|
449
152
|
* @returns SQL 表达式与参数
|
|
450
|
-
*
|
|
451
153
|
* @example
|
|
452
154
|
* ```ts
|
|
453
|
-
*
|
|
454
|
-
*
|
|
455
|
-
*
|
|
456
|
-
*
|
|
457
|
-
* )
|
|
155
|
+
* import { reldb } from '@h-ai/reldb'
|
|
156
|
+
*
|
|
157
|
+
* const expression = reldb.json.merge('settings', { theme: 'dark', obsolete: null })
|
|
158
|
+
* const result = await reldb.sql.execute(`UPDATE users SET settings = ${expression.sql} WHERE id = ?`, [...expression.params, 'u1'])
|
|
159
|
+
* if (!result.success) throw new Error(result.error.message)
|
|
458
160
|
* ```
|
|
459
161
|
*/
|
|
460
162
|
merge: (column: string, patch: Record<string, unknown>) => JsonSqlExpr;
|
|
@@ -466,12 +168,11 @@ interface ReldbJsonOps {
|
|
|
466
168
|
*
|
|
467
169
|
* @param path - JSON 路径(以 `$` 开头)
|
|
468
170
|
* @returns 路径段数组
|
|
469
|
-
*
|
|
470
171
|
* @example
|
|
471
172
|
* ```ts
|
|
472
|
-
* parseJsonPath
|
|
473
|
-
*
|
|
474
|
-
* parseJsonPath('
|
|
173
|
+
* import { parseJsonPath } from '@h-ai/reldb'
|
|
174
|
+
*
|
|
175
|
+
* void parseJsonPath('$.items[0].name') // ['items', '0', 'name']
|
|
475
176
|
* ```
|
|
476
177
|
*/
|
|
477
178
|
declare function parseJsonPath(path: string): string[];
|
|
@@ -480,19 +181,28 @@ declare function parseJsonPath(path: string): string[];
|
|
|
480
181
|
*
|
|
481
182
|
* @param dbType - 数据库类型(来自 `reldb.config?.type`)
|
|
482
183
|
* @returns JSON 操作实例
|
|
483
|
-
*
|
|
484
184
|
* @example
|
|
485
185
|
* ```ts
|
|
486
|
-
*
|
|
487
|
-
* const { sql, params } = reldb.json.extract('data', '$.key')
|
|
186
|
+
* import { createJsonOps } from '@h-ai/reldb'
|
|
488
187
|
*
|
|
489
|
-
*
|
|
490
|
-
* const
|
|
491
|
-
*
|
|
188
|
+
* const sqlite = createJsonOps('sqlite')
|
|
189
|
+
* const expression = sqlite.extract('settings', '$.theme')
|
|
190
|
+
* void expression
|
|
492
191
|
* ```
|
|
493
192
|
*/
|
|
494
193
|
declare function createJsonOps(dbType: 'sqlite' | 'postgresql' | 'mysql'): ReldbJsonOps;
|
|
495
194
|
|
|
195
|
+
/**
|
|
196
|
+
* HaiReldbError 的数据约束与操作契约。
|
|
197
|
+
* @example
|
|
198
|
+
* ```ts
|
|
199
|
+
* import { HaiReldbError } from '@h-ai/reldb'
|
|
200
|
+
* import { err } from '@h-ai/core'
|
|
201
|
+
*
|
|
202
|
+
* const result = err(HaiReldbError.QUERY_FAILED, 'Query failed')
|
|
203
|
+
* if (!result.success) void result.error.code
|
|
204
|
+
* ```
|
|
205
|
+
*/
|
|
496
206
|
declare const HaiReldbError: {
|
|
497
207
|
CONNECTION_FAILED: _h_ai_core.HaiErrorDef;
|
|
498
208
|
QUERY_FAILED: _h_ai_core.HaiErrorDef;
|
|
@@ -517,7 +227,8 @@ declare const HaiReldbError: {
|
|
|
517
227
|
* | 类型 | SQLite | PostgreSQL | MySQL |
|
|
518
228
|
* |------------|---------|------------------|--------------|
|
|
519
229
|
* | TEXT | TEXT | TEXT | VARCHAR(255) |
|
|
520
|
-
* | INTEGER | INTEGER | INTEGER/
|
|
230
|
+
* | INTEGER | INTEGER | INTEGER/BIGSERIAL | INT/BIGINT |
|
|
231
|
+
* | BIGINT | INTEGER | BIGINT | BIGINT |
|
|
521
232
|
* | REAL | REAL | DOUBLE PRECISION | DOUBLE |
|
|
522
233
|
* | BLOB | BLOB | BYTEA | BLOB |
|
|
523
234
|
* | BOOLEAN | INTEGER | BOOLEAN | TINYINT(1) |
|
|
@@ -525,33 +236,28 @@ declare const HaiReldbError: {
|
|
|
525
236
|
* | JSON | TEXT | JSONB | JSON |
|
|
526
237
|
*
|
|
527
238
|
* 注:MySQL 将 TEXT 映射为 VARCHAR(255) 以支持索引和 UNIQUE 约束。
|
|
528
|
-
* INTEGER 在 MySQL autoIncrement 时映射为 BIGINT
|
|
239
|
+
* INTEGER 在 MySQL autoIncrement 时映射为 BIGINT,在 PostgreSQL 映射为 BIGSERIAL,否则为 32 位 INT/INTEGER。
|
|
240
|
+
* Unix 毫秒应声明为 BIGINT;原始 SQL/CRUD 的 BIGINT 返回形态取决于驱动,可能为 number/string/bigint。
|
|
241
|
+
* 使用 number 的业务仓库须校验 Number.isSafeInteger,超出范围不能直接强转而丢失精度。
|
|
242
|
+
* @example
|
|
243
|
+
* ```ts
|
|
244
|
+
* import type { ColumnType } from '@h-ai/reldb'
|
|
245
|
+
*
|
|
246
|
+
* const value: ColumnType = 'TEXT'
|
|
247
|
+
* void value
|
|
248
|
+
* ```
|
|
529
249
|
*/
|
|
530
|
-
type ColumnType = 'TEXT' | 'INTEGER' | 'REAL' | 'BLOB' | 'BOOLEAN' | 'TIMESTAMP' | 'JSON';
|
|
250
|
+
type ColumnType = 'TEXT' | 'INTEGER' | 'BIGINT' | 'REAL' | 'BLOB' | 'BOOLEAN' | 'TIMESTAMP' | 'JSON';
|
|
531
251
|
/**
|
|
532
252
|
* 列定义接口
|
|
533
253
|
*
|
|
534
254
|
* 用于定义表的列结构。
|
|
535
|
-
*
|
|
536
255
|
* @example
|
|
537
256
|
* ```ts
|
|
538
|
-
*
|
|
539
|
-
* const idColumn: ReldbColumnDef = {
|
|
540
|
-
* type: 'INTEGER',
|
|
541
|
-
* primaryKey: true,
|
|
542
|
-
* autoIncrement: true
|
|
543
|
-
* }
|
|
257
|
+
* import type { ReldbColumnDef } from '@h-ai/reldb'
|
|
544
258
|
*
|
|
545
|
-
*
|
|
546
|
-
*
|
|
547
|
-
* type: 'INTEGER',
|
|
548
|
-
* notNull: true,
|
|
549
|
-
* references: {
|
|
550
|
-
* table: 'users',
|
|
551
|
-
* column: 'id',
|
|
552
|
-
* onDelete: 'CASCADE'
|
|
553
|
-
* }
|
|
554
|
-
* }
|
|
259
|
+
* const value: ReldbColumnDef = { type: 'INTEGER', primaryKey: true, autoIncrement: true }
|
|
260
|
+
* void value
|
|
555
261
|
* ```
|
|
556
262
|
*/
|
|
557
263
|
interface ReldbColumnDef {
|
|
@@ -581,15 +287,12 @@ interface ReldbColumnDef {
|
|
|
581
287
|
}
|
|
582
288
|
/**
|
|
583
289
|
* 表定义(列名到列定义的映射)
|
|
584
|
-
*
|
|
585
290
|
* @example
|
|
586
291
|
* ```ts
|
|
587
|
-
*
|
|
588
|
-
*
|
|
589
|
-
*
|
|
590
|
-
*
|
|
591
|
-
* created_at: { type: 'TIMESTAMP', defaultValue: 'NOW()' }
|
|
592
|
-
* }
|
|
292
|
+
* import type { ReldbTableDef } from '@h-ai/reldb'
|
|
293
|
+
*
|
|
294
|
+
* const value: ReldbTableDef = { id: { type: 'TEXT', primaryKey: true }, name: { type: 'TEXT', notNull: true } }
|
|
295
|
+
* void value
|
|
593
296
|
* ```
|
|
594
297
|
*/
|
|
595
298
|
interface ReldbTableDef {
|
|
@@ -597,23 +300,12 @@ interface ReldbTableDef {
|
|
|
597
300
|
}
|
|
598
301
|
/**
|
|
599
302
|
* 索引定义
|
|
600
|
-
*
|
|
601
303
|
* @example
|
|
602
304
|
* ```ts
|
|
603
|
-
*
|
|
604
|
-
* const emailIndex: ReldbIndexDef = { columns: ['email'] }
|
|
305
|
+
* import type { ReldbIndexDef } from '@h-ai/reldb'
|
|
605
306
|
*
|
|
606
|
-
*
|
|
607
|
-
*
|
|
608
|
-
* columns: ['user_id', 'created_at'],
|
|
609
|
-
* unique: true
|
|
610
|
-
* }
|
|
611
|
-
*
|
|
612
|
-
* // 部分索引(带条件)
|
|
613
|
-
* const partialIndex: ReldbIndexDef = {
|
|
614
|
-
* columns: ['status'],
|
|
615
|
-
* where: "status = 'active'"
|
|
616
|
-
* }
|
|
307
|
+
* const value: ReldbIndexDef = { columns: ['email'], unique: true }
|
|
308
|
+
* void value
|
|
617
309
|
* ```
|
|
618
310
|
*/
|
|
619
311
|
interface ReldbIndexDef {
|
|
@@ -626,6 +318,13 @@ interface ReldbIndexDef {
|
|
|
626
318
|
*
|
|
627
319
|
* **⚠️ 安全警告:** `where` 为原始 SQL 片段,不会经过参数化处理,
|
|
628
320
|
* **禁止**将用户输入直接拼接。仅用于开发者编写的静态条件。
|
|
321
|
+
* @example
|
|
322
|
+
* ```ts
|
|
323
|
+
* import type { CrudQueryOptions } from '@h-ai/reldb'
|
|
324
|
+
*
|
|
325
|
+
* const options: CrudQueryOptions = { where: 'name = ?', params: ['Alice'] }
|
|
326
|
+
* void options // 值走绑定参数;SQL 结构由开发者静态编写。
|
|
327
|
+
* ```
|
|
629
328
|
*/
|
|
630
329
|
where?: string;
|
|
631
330
|
}
|
|
@@ -633,18 +332,15 @@ interface ReldbIndexDef {
|
|
|
633
332
|
* DDL(数据定义语言)操作接口
|
|
634
333
|
*
|
|
635
334
|
* 提供表结构管理功能,包括创建/删除表、添加/删除列、创建索引等。
|
|
636
|
-
*
|
|
637
|
-
*
|
|
335
|
+
* 结构修改返回 `HaiResult<void>`;hasTable 返回 `HaiResult<boolean>`,以实际签名为准。
|
|
638
336
|
* @example
|
|
639
337
|
* ```ts
|
|
640
|
-
*
|
|
641
|
-
*
|
|
642
|
-
*
|
|
643
|
-
*
|
|
644
|
-
*
|
|
645
|
-
*
|
|
646
|
-
* if (!result.success) {
|
|
647
|
-
* // 处理错误:创建表失败(可根据 result.error.code / message 做兜底)
|
|
338
|
+
* import type { DdlOperations } from '@h-ai/reldb'
|
|
339
|
+
*
|
|
340
|
+
* async function use(operations: DdlOperations) {
|
|
341
|
+
* const result = await operations.createTable('users', { id: { type: 'TEXT', primaryKey: true } })
|
|
342
|
+
* if (!result.success) throw new Error(result.error.message)
|
|
343
|
+
* void result.data
|
|
648
344
|
* }
|
|
649
345
|
* ```
|
|
650
346
|
*/
|
|
@@ -656,13 +352,11 @@ interface DdlOperations {
|
|
|
656
352
|
* @param ifNotExists - 是否使用 IF NOT EXISTS(默认 true)
|
|
657
353
|
* @example
|
|
658
354
|
* ```ts
|
|
659
|
-
*
|
|
660
|
-
*
|
|
661
|
-
*
|
|
662
|
-
*
|
|
663
|
-
*
|
|
664
|
-
* // 创建失败:根据 result.error.code / message 处理
|
|
665
|
-
* }
|
|
355
|
+
* import { reldb } from '@h-ai/reldb'
|
|
356
|
+
*
|
|
357
|
+
* const result = await reldb.ddl.createTable('users', { id: { type: 'TEXT', primaryKey: true }, name: { type: 'TEXT' } })
|
|
358
|
+
* if (!result.success) throw new Error(result.error.message)
|
|
359
|
+
* void result.data
|
|
666
360
|
* ```
|
|
667
361
|
*/
|
|
668
362
|
createTable: (tableName: string, columns: ReldbTableDef, ifNotExists?: boolean) => Promise<HaiResult<void>>;
|
|
@@ -672,8 +366,11 @@ interface DdlOperations {
|
|
|
672
366
|
* @param ifExists - 是否使用 IF EXISTS(默认 true)
|
|
673
367
|
* @example
|
|
674
368
|
* ```ts
|
|
675
|
-
*
|
|
676
|
-
*
|
|
369
|
+
* import { reldb } from '@h-ai/reldb'
|
|
370
|
+
*
|
|
371
|
+
* const result = await reldb.ddl.dropTable('users_backup')
|
|
372
|
+
* if (!result.success) throw new Error(result.error.message)
|
|
373
|
+
* void result.data
|
|
677
374
|
* ```
|
|
678
375
|
*/
|
|
679
376
|
dropTable: (tableName: string, ifExists?: boolean) => Promise<HaiResult<void>>;
|
|
@@ -684,8 +381,11 @@ interface DdlOperations {
|
|
|
684
381
|
* @param columnDef - 列定义
|
|
685
382
|
* @example
|
|
686
383
|
* ```ts
|
|
687
|
-
*
|
|
688
|
-
*
|
|
384
|
+
* import { reldb } from '@h-ai/reldb'
|
|
385
|
+
*
|
|
386
|
+
* const result = await reldb.ddl.addColumn('users', 'age', { type: 'INTEGER' })
|
|
387
|
+
* if (!result.success) throw new Error(result.error.message)
|
|
388
|
+
* void result.data
|
|
689
389
|
* ```
|
|
690
390
|
*/
|
|
691
391
|
addColumn: (tableName: string, columnName: string, columnDef: ReldbColumnDef) => Promise<HaiResult<void>>;
|
|
@@ -695,7 +395,11 @@ interface DdlOperations {
|
|
|
695
395
|
* @param columnName - 列名
|
|
696
396
|
* @example
|
|
697
397
|
* ```ts
|
|
698
|
-
*
|
|
398
|
+
* import { reldb } from '@h-ai/reldb'
|
|
399
|
+
*
|
|
400
|
+
* const result = await reldb.ddl.dropColumn('users', 'legacy_field')
|
|
401
|
+
* if (!result.success) throw new Error(result.error.message)
|
|
402
|
+
* void result.data
|
|
699
403
|
* ```
|
|
700
404
|
*/
|
|
701
405
|
dropColumn: (tableName: string, columnName: string) => Promise<HaiResult<void>>;
|
|
@@ -705,7 +409,11 @@ interface DdlOperations {
|
|
|
705
409
|
* @param newName - 新表名
|
|
706
410
|
* @example
|
|
707
411
|
* ```ts
|
|
708
|
-
*
|
|
412
|
+
* import { reldb } from '@h-ai/reldb'
|
|
413
|
+
*
|
|
414
|
+
* const result = await reldb.ddl.renameTable('users_old', 'users')
|
|
415
|
+
* if (!result.success) throw new Error(result.error.message)
|
|
416
|
+
* void result.data
|
|
709
417
|
* ```
|
|
710
418
|
*/
|
|
711
419
|
renameTable: (oldName: string, newName: string) => Promise<HaiResult<void>>;
|
|
@@ -716,10 +424,11 @@ interface DdlOperations {
|
|
|
716
424
|
* @param indexDef - 索引定义
|
|
717
425
|
* @example
|
|
718
426
|
* ```ts
|
|
719
|
-
*
|
|
720
|
-
*
|
|
721
|
-
*
|
|
722
|
-
*
|
|
427
|
+
* import { reldb } from '@h-ai/reldb'
|
|
428
|
+
*
|
|
429
|
+
* const result = await reldb.ddl.createIndex('users', 'users_name_idx', { columns: ['name'] })
|
|
430
|
+
* if (!result.success) throw new Error(result.error.message)
|
|
431
|
+
* void result.data
|
|
723
432
|
* ```
|
|
724
433
|
*/
|
|
725
434
|
createIndex: (tableName: string, indexName: string, indexDef: ReldbIndexDef) => Promise<HaiResult<void>>;
|
|
@@ -729,7 +438,11 @@ interface DdlOperations {
|
|
|
729
438
|
* @param ifExists - 是否使用 IF EXISTS(默认 true)
|
|
730
439
|
* @example
|
|
731
440
|
* ```ts
|
|
732
|
-
*
|
|
441
|
+
* import { reldb } from '@h-ai/reldb'
|
|
442
|
+
*
|
|
443
|
+
* const result = await reldb.ddl.dropIndex('users_name_idx')
|
|
444
|
+
* if (!result.success) throw new Error(result.error.message)
|
|
445
|
+
* void result.data
|
|
733
446
|
* ```
|
|
734
447
|
*/
|
|
735
448
|
dropIndex: (indexName: string, ifExists?: boolean) => Promise<HaiResult<void>>;
|
|
@@ -743,11 +456,11 @@ interface DdlOperations {
|
|
|
743
456
|
* @param sql - DDL SQL 语句(必须为开发者静态构造,禁止包含用户输入)
|
|
744
457
|
* @example
|
|
745
458
|
* ```ts
|
|
746
|
-
*
|
|
747
|
-
* await reldb.ddl.raw('ALTER TABLE users ADD COLUMN status TEXT')
|
|
459
|
+
* import { reldb } from '@h-ai/reldb'
|
|
748
460
|
*
|
|
749
|
-
*
|
|
750
|
-
*
|
|
461
|
+
* const result = await reldb.ddl.raw('ALTER TABLE users ADD COLUMN status TEXT')
|
|
462
|
+
* if (!result.success) throw new Error(result.error.message)
|
|
463
|
+
* void result.data
|
|
751
464
|
* ```
|
|
752
465
|
*/
|
|
753
466
|
raw: (sql: string) => Promise<HaiResult<void>>;
|
|
@@ -756,12 +469,26 @@ interface DdlOperations {
|
|
|
756
469
|
* 查询结果行类型
|
|
757
470
|
*
|
|
758
471
|
* 约定为键值对象,字段名与 SQL 返回列一致。
|
|
472
|
+
* @example
|
|
473
|
+
* ```ts
|
|
474
|
+
* import type { QueryRow } from '@h-ai/reldb'
|
|
475
|
+
*
|
|
476
|
+
* const value: QueryRow = { id: 'u1', name: 'Alice' }
|
|
477
|
+
* void value
|
|
478
|
+
* ```
|
|
759
479
|
*/
|
|
760
480
|
type QueryRow = Record<string, unknown>;
|
|
761
481
|
/**
|
|
762
482
|
* 执行结果
|
|
763
483
|
*
|
|
764
484
|
* INSERT/UPDATE/DELETE 操作返回的结果。
|
|
485
|
+
* @example
|
|
486
|
+
* ```ts
|
|
487
|
+
* import type { ExecuteResult } from '@h-ai/reldb'
|
|
488
|
+
*
|
|
489
|
+
* const value: ExecuteResult = { changes: 1 }
|
|
490
|
+
* void value
|
|
491
|
+
* ```
|
|
765
492
|
*/
|
|
766
493
|
interface ExecuteResult {
|
|
767
494
|
/** 影响的行数 */
|
|
@@ -771,6 +498,13 @@ interface ExecuteResult {
|
|
|
771
498
|
}
|
|
772
499
|
/**
|
|
773
500
|
* 规范化后的分页参数
|
|
501
|
+
* @example
|
|
502
|
+
* ```ts
|
|
503
|
+
* import type { NormalizedPagination } from '@h-ai/reldb'
|
|
504
|
+
*
|
|
505
|
+
* const value: NormalizedPagination = { page: 2, pageSize: 10, offset: 10, limit: 10 }
|
|
506
|
+
* void value
|
|
507
|
+
* ```
|
|
774
508
|
*/
|
|
775
509
|
interface NormalizedPagination extends PaginationOptions {
|
|
776
510
|
/** SQL offset */
|
|
@@ -780,6 +514,13 @@ interface NormalizedPagination extends PaginationOptions {
|
|
|
780
514
|
}
|
|
781
515
|
/**
|
|
782
516
|
* 分页参数覆盖
|
|
517
|
+
* @example
|
|
518
|
+
* ```ts
|
|
519
|
+
* import type { PaginationOverrides } from '@h-ai/reldb'
|
|
520
|
+
*
|
|
521
|
+
* const value: PaginationOverrides = { defaultPageSize: 20, maxPageSize: 100 }
|
|
522
|
+
* void value
|
|
523
|
+
* ```
|
|
783
524
|
*/
|
|
784
525
|
interface PaginationOverrides {
|
|
785
526
|
/** 默认页码 */
|
|
@@ -791,6 +532,13 @@ interface PaginationOverrides {
|
|
|
791
532
|
}
|
|
792
533
|
/**
|
|
793
534
|
* 分页查询参数
|
|
535
|
+
* @example
|
|
536
|
+
* ```ts
|
|
537
|
+
* import type { PaginationQueryOptions } from '@h-ai/reldb'
|
|
538
|
+
*
|
|
539
|
+
* const value: PaginationQueryOptions = { sql: 'SELECT id, name FROM users WHERE active = ?', params: [true], pagination: { page: 2, pageSize: 10 } }
|
|
540
|
+
* void value
|
|
541
|
+
* ```
|
|
794
542
|
*/
|
|
795
543
|
interface PaginationQueryOptions {
|
|
796
544
|
/** 数据查询 SQL(不含 LIMIT/OFFSET) */
|
|
@@ -804,37 +552,104 @@ interface PaginationQueryOptions {
|
|
|
804
552
|
}
|
|
805
553
|
/**
|
|
806
554
|
* 数据读写操作接口(SQL / 事务共享)
|
|
555
|
+
* @example
|
|
556
|
+
* ```ts
|
|
557
|
+
* import type { DmlOperations } from '@h-ai/reldb'
|
|
558
|
+
*
|
|
559
|
+
* async function use(operations: DmlOperations) {
|
|
560
|
+
* const result = await operations.query<{ id: string }>('SELECT id FROM users WHERE name = ?', ['Alice'])
|
|
561
|
+
* if (!result.success) throw new Error(result.error.message)
|
|
562
|
+
* return result.data
|
|
563
|
+
* }
|
|
564
|
+
* ```
|
|
807
565
|
*/
|
|
808
566
|
interface DmlOperations {
|
|
809
|
-
/**
|
|
567
|
+
/**
|
|
568
|
+
* 查询多行
|
|
569
|
+
* @example
|
|
570
|
+
* ```ts
|
|
571
|
+
* import { reldb } from '@h-ai/reldb'
|
|
572
|
+
*
|
|
573
|
+
* const result = await reldb.sql.query<{ id: string }>('SELECT id FROM users WHERE name = ?', ['Alice'])
|
|
574
|
+
* if (!result.success) throw new Error(result.error.message)
|
|
575
|
+
* void result.data
|
|
576
|
+
* ```
|
|
577
|
+
*/
|
|
810
578
|
query: <T = QueryRow>(sql: string, params?: unknown[]) => Promise<HaiResult<T[]>>;
|
|
811
|
-
/**
|
|
579
|
+
/**
|
|
580
|
+
* 查询单行
|
|
581
|
+
* @example
|
|
582
|
+
* ```ts
|
|
583
|
+
* import { reldb } from '@h-ai/reldb'
|
|
584
|
+
*
|
|
585
|
+
* const result = await reldb.sql.get<{ id: string }>('SELECT id FROM users WHERE name = ?', ['Alice'])
|
|
586
|
+
* if (!result.success) throw new Error(result.error.message)
|
|
587
|
+
* void result.data
|
|
588
|
+
* ```
|
|
589
|
+
*/
|
|
812
590
|
get: <T = QueryRow>(sql: string, params?: unknown[]) => Promise<HaiResult<T | null>>;
|
|
813
|
-
/**
|
|
591
|
+
/**
|
|
592
|
+
* 执行修改语句(INSERT/UPDATE/DELETE)
|
|
593
|
+
* @example
|
|
594
|
+
* ```ts
|
|
595
|
+
* import { reldb } from '@h-ai/reldb'
|
|
596
|
+
*
|
|
597
|
+
* const result = await reldb.sql.execute('UPDATE users SET name = ? WHERE id = ?', ['Alice', 'u1'])
|
|
598
|
+
* if (!result.success) throw new Error(result.error.message)
|
|
599
|
+
* void result.data
|
|
600
|
+
* ```
|
|
601
|
+
*/
|
|
814
602
|
execute: (sql: string, params?: unknown[]) => Promise<HaiResult<ExecuteResult>>;
|
|
815
|
-
/**
|
|
603
|
+
/**
|
|
604
|
+
* 批量执行多条语句(在同一事务上下文中)
|
|
605
|
+
* @example
|
|
606
|
+
* ```ts
|
|
607
|
+
* import { reldb } from '@h-ai/reldb'
|
|
608
|
+
*
|
|
609
|
+
* const result = await reldb.sql.batch([{ sql: 'UPDATE users SET name = ? WHERE id = ?', params: ['Alice', 'u1'] }])
|
|
610
|
+
* if (!result.success) throw new Error(result.error.message)
|
|
611
|
+
* void result.data
|
|
612
|
+
* ```
|
|
613
|
+
*/
|
|
816
614
|
batch: (statements: Array<{
|
|
817
615
|
sql: string;
|
|
818
616
|
params?: unknown[];
|
|
819
617
|
}>) => Promise<HaiResult<void>>;
|
|
820
|
-
/**
|
|
618
|
+
/**
|
|
619
|
+
* 分页查询
|
|
620
|
+
* @example
|
|
621
|
+
* ```ts
|
|
622
|
+
* import { reldb } from '@h-ai/reldb'
|
|
623
|
+
*
|
|
624
|
+
* const result = await reldb.sql.queryPage<{ id: string }>({ sql: 'SELECT id FROM users', pagination: { page: 1, pageSize: 10 } })
|
|
625
|
+
* if (!result.success) throw new Error(result.error.message)
|
|
626
|
+
* void result.data
|
|
627
|
+
* ```
|
|
628
|
+
*/
|
|
821
629
|
queryPage: <T = QueryRow>(options: PaginationQueryOptions) => Promise<HaiResult<PaginatedResult<T>>>;
|
|
822
630
|
}
|
|
823
|
-
/**
|
|
631
|
+
/**
|
|
632
|
+
* CRUD 查询条件
|
|
633
|
+
* @example
|
|
634
|
+
* ```ts
|
|
635
|
+
* import type { CrudQueryOptions } from '@h-ai/reldb'
|
|
636
|
+
*
|
|
637
|
+
* const value: CrudQueryOptions = { where: 'name = ?', params: ['Alice'], orderBy: 'id ASC', limit: 10 }
|
|
638
|
+
* void value
|
|
639
|
+
* ```
|
|
640
|
+
*/
|
|
824
641
|
interface CrudQueryOptions {
|
|
825
642
|
/**
|
|
826
643
|
* WHERE 子句(不包含 WHERE 关键字)
|
|
827
644
|
*
|
|
828
645
|
* **⚠️ 安全警告:** `where` 为原始 SQL 片段,**禁止**将用户输入直接拼接。
|
|
829
646
|
* 动态值必须通过 `params` 占位符(`?`)传入。
|
|
830
|
-
*
|
|
831
647
|
* @example
|
|
832
648
|
* ```ts
|
|
833
|
-
*
|
|
834
|
-
* crud.findAll({ where: 'status = ? AND age > ?', params: ['active', 18] })
|
|
649
|
+
* import type { CrudQueryOptions } from '@h-ai/reldb'
|
|
835
650
|
*
|
|
836
|
-
*
|
|
837
|
-
*
|
|
651
|
+
* const options: CrudQueryOptions = { where: 'name = ?', params: ['Alice'] }
|
|
652
|
+
* void options // 值走绑定参数;SQL 结构由开发者静态编写。
|
|
838
653
|
* ```
|
|
839
654
|
*/
|
|
840
655
|
where?: string;
|
|
@@ -847,13 +662,29 @@ interface CrudQueryOptions {
|
|
|
847
662
|
/** OFFSET */
|
|
848
663
|
offset?: number;
|
|
849
664
|
}
|
|
850
|
-
/**
|
|
665
|
+
/**
|
|
666
|
+
* CRUD 分页查询条件
|
|
667
|
+
* @example
|
|
668
|
+
* ```ts
|
|
669
|
+
* import type { CrudPageOptions } from '@h-ai/reldb'
|
|
670
|
+
*
|
|
671
|
+
* const value: CrudPageOptions = { where: 'active = ?', params: [true], pagination: { page: 1, pageSize: 20 } }
|
|
672
|
+
* void value
|
|
673
|
+
* ```
|
|
674
|
+
*/
|
|
851
675
|
interface CrudPageOptions {
|
|
852
676
|
/**
|
|
853
677
|
* WHERE 子句(不包含 WHERE 关键字)
|
|
854
678
|
*
|
|
855
679
|
* **⚠️ 安全警告:** `where` 为原始 SQL 片段,**禁止**将用户输入直接拼接。
|
|
856
680
|
* 动态值必须通过 `params` 占位符(`?`)传入。
|
|
681
|
+
* @example
|
|
682
|
+
* ```ts
|
|
683
|
+
* import type { CrudQueryOptions } from '@h-ai/reldb'
|
|
684
|
+
*
|
|
685
|
+
* const options: CrudQueryOptions = { where: 'name = ?', params: ['Alice'] }
|
|
686
|
+
* void options // 值走绑定参数;SQL 结构由开发者静态编写。
|
|
687
|
+
* ```
|
|
857
688
|
*/
|
|
858
689
|
where?: string;
|
|
859
690
|
/** 参数列表 */
|
|
@@ -865,19 +696,44 @@ interface CrudPageOptions {
|
|
|
865
696
|
/** 分页参数覆盖 */
|
|
866
697
|
overrides?: PaginationOverrides;
|
|
867
698
|
}
|
|
868
|
-
/**
|
|
699
|
+
/**
|
|
700
|
+
* CRUD 统计条件
|
|
701
|
+
* @example
|
|
702
|
+
* ```ts
|
|
703
|
+
* import type { ReldbCrudCountOptions } from '@h-ai/reldb'
|
|
704
|
+
*
|
|
705
|
+
* const value: ReldbCrudCountOptions = { where: 'active = ?', params: [true] }
|
|
706
|
+
* void value
|
|
707
|
+
* ```
|
|
708
|
+
*/
|
|
869
709
|
interface ReldbCrudCountOptions {
|
|
870
710
|
/**
|
|
871
711
|
* WHERE 子句(不包含 WHERE 关键字)
|
|
872
712
|
*
|
|
873
713
|
* **⚠️ 安全警告:** `where` 为原始 SQL 片段,**禁止**将用户输入直接拼接。
|
|
874
714
|
* 动态值必须通过 `params` 占位符(`?`)传入。
|
|
715
|
+
* @example
|
|
716
|
+
* ```ts
|
|
717
|
+
* import type { CrudQueryOptions } from '@h-ai/reldb'
|
|
718
|
+
*
|
|
719
|
+
* const options: CrudQueryOptions = { where: 'name = ?', params: ['Alice'] }
|
|
720
|
+
* void options // 值走绑定参数;SQL 结构由开发者静态编写。
|
|
721
|
+
* ```
|
|
875
722
|
*/
|
|
876
723
|
where?: string;
|
|
877
724
|
/** 参数列表 */
|
|
878
725
|
params?: unknown[];
|
|
879
726
|
}
|
|
880
|
-
/**
|
|
727
|
+
/**
|
|
728
|
+
* CRUD 配置
|
|
729
|
+
* @example
|
|
730
|
+
* ```ts
|
|
731
|
+
* import type { CrudConfig } from '@h-ai/reldb'
|
|
732
|
+
*
|
|
733
|
+
* const config: CrudConfig<{ id: string }> = { table: 'users', dbType: 'postgresql', select: ['id'], createColumns: ['id'], updateColumns: [] }
|
|
734
|
+
* void config
|
|
735
|
+
* ```
|
|
736
|
+
*/
|
|
881
737
|
interface CrudConfig<TItem> {
|
|
882
738
|
/** 表名 */
|
|
883
739
|
table: string;
|
|
@@ -894,7 +750,16 @@ interface CrudConfig<TItem> {
|
|
|
894
750
|
/** 数据库类型 */
|
|
895
751
|
dbType: DbType;
|
|
896
752
|
}
|
|
897
|
-
/**
|
|
753
|
+
/**
|
|
754
|
+
* CRUD 字段定义
|
|
755
|
+
* @example
|
|
756
|
+
* ```ts
|
|
757
|
+
* import type { ReldbCrudFieldDefinition } from '@h-ai/reldb'
|
|
758
|
+
*
|
|
759
|
+
* const value: ReldbCrudFieldDefinition = { fieldName: 'name', columnName: 'name', def: { type: 'TEXT', notNull: true }, select: true, create: true, update: true }
|
|
760
|
+
* void value
|
|
761
|
+
* ```
|
|
762
|
+
*/
|
|
898
763
|
interface ReldbCrudFieldDefinition {
|
|
899
764
|
/** 对象字段名 */
|
|
900
765
|
fieldName: string;
|
|
@@ -909,7 +774,20 @@ interface ReldbCrudFieldDefinition {
|
|
|
909
774
|
/** 是否允许更新 */
|
|
910
775
|
update: boolean;
|
|
911
776
|
}
|
|
912
|
-
/**
|
|
777
|
+
/**
|
|
778
|
+
* BaseReldbCrudRepository 配置
|
|
779
|
+
* @example
|
|
780
|
+
* ```ts
|
|
781
|
+
* import type { BaseReldbCrudRepositoryConfig } from '@h-ai/reldb'
|
|
782
|
+
*
|
|
783
|
+
* const config: BaseReldbCrudRepositoryConfig<{ id: string }> = {
|
|
784
|
+
* table: 'users', idField: 'id', fields: [
|
|
785
|
+
* { fieldName: 'id', columnName: 'id', def: { type: 'TEXT', primaryKey: true }, select: true, create: true, update: false },
|
|
786
|
+
* ],
|
|
787
|
+
* }
|
|
788
|
+
* void config
|
|
789
|
+
* ```
|
|
790
|
+
*/
|
|
913
791
|
interface BaseReldbCrudRepositoryConfig<TItem> {
|
|
914
792
|
/** 表名 */
|
|
915
793
|
table: string;
|
|
@@ -926,7 +804,19 @@ interface BaseReldbCrudRepositoryConfig<TItem> {
|
|
|
926
804
|
/** 当前时间提供者(默认 Date.now) */
|
|
927
805
|
nowProvider?: () => number;
|
|
928
806
|
}
|
|
929
|
-
/**
|
|
807
|
+
/**
|
|
808
|
+
* CRUD 仓库接口
|
|
809
|
+
* @example
|
|
810
|
+
* ```ts
|
|
811
|
+
* import type { ReldbCrudRepository } from '@h-ai/reldb'
|
|
812
|
+
*
|
|
813
|
+
* async function use(operations: ReldbCrudRepository<{ id: string }>) {
|
|
814
|
+
* const result = await operations.findById('u1')
|
|
815
|
+
* if (!result.success) throw new Error(result.error.message)
|
|
816
|
+
* return result.data
|
|
817
|
+
* }
|
|
818
|
+
* ```
|
|
819
|
+
*/
|
|
930
820
|
interface ReldbCrudRepository<TItem> {
|
|
931
821
|
create: (data: Record<string, unknown>, tx?: DmlWithTxOperations) => Promise<HaiResult<ExecuteResult>>;
|
|
932
822
|
createMany: (items: Array<Record<string, unknown>>, tx?: DmlWithTxOperations) => Promise<HaiResult<void>>;
|
|
@@ -941,13 +831,37 @@ interface ReldbCrudRepository<TItem> {
|
|
|
941
831
|
exists: (options?: ReldbCrudCountOptions, tx?: DmlWithTxOperations) => Promise<HaiResult<boolean>>;
|
|
942
832
|
existsById: (id: unknown, tx?: DmlWithTxOperations) => Promise<HaiResult<boolean>>;
|
|
943
833
|
}
|
|
944
|
-
/**
|
|
834
|
+
/**
|
|
835
|
+
* CRUD 管理器(统一入口)
|
|
836
|
+
* @example
|
|
837
|
+
* ```ts
|
|
838
|
+
* import type { CrudManager } from '@h-ai/reldb'
|
|
839
|
+
*
|
|
840
|
+
* async function use(operations: CrudManager) {
|
|
841
|
+
* const result = await operations.table<{ id: string }>({ table: 'users', dbType: 'postgresql' }).findById('u1')
|
|
842
|
+
* if (!result.success) throw new Error(result.error.message)
|
|
843
|
+
* return result.data
|
|
844
|
+
* }
|
|
845
|
+
* ```
|
|
846
|
+
*/
|
|
945
847
|
interface CrudManager {
|
|
946
848
|
/** 获取单表 CRUD 仓库 */
|
|
947
849
|
table: <TItem>(config: CrudConfig<TItem>) => ReldbCrudRepository<TItem>;
|
|
948
850
|
}
|
|
949
851
|
/**
|
|
950
852
|
* 事务句柄接口(分步事务)
|
|
853
|
+
* @example
|
|
854
|
+
* ```ts
|
|
855
|
+
* import type { DmlWithTxOperations } from '@h-ai/reldb'
|
|
856
|
+
*
|
|
857
|
+
* async function use(operations: DmlWithTxOperations) {
|
|
858
|
+
* const result = await operations.execute('UPDATE users SET name = ? WHERE id = ?', ['Alice', 'u1'])
|
|
859
|
+
* if (!result.success) throw new Error(result.error.message)
|
|
860
|
+
* const committed = await operations.commit()
|
|
861
|
+
* if (!committed.success) throw new Error(committed.error.message)
|
|
862
|
+
* return result.data.changes
|
|
863
|
+
* }
|
|
864
|
+
* ```
|
|
951
865
|
*/
|
|
952
866
|
interface DmlWithTxOperations extends DmlOperations {
|
|
953
867
|
/** CRUD 管理器 */
|
|
@@ -961,18 +875,36 @@ interface DmlWithTxOperations extends DmlOperations {
|
|
|
961
875
|
* 事务回调函数类型
|
|
962
876
|
*
|
|
963
877
|
* @param tx - 事务内操作对象
|
|
964
|
-
* @returns 业务返回值(将被包装为 HaiResult
|
|
878
|
+
* @returns 业务返回值(将被包装为 HaiResult);callback 抛错才回滚,返回失败 HaiResult 不会被自动展开。
|
|
965
879
|
* @example
|
|
966
880
|
* ```ts
|
|
967
|
-
*
|
|
968
|
-
*
|
|
969
|
-
*
|
|
970
|
-
*
|
|
881
|
+
* import type { TxWrapCallback } from '@h-ai/reldb'
|
|
882
|
+
*
|
|
883
|
+
* const insert: TxWrapCallback<number> = async (tx) => {
|
|
884
|
+
* const result = await tx.execute('INSERT INTO users (id, name) VALUES (?, ?)', ['u1', 'Alice'])
|
|
885
|
+
* if (!result.success) throw new Error(result.error.message) // 显式抛错触发 wrap 回滚。
|
|
886
|
+
* return result.data.changes
|
|
887
|
+
* }
|
|
888
|
+
* void insert
|
|
971
889
|
* ```
|
|
972
890
|
*/
|
|
973
891
|
type TxWrapCallback<T> = (tx: DmlWithTxOperations) => Promise<T>;
|
|
974
892
|
/**
|
|
975
893
|
* 事务管理器
|
|
894
|
+
* @example
|
|
895
|
+
* ```ts
|
|
896
|
+
* import type { TxManager } from '@h-ai/reldb'
|
|
897
|
+
*
|
|
898
|
+
* async function use(operations: TxManager) {
|
|
899
|
+
* const result = await operations.wrap(async (tx) => {
|
|
900
|
+
* const changed = await tx.execute('UPDATE users SET name = ? WHERE id = ?', ['Alice', 'u1'])
|
|
901
|
+
* if (!changed.success) throw new Error(changed.error.message)
|
|
902
|
+
* return changed.data.changes
|
|
903
|
+
* })
|
|
904
|
+
* if (!result.success) throw new Error(result.error.message)
|
|
905
|
+
* return result.data
|
|
906
|
+
* }
|
|
907
|
+
* ```
|
|
976
908
|
*/
|
|
977
909
|
interface TxManager {
|
|
978
910
|
/** 开启事务(分步事务) */
|
|
@@ -984,30 +916,21 @@ interface TxManager {
|
|
|
984
916
|
* 数据库函数接口
|
|
985
917
|
*
|
|
986
918
|
* 统一的数据库访问入口,通过 `reldb` 对象提供所有数据库操作。
|
|
987
|
-
*
|
|
988
919
|
* @example
|
|
989
920
|
* ```ts
|
|
990
921
|
* import { reldb } from '@h-ai/reldb'
|
|
991
922
|
*
|
|
992
|
-
* //
|
|
993
|
-
*
|
|
994
|
-
*
|
|
995
|
-
*
|
|
996
|
-
*
|
|
997
|
-
*
|
|
923
|
+
* const initialized = await reldb.init({ type: 'sqlite', database: ':memory:' }) // 仅示例/测试。
|
|
924
|
+
* if (!initialized.success) throw new Error(initialized.error.message)
|
|
925
|
+
* try {
|
|
926
|
+
* const created = await reldb.ddl.createTable('users', { id: { type: 'TEXT', primaryKey: true }, name: { type: 'TEXT' } })
|
|
927
|
+
* if (!created.success) throw new Error(created.error.message)
|
|
928
|
+
* const inserted = await reldb.sql.execute('INSERT INTO users (id, name) VALUES (?, ?)', ['u1', 'Alice'])
|
|
929
|
+
* if (!inserted.success) throw new Error(inserted.error.message)
|
|
930
|
+
* } finally {
|
|
931
|
+
* const closed = await reldb.close()
|
|
932
|
+
* if (!closed.success) throw new Error(closed.error.message)
|
|
998
933
|
* }
|
|
999
|
-
*
|
|
1000
|
-
* // 使用 DDL
|
|
1001
|
-
* await reldb.ddl.createTable('users', { ... })
|
|
1002
|
-
*
|
|
1003
|
-
* // 使用 SQL
|
|
1004
|
-
* await reldb.sql.query('SELECT * FROM users')
|
|
1005
|
-
*
|
|
1006
|
-
* // 使用事务
|
|
1007
|
-
* await reldb.tx.wrap(async (tx) => { ... })
|
|
1008
|
-
*
|
|
1009
|
-
* // 关闭连接
|
|
1010
|
-
* await reldb.close()
|
|
1011
934
|
* ```
|
|
1012
935
|
*/
|
|
1013
936
|
interface ReldbFunctions {
|
|
@@ -1016,6 +939,14 @@ interface ReldbFunctions {
|
|
|
1016
939
|
*
|
|
1017
940
|
* @param config - 数据库配置
|
|
1018
941
|
* @returns 初始化结果
|
|
942
|
+
* @example
|
|
943
|
+
* ```ts
|
|
944
|
+
* import { reldb } from '@h-ai/reldb'
|
|
945
|
+
*
|
|
946
|
+
* const result = await reldb.init({ type: 'sqlite', database: ':memory:' })
|
|
947
|
+
* if (!result.success) throw new Error(result.error.message)
|
|
948
|
+
* void result.data
|
|
949
|
+
* ```
|
|
1019
950
|
*/
|
|
1020
951
|
init: (config: ReldbConfigInput) => Promise<HaiResult<void>>;
|
|
1021
952
|
/** DDL 操作(表结构管理) */
|
|
@@ -1026,7 +957,7 @@ interface ReldbFunctions {
|
|
|
1026
957
|
readonly crud: CrudManager;
|
|
1027
958
|
/** 事务管理器 */
|
|
1028
959
|
readonly tx: TxManager;
|
|
1029
|
-
/**
|
|
960
|
+
/** 当前数据库脱敏配置快照(未初始化时为 null) */
|
|
1030
961
|
readonly config: ReldbConfig | null;
|
|
1031
962
|
/** 是否已初始化 */
|
|
1032
963
|
readonly isInitialized: boolean;
|
|
@@ -1044,49 +975,29 @@ interface ReldbFunctions {
|
|
|
1044
975
|
* 返回的 SQL 片段可嵌入 `reldb.sql.query` / `reldb.sql.execute` 等调用。
|
|
1045
976
|
*
|
|
1046
977
|
* 未初始化时默认返回 SQLite 格式的构建器;初始化后自动匹配当前数据库类型。
|
|
1047
|
-
*
|
|
1048
978
|
* @example
|
|
1049
979
|
* ```ts
|
|
1050
|
-
*
|
|
1051
|
-
*
|
|
1052
|
-
* const
|
|
1053
|
-
*
|
|
1054
|
-
*
|
|
1055
|
-
* )
|
|
1056
|
-
*
|
|
1057
|
-
* // 设置 JSON 字段路径
|
|
1058
|
-
* const { sql, params } = reldb.json.set('settings', '$.theme', 'dark')
|
|
1059
|
-
* await reldb.sql.execute(
|
|
1060
|
-
* `UPDATE users SET settings = ${sql} WHERE id = ?`,
|
|
1061
|
-
* [...params, userId],
|
|
1062
|
-
* )
|
|
980
|
+
* import { reldb } from '@h-ai/reldb'
|
|
981
|
+
*
|
|
982
|
+
* const expression = reldb.json.set('settings', '$.theme', 'dark')
|
|
983
|
+
* const result = await reldb.sql.execute(`UPDATE users SET settings = ${expression.sql} WHERE id = ?`, [...expression.params, 'u1'])
|
|
984
|
+
* if (!result.success) throw new Error(result.error.message)
|
|
1063
985
|
* ```
|
|
1064
986
|
*/
|
|
1065
987
|
readonly json: ReldbJsonOps;
|
|
1066
|
-
/**
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
/** SQL 操作(数据查询和修改) */
|
|
1079
|
-
readonly sql: DmlOperations;
|
|
1080
|
-
/** CRUD 管理器 */
|
|
1081
|
-
readonly crud: CrudManager;
|
|
1082
|
-
/** 事务管理器 */
|
|
1083
|
-
readonly tx: TxManager;
|
|
1084
|
-
/** 连接数据库 */
|
|
1085
|
-
connect: (config: ReldbConfig) => Promise<HaiResult<void>>;
|
|
1086
|
-
/** 关闭连接 */
|
|
988
|
+
/**
|
|
989
|
+
* 等待初始化/在途事务并关闭连接;清理失败后操作不可用,资源保留供重试。
|
|
990
|
+
* @returns 资源全部释放时成功;未初始化时同样成功。
|
|
991
|
+
* @example
|
|
992
|
+
* ```ts
|
|
993
|
+
* import { reldb } from '@h-ai/reldb'
|
|
994
|
+
*
|
|
995
|
+
* const result = await reldb.close()
|
|
996
|
+
* if (!result.success) throw new Error(result.error.message)
|
|
997
|
+
* void result.data
|
|
998
|
+
* ```
|
|
999
|
+
*/
|
|
1087
1000
|
close: () => Promise<HaiResult<void>>;
|
|
1088
|
-
/** 是否已连接 */
|
|
1089
|
-
isConnected: () => boolean;
|
|
1090
1001
|
}
|
|
1091
1002
|
|
|
1092
1003
|
/**
|
|
@@ -1107,21 +1018,24 @@ interface ReldbProvider {
|
|
|
1107
1018
|
* - 自动填充主键、createdAt、updatedAt
|
|
1108
1019
|
* - 跨数据库类型值转换(BOOLEAN / TIMESTAMP / JSON)
|
|
1109
1020
|
* - 支持事务上下文(所有方法均接受可选 tx 参数)
|
|
1110
|
-
*
|
|
1111
1021
|
* @example
|
|
1112
1022
|
* ```ts
|
|
1113
|
-
*
|
|
1023
|
+
* import { BaseReldbCrudRepository, type ReldbFunctions } from '@h-ai/reldb'
|
|
1024
|
+
*
|
|
1025
|
+
* type User = { id: string, name: string }
|
|
1026
|
+
* class Users extends BaseReldbCrudRepository<User> {
|
|
1114
1027
|
* constructor(db: ReldbFunctions) {
|
|
1115
|
-
* super(db, {
|
|
1116
|
-
*
|
|
1117
|
-
*
|
|
1118
|
-
*
|
|
1119
|
-
* { fieldName: 'name', columnName: 'name', def: { type: 'TEXT', notNull: true }, select: true, create: true, update: true },
|
|
1120
|
-
* { fieldName: 'createdAt', columnName: 'created_at', def: { type: 'TIMESTAMP' }, select: true, create: true, update: false },
|
|
1121
|
-
* ],
|
|
1122
|
-
* })
|
|
1028
|
+
* super(db, { table: 'users', fields: [
|
|
1029
|
+
* { fieldName: 'id', columnName: 'id', def: { type: 'TEXT', primaryKey: true }, select: true, create: true, update: false },
|
|
1030
|
+
* { fieldName: 'name', columnName: 'name', def: { type: 'TEXT' }, select: true, create: true, update: true },
|
|
1031
|
+
* ] })
|
|
1123
1032
|
* }
|
|
1124
1033
|
* }
|
|
1034
|
+
* async function create(db: ReldbFunctions) { // db 已初始化。
|
|
1035
|
+
* const result = await new Users(db).create({ name: 'Alice' })
|
|
1036
|
+
* if (!result.success) throw new Error(result.error.message)
|
|
1037
|
+
* return result.data
|
|
1038
|
+
* }
|
|
1125
1039
|
* ```
|
|
1126
1040
|
*/
|
|
1127
1041
|
declare abstract class BaseReldbCrudRepository<TItem> implements ReldbCrudRepository<TItem> {
|
|
@@ -1239,11 +1153,15 @@ declare abstract class BaseReldbCrudRepository<TItem> implements ReldbCrudReposi
|
|
|
1239
1153
|
*/
|
|
1240
1154
|
private buildUpdatePayload;
|
|
1241
1155
|
/**
|
|
1242
|
-
*
|
|
1156
|
+
* 等待初始化完成(自动建表等)
|
|
1157
|
+
*
|
|
1158
|
+
* 内置 CRUD 方法均已在执行前调用;自定义方法若通过 `this.sql()` 直接执行原始
|
|
1159
|
+
* SQL(尤其是写操作或在事务中),应先 `await this.ensureReady()` 以避免表尚未
|
|
1160
|
+
* 建好时(例如刚 dropTable 后、或后端建表较慢时)产生「表不存在」的竞态失败。
|
|
1243
1161
|
*
|
|
1244
1162
|
* @returns 初始化结果
|
|
1245
1163
|
*/
|
|
1246
|
-
|
|
1164
|
+
protected ensureReady(): Promise<HaiResult<void>>;
|
|
1247
1165
|
/**
|
|
1248
1166
|
* 创建单条记录
|
|
1249
1167
|
*
|
|
@@ -1252,6 +1170,17 @@ declare abstract class BaseReldbCrudRepository<TItem> implements ReldbCrudReposi
|
|
|
1252
1170
|
* @param data - 业务字段与值的映射
|
|
1253
1171
|
* @param tx - 可选事务句柄
|
|
1254
1172
|
* @returns 插入结果(含 changes、lastInsertRowid)
|
|
1173
|
+
* @example
|
|
1174
|
+
* ```ts
|
|
1175
|
+
* import type { ReldbCrudRepository } from '@h-ai/reldb'
|
|
1176
|
+
*
|
|
1177
|
+
* async function use(repo: ReldbCrudRepository<{ id: string, name: string }>) {
|
|
1178
|
+
* const result = await repo.create({ name: 'Alice' })
|
|
1179
|
+
* if (!result.success) throw new Error(result.error.message)
|
|
1180
|
+
* return result.data
|
|
1181
|
+
* }
|
|
1182
|
+
* void use
|
|
1183
|
+
* ```
|
|
1255
1184
|
*/
|
|
1256
1185
|
create(data: Record<string, unknown>, tx?: DmlWithTxOperations): Promise<HaiResult<ExecuteResult>>;
|
|
1257
1186
|
/**
|
|
@@ -1262,6 +1191,17 @@ declare abstract class BaseReldbCrudRepository<TItem> implements ReldbCrudReposi
|
|
|
1262
1191
|
* @param items - 待插入的业务数据数组
|
|
1263
1192
|
* @param tx - 可选事务句柄
|
|
1264
1193
|
* @returns 批量插入结果
|
|
1194
|
+
* @example
|
|
1195
|
+
* ```ts
|
|
1196
|
+
* import type { ReldbCrudRepository } from '@h-ai/reldb'
|
|
1197
|
+
*
|
|
1198
|
+
* async function use(repo: ReldbCrudRepository<{ id: string, name: string }>) {
|
|
1199
|
+
* const result = await repo.createMany([{ name: 'Alice' }, { name: 'Bob' }])
|
|
1200
|
+
* if (!result.success) throw new Error(result.error.message)
|
|
1201
|
+
* return result.data
|
|
1202
|
+
* }
|
|
1203
|
+
* void use
|
|
1204
|
+
* ```
|
|
1265
1205
|
*/
|
|
1266
1206
|
createMany(items: Array<Record<string, unknown>>, tx?: DmlWithTxOperations): Promise<HaiResult<void>>;
|
|
1267
1207
|
/**
|
|
@@ -1289,6 +1229,17 @@ declare abstract class BaseReldbCrudRepository<TItem> implements ReldbCrudReposi
|
|
|
1289
1229
|
* @param data - 业务字段与值的映射
|
|
1290
1230
|
* @param tx - 可选事务句柄
|
|
1291
1231
|
* @returns 执行结果(含 changes)
|
|
1232
|
+
* @example
|
|
1233
|
+
* ```ts
|
|
1234
|
+
* import type { ReldbCrudRepository } from '@h-ai/reldb'
|
|
1235
|
+
*
|
|
1236
|
+
* async function use(repo: ReldbCrudRepository<{ id: string, name: string }>) {
|
|
1237
|
+
* const result = await repo.createOrUpdate({ id: 'u1', name: 'Alice' })
|
|
1238
|
+
* if (!result.success) throw new Error(result.error.message)
|
|
1239
|
+
* return result.data
|
|
1240
|
+
* }
|
|
1241
|
+
* void use
|
|
1242
|
+
* ```
|
|
1292
1243
|
*/
|
|
1293
1244
|
createOrUpdate(data: Record<string, unknown>, tx?: DmlWithTxOperations): Promise<HaiResult<ExecuteResult>>;
|
|
1294
1245
|
/**
|
|
@@ -1297,6 +1248,17 @@ declare abstract class BaseReldbCrudRepository<TItem> implements ReldbCrudReposi
|
|
|
1297
1248
|
* @param id - 主键值
|
|
1298
1249
|
* @param tx - 可选事务句柄
|
|
1299
1250
|
* @returns 业务模型对象或 null(未找到)
|
|
1251
|
+
* @example
|
|
1252
|
+
* ```ts
|
|
1253
|
+
* import type { ReldbCrudRepository } from '@h-ai/reldb'
|
|
1254
|
+
*
|
|
1255
|
+
* async function use(repo: ReldbCrudRepository<{ id: string, name: string }>) {
|
|
1256
|
+
* const result = await repo.findById('u1')
|
|
1257
|
+
* if (!result.success) throw new Error(result.error.message)
|
|
1258
|
+
* return result.data
|
|
1259
|
+
* }
|
|
1260
|
+
* void use
|
|
1261
|
+
* ```
|
|
1300
1262
|
*/
|
|
1301
1263
|
findById(id: unknown, tx?: DmlWithTxOperations): Promise<HaiResult<TItem | null>>;
|
|
1302
1264
|
/**
|
|
@@ -1307,6 +1269,17 @@ declare abstract class BaseReldbCrudRepository<TItem> implements ReldbCrudReposi
|
|
|
1307
1269
|
* @param id - 主键值
|
|
1308
1270
|
* @param tx - 可选事务句柄
|
|
1309
1271
|
* @returns 业务模型对象(不存在时返回错误)
|
|
1272
|
+
* @example
|
|
1273
|
+
* ```ts
|
|
1274
|
+
* import type { ReldbCrudRepository } from '@h-ai/reldb'
|
|
1275
|
+
*
|
|
1276
|
+
* async function use(repo: ReldbCrudRepository<{ id: string, name: string }>) {
|
|
1277
|
+
* const result = await repo.getById('u1')
|
|
1278
|
+
* if (!result.success) throw new Error(result.error.message)
|
|
1279
|
+
* return result.data
|
|
1280
|
+
* }
|
|
1281
|
+
* void use
|
|
1282
|
+
* ```
|
|
1310
1283
|
*/
|
|
1311
1284
|
getById(id: unknown, tx?: DmlWithTxOperations): Promise<HaiResult<TItem>>;
|
|
1312
1285
|
/**
|
|
@@ -1315,6 +1288,17 @@ declare abstract class BaseReldbCrudRepository<TItem> implements ReldbCrudReposi
|
|
|
1315
1288
|
* @param options - 查询条件(where、orderBy、limit、offset)
|
|
1316
1289
|
* @param tx - 可选事务句柄
|
|
1317
1290
|
* @returns 业务模型数组
|
|
1291
|
+
* @example
|
|
1292
|
+
* ```ts
|
|
1293
|
+
* import type { ReldbCrudRepository } from '@h-ai/reldb'
|
|
1294
|
+
*
|
|
1295
|
+
* async function use(repo: ReldbCrudRepository<{ id: string, name: string }>) {
|
|
1296
|
+
* const result = await repo.findAll({ where: 'name = ?', params: ['Alice'] })
|
|
1297
|
+
* if (!result.success) throw new Error(result.error.message)
|
|
1298
|
+
* return result.data
|
|
1299
|
+
* }
|
|
1300
|
+
* void use
|
|
1301
|
+
* ```
|
|
1318
1302
|
*/
|
|
1319
1303
|
findAll(options?: CrudQueryOptions, tx?: DmlWithTxOperations): Promise<HaiResult<TItem[]>>;
|
|
1320
1304
|
/**
|
|
@@ -1323,6 +1307,17 @@ declare abstract class BaseReldbCrudRepository<TItem> implements ReldbCrudReposi
|
|
|
1323
1307
|
* @param options - 分页查询条件(where、orderBy、pagination、overrides)
|
|
1324
1308
|
* @param tx - 可选事务句柄
|
|
1325
1309
|
* @returns 分页结果(含 items、total、page、pageSize)
|
|
1310
|
+
* @example
|
|
1311
|
+
* ```ts
|
|
1312
|
+
* import type { ReldbCrudRepository } from '@h-ai/reldb'
|
|
1313
|
+
*
|
|
1314
|
+
* async function use(repo: ReldbCrudRepository<{ id: string, name: string }>) {
|
|
1315
|
+
* const result = await repo.findPage({ pagination: { page: 1, pageSize: 10 }, orderBy: 'id ASC' })
|
|
1316
|
+
* if (!result.success) throw new Error(result.error.message)
|
|
1317
|
+
* return result.data
|
|
1318
|
+
* }
|
|
1319
|
+
* void use
|
|
1320
|
+
* ```
|
|
1326
1321
|
*/
|
|
1327
1322
|
findPage(options: CrudPageOptions, tx?: DmlWithTxOperations): Promise<HaiResult<PaginatedResult<TItem>>>;
|
|
1328
1323
|
/**
|
|
@@ -1334,6 +1329,17 @@ declare abstract class BaseReldbCrudRepository<TItem> implements ReldbCrudReposi
|
|
|
1334
1329
|
* @param data - 待更新的业务字段
|
|
1335
1330
|
* @param tx - 可选事务句柄
|
|
1336
1331
|
* @returns 更新结果(含 changes)
|
|
1332
|
+
* @example
|
|
1333
|
+
* ```ts
|
|
1334
|
+
* import type { ReldbCrudRepository } from '@h-ai/reldb'
|
|
1335
|
+
*
|
|
1336
|
+
* async function use(repo: ReldbCrudRepository<{ id: string, name: string }>) {
|
|
1337
|
+
* const result = await repo.updateById('u1', { name: 'Bob' })
|
|
1338
|
+
* if (!result.success) throw new Error(result.error.message)
|
|
1339
|
+
* return result.data
|
|
1340
|
+
* }
|
|
1341
|
+
* void use
|
|
1342
|
+
* ```
|
|
1337
1343
|
*/
|
|
1338
1344
|
updateById(id: unknown, data: Record<string, unknown>, tx?: DmlWithTxOperations): Promise<HaiResult<ExecuteResult>>;
|
|
1339
1345
|
/**
|
|
@@ -1342,6 +1348,17 @@ declare abstract class BaseReldbCrudRepository<TItem> implements ReldbCrudReposi
|
|
|
1342
1348
|
* @param id - 主键值
|
|
1343
1349
|
* @param tx - 可选事务句柄
|
|
1344
1350
|
* @returns 删除结果(含 changes)
|
|
1351
|
+
* @example
|
|
1352
|
+
* ```ts
|
|
1353
|
+
* import type { ReldbCrudRepository } from '@h-ai/reldb'
|
|
1354
|
+
*
|
|
1355
|
+
* async function use(repo: ReldbCrudRepository<{ id: string, name: string }>) {
|
|
1356
|
+
* const result = await repo.deleteById('u1')
|
|
1357
|
+
* if (!result.success) throw new Error(result.error.message)
|
|
1358
|
+
* return result.data
|
|
1359
|
+
* }
|
|
1360
|
+
* void use
|
|
1361
|
+
* ```
|
|
1345
1362
|
*/
|
|
1346
1363
|
deleteById(id: unknown, tx?: DmlWithTxOperations): Promise<HaiResult<ExecuteResult>>;
|
|
1347
1364
|
/**
|
|
@@ -1350,6 +1367,17 @@ declare abstract class BaseReldbCrudRepository<TItem> implements ReldbCrudReposi
|
|
|
1350
1367
|
* @param options - 查询条件(where、params)
|
|
1351
1368
|
* @param tx - 可选事务句柄
|
|
1352
1369
|
* @returns 记录数
|
|
1370
|
+
* @example
|
|
1371
|
+
* ```ts
|
|
1372
|
+
* import type { ReldbCrudRepository } from '@h-ai/reldb'
|
|
1373
|
+
*
|
|
1374
|
+
* async function use(repo: ReldbCrudRepository<{ id: string, name: string }>) {
|
|
1375
|
+
* const result = await repo.count({ where: 'name = ?', params: ['Alice'] })
|
|
1376
|
+
* if (!result.success) throw new Error(result.error.message)
|
|
1377
|
+
* return result.data
|
|
1378
|
+
* }
|
|
1379
|
+
* void use
|
|
1380
|
+
* ```
|
|
1353
1381
|
*/
|
|
1354
1382
|
count(options?: ReldbCrudCountOptions, tx?: DmlWithTxOperations): Promise<HaiResult<number>>;
|
|
1355
1383
|
/**
|
|
@@ -1358,6 +1386,17 @@ declare abstract class BaseReldbCrudRepository<TItem> implements ReldbCrudReposi
|
|
|
1358
1386
|
* @param options - 查询条件(where、params)
|
|
1359
1387
|
* @param tx - 可选事务句柄
|
|
1360
1388
|
* @returns 是否存在
|
|
1389
|
+
* @example
|
|
1390
|
+
* ```ts
|
|
1391
|
+
* import type { ReldbCrudRepository } from '@h-ai/reldb'
|
|
1392
|
+
*
|
|
1393
|
+
* async function use(repo: ReldbCrudRepository<{ id: string, name: string }>) {
|
|
1394
|
+
* const result = await repo.exists({ where: 'name = ?', params: ['Alice'] })
|
|
1395
|
+
* if (!result.success) throw new Error(result.error.message)
|
|
1396
|
+
* return result.data
|
|
1397
|
+
* }
|
|
1398
|
+
* void use
|
|
1399
|
+
* ```
|
|
1361
1400
|
*/
|
|
1362
1401
|
exists(options?: ReldbCrudCountOptions, tx?: DmlWithTxOperations): Promise<HaiResult<boolean>>;
|
|
1363
1402
|
/**
|
|
@@ -1366,6 +1405,17 @@ declare abstract class BaseReldbCrudRepository<TItem> implements ReldbCrudReposi
|
|
|
1366
1405
|
* @param id - 主键值
|
|
1367
1406
|
* @param tx - 可选事务句柄
|
|
1368
1407
|
* @returns 是否存在
|
|
1408
|
+
* @example
|
|
1409
|
+
* ```ts
|
|
1410
|
+
* import type { ReldbCrudRepository } from '@h-ai/reldb'
|
|
1411
|
+
*
|
|
1412
|
+
* async function use(repo: ReldbCrudRepository<{ id: string, name: string }>) {
|
|
1413
|
+
* const result = await repo.existsById('u1')
|
|
1414
|
+
* if (!result.success) throw new Error(result.error.message)
|
|
1415
|
+
* return result.data
|
|
1416
|
+
* }
|
|
1417
|
+
* void use
|
|
1418
|
+
* ```
|
|
1369
1419
|
*/
|
|
1370
1420
|
existsById(id: unknown, tx?: DmlWithTxOperations): Promise<HaiResult<boolean>>;
|
|
1371
1421
|
}
|
|
@@ -1389,37 +1439,78 @@ declare abstract class BaseReldbCrudRepository<TItem> implements ReldbCrudReposi
|
|
|
1389
1439
|
* - `reldb.json` - JSON 路径操作 SQL 构建器(提取、设置、插入、删除、合并)
|
|
1390
1440
|
* - `reldb.config` - 当前配置
|
|
1391
1441
|
* - `reldb.isInitialized` - 初始化状态
|
|
1392
|
-
*
|
|
1393
1442
|
* @example
|
|
1394
1443
|
* ```ts
|
|
1395
1444
|
* import { reldb } from '@h-ai/reldb'
|
|
1396
1445
|
*
|
|
1397
|
-
* //
|
|
1398
|
-
*
|
|
1399
|
-
*
|
|
1400
|
-
*
|
|
1401
|
-
*
|
|
1402
|
-
*
|
|
1403
|
-
*
|
|
1404
|
-
* }
|
|
1405
|
-
*
|
|
1406
|
-
*
|
|
1407
|
-
*
|
|
1408
|
-
* const users = await reldb.sql.query('SELECT * FROM users')
|
|
1409
|
-
*
|
|
1410
|
-
* // 事务操作
|
|
1411
|
-
* await reldb.tx.wrap(async (tx) => {
|
|
1412
|
-
* await tx.execute('INSERT INTO users (name) VALUES (?)', ['用户1'])
|
|
1413
|
-
* await tx.execute('INSERT INTO users (name) VALUES (?)', ['用户2'])
|
|
1414
|
-
* return 'done'
|
|
1415
|
-
* })
|
|
1416
|
-
*
|
|
1417
|
-
* // 关闭连接
|
|
1418
|
-
* await reldb.close()
|
|
1446
|
+
* const initialized = await reldb.init({ type: 'sqlite', database: ':memory:' }) // 仅示例/测试。
|
|
1447
|
+
* if (!initialized.success) throw new Error(initialized.error.message)
|
|
1448
|
+
* try {
|
|
1449
|
+
* const created = await reldb.ddl.createTable('users', { id: { type: 'TEXT', primaryKey: true }, name: { type: 'TEXT' } })
|
|
1450
|
+
* if (!created.success) throw new Error(created.error.message)
|
|
1451
|
+
* const inserted = await reldb.sql.execute('INSERT INTO users (id, name) VALUES (?, ?)', ['u1', 'Alice'])
|
|
1452
|
+
* if (!inserted.success) throw new Error(inserted.error.message)
|
|
1453
|
+
* } finally {
|
|
1454
|
+
* const closed = await reldb.close()
|
|
1455
|
+
* if (!closed.success) throw new Error(closed.error.message)
|
|
1456
|
+
* }
|
|
1419
1457
|
* ```
|
|
1420
1458
|
*/
|
|
1421
1459
|
declare const reldb: ReldbFunctions;
|
|
1422
1460
|
|
|
1461
|
+
/** 模块维护自己的迁移;这里只提供跨数据库列检查、版本账本和执行边界。 */
|
|
1462
|
+
|
|
1463
|
+
/**
|
|
1464
|
+
* 一个可重入的模块升级步骤;只接收代码中固定的 SQL 与表名。
|
|
1465
|
+
* @example
|
|
1466
|
+
* ```ts
|
|
1467
|
+
* import type { SchemaMigration } from '@h-ai/reldb'
|
|
1468
|
+
* const steps: SchemaMigration[] = []
|
|
1469
|
+
* ```
|
|
1470
|
+
*/
|
|
1471
|
+
interface SchemaMigration {
|
|
1472
|
+
version: number;
|
|
1473
|
+
name: string;
|
|
1474
|
+
needed: (sql: DmlOperations) => Promise<HaiResult<boolean>>;
|
|
1475
|
+
apply: (sql: DmlOperations) => Promise<HaiResult<unknown>>;
|
|
1476
|
+
}
|
|
1477
|
+
/**
|
|
1478
|
+
* 只读预检结果;生产升级需先停旧写入并备份数据库与共享缓存。
|
|
1479
|
+
* @example
|
|
1480
|
+
* ```ts
|
|
1481
|
+
* import type { SchemaMigrationPlan } from '@h-ai/reldb'
|
|
1482
|
+
* function changes(plan: SchemaMigrationPlan) { return plan.changes }
|
|
1483
|
+
* ```
|
|
1484
|
+
*/
|
|
1485
|
+
interface SchemaMigrationPlan {
|
|
1486
|
+
module: string;
|
|
1487
|
+
currentVersion: number;
|
|
1488
|
+
targetVersion: number;
|
|
1489
|
+
changes: string[];
|
|
1490
|
+
requiresExclusiveAccess: boolean;
|
|
1491
|
+
}
|
|
1492
|
+
/**
|
|
1493
|
+
* 查询真实列名;不创建表,不把查询错误当成新安装。
|
|
1494
|
+
* @example
|
|
1495
|
+
* ```ts
|
|
1496
|
+
* import { reldb, schemaColumns } from '@h-ai/reldb'
|
|
1497
|
+
* const columns = await schemaColumns(reldb, 'hai_iam_users')
|
|
1498
|
+
* ```
|
|
1499
|
+
*/
|
|
1500
|
+
declare function schemaColumns(db: ReldbFunctions, table: string, sql?: DmlOperations): Promise<HaiResult<string[]>>;
|
|
1501
|
+
/**
|
|
1502
|
+
* 预检或执行模块维护的版本迁移。SQLite/PostgreSQL 原子提交;MySQL DDL 隐式提交,步骤须可重入。
|
|
1503
|
+
* 失败不记录目标版本;重启重新检查真实结构。新版本账本拒绝旧代码向下迁移。
|
|
1504
|
+
* @example
|
|
1505
|
+
* ```ts
|
|
1506
|
+
* import { reldb, migrateSchema } from '@h-ai/reldb'
|
|
1507
|
+
* const plan = await migrateSchema(reldb, 'example', [], { dryRun: true })
|
|
1508
|
+
* ```
|
|
1509
|
+
*/
|
|
1510
|
+
declare function migrateSchema(db: ReldbFunctions, module: string, steps: readonly SchemaMigration[], options?: {
|
|
1511
|
+
dryRun?: boolean;
|
|
1512
|
+
}): Promise<HaiResult<SchemaMigrationPlan>>;
|
|
1513
|
+
|
|
1423
1514
|
/**
|
|
1424
1515
|
* @h-ai/reldb — 安全工具
|
|
1425
1516
|
*
|
|
@@ -1435,14 +1526,13 @@ declare const reldb: ReldbFunctions;
|
|
|
1435
1526
|
*
|
|
1436
1527
|
* @param name - 待校验的标识符
|
|
1437
1528
|
* @returns 校验通过时返回 ok(name);不合法时返回错误 HaiResult
|
|
1438
|
-
*
|
|
1439
1529
|
* @example
|
|
1440
1530
|
* ```ts
|
|
1441
|
-
*
|
|
1442
|
-
* // result.success === true
|
|
1531
|
+
* import { validateIdentifier } from '@h-ai/reldb'
|
|
1443
1532
|
*
|
|
1444
|
-
* const
|
|
1445
|
-
*
|
|
1533
|
+
* const checked = validateIdentifier('users')
|
|
1534
|
+
* if (!checked.success) throw new Error(checked.error.message)
|
|
1535
|
+
* void checked.data
|
|
1446
1536
|
* ```
|
|
1447
1537
|
*/
|
|
1448
1538
|
declare function validateIdentifier(name: string): HaiResult<string>;
|
|
@@ -1453,6 +1543,13 @@ declare function validateIdentifier(name: string): HaiResult<string>;
|
|
|
1453
1543
|
*
|
|
1454
1544
|
* @param names - 待校验的标识符数组
|
|
1455
1545
|
* @returns 全部合法时返回 ok(undefined);否则返回第一个不合法项的错误
|
|
1546
|
+
* @example
|
|
1547
|
+
* ```ts
|
|
1548
|
+
* import { validateIdentifiers } from '@h-ai/reldb'
|
|
1549
|
+
*
|
|
1550
|
+
* const checked = validateIdentifiers(['users', 'id'])
|
|
1551
|
+
* if (!checked.success) throw new Error(checked.error.message)
|
|
1552
|
+
* ```
|
|
1456
1553
|
*/
|
|
1457
1554
|
declare function validateIdentifiers(names: string[]): HaiResult<void>;
|
|
1458
1555
|
/**
|
|
@@ -1464,11 +1561,13 @@ declare function validateIdentifiers(names: string[]): HaiResult<void>;
|
|
|
1464
1561
|
*
|
|
1465
1562
|
* @param name - 已校验的标识符
|
|
1466
1563
|
* @returns 双引号包裹的安全标识符
|
|
1467
|
-
*
|
|
1468
1564
|
* @example
|
|
1469
1565
|
* ```ts
|
|
1470
|
-
* quoteIdentifier
|
|
1471
|
-
*
|
|
1566
|
+
* import { quoteIdentifier, validateIdentifier } from '@h-ai/reldb'
|
|
1567
|
+
*
|
|
1568
|
+
* const checked = validateIdentifier('order')
|
|
1569
|
+
* if (!checked.success) throw new Error(checked.error.message)
|
|
1570
|
+
* void quoteIdentifier(checked.data)
|
|
1472
1571
|
* ```
|
|
1473
1572
|
*/
|
|
1474
1573
|
declare function quoteIdentifier(name: string): string;
|
|
@@ -1480,13 +1579,13 @@ declare function quoteIdentifier(name: string): string;
|
|
|
1480
1579
|
*
|
|
1481
1580
|
* @param value - 原始字符串
|
|
1482
1581
|
* @returns 转义后的安全字符串
|
|
1483
|
-
*
|
|
1484
1582
|
* @example
|
|
1485
1583
|
* ```ts
|
|
1486
|
-
* escapeSqlString
|
|
1487
|
-
*
|
|
1584
|
+
* import { escapeSqlString } from '@h-ai/reldb'
|
|
1585
|
+
*
|
|
1586
|
+
* void escapeSqlString("it's") // it''s;仅用于可信 DDL 字面量,业务值使用占位符。
|
|
1488
1587
|
* ```
|
|
1489
1588
|
*/
|
|
1490
1589
|
declare function escapeSqlString(value: string): string;
|
|
1491
1590
|
|
|
1492
|
-
export { BaseReldbCrudRepository, type BaseReldbCrudRepositoryConfig, type ColumnType, type CrudConfig, type CrudManager, type CrudPageOptions, type CrudQueryOptions,
|
|
1591
|
+
export { BaseReldbCrudRepository, type BaseReldbCrudRepositoryConfig, type ColumnType, type CrudConfig, type CrudManager, type CrudPageOptions, type CrudQueryOptions, DbType, type DdlOperations, type DmlOperations, type DmlWithTxOperations, type ExecuteResult, HaiReldbError, type JsonSqlExpr, type NormalizedPagination, type PaginationOverrides, type PaginationQueryOptions, type QueryRow, type ReldbColumnDef, ReldbConfig, ReldbConfigInput, type ReldbCrudCountOptions, type ReldbCrudFieldDefinition, type ReldbCrudRepository, type ReldbFunctions, type ReldbIndexDef, type ReldbJsonOps, type ReldbTableDef, type SchemaMigration, type SchemaMigrationPlan, type TxManager, type TxWrapCallback, createJsonOps, escapeSqlString, migrateSchema, parseJsonPath, quoteIdentifier, reldb, schemaColumns, validateIdentifier, validateIdentifiers };
|