@zhin.js/database 1.0.3 → 1.0.5

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.
Files changed (119) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +1360 -34
  3. package/lib/base/database.d.ts +71 -13
  4. package/lib/base/database.d.ts.map +1 -1
  5. package/lib/base/database.js +128 -4
  6. package/lib/base/database.js.map +1 -1
  7. package/lib/base/dialect.d.ts +27 -10
  8. package/lib/base/dialect.d.ts.map +1 -1
  9. package/lib/base/dialect.js +32 -0
  10. package/lib/base/dialect.js.map +1 -1
  11. package/lib/base/index.d.ts +1 -0
  12. package/lib/base/index.d.ts.map +1 -1
  13. package/lib/base/index.js +1 -0
  14. package/lib/base/index.js.map +1 -1
  15. package/lib/base/model.d.ts +105 -12
  16. package/lib/base/model.d.ts.map +1 -1
  17. package/lib/base/model.js +224 -3
  18. package/lib/base/model.js.map +1 -1
  19. package/lib/base/query-classes.d.ts +204 -33
  20. package/lib/base/query-classes.d.ts.map +1 -1
  21. package/lib/base/query-classes.js +276 -0
  22. package/lib/base/query-classes.js.map +1 -1
  23. package/lib/base/thenable.d.ts +7 -7
  24. package/lib/base/thenable.d.ts.map +1 -1
  25. package/lib/base/thenable.js +5 -4
  26. package/lib/base/thenable.js.map +1 -1
  27. package/lib/base/transaction.d.ts +46 -0
  28. package/lib/base/transaction.d.ts.map +1 -0
  29. package/lib/base/transaction.js +186 -0
  30. package/lib/base/transaction.js.map +1 -0
  31. package/lib/dialects/memory.d.ts +13 -8
  32. package/lib/dialects/memory.d.ts.map +1 -1
  33. package/lib/dialects/memory.js +10 -7
  34. package/lib/dialects/memory.js.map +1 -1
  35. package/lib/dialects/mongodb.d.ts +12 -8
  36. package/lib/dialects/mongodb.d.ts.map +1 -1
  37. package/lib/dialects/mongodb.js +21 -18
  38. package/lib/dialects/mongodb.js.map +1 -1
  39. package/lib/dialects/mysql.d.ts +36 -7
  40. package/lib/dialects/mysql.d.ts.map +1 -1
  41. package/lib/dialects/mysql.js +140 -21
  42. package/lib/dialects/mysql.js.map +1 -1
  43. package/lib/dialects/pg.d.ts +36 -7
  44. package/lib/dialects/pg.d.ts.map +1 -1
  45. package/lib/dialects/pg.js +140 -21
  46. package/lib/dialects/pg.js.map +1 -1
  47. package/lib/dialects/redis.d.ts +13 -8
  48. package/lib/dialects/redis.d.ts.map +1 -1
  49. package/lib/dialects/redis.js +14 -11
  50. package/lib/dialects/redis.js.map +1 -1
  51. package/lib/dialects/sqlite.d.ts +20 -7
  52. package/lib/dialects/sqlite.d.ts.map +1 -1
  53. package/lib/dialects/sqlite.js +66 -13
  54. package/lib/dialects/sqlite.js.map +1 -1
  55. package/lib/index.d.ts +1 -0
  56. package/lib/index.d.ts.map +1 -1
  57. package/lib/index.js +1 -0
  58. package/lib/index.js.map +1 -1
  59. package/lib/migration.d.ts +132 -0
  60. package/lib/migration.d.ts.map +1 -0
  61. package/lib/migration.js +475 -0
  62. package/lib/migration.js.map +1 -0
  63. package/lib/registry.d.ts +26 -23
  64. package/lib/registry.d.ts.map +1 -1
  65. package/lib/registry.js +1 -5
  66. package/lib/registry.js.map +1 -1
  67. package/lib/type/document/database.d.ts +12 -12
  68. package/lib/type/document/database.d.ts.map +1 -1
  69. package/lib/type/document/database.js +1 -1
  70. package/lib/type/document/database.js.map +1 -1
  71. package/lib/type/document/model.d.ts +8 -8
  72. package/lib/type/document/model.d.ts.map +1 -1
  73. package/lib/type/document/model.js +1 -1
  74. package/lib/type/document/model.js.map +1 -1
  75. package/lib/type/keyvalue/database.d.ts +12 -12
  76. package/lib/type/keyvalue/database.d.ts.map +1 -1
  77. package/lib/type/keyvalue/database.js +1 -1
  78. package/lib/type/keyvalue/database.js.map +1 -1
  79. package/lib/type/keyvalue/model.d.ts +3 -3
  80. package/lib/type/keyvalue/model.d.ts.map +1 -1
  81. package/lib/type/keyvalue/model.js +1 -1
  82. package/lib/type/keyvalue/model.js.map +1 -1
  83. package/lib/type/related/database.d.ts +49 -14
  84. package/lib/type/related/database.d.ts.map +1 -1
  85. package/lib/type/related/database.js +259 -28
  86. package/lib/type/related/database.js.map +1 -1
  87. package/lib/type/related/model.d.ts +252 -16
  88. package/lib/type/related/model.d.ts.map +1 -1
  89. package/lib/type/related/model.js +648 -23
  90. package/lib/type/related/model.js.map +1 -1
  91. package/lib/types.d.ts +475 -37
  92. package/lib/types.d.ts.map +1 -1
  93. package/lib/types.js +6 -0
  94. package/lib/types.js.map +1 -1
  95. package/package.json +10 -5
  96. package/src/base/database.ts +168 -24
  97. package/src/base/dialect.ts +49 -10
  98. package/src/base/index.ts +2 -1
  99. package/src/base/model.ts +258 -18
  100. package/src/base/query-classes.ts +471 -63
  101. package/src/base/thenable.ts +12 -11
  102. package/src/base/transaction.ts +213 -0
  103. package/src/dialects/memory.ts +17 -16
  104. package/src/dialects/mongodb.ts +44 -42
  105. package/src/dialects/mysql.ts +155 -26
  106. package/src/dialects/pg.ts +152 -25
  107. package/src/dialects/redis.ts +45 -43
  108. package/src/dialects/sqlite.ts +77 -19
  109. package/src/index.ts +1 -2
  110. package/src/migration.ts +544 -0
  111. package/src/registry.ts +33 -33
  112. package/src/type/document/database.ts +33 -33
  113. package/src/type/document/model.ts +15 -15
  114. package/src/type/keyvalue/database.ts +33 -33
  115. package/src/type/keyvalue/model.ts +19 -19
  116. package/src/type/related/database.ts +309 -34
  117. package/src/type/related/model.ts +801 -34
  118. package/src/types.ts +559 -44
  119. package/tests/database.test.ts +1738 -0
