@zhin.js/database 1.0.44 → 1.0.47
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/package.json +7 -4
- package/CHANGELOG.md +0 -287
- package/src/base/database.ts +0 -272
- package/src/base/dialect.ts +0 -89
- package/src/base/index.ts +0 -6
- package/src/base/model.ts +0 -329
- package/src/base/query-classes.ts +0 -625
- package/src/base/thenable.ts +0 -55
- package/src/base/transaction.ts +0 -213
- package/src/dialects/memory.ts +0 -882
- package/src/dialects/mongodb.ts +0 -535
- package/src/dialects/mysql.ts +0 -286
- package/src/dialects/pg.ts +0 -284
- package/src/dialects/redis.ts +0 -600
- package/src/dialects/sqlite.ts +0 -317
- package/src/index.ts +0 -19
- package/src/migration.ts +0 -547
- package/src/registry.ts +0 -59
- package/src/type/document/database.ts +0 -284
- package/src/type/document/model.ts +0 -87
- package/src/type/keyvalue/database.ts +0 -262
- package/src/type/keyvalue/model.ts +0 -339
- package/src/type/related/database.ts +0 -674
- package/src/type/related/model.ts +0 -884
- package/src/types.ts +0 -918
- package/tests/database.test.ts +0 -1750
- package/tests/dialects.test.ts +0 -147
- package/tests/migration.test.ts +0 -73
- package/tsconfig.json +0 -24
|
@@ -1,625 +0,0 @@
|
|
|
1
|
-
import type { Database } from './database.js';
|
|
2
|
-
import type { Dialect } from './dialect.js';
|
|
3
|
-
import { ThenableQuery } from './thenable.js';
|
|
4
|
-
import { QueryParams, AlterDefinition, Condition, Ordering, Definition, AggregateField, AggregateFunction, Subquery, JoinClause, JoinType, ModelOptions } from '../types.js';
|
|
5
|
-
|
|
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> {
|
|
10
|
-
constructor(
|
|
11
|
-
database: Database<C, S, D>,
|
|
12
|
-
private readonly tableName: T,
|
|
13
|
-
private readonly alterations: AlterDefinition<S[T]>
|
|
14
|
-
) {
|
|
15
|
-
super(database, database.dialect as Dialect<C,S, D>);
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
protected getQueryParams(): QueryParams<S,T> {
|
|
19
|
-
return {
|
|
20
|
-
type: 'alter',
|
|
21
|
-
tableName: this.tableName,
|
|
22
|
-
alterations: this.alterations
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
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]> = {};
|
|
29
|
-
|
|
30
|
-
constructor(
|
|
31
|
-
database: Database<C, S, any>,
|
|
32
|
-
private readonly tableName: T
|
|
33
|
-
) {
|
|
34
|
-
super(database, database.dialect as Dialect<C,S, D>);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
where(query: Condition<S[T]>): this {
|
|
38
|
-
this.conditions = { ...this.conditions, ...query };
|
|
39
|
-
return this;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
protected getQueryParams(): QueryParams<S,T> {
|
|
43
|
-
return {
|
|
44
|
-
type: 'drop_table',
|
|
45
|
-
tableName: this.tableName,
|
|
46
|
-
conditions: this.conditions
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export class DroppingIndex<S extends Record<string, object>, T extends keyof S,C = any, D = string> extends ThenableQuery<number,S,T, C, D> {
|
|
52
|
-
private conditions: Condition<any> = {};
|
|
53
|
-
|
|
54
|
-
constructor(
|
|
55
|
-
database: Database<C, S, D>,
|
|
56
|
-
private readonly indexName: string,
|
|
57
|
-
private readonly tableName: T
|
|
58
|
-
) {
|
|
59
|
-
super(database, database.dialect as Dialect<C,S, D>);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
where(query: Condition<S[T]>): this {
|
|
63
|
-
this.conditions = { ...this.conditions, ...query };
|
|
64
|
-
return this;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
protected getQueryParams(): QueryParams<S,T> {
|
|
68
|
-
return {
|
|
69
|
-
type: 'drop_index',
|
|
70
|
-
tableName: this.tableName,
|
|
71
|
-
indexName: this.indexName,
|
|
72
|
-
conditions: this.conditions
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
export class Creation<S extends Record<string, object>, T extends keyof S, C = any, D = string> extends ThenableQuery<void,S,T, C, D> {
|
|
78
|
-
constructor(
|
|
79
|
-
database: Database<C, S, D>,
|
|
80
|
-
private readonly tableName: T,
|
|
81
|
-
private readonly definition: Definition<S[T]>
|
|
82
|
-
) {
|
|
83
|
-
super(database, database.dialect as Dialect<C,S, D>);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
protected getQueryParams(): QueryParams<S,T> {
|
|
87
|
-
return {
|
|
88
|
-
type: 'create',
|
|
89
|
-
tableName: this.tableName,
|
|
90
|
-
definition: this.definition
|
|
91
|
-
};
|
|
92
|
-
}
|
|
93
|
-
}
|
|
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
|
-
*/
|
|
124
|
-
export class Selection<
|
|
125
|
-
S extends Record<string, object>, T extends keyof S,
|
|
126
|
-
K extends keyof S[T],
|
|
127
|
-
C = any,
|
|
128
|
-
D = string
|
|
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;
|
|
138
|
-
|
|
139
|
-
constructor(
|
|
140
|
-
database: Database<C, S, D>,
|
|
141
|
-
protected readonly modelName: T,
|
|
142
|
-
protected readonly fields: Array<K>
|
|
143
|
-
) {
|
|
144
|
-
super(database, database.dialect as Dialect<C,S, D>);
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
where(query: Condition<S[T]>): this {
|
|
148
|
-
this.conditions = { ...this.conditions, ...query };
|
|
149
|
-
return this;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
groupBy(...fields: (keyof S[T])[]): this {
|
|
153
|
-
this.groupings.push(...fields);
|
|
154
|
-
return this;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
orderBy(field: keyof S[T], direction: "ASC" | "DESC" = "ASC"): this {
|
|
158
|
-
this.orderings.push({ field, direction });
|
|
159
|
-
return this;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
limit(count: number): this {
|
|
163
|
-
this.limitCount = count;
|
|
164
|
-
return this;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
offset(count: number): this {
|
|
168
|
-
this.offsetCount = count;
|
|
169
|
-
return this;
|
|
170
|
-
}
|
|
171
|
-
|
|
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> {
|
|
266
|
-
return {
|
|
267
|
-
type: 'select',
|
|
268
|
-
tableName: this.modelName,
|
|
269
|
-
fields: this.fields,
|
|
270
|
-
conditions: this.conditions,
|
|
271
|
-
groupings: this.groupings,
|
|
272
|
-
orderings: this.orderings,
|
|
273
|
-
limitCount: this.limitCount,
|
|
274
|
-
offsetCount: this.offsetCount
|
|
275
|
-
};
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
|
|
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> {
|
|
422
|
-
constructor(
|
|
423
|
-
database: Database<C, S, D>,
|
|
424
|
-
private readonly modelName: T,
|
|
425
|
-
private readonly data: S[T]
|
|
426
|
-
) {
|
|
427
|
-
super(database, database.dialect as Dialect<C,S, D>);
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
protected getQueryParams(): QueryParams<S,T> {
|
|
431
|
-
return {
|
|
432
|
-
type: 'insert',
|
|
433
|
-
tableName: this.modelName,
|
|
434
|
-
data: this.data
|
|
435
|
-
};
|
|
436
|
-
}
|
|
437
|
-
}
|
|
438
|
-
|
|
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]> = {};
|
|
441
|
-
|
|
442
|
-
constructor(
|
|
443
|
-
database: Database<C, S, D>,
|
|
444
|
-
private readonly modelName: T,
|
|
445
|
-
private readonly update: Partial<S[T]>
|
|
446
|
-
) {
|
|
447
|
-
super(database, database.dialect as Dialect<C,S, D>);
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
where(query: Condition<S[T]>): this {
|
|
451
|
-
this.conditions = { ...this.conditions, ...query };
|
|
452
|
-
return this;
|
|
453
|
-
}
|
|
454
|
-
|
|
455
|
-
protected getQueryParams(): QueryParams<S,T> {
|
|
456
|
-
return {
|
|
457
|
-
type: 'update',
|
|
458
|
-
tableName: this.modelName,
|
|
459
|
-
update: this.update,
|
|
460
|
-
conditions: this.conditions
|
|
461
|
-
};
|
|
462
|
-
}
|
|
463
|
-
}
|
|
464
|
-
|
|
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]> = {};
|
|
467
|
-
|
|
468
|
-
constructor(
|
|
469
|
-
database: Database<C, S, D>,
|
|
470
|
-
private readonly modelName: T
|
|
471
|
-
) {
|
|
472
|
-
super(database, database.dialect);
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
where(query: Condition<S[T]>): this {
|
|
476
|
-
this.conditions = { ...this.conditions, ...query };
|
|
477
|
-
return this;
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
protected getQueryParams(): QueryParams<S,T> {
|
|
481
|
-
return {
|
|
482
|
-
type: 'delete',
|
|
483
|
-
tableName: this.modelName,
|
|
484
|
-
conditions: this.conditions
|
|
485
|
-
};
|
|
486
|
-
}
|
|
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
|
-
}
|
package/src/base/thenable.ts
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import type { Database } from "./database.js";
|
|
2
|
-
import type { Dialect } from "./dialect.js";
|
|
3
|
-
import { QueryParams } from "../types.js";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
export abstract class ThenableQuery<R,S extends Record<string, object>, T extends keyof S,C=any,D=string>
|
|
7
|
-
implements PromiseLike<R>, AsyncIterable<R>
|
|
8
|
-
{
|
|
9
|
-
protected constructor(protected readonly database: Database<C,S,D>,protected readonly dialect: Dialect<C,S,D>) {}
|
|
10
|
-
|
|
11
|
-
// Abstract method to get query parameters
|
|
12
|
-
protected abstract getQueryParams(): QueryParams<S,T>;
|
|
13
|
-
[Symbol.toStringTag] = 'ThenableQuery';
|
|
14
|
-
then<TResult1 = R, TResult2 = never>(
|
|
15
|
-
onfulfilled?:
|
|
16
|
-
| ((value: R) => TResult1 | PromiseLike<TResult1>)
|
|
17
|
-
| undefined
|
|
18
|
-
| null,
|
|
19
|
-
onrejected?:
|
|
20
|
-
| ((reason: any) => TResult2 | PromiseLike<TResult2>)
|
|
21
|
-
| undefined
|
|
22
|
-
| null
|
|
23
|
-
): Promise<TResult1 | TResult2> {
|
|
24
|
-
const params = this.getQueryParams();
|
|
25
|
-
const { query, params: queryParams } = this.database.buildQuery(params);
|
|
26
|
-
// 使用 database.query 以支持日志记录
|
|
27
|
-
return this.database.query<R>(query, queryParams).then(onfulfilled, onrejected);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
catch<TResult = never>(
|
|
31
|
-
onrejected?:
|
|
32
|
-
| ((reason: any) => TResult | PromiseLike<TResult>)
|
|
33
|
-
| undefined
|
|
34
|
-
| null
|
|
35
|
-
): Promise<any | TResult> {
|
|
36
|
-
const params = this.getQueryParams();
|
|
37
|
-
const { query, params: queryParams } = this.database.buildQuery(params);
|
|
38
|
-
return this.database.query(query, queryParams).catch(onrejected);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
finally(onfinally?: (() => void) | undefined | null): Promise<any> {
|
|
42
|
-
const params = this.getQueryParams();
|
|
43
|
-
const { query, params: queryParams } = this.database.buildQuery(params);
|
|
44
|
-
return this.database.query(query, queryParams).finally(onfinally);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
async *[Symbol.asyncIterator](): AsyncIterator<R, void, unknown> {
|
|
48
|
-
const params = this.getQueryParams();
|
|
49
|
-
const { query, params: queryParams } = this.database.buildQuery(params);
|
|
50
|
-
const rows = await this.database.query(query, queryParams);
|
|
51
|
-
for (const row of Array.isArray(rows) ? rows : [rows]) {
|
|
52
|
-
yield row;
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
}
|