@h-ai/reldb 0.1.0-alpha5

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.
@@ -0,0 +1,1492 @@
1
+ import { z } from 'zod';
2
+ import * as _h_ai_core from '@h-ai/core';
3
+ 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>;
287
+
288
+ /**
289
+ * @h-ai/reldb — JSON 操作 SQL 构建器
290
+ *
291
+ * 为不同数据库后端提供统一的 JSON 路径操作 SQL 表达式构建能力。
292
+ * 路径格式遵循 SQL/JSON Path 标准(`$.key` / `$.key.subkey` / `$[0]`)。
293
+ *
294
+ * 各数据库后端映射:
295
+ *
296
+ * | 操作 | SQLite | PostgreSQL | MySQL |
297
+ * |---------|----------------------|-------------------------------|-----------------------------|
298
+ * | extract | json_extract | #> (text[]) | JSON_EXTRACT |
299
+ * | set | json_set + json() | jsonb_set + ::jsonb | JSON_SET + CAST AS JSON |
300
+ * | insert | json_insert + json() | jsonb_insert + ::jsonb | JSON_INSERT + CAST AS JSON |
301
+ * | remove | json_remove | #- (text[]) | JSON_REMOVE |
302
+ * | merge | json_patch | \|\| ::jsonb | JSON_MERGE_PATCH + CAST |
303
+ *
304
+ * @module reldb-json
305
+ */
306
+ /**
307
+ * JSON SQL 表达式结果
308
+ *
309
+ * 包含可嵌入 SQL 语句的表达式片段与对应参数列表。
310
+ * 参数占位符统一使用 `?`,各 Provider 会在执行前自动转换。
311
+ *
312
+ * @example
313
+ * ```ts
314
+ * const { sql, params } = reldb.json.set('settings', '$.theme', 'dark')
315
+ * // 将 sql 和 params 嵌入到完整 SQL 中执行
316
+ * await reldb.sql.execute(
317
+ * `UPDATE users SET settings = ${sql} WHERE id = ?`,
318
+ * [...params, userId],
319
+ * )
320
+ * ```
321
+ */
322
+ interface JsonSqlExpr {
323
+ /** SQL 表达式片段(含 ? 占位符) */
324
+ sql: string;
325
+ /** 参数列表(对应 ? 占位符,顺序与 sql 中出现顺序一致) */
326
+ params: unknown[];
327
+ }
328
+ /**
329
+ * JSON 操作接口
330
+ *
331
+ * 提供跨数据库统一的 JSON 路径操作 SQL 构建能力。
332
+ * 所有方法返回 `JsonSqlExpr`,可嵌入 `reldb.sql.query` / `reldb.sql.execute` 等调用。
333
+ *
334
+ * 路径格式:遵循 SQL/JSON Path 标准,以 `$` 开头:
335
+ * - 对象字段:`$.key`、`$.key.subkey`
336
+ * - 数组元素:`$[0]`、`$.items[1]`
337
+ *
338
+ * @example
339
+ * ```ts
340
+ * // 提取 JSON 字段值(用于 SELECT 或 WHERE)
341
+ * const { sql, params } = reldb.json.extract('settings', '$.theme')
342
+ * const rows = await reldb.sql.query(
343
+ * `SELECT * FROM users WHERE ${sql} = ?`,
344
+ * [...params, '"dark"'],
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
+ * )
353
+ * ```
354
+ */
355
+ interface ReldbJsonOps {
356
+ /**
357
+ * JSON 路径提取表达式
358
+ *
359
+ * 提取 JSON 列中指定路径的值,返回 JSON 类型的值。
360
+ * 可用于 SELECT 列表、WHERE 条件或 ORDER BY。
361
+ *
362
+ * @param column - 列名(或 SQL 列表达式,开发者负责安全性,禁止传入用户输入)
363
+ * @param path - JSON 路径(如 `$.status`、`$.user.name`、`$[0]`)
364
+ * @returns SQL 表达式与参数
365
+ *
366
+ * @example
367
+ * ```ts
368
+ * const { sql, params } = reldb.json.extract('data', '$.status')
369
+ * // SQLite: sql = "json_extract(data, ?)", params = ["$.status"]
370
+ * // PostgreSQL: sql = "data #> ?::text[]", params = [["status"]]
371
+ * // MySQL: sql = "JSON_EXTRACT(data, ?)", params = ["$.status"]
372
+ * ```
373
+ */
374
+ extract: (column: string, path: string) => JsonSqlExpr;
375
+ /**
376
+ * JSON 路径设置表达式(创建或替换)
377
+ *
378
+ * 在 JSON 列的指定路径设置新值。若路径不存在则创建,若已存在则替换。
379
+ * 返回修改后的完整 JSON 值,通常用于 `UPDATE SET col = ...`。
380
+ *
381
+ * @param column - 列名(开发者负责安全性,禁止传入用户输入)
382
+ * @param path - JSON 路径
383
+ * @param value - 要设置的值(支持任意 JSON 兼容类型)
384
+ * @returns SQL 表达式与参数
385
+ *
386
+ * @example
387
+ * ```ts
388
+ * const { sql, params } = reldb.json.set('settings', '$.theme', 'dark')
389
+ * await reldb.sql.execute(
390
+ * `UPDATE users SET settings = ${sql} WHERE id = ?`,
391
+ * [...params, id],
392
+ * )
393
+ * ```
394
+ */
395
+ set: (column: string, path: string, value: unknown) => JsonSqlExpr;
396
+ /**
397
+ * JSON 路径插入表达式(仅当路径不存在时)
398
+ *
399
+ * 仅在指定路径不存在时插入新值,已存在的路径不会被覆盖。
400
+ * 返回修改后的完整 JSON 值。
401
+ *
402
+ * @param column - 列名(开发者负责安全性,禁止传入用户输入)
403
+ * @param path - JSON 路径
404
+ * @param value - 要插入的值
405
+ * @returns SQL 表达式与参数
406
+ *
407
+ * @example
408
+ * ```ts
409
+ * const { sql, params } = reldb.json.insert('data', '$.newField', 'value')
410
+ * await reldb.sql.execute(
411
+ * `UPDATE items SET data = ${sql} WHERE id = ?`,
412
+ * [...params, id],
413
+ * )
414
+ * ```
415
+ */
416
+ insert: (column: string, path: string, value: unknown) => JsonSqlExpr;
417
+ /**
418
+ * JSON 路径删除表达式
419
+ *
420
+ * 从 JSON 列中移除指定路径对应的键或数组元素。
421
+ * 返回删除后的完整 JSON 值。
422
+ *
423
+ * @param column - 列名(开发者负责安全性,禁止传入用户输入)
424
+ * @param path - JSON 路径
425
+ * @returns SQL 表达式与参数
426
+ *
427
+ * @example
428
+ * ```ts
429
+ * const { sql, params } = reldb.json.remove('settings', '$.deprecated')
430
+ * await reldb.sql.execute(
431
+ * `UPDATE users SET settings = ${sql} WHERE id = ?`,
432
+ * [...params, id],
433
+ * )
434
+ * ```
435
+ */
436
+ remove: (column: string, path: string) => JsonSqlExpr;
437
+ /**
438
+ * JSON 合并/补丁表达式(RFC 7396 Merge Patch)
439
+ *
440
+ * 将 patch 对象合并到 JSON 列:
441
+ * - patch 中存在的键:覆盖原值
442
+ * - patch 中值为 null 的键:删除原键
443
+ * - patch 中不存在的键:保持不变
444
+ *
445
+ * 返回合并后的完整 JSON 值,通常用于 `UPDATE SET col = ...`。
446
+ *
447
+ * @param column - 列名(开发者负责安全性,禁止传入用户输入)
448
+ * @param patch - 要合并的 JSON 对象
449
+ * @returns SQL 表达式与参数
450
+ *
451
+ * @example
452
+ * ```ts
453
+ * const { sql, params } = reldb.json.merge('profile', { bio: 'new bio', avatar: null })
454
+ * await reldb.sql.execute(
455
+ * `UPDATE users SET profile = ${sql} WHERE id = ?`,
456
+ * [...params, id],
457
+ * )
458
+ * ```
459
+ */
460
+ merge: (column: string, patch: Record<string, unknown>) => JsonSqlExpr;
461
+ }
462
+ /**
463
+ * 解析 JSON Path 为路径段数组
464
+ *
465
+ * 将 `$.key.subkey[0]` 格式的路径解析为 `['key', 'subkey', '0']`。
466
+ *
467
+ * @param path - JSON 路径(以 `$` 开头)
468
+ * @returns 路径段数组
469
+ *
470
+ * @example
471
+ * ```ts
472
+ * parseJsonPath('$.user.name') // ['user', 'name']
473
+ * parseJsonPath('$.items[0]') // ['items', '0']
474
+ * parseJsonPath('$[1]') // ['1']
475
+ * ```
476
+ */
477
+ declare function parseJsonPath(path: string): string[];
478
+ /**
479
+ * 创建指定数据库类型的 JSON 操作实例
480
+ *
481
+ * @param dbType - 数据库类型(来自 `reldb.config?.type`)
482
+ * @returns JSON 操作实例
483
+ *
484
+ * @example
485
+ * ```ts
486
+ * // 通过 reldb.json 直接使用(推荐)
487
+ * const { sql, params } = reldb.json.extract('data', '$.key')
488
+ *
489
+ * // 手动创建(用于测试或特殊场景)
490
+ * const jsonOps = createJsonOps('sqlite')
491
+ * const { sql, params } = jsonOps.set('data', '$.key', 'value')
492
+ * ```
493
+ */
494
+ declare function createJsonOps(dbType: 'sqlite' | 'postgresql' | 'mysql'): ReldbJsonOps;
495
+
496
+ declare const HaiReldbError: {
497
+ CONNECTION_FAILED: _h_ai_core.HaiErrorDef;
498
+ QUERY_FAILED: _h_ai_core.HaiErrorDef;
499
+ CONSTRAINT_VIOLATION: _h_ai_core.HaiErrorDef;
500
+ TRANSACTION_FAILED: _h_ai_core.HaiErrorDef;
501
+ MIGRATION_FAILED: _h_ai_core.HaiErrorDef;
502
+ RECORD_NOT_FOUND: _h_ai_core.HaiErrorDef;
503
+ DUPLICATE_ENTRY: _h_ai_core.HaiErrorDef;
504
+ DEADLOCK: _h_ai_core.HaiErrorDef;
505
+ TIMEOUT: _h_ai_core.HaiErrorDef;
506
+ POOL_EXHAUSTED: _h_ai_core.HaiErrorDef;
507
+ NOT_INITIALIZED: _h_ai_core.HaiErrorDef;
508
+ DDL_FAILED: _h_ai_core.HaiErrorDef;
509
+ UNSUPPORTED_TYPE: _h_ai_core.HaiErrorDef;
510
+ CONFIG_ERROR: _h_ai_core.HaiErrorDef;
511
+ };
512
+ /**
513
+ * 列数据类型
514
+ *
515
+ * 统一的列类型定义,会根据不同数据库自动映射:
516
+ *
517
+ * | 类型 | SQLite | PostgreSQL | MySQL |
518
+ * |------------|---------|------------------|--------------|
519
+ * | TEXT | TEXT | TEXT | VARCHAR(255) |
520
+ * | INTEGER | INTEGER | INTEGER/SERIAL | INT/BIGINT |
521
+ * | REAL | REAL | DOUBLE PRECISION | DOUBLE |
522
+ * | BLOB | BLOB | BYTEA | BLOB |
523
+ * | BOOLEAN | INTEGER | BOOLEAN | TINYINT(1) |
524
+ * | TIMESTAMP | INTEGER | TIMESTAMP | DATETIME |
525
+ * | JSON | TEXT | JSONB | JSON |
526
+ *
527
+ * 注:MySQL 将 TEXT 映射为 VARCHAR(255) 以支持索引和 UNIQUE 约束。
528
+ * INTEGER 在 MySQL autoIncrement 时映射为 BIGINT,否则映射为 INT。
529
+ */
530
+ type ColumnType = 'TEXT' | 'INTEGER' | 'REAL' | 'BLOB' | 'BOOLEAN' | 'TIMESTAMP' | 'JSON';
531
+ /**
532
+ * 列定义接口
533
+ *
534
+ * 用于定义表的列结构。
535
+ *
536
+ * @example
537
+ * ```ts
538
+ * // 主键列
539
+ * const idColumn: ReldbColumnDef = {
540
+ * type: 'INTEGER',
541
+ * primaryKey: true,
542
+ * autoIncrement: true
543
+ * }
544
+ *
545
+ * // 带外键的列
546
+ * const userIdColumn: ReldbColumnDef = {
547
+ * type: 'INTEGER',
548
+ * notNull: true,
549
+ * references: {
550
+ * table: 'users',
551
+ * column: 'id',
552
+ * onDelete: 'CASCADE'
553
+ * }
554
+ * }
555
+ * ```
556
+ */
557
+ interface ReldbColumnDef {
558
+ /** 列数据类型 */
559
+ type: ColumnType;
560
+ /** 是否为主键 */
561
+ primaryKey?: boolean;
562
+ /** 是否自增(仅主键有效) */
563
+ autoIncrement?: boolean;
564
+ /** 是否非空 */
565
+ notNull?: boolean;
566
+ /** 默认值(支持字符串、数字、布尔、null) */
567
+ defaultValue?: string | number | boolean | null;
568
+ /** 是否唯一 */
569
+ unique?: boolean;
570
+ /** 外键引用 */
571
+ references?: {
572
+ /** 引用的表名 */
573
+ table: string;
574
+ /** 引用的列名 */
575
+ column: string;
576
+ /** 删除时的行为 */
577
+ onDelete?: 'CASCADE' | 'SET NULL' | 'RESTRICT' | 'NO ACTION';
578
+ /** 更新时的行为 */
579
+ onUpdate?: 'CASCADE' | 'SET NULL' | 'RESTRICT' | 'NO ACTION';
580
+ };
581
+ }
582
+ /**
583
+ * 表定义(列名到列定义的映射)
584
+ *
585
+ * @example
586
+ * ```ts
587
+ * const userTable: ReldbTableDef = {
588
+ * id: { type: 'INTEGER', primaryKey: true, autoIncrement: true },
589
+ * name: { type: 'TEXT', notNull: true },
590
+ * email: { type: 'TEXT', unique: true },
591
+ * created_at: { type: 'TIMESTAMP', defaultValue: 'NOW()' }
592
+ * }
593
+ * ```
594
+ */
595
+ interface ReldbTableDef {
596
+ [columnName: string]: ReldbColumnDef;
597
+ }
598
+ /**
599
+ * 索引定义
600
+ *
601
+ * @example
602
+ * ```ts
603
+ * // 普通索引
604
+ * const emailIndex: ReldbIndexDef = { columns: ['email'] }
605
+ *
606
+ * // 唯一复合索引
607
+ * const compositeIndex: ReldbIndexDef = {
608
+ * columns: ['user_id', 'created_at'],
609
+ * unique: true
610
+ * }
611
+ *
612
+ * // 部分索引(带条件)
613
+ * const partialIndex: ReldbIndexDef = {
614
+ * columns: ['status'],
615
+ * where: "status = 'active'"
616
+ * }
617
+ * ```
618
+ */
619
+ interface ReldbIndexDef {
620
+ /** 索引包含的列 */
621
+ columns: string[];
622
+ /** 是否为唯一索引 */
623
+ unique?: boolean;
624
+ /**
625
+ * 索引条件(WHERE 子句,用于部分索引)
626
+ *
627
+ * **⚠️ 安全警告:** `where` 为原始 SQL 片段,不会经过参数化处理,
628
+ * **禁止**将用户输入直接拼接。仅用于开发者编写的静态条件。
629
+ */
630
+ where?: string;
631
+ }
632
+ /**
633
+ * DDL(数据定义语言)操作接口
634
+ *
635
+ * 提供表结构管理功能,包括创建/删除表、添加/删除列、创建索引等。
636
+ * 所有操作返回 `HaiResult<void>` 类型。
637
+ *
638
+ * @example
639
+ * ```ts
640
+ * // 创建表
641
+ * const result = await reldb.ddl.createTable('users', {
642
+ * id: { type: 'INTEGER', primaryKey: true, autoIncrement: true },
643
+ * name: { type: 'TEXT', notNull: true }
644
+ * })
645
+ *
646
+ * if (!result.success) {
647
+ * // 处理错误:创建表失败(可根据 result.error.code / message 做兜底)
648
+ * }
649
+ * ```
650
+ */
651
+ interface DdlOperations {
652
+ /**
653
+ * 创建表
654
+ * @param tableName - 表名
655
+ * @param columns - 列定义
656
+ * @param ifNotExists - 是否使用 IF NOT EXISTS(默认 true)
657
+ * @example
658
+ * ```ts
659
+ * const result = await reldb.ddl.createTable('users', {
660
+ * id: { type: 'INTEGER', primaryKey: true, autoIncrement: true },
661
+ * name: { type: 'TEXT', notNull: true }
662
+ * })
663
+ * if (!result.success) {
664
+ * // 创建失败:根据 result.error.code / message 处理
665
+ * }
666
+ * ```
667
+ */
668
+ createTable: (tableName: string, columns: ReldbTableDef, ifNotExists?: boolean) => Promise<HaiResult<void>>;
669
+ /**
670
+ * 删除表
671
+ * @param tableName - 表名
672
+ * @param ifExists - 是否使用 IF EXISTS(默认 true)
673
+ * @example
674
+ * ```ts
675
+ * await reldb.ddl.dropTable('users')
676
+ * await reldb.ddl.dropTable('users_backup', false)
677
+ * ```
678
+ */
679
+ dropTable: (tableName: string, ifExists?: boolean) => Promise<HaiResult<void>>;
680
+ /**
681
+ * 添加列
682
+ * @param tableName - 表名
683
+ * @param columnName - 列名
684
+ * @param columnDef - 列定义
685
+ * @example
686
+ * ```ts
687
+ * await reldb.ddl.addColumn('users', 'age', { type: 'INTEGER' })
688
+ * await reldb.ddl.addColumn('users', 'email', { type: 'TEXT', unique: true })
689
+ * ```
690
+ */
691
+ addColumn: (tableName: string, columnName: string, columnDef: ReldbColumnDef) => Promise<HaiResult<void>>;
692
+ /**
693
+ * 删除列
694
+ * @param tableName - 表名
695
+ * @param columnName - 列名
696
+ * @example
697
+ * ```ts
698
+ * await reldb.ddl.dropColumn('users', 'legacy_field')
699
+ * ```
700
+ */
701
+ dropColumn: (tableName: string, columnName: string) => Promise<HaiResult<void>>;
702
+ /**
703
+ * 重命名表
704
+ * @param oldName - 原表名
705
+ * @param newName - 新表名
706
+ * @example
707
+ * ```ts
708
+ * await reldb.ddl.renameTable('users_temp', 'users')
709
+ * ```
710
+ */
711
+ renameTable: (oldName: string, newName: string) => Promise<HaiResult<void>>;
712
+ /**
713
+ * 创建索引
714
+ * @param tableName - 表名
715
+ * @param indexName - 索引名
716
+ * @param indexDef - 索引定义
717
+ * @example
718
+ * ```ts
719
+ * await reldb.ddl.createIndex('users', 'idx_users_email', {
720
+ * columns: ['email'],
721
+ * unique: true,
722
+ * })
723
+ * ```
724
+ */
725
+ createIndex: (tableName: string, indexName: string, indexDef: ReldbIndexDef) => Promise<HaiResult<void>>;
726
+ /**
727
+ * 删除索引
728
+ * @param indexName - 索引名
729
+ * @param ifExists - 是否使用 IF EXISTS(默认 true)
730
+ * @example
731
+ * ```ts
732
+ * await reldb.ddl.dropIndex('idx_users_email')
733
+ * ```
734
+ */
735
+ dropIndex: (indexName: string, ifExists?: boolean) => Promise<HaiResult<void>>;
736
+ /**
737
+ * 执行原始 DDL SQL
738
+ *
739
+ * **⚠️ 安全警告:** `sql` 参数不会经过标识符校验或参数化处理,
740
+ * **禁止**将用户输入直接拼接到 SQL 中,否则会导致 SQL 注入风险。
741
+ * 仅用于开发者编写的静态 DDL 语句(如 ALTER TABLE)。
742
+ *
743
+ * @param sql - DDL SQL 语句(必须为开发者静态构造,禁止包含用户输入)
744
+ * @example
745
+ * ```ts
746
+ * // ✅ 安全:静态 SQL
747
+ * await reldb.ddl.raw('ALTER TABLE users ADD COLUMN status TEXT')
748
+ *
749
+ * // ❌ 危险:拼接用户输入
750
+ * await reldb.ddl.raw(`ALTER TABLE ${userInput} ADD COLUMN status TEXT`)
751
+ * ```
752
+ */
753
+ raw: (sql: string) => Promise<HaiResult<void>>;
754
+ }
755
+ /**
756
+ * 查询结果行类型
757
+ *
758
+ * 约定为键值对象,字段名与 SQL 返回列一致。
759
+ */
760
+ type QueryRow = Record<string, unknown>;
761
+ /**
762
+ * 执行结果
763
+ *
764
+ * INSERT/UPDATE/DELETE 操作返回的结果。
765
+ */
766
+ interface ExecuteResult {
767
+ /** 影响的行数 */
768
+ changes: number;
769
+ /** 最后插入的行 ID(仅 INSERT 时有效) */
770
+ lastInsertRowid?: number | bigint;
771
+ }
772
+ /**
773
+ * 规范化后的分页参数
774
+ */
775
+ interface NormalizedPagination extends PaginationOptions {
776
+ /** SQL offset */
777
+ offset: number;
778
+ /** SQL limit */
779
+ limit: number;
780
+ }
781
+ /**
782
+ * 分页参数覆盖
783
+ */
784
+ interface PaginationOverrides {
785
+ /** 默认页码 */
786
+ defaultPage?: number;
787
+ /** 默认每页数量 */
788
+ defaultPageSize?: number;
789
+ /** 最大每页数量 */
790
+ maxPageSize?: number;
791
+ }
792
+ /**
793
+ * 分页查询参数
794
+ */
795
+ interface PaginationQueryOptions {
796
+ /** 数据查询 SQL(不含 LIMIT/OFFSET) */
797
+ sql: string;
798
+ /** 参数列表 */
799
+ params?: unknown[];
800
+ /** 分页参数 */
801
+ pagination?: PaginationOptionsInput;
802
+ /** 覆盖默认分页参数 */
803
+ overrides?: PaginationOverrides;
804
+ }
805
+ /**
806
+ * 数据读写操作接口(SQL / 事务共享)
807
+ */
808
+ interface DmlOperations {
809
+ /** 查询多行 */
810
+ query: <T = QueryRow>(sql: string, params?: unknown[]) => Promise<HaiResult<T[]>>;
811
+ /** 查询单行 */
812
+ get: <T = QueryRow>(sql: string, params?: unknown[]) => Promise<HaiResult<T | null>>;
813
+ /** 执行修改语句(INSERT/UPDATE/DELETE) */
814
+ execute: (sql: string, params?: unknown[]) => Promise<HaiResult<ExecuteResult>>;
815
+ /** 批量执行多条语句(在同一事务上下文中) */
816
+ batch: (statements: Array<{
817
+ sql: string;
818
+ params?: unknown[];
819
+ }>) => Promise<HaiResult<void>>;
820
+ /** 分页查询 */
821
+ queryPage: <T = QueryRow>(options: PaginationQueryOptions) => Promise<HaiResult<PaginatedResult<T>>>;
822
+ }
823
+ /** CRUD 查询条件 */
824
+ interface CrudQueryOptions {
825
+ /**
826
+ * WHERE 子句(不包含 WHERE 关键字)
827
+ *
828
+ * **⚠️ 安全警告:** `where` 为原始 SQL 片段,**禁止**将用户输入直接拼接。
829
+ * 动态值必须通过 `params` 占位符(`?`)传入。
830
+ *
831
+ * @example
832
+ * ```ts
833
+ * // ✅ 安全:占位符 + params
834
+ * crud.findAll({ where: 'status = ? AND age > ?', params: ['active', 18] })
835
+ *
836
+ * // ❌ 危险:拼接用户输入
837
+ * crud.findAll({ where: `name = '${userInput}'` })
838
+ * ```
839
+ */
840
+ where?: string;
841
+ /** 参数列表 */
842
+ params?: unknown[];
843
+ /** ORDER BY 子句(不包含 ORDER BY 关键字) */
844
+ orderBy?: string;
845
+ /** LIMIT */
846
+ limit?: number;
847
+ /** OFFSET */
848
+ offset?: number;
849
+ }
850
+ /** CRUD 分页查询条件 */
851
+ interface CrudPageOptions {
852
+ /**
853
+ * WHERE 子句(不包含 WHERE 关键字)
854
+ *
855
+ * **⚠️ 安全警告:** `where` 为原始 SQL 片段,**禁止**将用户输入直接拼接。
856
+ * 动态值必须通过 `params` 占位符(`?`)传入。
857
+ */
858
+ where?: string;
859
+ /** 参数列表 */
860
+ params?: unknown[];
861
+ /** ORDER BY 子句(不包含 ORDER BY 关键字) */
862
+ orderBy?: string;
863
+ /** 分页参数 */
864
+ pagination?: PaginationOptionsInput;
865
+ /** 分页参数覆盖 */
866
+ overrides?: PaginationOverrides;
867
+ }
868
+ /** CRUD 统计条件 */
869
+ interface ReldbCrudCountOptions {
870
+ /**
871
+ * WHERE 子句(不包含 WHERE 关键字)
872
+ *
873
+ * **⚠️ 安全警告:** `where` 为原始 SQL 片段,**禁止**将用户输入直接拼接。
874
+ * 动态值必须通过 `params` 占位符(`?`)传入。
875
+ */
876
+ where?: string;
877
+ /** 参数列表 */
878
+ params?: unknown[];
879
+ }
880
+ /** CRUD 配置 */
881
+ interface CrudConfig<TItem> {
882
+ /** 表名 */
883
+ table: string;
884
+ /** 主键列名(默认 id) */
885
+ idColumn?: string;
886
+ /** 查询列(默认 *) */
887
+ select?: string[];
888
+ /** 允许插入的列(不填则使用数据本身列) */
889
+ createColumns?: string[];
890
+ /** 允许更新的列(不填则使用数据本身列) */
891
+ updateColumns?: string[];
892
+ /** 行映射函数(可选) */
893
+ mapRow?: (row: QueryRow) => TItem;
894
+ /** 数据库类型 */
895
+ dbType: DbType;
896
+ }
897
+ /** CRUD 字段定义 */
898
+ interface ReldbCrudFieldDefinition {
899
+ /** 对象字段名 */
900
+ fieldName: string;
901
+ /** 数据库列名 */
902
+ columnName: string;
903
+ /** 列定义 */
904
+ def: ReldbColumnDef;
905
+ /** 是否用于查询 */
906
+ select: boolean;
907
+ /** 是否允许插入 */
908
+ create: boolean;
909
+ /** 是否允许更新 */
910
+ update: boolean;
911
+ }
912
+ /** BaseReldbCrudRepository 配置 */
913
+ interface BaseReldbCrudRepositoryConfig<TItem> {
914
+ /** 表名 */
915
+ table: string;
916
+ /** 字段定义 */
917
+ fields: ReldbCrudFieldDefinition[];
918
+ /** 主键列名(默认 id) */
919
+ idColumn?: string;
920
+ /** 主键字段名(默认与 idColumn 相同) */
921
+ idField?: keyof TItem & string;
922
+ /** 是否自动创建表(默认 true) */
923
+ createTableIfNotExists?: boolean;
924
+ /** 主键生成策略(未提供则尝试使用 crypto.randomUUID) */
925
+ generateId?: () => string | number;
926
+ /** 当前时间提供者(默认 Date.now) */
927
+ nowProvider?: () => number;
928
+ }
929
+ /** CRUD 仓库接口 */
930
+ interface ReldbCrudRepository<TItem> {
931
+ create: (data: Record<string, unknown>, tx?: DmlWithTxOperations) => Promise<HaiResult<ExecuteResult>>;
932
+ createMany: (items: Array<Record<string, unknown>>, tx?: DmlWithTxOperations) => Promise<HaiResult<void>>;
933
+ createOrUpdate: (data: Record<string, unknown>, tx?: DmlWithTxOperations) => Promise<HaiResult<ExecuteResult>>;
934
+ findById: (id: unknown, tx?: DmlWithTxOperations) => Promise<HaiResult<TItem | null>>;
935
+ getById: (id: unknown, tx?: DmlWithTxOperations) => Promise<HaiResult<TItem>>;
936
+ findAll: (options?: CrudQueryOptions, tx?: DmlWithTxOperations) => Promise<HaiResult<TItem[]>>;
937
+ findPage: (options: CrudPageOptions, tx?: DmlWithTxOperations) => Promise<HaiResult<PaginatedResult<TItem>>>;
938
+ updateById: (id: unknown, data: Record<string, unknown>, tx?: DmlWithTxOperations) => Promise<HaiResult<ExecuteResult>>;
939
+ deleteById: (id: unknown, tx?: DmlWithTxOperations) => Promise<HaiResult<ExecuteResult>>;
940
+ count: (options?: ReldbCrudCountOptions, tx?: DmlWithTxOperations) => Promise<HaiResult<number>>;
941
+ exists: (options?: ReldbCrudCountOptions, tx?: DmlWithTxOperations) => Promise<HaiResult<boolean>>;
942
+ existsById: (id: unknown, tx?: DmlWithTxOperations) => Promise<HaiResult<boolean>>;
943
+ }
944
+ /** CRUD 管理器(统一入口) */
945
+ interface CrudManager {
946
+ /** 获取单表 CRUD 仓库 */
947
+ table: <TItem>(config: CrudConfig<TItem>) => ReldbCrudRepository<TItem>;
948
+ }
949
+ /**
950
+ * 事务句柄接口(分步事务)
951
+ */
952
+ interface DmlWithTxOperations extends DmlOperations {
953
+ /** CRUD 管理器 */
954
+ crud: CrudManager;
955
+ /** 提交事务 */
956
+ commit: () => Promise<HaiResult<void>>;
957
+ /** 回滚事务 */
958
+ rollback: () => Promise<HaiResult<void>>;
959
+ }
960
+ /**
961
+ * 事务回调函数类型
962
+ *
963
+ * @param tx - 事务内操作对象
964
+ * @returns 业务返回值(将被包装为 HaiResult)
965
+ * @example
966
+ * ```ts
967
+ * const result = await reldb.tx.wrap(async (tx) => {
968
+ * await tx.execute('INSERT INTO users (name) VALUES (?)', ['用户A'])
969
+ * return await tx.get('SELECT * FROM users WHERE name = ?', ['用户A'])
970
+ * })
971
+ * ```
972
+ */
973
+ type TxWrapCallback<T> = (tx: DmlWithTxOperations) => Promise<T>;
974
+ /**
975
+ * 事务管理器
976
+ */
977
+ interface TxManager {
978
+ /** 开启事务(分步事务) */
979
+ begin: () => Promise<HaiResult<DmlWithTxOperations>>;
980
+ /** 包裹事务(自动提交/回滚) */
981
+ wrap: <T>(fn: TxWrapCallback<T>) => Promise<HaiResult<T>>;
982
+ }
983
+ /**
984
+ * 数据库函数接口
985
+ *
986
+ * 统一的数据库访问入口,通过 `reldb` 对象提供所有数据库操作。
987
+ *
988
+ * @example
989
+ * ```ts
990
+ * import { reldb } from '@h-ai/reldb'
991
+ *
992
+ * // 初始化
993
+ * await reldb.init({ type: 'sqlite', database: ':memory:' })
994
+ *
995
+ * // 检查状态
996
+ * if (reldb.isInitialized) {
997
+ * // 可读取当前数据库类型:reldb.config?.type
998
+ * }
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
+ * ```
1012
+ */
1013
+ interface ReldbFunctions {
1014
+ /**
1015
+ * 初始化数据库连接
1016
+ *
1017
+ * @param config - 数据库配置
1018
+ * @returns 初始化结果
1019
+ */
1020
+ init: (config: ReldbConfigInput) => Promise<HaiResult<void>>;
1021
+ /** DDL 操作(表结构管理) */
1022
+ readonly ddl: DdlOperations;
1023
+ /** SQL 操作(数据查询和修改) */
1024
+ readonly sql: DmlOperations;
1025
+ /** CRUD 管理器 */
1026
+ readonly crud: CrudManager;
1027
+ /** 事务管理器 */
1028
+ readonly tx: TxManager;
1029
+ /** 当前数据库配置(未初始化时为 null) */
1030
+ readonly config: ReldbConfig | null;
1031
+ /** 是否已初始化 */
1032
+ readonly isInitialized: boolean;
1033
+ /** 分页工具 */
1034
+ readonly pagination: {
1035
+ /** 规范化分页参数 */
1036
+ normalize: (options?: PaginationOptionsInput, overrides?: PaginationOverrides) => NormalizedPagination;
1037
+ /** 构建分页结果 */
1038
+ build: <T>(items: T[], total: number, pagination: PaginationOptions) => PaginatedResult<T>;
1039
+ };
1040
+ /**
1041
+ * JSON 操作 SQL 构建器
1042
+ *
1043
+ * 提供跨数据库统一的 JSON 路径操作(提取、设置、插入、删除、合并)。
1044
+ * 返回的 SQL 片段可嵌入 `reldb.sql.query` / `reldb.sql.execute` 等调用。
1045
+ *
1046
+ * 未初始化时默认返回 SQLite 格式的构建器;初始化后自动匹配当前数据库类型。
1047
+ *
1048
+ * @example
1049
+ * ```ts
1050
+ * // 提取 JSON 字段值(用于 WHERE 条件)
1051
+ * const { sql, params } = reldb.json.extract('settings', '$.theme')
1052
+ * const rows = await reldb.sql.query(
1053
+ * `SELECT * FROM users WHERE ${sql} = ?`,
1054
+ * [...params, '"dark"'],
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
+ * )
1063
+ * ```
1064
+ */
1065
+ readonly json: ReldbJsonOps;
1066
+ /** 关闭数据库连接 */
1067
+ close: () => Promise<HaiResult<void>>;
1068
+ }
1069
+ /**
1070
+ * 数据库 Provider 接口
1071
+ *
1072
+ * 内部使用,定义各数据库驱动需要实现的接口。
1073
+ * 每个数据库类型(SQLite、PostgreSQL、MySQL)都有对应的 Provider 实现。
1074
+ */
1075
+ interface ReldbProvider {
1076
+ /** DDL 操作(表结构管理) */
1077
+ readonly ddl: DdlOperations;
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
+ /** 关闭连接 */
1087
+ close: () => Promise<HaiResult<void>>;
1088
+ /** 是否已连接 */
1089
+ isConnected: () => boolean;
1090
+ }
1091
+
1092
+ /**
1093
+ * @h-ai/reldb — CRUD 仓库基类
1094
+ *
1095
+ * 提供 `BaseReldbCrudRepository` 抽象基类,供业务仓库继承复用。
1096
+ * @module reldb-crud-repository
1097
+ */
1098
+
1099
+ /**
1100
+ * CRUD 仓库基类
1101
+ *
1102
+ * 提供通用的单表 CRUD 操作封装,业务仓库可继承该类实现自定义逻辑。
1103
+ *
1104
+ * 核心能力:
1105
+ * - 自动建表(默认开启,可通过 `createTableIfNotExists: false` 关闭)
1106
+ * - 字段级别的权限控制(select / create / update 分别配置)
1107
+ * - 自动填充主键、createdAt、updatedAt
1108
+ * - 跨数据库类型值转换(BOOLEAN / TIMESTAMP / JSON)
1109
+ * - 支持事务上下文(所有方法均接受可选 tx 参数)
1110
+ *
1111
+ * @example
1112
+ * ```ts
1113
+ * class UserRepository extends BaseReldbCrudRepository<User> {
1114
+ * constructor(db: ReldbFunctions) {
1115
+ * super(db, {
1116
+ * table: 'users',
1117
+ * fields: [
1118
+ * { fieldName: 'id', columnName: 'id', def: { type: 'INTEGER', primaryKey: true, autoIncrement: true }, select: true, create: false, update: false },
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
+ * })
1123
+ * }
1124
+ * }
1125
+ * ```
1126
+ */
1127
+ declare abstract class BaseReldbCrudRepository<TItem> implements ReldbCrudRepository<TItem> {
1128
+ /** 底层 CRUD 仓库实例(基于 reldb-crud-kernel 创建) */
1129
+ protected readonly crud: ReldbCrudRepository<TItem>;
1130
+ /** 数据库服务对象 */
1131
+ protected readonly db: ReldbFunctions;
1132
+ /** 字段定义列表 */
1133
+ private readonly fields;
1134
+ /** 主键字段名(对象侧) */
1135
+ private readonly idField?;
1136
+ /** 主键列名(数据库侧) */
1137
+ private readonly idColumn;
1138
+ /** 主键生成器 */
1139
+ private readonly generateId?;
1140
+ /** 当前时间提供者(默认 Date.now) */
1141
+ private readonly nowProvider;
1142
+ /** 初始化 Promise(自动建表等) */
1143
+ private readonly initPromise;
1144
+ /** 可查询列 */
1145
+ private readonly selectColumns;
1146
+ /** 可插入列 */
1147
+ private readonly createColumns;
1148
+ /** 可更新列 */
1149
+ private readonly updateColumns;
1150
+ /** 表名 */
1151
+ private readonly table;
1152
+ /** 当前数据库类型(延迟读取,确保获取初始化后的值) */
1153
+ private get dbType();
1154
+ /**
1155
+ * 创建 BaseReldbCrudRepository
1156
+ *
1157
+ * 初始化字段映射、构建表结构(默认自动建表)并配置底层 CRUD 仓库。
1158
+ *
1159
+ * @param db - 数据库服务对象
1160
+ * @param config - BaseReldbCrudRepository 配置(表名、字段定义、主键策略等)
1161
+ */
1162
+ protected constructor(db: ReldbFunctions, config: BaseReldbCrudRepositoryConfig<TItem>);
1163
+ /**
1164
+ * 获取 SQL 操作对象(自动选择 reldb.sql 或 tx)
1165
+ *
1166
+ * 当传入事务句柄时,自动使用事务内 DataOperations;否则使用 reldb.sql。
1167
+ *
1168
+ * @param tx - 可选事务句柄
1169
+ * @returns DataOperations 实例
1170
+ */
1171
+ protected sql(tx?: DmlWithTxOperations): DmlOperations;
1172
+ /**
1173
+ * 解析主键字段
1174
+ *
1175
+ * 优先使用声明为主键的字段;如果未声明主键,则回退到列名匹配。
1176
+ *
1177
+ * @param fields - 字段定义列表
1178
+ * @param idColumn - 主键列名
1179
+ * @returns 主键字段名(可能为空)
1180
+ */
1181
+ private resolveIdField;
1182
+ /**
1183
+ * 生成默认主键生成器
1184
+ *
1185
+ * 在运行环境支持 `crypto.randomUUID` 时返回 UUID 生成函数,否则返回 undefined。
1186
+ */
1187
+ private defaultIdGenerator;
1188
+ /**
1189
+ * 构建表结构定义
1190
+ *
1191
+ * @param fields - 字段定义列表
1192
+ * @returns 表结构定义
1193
+ */
1194
+ private buildReldbTableDef;
1195
+ /**
1196
+ * 归一化列定义
1197
+ *
1198
+ * 用于处理不同数据库对默认值的兼容差异(例如 BOOLEAN)。
1199
+ */
1200
+ private normalizeReldbColumnDef;
1201
+ /**
1202
+ * 判断是否为创建时间字段
1203
+ */
1204
+ private isCreatedAtField;
1205
+ /**
1206
+ * 判断是否为更新时间字段
1207
+ */
1208
+ private isUpdatedAtField;
1209
+ /**
1210
+ * 将数据库值转换为业务值
1211
+ *
1212
+ * @param value - 数据库原始值
1213
+ * @param def - 字段定义
1214
+ * @returns 业务侧值(可能为 undefined)
1215
+ */
1216
+ private fromDbValue;
1217
+ /**
1218
+ * 将业务值转换为数据库值
1219
+ *
1220
+ * @param value - 业务侧值
1221
+ * @param def - 字段定义
1222
+ * @returns 适配数据库的值
1223
+ */
1224
+ private toDbValue;
1225
+ /**
1226
+ * 将查询行映射为业务模型
1227
+ */
1228
+ private mapRow;
1229
+ /**
1230
+ * 构建创建数据的列值映射
1231
+ *
1232
+ * 处理主键生成、默认值、createdAt/updatedAt 填充等规则。
1233
+ */
1234
+ private buildCreatePayload;
1235
+ /**
1236
+ * 构建更新数据的列值映射
1237
+ *
1238
+ * 当没有任何可更新字段时返回 null。
1239
+ */
1240
+ private buildUpdatePayload;
1241
+ /**
1242
+ * 等待初始化完成
1243
+ *
1244
+ * @returns 初始化结果
1245
+ */
1246
+ private ensureReady;
1247
+ /**
1248
+ * 创建单条记录
1249
+ *
1250
+ * 自动处理主键生成、createdAt/updatedAt 填充、字段类型转换。
1251
+ *
1252
+ * @param data - 业务字段与值的映射
1253
+ * @param tx - 可选事务句柄
1254
+ * @returns 插入结果(含 changes、lastInsertRowid)
1255
+ */
1256
+ create(data: Record<string, unknown>, tx?: DmlWithTxOperations): Promise<HaiResult<ExecuteResult>>;
1257
+ /**
1258
+ * 批量创建记录
1259
+ *
1260
+ * 每条记录均通过 buildCreatePayload 处理,然后以 batch 方式写入。
1261
+ *
1262
+ * @param items - 待插入的业务数据数组
1263
+ * @param tx - 可选事务句柄
1264
+ * @returns 批量插入结果
1265
+ */
1266
+ createMany(items: Array<Record<string, unknown>>, tx?: DmlWithTxOperations): Promise<HaiResult<void>>;
1267
+ /**
1268
+ * 创建或更新单条记录(upsert)
1269
+ *
1270
+ * 主键存在时更新可更新字段,否则插入新记录。
1271
+ * 自动处理主键生成、createdAt/updatedAt 填充、字段类型转换。
1272
+ * 更新时仅写入用户显式提供的可更新字段,不会用默认值覆盖已有数据。
1273
+ *
1274
+ * ### 为什么不复用 this.crud.createOrUpdate(kernel)
1275
+ *
1276
+ * Kernel 的 createOrUpdate 使用 `excluded.col` / `VALUES(col)` 引用 INSERT 值作为
1277
+ * UPDATE 值,即 INSERT 和 UPDATE 共享同一组数据。但 Repository 层的 INSERT 负载和
1278
+ * UPDATE 负载语义不同:
1279
+ *
1280
+ * - **INSERT 负载**(buildCreatePayload):包含自动生成的主键、createdAt、updatedAt、
1281
+ * 字段默认值(如 `status: 'active'`)等应用层填充值。
1282
+ * - **UPDATE 负载**(buildUpdatePayload):仅包含用户显式传入的可更新字段 + updatedAt,
1283
+ * 不包含 createdAt(避免覆盖原始创建时间)、不包含应用默认值(避免覆盖已有数据)。
1284
+ *
1285
+ * 若复用 kernel,冲突更新时会将 INSERT 的 createdAt、默认值等一并写入,破坏已有记录。
1286
+ * 因此 Repository 自行构建两份独立负载,使用 `col = ?` 参数化占位分别传入 INSERT 值
1287
+ * 和 UPDATE 值,通过 this.sql(tx).execute() 直接执行。
1288
+ *
1289
+ * @param data - 业务字段与值的映射
1290
+ * @param tx - 可选事务句柄
1291
+ * @returns 执行结果(含 changes)
1292
+ */
1293
+ createOrUpdate(data: Record<string, unknown>, tx?: DmlWithTxOperations): Promise<HaiResult<ExecuteResult>>;
1294
+ /**
1295
+ * 根据主键查找单条记录
1296
+ *
1297
+ * @param id - 主键值
1298
+ * @param tx - 可选事务句柄
1299
+ * @returns 业务模型对象或 null(未找到)
1300
+ */
1301
+ findById(id: unknown, tx?: DmlWithTxOperations): Promise<HaiResult<TItem | null>>;
1302
+ /**
1303
+ * 根据主键获取单条记录(必须存在)
1304
+ *
1305
+ * 与 findById 不同,当记录不存在时返回 RECORD_NOT_FOUND 错误。
1306
+ *
1307
+ * @param id - 主键值
1308
+ * @param tx - 可选事务句柄
1309
+ * @returns 业务模型对象(不存在时返回错误)
1310
+ */
1311
+ getById(id: unknown, tx?: DmlWithTxOperations): Promise<HaiResult<TItem>>;
1312
+ /**
1313
+ * 条件查询多条记录
1314
+ *
1315
+ * @param options - 查询条件(where、orderBy、limit、offset)
1316
+ * @param tx - 可选事务句柄
1317
+ * @returns 业务模型数组
1318
+ */
1319
+ findAll(options?: CrudQueryOptions, tx?: DmlWithTxOperations): Promise<HaiResult<TItem[]>>;
1320
+ /**
1321
+ * 分页查询记录
1322
+ *
1323
+ * @param options - 分页查询条件(where、orderBy、pagination、overrides)
1324
+ * @param tx - 可选事务句柄
1325
+ * @returns 分页结果(含 items、total、page、pageSize)
1326
+ */
1327
+ findPage(options: CrudPageOptions, tx?: DmlWithTxOperations): Promise<HaiResult<PaginatedResult<TItem>>>;
1328
+ /**
1329
+ * 根据主键更新记录
1330
+ *
1331
+ * 自动填充 updatedAt 字段。无可更新字段时返回 CONFIG_ERROR。
1332
+ *
1333
+ * @param id - 主键值
1334
+ * @param data - 待更新的业务字段
1335
+ * @param tx - 可选事务句柄
1336
+ * @returns 更新结果(含 changes)
1337
+ */
1338
+ updateById(id: unknown, data: Record<string, unknown>, tx?: DmlWithTxOperations): Promise<HaiResult<ExecuteResult>>;
1339
+ /**
1340
+ * 根据主键删除记录
1341
+ *
1342
+ * @param id - 主键值
1343
+ * @param tx - 可选事务句柄
1344
+ * @returns 删除结果(含 changes)
1345
+ */
1346
+ deleteById(id: unknown, tx?: DmlWithTxOperations): Promise<HaiResult<ExecuteResult>>;
1347
+ /**
1348
+ * 统计符合条件的记录数
1349
+ *
1350
+ * @param options - 查询条件(where、params)
1351
+ * @param tx - 可选事务句柄
1352
+ * @returns 记录数
1353
+ */
1354
+ count(options?: ReldbCrudCountOptions, tx?: DmlWithTxOperations): Promise<HaiResult<number>>;
1355
+ /**
1356
+ * 检查是否存在符合条件的记录
1357
+ *
1358
+ * @param options - 查询条件(where、params)
1359
+ * @param tx - 可选事务句柄
1360
+ * @returns 是否存在
1361
+ */
1362
+ exists(options?: ReldbCrudCountOptions, tx?: DmlWithTxOperations): Promise<HaiResult<boolean>>;
1363
+ /**
1364
+ * 根据主键检查记录是否存在
1365
+ *
1366
+ * @param id - 主键值
1367
+ * @param tx - 可选事务句柄
1368
+ * @returns 是否存在
1369
+ */
1370
+ existsById(id: unknown, tx?: DmlWithTxOperations): Promise<HaiResult<boolean>>;
1371
+ }
1372
+
1373
+ /**
1374
+ * @h-ai/reldb — 数据库服务主入口
1375
+ *
1376
+ * 本文件提供统一的 `reldb` 对象,聚合所有数据库操作功能。
1377
+ * @module reldb-main
1378
+ */
1379
+
1380
+ /**
1381
+ * 数据库服务对象
1382
+ *
1383
+ * 统一的数据库访问入口,提供以下功能:
1384
+ * - `reldb.init()` - 初始化数据库连接
1385
+ * - `reldb.close()` - 关闭连接
1386
+ * - `reldb.ddl` - DDL 操作(表结构管理)
1387
+ * - `reldb.sql` - SQL 操作(数据查询和修改)
1388
+ * - `reldb.tx` - 事务管理器(begin / wrap)
1389
+ * - `reldb.json` - JSON 路径操作 SQL 构建器(提取、设置、插入、删除、合并)
1390
+ * - `reldb.config` - 当前配置
1391
+ * - `reldb.isInitialized` - 初始化状态
1392
+ *
1393
+ * @example
1394
+ * ```ts
1395
+ * import { reldb } from '@h-ai/reldb'
1396
+ *
1397
+ * // 初始化
1398
+ * await reldb.init({ type: 'sqlite', database: ':memory:' })
1399
+ *
1400
+ * // DDL 操作
1401
+ * await reldb.ddl.createTable('users', {
1402
+ * id: { type: 'INTEGER', primaryKey: true, autoIncrement: true },
1403
+ * name: { type: 'TEXT', notNull: true }
1404
+ * })
1405
+ *
1406
+ * // SQL 操作
1407
+ * await reldb.sql.execute('INSERT INTO users (name) VALUES (?)', ['张三'])
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()
1419
+ * ```
1420
+ */
1421
+ declare const reldb: ReldbFunctions;
1422
+
1423
+ /**
1424
+ * @h-ai/reldb — 安全工具
1425
+ *
1426
+ * 提供 SQL 标识符校验与字符串值转义功能,防止注入风险。
1427
+ * @module reldb-security
1428
+ */
1429
+
1430
+ /**
1431
+ * 校验 SQL 标识符合法性
1432
+ *
1433
+ * 防止因动态拼接表名/列名/索引名而产生 SQL 注入风险。
1434
+ * 仅允许 `[a-zA-Z_][a-zA-Z0-9_]*`,最长 128 字符。
1435
+ *
1436
+ * @param name - 待校验的标识符
1437
+ * @returns 校验通过时返回 ok(name);不合法时返回错误 HaiResult
1438
+ *
1439
+ * @example
1440
+ * ```ts
1441
+ * const result = validateIdentifier('users')
1442
+ * // result.success === true
1443
+ *
1444
+ * const bad = validateIdentifier('users; DROP TABLE')
1445
+ * // bad.success === false
1446
+ * ```
1447
+ */
1448
+ declare function validateIdentifier(name: string): HaiResult<string>;
1449
+ /**
1450
+ * 批量校验多个 SQL 标识符
1451
+ *
1452
+ * 逐个校验,遇到第一个不合法的立即返回错误。
1453
+ *
1454
+ * @param names - 待校验的标识符数组
1455
+ * @returns 全部合法时返回 ok(undefined);否则返回第一个不合法项的错误
1456
+ */
1457
+ declare function validateIdentifiers(names: string[]): HaiResult<void>;
1458
+ /**
1459
+ * 用双引号包裹 SQL 标识符(适用于 PostgreSQL / SQLite / 标准 SQL)
1460
+ *
1461
+ * 标识符内的双引号会被转义为两个双引号。
1462
+ * 使用场景:DDL 中的表名、列名、索引名。
1463
+ * 调用前应先通过 `validateIdentifier` 校验合法性。
1464
+ *
1465
+ * @param name - 已校验的标识符
1466
+ * @returns 双引号包裹的安全标识符
1467
+ *
1468
+ * @example
1469
+ * ```ts
1470
+ * quoteIdentifier('users') // '"users"'
1471
+ * quoteIdentifier('order') // '"order"' (安全引用 SQL 保留字)
1472
+ * ```
1473
+ */
1474
+ declare function quoteIdentifier(name: string): string;
1475
+ /**
1476
+ * 转义 SQL 字符串字面量中的单引号
1477
+ *
1478
+ * 将 `'` 转义为 `''`,用于 DDL 中 DEFAULT 值等需要直接拼接的场景。
1479
+ * 注意:仅用于标识符/DDL 场景,数据操作应始终使用参数化查询。
1480
+ *
1481
+ * @param value - 原始字符串
1482
+ * @returns 转义后的安全字符串
1483
+ *
1484
+ * @example
1485
+ * ```ts
1486
+ * escapeSqlString("it's") // "it''s"
1487
+ * escapeSqlString("normal") // "normal"
1488
+ * ```
1489
+ */
1490
+ declare function escapeSqlString(value: string): string;
1491
+
1492
+ export { BaseReldbCrudRepository, type BaseReldbCrudRepositoryConfig, type ColumnType, type CrudConfig, type CrudManager, type CrudPageOptions, type CrudQueryOptions, type DbType, type DdlOperations, type DmlOperations, type DmlWithTxOperations, type ExecuteResult, HaiReldbError, type JsonSqlExpr, type MysqlConfig, MysqlConfigSchema, MysqlOptionsSchema, type NormalizedPagination, type PaginationOverrides, type PaginationQueryOptions, type PoolConfig, PoolConfigSchema, type PostgresqlConfig, PostgresqlConfigSchema, type QueryRow, type ReldbColumnDef, type ReldbConfig, type ReldbConfigInput, ReldbConfigSchema, type ReldbCrudCountOptions, type ReldbCrudFieldDefinition, type ReldbCrudRepository, type ReldbFunctions, type ReldbIndexDef, type ReldbJsonOps, type ReldbProvider, type ReldbTableDef, ReldbTypeSchema, type SqliteConfig, SqliteConfigSchema, SqliteOptionsSchema, type SslConfig, SslConfigSchema, type TxManager, type TxWrapCallback, createJsonOps, escapeSqlString, parseJsonPath, quoteIdentifier, reldb, validateIdentifier, validateIdentifiers };