@@ -1,18 +1,21 @@
1
1
  import type { Database } from './database.js';
2
2
  import type { Dialect } from './dialect.js';
3
3
  import { ThenableQuery } from './thenable.js';
4
- import { QueryParams, AlterDefinition, Condition, Ordering, Definition } from '../types.js';
4
+ import { QueryParams, AlterDefinition, Condition, Ordering, Definition, AggregateField, AggregateFunction, Subquery, JoinClause, JoinType, ModelOptions } from '../types.js';
5
5
 
6
- export class Alteration<T extends object, C = any, D = string> extends ThenableQuery<void, C, D> {
6
+ /** 软删除查询模式 */
7
+ export type SoftDeleteMode = 'default' | 'withTrashed' | 'onlyTrashed';
8
+
9
+ export class Alteration<S extends Record<string, object>, T extends keyof S, C = any, D = string> extends ThenableQuery<void,S,T, C, D> {
7
10
  constructor(
8
- database: Database<C, Record<string, object>, D>,
9
- private readonly tableName: string,
10
- private readonly alterations: AlterDefinition<T>
11
+ database: Database<C, S, D>,
12
+ private readonly tableName: T,
13
+ private readonly alterations: AlterDefinition<S[T]>
11
14
  ) {
12
- super(database, database.dialect as Dialect<C, D>);
15
+ super(database, database.dialect as Dialect<C,S, D>);
13
16
  }
14
17
 
15
- protected getQueryParams(): QueryParams<T> {
18
+ protected getQueryParams(): QueryParams<S,T> {
16
19
  return {
17
20
  type: 'alter',
18
21
  tableName: this.tableName,
@@ -21,22 +24,22 @@ export class Alteration<T extends object, C = any, D = string> extends ThenableQ
21
24
  }
22
25
  }
23
26
 
24
- export class DroppingTable<T extends object = any, C = any, D = string> extends ThenableQuery<number, C, D> {
25
- private conditions: Condition<T> = {};
27
+ export class DroppingTable<S extends Record<string, object>, T extends keyof S, C = any, D = string> extends ThenableQuery<number,S,T, C, D> {
28
+ private conditions: Condition<S[T]> = {};
26
29
 
27
30
  constructor(
28
- database: Database<C, Record<string, object>, any>,
29
- private readonly tableName: string
31
+ database: Database<C, S, any>,
32
+ private readonly tableName: T
30
33
  ) {
31
- super(database, database.dialect as Dialect<C, D>);
34
+ super(database, database.dialect as Dialect<C,S, D>);
32
35
  }
33
36
 
34
- where(query: Condition<T>): this {
37
+ where(query: Condition<S[T]>): this {
35
38
  this.conditions = { ...this.conditions, ...query };
36
39
  return this;
37
40
  }
38
41
 
39
- protected getQueryParams(): QueryParams<T> {
42
+ protected getQueryParams(): QueryParams<S,T> {
40
43
  return {
41
44
  type: 'drop_table',
42
45
  tableName: this.tableName,
@@ -45,23 +48,23 @@ export class DroppingTable<T extends object = any, C = any, D = string> extends
45
48
  }
46
49
  }
47
50
 
48
- export class DroppingIndex<C = any, D = string> extends ThenableQuery<number, C, D> {
51
+ export class DroppingIndex<S extends Record<string, object>, T extends keyof S,C = any, D = string> extends ThenableQuery<number,S,T, C, D> {
49
52
  private conditions: Condition<any> = {};
50
53
 
51
54
  constructor(
52
- database: Database<C, Record<string, object>, D>,
55
+ database: Database<C, S, D>,
53
56
  private readonly indexName: string,
54
- private readonly tableName: string
57
+ private readonly tableName: T
55
58
  ) {
56
- super(database, database.dialect as Dialect<C, D>);
59
+ super(database, database.dialect as Dialect<C,S, D>);
57
60
  }
58
61
 
59
- where(query: Condition<any>): this {
62
+ where(query: Condition<S[T]>): this {
60
63
  this.conditions = { ...this.conditions, ...query };
61
64
  return this;
62
65
  }
63
66
 
64
- protected getQueryParams(): QueryParams<any> {
67
+ protected getQueryParams(): QueryParams<S,T> {
65
68
  return {
66
69
  type: 'drop_index',
67
70
  tableName: this.tableName,
@@ -71,16 +74,16 @@ export class DroppingIndex<C = any, D = string> extends ThenableQuery<number, C,
71
74
  }
72
75
  }
73
76
 
74
- export class Creation<T extends object, C = any, D = string> extends ThenableQuery<void, C, D> {
77
+ export class Creation<S extends Record<string, object>, T extends keyof S, C = any, D = string> extends ThenableQuery<void,S,T, C, D> {
75
78
  constructor(
76
- database: Database<C, Record<string, object>, D>,
77
- private readonly tableName: string,
78
- private readonly definition: Definition<T>
79
+ database: Database<C, S, D>,
80
+ private readonly tableName: T,
81
+ private readonly definition: Definition<S[T]>
79
82
  ) {
80
- super(database, database.dialect as Dialect<C, D>);
83
+ super(database, database.dialect as Dialect<C,S, D>);
81
84
  }
82
85
 
83
- protected getQueryParams(): QueryParams<T> {
86
+ protected getQueryParams(): QueryParams<S,T> {
84
87
  return {
85
88
  type: 'create',
86
89
  tableName: this.tableName,
@@ -89,37 +92,69 @@ export class Creation<T extends object, C = any, D = string> extends ThenableQue
89
92
  }
90
93
  }
91
94
 
95
+ /**
96
+ * SELECT 查询类
97
+ * 实现 Subquery<S[T][K]> 以支持类型安全的子查询
98
+ *
99
+ * @template S Schema 类型
100
+ * @template T 表名
101
+ * @template K 选择的字段
102
+ * @template C 连接类型
103
+ * @template D 方言类型
104
+ *
105
+ * @example
106
+ * ```ts
107
+ * // 子查询类型推断示例
108
+ * interface Schema {
109
+ * users: { id: number; name: string };
110
+ * orders: { id: number; userId: number; amount: number };
111
+ * }
112
+ *
113
+ * // ✅ 正确:userId 是 number,匹配 users.id
114
+ * db.select('users', ['id']).where({
115
+ * id: { $in: db.select('orders', ['userId']) }
116
+ * });
117
+ *
118
+ * // ❌ 类型错误:name 是 string,不能与 number 的 id 匹配
119
+ * db.select('users', ['id']).where({
120
+ * id: { $in: db.select('users', ['name']) } // Type error!
121
+ * });
122
+ * ```
123
+ */
92
124
  export class Selection<
93
- T extends object,
94
- K extends keyof T,
125
+ S extends Record<string, object>, T extends keyof S,
126
+ K extends keyof S[T],
95
127
  C = any,
96
128
  D = string
97
- > extends ThenableQuery<Pick<T, K>[], C, D> {
98
- private conditions: Condition<T> = {};
99
- private groupings: (keyof T)[] = [];
100
- private orderings: Ordering<T>[] = [];
101
- private limitCount?: number;
102
- private offsetCount?: number;
129
+ > extends ThenableQuery<Pick<S[T], K>[],S,T, C, D> implements Subquery<S[T][K]> {
130
+ readonly __isSubquery = true as const;
131
+ readonly __returnType?: S[T][K];
132
+
133
+ protected conditions: Condition<S[T]> = {};
134
+ protected groupings: (keyof S[T])[] = [];
135
+ protected orderings: Ordering<S[T]>[] = [];
136
+ protected limitCount?: number;
137
+ protected offsetCount?: number;
103
138
 
104
139
  constructor(
105
- database: Database<C, Record<string, object>, D>,
106
- private readonly modelName: string,
107
- private readonly fields: Array<K>
140
+ database: Database<C, S, D>,
141
+ protected readonly modelName: T,
142
+ protected readonly fields: Array<K>
108
143
  ) {
109
- super(database, database.dialect as Dialect<C, D>);
144
+ super(database, database.dialect as Dialect<C,S, D>);
110
145
  }
111
146
 
112
- where(query: Condition<T>): this {
147
+ where(query: Condition<S[T]>): this {
113
148
  this.conditions = { ...this.conditions, ...query };
114
149
  return this;
115
150
  }
116
151
 
117
- groupBy(...fields: (keyof T)[]): this {
152
+ groupBy(...fields: (keyof S[T])[]): this {
118
153
  this.groupings.push(...fields);
119
154
  return this;
120
155
  }
121
156
 
122
- orderBy(field: keyof T, direction: "ASC" | "DESC" = "ASC"): this {
157
+ orderBy(field: keyof S[T], direction: "ASC" | "DESC" = "ASC"): this {
123
158
  this.orderings.push({ field, direction });
124
159
  return this;
125
160
  }
@@ -134,7 +169,100 @@ export class Selection<
134
169
  return this;
135
170
  }
136
171
 
137
- protected getQueryParams(): QueryParams<T> {
172
+ // ========================================================================
173
+ // JOIN Methods - 返回带扩展类型的 JoinedSelection
174
+ // ========================================================================
175
+
176
+ /**
177
+ * INNER JOIN - 只返回两表都有匹配的行
178
+ * 返回类型扩展为包含关联表字段
179
+ *
180
+ * @example
181
+ * ```ts
182
+ * const result = await db.select('users', ['id', 'name'])
183
+ * .join('orders', 'id', 'userId');
184
+ * // result 类型: { users: { id, name }, orders: { id, userId, amount } }[]
185
+ * ```
186
+ */
187
+ join<J extends keyof S>(
188
+ table: J,
189
+ leftField: keyof S[T],
190
+ rightField: keyof S[J]
191
+ ): JoinedSelection<S, T, K, J, C, D> {
192
+ return new JoinedSelection<S, T, K, J, C, D>(
193
+ this.database,
194
+ this.modelName,
195
+ this.fields,
196
+ table,
197
+ 'INNER',
198
+ leftField,
199
+ rightField,
200
+ this.conditions,
201
+ this.orderings,
202
+ this.groupings,
203
+ this.limitCount,
204
+ this.offsetCount
205
+ );
206
+ }
207
+
208
+ /**
209
+ * LEFT JOIN - 返回左表所有行,右表无匹配则为 NULL
210
+ */
211
+ leftJoin<J extends keyof S>(
212
+ table: J,
213
+ leftField: keyof S[T],
214
+ rightField: keyof S[J]
215
+ ): JoinedSelection<S, T, K, J, C, D, true> {
216
+ return new JoinedSelection<S, T, K, J, C, D, true>(
217
+ this.database,
218
+ this.modelName,
219
+ this.fields,
220
+ table,
221
+ 'LEFT',
222
+ leftField,
223
+ rightField,
224
+ this.conditions,
225
+ this.orderings,
226
+ this.groupings,
227
+ this.limitCount,
228
+ this.offsetCount
229
+ );
230
+ }
231
+
232
+ /**
233
+ * RIGHT JOIN - 返回右表所有行,左表无匹配则为 NULL
234
+ */
235
+ rightJoin<J extends keyof S>(
236
+ table: J,
237
+ leftField: keyof S[T],
238
+ rightField: keyof S[J]
239
+ ): JoinedSelection<S, T, K, J, C, D, false, true> {
240
+ return new JoinedSelection<S, T, K, J, C, D, false, true>(
241
+ this.database,
242
+ this.modelName,
243
+ this.fields,
244
+ table,
245
+ 'RIGHT',
246
+ leftField,
247
+ rightField,
248
+ this.conditions,
249
+ this.orderings,
250
+ this.groupings,
251
+ this.limitCount,
252
+ this.offsetCount
253
+ );
254
+ }
255
+
256
+ /**
257
+ * 转换为子查询 SQL
258
+ * 用于 $in / $nin 等操作符中嵌套查询
259
+ */
260
+ toSQL(): { sql: string; params: any[] } {
261
+ const { query, params } = this.database.buildQuery(this.getQueryParams());
262
+ return { sql: String(query), params };
263
+ }
264
+
265
+ protected getQueryParams(): QueryParams<S,T> {
138
266
  return {
139
267
  type: 'select',
140
268
  tableName: this.modelName,
@@ -148,16 +276,158 @@ export class Selection<
148
276
  }
149
277
  }
150
278
 
151
- export class Insertion<T extends object, C = any, D = string> extends ThenableQuery<T, C, D> {
279
+ /**
280
+ * JOIN 结果类型 - 根据表名命名空间化
281
+ */
282
+ type JoinResult<
283
+ S extends Record<string, object>,
284
+ T extends keyof S,
285
+ K extends keyof S[T],
286
+ J extends keyof S,
287
+ LeftNullable extends boolean = false,
288
+ RightNullable extends boolean = false
289
+ > = {
290
+ [P in T]: LeftNullable extends true ? Partial<Pick<S[T], K>> : Pick<S[T], K>;
291
+ } & {
292
+ [P in J]: RightNullable extends true ? Partial<S[J]> | null : S[J];
293
+ };
294
+
295
+ /**
296
+ * JOIN 查询类 - 支持类型安全的关联查询
297
+ *
298
+ * @template S Schema 类型
299
+ * @template T 主表名
300
+ * @template K 主表选择的字段
301
+ * @template J 关联表名
302
+ * @template LeftNullable LEFT JOIN 时主表可能为 null
303
+ * @template RightNullable RIGHT JOIN 时关联表可能为 null
304
+ */
305
+ export class JoinedSelection<
306
+ S extends Record<string, object>,
307
+ T extends keyof S,
308
+ K extends keyof S[T],
309
+ J extends keyof S,
310
+ C = any,
311
+ D = string,
312
+ LeftNullable extends boolean = false,
313
+ RightNullable extends boolean = false
314
+ > extends ThenableQuery<JoinResult<S, T, K, J, LeftNullable, RightNullable>[], S, T, C, D> {
315
+
316
+ private joinClauses: JoinClause<S, T, keyof S>[] = [];
317
+
318
+ constructor(
319
+ database: Database<C, S, D>,
320
+ private readonly modelName: T,
321
+ private readonly fields: Array<K>,
322
+ joinTable: J,
323
+ joinType: JoinType,
324
+ leftField: keyof S[T],
325
+ rightField: keyof S[J],
326
+ private conditions: Condition<S[T]> = {},
327
+ private orderings: Ordering<S[T]>[] = [],
328
+ private groupings: (keyof S[T])[] = [],
329
+ private limitCount?: number,
330
+ private offsetCount?: number
331
+ ) {
332
+ super(database, database.dialect as Dialect<C, S, D>);
333
+ this.joinClauses.push({
334
+ type: joinType,
335
+ table: joinTable,
336
+ leftField,
337
+ rightField: rightField as keyof S[keyof S]
338
+ });
339
+ }
340
+
341
+ where(query: Condition<S[T]>): this {
342
+ this.conditions = { ...this.conditions, ...query };
343
+ return this;
344
+ }
345
+
346
+ orderBy(field: keyof S[T], direction: "ASC" | "DESC" = "ASC"): this {
347
+ this.orderings.push({ field, direction });
348
+ return this;
349
+ }
350
+
351
+ limit(count: number): this {
352
+ this.limitCount = count;
353
+ return this;
354
+ }
355
+
356
+ offset(count: number): this {
357
+ this.offsetCount = count;
358
+ return this;
359
+ }
360
+
361
+ /**
362
+ * 继续 JOIN 更多表
363
+ */
364
+ join<J2 extends keyof S>(
365
+ table: J2,
366
+ leftField: keyof S[T],
367
+ rightField: keyof S[J2]
368
+ ): this {
369
+ this.joinClauses.push({
370
+ type: 'INNER',
371
+ table,
372
+ leftField,
373
+ rightField: rightField as keyof S[keyof S]
374
+ });
375
+ return this;
376
+ }
377
+
378
+ leftJoin<J2 extends keyof S>(
379
+ table: J2,
380
+ leftField: keyof S[T],
381
+ rightField: keyof S[J2]
382
+ ): this {
383
+ this.joinClauses.push({
384
+ type: 'LEFT',
385
+ table,
386
+ leftField,
387
+ rightField: rightField as keyof S[keyof S]
388
+ });
389
+ return this;
390
+ }
391
+
392
+ rightJoin<J2 extends keyof S>(
393
+ table: J2,
394
+ leftField: keyof S[T],
395
+ rightField: keyof S[J2]
396
+ ): this {
397
+ this.joinClauses.push({
398
+ type: 'RIGHT',
399
+ table,
400
+ leftField,
401
+ rightField: rightField as keyof S[keyof S]
402
+ });
403
+ return this;
404
+ }
405
+
406
+ protected getQueryParams(): QueryParams<S, T> {
407
+ return {
408
+ type: 'select',
409
+ tableName: this.modelName,
410
+ fields: this.fields,
411
+ conditions: this.conditions,
412
+ groupings: this.groupings,
413
+ orderings: this.orderings,
414
+ limitCount: this.limitCount,
415
+ offsetCount: this.offsetCount,
416
+ joins: this.joinClauses
417
+ };
418
+ }
419
+ }
420
+
421
+ export class Insertion<S extends Record<string, object>, T extends keyof S, C = any, D = string> extends ThenableQuery<S[T], S, T, C, D> {
152
422
  constructor(
153
- database: Database<C, Record<string, object>, D>,
154
- private readonly modelName: string,
155
- private readonly data: T
423
+ database: Database<C, S, D>,
424
+ private readonly modelName: T,
425
+ private readonly data: S[T]
156
426
  ) {
157
- super(database, database.dialect as Dialect<C, D>);
427
+ super(database, database.dialect as Dialect<C,S, D>);
158
428
  }
159
429
 
160
- protected getQueryParams(): QueryParams<T> {
430
+ protected getQueryParams(): QueryParams<S,T> {
161
431
  return {
162
432
  type: 'insert',
163
433
  tableName: this.modelName,
@@ -166,23 +436,23 @@ export class Insertion<T extends object, C = any, D = string> extends ThenableQu
166
436
  }
167
437
  }
168
438
 
169
- export class Updation<T extends object, C = any, D = string> extends ThenableQuery<number, C, D> {
170
- private conditions: Condition<T> = {};
439
+ export class Updation<S extends Record<string, object>, T extends keyof S, C = any, D = string> extends ThenableQuery<number,S,T, C, D> {
440
+ private conditions: Condition<S[T]> = {};
171
441
 
172
442
  constructor(
173
- database: Database<C, Record<string, object>, D>,
174
- private readonly modelName: string,
175
- private readonly update: Partial<T>
443
+ database: Database<C, S, D>,
444
+ private readonly modelName: T,
445
+ private readonly update: Partial<S[T]>
176
446
  ) {
177
- super(database, database.dialect as Dialect<C, D>);
447
+ super(database, database.dialect as Dialect<C,S, D>);
178
448
  }
179
449
 
180
- where(query: Condition<T>): this {
450
+ where(query: Condition<S[T]>): this {
181
451
  this.conditions = { ...this.conditions, ...query };
182
452
  return this;
183
453
  }
184
454
 
185
- protected getQueryParams(): QueryParams<T> {
455
+ protected getQueryParams(): QueryParams<S,T> {
186
456
  return {
187
457
  type: 'update',
188
458
  tableName: this.modelName,
@@ -192,22 +462,22 @@ export class Updation<T extends object, C = any, D = string> extends ThenableQue
192
462
  }
193
463
  }
194
464
 
195
- export class Deletion<T extends object = any, C = any, D = string> extends ThenableQuery<number, C, D> {
196
- private conditions: Condition<T> = {};
465
+ export class Deletion<S extends Record<string, object>, T extends keyof S, C = any, D = string> extends ThenableQuery<S[T][],S,T, C, D> {
466
+ private conditions: Condition<S[T]> = {};
197
467
 
198
468
  constructor(
199
- database: Database<C, Record<string, object>, D>,
200
- private readonly modelName: string
469
+ database: Database<C, S, D>,
470
+ private readonly modelName: T
201
471
  ) {
202
- super(database, database.dialect as Dialect<C, D>);
472
+ super(database, database.dialect);
203
473
  }
204
474
 
205
- where(query: Condition<T>): this {
475
+ where(query: Condition<S[T]>): this {
206
476
  this.conditions = { ...this.conditions, ...query };
207
477
  return this;
208
478
  }
209
479
 
210
- protected getQueryParams(): QueryParams<T> {
480
+ protected getQueryParams(): QueryParams<S,T> {
211
481
  return {
212
482
  type: 'delete',
213
483
  tableName: this.modelName,
@@ -215,3 +485,141 @@ export class Deletion<T extends object = any, C = any, D = string> extends Thena
215
485
  };
216
486
  }
217
487
  }
488
+
489
+ /**
490
+ * 批量插入查询类
491
+ */
492
+ export class BatchInsertion<S extends Record<string, object>, T extends keyof S, C = any, D = string> extends ThenableQuery<{ affectedRows: number; insertIds?: (number | string)[] }, S, T, C, D> {
493
+ constructor(
494
+ database: Database<C, S, D>,
495
+ private readonly modelName: T,
496
+ private readonly data: S[T][]
497
+ ) {
498
+ super(database, database.dialect as Dialect<C,S, D>);
499
+ }
500
+
501
+ // 重写 then 方法来转换返回值
502
+ then<TResult1 = { affectedRows: number; insertIds?: (number | string)[] }, TResult2 = never>(
503
+ onfulfilled?: ((value: { affectedRows: number; insertIds?: (number | string)[] }) => TResult1 | PromiseLike<TResult1>) | undefined | null,
504
+ onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null
505
+ ): Promise<TResult1 | TResult2> {
506
+ const params = this.getQueryParams();
507
+ const { query, params: queryParams } = this.database.buildQuery(params);
508
+ // 使用 database.query 以支持日志记录
509
+ return this.database.query<any>(query, queryParams).then((result) => {
510
+ // 转换不同数据库的返回格式
511
+ const normalized = {
512
+ affectedRows: result?.changes ?? result?.affectedRows ?? this.data.length,
513
+ insertIds: result?.lastID ? [result.lastID] : result?.insertIds
514
+ };
515
+ return onfulfilled ? onfulfilled(normalized) : normalized as any;
516
+ }, onrejected);
517
+ }
518
+
519
+ protected getQueryParams(): QueryParams<S,T> {
520
+ return {
521
+ type: 'insert_many',
522
+ tableName: this.modelName,
523
+ data: this.data
524
+ };
525
+ }
526
+ }
527
+
528
+ /**
529
+ * 聚合查询结果类型
530
+ */
531
+ export interface AggregateResult {
532
+ [key: string]: number | string | null;
533
+ }
534
+
535
+ /**
536
+ * 聚合查询类
537
+ */
538
+ export class Aggregation<S extends Record<string, object>, T extends keyof S, C = any, D = string> extends ThenableQuery<AggregateResult[], S, T, C, D> {
539
+ private conditions: Condition<S[T]> = {};
540
+ private groupings: (keyof S[T])[] = [];
541
+ private havingConditions: Condition<S[T]> = {};
542
+ private aggregates: AggregateField<S[T]>[] = [];
543
+
544
+ constructor(
545
+ database: Database<C, S, D>,
546
+ private readonly modelName: T
547
+ ) {
548
+ super(database, database.dialect as Dialect<C,S, D>);
549
+ }
550
+
551
+ /**
552
+ * COUNT 聚合
553
+ */
554
+ count(field: keyof S[T] | '*' = '*', alias?: string): this {
555
+ this.aggregates.push({ fn: 'count', field, alias: alias || `count_${String(field)}` });
556
+ return this;
557
+ }
558
+
559
+ /**
560
+ * SUM 聚合
561
+ */
562
+ sum(field: keyof S[T], alias?: string): this {
563
+ this.aggregates.push({ fn: 'sum', field, alias: alias || `sum_${String(field)}` });
564
+ return this;
565
+ }
566
+
567
+ /**
568
+ * AVG 聚合
569
+ */
570
+ avg(field: keyof S[T], alias?: string): this {
571
+ this.aggregates.push({ fn: 'avg', field, alias: alias || `avg_${String(field)}` });
572
+ return this;
573
+ }
574
+
575
+ /**
576
+ * MIN 聚合
577
+ */
578
+ min(field: keyof S[T], alias?: string): this {
579
+ this.aggregates.push({ fn: 'min', field, alias: alias || `min_${String(field)}` });
580
+ return this;
581
+ }
582
+
583
+ /**
584
+ * MAX 聚合
585
+ */
586
+ max(field: keyof S[T], alias?: string): this {
587
+ this.aggregates.push({ fn: 'max', field, alias: alias || `max_${String(field)}` });
588
+ return this;
589
+ }
590
+
591
+ /**
592
+ * WHERE 条件
593
+ */
594
+ where(query: Condition<S[T]>): this {
595
+ this.conditions = { ...this.conditions, ...query };
596
+ return this;
597
+ }
598
+
599
+ /**
600
+ * GROUP BY
601
+ */
602
+ groupBy(...fields: (keyof S[T])[]): this {
603
+ this.groupings.push(...fields);
604
+ return this;
605
+ }
606
+
607
+ /**
608
+ * HAVING 条件(用于聚合后的过滤)
609
+ */
610
+ having(query: Condition<S[T]>): this {
611
+ this.havingConditions = { ...this.havingConditions, ...query };
612
+ return this;
613
+ }
614
+
615
+ protected getQueryParams(): QueryParams<S,T> {
616
+ return {
617
+ type: 'aggregate',
618
+ tableName: this.modelName,
619
+ aggregates: this.aggregates,
620
+ conditions: this.conditions,
621
+ groupings: this.groupings,
622
+ havingConditions: this.havingConditions
623
+ };
624
+ }
625
+ }