metal-orm 1.0.15 → 1.0.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +34 -27
- package/dist/decorators/index.cjs +339 -153
- package/dist/decorators/index.cjs.map +1 -1
- package/dist/decorators/index.d.cts +1 -5
- package/dist/decorators/index.d.ts +1 -5
- package/dist/decorators/index.js +339 -153
- package/dist/decorators/index.js.map +1 -1
- package/dist/index.cjs +838 -484
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +17 -14
- package/dist/index.d.ts +17 -14
- package/dist/index.js +833 -483
- package/dist/index.js.map +1 -1
- package/dist/{select-Bkv8g8u_.d.cts → select-BKZrMRCQ.d.cts} +363 -28
- package/dist/{select-Bkv8g8u_.d.ts → select-BKZrMRCQ.d.ts} +363 -28
- package/package.json +1 -1
- package/src/codegen/naming-strategy.ts +64 -0
- package/src/codegen/typescript.ts +48 -53
- package/src/core/ddl/schema-generator.ts +3 -2
- package/src/core/ddl/schema-introspect.ts +1 -1
- package/src/core/dialect/abstract.ts +28 -0
- package/src/decorators/column.ts +13 -4
- package/src/index.ts +8 -1
- package/src/orm/entity-context.ts +30 -0
- package/src/orm/entity-meta.ts +2 -2
- package/src/orm/entity-metadata.ts +1 -6
- package/src/orm/entity.ts +88 -88
- package/src/orm/execute.ts +42 -25
- package/src/orm/execution-context.ts +12 -0
- package/src/orm/hydration-context.ts +14 -0
- package/src/orm/identity-map.ts +4 -0
- package/src/orm/interceptor-pipeline.ts +29 -0
- package/src/orm/lazy-batch.ts +6 -6
- package/src/orm/orm-session.ts +234 -0
- package/src/orm/orm.ts +58 -0
- package/src/orm/relation-change-processor.ts +5 -1
- package/src/orm/relations/belongs-to.ts +45 -44
- package/src/orm/relations/has-many.ts +44 -43
- package/src/orm/relations/has-one.ts +140 -139
- package/src/orm/relations/many-to-many.ts +46 -45
- package/src/orm/unit-of-work.ts +6 -1
- package/src/query-builder/select.ts +509 -3
- package/src/orm/orm-context.ts +0 -159
package/dist/index.cjs
CHANGED
|
@@ -48,10 +48,12 @@ __export(index_exports, {
|
|
|
48
48
|
DefaultHasManyCollection: () => DefaultHasManyCollection,
|
|
49
49
|
DefaultManyToManyCollection: () => DefaultManyToManyCollection,
|
|
50
50
|
DeleteQueryBuilder: () => DeleteQueryBuilder,
|
|
51
|
+
DomainEventBus: () => DomainEventBus,
|
|
51
52
|
EntityStatus: () => EntityStatus,
|
|
52
53
|
InsertQueryBuilder: () => InsertQueryBuilder,
|
|
53
54
|
MySqlDialect: () => MySqlDialect,
|
|
54
|
-
|
|
55
|
+
Orm: () => Orm,
|
|
56
|
+
OrmSession: () => OrmSession,
|
|
55
57
|
PostgresDialect: () => PostgresDialect,
|
|
56
58
|
RelationKinds: () => RelationKinds,
|
|
57
59
|
SelectQueryBuilder: () => SelectQueryBuilder,
|
|
@@ -93,6 +95,7 @@ __export(index_exports, {
|
|
|
93
95
|
createMssqlExecutor: () => createMssqlExecutor,
|
|
94
96
|
createMysqlExecutor: () => createMysqlExecutor,
|
|
95
97
|
createPostgresExecutor: () => createPostgresExecutor,
|
|
98
|
+
createQueryLoggingExecutor: () => createQueryLoggingExecutor,
|
|
96
99
|
createSqliteExecutor: () => createSqliteExecutor,
|
|
97
100
|
currentDate: () => currentDate,
|
|
98
101
|
currentTime: () => currentTime,
|
|
@@ -110,6 +113,7 @@ __export(index_exports, {
|
|
|
110
113
|
endOfMonth: () => endOfMonth,
|
|
111
114
|
eq: () => eq,
|
|
112
115
|
executeHydrated: () => executeHydrated,
|
|
116
|
+
executeHydratedWithContexts: () => executeHydratedWithContexts,
|
|
113
117
|
exists: () => exists,
|
|
114
118
|
exp: () => exp,
|
|
115
119
|
extract: () => extract,
|
|
@@ -723,7 +727,7 @@ var StandardFunctionStrategy = class {
|
|
|
723
727
|
};
|
|
724
728
|
|
|
725
729
|
// src/core/dialect/abstract.ts
|
|
726
|
-
var Dialect = class {
|
|
730
|
+
var Dialect = class _Dialect {
|
|
727
731
|
/**
|
|
728
732
|
* Compiles a SELECT query AST to SQL
|
|
729
733
|
* @param ast - Query AST to compile
|
|
@@ -896,6 +900,35 @@ var Dialect = class {
|
|
|
896
900
|
this.registerDefaultOperandCompilers();
|
|
897
901
|
this.registerDefaultExpressionCompilers();
|
|
898
902
|
}
|
|
903
|
+
/**
|
|
904
|
+
* Creates a new Dialect instance (for testing purposes)
|
|
905
|
+
* @param functionStrategy - Optional function strategy
|
|
906
|
+
* @returns New Dialect instance
|
|
907
|
+
*/
|
|
908
|
+
static create(functionStrategy) {
|
|
909
|
+
class TestDialect extends _Dialect {
|
|
910
|
+
constructor() {
|
|
911
|
+
super(...arguments);
|
|
912
|
+
this.dialect = "sqlite";
|
|
913
|
+
}
|
|
914
|
+
quoteIdentifier(id) {
|
|
915
|
+
return `"${id}"`;
|
|
916
|
+
}
|
|
917
|
+
compileSelectAst() {
|
|
918
|
+
throw new Error("Not implemented");
|
|
919
|
+
}
|
|
920
|
+
compileInsertAst() {
|
|
921
|
+
throw new Error("Not implemented");
|
|
922
|
+
}
|
|
923
|
+
compileUpdateAst() {
|
|
924
|
+
throw new Error("Not implemented");
|
|
925
|
+
}
|
|
926
|
+
compileDeleteAst() {
|
|
927
|
+
throw new Error("Not implemented");
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
return new TestDialect(functionStrategy);
|
|
931
|
+
}
|
|
899
932
|
/**
|
|
900
933
|
* Registers an expression compiler for a specific node type
|
|
901
934
|
* @param type - Expression node type
|
|
@@ -4288,31 +4321,43 @@ var flattenResults = (results) => {
|
|
|
4288
4321
|
}
|
|
4289
4322
|
return rows;
|
|
4290
4323
|
};
|
|
4291
|
-
async
|
|
4324
|
+
var executeWithEntityContext = async (entityCtx, qb) => {
|
|
4292
4325
|
const ast = qb.getAST();
|
|
4293
|
-
const compiled =
|
|
4294
|
-
const executed = await
|
|
4326
|
+
const compiled = entityCtx.dialect.compileSelect(ast);
|
|
4327
|
+
const executed = await entityCtx.executor.executeSql(compiled.sql, compiled.params);
|
|
4295
4328
|
const rows = flattenResults(executed);
|
|
4296
4329
|
if (ast.setOps && ast.setOps.length > 0) {
|
|
4297
|
-
return rows.map(
|
|
4298
|
-
(row) => createEntityProxy(ctx, qb.getTable(), row, qb.getLazyRelations())
|
|
4299
|
-
);
|
|
4330
|
+
return rows.map((row) => createEntityProxy(entityCtx, qb.getTable(), row, qb.getLazyRelations()));
|
|
4300
4331
|
}
|
|
4301
4332
|
const hydrated = hydrateRows(rows, qb.getHydrationPlan());
|
|
4302
|
-
return hydrated.map(
|
|
4303
|
-
|
|
4304
|
-
|
|
4333
|
+
return hydrated.map((row) => createEntityFromRow(entityCtx, qb.getTable(), row, qb.getLazyRelations()));
|
|
4334
|
+
};
|
|
4335
|
+
async function executeHydrated(session, qb) {
|
|
4336
|
+
return executeWithEntityContext(session, qb);
|
|
4337
|
+
}
|
|
4338
|
+
async function executeHydratedWithContexts(_execCtx, hydCtx, qb) {
|
|
4339
|
+
const entityCtx = hydCtx.entityContext;
|
|
4340
|
+
if (!entityCtx) {
|
|
4341
|
+
throw new Error("Hydration context is missing an EntityContext");
|
|
4342
|
+
}
|
|
4343
|
+
return executeWithEntityContext(entityCtx, qb);
|
|
4305
4344
|
}
|
|
4306
4345
|
|
|
4307
4346
|
// src/query-builder/select.ts
|
|
4308
4347
|
var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
4309
4348
|
/**
|
|
4310
|
-
|
|
4311
|
-
|
|
4312
|
-
|
|
4313
|
-
|
|
4314
|
-
|
|
4315
|
-
|
|
4349
|
+
|
|
4350
|
+
* Creates a new SelectQueryBuilder instance
|
|
4351
|
+
|
|
4352
|
+
* @param table - Table definition to query
|
|
4353
|
+
|
|
4354
|
+
* @param state - Optional initial query state
|
|
4355
|
+
|
|
4356
|
+
* @param hydration - Optional hydration manager
|
|
4357
|
+
|
|
4358
|
+
* @param dependencies - Optional query builder dependencies
|
|
4359
|
+
|
|
4360
|
+
*/
|
|
4316
4361
|
constructor(table, state, hydration, dependencies, lazyRelations) {
|
|
4317
4362
|
const deps = resolveSelectQueryBuilderDependencies(dependencies);
|
|
4318
4363
|
this.env = { table, deps };
|
|
@@ -4349,112 +4394,168 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
4349
4394
|
return this.applyAst(this.context, (service) => service.withSetOperation(operator, subAst));
|
|
4350
4395
|
}
|
|
4351
4396
|
/**
|
|
4352
|
-
|
|
4353
|
-
|
|
4354
|
-
|
|
4355
|
-
|
|
4397
|
+
|
|
4398
|
+
* Selects specific columns for the query
|
|
4399
|
+
|
|
4400
|
+
* @param columns - Record of column definitions, function nodes, case expressions, or window functions
|
|
4401
|
+
|
|
4402
|
+
* @returns New query builder instance with selected columns
|
|
4403
|
+
|
|
4404
|
+
*/
|
|
4356
4405
|
select(columns) {
|
|
4357
4406
|
return this.clone(this.columnSelector.select(this.context, columns));
|
|
4358
4407
|
}
|
|
4359
4408
|
/**
|
|
4360
|
-
|
|
4361
|
-
|
|
4362
|
-
|
|
4363
|
-
|
|
4409
|
+
|
|
4410
|
+
* Selects raw column expressions
|
|
4411
|
+
|
|
4412
|
+
* @param cols - Column expressions as strings
|
|
4413
|
+
|
|
4414
|
+
* @returns New query builder instance with raw column selections
|
|
4415
|
+
|
|
4416
|
+
*/
|
|
4364
4417
|
selectRaw(...cols) {
|
|
4365
4418
|
return this.clone(this.columnSelector.selectRaw(this.context, cols));
|
|
4366
4419
|
}
|
|
4367
4420
|
/**
|
|
4368
|
-
|
|
4369
|
-
|
|
4370
|
-
|
|
4371
|
-
|
|
4372
|
-
|
|
4373
|
-
|
|
4421
|
+
|
|
4422
|
+
* Adds a Common Table Expression (CTE) to the query
|
|
4423
|
+
|
|
4424
|
+
* @param name - Name of the CTE
|
|
4425
|
+
|
|
4426
|
+
* @param query - Query builder or query node for the CTE
|
|
4427
|
+
|
|
4428
|
+
* @param columns - Optional column names for the CTE
|
|
4429
|
+
|
|
4430
|
+
* @returns New query builder instance with the CTE
|
|
4431
|
+
|
|
4432
|
+
*/
|
|
4374
4433
|
with(name, query, columns) {
|
|
4375
4434
|
const subAst = this.resolveQueryNode(query);
|
|
4376
4435
|
const nextContext = this.applyAst(this.context, (service) => service.withCte(name, subAst, columns, false));
|
|
4377
4436
|
return this.clone(nextContext);
|
|
4378
4437
|
}
|
|
4379
4438
|
/**
|
|
4380
|
-
|
|
4381
|
-
|
|
4382
|
-
|
|
4383
|
-
|
|
4384
|
-
|
|
4385
|
-
|
|
4439
|
+
|
|
4440
|
+
* Adds a recursive Common Table Expression (CTE) to the query
|
|
4441
|
+
|
|
4442
|
+
* @param name - Name of the CTE
|
|
4443
|
+
|
|
4444
|
+
* @param query - Query builder or query node for the CTE
|
|
4445
|
+
|
|
4446
|
+
* @param columns - Optional column names for the CTE
|
|
4447
|
+
|
|
4448
|
+
* @returns New query builder instance with the recursive CTE
|
|
4449
|
+
|
|
4450
|
+
*/
|
|
4386
4451
|
withRecursive(name, query, columns) {
|
|
4387
4452
|
const subAst = this.resolveQueryNode(query);
|
|
4388
4453
|
const nextContext = this.applyAst(this.context, (service) => service.withCte(name, subAst, columns, true));
|
|
4389
4454
|
return this.clone(nextContext);
|
|
4390
4455
|
}
|
|
4391
4456
|
/**
|
|
4392
|
-
|
|
4393
|
-
|
|
4394
|
-
|
|
4395
|
-
|
|
4396
|
-
|
|
4457
|
+
|
|
4458
|
+
* Selects a subquery as a column
|
|
4459
|
+
|
|
4460
|
+
* @param alias - Alias for the subquery column
|
|
4461
|
+
|
|
4462
|
+
* @param sub - Query builder or query node for the subquery
|
|
4463
|
+
|
|
4464
|
+
* @returns New query builder instance with the subquery selection
|
|
4465
|
+
|
|
4466
|
+
*/
|
|
4397
4467
|
selectSubquery(alias, sub) {
|
|
4398
4468
|
const query = this.resolveQueryNode(sub);
|
|
4399
4469
|
return this.clone(this.columnSelector.selectSubquery(this.context, alias, query));
|
|
4400
4470
|
}
|
|
4401
4471
|
/**
|
|
4402
|
-
|
|
4403
|
-
|
|
4404
|
-
|
|
4405
|
-
|
|
4406
|
-
|
|
4472
|
+
|
|
4473
|
+
* Adds an INNER JOIN to the query
|
|
4474
|
+
|
|
4475
|
+
* @param table - Table to join
|
|
4476
|
+
|
|
4477
|
+
* @param condition - Join condition expression
|
|
4478
|
+
|
|
4479
|
+
* @returns New query builder instance with the INNER JOIN
|
|
4480
|
+
|
|
4481
|
+
*/
|
|
4407
4482
|
innerJoin(table, condition) {
|
|
4408
4483
|
const nextContext = this.applyJoin(this.context, table, condition, JOIN_KINDS.INNER);
|
|
4409
4484
|
return this.clone(nextContext);
|
|
4410
4485
|
}
|
|
4411
4486
|
/**
|
|
4412
|
-
|
|
4413
|
-
|
|
4414
|
-
|
|
4415
|
-
|
|
4416
|
-
|
|
4487
|
+
|
|
4488
|
+
* Adds a LEFT JOIN to the query
|
|
4489
|
+
|
|
4490
|
+
* @param table - Table to join
|
|
4491
|
+
|
|
4492
|
+
* @param condition - Join condition expression
|
|
4493
|
+
|
|
4494
|
+
* @returns New query builder instance with the LEFT JOIN
|
|
4495
|
+
|
|
4496
|
+
*/
|
|
4417
4497
|
leftJoin(table, condition) {
|
|
4418
4498
|
const nextContext = this.applyJoin(this.context, table, condition, JOIN_KINDS.LEFT);
|
|
4419
4499
|
return this.clone(nextContext);
|
|
4420
4500
|
}
|
|
4421
4501
|
/**
|
|
4422
|
-
|
|
4423
|
-
|
|
4424
|
-
|
|
4425
|
-
|
|
4426
|
-
|
|
4502
|
+
|
|
4503
|
+
* Adds a RIGHT JOIN to the query
|
|
4504
|
+
|
|
4505
|
+
* @param table - Table to join
|
|
4506
|
+
|
|
4507
|
+
* @param condition - Join condition expression
|
|
4508
|
+
|
|
4509
|
+
* @returns New query builder instance with the RIGHT JOIN
|
|
4510
|
+
|
|
4511
|
+
*/
|
|
4427
4512
|
rightJoin(table, condition) {
|
|
4428
4513
|
const nextContext = this.applyJoin(this.context, table, condition, JOIN_KINDS.RIGHT);
|
|
4429
4514
|
return this.clone(nextContext);
|
|
4430
4515
|
}
|
|
4431
4516
|
/**
|
|
4432
|
-
|
|
4433
|
-
|
|
4434
|
-
|
|
4435
|
-
|
|
4436
|
-
|
|
4517
|
+
|
|
4518
|
+
* Matches records based on a relationship
|
|
4519
|
+
|
|
4520
|
+
* @param relationName - Name of the relationship to match
|
|
4521
|
+
|
|
4522
|
+
* @param predicate - Optional predicate expression
|
|
4523
|
+
|
|
4524
|
+
* @returns New query builder instance with the relationship match
|
|
4525
|
+
|
|
4526
|
+
*/
|
|
4437
4527
|
match(relationName, predicate) {
|
|
4438
4528
|
const nextContext = this.relationManager.match(this.context, relationName, predicate);
|
|
4439
4529
|
return this.clone(nextContext);
|
|
4440
4530
|
}
|
|
4441
4531
|
/**
|
|
4442
|
-
|
|
4443
|
-
|
|
4444
|
-
|
|
4445
|
-
|
|
4446
|
-
|
|
4447
|
-
|
|
4532
|
+
|
|
4533
|
+
* Joins a related table
|
|
4534
|
+
|
|
4535
|
+
* @param relationName - Name of the relationship to join
|
|
4536
|
+
|
|
4537
|
+
* @param joinKind - Type of join (defaults to INNER)
|
|
4538
|
+
|
|
4539
|
+
* @param extraCondition - Optional additional join condition
|
|
4540
|
+
|
|
4541
|
+
* @returns New query builder instance with the relationship join
|
|
4542
|
+
|
|
4543
|
+
*/
|
|
4448
4544
|
joinRelation(relationName, joinKind = JOIN_KINDS.INNER, extraCondition) {
|
|
4449
4545
|
const nextContext = this.relationManager.joinRelation(this.context, relationName, joinKind, extraCondition);
|
|
4450
4546
|
return this.clone(nextContext);
|
|
4451
4547
|
}
|
|
4452
4548
|
/**
|
|
4453
|
-
|
|
4454
|
-
|
|
4455
|
-
|
|
4456
|
-
|
|
4457
|
-
|
|
4549
|
+
|
|
4550
|
+
* Includes related data in the query results
|
|
4551
|
+
|
|
4552
|
+
* @param relationName - Name of the relationship to include
|
|
4553
|
+
|
|
4554
|
+
* @param options - Optional include options
|
|
4555
|
+
|
|
4556
|
+
* @returns New query builder instance with the relationship inclusion
|
|
4557
|
+
|
|
4558
|
+
*/
|
|
4458
4559
|
include(relationName, options) {
|
|
4459
4560
|
const nextContext = this.relationManager.include(this.context, relationName, options);
|
|
4460
4561
|
return this.clone(nextContext);
|
|
@@ -4473,125 +4574,186 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
4473
4574
|
async execute(ctx) {
|
|
4474
4575
|
return executeHydrated(ctx, this);
|
|
4475
4576
|
}
|
|
4577
|
+
async executeWithContexts(execCtx, hydCtx) {
|
|
4578
|
+
return executeHydratedWithContexts(execCtx, hydCtx, this);
|
|
4579
|
+
}
|
|
4476
4580
|
/**
|
|
4477
|
-
|
|
4478
|
-
|
|
4479
|
-
|
|
4480
|
-
|
|
4581
|
+
|
|
4582
|
+
* Adds a WHERE condition to the query
|
|
4583
|
+
|
|
4584
|
+
* @param expr - Expression for the WHERE clause
|
|
4585
|
+
|
|
4586
|
+
* @returns New query builder instance with the WHERE condition
|
|
4587
|
+
|
|
4588
|
+
*/
|
|
4481
4589
|
where(expr) {
|
|
4482
4590
|
const nextContext = this.applyAst(this.context, (service) => service.withWhere(expr));
|
|
4483
4591
|
return this.clone(nextContext);
|
|
4484
4592
|
}
|
|
4485
4593
|
/**
|
|
4486
|
-
|
|
4487
|
-
|
|
4488
|
-
|
|
4489
|
-
|
|
4594
|
+
|
|
4595
|
+
* Adds a GROUP BY clause to the query
|
|
4596
|
+
|
|
4597
|
+
* @param col - Column definition or column node to group by
|
|
4598
|
+
|
|
4599
|
+
* @returns New query builder instance with the GROUP BY clause
|
|
4600
|
+
|
|
4601
|
+
*/
|
|
4490
4602
|
groupBy(col2) {
|
|
4491
4603
|
const nextContext = this.applyAst(this.context, (service) => service.withGroupBy(col2));
|
|
4492
4604
|
return this.clone(nextContext);
|
|
4493
4605
|
}
|
|
4494
4606
|
/**
|
|
4495
|
-
|
|
4496
|
-
|
|
4497
|
-
|
|
4498
|
-
|
|
4607
|
+
|
|
4608
|
+
* Adds a HAVING condition to the query
|
|
4609
|
+
|
|
4610
|
+
* @param expr - Expression for the HAVING clause
|
|
4611
|
+
|
|
4612
|
+
* @returns New query builder instance with the HAVING condition
|
|
4613
|
+
|
|
4614
|
+
*/
|
|
4499
4615
|
having(expr) {
|
|
4500
4616
|
const nextContext = this.applyAst(this.context, (service) => service.withHaving(expr));
|
|
4501
4617
|
return this.clone(nextContext);
|
|
4502
4618
|
}
|
|
4503
4619
|
/**
|
|
4504
|
-
|
|
4505
|
-
|
|
4506
|
-
|
|
4507
|
-
|
|
4508
|
-
|
|
4620
|
+
|
|
4621
|
+
* Adds an ORDER BY clause to the query
|
|
4622
|
+
|
|
4623
|
+
* @param col - Column definition or column node to order by
|
|
4624
|
+
|
|
4625
|
+
* @param direction - Order direction (defaults to ASC)
|
|
4626
|
+
|
|
4627
|
+
* @returns New query builder instance with the ORDER BY clause
|
|
4628
|
+
|
|
4629
|
+
*/
|
|
4509
4630
|
orderBy(col2, direction = ORDER_DIRECTIONS.ASC) {
|
|
4510
4631
|
const nextContext = this.applyAst(this.context, (service) => service.withOrderBy(col2, direction));
|
|
4511
4632
|
return this.clone(nextContext);
|
|
4512
4633
|
}
|
|
4513
4634
|
/**
|
|
4514
|
-
|
|
4515
|
-
|
|
4516
|
-
|
|
4517
|
-
|
|
4635
|
+
|
|
4636
|
+
* Adds a DISTINCT clause to the query
|
|
4637
|
+
|
|
4638
|
+
* @param cols - Columns to make distinct
|
|
4639
|
+
|
|
4640
|
+
* @returns New query builder instance with the DISTINCT clause
|
|
4641
|
+
|
|
4642
|
+
*/
|
|
4518
4643
|
distinct(...cols) {
|
|
4519
4644
|
return this.clone(this.columnSelector.distinct(this.context, cols));
|
|
4520
4645
|
}
|
|
4521
4646
|
/**
|
|
4522
|
-
|
|
4523
|
-
|
|
4524
|
-
|
|
4525
|
-
|
|
4647
|
+
|
|
4648
|
+
* Adds a LIMIT clause to the query
|
|
4649
|
+
|
|
4650
|
+
* @param n - Maximum number of rows to return
|
|
4651
|
+
|
|
4652
|
+
* @returns New query builder instance with the LIMIT clause
|
|
4653
|
+
|
|
4654
|
+
*/
|
|
4526
4655
|
limit(n) {
|
|
4527
4656
|
const nextContext = this.applyAst(this.context, (service) => service.withLimit(n));
|
|
4528
4657
|
return this.clone(nextContext);
|
|
4529
4658
|
}
|
|
4530
4659
|
/**
|
|
4531
|
-
|
|
4532
|
-
|
|
4533
|
-
|
|
4534
|
-
|
|
4660
|
+
|
|
4661
|
+
* Adds an OFFSET clause to the query
|
|
4662
|
+
|
|
4663
|
+
* @param n - Number of rows to skip
|
|
4664
|
+
|
|
4665
|
+
* @returns New query builder instance with the OFFSET clause
|
|
4666
|
+
|
|
4667
|
+
*/
|
|
4535
4668
|
offset(n) {
|
|
4536
4669
|
const nextContext = this.applyAst(this.context, (service) => service.withOffset(n));
|
|
4537
4670
|
return this.clone(nextContext);
|
|
4538
4671
|
}
|
|
4539
4672
|
/**
|
|
4540
|
-
|
|
4541
|
-
|
|
4542
|
-
|
|
4543
|
-
|
|
4673
|
+
|
|
4674
|
+
* Combines this query with another using UNION
|
|
4675
|
+
|
|
4676
|
+
* @param query - Query to union with
|
|
4677
|
+
|
|
4678
|
+
* @returns New query builder instance with the set operation
|
|
4679
|
+
|
|
4680
|
+
*/
|
|
4544
4681
|
union(query) {
|
|
4545
4682
|
return this.clone(this.applySetOperation("UNION", query));
|
|
4546
4683
|
}
|
|
4547
4684
|
/**
|
|
4548
|
-
|
|
4549
|
-
|
|
4550
|
-
|
|
4551
|
-
|
|
4685
|
+
|
|
4686
|
+
* Combines this query with another using UNION ALL
|
|
4687
|
+
|
|
4688
|
+
* @param query - Query to union with
|
|
4689
|
+
|
|
4690
|
+
* @returns New query builder instance with the set operation
|
|
4691
|
+
|
|
4692
|
+
*/
|
|
4552
4693
|
unionAll(query) {
|
|
4553
4694
|
return this.clone(this.applySetOperation("UNION ALL", query));
|
|
4554
4695
|
}
|
|
4555
4696
|
/**
|
|
4556
|
-
|
|
4557
|
-
|
|
4558
|
-
|
|
4559
|
-
|
|
4697
|
+
|
|
4698
|
+
* Combines this query with another using INTERSECT
|
|
4699
|
+
|
|
4700
|
+
* @param query - Query to intersect with
|
|
4701
|
+
|
|
4702
|
+
* @returns New query builder instance with the set operation
|
|
4703
|
+
|
|
4704
|
+
*/
|
|
4560
4705
|
intersect(query) {
|
|
4561
4706
|
return this.clone(this.applySetOperation("INTERSECT", query));
|
|
4562
4707
|
}
|
|
4563
4708
|
/**
|
|
4564
|
-
|
|
4565
|
-
|
|
4566
|
-
|
|
4567
|
-
|
|
4709
|
+
|
|
4710
|
+
* Combines this query with another using EXCEPT
|
|
4711
|
+
|
|
4712
|
+
* @param query - Query to subtract
|
|
4713
|
+
|
|
4714
|
+
* @returns New query builder instance with the set operation
|
|
4715
|
+
|
|
4716
|
+
*/
|
|
4568
4717
|
except(query) {
|
|
4569
4718
|
return this.clone(this.applySetOperation("EXCEPT", query));
|
|
4570
4719
|
}
|
|
4571
4720
|
/**
|
|
4572
|
-
|
|
4573
|
-
|
|
4574
|
-
|
|
4575
|
-
|
|
4721
|
+
|
|
4722
|
+
* Adds a WHERE EXISTS condition to the query
|
|
4723
|
+
|
|
4724
|
+
* @param subquery - Subquery to check for existence
|
|
4725
|
+
|
|
4726
|
+
* @returns New query builder instance with the WHERE EXISTS condition
|
|
4727
|
+
|
|
4728
|
+
*/
|
|
4576
4729
|
whereExists(subquery) {
|
|
4577
4730
|
const subAst = this.resolveQueryNode(subquery);
|
|
4578
4731
|
return this.where(exists(subAst));
|
|
4579
4732
|
}
|
|
4580
4733
|
/**
|
|
4581
|
-
|
|
4582
|
-
|
|
4583
|
-
|
|
4584
|
-
|
|
4734
|
+
|
|
4735
|
+
* Adds a WHERE NOT EXISTS condition to the query
|
|
4736
|
+
|
|
4737
|
+
* @param subquery - Subquery to check for non-existence
|
|
4738
|
+
|
|
4739
|
+
* @returns New query builder instance with the WHERE NOT EXISTS condition
|
|
4740
|
+
|
|
4741
|
+
*/
|
|
4585
4742
|
whereNotExists(subquery) {
|
|
4586
4743
|
const subAst = this.resolveQueryNode(subquery);
|
|
4587
4744
|
return this.where(notExists(subAst));
|
|
4588
4745
|
}
|
|
4589
4746
|
/**
|
|
4590
|
-
|
|
4591
|
-
|
|
4592
|
-
|
|
4593
|
-
|
|
4594
|
-
|
|
4747
|
+
|
|
4748
|
+
* Adds a WHERE EXISTS condition based on a relationship
|
|
4749
|
+
|
|
4750
|
+
* @param relationName - Name of the relationship to check
|
|
4751
|
+
|
|
4752
|
+
* @param callback - Optional callback to modify the relationship query
|
|
4753
|
+
|
|
4754
|
+
* @returns New query builder instance with the relationship existence check
|
|
4755
|
+
|
|
4756
|
+
*/
|
|
4595
4757
|
whereHas(relationName, callback) {
|
|
4596
4758
|
const relation = this.env.table.relations[relationName];
|
|
4597
4759
|
if (!relation) {
|
|
@@ -4606,11 +4768,16 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
4606
4768
|
return this.where(exists(finalSubAst));
|
|
4607
4769
|
}
|
|
4608
4770
|
/**
|
|
4609
|
-
|
|
4610
|
-
|
|
4611
|
-
|
|
4612
|
-
|
|
4613
|
-
|
|
4771
|
+
|
|
4772
|
+
* Adds a WHERE NOT EXISTS condition based on a relationship
|
|
4773
|
+
|
|
4774
|
+
* @param relationName - Name of the relationship to check
|
|
4775
|
+
|
|
4776
|
+
* @param callback - Optional callback to modify the relationship query
|
|
4777
|
+
|
|
4778
|
+
* @returns New query builder instance with the relationship non-existence check
|
|
4779
|
+
|
|
4780
|
+
*/
|
|
4614
4781
|
whereHasNot(relationName, callback) {
|
|
4615
4782
|
const relation = this.env.table.relations[relationName];
|
|
4616
4783
|
if (!relation) {
|
|
@@ -4625,33 +4792,47 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
4625
4792
|
return this.where(notExists(finalSubAst));
|
|
4626
4793
|
}
|
|
4627
4794
|
/**
|
|
4628
|
-
|
|
4629
|
-
|
|
4630
|
-
|
|
4631
|
-
|
|
4795
|
+
|
|
4796
|
+
* Compiles the query to SQL for a specific dialect
|
|
4797
|
+
|
|
4798
|
+
* @param dialect - Database dialect to compile for
|
|
4799
|
+
|
|
4800
|
+
* @returns Compiled query with SQL and parameters
|
|
4801
|
+
|
|
4802
|
+
*/
|
|
4632
4803
|
compile(dialect) {
|
|
4633
4804
|
const resolved = resolveDialectInput(dialect);
|
|
4634
4805
|
return resolved.compileSelect(this.context.state.ast);
|
|
4635
4806
|
}
|
|
4636
4807
|
/**
|
|
4637
|
-
|
|
4638
|
-
|
|
4639
|
-
|
|
4640
|
-
|
|
4808
|
+
|
|
4809
|
+
* Converts the query to SQL string for a specific dialect
|
|
4810
|
+
|
|
4811
|
+
* @param dialect - Database dialect to generate SQL for
|
|
4812
|
+
|
|
4813
|
+
* @returns SQL string representation of the query
|
|
4814
|
+
|
|
4815
|
+
*/
|
|
4641
4816
|
toSql(dialect) {
|
|
4642
4817
|
return this.compile(dialect).sql;
|
|
4643
4818
|
}
|
|
4644
4819
|
/**
|
|
4645
|
-
|
|
4646
|
-
|
|
4647
|
-
|
|
4820
|
+
|
|
4821
|
+
* Gets the hydration plan for the query
|
|
4822
|
+
|
|
4823
|
+
* @returns Hydration plan or undefined if none exists
|
|
4824
|
+
|
|
4825
|
+
*/
|
|
4648
4826
|
getHydrationPlan() {
|
|
4649
4827
|
return this.context.hydration.getPlan();
|
|
4650
4828
|
}
|
|
4651
4829
|
/**
|
|
4652
|
-
|
|
4653
|
-
|
|
4654
|
-
|
|
4830
|
+
|
|
4831
|
+
* Gets the Abstract Syntax Tree (AST) representation of the query
|
|
4832
|
+
|
|
4833
|
+
* @returns Query AST with hydration applied
|
|
4834
|
+
|
|
4835
|
+
*/
|
|
4655
4836
|
getAST() {
|
|
4656
4837
|
return this.context.hydration.applyToAst(this.context.state.ast);
|
|
4657
4838
|
}
|
|
@@ -5949,12 +6130,47 @@ var SQL_OPERATOR_REGISTRY = {
|
|
|
5949
6130
|
[SQL_OPERATORS.NOT_EXISTS]: { sql: SQL_OPERATORS.NOT_EXISTS, tsName: "notExists" }
|
|
5950
6131
|
};
|
|
5951
6132
|
|
|
6133
|
+
// src/codegen/naming-strategy.ts
|
|
6134
|
+
var DefaultNamingStrategy = class {
|
|
6135
|
+
/**
|
|
6136
|
+
* Converts table names to TypeScript symbols
|
|
6137
|
+
* @param table - Table node, function table node, or string name
|
|
6138
|
+
* @returns Capitalized table name (handles schema-qualified names)
|
|
6139
|
+
*/
|
|
6140
|
+
tableToSymbol(table) {
|
|
6141
|
+
const tableName = typeof table === "string" ? table : table.name;
|
|
6142
|
+
if (tableName.includes(".")) {
|
|
6143
|
+
return tableName.split(".").map((part) => this.capitalize(part)).join("");
|
|
6144
|
+
}
|
|
6145
|
+
return this.capitalize(tableName);
|
|
6146
|
+
}
|
|
6147
|
+
/**
|
|
6148
|
+
* Converts column references to property names
|
|
6149
|
+
* @param column - Column node
|
|
6150
|
+
* @returns Column name as-is (for backward compatibility)
|
|
6151
|
+
*/
|
|
6152
|
+
columnToProperty(column) {
|
|
6153
|
+
return column.name;
|
|
6154
|
+
}
|
|
6155
|
+
/**
|
|
6156
|
+
* Capitalizes the first letter of a string
|
|
6157
|
+
* @param s - String to capitalize
|
|
6158
|
+
* @returns Capitalized string
|
|
6159
|
+
*/
|
|
6160
|
+
capitalize(s) {
|
|
6161
|
+
if (!s) return s;
|
|
6162
|
+
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
6163
|
+
}
|
|
6164
|
+
};
|
|
6165
|
+
|
|
5952
6166
|
// src/codegen/typescript.ts
|
|
5953
|
-
var capitalize = (s) => s.charAt(0).toUpperCase() + s.slice(1);
|
|
5954
6167
|
var assertNever2 = (value) => {
|
|
5955
6168
|
throw new Error(`Unhandled SQL operator: ${value}`);
|
|
5956
6169
|
};
|
|
5957
6170
|
var TypeScriptGenerator = class {
|
|
6171
|
+
constructor(namingStrategy = new DefaultNamingStrategy()) {
|
|
6172
|
+
this.namingStrategy = namingStrategy;
|
|
6173
|
+
}
|
|
5958
6174
|
/**
|
|
5959
6175
|
* Generates TypeScript code from a query AST
|
|
5960
6176
|
* @param ast - Query AST to generate code from
|
|
@@ -5985,9 +6201,9 @@ var TypeScriptGenerator = class {
|
|
|
5985
6201
|
lines.push(` ${sel}${index < selections.length - 1 ? "," : ""}`);
|
|
5986
6202
|
});
|
|
5987
6203
|
lines.push(`})`);
|
|
5988
|
-
lines.push(`.from(${
|
|
6204
|
+
lines.push(`.from(${this.namingStrategy.tableToSymbol(ast.from)})`);
|
|
5989
6205
|
if (ast.distinct && ast.distinct.length) {
|
|
5990
|
-
const cols = ast.distinct.map((c) => `${
|
|
6206
|
+
const cols = ast.distinct.map((c) => `${this.namingStrategy.tableToSymbol(c.table)}.${c.name}`).join(", ");
|
|
5991
6207
|
lines.push(`.distinct(${cols})`);
|
|
5992
6208
|
}
|
|
5993
6209
|
ast.joins.forEach((join) => {
|
|
@@ -6002,7 +6218,7 @@ var TypeScriptGenerator = class {
|
|
|
6002
6218
|
lines.push(`.joinRelation('${relationName}', '${join.kind}')`);
|
|
6003
6219
|
}
|
|
6004
6220
|
} else {
|
|
6005
|
-
const table =
|
|
6221
|
+
const table = this.namingStrategy.tableToSymbol(join.table);
|
|
6006
6222
|
const cond = this.printExpression(join.condition);
|
|
6007
6223
|
let method = "innerJoin";
|
|
6008
6224
|
if (join.kind === "LEFT") method = "leftJoin";
|
|
@@ -6023,7 +6239,7 @@ var TypeScriptGenerator = class {
|
|
|
6023
6239
|
lines.push(`.where(${this.printExpression(ast.where)})`);
|
|
6024
6240
|
}
|
|
6025
6241
|
if (ast.groupBy && ast.groupBy.length) {
|
|
6026
|
-
const cols = ast.groupBy.map((c) => `${
|
|
6242
|
+
const cols = ast.groupBy.map((c) => `${this.namingStrategy.tableToSymbol(c.table)}.${c.name}`).join(", ");
|
|
6027
6243
|
lines.push(`.groupBy(${cols})`);
|
|
6028
6244
|
}
|
|
6029
6245
|
if (ast.having) {
|
|
@@ -6031,7 +6247,7 @@ var TypeScriptGenerator = class {
|
|
|
6031
6247
|
}
|
|
6032
6248
|
if (ast.orderBy && ast.orderBy.length) {
|
|
6033
6249
|
ast.orderBy.forEach((o) => {
|
|
6034
|
-
lines.push(`.orderBy(${
|
|
6250
|
+
lines.push(`.orderBy(${this.namingStrategy.tableToSymbol(o.column.table)}.${o.column.name}, '${o.direction}')`);
|
|
6035
6251
|
});
|
|
6036
6252
|
}
|
|
6037
6253
|
if (ast.limit) lines.push(`.limit(${ast.limit})`);
|
|
@@ -6170,7 +6386,7 @@ var TypeScriptGenerator = class {
|
|
|
6170
6386
|
* @returns TypeScript code representation
|
|
6171
6387
|
*/
|
|
6172
6388
|
printColumnOperand(column) {
|
|
6173
|
-
return `${
|
|
6389
|
+
return `${this.namingStrategy.tableToSymbol(column.table)}.${column.name}`;
|
|
6174
6390
|
}
|
|
6175
6391
|
/**
|
|
6176
6392
|
* Prints a literal operand to TypeScript code
|
|
@@ -6196,7 +6412,7 @@ var TypeScriptGenerator = class {
|
|
|
6196
6412
|
* @returns TypeScript code representation
|
|
6197
6413
|
*/
|
|
6198
6414
|
printJsonPathOperand(json) {
|
|
6199
|
-
return `jsonPath(${
|
|
6415
|
+
return `jsonPath(${this.namingStrategy.tableToSymbol(json.column.table)}.${json.column.name}, '${json.path}')`;
|
|
6200
6416
|
}
|
|
6201
6417
|
/**
|
|
6202
6418
|
* Prints a scalar subquery operand to TypeScript code
|
|
@@ -6232,11 +6448,11 @@ var TypeScriptGenerator = class {
|
|
|
6232
6448
|
result += ") OVER (";
|
|
6233
6449
|
const parts = [];
|
|
6234
6450
|
if (node.partitionBy && node.partitionBy.length > 0) {
|
|
6235
|
-
const partitionClause = "PARTITION BY " + node.partitionBy.map((col2) => `${
|
|
6451
|
+
const partitionClause = "PARTITION BY " + node.partitionBy.map((col2) => `${this.namingStrategy.tableToSymbol(col2.table)}.${col2.name}`).join(", ");
|
|
6236
6452
|
parts.push(partitionClause);
|
|
6237
6453
|
}
|
|
6238
6454
|
if (node.orderBy && node.orderBy.length > 0) {
|
|
6239
|
-
const orderClause = "ORDER BY " + node.orderBy.map((o) => `${
|
|
6455
|
+
const orderClause = "ORDER BY " + node.orderBy.map((o) => `${this.namingStrategy.tableToSymbol(o.column.table)}.${o.column.name} ${o.direction}`).join(", ");
|
|
6240
6456
|
parts.push(orderClause);
|
|
6241
6457
|
}
|
|
6242
6458
|
result += parts.join(" ");
|
|
@@ -6265,46 +6481,24 @@ var TypeScriptGenerator = class {
|
|
|
6265
6481
|
}
|
|
6266
6482
|
};
|
|
6267
6483
|
|
|
6268
|
-
// src/orm/
|
|
6269
|
-
var
|
|
6270
|
-
|
|
6271
|
-
|
|
6272
|
-
const handlers = initialHandlers ?? {};
|
|
6273
|
-
Object.entries(handlers).forEach(([name, list]) => {
|
|
6274
|
-
this.handlers.set(name, [...list]);
|
|
6275
|
-
});
|
|
6276
|
-
}
|
|
6277
|
-
register(name, handler) {
|
|
6278
|
-
const existing = this.handlers.get(name) ?? [];
|
|
6279
|
-
existing.push(handler);
|
|
6280
|
-
this.handlers.set(name, existing);
|
|
6281
|
-
}
|
|
6282
|
-
async dispatch(trackedEntities, ctx) {
|
|
6283
|
-
for (const tracked of trackedEntities) {
|
|
6284
|
-
const entity = tracked.entity;
|
|
6285
|
-
if (!entity.domainEvents || !entity.domainEvents.length) continue;
|
|
6286
|
-
for (const event of entity.domainEvents) {
|
|
6287
|
-
const eventName = this.getEventName(event);
|
|
6288
|
-
const handlers = this.handlers.get(eventName);
|
|
6289
|
-
if (!handlers) continue;
|
|
6290
|
-
for (const handler of handlers) {
|
|
6291
|
-
await handler(event, ctx);
|
|
6292
|
-
}
|
|
6293
|
-
}
|
|
6294
|
-
entity.domainEvents = [];
|
|
6295
|
-
}
|
|
6296
|
-
}
|
|
6297
|
-
getEventName(event) {
|
|
6298
|
-
if (!event) return "Unknown";
|
|
6299
|
-
if (typeof event === "string") return event;
|
|
6300
|
-
return event.constructor?.name ?? "Unknown";
|
|
6301
|
-
}
|
|
6484
|
+
// src/orm/entity-metadata.ts
|
|
6485
|
+
var metadataMap = /* @__PURE__ */ new Map();
|
|
6486
|
+
var getEntityMetadata = (target) => {
|
|
6487
|
+
return metadataMap.get(target);
|
|
6302
6488
|
};
|
|
6303
|
-
|
|
6304
|
-
|
|
6305
|
-
|
|
6489
|
+
|
|
6490
|
+
// src/decorators/bootstrap.ts
|
|
6491
|
+
var getTableDefFromEntity = (ctor) => {
|
|
6492
|
+
const meta = getEntityMetadata(ctor);
|
|
6493
|
+
if (!meta) return void 0;
|
|
6494
|
+
return meta.table;
|
|
6495
|
+
};
|
|
6496
|
+
var selectFromEntity = (ctor) => {
|
|
6497
|
+
const table = getTableDefFromEntity(ctor);
|
|
6498
|
+
if (!table) {
|
|
6499
|
+
throw new Error("Entity metadata has not been bootstrapped");
|
|
6306
6500
|
}
|
|
6307
|
-
|
|
6501
|
+
return new SelectQueryBuilder(table);
|
|
6308
6502
|
};
|
|
6309
6503
|
|
|
6310
6504
|
// src/orm/identity-map.ts
|
|
@@ -6334,272 +6528,121 @@ var IdentityMap = class {
|
|
|
6334
6528
|
const bucket = this.buckets.get(table.name);
|
|
6335
6529
|
return bucket ? Array.from(bucket.values()) : [];
|
|
6336
6530
|
}
|
|
6531
|
+
clear() {
|
|
6532
|
+
this.buckets.clear();
|
|
6533
|
+
}
|
|
6337
6534
|
toIdentityKey(pk) {
|
|
6338
6535
|
return String(pk);
|
|
6339
6536
|
}
|
|
6340
6537
|
};
|
|
6341
6538
|
|
|
6342
|
-
// src/orm/
|
|
6343
|
-
var
|
|
6344
|
-
|
|
6345
|
-
|
|
6539
|
+
// src/orm/runtime-types.ts
|
|
6540
|
+
var EntityStatus = /* @__PURE__ */ ((EntityStatus2) => {
|
|
6541
|
+
EntityStatus2["New"] = "new";
|
|
6542
|
+
EntityStatus2["Managed"] = "managed";
|
|
6543
|
+
EntityStatus2["Dirty"] = "dirty";
|
|
6544
|
+
EntityStatus2["Removed"] = "removed";
|
|
6545
|
+
EntityStatus2["Detached"] = "detached";
|
|
6546
|
+
return EntityStatus2;
|
|
6547
|
+
})(EntityStatus || {});
|
|
6548
|
+
|
|
6549
|
+
// src/orm/unit-of-work.ts
|
|
6550
|
+
var UnitOfWork = class {
|
|
6551
|
+
constructor(dialect, executor, identityMap, hookContext) {
|
|
6346
6552
|
this.dialect = dialect;
|
|
6347
6553
|
this.executor = executor;
|
|
6348
|
-
this.
|
|
6554
|
+
this.identityMap = identityMap;
|
|
6555
|
+
this.hookContext = hookContext;
|
|
6556
|
+
this.trackedEntities = /* @__PURE__ */ new Map();
|
|
6349
6557
|
}
|
|
6350
|
-
|
|
6351
|
-
this.
|
|
6558
|
+
get identityBuckets() {
|
|
6559
|
+
return this.identityMap.bucketsMap;
|
|
6352
6560
|
}
|
|
6353
|
-
|
|
6354
|
-
|
|
6355
|
-
|
|
6356
|
-
|
|
6357
|
-
|
|
6358
|
-
|
|
6359
|
-
|
|
6360
|
-
|
|
6561
|
+
getTracked() {
|
|
6562
|
+
return Array.from(this.trackedEntities.values());
|
|
6563
|
+
}
|
|
6564
|
+
getEntity(table, pk) {
|
|
6565
|
+
return this.identityMap.getEntity(table, pk);
|
|
6566
|
+
}
|
|
6567
|
+
getEntitiesForTable(table) {
|
|
6568
|
+
return this.identityMap.getEntitiesForTable(table);
|
|
6569
|
+
}
|
|
6570
|
+
findTracked(entity) {
|
|
6571
|
+
return this.trackedEntities.get(entity);
|
|
6572
|
+
}
|
|
6573
|
+
setEntity(table, pk, entity) {
|
|
6574
|
+
if (pk === null || pk === void 0) return;
|
|
6575
|
+
let tracked = this.trackedEntities.get(entity);
|
|
6576
|
+
if (!tracked) {
|
|
6577
|
+
tracked = {
|
|
6578
|
+
table,
|
|
6579
|
+
entity,
|
|
6580
|
+
pk,
|
|
6581
|
+
status: "managed" /* Managed */,
|
|
6582
|
+
original: this.createSnapshot(table, entity)
|
|
6583
|
+
};
|
|
6584
|
+
this.trackedEntities.set(entity, tracked);
|
|
6585
|
+
} else {
|
|
6586
|
+
tracked.pk = pk;
|
|
6587
|
+
}
|
|
6588
|
+
this.registerIdentity(tracked);
|
|
6589
|
+
}
|
|
6590
|
+
trackNew(table, entity, pk) {
|
|
6591
|
+
const tracked = {
|
|
6592
|
+
table,
|
|
6593
|
+
entity,
|
|
6594
|
+
pk: pk ?? null,
|
|
6595
|
+
status: "new" /* New */,
|
|
6596
|
+
original: null
|
|
6597
|
+
};
|
|
6598
|
+
this.trackedEntities.set(entity, tracked);
|
|
6599
|
+
if (pk != null) {
|
|
6600
|
+
this.registerIdentity(tracked);
|
|
6601
|
+
}
|
|
6602
|
+
}
|
|
6603
|
+
trackManaged(table, pk, entity) {
|
|
6604
|
+
const tracked = {
|
|
6605
|
+
table,
|
|
6606
|
+
entity,
|
|
6607
|
+
pk,
|
|
6608
|
+
status: "managed" /* Managed */,
|
|
6609
|
+
original: this.createSnapshot(table, entity)
|
|
6610
|
+
};
|
|
6611
|
+
this.trackedEntities.set(entity, tracked);
|
|
6612
|
+
this.registerIdentity(tracked);
|
|
6613
|
+
}
|
|
6614
|
+
markDirty(entity) {
|
|
6615
|
+
const tracked = this.trackedEntities.get(entity);
|
|
6616
|
+
if (!tracked) return;
|
|
6617
|
+
if (tracked.status === "new" /* New */ || tracked.status === "removed" /* Removed */) return;
|
|
6618
|
+
tracked.status = "dirty" /* Dirty */;
|
|
6619
|
+
}
|
|
6620
|
+
markRemoved(entity) {
|
|
6621
|
+
const tracked = this.trackedEntities.get(entity);
|
|
6622
|
+
if (!tracked) return;
|
|
6623
|
+
tracked.status = "removed" /* Removed */;
|
|
6624
|
+
}
|
|
6625
|
+
async flush() {
|
|
6626
|
+
const toFlush = Array.from(this.trackedEntities.values());
|
|
6627
|
+
for (const tracked of toFlush) {
|
|
6628
|
+
switch (tracked.status) {
|
|
6629
|
+
case "new" /* New */:
|
|
6630
|
+
await this.flushInsert(tracked);
|
|
6361
6631
|
break;
|
|
6362
|
-
case
|
|
6363
|
-
await this.
|
|
6632
|
+
case "dirty" /* Dirty */:
|
|
6633
|
+
await this.flushUpdate(tracked);
|
|
6364
6634
|
break;
|
|
6365
|
-
case
|
|
6366
|
-
await this.
|
|
6635
|
+
case "removed" /* Removed */:
|
|
6636
|
+
await this.flushDelete(tracked);
|
|
6367
6637
|
break;
|
|
6368
|
-
|
|
6369
|
-
await this.handleBelongsToChange(entry);
|
|
6638
|
+
default:
|
|
6370
6639
|
break;
|
|
6371
6640
|
}
|
|
6372
6641
|
}
|
|
6373
6642
|
}
|
|
6374
|
-
|
|
6375
|
-
|
|
6376
|
-
|
|
6377
|
-
if (!target) return;
|
|
6378
|
-
const tracked = this.unitOfWork.findTracked(target);
|
|
6379
|
-
if (!tracked) return;
|
|
6380
|
-
const localKey = relation.localKey || findPrimaryKey(entry.rootTable);
|
|
6381
|
-
const rootValue = entry.root[localKey];
|
|
6382
|
-
if (rootValue === void 0 || rootValue === null) return;
|
|
6383
|
-
if (entry.change.kind === "add" || entry.change.kind === "attach") {
|
|
6384
|
-
this.assignHasManyForeignKey(tracked.entity, relation, rootValue);
|
|
6385
|
-
this.unitOfWork.markDirty(tracked.entity);
|
|
6386
|
-
return;
|
|
6387
|
-
}
|
|
6388
|
-
if (entry.change.kind === "remove") {
|
|
6389
|
-
this.detachHasManyChild(tracked.entity, relation);
|
|
6390
|
-
}
|
|
6391
|
-
}
|
|
6392
|
-
async handleHasOneChange(entry) {
|
|
6393
|
-
const relation = entry.relation;
|
|
6394
|
-
const target = entry.change.entity;
|
|
6395
|
-
if (!target) return;
|
|
6396
|
-
const tracked = this.unitOfWork.findTracked(target);
|
|
6397
|
-
if (!tracked) return;
|
|
6398
|
-
const localKey = relation.localKey || findPrimaryKey(entry.rootTable);
|
|
6399
|
-
const rootValue = entry.root[localKey];
|
|
6400
|
-
if (rootValue === void 0 || rootValue === null) return;
|
|
6401
|
-
if (entry.change.kind === "attach" || entry.change.kind === "add") {
|
|
6402
|
-
this.assignHasOneForeignKey(tracked.entity, relation, rootValue);
|
|
6403
|
-
this.unitOfWork.markDirty(tracked.entity);
|
|
6404
|
-
return;
|
|
6405
|
-
}
|
|
6406
|
-
if (entry.change.kind === "remove") {
|
|
6407
|
-
this.detachHasOneChild(tracked.entity, relation);
|
|
6408
|
-
}
|
|
6409
|
-
}
|
|
6410
|
-
async handleBelongsToChange(_entry) {
|
|
6411
|
-
}
|
|
6412
|
-
async handleBelongsToManyChange(entry) {
|
|
6413
|
-
const relation = entry.relation;
|
|
6414
|
-
const rootKey = relation.localKey || findPrimaryKey(entry.rootTable);
|
|
6415
|
-
const rootId = entry.root[rootKey];
|
|
6416
|
-
if (rootId === void 0 || rootId === null) return;
|
|
6417
|
-
const targetId = this.resolvePrimaryKeyValue(entry.change.entity, relation.target);
|
|
6418
|
-
if (targetId === null) return;
|
|
6419
|
-
if (entry.change.kind === "attach" || entry.change.kind === "add") {
|
|
6420
|
-
await this.insertPivotRow(relation, rootId, targetId);
|
|
6421
|
-
return;
|
|
6422
|
-
}
|
|
6423
|
-
if (entry.change.kind === "detach" || entry.change.kind === "remove") {
|
|
6424
|
-
await this.deletePivotRow(relation, rootId, targetId);
|
|
6425
|
-
if (relation.cascade === "all" || relation.cascade === "remove") {
|
|
6426
|
-
this.unitOfWork.markRemoved(entry.change.entity);
|
|
6427
|
-
}
|
|
6428
|
-
}
|
|
6429
|
-
}
|
|
6430
|
-
assignHasManyForeignKey(child, relation, rootValue) {
|
|
6431
|
-
const current = child[relation.foreignKey];
|
|
6432
|
-
if (current === rootValue) return;
|
|
6433
|
-
child[relation.foreignKey] = rootValue;
|
|
6434
|
-
}
|
|
6435
|
-
detachHasManyChild(child, relation) {
|
|
6436
|
-
if (relation.cascade === "all" || relation.cascade === "remove") {
|
|
6437
|
-
this.unitOfWork.markRemoved(child);
|
|
6438
|
-
return;
|
|
6439
|
-
}
|
|
6440
|
-
child[relation.foreignKey] = null;
|
|
6441
|
-
this.unitOfWork.markDirty(child);
|
|
6442
|
-
}
|
|
6443
|
-
assignHasOneForeignKey(child, relation, rootValue) {
|
|
6444
|
-
const current = child[relation.foreignKey];
|
|
6445
|
-
if (current === rootValue) return;
|
|
6446
|
-
child[relation.foreignKey] = rootValue;
|
|
6447
|
-
}
|
|
6448
|
-
detachHasOneChild(child, relation) {
|
|
6449
|
-
if (relation.cascade === "all" || relation.cascade === "remove") {
|
|
6450
|
-
this.unitOfWork.markRemoved(child);
|
|
6451
|
-
return;
|
|
6452
|
-
}
|
|
6453
|
-
child[relation.foreignKey] = null;
|
|
6454
|
-
this.unitOfWork.markDirty(child);
|
|
6455
|
-
}
|
|
6456
|
-
async insertPivotRow(relation, rootId, targetId) {
|
|
6457
|
-
const payload = {
|
|
6458
|
-
[relation.pivotForeignKeyToRoot]: rootId,
|
|
6459
|
-
[relation.pivotForeignKeyToTarget]: targetId
|
|
6460
|
-
};
|
|
6461
|
-
const builder = new InsertQueryBuilder(relation.pivotTable).values(payload);
|
|
6462
|
-
const compiled = builder.compile(this.dialect);
|
|
6463
|
-
await this.executor.executeSql(compiled.sql, compiled.params);
|
|
6464
|
-
}
|
|
6465
|
-
async deletePivotRow(relation, rootId, targetId) {
|
|
6466
|
-
const rootCol = relation.pivotTable.columns[relation.pivotForeignKeyToRoot];
|
|
6467
|
-
const targetCol = relation.pivotTable.columns[relation.pivotForeignKeyToTarget];
|
|
6468
|
-
if (!rootCol || !targetCol) return;
|
|
6469
|
-
const builder = new DeleteQueryBuilder(relation.pivotTable).where(
|
|
6470
|
-
and(eq(rootCol, rootId), eq(targetCol, targetId))
|
|
6471
|
-
);
|
|
6472
|
-
const compiled = builder.compile(this.dialect);
|
|
6473
|
-
await this.executor.executeSql(compiled.sql, compiled.params);
|
|
6474
|
-
}
|
|
6475
|
-
resolvePrimaryKeyValue(entity, table) {
|
|
6476
|
-
if (!entity) return null;
|
|
6477
|
-
const key = findPrimaryKey(table);
|
|
6478
|
-
const value = entity[key];
|
|
6479
|
-
if (value === void 0 || value === null) return null;
|
|
6480
|
-
return value;
|
|
6481
|
-
}
|
|
6482
|
-
};
|
|
6483
|
-
|
|
6484
|
-
// src/orm/transaction-runner.ts
|
|
6485
|
-
var runInTransaction = async (executor, action) => {
|
|
6486
|
-
if (!executor.beginTransaction) {
|
|
6487
|
-
await action();
|
|
6488
|
-
return;
|
|
6489
|
-
}
|
|
6490
|
-
await executor.beginTransaction();
|
|
6491
|
-
try {
|
|
6492
|
-
await action();
|
|
6493
|
-
await executor.commitTransaction?.();
|
|
6494
|
-
} catch (error) {
|
|
6495
|
-
await executor.rollbackTransaction?.();
|
|
6496
|
-
throw error;
|
|
6497
|
-
}
|
|
6498
|
-
};
|
|
6499
|
-
|
|
6500
|
-
// src/orm/runtime-types.ts
|
|
6501
|
-
var EntityStatus = /* @__PURE__ */ ((EntityStatus2) => {
|
|
6502
|
-
EntityStatus2["New"] = "new";
|
|
6503
|
-
EntityStatus2["Managed"] = "managed";
|
|
6504
|
-
EntityStatus2["Dirty"] = "dirty";
|
|
6505
|
-
EntityStatus2["Removed"] = "removed";
|
|
6506
|
-
EntityStatus2["Detached"] = "detached";
|
|
6507
|
-
return EntityStatus2;
|
|
6508
|
-
})(EntityStatus || {});
|
|
6509
|
-
|
|
6510
|
-
// src/orm/unit-of-work.ts
|
|
6511
|
-
var UnitOfWork = class {
|
|
6512
|
-
constructor(dialect, executor, identityMap, hookContext) {
|
|
6513
|
-
this.dialect = dialect;
|
|
6514
|
-
this.executor = executor;
|
|
6515
|
-
this.identityMap = identityMap;
|
|
6516
|
-
this.hookContext = hookContext;
|
|
6517
|
-
this.trackedEntities = /* @__PURE__ */ new Map();
|
|
6518
|
-
}
|
|
6519
|
-
get identityBuckets() {
|
|
6520
|
-
return this.identityMap.bucketsMap;
|
|
6521
|
-
}
|
|
6522
|
-
getTracked() {
|
|
6523
|
-
return Array.from(this.trackedEntities.values());
|
|
6524
|
-
}
|
|
6525
|
-
getEntity(table, pk) {
|
|
6526
|
-
return this.identityMap.getEntity(table, pk);
|
|
6527
|
-
}
|
|
6528
|
-
getEntitiesForTable(table) {
|
|
6529
|
-
return this.identityMap.getEntitiesForTable(table);
|
|
6530
|
-
}
|
|
6531
|
-
findTracked(entity) {
|
|
6532
|
-
return this.trackedEntities.get(entity);
|
|
6533
|
-
}
|
|
6534
|
-
setEntity(table, pk, entity) {
|
|
6535
|
-
if (pk === null || pk === void 0) return;
|
|
6536
|
-
let tracked = this.trackedEntities.get(entity);
|
|
6537
|
-
if (!tracked) {
|
|
6538
|
-
tracked = {
|
|
6539
|
-
table,
|
|
6540
|
-
entity,
|
|
6541
|
-
pk,
|
|
6542
|
-
status: "managed" /* Managed */,
|
|
6543
|
-
original: this.createSnapshot(table, entity)
|
|
6544
|
-
};
|
|
6545
|
-
this.trackedEntities.set(entity, tracked);
|
|
6546
|
-
} else {
|
|
6547
|
-
tracked.pk = pk;
|
|
6548
|
-
}
|
|
6549
|
-
this.registerIdentity(tracked);
|
|
6550
|
-
}
|
|
6551
|
-
trackNew(table, entity, pk) {
|
|
6552
|
-
const tracked = {
|
|
6553
|
-
table,
|
|
6554
|
-
entity,
|
|
6555
|
-
pk: pk ?? null,
|
|
6556
|
-
status: "new" /* New */,
|
|
6557
|
-
original: null
|
|
6558
|
-
};
|
|
6559
|
-
this.trackedEntities.set(entity, tracked);
|
|
6560
|
-
if (pk != null) {
|
|
6561
|
-
this.registerIdentity(tracked);
|
|
6562
|
-
}
|
|
6563
|
-
}
|
|
6564
|
-
trackManaged(table, pk, entity) {
|
|
6565
|
-
const tracked = {
|
|
6566
|
-
table,
|
|
6567
|
-
entity,
|
|
6568
|
-
pk,
|
|
6569
|
-
status: "managed" /* Managed */,
|
|
6570
|
-
original: this.createSnapshot(table, entity)
|
|
6571
|
-
};
|
|
6572
|
-
this.trackedEntities.set(entity, tracked);
|
|
6573
|
-
this.registerIdentity(tracked);
|
|
6574
|
-
}
|
|
6575
|
-
markDirty(entity) {
|
|
6576
|
-
const tracked = this.trackedEntities.get(entity);
|
|
6577
|
-
if (!tracked) return;
|
|
6578
|
-
if (tracked.status === "new" /* New */ || tracked.status === "removed" /* Removed */) return;
|
|
6579
|
-
tracked.status = "dirty" /* Dirty */;
|
|
6580
|
-
}
|
|
6581
|
-
markRemoved(entity) {
|
|
6582
|
-
const tracked = this.trackedEntities.get(entity);
|
|
6583
|
-
if (!tracked) return;
|
|
6584
|
-
tracked.status = "removed" /* Removed */;
|
|
6585
|
-
}
|
|
6586
|
-
async flush() {
|
|
6587
|
-
const toFlush = Array.from(this.trackedEntities.values());
|
|
6588
|
-
for (const tracked of toFlush) {
|
|
6589
|
-
switch (tracked.status) {
|
|
6590
|
-
case "new" /* New */:
|
|
6591
|
-
await this.flushInsert(tracked);
|
|
6592
|
-
break;
|
|
6593
|
-
case "dirty" /* Dirty */:
|
|
6594
|
-
await this.flushUpdate(tracked);
|
|
6595
|
-
break;
|
|
6596
|
-
case "removed" /* Removed */:
|
|
6597
|
-
await this.flushDelete(tracked);
|
|
6598
|
-
break;
|
|
6599
|
-
default:
|
|
6600
|
-
break;
|
|
6601
|
-
}
|
|
6602
|
-
}
|
|
6643
|
+
reset() {
|
|
6644
|
+
this.trackedEntities.clear();
|
|
6645
|
+
this.identityMap.clear();
|
|
6603
6646
|
}
|
|
6604
6647
|
async flushInsert(tracked) {
|
|
6605
6648
|
await this.runHook(tracked.table.hooks?.beforeInsert, tracked);
|
|
@@ -6720,6 +6763,193 @@ var UnitOfWork = class {
|
|
|
6720
6763
|
}
|
|
6721
6764
|
};
|
|
6722
6765
|
|
|
6766
|
+
// src/orm/domain-event-bus.ts
|
|
6767
|
+
var DomainEventBus = class {
|
|
6768
|
+
constructor(initialHandlers) {
|
|
6769
|
+
this.handlers = /* @__PURE__ */ new Map();
|
|
6770
|
+
const handlers = initialHandlers ?? {};
|
|
6771
|
+
Object.entries(handlers).forEach(([name, list]) => {
|
|
6772
|
+
this.handlers.set(name, [...list]);
|
|
6773
|
+
});
|
|
6774
|
+
}
|
|
6775
|
+
register(name, handler) {
|
|
6776
|
+
const existing = this.handlers.get(name) ?? [];
|
|
6777
|
+
existing.push(handler);
|
|
6778
|
+
this.handlers.set(name, existing);
|
|
6779
|
+
}
|
|
6780
|
+
async dispatch(trackedEntities, ctx) {
|
|
6781
|
+
for (const tracked of trackedEntities) {
|
|
6782
|
+
const entity = tracked.entity;
|
|
6783
|
+
if (!entity.domainEvents || !entity.domainEvents.length) continue;
|
|
6784
|
+
for (const event of entity.domainEvents) {
|
|
6785
|
+
const eventName = this.getEventName(event);
|
|
6786
|
+
const handlers = this.handlers.get(eventName);
|
|
6787
|
+
if (!handlers) continue;
|
|
6788
|
+
for (const handler of handlers) {
|
|
6789
|
+
await handler(event, ctx);
|
|
6790
|
+
}
|
|
6791
|
+
}
|
|
6792
|
+
entity.domainEvents = [];
|
|
6793
|
+
}
|
|
6794
|
+
}
|
|
6795
|
+
getEventName(event) {
|
|
6796
|
+
if (!event) return "Unknown";
|
|
6797
|
+
if (typeof event === "string") return event;
|
|
6798
|
+
return event.constructor?.name ?? "Unknown";
|
|
6799
|
+
}
|
|
6800
|
+
};
|
|
6801
|
+
var addDomainEvent = (entity, event) => {
|
|
6802
|
+
if (!entity.domainEvents) {
|
|
6803
|
+
entity.domainEvents = [];
|
|
6804
|
+
}
|
|
6805
|
+
entity.domainEvents.push(event);
|
|
6806
|
+
};
|
|
6807
|
+
|
|
6808
|
+
// src/orm/relation-change-processor.ts
|
|
6809
|
+
var RelationChangeProcessor = class {
|
|
6810
|
+
constructor(unitOfWork, dialect, executor) {
|
|
6811
|
+
this.unitOfWork = unitOfWork;
|
|
6812
|
+
this.dialect = dialect;
|
|
6813
|
+
this.executor = executor;
|
|
6814
|
+
this.relationChanges = [];
|
|
6815
|
+
}
|
|
6816
|
+
registerChange(entry) {
|
|
6817
|
+
this.relationChanges.push(entry);
|
|
6818
|
+
}
|
|
6819
|
+
reset() {
|
|
6820
|
+
this.relationChanges.length = 0;
|
|
6821
|
+
}
|
|
6822
|
+
async process() {
|
|
6823
|
+
if (!this.relationChanges.length) return;
|
|
6824
|
+
const entries = [...this.relationChanges];
|
|
6825
|
+
this.relationChanges.length = 0;
|
|
6826
|
+
for (const entry of entries) {
|
|
6827
|
+
switch (entry.relation.type) {
|
|
6828
|
+
case RelationKinds.HasMany:
|
|
6829
|
+
await this.handleHasManyChange(entry);
|
|
6830
|
+
break;
|
|
6831
|
+
case RelationKinds.HasOne:
|
|
6832
|
+
await this.handleHasOneChange(entry);
|
|
6833
|
+
break;
|
|
6834
|
+
case RelationKinds.BelongsToMany:
|
|
6835
|
+
await this.handleBelongsToManyChange(entry);
|
|
6836
|
+
break;
|
|
6837
|
+
case RelationKinds.BelongsTo:
|
|
6838
|
+
await this.handleBelongsToChange(entry);
|
|
6839
|
+
break;
|
|
6840
|
+
}
|
|
6841
|
+
}
|
|
6842
|
+
}
|
|
6843
|
+
async handleHasManyChange(entry) {
|
|
6844
|
+
const relation = entry.relation;
|
|
6845
|
+
const target = entry.change.entity;
|
|
6846
|
+
if (!target) return;
|
|
6847
|
+
const tracked = this.unitOfWork.findTracked(target);
|
|
6848
|
+
if (!tracked) return;
|
|
6849
|
+
const localKey = relation.localKey || findPrimaryKey(entry.rootTable);
|
|
6850
|
+
const rootValue = entry.root[localKey];
|
|
6851
|
+
if (rootValue === void 0 || rootValue === null) return;
|
|
6852
|
+
if (entry.change.kind === "add" || entry.change.kind === "attach") {
|
|
6853
|
+
this.assignHasManyForeignKey(tracked.entity, relation, rootValue);
|
|
6854
|
+
this.unitOfWork.markDirty(tracked.entity);
|
|
6855
|
+
return;
|
|
6856
|
+
}
|
|
6857
|
+
if (entry.change.kind === "remove") {
|
|
6858
|
+
this.detachHasManyChild(tracked.entity, relation);
|
|
6859
|
+
}
|
|
6860
|
+
}
|
|
6861
|
+
async handleHasOneChange(entry) {
|
|
6862
|
+
const relation = entry.relation;
|
|
6863
|
+
const target = entry.change.entity;
|
|
6864
|
+
if (!target) return;
|
|
6865
|
+
const tracked = this.unitOfWork.findTracked(target);
|
|
6866
|
+
if (!tracked) return;
|
|
6867
|
+
const localKey = relation.localKey || findPrimaryKey(entry.rootTable);
|
|
6868
|
+
const rootValue = entry.root[localKey];
|
|
6869
|
+
if (rootValue === void 0 || rootValue === null) return;
|
|
6870
|
+
if (entry.change.kind === "attach" || entry.change.kind === "add") {
|
|
6871
|
+
this.assignHasOneForeignKey(tracked.entity, relation, rootValue);
|
|
6872
|
+
this.unitOfWork.markDirty(tracked.entity);
|
|
6873
|
+
return;
|
|
6874
|
+
}
|
|
6875
|
+
if (entry.change.kind === "remove") {
|
|
6876
|
+
this.detachHasOneChild(tracked.entity, relation);
|
|
6877
|
+
}
|
|
6878
|
+
}
|
|
6879
|
+
async handleBelongsToChange(_entry) {
|
|
6880
|
+
}
|
|
6881
|
+
async handleBelongsToManyChange(entry) {
|
|
6882
|
+
const relation = entry.relation;
|
|
6883
|
+
const rootKey = relation.localKey || findPrimaryKey(entry.rootTable);
|
|
6884
|
+
const rootId = entry.root[rootKey];
|
|
6885
|
+
if (rootId === void 0 || rootId === null) return;
|
|
6886
|
+
const targetId = this.resolvePrimaryKeyValue(entry.change.entity, relation.target);
|
|
6887
|
+
if (targetId === null) return;
|
|
6888
|
+
if (entry.change.kind === "attach" || entry.change.kind === "add") {
|
|
6889
|
+
await this.insertPivotRow(relation, rootId, targetId);
|
|
6890
|
+
return;
|
|
6891
|
+
}
|
|
6892
|
+
if (entry.change.kind === "detach" || entry.change.kind === "remove") {
|
|
6893
|
+
await this.deletePivotRow(relation, rootId, targetId);
|
|
6894
|
+
if (relation.cascade === "all" || relation.cascade === "remove") {
|
|
6895
|
+
this.unitOfWork.markRemoved(entry.change.entity);
|
|
6896
|
+
}
|
|
6897
|
+
}
|
|
6898
|
+
}
|
|
6899
|
+
assignHasManyForeignKey(child, relation, rootValue) {
|
|
6900
|
+
const current = child[relation.foreignKey];
|
|
6901
|
+
if (current === rootValue) return;
|
|
6902
|
+
child[relation.foreignKey] = rootValue;
|
|
6903
|
+
}
|
|
6904
|
+
detachHasManyChild(child, relation) {
|
|
6905
|
+
if (relation.cascade === "all" || relation.cascade === "remove") {
|
|
6906
|
+
this.unitOfWork.markRemoved(child);
|
|
6907
|
+
return;
|
|
6908
|
+
}
|
|
6909
|
+
child[relation.foreignKey] = null;
|
|
6910
|
+
this.unitOfWork.markDirty(child);
|
|
6911
|
+
}
|
|
6912
|
+
assignHasOneForeignKey(child, relation, rootValue) {
|
|
6913
|
+
const current = child[relation.foreignKey];
|
|
6914
|
+
if (current === rootValue) return;
|
|
6915
|
+
child[relation.foreignKey] = rootValue;
|
|
6916
|
+
}
|
|
6917
|
+
detachHasOneChild(child, relation) {
|
|
6918
|
+
if (relation.cascade === "all" || relation.cascade === "remove") {
|
|
6919
|
+
this.unitOfWork.markRemoved(child);
|
|
6920
|
+
return;
|
|
6921
|
+
}
|
|
6922
|
+
child[relation.foreignKey] = null;
|
|
6923
|
+
this.unitOfWork.markDirty(child);
|
|
6924
|
+
}
|
|
6925
|
+
async insertPivotRow(relation, rootId, targetId) {
|
|
6926
|
+
const payload = {
|
|
6927
|
+
[relation.pivotForeignKeyToRoot]: rootId,
|
|
6928
|
+
[relation.pivotForeignKeyToTarget]: targetId
|
|
6929
|
+
};
|
|
6930
|
+
const builder = new InsertQueryBuilder(relation.pivotTable).values(payload);
|
|
6931
|
+
const compiled = builder.compile(this.dialect);
|
|
6932
|
+
await this.executor.executeSql(compiled.sql, compiled.params);
|
|
6933
|
+
}
|
|
6934
|
+
async deletePivotRow(relation, rootId, targetId) {
|
|
6935
|
+
const rootCol = relation.pivotTable.columns[relation.pivotForeignKeyToRoot];
|
|
6936
|
+
const targetCol = relation.pivotTable.columns[relation.pivotForeignKeyToTarget];
|
|
6937
|
+
if (!rootCol || !targetCol) return;
|
|
6938
|
+
const builder = new DeleteQueryBuilder(relation.pivotTable).where(
|
|
6939
|
+
and(eq(rootCol, rootId), eq(targetCol, targetId))
|
|
6940
|
+
);
|
|
6941
|
+
const compiled = builder.compile(this.dialect);
|
|
6942
|
+
await this.executor.executeSql(compiled.sql, compiled.params);
|
|
6943
|
+
}
|
|
6944
|
+
resolvePrimaryKeyValue(entity, table) {
|
|
6945
|
+
if (!entity) return null;
|
|
6946
|
+
const key = findPrimaryKey(table);
|
|
6947
|
+
const value = entity[key];
|
|
6948
|
+
if (value === void 0 || value === null) return null;
|
|
6949
|
+
return value;
|
|
6950
|
+
}
|
|
6951
|
+
};
|
|
6952
|
+
|
|
6723
6953
|
// src/orm/query-logger.ts
|
|
6724
6954
|
var createQueryLoggingExecutor = (executor, logger) => {
|
|
6725
6955
|
if (!logger) {
|
|
@@ -6743,31 +6973,40 @@ var createQueryLoggingExecutor = (executor, logger) => {
|
|
|
6743
6973
|
return wrapped;
|
|
6744
6974
|
};
|
|
6745
6975
|
|
|
6746
|
-
// src/orm/
|
|
6747
|
-
var
|
|
6748
|
-
|
|
6749
|
-
|
|
6976
|
+
// src/orm/transaction-runner.ts
|
|
6977
|
+
var runInTransaction = async (executor, action) => {
|
|
6978
|
+
if (!executor.beginTransaction) {
|
|
6979
|
+
await action();
|
|
6980
|
+
return;
|
|
6981
|
+
}
|
|
6982
|
+
await executor.beginTransaction();
|
|
6983
|
+
try {
|
|
6984
|
+
await action();
|
|
6985
|
+
await executor.commitTransaction?.();
|
|
6986
|
+
} catch (error) {
|
|
6987
|
+
await executor.rollbackTransaction?.();
|
|
6988
|
+
throw error;
|
|
6989
|
+
}
|
|
6990
|
+
};
|
|
6991
|
+
|
|
6992
|
+
// src/orm/orm-session.ts
|
|
6993
|
+
var OrmSession = class {
|
|
6994
|
+
constructor(opts) {
|
|
6995
|
+
this.registerRelationChange = (root, relationKey, rootTable, relationName, relation, change) => {
|
|
6996
|
+
this.relationChanges.registerChange(
|
|
6997
|
+
buildRelationChangeEntry(root, relationKey, rootTable, relationName, relation, change)
|
|
6998
|
+
);
|
|
6999
|
+
};
|
|
7000
|
+
this.orm = opts.orm;
|
|
7001
|
+
this.executor = createQueryLoggingExecutor(opts.executor, opts.queryLogger);
|
|
7002
|
+
this.interceptors = [...opts.interceptors ?? []];
|
|
6750
7003
|
this.identityMap = new IdentityMap();
|
|
6751
|
-
this.
|
|
6752
|
-
this.
|
|
6753
|
-
this.
|
|
6754
|
-
options.dialect,
|
|
6755
|
-
this.executorWithLogging,
|
|
6756
|
-
this.identityMap,
|
|
6757
|
-
() => this
|
|
6758
|
-
);
|
|
6759
|
-
this.relationChanges = new RelationChangeProcessor(
|
|
6760
|
-
this.unitOfWork,
|
|
6761
|
-
options.dialect,
|
|
6762
|
-
this.executorWithLogging
|
|
6763
|
-
);
|
|
6764
|
-
this.domainEvents = new DomainEventBus(options.domainEventHandlers);
|
|
7004
|
+
this.unitOfWork = new UnitOfWork(this.orm.dialect, this.executor, this.identityMap, () => this);
|
|
7005
|
+
this.relationChanges = new RelationChangeProcessor(this.unitOfWork, this.orm.dialect, this.executor);
|
|
7006
|
+
this.domainEvents = new DomainEventBus(opts.domainEventHandlers);
|
|
6765
7007
|
}
|
|
6766
7008
|
get dialect() {
|
|
6767
|
-
return this.
|
|
6768
|
-
}
|
|
6769
|
-
get executor() {
|
|
6770
|
-
return this.executorWithLogging;
|
|
7009
|
+
return this.orm.dialect;
|
|
6771
7010
|
}
|
|
6772
7011
|
get identityBuckets() {
|
|
6773
7012
|
return this.unitOfWork.identityBuckets;
|
|
@@ -6793,16 +7032,8 @@ var OrmContext = class {
|
|
|
6793
7032
|
markRemoved(entity) {
|
|
6794
7033
|
this.unitOfWork.markRemoved(entity);
|
|
6795
7034
|
}
|
|
6796
|
-
|
|
6797
|
-
|
|
6798
|
-
root,
|
|
6799
|
-
relationKey,
|
|
6800
|
-
rootTable,
|
|
6801
|
-
relationName,
|
|
6802
|
-
relation,
|
|
6803
|
-
change
|
|
6804
|
-
};
|
|
6805
|
-
this.relationChanges.registerChange(entry);
|
|
7035
|
+
getEntitiesForTable(table) {
|
|
7036
|
+
return this.unitOfWork.getEntitiesForTable(table);
|
|
6806
7037
|
}
|
|
6807
7038
|
registerInterceptor(interceptor) {
|
|
6808
7039
|
this.interceptors.push(interceptor);
|
|
@@ -6810,7 +7041,51 @@ var OrmContext = class {
|
|
|
6810
7041
|
registerDomainEventHandler(name, handler) {
|
|
6811
7042
|
this.domainEvents.register(name, handler);
|
|
6812
7043
|
}
|
|
6813
|
-
async
|
|
7044
|
+
async find(entityClass, id) {
|
|
7045
|
+
const table = getTableDefFromEntity(entityClass);
|
|
7046
|
+
if (!table) {
|
|
7047
|
+
throw new Error("Entity metadata has not been bootstrapped");
|
|
7048
|
+
}
|
|
7049
|
+
const primaryKey = findPrimaryKey(table);
|
|
7050
|
+
const column = table.columns[primaryKey];
|
|
7051
|
+
if (!column) {
|
|
7052
|
+
throw new Error("Entity table does not expose a primary key");
|
|
7053
|
+
}
|
|
7054
|
+
const qb = selectFromEntity(entityClass).where(eq(column, id)).limit(1);
|
|
7055
|
+
const rows = await executeHydrated(this, qb);
|
|
7056
|
+
return rows[0] ?? null;
|
|
7057
|
+
}
|
|
7058
|
+
async findOne(qb) {
|
|
7059
|
+
const limited = qb.limit(1);
|
|
7060
|
+
const rows = await executeHydrated(this, limited);
|
|
7061
|
+
return rows[0] ?? null;
|
|
7062
|
+
}
|
|
7063
|
+
async findMany(qb) {
|
|
7064
|
+
return executeHydrated(this, qb);
|
|
7065
|
+
}
|
|
7066
|
+
async persist(entity) {
|
|
7067
|
+
if (this.unitOfWork.findTracked(entity)) {
|
|
7068
|
+
return;
|
|
7069
|
+
}
|
|
7070
|
+
const table = getTableDefFromEntity(entity.constructor);
|
|
7071
|
+
if (!table) {
|
|
7072
|
+
throw new Error("Entity metadata has not been bootstrapped");
|
|
7073
|
+
}
|
|
7074
|
+
const primaryKey = findPrimaryKey(table);
|
|
7075
|
+
const pkValue = entity[primaryKey];
|
|
7076
|
+
if (pkValue !== void 0 && pkValue !== null) {
|
|
7077
|
+
this.trackManaged(table, pkValue, entity);
|
|
7078
|
+
} else {
|
|
7079
|
+
this.trackNew(table, entity);
|
|
7080
|
+
}
|
|
7081
|
+
}
|
|
7082
|
+
async remove(entity) {
|
|
7083
|
+
this.markRemoved(entity);
|
|
7084
|
+
}
|
|
7085
|
+
async flush() {
|
|
7086
|
+
await this.unitOfWork.flush();
|
|
7087
|
+
}
|
|
7088
|
+
async commit() {
|
|
6814
7089
|
await runInTransaction(this.executor, async () => {
|
|
6815
7090
|
for (const interceptor of this.interceptors) {
|
|
6816
7091
|
await interceptor.beforeFlush?.(this);
|
|
@@ -6824,8 +7099,83 @@ var OrmContext = class {
|
|
|
6824
7099
|
});
|
|
6825
7100
|
await this.domainEvents.dispatch(this.unitOfWork.getTracked(), this);
|
|
6826
7101
|
}
|
|
6827
|
-
|
|
6828
|
-
|
|
7102
|
+
async rollback() {
|
|
7103
|
+
await this.executor.rollbackTransaction?.();
|
|
7104
|
+
this.unitOfWork.reset();
|
|
7105
|
+
this.relationChanges.reset();
|
|
7106
|
+
}
|
|
7107
|
+
getExecutionContext() {
|
|
7108
|
+
return {
|
|
7109
|
+
dialect: this.orm.dialect,
|
|
7110
|
+
executor: this.executor,
|
|
7111
|
+
interceptors: this.orm.interceptors
|
|
7112
|
+
};
|
|
7113
|
+
}
|
|
7114
|
+
getHydrationContext() {
|
|
7115
|
+
return {
|
|
7116
|
+
identityMap: this.identityMap,
|
|
7117
|
+
unitOfWork: this.unitOfWork,
|
|
7118
|
+
domainEvents: this.domainEvents,
|
|
7119
|
+
relationChanges: this.relationChanges,
|
|
7120
|
+
entityContext: this
|
|
7121
|
+
};
|
|
7122
|
+
}
|
|
7123
|
+
};
|
|
7124
|
+
var buildRelationChangeEntry = (root, relationKey, rootTable, relationName, relation, change) => ({
|
|
7125
|
+
root,
|
|
7126
|
+
relationKey,
|
|
7127
|
+
rootTable,
|
|
7128
|
+
relationName,
|
|
7129
|
+
relation,
|
|
7130
|
+
change
|
|
7131
|
+
});
|
|
7132
|
+
|
|
7133
|
+
// src/orm/interceptor-pipeline.ts
|
|
7134
|
+
var InterceptorPipeline = class {
|
|
7135
|
+
constructor() {
|
|
7136
|
+
this.interceptors = [];
|
|
7137
|
+
}
|
|
7138
|
+
use(interceptor) {
|
|
7139
|
+
this.interceptors.push(interceptor);
|
|
7140
|
+
}
|
|
7141
|
+
async run(ctx, executor) {
|
|
7142
|
+
let i = 0;
|
|
7143
|
+
const dispatch = async () => {
|
|
7144
|
+
const interceptor = this.interceptors[i++];
|
|
7145
|
+
if (!interceptor) {
|
|
7146
|
+
return executor.executeSql(ctx.sql, ctx.params);
|
|
7147
|
+
}
|
|
7148
|
+
return interceptor(ctx, dispatch);
|
|
7149
|
+
};
|
|
7150
|
+
return dispatch();
|
|
7151
|
+
}
|
|
7152
|
+
};
|
|
7153
|
+
|
|
7154
|
+
// src/orm/orm.ts
|
|
7155
|
+
var Orm = class {
|
|
7156
|
+
constructor(opts) {
|
|
7157
|
+
this.dialect = opts.dialect;
|
|
7158
|
+
this.interceptors = opts.interceptors ?? new InterceptorPipeline();
|
|
7159
|
+
this.namingStrategy = opts.namingStrategy ?? new DefaultNamingStrategy();
|
|
7160
|
+
this.executorFactory = opts.executorFactory;
|
|
7161
|
+
}
|
|
7162
|
+
createSession(options) {
|
|
7163
|
+
const executor = this.executorFactory.createExecutor(options?.tx);
|
|
7164
|
+
return new OrmSession({ orm: this, executor });
|
|
7165
|
+
}
|
|
7166
|
+
// Nice convenience:
|
|
7167
|
+
async transaction(fn4) {
|
|
7168
|
+
const executor = this.executorFactory.createTransactionalExecutor();
|
|
7169
|
+
const session = new OrmSession({ orm: this, executor });
|
|
7170
|
+
try {
|
|
7171
|
+
const result = await fn4(session);
|
|
7172
|
+
await session.commit();
|
|
7173
|
+
return result;
|
|
7174
|
+
} catch (err) {
|
|
7175
|
+
await session.rollback();
|
|
7176
|
+
throw err;
|
|
7177
|
+
} finally {
|
|
7178
|
+
}
|
|
6829
7179
|
}
|
|
6830
7180
|
};
|
|
6831
7181
|
|
|
@@ -6941,10 +7291,12 @@ function createMssqlExecutor(client) {
|
|
|
6941
7291
|
DefaultHasManyCollection,
|
|
6942
7292
|
DefaultManyToManyCollection,
|
|
6943
7293
|
DeleteQueryBuilder,
|
|
7294
|
+
DomainEventBus,
|
|
6944
7295
|
EntityStatus,
|
|
6945
7296
|
InsertQueryBuilder,
|
|
6946
7297
|
MySqlDialect,
|
|
6947
|
-
|
|
7298
|
+
Orm,
|
|
7299
|
+
OrmSession,
|
|
6948
7300
|
PostgresDialect,
|
|
6949
7301
|
RelationKinds,
|
|
6950
7302
|
SelectQueryBuilder,
|
|
@@ -6986,6 +7338,7 @@ function createMssqlExecutor(client) {
|
|
|
6986
7338
|
createMssqlExecutor,
|
|
6987
7339
|
createMysqlExecutor,
|
|
6988
7340
|
createPostgresExecutor,
|
|
7341
|
+
createQueryLoggingExecutor,
|
|
6989
7342
|
createSqliteExecutor,
|
|
6990
7343
|
currentDate,
|
|
6991
7344
|
currentTime,
|
|
@@ -7003,6 +7356,7 @@ function createMssqlExecutor(client) {
|
|
|
7003
7356
|
endOfMonth,
|
|
7004
7357
|
eq,
|
|
7005
7358
|
executeHydrated,
|
|
7359
|
+
executeHydratedWithContexts,
|
|
7006
7360
|
exists,
|
|
7007
7361
|
exp,
|
|
7008
7362
|
extract,
|