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.js
CHANGED
|
@@ -542,7 +542,7 @@ var StandardFunctionStrategy = class {
|
|
|
542
542
|
};
|
|
543
543
|
|
|
544
544
|
// src/core/dialect/abstract.ts
|
|
545
|
-
var Dialect = class {
|
|
545
|
+
var Dialect = class _Dialect {
|
|
546
546
|
/**
|
|
547
547
|
* Compiles a SELECT query AST to SQL
|
|
548
548
|
* @param ast - Query AST to compile
|
|
@@ -715,6 +715,35 @@ var Dialect = class {
|
|
|
715
715
|
this.registerDefaultOperandCompilers();
|
|
716
716
|
this.registerDefaultExpressionCompilers();
|
|
717
717
|
}
|
|
718
|
+
/**
|
|
719
|
+
* Creates a new Dialect instance (for testing purposes)
|
|
720
|
+
* @param functionStrategy - Optional function strategy
|
|
721
|
+
* @returns New Dialect instance
|
|
722
|
+
*/
|
|
723
|
+
static create(functionStrategy) {
|
|
724
|
+
class TestDialect extends _Dialect {
|
|
725
|
+
constructor() {
|
|
726
|
+
super(...arguments);
|
|
727
|
+
this.dialect = "sqlite";
|
|
728
|
+
}
|
|
729
|
+
quoteIdentifier(id) {
|
|
730
|
+
return `"${id}"`;
|
|
731
|
+
}
|
|
732
|
+
compileSelectAst() {
|
|
733
|
+
throw new Error("Not implemented");
|
|
734
|
+
}
|
|
735
|
+
compileInsertAst() {
|
|
736
|
+
throw new Error("Not implemented");
|
|
737
|
+
}
|
|
738
|
+
compileUpdateAst() {
|
|
739
|
+
throw new Error("Not implemented");
|
|
740
|
+
}
|
|
741
|
+
compileDeleteAst() {
|
|
742
|
+
throw new Error("Not implemented");
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
return new TestDialect(functionStrategy);
|
|
746
|
+
}
|
|
718
747
|
/**
|
|
719
748
|
* Registers an expression compiler for a specific node type
|
|
720
749
|
* @param type - Expression node type
|
|
@@ -4107,31 +4136,43 @@ var flattenResults = (results) => {
|
|
|
4107
4136
|
}
|
|
4108
4137
|
return rows;
|
|
4109
4138
|
};
|
|
4110
|
-
async
|
|
4139
|
+
var executeWithEntityContext = async (entityCtx, qb) => {
|
|
4111
4140
|
const ast = qb.getAST();
|
|
4112
|
-
const compiled =
|
|
4113
|
-
const executed = await
|
|
4141
|
+
const compiled = entityCtx.dialect.compileSelect(ast);
|
|
4142
|
+
const executed = await entityCtx.executor.executeSql(compiled.sql, compiled.params);
|
|
4114
4143
|
const rows = flattenResults(executed);
|
|
4115
4144
|
if (ast.setOps && ast.setOps.length > 0) {
|
|
4116
|
-
return rows.map(
|
|
4117
|
-
(row) => createEntityProxy(ctx, qb.getTable(), row, qb.getLazyRelations())
|
|
4118
|
-
);
|
|
4145
|
+
return rows.map((row) => createEntityProxy(entityCtx, qb.getTable(), row, qb.getLazyRelations()));
|
|
4119
4146
|
}
|
|
4120
4147
|
const hydrated = hydrateRows(rows, qb.getHydrationPlan());
|
|
4121
|
-
return hydrated.map(
|
|
4122
|
-
|
|
4123
|
-
|
|
4148
|
+
return hydrated.map((row) => createEntityFromRow(entityCtx, qb.getTable(), row, qb.getLazyRelations()));
|
|
4149
|
+
};
|
|
4150
|
+
async function executeHydrated(session, qb) {
|
|
4151
|
+
return executeWithEntityContext(session, qb);
|
|
4152
|
+
}
|
|
4153
|
+
async function executeHydratedWithContexts(_execCtx, hydCtx, qb) {
|
|
4154
|
+
const entityCtx = hydCtx.entityContext;
|
|
4155
|
+
if (!entityCtx) {
|
|
4156
|
+
throw new Error("Hydration context is missing an EntityContext");
|
|
4157
|
+
}
|
|
4158
|
+
return executeWithEntityContext(entityCtx, qb);
|
|
4124
4159
|
}
|
|
4125
4160
|
|
|
4126
4161
|
// src/query-builder/select.ts
|
|
4127
4162
|
var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
4128
4163
|
/**
|
|
4129
|
-
|
|
4130
|
-
|
|
4131
|
-
|
|
4132
|
-
|
|
4133
|
-
|
|
4134
|
-
|
|
4164
|
+
|
|
4165
|
+
* Creates a new SelectQueryBuilder instance
|
|
4166
|
+
|
|
4167
|
+
* @param table - Table definition to query
|
|
4168
|
+
|
|
4169
|
+
* @param state - Optional initial query state
|
|
4170
|
+
|
|
4171
|
+
* @param hydration - Optional hydration manager
|
|
4172
|
+
|
|
4173
|
+
* @param dependencies - Optional query builder dependencies
|
|
4174
|
+
|
|
4175
|
+
*/
|
|
4135
4176
|
constructor(table, state, hydration, dependencies, lazyRelations) {
|
|
4136
4177
|
const deps = resolveSelectQueryBuilderDependencies(dependencies);
|
|
4137
4178
|
this.env = { table, deps };
|
|
@@ -4168,112 +4209,168 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
4168
4209
|
return this.applyAst(this.context, (service) => service.withSetOperation(operator, subAst));
|
|
4169
4210
|
}
|
|
4170
4211
|
/**
|
|
4171
|
-
|
|
4172
|
-
|
|
4173
|
-
|
|
4174
|
-
|
|
4212
|
+
|
|
4213
|
+
* Selects specific columns for the query
|
|
4214
|
+
|
|
4215
|
+
* @param columns - Record of column definitions, function nodes, case expressions, or window functions
|
|
4216
|
+
|
|
4217
|
+
* @returns New query builder instance with selected columns
|
|
4218
|
+
|
|
4219
|
+
*/
|
|
4175
4220
|
select(columns) {
|
|
4176
4221
|
return this.clone(this.columnSelector.select(this.context, columns));
|
|
4177
4222
|
}
|
|
4178
4223
|
/**
|
|
4179
|
-
|
|
4180
|
-
|
|
4181
|
-
|
|
4182
|
-
|
|
4224
|
+
|
|
4225
|
+
* Selects raw column expressions
|
|
4226
|
+
|
|
4227
|
+
* @param cols - Column expressions as strings
|
|
4228
|
+
|
|
4229
|
+
* @returns New query builder instance with raw column selections
|
|
4230
|
+
|
|
4231
|
+
*/
|
|
4183
4232
|
selectRaw(...cols) {
|
|
4184
4233
|
return this.clone(this.columnSelector.selectRaw(this.context, cols));
|
|
4185
4234
|
}
|
|
4186
4235
|
/**
|
|
4187
|
-
|
|
4188
|
-
|
|
4189
|
-
|
|
4190
|
-
|
|
4191
|
-
|
|
4192
|
-
|
|
4236
|
+
|
|
4237
|
+
* Adds a Common Table Expression (CTE) to the query
|
|
4238
|
+
|
|
4239
|
+
* @param name - Name of the CTE
|
|
4240
|
+
|
|
4241
|
+
* @param query - Query builder or query node for the CTE
|
|
4242
|
+
|
|
4243
|
+
* @param columns - Optional column names for the CTE
|
|
4244
|
+
|
|
4245
|
+
* @returns New query builder instance with the CTE
|
|
4246
|
+
|
|
4247
|
+
*/
|
|
4193
4248
|
with(name, query, columns) {
|
|
4194
4249
|
const subAst = this.resolveQueryNode(query);
|
|
4195
4250
|
const nextContext = this.applyAst(this.context, (service) => service.withCte(name, subAst, columns, false));
|
|
4196
4251
|
return this.clone(nextContext);
|
|
4197
4252
|
}
|
|
4198
4253
|
/**
|
|
4199
|
-
|
|
4200
|
-
|
|
4201
|
-
|
|
4202
|
-
|
|
4203
|
-
|
|
4204
|
-
|
|
4254
|
+
|
|
4255
|
+
* Adds a recursive Common Table Expression (CTE) to the query
|
|
4256
|
+
|
|
4257
|
+
* @param name - Name of the CTE
|
|
4258
|
+
|
|
4259
|
+
* @param query - Query builder or query node for the CTE
|
|
4260
|
+
|
|
4261
|
+
* @param columns - Optional column names for the CTE
|
|
4262
|
+
|
|
4263
|
+
* @returns New query builder instance with the recursive CTE
|
|
4264
|
+
|
|
4265
|
+
*/
|
|
4205
4266
|
withRecursive(name, query, columns) {
|
|
4206
4267
|
const subAst = this.resolveQueryNode(query);
|
|
4207
4268
|
const nextContext = this.applyAst(this.context, (service) => service.withCte(name, subAst, columns, true));
|
|
4208
4269
|
return this.clone(nextContext);
|
|
4209
4270
|
}
|
|
4210
4271
|
/**
|
|
4211
|
-
|
|
4212
|
-
|
|
4213
|
-
|
|
4214
|
-
|
|
4215
|
-
|
|
4272
|
+
|
|
4273
|
+
* Selects a subquery as a column
|
|
4274
|
+
|
|
4275
|
+
* @param alias - Alias for the subquery column
|
|
4276
|
+
|
|
4277
|
+
* @param sub - Query builder or query node for the subquery
|
|
4278
|
+
|
|
4279
|
+
* @returns New query builder instance with the subquery selection
|
|
4280
|
+
|
|
4281
|
+
*/
|
|
4216
4282
|
selectSubquery(alias, sub) {
|
|
4217
4283
|
const query = this.resolveQueryNode(sub);
|
|
4218
4284
|
return this.clone(this.columnSelector.selectSubquery(this.context, alias, query));
|
|
4219
4285
|
}
|
|
4220
4286
|
/**
|
|
4221
|
-
|
|
4222
|
-
|
|
4223
|
-
|
|
4224
|
-
|
|
4225
|
-
|
|
4287
|
+
|
|
4288
|
+
* Adds an INNER JOIN to the query
|
|
4289
|
+
|
|
4290
|
+
* @param table - Table to join
|
|
4291
|
+
|
|
4292
|
+
* @param condition - Join condition expression
|
|
4293
|
+
|
|
4294
|
+
* @returns New query builder instance with the INNER JOIN
|
|
4295
|
+
|
|
4296
|
+
*/
|
|
4226
4297
|
innerJoin(table, condition) {
|
|
4227
4298
|
const nextContext = this.applyJoin(this.context, table, condition, JOIN_KINDS.INNER);
|
|
4228
4299
|
return this.clone(nextContext);
|
|
4229
4300
|
}
|
|
4230
4301
|
/**
|
|
4231
|
-
|
|
4232
|
-
|
|
4233
|
-
|
|
4234
|
-
|
|
4235
|
-
|
|
4302
|
+
|
|
4303
|
+
* Adds a LEFT JOIN to the query
|
|
4304
|
+
|
|
4305
|
+
* @param table - Table to join
|
|
4306
|
+
|
|
4307
|
+
* @param condition - Join condition expression
|
|
4308
|
+
|
|
4309
|
+
* @returns New query builder instance with the LEFT JOIN
|
|
4310
|
+
|
|
4311
|
+
*/
|
|
4236
4312
|
leftJoin(table, condition) {
|
|
4237
4313
|
const nextContext = this.applyJoin(this.context, table, condition, JOIN_KINDS.LEFT);
|
|
4238
4314
|
return this.clone(nextContext);
|
|
4239
4315
|
}
|
|
4240
4316
|
/**
|
|
4241
|
-
|
|
4242
|
-
|
|
4243
|
-
|
|
4244
|
-
|
|
4245
|
-
|
|
4317
|
+
|
|
4318
|
+
* Adds a RIGHT JOIN to the query
|
|
4319
|
+
|
|
4320
|
+
* @param table - Table to join
|
|
4321
|
+
|
|
4322
|
+
* @param condition - Join condition expression
|
|
4323
|
+
|
|
4324
|
+
* @returns New query builder instance with the RIGHT JOIN
|
|
4325
|
+
|
|
4326
|
+
*/
|
|
4246
4327
|
rightJoin(table, condition) {
|
|
4247
4328
|
const nextContext = this.applyJoin(this.context, table, condition, JOIN_KINDS.RIGHT);
|
|
4248
4329
|
return this.clone(nextContext);
|
|
4249
4330
|
}
|
|
4250
4331
|
/**
|
|
4251
|
-
|
|
4252
|
-
|
|
4253
|
-
|
|
4254
|
-
|
|
4255
|
-
|
|
4332
|
+
|
|
4333
|
+
* Matches records based on a relationship
|
|
4334
|
+
|
|
4335
|
+
* @param relationName - Name of the relationship to match
|
|
4336
|
+
|
|
4337
|
+
* @param predicate - Optional predicate expression
|
|
4338
|
+
|
|
4339
|
+
* @returns New query builder instance with the relationship match
|
|
4340
|
+
|
|
4341
|
+
*/
|
|
4256
4342
|
match(relationName, predicate) {
|
|
4257
4343
|
const nextContext = this.relationManager.match(this.context, relationName, predicate);
|
|
4258
4344
|
return this.clone(nextContext);
|
|
4259
4345
|
}
|
|
4260
4346
|
/**
|
|
4261
|
-
|
|
4262
|
-
|
|
4263
|
-
|
|
4264
|
-
|
|
4265
|
-
|
|
4266
|
-
|
|
4347
|
+
|
|
4348
|
+
* Joins a related table
|
|
4349
|
+
|
|
4350
|
+
* @param relationName - Name of the relationship to join
|
|
4351
|
+
|
|
4352
|
+
* @param joinKind - Type of join (defaults to INNER)
|
|
4353
|
+
|
|
4354
|
+
* @param extraCondition - Optional additional join condition
|
|
4355
|
+
|
|
4356
|
+
* @returns New query builder instance with the relationship join
|
|
4357
|
+
|
|
4358
|
+
*/
|
|
4267
4359
|
joinRelation(relationName, joinKind = JOIN_KINDS.INNER, extraCondition) {
|
|
4268
4360
|
const nextContext = this.relationManager.joinRelation(this.context, relationName, joinKind, extraCondition);
|
|
4269
4361
|
return this.clone(nextContext);
|
|
4270
4362
|
}
|
|
4271
4363
|
/**
|
|
4272
|
-
|
|
4273
|
-
|
|
4274
|
-
|
|
4275
|
-
|
|
4276
|
-
|
|
4364
|
+
|
|
4365
|
+
* Includes related data in the query results
|
|
4366
|
+
|
|
4367
|
+
* @param relationName - Name of the relationship to include
|
|
4368
|
+
|
|
4369
|
+
* @param options - Optional include options
|
|
4370
|
+
|
|
4371
|
+
* @returns New query builder instance with the relationship inclusion
|
|
4372
|
+
|
|
4373
|
+
*/
|
|
4277
4374
|
include(relationName, options) {
|
|
4278
4375
|
const nextContext = this.relationManager.include(this.context, relationName, options);
|
|
4279
4376
|
return this.clone(nextContext);
|
|
@@ -4292,125 +4389,186 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
4292
4389
|
async execute(ctx) {
|
|
4293
4390
|
return executeHydrated(ctx, this);
|
|
4294
4391
|
}
|
|
4392
|
+
async executeWithContexts(execCtx, hydCtx) {
|
|
4393
|
+
return executeHydratedWithContexts(execCtx, hydCtx, this);
|
|
4394
|
+
}
|
|
4295
4395
|
/**
|
|
4296
|
-
|
|
4297
|
-
|
|
4298
|
-
|
|
4299
|
-
|
|
4396
|
+
|
|
4397
|
+
* Adds a WHERE condition to the query
|
|
4398
|
+
|
|
4399
|
+
* @param expr - Expression for the WHERE clause
|
|
4400
|
+
|
|
4401
|
+
* @returns New query builder instance with the WHERE condition
|
|
4402
|
+
|
|
4403
|
+
*/
|
|
4300
4404
|
where(expr) {
|
|
4301
4405
|
const nextContext = this.applyAst(this.context, (service) => service.withWhere(expr));
|
|
4302
4406
|
return this.clone(nextContext);
|
|
4303
4407
|
}
|
|
4304
4408
|
/**
|
|
4305
|
-
|
|
4306
|
-
|
|
4307
|
-
|
|
4308
|
-
|
|
4409
|
+
|
|
4410
|
+
* Adds a GROUP BY clause to the query
|
|
4411
|
+
|
|
4412
|
+
* @param col - Column definition or column node to group by
|
|
4413
|
+
|
|
4414
|
+
* @returns New query builder instance with the GROUP BY clause
|
|
4415
|
+
|
|
4416
|
+
*/
|
|
4309
4417
|
groupBy(col2) {
|
|
4310
4418
|
const nextContext = this.applyAst(this.context, (service) => service.withGroupBy(col2));
|
|
4311
4419
|
return this.clone(nextContext);
|
|
4312
4420
|
}
|
|
4313
4421
|
/**
|
|
4314
|
-
|
|
4315
|
-
|
|
4316
|
-
|
|
4317
|
-
|
|
4422
|
+
|
|
4423
|
+
* Adds a HAVING condition to the query
|
|
4424
|
+
|
|
4425
|
+
* @param expr - Expression for the HAVING clause
|
|
4426
|
+
|
|
4427
|
+
* @returns New query builder instance with the HAVING condition
|
|
4428
|
+
|
|
4429
|
+
*/
|
|
4318
4430
|
having(expr) {
|
|
4319
4431
|
const nextContext = this.applyAst(this.context, (service) => service.withHaving(expr));
|
|
4320
4432
|
return this.clone(nextContext);
|
|
4321
4433
|
}
|
|
4322
4434
|
/**
|
|
4323
|
-
|
|
4324
|
-
|
|
4325
|
-
|
|
4326
|
-
|
|
4327
|
-
|
|
4435
|
+
|
|
4436
|
+
* Adds an ORDER BY clause to the query
|
|
4437
|
+
|
|
4438
|
+
* @param col - Column definition or column node to order by
|
|
4439
|
+
|
|
4440
|
+
* @param direction - Order direction (defaults to ASC)
|
|
4441
|
+
|
|
4442
|
+
* @returns New query builder instance with the ORDER BY clause
|
|
4443
|
+
|
|
4444
|
+
*/
|
|
4328
4445
|
orderBy(col2, direction = ORDER_DIRECTIONS.ASC) {
|
|
4329
4446
|
const nextContext = this.applyAst(this.context, (service) => service.withOrderBy(col2, direction));
|
|
4330
4447
|
return this.clone(nextContext);
|
|
4331
4448
|
}
|
|
4332
4449
|
/**
|
|
4333
|
-
|
|
4334
|
-
|
|
4335
|
-
|
|
4336
|
-
|
|
4450
|
+
|
|
4451
|
+
* Adds a DISTINCT clause to the query
|
|
4452
|
+
|
|
4453
|
+
* @param cols - Columns to make distinct
|
|
4454
|
+
|
|
4455
|
+
* @returns New query builder instance with the DISTINCT clause
|
|
4456
|
+
|
|
4457
|
+
*/
|
|
4337
4458
|
distinct(...cols) {
|
|
4338
4459
|
return this.clone(this.columnSelector.distinct(this.context, cols));
|
|
4339
4460
|
}
|
|
4340
4461
|
/**
|
|
4341
|
-
|
|
4342
|
-
|
|
4343
|
-
|
|
4344
|
-
|
|
4462
|
+
|
|
4463
|
+
* Adds a LIMIT clause to the query
|
|
4464
|
+
|
|
4465
|
+
* @param n - Maximum number of rows to return
|
|
4466
|
+
|
|
4467
|
+
* @returns New query builder instance with the LIMIT clause
|
|
4468
|
+
|
|
4469
|
+
*/
|
|
4345
4470
|
limit(n) {
|
|
4346
4471
|
const nextContext = this.applyAst(this.context, (service) => service.withLimit(n));
|
|
4347
4472
|
return this.clone(nextContext);
|
|
4348
4473
|
}
|
|
4349
4474
|
/**
|
|
4350
|
-
|
|
4351
|
-
|
|
4352
|
-
|
|
4353
|
-
|
|
4475
|
+
|
|
4476
|
+
* Adds an OFFSET clause to the query
|
|
4477
|
+
|
|
4478
|
+
* @param n - Number of rows to skip
|
|
4479
|
+
|
|
4480
|
+
* @returns New query builder instance with the OFFSET clause
|
|
4481
|
+
|
|
4482
|
+
*/
|
|
4354
4483
|
offset(n) {
|
|
4355
4484
|
const nextContext = this.applyAst(this.context, (service) => service.withOffset(n));
|
|
4356
4485
|
return this.clone(nextContext);
|
|
4357
4486
|
}
|
|
4358
4487
|
/**
|
|
4359
|
-
|
|
4360
|
-
|
|
4361
|
-
|
|
4362
|
-
|
|
4488
|
+
|
|
4489
|
+
* Combines this query with another using UNION
|
|
4490
|
+
|
|
4491
|
+
* @param query - Query to union with
|
|
4492
|
+
|
|
4493
|
+
* @returns New query builder instance with the set operation
|
|
4494
|
+
|
|
4495
|
+
*/
|
|
4363
4496
|
union(query) {
|
|
4364
4497
|
return this.clone(this.applySetOperation("UNION", query));
|
|
4365
4498
|
}
|
|
4366
4499
|
/**
|
|
4367
|
-
|
|
4368
|
-
|
|
4369
|
-
|
|
4370
|
-
|
|
4500
|
+
|
|
4501
|
+
* Combines this query with another using UNION ALL
|
|
4502
|
+
|
|
4503
|
+
* @param query - Query to union with
|
|
4504
|
+
|
|
4505
|
+
* @returns New query builder instance with the set operation
|
|
4506
|
+
|
|
4507
|
+
*/
|
|
4371
4508
|
unionAll(query) {
|
|
4372
4509
|
return this.clone(this.applySetOperation("UNION ALL", query));
|
|
4373
4510
|
}
|
|
4374
4511
|
/**
|
|
4375
|
-
|
|
4376
|
-
|
|
4377
|
-
|
|
4378
|
-
|
|
4512
|
+
|
|
4513
|
+
* Combines this query with another using INTERSECT
|
|
4514
|
+
|
|
4515
|
+
* @param query - Query to intersect with
|
|
4516
|
+
|
|
4517
|
+
* @returns New query builder instance with the set operation
|
|
4518
|
+
|
|
4519
|
+
*/
|
|
4379
4520
|
intersect(query) {
|
|
4380
4521
|
return this.clone(this.applySetOperation("INTERSECT", query));
|
|
4381
4522
|
}
|
|
4382
4523
|
/**
|
|
4383
|
-
|
|
4384
|
-
|
|
4385
|
-
|
|
4386
|
-
|
|
4524
|
+
|
|
4525
|
+
* Combines this query with another using EXCEPT
|
|
4526
|
+
|
|
4527
|
+
* @param query - Query to subtract
|
|
4528
|
+
|
|
4529
|
+
* @returns New query builder instance with the set operation
|
|
4530
|
+
|
|
4531
|
+
*/
|
|
4387
4532
|
except(query) {
|
|
4388
4533
|
return this.clone(this.applySetOperation("EXCEPT", query));
|
|
4389
4534
|
}
|
|
4390
4535
|
/**
|
|
4391
|
-
|
|
4392
|
-
|
|
4393
|
-
|
|
4394
|
-
|
|
4536
|
+
|
|
4537
|
+
* Adds a WHERE EXISTS condition to the query
|
|
4538
|
+
|
|
4539
|
+
* @param subquery - Subquery to check for existence
|
|
4540
|
+
|
|
4541
|
+
* @returns New query builder instance with the WHERE EXISTS condition
|
|
4542
|
+
|
|
4543
|
+
*/
|
|
4395
4544
|
whereExists(subquery) {
|
|
4396
4545
|
const subAst = this.resolveQueryNode(subquery);
|
|
4397
4546
|
return this.where(exists(subAst));
|
|
4398
4547
|
}
|
|
4399
4548
|
/**
|
|
4400
|
-
|
|
4401
|
-
|
|
4402
|
-
|
|
4403
|
-
|
|
4549
|
+
|
|
4550
|
+
* Adds a WHERE NOT EXISTS condition to the query
|
|
4551
|
+
|
|
4552
|
+
* @param subquery - Subquery to check for non-existence
|
|
4553
|
+
|
|
4554
|
+
* @returns New query builder instance with the WHERE NOT EXISTS condition
|
|
4555
|
+
|
|
4556
|
+
*/
|
|
4404
4557
|
whereNotExists(subquery) {
|
|
4405
4558
|
const subAst = this.resolveQueryNode(subquery);
|
|
4406
4559
|
return this.where(notExists(subAst));
|
|
4407
4560
|
}
|
|
4408
4561
|
/**
|
|
4409
|
-
|
|
4410
|
-
|
|
4411
|
-
|
|
4412
|
-
|
|
4413
|
-
|
|
4562
|
+
|
|
4563
|
+
* Adds a WHERE EXISTS condition based on a relationship
|
|
4564
|
+
|
|
4565
|
+
* @param relationName - Name of the relationship to check
|
|
4566
|
+
|
|
4567
|
+
* @param callback - Optional callback to modify the relationship query
|
|
4568
|
+
|
|
4569
|
+
* @returns New query builder instance with the relationship existence check
|
|
4570
|
+
|
|
4571
|
+
*/
|
|
4414
4572
|
whereHas(relationName, callback) {
|
|
4415
4573
|
const relation = this.env.table.relations[relationName];
|
|
4416
4574
|
if (!relation) {
|
|
@@ -4425,11 +4583,16 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
4425
4583
|
return this.where(exists(finalSubAst));
|
|
4426
4584
|
}
|
|
4427
4585
|
/**
|
|
4428
|
-
|
|
4429
|
-
|
|
4430
|
-
|
|
4431
|
-
|
|
4432
|
-
|
|
4586
|
+
|
|
4587
|
+
* Adds a WHERE NOT EXISTS condition based on a relationship
|
|
4588
|
+
|
|
4589
|
+
* @param relationName - Name of the relationship to check
|
|
4590
|
+
|
|
4591
|
+
* @param callback - Optional callback to modify the relationship query
|
|
4592
|
+
|
|
4593
|
+
* @returns New query builder instance with the relationship non-existence check
|
|
4594
|
+
|
|
4595
|
+
*/
|
|
4433
4596
|
whereHasNot(relationName, callback) {
|
|
4434
4597
|
const relation = this.env.table.relations[relationName];
|
|
4435
4598
|
if (!relation) {
|
|
@@ -4444,33 +4607,47 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
4444
4607
|
return this.where(notExists(finalSubAst));
|
|
4445
4608
|
}
|
|
4446
4609
|
/**
|
|
4447
|
-
|
|
4448
|
-
|
|
4449
|
-
|
|
4450
|
-
|
|
4610
|
+
|
|
4611
|
+
* Compiles the query to SQL for a specific dialect
|
|
4612
|
+
|
|
4613
|
+
* @param dialect - Database dialect to compile for
|
|
4614
|
+
|
|
4615
|
+
* @returns Compiled query with SQL and parameters
|
|
4616
|
+
|
|
4617
|
+
*/
|
|
4451
4618
|
compile(dialect) {
|
|
4452
4619
|
const resolved = resolveDialectInput(dialect);
|
|
4453
4620
|
return resolved.compileSelect(this.context.state.ast);
|
|
4454
4621
|
}
|
|
4455
4622
|
/**
|
|
4456
|
-
|
|
4457
|
-
|
|
4458
|
-
|
|
4459
|
-
|
|
4623
|
+
|
|
4624
|
+
* Converts the query to SQL string for a specific dialect
|
|
4625
|
+
|
|
4626
|
+
* @param dialect - Database dialect to generate SQL for
|
|
4627
|
+
|
|
4628
|
+
* @returns SQL string representation of the query
|
|
4629
|
+
|
|
4630
|
+
*/
|
|
4460
4631
|
toSql(dialect) {
|
|
4461
4632
|
return this.compile(dialect).sql;
|
|
4462
4633
|
}
|
|
4463
4634
|
/**
|
|
4464
|
-
|
|
4465
|
-
|
|
4466
|
-
|
|
4635
|
+
|
|
4636
|
+
* Gets the hydration plan for the query
|
|
4637
|
+
|
|
4638
|
+
* @returns Hydration plan or undefined if none exists
|
|
4639
|
+
|
|
4640
|
+
*/
|
|
4467
4641
|
getHydrationPlan() {
|
|
4468
4642
|
return this.context.hydration.getPlan();
|
|
4469
4643
|
}
|
|
4470
4644
|
/**
|
|
4471
|
-
|
|
4472
|
-
|
|
4473
|
-
|
|
4645
|
+
|
|
4646
|
+
* Gets the Abstract Syntax Tree (AST) representation of the query
|
|
4647
|
+
|
|
4648
|
+
* @returns Query AST with hydration applied
|
|
4649
|
+
|
|
4650
|
+
*/
|
|
4474
4651
|
getAST() {
|
|
4475
4652
|
return this.context.hydration.applyToAst(this.context.state.ast);
|
|
4476
4653
|
}
|
|
@@ -5768,12 +5945,47 @@ var SQL_OPERATOR_REGISTRY = {
|
|
|
5768
5945
|
[SQL_OPERATORS.NOT_EXISTS]: { sql: SQL_OPERATORS.NOT_EXISTS, tsName: "notExists" }
|
|
5769
5946
|
};
|
|
5770
5947
|
|
|
5948
|
+
// src/codegen/naming-strategy.ts
|
|
5949
|
+
var DefaultNamingStrategy = class {
|
|
5950
|
+
/**
|
|
5951
|
+
* Converts table names to TypeScript symbols
|
|
5952
|
+
* @param table - Table node, function table node, or string name
|
|
5953
|
+
* @returns Capitalized table name (handles schema-qualified names)
|
|
5954
|
+
*/
|
|
5955
|
+
tableToSymbol(table) {
|
|
5956
|
+
const tableName = typeof table === "string" ? table : table.name;
|
|
5957
|
+
if (tableName.includes(".")) {
|
|
5958
|
+
return tableName.split(".").map((part) => this.capitalize(part)).join("");
|
|
5959
|
+
}
|
|
5960
|
+
return this.capitalize(tableName);
|
|
5961
|
+
}
|
|
5962
|
+
/**
|
|
5963
|
+
* Converts column references to property names
|
|
5964
|
+
* @param column - Column node
|
|
5965
|
+
* @returns Column name as-is (for backward compatibility)
|
|
5966
|
+
*/
|
|
5967
|
+
columnToProperty(column) {
|
|
5968
|
+
return column.name;
|
|
5969
|
+
}
|
|
5970
|
+
/**
|
|
5971
|
+
* Capitalizes the first letter of a string
|
|
5972
|
+
* @param s - String to capitalize
|
|
5973
|
+
* @returns Capitalized string
|
|
5974
|
+
*/
|
|
5975
|
+
capitalize(s) {
|
|
5976
|
+
if (!s) return s;
|
|
5977
|
+
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
5978
|
+
}
|
|
5979
|
+
};
|
|
5980
|
+
|
|
5771
5981
|
// src/codegen/typescript.ts
|
|
5772
|
-
var capitalize = (s) => s.charAt(0).toUpperCase() + s.slice(1);
|
|
5773
5982
|
var assertNever2 = (value) => {
|
|
5774
5983
|
throw new Error(`Unhandled SQL operator: ${value}`);
|
|
5775
5984
|
};
|
|
5776
5985
|
var TypeScriptGenerator = class {
|
|
5986
|
+
constructor(namingStrategy = new DefaultNamingStrategy()) {
|
|
5987
|
+
this.namingStrategy = namingStrategy;
|
|
5988
|
+
}
|
|
5777
5989
|
/**
|
|
5778
5990
|
* Generates TypeScript code from a query AST
|
|
5779
5991
|
* @param ast - Query AST to generate code from
|
|
@@ -5804,9 +6016,9 @@ var TypeScriptGenerator = class {
|
|
|
5804
6016
|
lines.push(` ${sel}${index < selections.length - 1 ? "," : ""}`);
|
|
5805
6017
|
});
|
|
5806
6018
|
lines.push(`})`);
|
|
5807
|
-
lines.push(`.from(${
|
|
6019
|
+
lines.push(`.from(${this.namingStrategy.tableToSymbol(ast.from)})`);
|
|
5808
6020
|
if (ast.distinct && ast.distinct.length) {
|
|
5809
|
-
const cols = ast.distinct.map((c) => `${
|
|
6021
|
+
const cols = ast.distinct.map((c) => `${this.namingStrategy.tableToSymbol(c.table)}.${c.name}`).join(", ");
|
|
5810
6022
|
lines.push(`.distinct(${cols})`);
|
|
5811
6023
|
}
|
|
5812
6024
|
ast.joins.forEach((join) => {
|
|
@@ -5821,7 +6033,7 @@ var TypeScriptGenerator = class {
|
|
|
5821
6033
|
lines.push(`.joinRelation('${relationName}', '${join.kind}')`);
|
|
5822
6034
|
}
|
|
5823
6035
|
} else {
|
|
5824
|
-
const table =
|
|
6036
|
+
const table = this.namingStrategy.tableToSymbol(join.table);
|
|
5825
6037
|
const cond = this.printExpression(join.condition);
|
|
5826
6038
|
let method = "innerJoin";
|
|
5827
6039
|
if (join.kind === "LEFT") method = "leftJoin";
|
|
@@ -5842,7 +6054,7 @@ var TypeScriptGenerator = class {
|
|
|
5842
6054
|
lines.push(`.where(${this.printExpression(ast.where)})`);
|
|
5843
6055
|
}
|
|
5844
6056
|
if (ast.groupBy && ast.groupBy.length) {
|
|
5845
|
-
const cols = ast.groupBy.map((c) => `${
|
|
6057
|
+
const cols = ast.groupBy.map((c) => `${this.namingStrategy.tableToSymbol(c.table)}.${c.name}`).join(", ");
|
|
5846
6058
|
lines.push(`.groupBy(${cols})`);
|
|
5847
6059
|
}
|
|
5848
6060
|
if (ast.having) {
|
|
@@ -5850,7 +6062,7 @@ var TypeScriptGenerator = class {
|
|
|
5850
6062
|
}
|
|
5851
6063
|
if (ast.orderBy && ast.orderBy.length) {
|
|
5852
6064
|
ast.orderBy.forEach((o) => {
|
|
5853
|
-
lines.push(`.orderBy(${
|
|
6065
|
+
lines.push(`.orderBy(${this.namingStrategy.tableToSymbol(o.column.table)}.${o.column.name}, '${o.direction}')`);
|
|
5854
6066
|
});
|
|
5855
6067
|
}
|
|
5856
6068
|
if (ast.limit) lines.push(`.limit(${ast.limit})`);
|
|
@@ -5989,7 +6201,7 @@ var TypeScriptGenerator = class {
|
|
|
5989
6201
|
* @returns TypeScript code representation
|
|
5990
6202
|
*/
|
|
5991
6203
|
printColumnOperand(column) {
|
|
5992
|
-
return `${
|
|
6204
|
+
return `${this.namingStrategy.tableToSymbol(column.table)}.${column.name}`;
|
|
5993
6205
|
}
|
|
5994
6206
|
/**
|
|
5995
6207
|
* Prints a literal operand to TypeScript code
|
|
@@ -6015,7 +6227,7 @@ var TypeScriptGenerator = class {
|
|
|
6015
6227
|
* @returns TypeScript code representation
|
|
6016
6228
|
*/
|
|
6017
6229
|
printJsonPathOperand(json) {
|
|
6018
|
-
return `jsonPath(${
|
|
6230
|
+
return `jsonPath(${this.namingStrategy.tableToSymbol(json.column.table)}.${json.column.name}, '${json.path}')`;
|
|
6019
6231
|
}
|
|
6020
6232
|
/**
|
|
6021
6233
|
* Prints a scalar subquery operand to TypeScript code
|
|
@@ -6051,11 +6263,11 @@ var TypeScriptGenerator = class {
|
|
|
6051
6263
|
result += ") OVER (";
|
|
6052
6264
|
const parts = [];
|
|
6053
6265
|
if (node.partitionBy && node.partitionBy.length > 0) {
|
|
6054
|
-
const partitionClause = "PARTITION BY " + node.partitionBy.map((col2) => `${
|
|
6266
|
+
const partitionClause = "PARTITION BY " + node.partitionBy.map((col2) => `${this.namingStrategy.tableToSymbol(col2.table)}.${col2.name}`).join(", ");
|
|
6055
6267
|
parts.push(partitionClause);
|
|
6056
6268
|
}
|
|
6057
6269
|
if (node.orderBy && node.orderBy.length > 0) {
|
|
6058
|
-
const orderClause = "ORDER BY " + node.orderBy.map((o) => `${
|
|
6270
|
+
const orderClause = "ORDER BY " + node.orderBy.map((o) => `${this.namingStrategy.tableToSymbol(o.column.table)}.${o.column.name} ${o.direction}`).join(", ");
|
|
6059
6271
|
parts.push(orderClause);
|
|
6060
6272
|
}
|
|
6061
6273
|
result += parts.join(" ");
|
|
@@ -6084,46 +6296,24 @@ var TypeScriptGenerator = class {
|
|
|
6084
6296
|
}
|
|
6085
6297
|
};
|
|
6086
6298
|
|
|
6087
|
-
// src/orm/
|
|
6088
|
-
var
|
|
6089
|
-
|
|
6090
|
-
|
|
6091
|
-
const handlers = initialHandlers ?? {};
|
|
6092
|
-
Object.entries(handlers).forEach(([name, list]) => {
|
|
6093
|
-
this.handlers.set(name, [...list]);
|
|
6094
|
-
});
|
|
6095
|
-
}
|
|
6096
|
-
register(name, handler) {
|
|
6097
|
-
const existing = this.handlers.get(name) ?? [];
|
|
6098
|
-
existing.push(handler);
|
|
6099
|
-
this.handlers.set(name, existing);
|
|
6100
|
-
}
|
|
6101
|
-
async dispatch(trackedEntities, ctx) {
|
|
6102
|
-
for (const tracked of trackedEntities) {
|
|
6103
|
-
const entity = tracked.entity;
|
|
6104
|
-
if (!entity.domainEvents || !entity.domainEvents.length) continue;
|
|
6105
|
-
for (const event of entity.domainEvents) {
|
|
6106
|
-
const eventName = this.getEventName(event);
|
|
6107
|
-
const handlers = this.handlers.get(eventName);
|
|
6108
|
-
if (!handlers) continue;
|
|
6109
|
-
for (const handler of handlers) {
|
|
6110
|
-
await handler(event, ctx);
|
|
6111
|
-
}
|
|
6112
|
-
}
|
|
6113
|
-
entity.domainEvents = [];
|
|
6114
|
-
}
|
|
6115
|
-
}
|
|
6116
|
-
getEventName(event) {
|
|
6117
|
-
if (!event) return "Unknown";
|
|
6118
|
-
if (typeof event === "string") return event;
|
|
6119
|
-
return event.constructor?.name ?? "Unknown";
|
|
6120
|
-
}
|
|
6299
|
+
// src/orm/entity-metadata.ts
|
|
6300
|
+
var metadataMap = /* @__PURE__ */ new Map();
|
|
6301
|
+
var getEntityMetadata = (target) => {
|
|
6302
|
+
return metadataMap.get(target);
|
|
6121
6303
|
};
|
|
6122
|
-
|
|
6123
|
-
|
|
6124
|
-
|
|
6304
|
+
|
|
6305
|
+
// src/decorators/bootstrap.ts
|
|
6306
|
+
var getTableDefFromEntity = (ctor) => {
|
|
6307
|
+
const meta = getEntityMetadata(ctor);
|
|
6308
|
+
if (!meta) return void 0;
|
|
6309
|
+
return meta.table;
|
|
6310
|
+
};
|
|
6311
|
+
var selectFromEntity = (ctor) => {
|
|
6312
|
+
const table = getTableDefFromEntity(ctor);
|
|
6313
|
+
if (!table) {
|
|
6314
|
+
throw new Error("Entity metadata has not been bootstrapped");
|
|
6125
6315
|
}
|
|
6126
|
-
|
|
6316
|
+
return new SelectQueryBuilder(table);
|
|
6127
6317
|
};
|
|
6128
6318
|
|
|
6129
6319
|
// src/orm/identity-map.ts
|
|
@@ -6153,272 +6343,121 @@ var IdentityMap = class {
|
|
|
6153
6343
|
const bucket = this.buckets.get(table.name);
|
|
6154
6344
|
return bucket ? Array.from(bucket.values()) : [];
|
|
6155
6345
|
}
|
|
6346
|
+
clear() {
|
|
6347
|
+
this.buckets.clear();
|
|
6348
|
+
}
|
|
6156
6349
|
toIdentityKey(pk) {
|
|
6157
6350
|
return String(pk);
|
|
6158
6351
|
}
|
|
6159
6352
|
};
|
|
6160
6353
|
|
|
6161
|
-
// src/orm/
|
|
6162
|
-
var
|
|
6163
|
-
|
|
6164
|
-
|
|
6354
|
+
// src/orm/runtime-types.ts
|
|
6355
|
+
var EntityStatus = /* @__PURE__ */ ((EntityStatus2) => {
|
|
6356
|
+
EntityStatus2["New"] = "new";
|
|
6357
|
+
EntityStatus2["Managed"] = "managed";
|
|
6358
|
+
EntityStatus2["Dirty"] = "dirty";
|
|
6359
|
+
EntityStatus2["Removed"] = "removed";
|
|
6360
|
+
EntityStatus2["Detached"] = "detached";
|
|
6361
|
+
return EntityStatus2;
|
|
6362
|
+
})(EntityStatus || {});
|
|
6363
|
+
|
|
6364
|
+
// src/orm/unit-of-work.ts
|
|
6365
|
+
var UnitOfWork = class {
|
|
6366
|
+
constructor(dialect, executor, identityMap, hookContext) {
|
|
6165
6367
|
this.dialect = dialect;
|
|
6166
6368
|
this.executor = executor;
|
|
6167
|
-
this.
|
|
6369
|
+
this.identityMap = identityMap;
|
|
6370
|
+
this.hookContext = hookContext;
|
|
6371
|
+
this.trackedEntities = /* @__PURE__ */ new Map();
|
|
6168
6372
|
}
|
|
6169
|
-
|
|
6170
|
-
this.
|
|
6373
|
+
get identityBuckets() {
|
|
6374
|
+
return this.identityMap.bucketsMap;
|
|
6171
6375
|
}
|
|
6172
|
-
|
|
6173
|
-
|
|
6174
|
-
|
|
6175
|
-
|
|
6176
|
-
|
|
6177
|
-
|
|
6178
|
-
|
|
6179
|
-
|
|
6376
|
+
getTracked() {
|
|
6377
|
+
return Array.from(this.trackedEntities.values());
|
|
6378
|
+
}
|
|
6379
|
+
getEntity(table, pk) {
|
|
6380
|
+
return this.identityMap.getEntity(table, pk);
|
|
6381
|
+
}
|
|
6382
|
+
getEntitiesForTable(table) {
|
|
6383
|
+
return this.identityMap.getEntitiesForTable(table);
|
|
6384
|
+
}
|
|
6385
|
+
findTracked(entity) {
|
|
6386
|
+
return this.trackedEntities.get(entity);
|
|
6387
|
+
}
|
|
6388
|
+
setEntity(table, pk, entity) {
|
|
6389
|
+
if (pk === null || pk === void 0) return;
|
|
6390
|
+
let tracked = this.trackedEntities.get(entity);
|
|
6391
|
+
if (!tracked) {
|
|
6392
|
+
tracked = {
|
|
6393
|
+
table,
|
|
6394
|
+
entity,
|
|
6395
|
+
pk,
|
|
6396
|
+
status: "managed" /* Managed */,
|
|
6397
|
+
original: this.createSnapshot(table, entity)
|
|
6398
|
+
};
|
|
6399
|
+
this.trackedEntities.set(entity, tracked);
|
|
6400
|
+
} else {
|
|
6401
|
+
tracked.pk = pk;
|
|
6402
|
+
}
|
|
6403
|
+
this.registerIdentity(tracked);
|
|
6404
|
+
}
|
|
6405
|
+
trackNew(table, entity, pk) {
|
|
6406
|
+
const tracked = {
|
|
6407
|
+
table,
|
|
6408
|
+
entity,
|
|
6409
|
+
pk: pk ?? null,
|
|
6410
|
+
status: "new" /* New */,
|
|
6411
|
+
original: null
|
|
6412
|
+
};
|
|
6413
|
+
this.trackedEntities.set(entity, tracked);
|
|
6414
|
+
if (pk != null) {
|
|
6415
|
+
this.registerIdentity(tracked);
|
|
6416
|
+
}
|
|
6417
|
+
}
|
|
6418
|
+
trackManaged(table, pk, entity) {
|
|
6419
|
+
const tracked = {
|
|
6420
|
+
table,
|
|
6421
|
+
entity,
|
|
6422
|
+
pk,
|
|
6423
|
+
status: "managed" /* Managed */,
|
|
6424
|
+
original: this.createSnapshot(table, entity)
|
|
6425
|
+
};
|
|
6426
|
+
this.trackedEntities.set(entity, tracked);
|
|
6427
|
+
this.registerIdentity(tracked);
|
|
6428
|
+
}
|
|
6429
|
+
markDirty(entity) {
|
|
6430
|
+
const tracked = this.trackedEntities.get(entity);
|
|
6431
|
+
if (!tracked) return;
|
|
6432
|
+
if (tracked.status === "new" /* New */ || tracked.status === "removed" /* Removed */) return;
|
|
6433
|
+
tracked.status = "dirty" /* Dirty */;
|
|
6434
|
+
}
|
|
6435
|
+
markRemoved(entity) {
|
|
6436
|
+
const tracked = this.trackedEntities.get(entity);
|
|
6437
|
+
if (!tracked) return;
|
|
6438
|
+
tracked.status = "removed" /* Removed */;
|
|
6439
|
+
}
|
|
6440
|
+
async flush() {
|
|
6441
|
+
const toFlush = Array.from(this.trackedEntities.values());
|
|
6442
|
+
for (const tracked of toFlush) {
|
|
6443
|
+
switch (tracked.status) {
|
|
6444
|
+
case "new" /* New */:
|
|
6445
|
+
await this.flushInsert(tracked);
|
|
6180
6446
|
break;
|
|
6181
|
-
case
|
|
6182
|
-
await this.
|
|
6447
|
+
case "dirty" /* Dirty */:
|
|
6448
|
+
await this.flushUpdate(tracked);
|
|
6183
6449
|
break;
|
|
6184
|
-
case
|
|
6185
|
-
await this.
|
|
6450
|
+
case "removed" /* Removed */:
|
|
6451
|
+
await this.flushDelete(tracked);
|
|
6186
6452
|
break;
|
|
6187
|
-
|
|
6188
|
-
await this.handleBelongsToChange(entry);
|
|
6453
|
+
default:
|
|
6189
6454
|
break;
|
|
6190
6455
|
}
|
|
6191
6456
|
}
|
|
6192
6457
|
}
|
|
6193
|
-
|
|
6194
|
-
|
|
6195
|
-
|
|
6196
|
-
if (!target) return;
|
|
6197
|
-
const tracked = this.unitOfWork.findTracked(target);
|
|
6198
|
-
if (!tracked) return;
|
|
6199
|
-
const localKey = relation.localKey || findPrimaryKey(entry.rootTable);
|
|
6200
|
-
const rootValue = entry.root[localKey];
|
|
6201
|
-
if (rootValue === void 0 || rootValue === null) return;
|
|
6202
|
-
if (entry.change.kind === "add" || entry.change.kind === "attach") {
|
|
6203
|
-
this.assignHasManyForeignKey(tracked.entity, relation, rootValue);
|
|
6204
|
-
this.unitOfWork.markDirty(tracked.entity);
|
|
6205
|
-
return;
|
|
6206
|
-
}
|
|
6207
|
-
if (entry.change.kind === "remove") {
|
|
6208
|
-
this.detachHasManyChild(tracked.entity, relation);
|
|
6209
|
-
}
|
|
6210
|
-
}
|
|
6211
|
-
async handleHasOneChange(entry) {
|
|
6212
|
-
const relation = entry.relation;
|
|
6213
|
-
const target = entry.change.entity;
|
|
6214
|
-
if (!target) return;
|
|
6215
|
-
const tracked = this.unitOfWork.findTracked(target);
|
|
6216
|
-
if (!tracked) return;
|
|
6217
|
-
const localKey = relation.localKey || findPrimaryKey(entry.rootTable);
|
|
6218
|
-
const rootValue = entry.root[localKey];
|
|
6219
|
-
if (rootValue === void 0 || rootValue === null) return;
|
|
6220
|
-
if (entry.change.kind === "attach" || entry.change.kind === "add") {
|
|
6221
|
-
this.assignHasOneForeignKey(tracked.entity, relation, rootValue);
|
|
6222
|
-
this.unitOfWork.markDirty(tracked.entity);
|
|
6223
|
-
return;
|
|
6224
|
-
}
|
|
6225
|
-
if (entry.change.kind === "remove") {
|
|
6226
|
-
this.detachHasOneChild(tracked.entity, relation);
|
|
6227
|
-
}
|
|
6228
|
-
}
|
|
6229
|
-
async handleBelongsToChange(_entry) {
|
|
6230
|
-
}
|
|
6231
|
-
async handleBelongsToManyChange(entry) {
|
|
6232
|
-
const relation = entry.relation;
|
|
6233
|
-
const rootKey = relation.localKey || findPrimaryKey(entry.rootTable);
|
|
6234
|
-
const rootId = entry.root[rootKey];
|
|
6235
|
-
if (rootId === void 0 || rootId === null) return;
|
|
6236
|
-
const targetId = this.resolvePrimaryKeyValue(entry.change.entity, relation.target);
|
|
6237
|
-
if (targetId === null) return;
|
|
6238
|
-
if (entry.change.kind === "attach" || entry.change.kind === "add") {
|
|
6239
|
-
await this.insertPivotRow(relation, rootId, targetId);
|
|
6240
|
-
return;
|
|
6241
|
-
}
|
|
6242
|
-
if (entry.change.kind === "detach" || entry.change.kind === "remove") {
|
|
6243
|
-
await this.deletePivotRow(relation, rootId, targetId);
|
|
6244
|
-
if (relation.cascade === "all" || relation.cascade === "remove") {
|
|
6245
|
-
this.unitOfWork.markRemoved(entry.change.entity);
|
|
6246
|
-
}
|
|
6247
|
-
}
|
|
6248
|
-
}
|
|
6249
|
-
assignHasManyForeignKey(child, relation, rootValue) {
|
|
6250
|
-
const current = child[relation.foreignKey];
|
|
6251
|
-
if (current === rootValue) return;
|
|
6252
|
-
child[relation.foreignKey] = rootValue;
|
|
6253
|
-
}
|
|
6254
|
-
detachHasManyChild(child, relation) {
|
|
6255
|
-
if (relation.cascade === "all" || relation.cascade === "remove") {
|
|
6256
|
-
this.unitOfWork.markRemoved(child);
|
|
6257
|
-
return;
|
|
6258
|
-
}
|
|
6259
|
-
child[relation.foreignKey] = null;
|
|
6260
|
-
this.unitOfWork.markDirty(child);
|
|
6261
|
-
}
|
|
6262
|
-
assignHasOneForeignKey(child, relation, rootValue) {
|
|
6263
|
-
const current = child[relation.foreignKey];
|
|
6264
|
-
if (current === rootValue) return;
|
|
6265
|
-
child[relation.foreignKey] = rootValue;
|
|
6266
|
-
}
|
|
6267
|
-
detachHasOneChild(child, relation) {
|
|
6268
|
-
if (relation.cascade === "all" || relation.cascade === "remove") {
|
|
6269
|
-
this.unitOfWork.markRemoved(child);
|
|
6270
|
-
return;
|
|
6271
|
-
}
|
|
6272
|
-
child[relation.foreignKey] = null;
|
|
6273
|
-
this.unitOfWork.markDirty(child);
|
|
6274
|
-
}
|
|
6275
|
-
async insertPivotRow(relation, rootId, targetId) {
|
|
6276
|
-
const payload = {
|
|
6277
|
-
[relation.pivotForeignKeyToRoot]: rootId,
|
|
6278
|
-
[relation.pivotForeignKeyToTarget]: targetId
|
|
6279
|
-
};
|
|
6280
|
-
const builder = new InsertQueryBuilder(relation.pivotTable).values(payload);
|
|
6281
|
-
const compiled = builder.compile(this.dialect);
|
|
6282
|
-
await this.executor.executeSql(compiled.sql, compiled.params);
|
|
6283
|
-
}
|
|
6284
|
-
async deletePivotRow(relation, rootId, targetId) {
|
|
6285
|
-
const rootCol = relation.pivotTable.columns[relation.pivotForeignKeyToRoot];
|
|
6286
|
-
const targetCol = relation.pivotTable.columns[relation.pivotForeignKeyToTarget];
|
|
6287
|
-
if (!rootCol || !targetCol) return;
|
|
6288
|
-
const builder = new DeleteQueryBuilder(relation.pivotTable).where(
|
|
6289
|
-
and(eq(rootCol, rootId), eq(targetCol, targetId))
|
|
6290
|
-
);
|
|
6291
|
-
const compiled = builder.compile(this.dialect);
|
|
6292
|
-
await this.executor.executeSql(compiled.sql, compiled.params);
|
|
6293
|
-
}
|
|
6294
|
-
resolvePrimaryKeyValue(entity, table) {
|
|
6295
|
-
if (!entity) return null;
|
|
6296
|
-
const key = findPrimaryKey(table);
|
|
6297
|
-
const value = entity[key];
|
|
6298
|
-
if (value === void 0 || value === null) return null;
|
|
6299
|
-
return value;
|
|
6300
|
-
}
|
|
6301
|
-
};
|
|
6302
|
-
|
|
6303
|
-
// src/orm/transaction-runner.ts
|
|
6304
|
-
var runInTransaction = async (executor, action) => {
|
|
6305
|
-
if (!executor.beginTransaction) {
|
|
6306
|
-
await action();
|
|
6307
|
-
return;
|
|
6308
|
-
}
|
|
6309
|
-
await executor.beginTransaction();
|
|
6310
|
-
try {
|
|
6311
|
-
await action();
|
|
6312
|
-
await executor.commitTransaction?.();
|
|
6313
|
-
} catch (error) {
|
|
6314
|
-
await executor.rollbackTransaction?.();
|
|
6315
|
-
throw error;
|
|
6316
|
-
}
|
|
6317
|
-
};
|
|
6318
|
-
|
|
6319
|
-
// src/orm/runtime-types.ts
|
|
6320
|
-
var EntityStatus = /* @__PURE__ */ ((EntityStatus2) => {
|
|
6321
|
-
EntityStatus2["New"] = "new";
|
|
6322
|
-
EntityStatus2["Managed"] = "managed";
|
|
6323
|
-
EntityStatus2["Dirty"] = "dirty";
|
|
6324
|
-
EntityStatus2["Removed"] = "removed";
|
|
6325
|
-
EntityStatus2["Detached"] = "detached";
|
|
6326
|
-
return EntityStatus2;
|
|
6327
|
-
})(EntityStatus || {});
|
|
6328
|
-
|
|
6329
|
-
// src/orm/unit-of-work.ts
|
|
6330
|
-
var UnitOfWork = class {
|
|
6331
|
-
constructor(dialect, executor, identityMap, hookContext) {
|
|
6332
|
-
this.dialect = dialect;
|
|
6333
|
-
this.executor = executor;
|
|
6334
|
-
this.identityMap = identityMap;
|
|
6335
|
-
this.hookContext = hookContext;
|
|
6336
|
-
this.trackedEntities = /* @__PURE__ */ new Map();
|
|
6337
|
-
}
|
|
6338
|
-
get identityBuckets() {
|
|
6339
|
-
return this.identityMap.bucketsMap;
|
|
6340
|
-
}
|
|
6341
|
-
getTracked() {
|
|
6342
|
-
return Array.from(this.trackedEntities.values());
|
|
6343
|
-
}
|
|
6344
|
-
getEntity(table, pk) {
|
|
6345
|
-
return this.identityMap.getEntity(table, pk);
|
|
6346
|
-
}
|
|
6347
|
-
getEntitiesForTable(table) {
|
|
6348
|
-
return this.identityMap.getEntitiesForTable(table);
|
|
6349
|
-
}
|
|
6350
|
-
findTracked(entity) {
|
|
6351
|
-
return this.trackedEntities.get(entity);
|
|
6352
|
-
}
|
|
6353
|
-
setEntity(table, pk, entity) {
|
|
6354
|
-
if (pk === null || pk === void 0) return;
|
|
6355
|
-
let tracked = this.trackedEntities.get(entity);
|
|
6356
|
-
if (!tracked) {
|
|
6357
|
-
tracked = {
|
|
6358
|
-
table,
|
|
6359
|
-
entity,
|
|
6360
|
-
pk,
|
|
6361
|
-
status: "managed" /* Managed */,
|
|
6362
|
-
original: this.createSnapshot(table, entity)
|
|
6363
|
-
};
|
|
6364
|
-
this.trackedEntities.set(entity, tracked);
|
|
6365
|
-
} else {
|
|
6366
|
-
tracked.pk = pk;
|
|
6367
|
-
}
|
|
6368
|
-
this.registerIdentity(tracked);
|
|
6369
|
-
}
|
|
6370
|
-
trackNew(table, entity, pk) {
|
|
6371
|
-
const tracked = {
|
|
6372
|
-
table,
|
|
6373
|
-
entity,
|
|
6374
|
-
pk: pk ?? null,
|
|
6375
|
-
status: "new" /* New */,
|
|
6376
|
-
original: null
|
|
6377
|
-
};
|
|
6378
|
-
this.trackedEntities.set(entity, tracked);
|
|
6379
|
-
if (pk != null) {
|
|
6380
|
-
this.registerIdentity(tracked);
|
|
6381
|
-
}
|
|
6382
|
-
}
|
|
6383
|
-
trackManaged(table, pk, entity) {
|
|
6384
|
-
const tracked = {
|
|
6385
|
-
table,
|
|
6386
|
-
entity,
|
|
6387
|
-
pk,
|
|
6388
|
-
status: "managed" /* Managed */,
|
|
6389
|
-
original: this.createSnapshot(table, entity)
|
|
6390
|
-
};
|
|
6391
|
-
this.trackedEntities.set(entity, tracked);
|
|
6392
|
-
this.registerIdentity(tracked);
|
|
6393
|
-
}
|
|
6394
|
-
markDirty(entity) {
|
|
6395
|
-
const tracked = this.trackedEntities.get(entity);
|
|
6396
|
-
if (!tracked) return;
|
|
6397
|
-
if (tracked.status === "new" /* New */ || tracked.status === "removed" /* Removed */) return;
|
|
6398
|
-
tracked.status = "dirty" /* Dirty */;
|
|
6399
|
-
}
|
|
6400
|
-
markRemoved(entity) {
|
|
6401
|
-
const tracked = this.trackedEntities.get(entity);
|
|
6402
|
-
if (!tracked) return;
|
|
6403
|
-
tracked.status = "removed" /* Removed */;
|
|
6404
|
-
}
|
|
6405
|
-
async flush() {
|
|
6406
|
-
const toFlush = Array.from(this.trackedEntities.values());
|
|
6407
|
-
for (const tracked of toFlush) {
|
|
6408
|
-
switch (tracked.status) {
|
|
6409
|
-
case "new" /* New */:
|
|
6410
|
-
await this.flushInsert(tracked);
|
|
6411
|
-
break;
|
|
6412
|
-
case "dirty" /* Dirty */:
|
|
6413
|
-
await this.flushUpdate(tracked);
|
|
6414
|
-
break;
|
|
6415
|
-
case "removed" /* Removed */:
|
|
6416
|
-
await this.flushDelete(tracked);
|
|
6417
|
-
break;
|
|
6418
|
-
default:
|
|
6419
|
-
break;
|
|
6420
|
-
}
|
|
6421
|
-
}
|
|
6458
|
+
reset() {
|
|
6459
|
+
this.trackedEntities.clear();
|
|
6460
|
+
this.identityMap.clear();
|
|
6422
6461
|
}
|
|
6423
6462
|
async flushInsert(tracked) {
|
|
6424
6463
|
await this.runHook(tracked.table.hooks?.beforeInsert, tracked);
|
|
@@ -6539,6 +6578,193 @@ var UnitOfWork = class {
|
|
|
6539
6578
|
}
|
|
6540
6579
|
};
|
|
6541
6580
|
|
|
6581
|
+
// src/orm/domain-event-bus.ts
|
|
6582
|
+
var DomainEventBus = class {
|
|
6583
|
+
constructor(initialHandlers) {
|
|
6584
|
+
this.handlers = /* @__PURE__ */ new Map();
|
|
6585
|
+
const handlers = initialHandlers ?? {};
|
|
6586
|
+
Object.entries(handlers).forEach(([name, list]) => {
|
|
6587
|
+
this.handlers.set(name, [...list]);
|
|
6588
|
+
});
|
|
6589
|
+
}
|
|
6590
|
+
register(name, handler) {
|
|
6591
|
+
const existing = this.handlers.get(name) ?? [];
|
|
6592
|
+
existing.push(handler);
|
|
6593
|
+
this.handlers.set(name, existing);
|
|
6594
|
+
}
|
|
6595
|
+
async dispatch(trackedEntities, ctx) {
|
|
6596
|
+
for (const tracked of trackedEntities) {
|
|
6597
|
+
const entity = tracked.entity;
|
|
6598
|
+
if (!entity.domainEvents || !entity.domainEvents.length) continue;
|
|
6599
|
+
for (const event of entity.domainEvents) {
|
|
6600
|
+
const eventName = this.getEventName(event);
|
|
6601
|
+
const handlers = this.handlers.get(eventName);
|
|
6602
|
+
if (!handlers) continue;
|
|
6603
|
+
for (const handler of handlers) {
|
|
6604
|
+
await handler(event, ctx);
|
|
6605
|
+
}
|
|
6606
|
+
}
|
|
6607
|
+
entity.domainEvents = [];
|
|
6608
|
+
}
|
|
6609
|
+
}
|
|
6610
|
+
getEventName(event) {
|
|
6611
|
+
if (!event) return "Unknown";
|
|
6612
|
+
if (typeof event === "string") return event;
|
|
6613
|
+
return event.constructor?.name ?? "Unknown";
|
|
6614
|
+
}
|
|
6615
|
+
};
|
|
6616
|
+
var addDomainEvent = (entity, event) => {
|
|
6617
|
+
if (!entity.domainEvents) {
|
|
6618
|
+
entity.domainEvents = [];
|
|
6619
|
+
}
|
|
6620
|
+
entity.domainEvents.push(event);
|
|
6621
|
+
};
|
|
6622
|
+
|
|
6623
|
+
// src/orm/relation-change-processor.ts
|
|
6624
|
+
var RelationChangeProcessor = class {
|
|
6625
|
+
constructor(unitOfWork, dialect, executor) {
|
|
6626
|
+
this.unitOfWork = unitOfWork;
|
|
6627
|
+
this.dialect = dialect;
|
|
6628
|
+
this.executor = executor;
|
|
6629
|
+
this.relationChanges = [];
|
|
6630
|
+
}
|
|
6631
|
+
registerChange(entry) {
|
|
6632
|
+
this.relationChanges.push(entry);
|
|
6633
|
+
}
|
|
6634
|
+
reset() {
|
|
6635
|
+
this.relationChanges.length = 0;
|
|
6636
|
+
}
|
|
6637
|
+
async process() {
|
|
6638
|
+
if (!this.relationChanges.length) return;
|
|
6639
|
+
const entries = [...this.relationChanges];
|
|
6640
|
+
this.relationChanges.length = 0;
|
|
6641
|
+
for (const entry of entries) {
|
|
6642
|
+
switch (entry.relation.type) {
|
|
6643
|
+
case RelationKinds.HasMany:
|
|
6644
|
+
await this.handleHasManyChange(entry);
|
|
6645
|
+
break;
|
|
6646
|
+
case RelationKinds.HasOne:
|
|
6647
|
+
await this.handleHasOneChange(entry);
|
|
6648
|
+
break;
|
|
6649
|
+
case RelationKinds.BelongsToMany:
|
|
6650
|
+
await this.handleBelongsToManyChange(entry);
|
|
6651
|
+
break;
|
|
6652
|
+
case RelationKinds.BelongsTo:
|
|
6653
|
+
await this.handleBelongsToChange(entry);
|
|
6654
|
+
break;
|
|
6655
|
+
}
|
|
6656
|
+
}
|
|
6657
|
+
}
|
|
6658
|
+
async handleHasManyChange(entry) {
|
|
6659
|
+
const relation = entry.relation;
|
|
6660
|
+
const target = entry.change.entity;
|
|
6661
|
+
if (!target) return;
|
|
6662
|
+
const tracked = this.unitOfWork.findTracked(target);
|
|
6663
|
+
if (!tracked) return;
|
|
6664
|
+
const localKey = relation.localKey || findPrimaryKey(entry.rootTable);
|
|
6665
|
+
const rootValue = entry.root[localKey];
|
|
6666
|
+
if (rootValue === void 0 || rootValue === null) return;
|
|
6667
|
+
if (entry.change.kind === "add" || entry.change.kind === "attach") {
|
|
6668
|
+
this.assignHasManyForeignKey(tracked.entity, relation, rootValue);
|
|
6669
|
+
this.unitOfWork.markDirty(tracked.entity);
|
|
6670
|
+
return;
|
|
6671
|
+
}
|
|
6672
|
+
if (entry.change.kind === "remove") {
|
|
6673
|
+
this.detachHasManyChild(tracked.entity, relation);
|
|
6674
|
+
}
|
|
6675
|
+
}
|
|
6676
|
+
async handleHasOneChange(entry) {
|
|
6677
|
+
const relation = entry.relation;
|
|
6678
|
+
const target = entry.change.entity;
|
|
6679
|
+
if (!target) return;
|
|
6680
|
+
const tracked = this.unitOfWork.findTracked(target);
|
|
6681
|
+
if (!tracked) return;
|
|
6682
|
+
const localKey = relation.localKey || findPrimaryKey(entry.rootTable);
|
|
6683
|
+
const rootValue = entry.root[localKey];
|
|
6684
|
+
if (rootValue === void 0 || rootValue === null) return;
|
|
6685
|
+
if (entry.change.kind === "attach" || entry.change.kind === "add") {
|
|
6686
|
+
this.assignHasOneForeignKey(tracked.entity, relation, rootValue);
|
|
6687
|
+
this.unitOfWork.markDirty(tracked.entity);
|
|
6688
|
+
return;
|
|
6689
|
+
}
|
|
6690
|
+
if (entry.change.kind === "remove") {
|
|
6691
|
+
this.detachHasOneChild(tracked.entity, relation);
|
|
6692
|
+
}
|
|
6693
|
+
}
|
|
6694
|
+
async handleBelongsToChange(_entry) {
|
|
6695
|
+
}
|
|
6696
|
+
async handleBelongsToManyChange(entry) {
|
|
6697
|
+
const relation = entry.relation;
|
|
6698
|
+
const rootKey = relation.localKey || findPrimaryKey(entry.rootTable);
|
|
6699
|
+
const rootId = entry.root[rootKey];
|
|
6700
|
+
if (rootId === void 0 || rootId === null) return;
|
|
6701
|
+
const targetId = this.resolvePrimaryKeyValue(entry.change.entity, relation.target);
|
|
6702
|
+
if (targetId === null) return;
|
|
6703
|
+
if (entry.change.kind === "attach" || entry.change.kind === "add") {
|
|
6704
|
+
await this.insertPivotRow(relation, rootId, targetId);
|
|
6705
|
+
return;
|
|
6706
|
+
}
|
|
6707
|
+
if (entry.change.kind === "detach" || entry.change.kind === "remove") {
|
|
6708
|
+
await this.deletePivotRow(relation, rootId, targetId);
|
|
6709
|
+
if (relation.cascade === "all" || relation.cascade === "remove") {
|
|
6710
|
+
this.unitOfWork.markRemoved(entry.change.entity);
|
|
6711
|
+
}
|
|
6712
|
+
}
|
|
6713
|
+
}
|
|
6714
|
+
assignHasManyForeignKey(child, relation, rootValue) {
|
|
6715
|
+
const current = child[relation.foreignKey];
|
|
6716
|
+
if (current === rootValue) return;
|
|
6717
|
+
child[relation.foreignKey] = rootValue;
|
|
6718
|
+
}
|
|
6719
|
+
detachHasManyChild(child, relation) {
|
|
6720
|
+
if (relation.cascade === "all" || relation.cascade === "remove") {
|
|
6721
|
+
this.unitOfWork.markRemoved(child);
|
|
6722
|
+
return;
|
|
6723
|
+
}
|
|
6724
|
+
child[relation.foreignKey] = null;
|
|
6725
|
+
this.unitOfWork.markDirty(child);
|
|
6726
|
+
}
|
|
6727
|
+
assignHasOneForeignKey(child, relation, rootValue) {
|
|
6728
|
+
const current = child[relation.foreignKey];
|
|
6729
|
+
if (current === rootValue) return;
|
|
6730
|
+
child[relation.foreignKey] = rootValue;
|
|
6731
|
+
}
|
|
6732
|
+
detachHasOneChild(child, relation) {
|
|
6733
|
+
if (relation.cascade === "all" || relation.cascade === "remove") {
|
|
6734
|
+
this.unitOfWork.markRemoved(child);
|
|
6735
|
+
return;
|
|
6736
|
+
}
|
|
6737
|
+
child[relation.foreignKey] = null;
|
|
6738
|
+
this.unitOfWork.markDirty(child);
|
|
6739
|
+
}
|
|
6740
|
+
async insertPivotRow(relation, rootId, targetId) {
|
|
6741
|
+
const payload = {
|
|
6742
|
+
[relation.pivotForeignKeyToRoot]: rootId,
|
|
6743
|
+
[relation.pivotForeignKeyToTarget]: targetId
|
|
6744
|
+
};
|
|
6745
|
+
const builder = new InsertQueryBuilder(relation.pivotTable).values(payload);
|
|
6746
|
+
const compiled = builder.compile(this.dialect);
|
|
6747
|
+
await this.executor.executeSql(compiled.sql, compiled.params);
|
|
6748
|
+
}
|
|
6749
|
+
async deletePivotRow(relation, rootId, targetId) {
|
|
6750
|
+
const rootCol = relation.pivotTable.columns[relation.pivotForeignKeyToRoot];
|
|
6751
|
+
const targetCol = relation.pivotTable.columns[relation.pivotForeignKeyToTarget];
|
|
6752
|
+
if (!rootCol || !targetCol) return;
|
|
6753
|
+
const builder = new DeleteQueryBuilder(relation.pivotTable).where(
|
|
6754
|
+
and(eq(rootCol, rootId), eq(targetCol, targetId))
|
|
6755
|
+
);
|
|
6756
|
+
const compiled = builder.compile(this.dialect);
|
|
6757
|
+
await this.executor.executeSql(compiled.sql, compiled.params);
|
|
6758
|
+
}
|
|
6759
|
+
resolvePrimaryKeyValue(entity, table) {
|
|
6760
|
+
if (!entity) return null;
|
|
6761
|
+
const key = findPrimaryKey(table);
|
|
6762
|
+
const value = entity[key];
|
|
6763
|
+
if (value === void 0 || value === null) return null;
|
|
6764
|
+
return value;
|
|
6765
|
+
}
|
|
6766
|
+
};
|
|
6767
|
+
|
|
6542
6768
|
// src/orm/query-logger.ts
|
|
6543
6769
|
var createQueryLoggingExecutor = (executor, logger) => {
|
|
6544
6770
|
if (!logger) {
|
|
@@ -6562,31 +6788,40 @@ var createQueryLoggingExecutor = (executor, logger) => {
|
|
|
6562
6788
|
return wrapped;
|
|
6563
6789
|
};
|
|
6564
6790
|
|
|
6565
|
-
// src/orm/
|
|
6566
|
-
var
|
|
6567
|
-
|
|
6568
|
-
|
|
6791
|
+
// src/orm/transaction-runner.ts
|
|
6792
|
+
var runInTransaction = async (executor, action) => {
|
|
6793
|
+
if (!executor.beginTransaction) {
|
|
6794
|
+
await action();
|
|
6795
|
+
return;
|
|
6796
|
+
}
|
|
6797
|
+
await executor.beginTransaction();
|
|
6798
|
+
try {
|
|
6799
|
+
await action();
|
|
6800
|
+
await executor.commitTransaction?.();
|
|
6801
|
+
} catch (error) {
|
|
6802
|
+
await executor.rollbackTransaction?.();
|
|
6803
|
+
throw error;
|
|
6804
|
+
}
|
|
6805
|
+
};
|
|
6806
|
+
|
|
6807
|
+
// src/orm/orm-session.ts
|
|
6808
|
+
var OrmSession = class {
|
|
6809
|
+
constructor(opts) {
|
|
6810
|
+
this.registerRelationChange = (root, relationKey, rootTable, relationName, relation, change) => {
|
|
6811
|
+
this.relationChanges.registerChange(
|
|
6812
|
+
buildRelationChangeEntry(root, relationKey, rootTable, relationName, relation, change)
|
|
6813
|
+
);
|
|
6814
|
+
};
|
|
6815
|
+
this.orm = opts.orm;
|
|
6816
|
+
this.executor = createQueryLoggingExecutor(opts.executor, opts.queryLogger);
|
|
6817
|
+
this.interceptors = [...opts.interceptors ?? []];
|
|
6569
6818
|
this.identityMap = new IdentityMap();
|
|
6570
|
-
this.
|
|
6571
|
-
this.
|
|
6572
|
-
this.
|
|
6573
|
-
options.dialect,
|
|
6574
|
-
this.executorWithLogging,
|
|
6575
|
-
this.identityMap,
|
|
6576
|
-
() => this
|
|
6577
|
-
);
|
|
6578
|
-
this.relationChanges = new RelationChangeProcessor(
|
|
6579
|
-
this.unitOfWork,
|
|
6580
|
-
options.dialect,
|
|
6581
|
-
this.executorWithLogging
|
|
6582
|
-
);
|
|
6583
|
-
this.domainEvents = new DomainEventBus(options.domainEventHandlers);
|
|
6819
|
+
this.unitOfWork = new UnitOfWork(this.orm.dialect, this.executor, this.identityMap, () => this);
|
|
6820
|
+
this.relationChanges = new RelationChangeProcessor(this.unitOfWork, this.orm.dialect, this.executor);
|
|
6821
|
+
this.domainEvents = new DomainEventBus(opts.domainEventHandlers);
|
|
6584
6822
|
}
|
|
6585
6823
|
get dialect() {
|
|
6586
|
-
return this.
|
|
6587
|
-
}
|
|
6588
|
-
get executor() {
|
|
6589
|
-
return this.executorWithLogging;
|
|
6824
|
+
return this.orm.dialect;
|
|
6590
6825
|
}
|
|
6591
6826
|
get identityBuckets() {
|
|
6592
6827
|
return this.unitOfWork.identityBuckets;
|
|
@@ -6612,16 +6847,8 @@ var OrmContext = class {
|
|
|
6612
6847
|
markRemoved(entity) {
|
|
6613
6848
|
this.unitOfWork.markRemoved(entity);
|
|
6614
6849
|
}
|
|
6615
|
-
|
|
6616
|
-
|
|
6617
|
-
root,
|
|
6618
|
-
relationKey,
|
|
6619
|
-
rootTable,
|
|
6620
|
-
relationName,
|
|
6621
|
-
relation,
|
|
6622
|
-
change
|
|
6623
|
-
};
|
|
6624
|
-
this.relationChanges.registerChange(entry);
|
|
6850
|
+
getEntitiesForTable(table) {
|
|
6851
|
+
return this.unitOfWork.getEntitiesForTable(table);
|
|
6625
6852
|
}
|
|
6626
6853
|
registerInterceptor(interceptor) {
|
|
6627
6854
|
this.interceptors.push(interceptor);
|
|
@@ -6629,7 +6856,51 @@ var OrmContext = class {
|
|
|
6629
6856
|
registerDomainEventHandler(name, handler) {
|
|
6630
6857
|
this.domainEvents.register(name, handler);
|
|
6631
6858
|
}
|
|
6632
|
-
async
|
|
6859
|
+
async find(entityClass, id) {
|
|
6860
|
+
const table = getTableDefFromEntity(entityClass);
|
|
6861
|
+
if (!table) {
|
|
6862
|
+
throw new Error("Entity metadata has not been bootstrapped");
|
|
6863
|
+
}
|
|
6864
|
+
const primaryKey = findPrimaryKey(table);
|
|
6865
|
+
const column = table.columns[primaryKey];
|
|
6866
|
+
if (!column) {
|
|
6867
|
+
throw new Error("Entity table does not expose a primary key");
|
|
6868
|
+
}
|
|
6869
|
+
const qb = selectFromEntity(entityClass).where(eq(column, id)).limit(1);
|
|
6870
|
+
const rows = await executeHydrated(this, qb);
|
|
6871
|
+
return rows[0] ?? null;
|
|
6872
|
+
}
|
|
6873
|
+
async findOne(qb) {
|
|
6874
|
+
const limited = qb.limit(1);
|
|
6875
|
+
const rows = await executeHydrated(this, limited);
|
|
6876
|
+
return rows[0] ?? null;
|
|
6877
|
+
}
|
|
6878
|
+
async findMany(qb) {
|
|
6879
|
+
return executeHydrated(this, qb);
|
|
6880
|
+
}
|
|
6881
|
+
async persist(entity) {
|
|
6882
|
+
if (this.unitOfWork.findTracked(entity)) {
|
|
6883
|
+
return;
|
|
6884
|
+
}
|
|
6885
|
+
const table = getTableDefFromEntity(entity.constructor);
|
|
6886
|
+
if (!table) {
|
|
6887
|
+
throw new Error("Entity metadata has not been bootstrapped");
|
|
6888
|
+
}
|
|
6889
|
+
const primaryKey = findPrimaryKey(table);
|
|
6890
|
+
const pkValue = entity[primaryKey];
|
|
6891
|
+
if (pkValue !== void 0 && pkValue !== null) {
|
|
6892
|
+
this.trackManaged(table, pkValue, entity);
|
|
6893
|
+
} else {
|
|
6894
|
+
this.trackNew(table, entity);
|
|
6895
|
+
}
|
|
6896
|
+
}
|
|
6897
|
+
async remove(entity) {
|
|
6898
|
+
this.markRemoved(entity);
|
|
6899
|
+
}
|
|
6900
|
+
async flush() {
|
|
6901
|
+
await this.unitOfWork.flush();
|
|
6902
|
+
}
|
|
6903
|
+
async commit() {
|
|
6633
6904
|
await runInTransaction(this.executor, async () => {
|
|
6634
6905
|
for (const interceptor of this.interceptors) {
|
|
6635
6906
|
await interceptor.beforeFlush?.(this);
|
|
@@ -6643,8 +6914,83 @@ var OrmContext = class {
|
|
|
6643
6914
|
});
|
|
6644
6915
|
await this.domainEvents.dispatch(this.unitOfWork.getTracked(), this);
|
|
6645
6916
|
}
|
|
6646
|
-
|
|
6647
|
-
|
|
6917
|
+
async rollback() {
|
|
6918
|
+
await this.executor.rollbackTransaction?.();
|
|
6919
|
+
this.unitOfWork.reset();
|
|
6920
|
+
this.relationChanges.reset();
|
|
6921
|
+
}
|
|
6922
|
+
getExecutionContext() {
|
|
6923
|
+
return {
|
|
6924
|
+
dialect: this.orm.dialect,
|
|
6925
|
+
executor: this.executor,
|
|
6926
|
+
interceptors: this.orm.interceptors
|
|
6927
|
+
};
|
|
6928
|
+
}
|
|
6929
|
+
getHydrationContext() {
|
|
6930
|
+
return {
|
|
6931
|
+
identityMap: this.identityMap,
|
|
6932
|
+
unitOfWork: this.unitOfWork,
|
|
6933
|
+
domainEvents: this.domainEvents,
|
|
6934
|
+
relationChanges: this.relationChanges,
|
|
6935
|
+
entityContext: this
|
|
6936
|
+
};
|
|
6937
|
+
}
|
|
6938
|
+
};
|
|
6939
|
+
var buildRelationChangeEntry = (root, relationKey, rootTable, relationName, relation, change) => ({
|
|
6940
|
+
root,
|
|
6941
|
+
relationKey,
|
|
6942
|
+
rootTable,
|
|
6943
|
+
relationName,
|
|
6944
|
+
relation,
|
|
6945
|
+
change
|
|
6946
|
+
});
|
|
6947
|
+
|
|
6948
|
+
// src/orm/interceptor-pipeline.ts
|
|
6949
|
+
var InterceptorPipeline = class {
|
|
6950
|
+
constructor() {
|
|
6951
|
+
this.interceptors = [];
|
|
6952
|
+
}
|
|
6953
|
+
use(interceptor) {
|
|
6954
|
+
this.interceptors.push(interceptor);
|
|
6955
|
+
}
|
|
6956
|
+
async run(ctx, executor) {
|
|
6957
|
+
let i = 0;
|
|
6958
|
+
const dispatch = async () => {
|
|
6959
|
+
const interceptor = this.interceptors[i++];
|
|
6960
|
+
if (!interceptor) {
|
|
6961
|
+
return executor.executeSql(ctx.sql, ctx.params);
|
|
6962
|
+
}
|
|
6963
|
+
return interceptor(ctx, dispatch);
|
|
6964
|
+
};
|
|
6965
|
+
return dispatch();
|
|
6966
|
+
}
|
|
6967
|
+
};
|
|
6968
|
+
|
|
6969
|
+
// src/orm/orm.ts
|
|
6970
|
+
var Orm = class {
|
|
6971
|
+
constructor(opts) {
|
|
6972
|
+
this.dialect = opts.dialect;
|
|
6973
|
+
this.interceptors = opts.interceptors ?? new InterceptorPipeline();
|
|
6974
|
+
this.namingStrategy = opts.namingStrategy ?? new DefaultNamingStrategy();
|
|
6975
|
+
this.executorFactory = opts.executorFactory;
|
|
6976
|
+
}
|
|
6977
|
+
createSession(options) {
|
|
6978
|
+
const executor = this.executorFactory.createExecutor(options?.tx);
|
|
6979
|
+
return new OrmSession({ orm: this, executor });
|
|
6980
|
+
}
|
|
6981
|
+
// Nice convenience:
|
|
6982
|
+
async transaction(fn4) {
|
|
6983
|
+
const executor = this.executorFactory.createTransactionalExecutor();
|
|
6984
|
+
const session = new OrmSession({ orm: this, executor });
|
|
6985
|
+
try {
|
|
6986
|
+
const result = await fn4(session);
|
|
6987
|
+
await session.commit();
|
|
6988
|
+
return result;
|
|
6989
|
+
} catch (err) {
|
|
6990
|
+
await session.rollback();
|
|
6991
|
+
throw err;
|
|
6992
|
+
} finally {
|
|
6993
|
+
}
|
|
6648
6994
|
}
|
|
6649
6995
|
};
|
|
6650
6996
|
|
|
@@ -6759,10 +7105,12 @@ export {
|
|
|
6759
7105
|
DefaultHasManyCollection,
|
|
6760
7106
|
DefaultManyToManyCollection,
|
|
6761
7107
|
DeleteQueryBuilder,
|
|
7108
|
+
DomainEventBus,
|
|
6762
7109
|
EntityStatus,
|
|
6763
7110
|
InsertQueryBuilder,
|
|
6764
7111
|
MySqlDialect,
|
|
6765
|
-
|
|
7112
|
+
Orm,
|
|
7113
|
+
OrmSession,
|
|
6766
7114
|
PostgresDialect,
|
|
6767
7115
|
RelationKinds,
|
|
6768
7116
|
SelectQueryBuilder,
|
|
@@ -6804,6 +7152,7 @@ export {
|
|
|
6804
7152
|
createMssqlExecutor,
|
|
6805
7153
|
createMysqlExecutor,
|
|
6806
7154
|
createPostgresExecutor,
|
|
7155
|
+
createQueryLoggingExecutor,
|
|
6807
7156
|
createSqliteExecutor,
|
|
6808
7157
|
currentDate,
|
|
6809
7158
|
currentTime,
|
|
@@ -6821,6 +7170,7 @@ export {
|
|
|
6821
7170
|
endOfMonth,
|
|
6822
7171
|
eq,
|
|
6823
7172
|
executeHydrated,
|
|
7173
|
+
executeHydratedWithContexts,
|
|
6824
7174
|
exists,
|
|
6825
7175
|
exp,
|
|
6826
7176
|
extract,
|