@zhin.js/database 1.0.45 → 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.
@@ -1,674 +0,0 @@
1
- import { Database,Dialect,Model } from '../../base/index.js';
2
- import { RelatedModel } from './model.js';
3
- import {
4
- QueryParams,
5
- BuildQueryResult,
6
- CreateQueryParams,
7
- SelectQueryParams,
8
- InsertQueryParams,
9
- InsertManyQueryParams,
10
- UpdateQueryParams,
11
- DeleteQueryParams,
12
- AlterQueryParams,
13
- DropTableQueryParams,
14
- DropIndexQueryParams,
15
- AggregateQueryParams,
16
- Condition,
17
- Column,
18
- AddDefinition,
19
- ModifyDefinition,
20
- DropDefinition,
21
- Subquery,
22
- JoinClause,
23
- RelationsConfig,
24
- isCreateQuery,
25
- isSelectQuery,
26
- isInsertQuery,
27
- isInsertManyQuery,
28
- isUpdateQuery,
29
- isDeleteQuery,
30
- isAlterQuery,
31
- isDropTableQuery,
32
- isDropIndexQuery,
33
- isAggregateQuery,
34
- } from '../../types.js';
35
-
36
- /**
37
- * 判断是否为子查询对象
38
- */
39
- function isSubquery(value: any): value is Subquery {
40
- return value && typeof value === 'object' && value.__isSubquery === true;
41
- }
42
-
43
- /**
44
- * 关系型数据库类
45
- * 支持表、行、列的关系型数据模型
46
- */
47
- export class RelatedDatabase<
48
- D=any,
49
- S extends Record<string, object> = Record<string, object>
50
- > extends Database<D,S,string> {
51
-
52
- /** 关系配置 */
53
- protected relationsConfig?: RelationsConfig<S>;
54
-
55
- constructor(
56
- dialect: Dialect<D,S,string>,
57
- definitions?: Database.DefinitionObj<S>,
58
- relations?: RelationsConfig<S>,
59
- ) {
60
- super(dialect,definitions);
61
- this.relationsConfig = relations;
62
- }
63
-
64
- /**
65
- * 设置关系配置
66
- * @example
67
- * ```ts
68
- * db.defineRelations({
69
- * users: {
70
- * hasMany: { orders: 'userId' },
71
- * hasOne: { profile: 'userId' }
72
- * },
73
- * orders: {
74
- * belongsTo: { users: 'userId' }
75
- * }
76
- * });
77
- * ```
78
- */
79
- defineRelations(config: RelationsConfig<S>): this {
80
- this.relationsConfig = config;
81
- // 清除模型缓存,以便重新应用关系
82
- this.models.clear();
83
- return this;
84
- }
85
-
86
- protected async initialize(): Promise<void> {
87
- // 并行创建所有表以提高性能
88
- const tableEntries = Array.from(this.definitions.entries());
89
- await Promise.all(
90
- tableEntries.map(async ([tableName, definition]) => {
91
- await this.create(tableName, definition);
92
- })
93
- );
94
- // 创建完成后,统一设置 models(避免并发竞争)
95
- for (const [tableName, definition] of tableEntries) {
96
- this.models.set(tableName, new RelatedModel(this, tableName, definition));
97
- }
98
- }
99
-
100
- // SQL generation method
101
- buildQuery<T extends keyof S>(params: QueryParams<S,T>): BuildQueryResult<string> {
102
- if (isCreateQuery(params)) {
103
- return this.buildCreateQuery(params);
104
- } else if (isSelectQuery(params)) {
105
- return this.buildSelectQuery(params);
106
- } else if (isInsertQuery(params)) {
107
- return this.buildInsertQuery(params);
108
- } else if (isInsertManyQuery(params)) {
109
- return this.buildInsertManyQuery(params);
110
- } else if (isUpdateQuery(params)) {
111
- return this.buildUpdateQuery(params);
112
- } else if (isDeleteQuery(params)) {
113
- return this.buildDeleteQuery(params);
114
- } else if (isAlterQuery(params)) {
115
- return this.buildAlterQuery(params);
116
- } else if (isDropTableQuery(params)) {
117
- return this.buildDropTableQuery(params);
118
- } else if (isDropIndexQuery(params)) {
119
- return this.buildDropIndexQuery(params);
120
- } else if (isAggregateQuery(params)) {
121
- return this.buildAggregateQuery(params);
122
- } else {
123
- throw new Error(`Unsupported query type: ${(params as any).type}`);
124
- }
125
- }
126
-
127
- // ========================================================================
128
- // CREATE TABLE Query
129
- // ========================================================================
130
-
131
- protected buildCreateQuery<T extends keyof S>(params: CreateQueryParams<S,T>): BuildQueryResult<string> {
132
- const columnDefs = Object.entries(params.definition).map(([field, column]) => this.formatColumnDefinition(field,column as Column));
133
- const query = this.dialect.formatCreateTable(params.tableName, columnDefs);
134
- return { query, params: [] };
135
- }
136
-
137
- // ========================================================================
138
- // SELECT Query
139
- // ========================================================================
140
-
141
- protected buildSelectQuery<T extends keyof S>(params: SelectQueryParams<S,T>): BuildQueryResult<string> {
142
- const tableName = String(params.tableName);
143
- const hasJoins = params.joins && params.joins.length > 0;
144
-
145
- // 构建字段列表(有 JOIN 时需要加表名前缀)
146
- const fields = params.fields && params.fields.length
147
- ? params.fields.map(f => {
148
- const fieldName = this.dialect.quoteIdentifier(String(f));
149
- return hasJoins
150
- ? `${this.dialect.quoteIdentifier(tableName)}.${fieldName}`
151
- : fieldName;
152
- }).join(', ')
153
- : hasJoins ? `${this.dialect.quoteIdentifier(tableName)}.*` : '*';
154
-
155
- let query = `SELECT ${fields} FROM ${this.dialect.quoteIdentifier(tableName)}`;
156
- const queryParams: any[] = [];
157
-
158
- // JOIN clauses
159
- if (hasJoins) {
160
- for (const join of params.joins!) {
161
- query += ` ${this.formatJoinClause(tableName, join)}`;
162
- }
163
- }
164
-
165
- // WHERE clause
166
- if (params.conditions) {
167
- const [condition, conditionParams] = this.parseCondition(params.conditions, hasJoins ? tableName : undefined);
168
- if (condition) {
169
- query += ` WHERE ${condition}`;
170
- queryParams.push(...conditionParams);
171
- }
172
- }
173
-
174
- // GROUP BY clause
175
- if (params.groupings && params.groupings.length) {
176
- const groupings = params.groupings.map(f => {
177
- const fieldName = this.dialect.quoteIdentifier(String(f));
178
- return hasJoins
179
- ? `${this.dialect.quoteIdentifier(tableName)}.${fieldName}`
180
- : fieldName;
181
- }).join(', ');
182
- query += ` GROUP BY ${groupings}`;
183
- }
184
-
185
- // ORDER BY clause
186
- if (params.orderings && params.orderings.length) {
187
- const orderings = params.orderings
188
- .map(o => {
189
- const fieldName = this.dialect.quoteIdentifier(String(o.field));
190
- const fullField = hasJoins
191
- ? `${this.dialect.quoteIdentifier(tableName)}.${fieldName}`
192
- : fieldName;
193
- return `${fullField} ${o.direction}`;
194
- })
195
- .join(', ');
196
- query += ` ORDER BY ${orderings}`;
197
- }
198
-
199
- // LIMIT and OFFSET
200
- if (params.limitCount !== undefined && params.offsetCount !== undefined) {
201
- query += ` ${this.dialect.formatLimitOffset(params.limitCount, params.offsetCount)}`;
202
- } else if (params.limitCount !== undefined) {
203
- query += ` ${this.dialect.formatLimit(params.limitCount)}`;
204
- } else if (params.offsetCount !== undefined) {
205
- query += ` ${this.dialect.formatOffset(params.offsetCount)}`;
206
- }
207
-
208
- return { query, params: queryParams };
209
- }
210
-
211
- /**
212
- * 格式化 JOIN 子句
213
- */
214
- protected formatJoinClause<T extends keyof S>(
215
- mainTable: string,
216
- join: JoinClause<S, T, keyof S>
217
- ): string {
218
- const joinTable = this.dialect.quoteIdentifier(String(join.table));
219
- const leftField = `${this.dialect.quoteIdentifier(mainTable)}.${this.dialect.quoteIdentifier(String(join.leftField))}`;
220
- const rightField = `${joinTable}.${this.dialect.quoteIdentifier(String(join.rightField))}`;
221
-
222
- return `${join.type} JOIN ${joinTable} ON ${leftField} = ${rightField}`;
223
- }
224
-
225
- // ========================================================================
226
- // INSERT Query
227
- // ========================================================================
228
-
229
- protected buildInsertQuery<T extends keyof S>(params: InsertQueryParams<S,T>): BuildQueryResult<string> {
230
- const keys = Object.keys(params.data);
231
- const columns = keys.map(k => this.dialect.quoteIdentifier(k)).join(', ');
232
- const placeholders = keys.map((_, index) => this.dialect.getParameterPlaceholder(index)).join(', ');
233
-
234
- const query = `INSERT INTO ${this.dialect.quoteIdentifier(params.tableName)} (${columns}) VALUES (${placeholders})`;
235
- // 直接传值,不要格式化(参数化查询由驱动处理)
236
- const values = Object.values(params.data);
237
-
238
- return { query, params: values };
239
- }
240
-
241
- // ========================================================================
242
- // INSERT MANY Query (Batch Insert)
243
- // ========================================================================
244
-
245
- protected buildInsertManyQuery<T extends keyof S>(params: InsertManyQueryParams<S,T>): BuildQueryResult<string> {
246
- if (!params.data.length) {
247
- throw new Error('Cannot insert empty array');
248
- }
249
-
250
- const keys = Object.keys(params.data[0]);
251
- const columns = keys.map(k => this.dialect.quoteIdentifier(k)).join(', ');
252
-
253
- const allValues: any[] = [];
254
- const valueRows: string[] = [];
255
-
256
- params.data.forEach((row, rowIndex) => {
257
- const placeholders = keys.map((_, colIndex) =>
258
- this.dialect.getParameterPlaceholder(rowIndex * keys.length + colIndex)
259
- ).join(', ');
260
- valueRows.push(`(${placeholders})`);
261
-
262
- keys.forEach(key => {
263
- // 直接传值,不要格式化(参数化查询由驱动处理)
264
- allValues.push((row as any)[key]);
265
- });
266
- });
267
-
268
- const query = `INSERT INTO ${this.dialect.quoteIdentifier(params.tableName)} (${columns}) VALUES ${valueRows.join(', ')}`;
269
-
270
- return { query, params: allValues };
271
- }
272
-
273
- // ========================================================================
274
- // UPDATE Query
275
- // ========================================================================
276
-
277
- protected buildUpdateQuery<T extends keyof S>(params: UpdateQueryParams<S,T>): BuildQueryResult<string> {
278
- const updateKeys = Object.keys(params.update);
279
- const setClause = updateKeys
280
- .map((k, index) => `${this.dialect.quoteIdentifier(k)} = ${this.dialect.getParameterPlaceholder(index)}`)
281
- .join(', ');
282
-
283
- let query = `UPDATE ${this.dialect.quoteIdentifier(params.tableName)} SET ${setClause}`;
284
- const queryParams: any[] = [...Object.values(params.update)];
285
-
286
- // WHERE clause
287
- if (params.conditions) {
288
- const [condition, conditionParams] = this.parseCondition(params.conditions);
289
- if (condition) {
290
- query += ` WHERE ${condition}`;
291
- queryParams.push(...conditionParams);
292
- }
293
- }
294
-
295
- return { query, params: queryParams };
296
- }
297
-
298
- // ========================================================================
299
- // DELETE Query
300
- // ========================================================================
301
-
302
- protected buildDeleteQuery<T extends keyof S>(params: DeleteQueryParams<S,T>): BuildQueryResult<string> {
303
- let query = `DELETE FROM ${this.dialect.quoteIdentifier(params.tableName)}`;
304
- const queryParams: any[] = [];
305
-
306
- // WHERE clause
307
- if (params.conditions) {
308
- const [condition, conditionParams] = this.parseCondition(params.conditions);
309
- if (condition) {
310
- query += ` WHERE ${condition}`;
311
- queryParams.push(...conditionParams);
312
- }
313
- }
314
-
315
- return { query, params: queryParams };
316
- }
317
-
318
- // ========================================================================
319
- // ALTER TABLE Query
320
- // ========================================================================
321
-
322
- protected buildAlterQuery<T extends keyof S>(params: AlterQueryParams<S,T>): BuildQueryResult<string> {
323
- const alterations = Object.entries(params.alterations).map(([field,alteration]) => this.formatAlteration(field, alteration as AddDefinition<T> | ModifyDefinition<T> | DropDefinition));
324
- const query = this.dialect.formatAlterTable(params.tableName, alterations);
325
- return { query, params: [] };
326
- }
327
-
328
- // ========================================================================
329
- // DROP TABLE Query
330
- // ========================================================================
331
-
332
- protected buildDropTableQuery<T extends keyof S>(params: DropTableQueryParams<S,T>): BuildQueryResult<string> {
333
- const query = this.dialect.formatDropTable(params.tableName, true);
334
- return { query, params: [] };
335
- }
336
-
337
- // ========================================================================
338
- // DROP INDEX Query
339
- // ========================================================================
340
-
341
- protected buildDropIndexQuery<T extends keyof S>(params: DropIndexQueryParams<S,T>): BuildQueryResult<string> {
342
- const query = this.dialect.formatDropIndex(params.indexName, params.tableName, true);
343
- return { query, params: [] };
344
- }
345
-
346
- // ========================================================================
347
- // AGGREGATE Query
348
- // ========================================================================
349
-
350
- protected buildAggregateQuery<T extends keyof S>(params: AggregateQueryParams<S,T>): BuildQueryResult<string> {
351
- if (!params.aggregates.length) {
352
- throw new Error('At least one aggregate function is required');
353
- }
354
-
355
- // Build SELECT fields with aggregate functions
356
- const selectFields: string[] = [];
357
-
358
- // Add grouping fields to select
359
- if (params.groupings && params.groupings.length) {
360
- params.groupings.forEach(field => {
361
- selectFields.push(this.dialect.quoteIdentifier(String(field)));
362
- });
363
- }
364
-
365
- // Add aggregate functions
366
- params.aggregates.forEach(agg => {
367
- selectFields.push(this.dialect.formatAggregate(agg.fn, String(agg.field), agg.alias));
368
- });
369
-
370
- let query = `SELECT ${selectFields.join(', ')} FROM ${this.dialect.quoteIdentifier(params.tableName)}`;
371
- const queryParams: any[] = [];
372
-
373
- // WHERE clause
374
- if (params.conditions) {
375
- const [condition, conditionParams] = this.parseCondition(params.conditions);
376
- if (condition) {
377
- query += ` WHERE ${condition}`;
378
- queryParams.push(...conditionParams);
379
- }
380
- }
381
-
382
- // GROUP BY clause
383
- if (params.groupings && params.groupings.length) {
384
- const groupings = params.groupings.map(f => this.dialect.quoteIdentifier(String(f))).join(', ');
385
- query += ` GROUP BY ${groupings}`;
386
- }
387
-
388
- // HAVING clause
389
- if (params.havingConditions && Object.keys(params.havingConditions).length) {
390
- const [havingCondition, havingParams] = this.parseCondition(params.havingConditions);
391
- if (havingCondition) {
392
- query += ` HAVING ${havingCondition}`;
393
- queryParams.push(...havingParams);
394
- }
395
- }
396
-
397
- return { query, params: queryParams };
398
- }
399
-
400
- // ========================================================================
401
- // Helper Methods
402
- // ========================================================================
403
-
404
- protected formatColumnDefinition<T =any>(field: string, column: Column<T>): string {
405
- const name = this.dialect.quoteIdentifier(String(field));
406
- const type = this.dialect.mapColumnType(column.type);
407
- const length = column.length ? `(${column.length})` : '';
408
- const nullable = column.nullable === false ? ' NOT NULL' : '';
409
- const primary = column.primary ? ' PRIMARY KEY' : '';
410
- const unique = column.unique ? ' UNIQUE' : '';
411
- const defaultVal = column.default !== undefined
412
- ? ` DEFAULT ${this.dialect.formatDefaultValue(column.default)}`
413
- : '';
414
-
415
- return `${name} ${type}${length}${primary}${unique}${nullable}${defaultVal}`;
416
- }
417
-
418
- protected formatAlteration<T=any>(field:string,alteration: AddDefinition<T> | ModifyDefinition<T> | DropDefinition): string {
419
- const name = this.dialect.quoteIdentifier(field);
420
-
421
- switch (alteration.action) {
422
- case 'add':
423
- // 将 alteration 转换为 Column 格式
424
- const addColumn: Column<T> = {
425
- type: alteration.type,
426
- nullable: alteration.nullable,
427
- default: alteration.default,
428
- primary: alteration.primary,
429
- length: alteration.length
430
- };
431
- return `ADD COLUMN ${this.formatColumnDefinition(field, addColumn)}`;
432
- case 'modify':
433
- const type = alteration.type ? this.dialect.mapColumnType(alteration.type) : '';
434
- const length = alteration.length ? `(${alteration.length})` : '';
435
- const nullable = alteration.nullable !== undefined
436
- ? (alteration.nullable ? ' NULL' : ' NOT NULL')
437
- : '';
438
- const defaultVal = alteration.default !== undefined
439
- ? ` DEFAULT ${this.dialect.formatDefaultValue(alteration.default)}`
440
- : '';
441
- return `MODIFY COLUMN ${name} ${type}${length}${nullable}${defaultVal}`;
442
- case 'drop':
443
- return `DROP COLUMN ${name}`;
444
- default:
445
- throw new Error(`Unsupported alteration action`);
446
- }
447
- }
448
-
449
- /**
450
- * 解析条件对象为 SQL WHERE 子句
451
- * @param condition 条件对象
452
- * @param tablePrefix 表名前缀(用于 JOIN 查询)
453
- */
454
- protected parseCondition<T extends object>(condition: Condition<T>, tablePrefix?: string): [string, any[]] {
455
- const clauses: string[] = [];
456
- const params: any[] = [];
457
-
458
- // 辅助函数:生成带前缀的字段名
459
- const formatField = (field: string): string => {
460
- const quotedField = this.dialect.quoteIdentifier(field);
461
- return tablePrefix
462
- ? `${this.dialect.quoteIdentifier(tablePrefix)}.${quotedField}`
463
- : quotedField;
464
- };
465
-
466
- for (const key in condition) {
467
- if (key === '$and' && Array.isArray((condition as any).$and)) {
468
- const subClauses: string[] = [];
469
- for (const subCondition of (condition as any).$and) {
470
- const [subClause, subParams] = this.parseCondition(subCondition, tablePrefix);
471
- if (subClause) {
472
- subClauses.push(`(${subClause})`);
473
- params.push(...subParams);
474
- }
475
- }
476
- if (subClauses.length) {
477
- clauses.push(subClauses.join(' AND '));
478
- }
479
- } else if (key === '$or' && Array.isArray((condition as any).$or)) {
480
- const subClauses: string[] = [];
481
- for (const subCondition of (condition as any).$or) {
482
- const [subClause, subParams] = this.parseCondition(subCondition, tablePrefix);
483
- if (subClause) {
484
- subClauses.push(`(${subClause})`);
485
- params.push(...subParams);
486
- }
487
- }
488
- if (subClauses.length) {
489
- clauses.push(subClauses.join(' OR '));
490
- }
491
- } else if (key === '$not' && (condition as any).$not) {
492
- const [subClause, subParams] = this.parseCondition((condition as any).$not, tablePrefix);
493
- if (subClause) {
494
- clauses.push(`NOT (${subClause})`);
495
- params.push(...subParams);
496
- }
497
- } else {
498
- const value = (condition as any)[key];
499
- if (value && typeof value === 'object' && !Array.isArray(value)) {
500
- for (const op in value) {
501
- const quotedKey = formatField(key);
502
- const placeholder = this.dialect.getParameterPlaceholder(params.length);
503
-
504
- switch (op) {
505
- case '$eq':
506
- if (value[op] === null) {
507
- clauses.push(`${quotedKey} IS NULL`);
508
- } else {
509
- clauses.push(`${quotedKey} = ${placeholder}`);
510
- params.push(value[op]);
511
- }
512
- break;
513
- case '$ne':
514
- if (value[op] === null) {
515
- clauses.push(`${quotedKey} IS NOT NULL`);
516
- } else {
517
- clauses.push(`${quotedKey} <> ${placeholder}`);
518
- params.push(value[op]);
519
- }
520
- break;
521
- case '$gt':
522
- clauses.push(`${quotedKey} > ${placeholder}`);
523
- params.push(value[op]);
524
- break;
525
- case '$gte':
526
- clauses.push(`${quotedKey} >= ${placeholder}`);
527
- params.push(value[op]);
528
- break;
529
- case '$lt':
530
- clauses.push(`${quotedKey} < ${placeholder}`);
531
- params.push(value[op]);
532
- break;
533
- case '$lte':
534
- clauses.push(`${quotedKey} <= ${placeholder}`);
535
- params.push(value[op]);
536
- break;
537
- case '$in':
538
- if (isSubquery(value[op])) {
539
- // 子查询
540
- const subquery = value[op].toSQL();
541
- clauses.push(`${quotedKey} IN (${subquery.sql})`);
542
- params.push(...subquery.params);
543
- } else if (Array.isArray(value[op]) && value[op].length) {
544
- const placeholders = value[op].map((_: any, i: number) => this.dialect.getParameterPlaceholder(params.length + i));
545
- clauses.push(`${quotedKey} IN (${placeholders.join(', ')})`);
546
- params.push(...value[op]);
547
- } else {
548
- clauses.push('1=0'); // Empty IN clause should yield no results
549
- }
550
- break;
551
- case '$nin':
552
- if (isSubquery(value[op])) {
553
- // 子查询
554
- const subquery = value[op].toSQL();
555
- clauses.push(`${quotedKey} NOT IN (${subquery.sql})`);
556
- params.push(...subquery.params);
557
- } else if (Array.isArray(value[op]) && value[op].length) {
558
- const placeholders = value[op].map((_: any, i: number) => this.dialect.getParameterPlaceholder(params.length + i));
559
- clauses.push(`${quotedKey} NOT IN (${placeholders.join(', ')})`);
560
- params.push(...value[op]);
561
- }
562
- break;
563
- case '$like':
564
- clauses.push(`${quotedKey} LIKE ${placeholder}`);
565
- params.push(value[op]);
566
- break;
567
- case '$nlike':
568
- clauses.push(`${quotedKey} NOT LIKE ${placeholder}`);
569
- params.push(value[op]);
570
- break;
571
- }
572
- }
573
- } else {
574
- const quotedKey = formatField(key);
575
- // null 值使用 IS NULL / IS NOT NULL
576
- if (value === null) {
577
- clauses.push(`${quotedKey} IS NULL`);
578
- } else {
579
- const placeholder = this.dialect.getParameterPlaceholder(params.length);
580
- clauses.push(`${quotedKey} = ${placeholder}`);
581
- params.push(value);
582
- }
583
- }
584
- }
585
- }
586
-
587
- return [clauses.join(' AND '), params];
588
- }
589
-
590
- /**
591
- * 获取模型
592
- * @param name 模型名称
593
- * @param options 可选的模型选项(如 softDelete, timestamps)
594
- */
595
- model<T extends keyof S>(name: T, options?: import('../../types.js').ModelOptions): RelatedModel<D,S,T> {
596
- // 如果有 options,每次都创建新的实例(因为选项可能不同)
597
- if (options) {
598
- const model = new RelatedModel(this, name, options);
599
- this.applyRelationsToModel(model, name);
600
- return model;
601
- }
602
- // 无选项时使用缓存
603
- let model = this.models.get(name) as RelatedModel<D,S,T> | undefined;
604
- if (!model) {
605
- model = new RelatedModel(this, name);
606
- this.applyRelationsToModel(model, name);
607
- this.models.set(name, model as any);
608
- }
609
- return model as RelatedModel<D,S,T>;
610
- }
611
-
612
- /**
613
- * 应用关系配置到模型
614
- */
615
- private applyRelationsToModel<T extends keyof S>(model: RelatedModel<D, S, T>, tableName: T): void {
616
- const tableConfig = this.relationsConfig?.[String(tableName) as Extract<keyof S, string>];
617
- if (!tableConfig) return;
618
-
619
- // 应用 hasMany 关系
620
- if (tableConfig.hasMany) {
621
- for (const [target, foreignKey] of Object.entries(tableConfig.hasMany)) {
622
- if (foreignKey) {
623
- const targetModel = new RelatedModel(this, target as keyof S);
624
- model.hasMany(targetModel as any, foreignKey as any);
625
- }
626
- }
627
- }
628
-
629
- // 应用 hasOne 关系
630
- if (tableConfig.hasOne) {
631
- for (const [target, foreignKey] of Object.entries(tableConfig.hasOne)) {
632
- if (foreignKey) {
633
- const targetModel = new RelatedModel(this, target as keyof S);
634
- model.hasOne(targetModel as any, foreignKey as any);
635
- }
636
- }
637
- }
638
-
639
- // 应用 belongsTo 关系
640
- if (tableConfig.belongsTo) {
641
- for (const [target, foreignKey] of Object.entries(tableConfig.belongsTo)) {
642
- if (foreignKey) {
643
- const targetModel = new RelatedModel(this, target as keyof S);
644
- model.belongsTo(targetModel as any, foreignKey as any);
645
- }
646
- }
647
- }
648
-
649
- // 应用 belongsToMany 关系
650
- if (tableConfig.belongsToMany) {
651
- for (const [target, config] of Object.entries(tableConfig.belongsToMany)) {
652
- if (config) {
653
- const targetModel = new RelatedModel(this, target as keyof S);
654
- model.belongsToMany(
655
- targetModel as any,
656
- config.pivot,
657
- config.foreignKey,
658
- config.relatedKey,
659
- 'id' as any,
660
- 'id' as any,
661
- config.pivotFields
662
- );
663
- }
664
- }
665
- }
666
- }
667
-
668
- /**
669
- * 获取所有模型名称
670
- */
671
- getModelNames(): string[] {
672
- return Object.keys(this.definitions || {});
673
- }
674
- }