metal-orm 1.0.41 → 1.0.43

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/README.md +74 -20
  2. package/dist/index.cjs +180 -74
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.d.cts +142 -96
  5. package/dist/index.d.ts +142 -96
  6. package/dist/index.js +177 -74
  7. package/dist/index.js.map +1 -1
  8. package/package.json +8 -2
  9. package/scripts/run-eslint.mjs +34 -0
  10. package/src/codegen/typescript.ts +32 -15
  11. package/src/core/ast/builders.ts +7 -2
  12. package/src/core/ast/expression-builders.ts +0 -2
  13. package/src/core/ast/expression-nodes.ts +14 -5
  14. package/src/core/ast/expression-visitor.ts +11 -8
  15. package/src/core/ast/expression.ts +2 -2
  16. package/src/core/ast/join-node.ts +1 -1
  17. package/src/core/ast/query.ts +6 -6
  18. package/src/core/ast/window-functions.ts +10 -2
  19. package/src/core/ddl/dialects/base-schema-dialect.ts +30 -3
  20. package/src/core/ddl/dialects/mssql-schema-dialect.ts +4 -0
  21. package/src/core/ddl/dialects/mysql-schema-dialect.ts +2 -0
  22. package/src/core/ddl/dialects/postgres-schema-dialect.ts +13 -1
  23. package/src/core/ddl/dialects/render-reference.test.ts +69 -0
  24. package/src/core/ddl/dialects/sqlite-schema-dialect.ts +9 -0
  25. package/src/core/ddl/introspect/mssql.ts +42 -8
  26. package/src/core/ddl/introspect/mysql.ts +30 -6
  27. package/src/core/ddl/introspect/postgres.ts +88 -34
  28. package/src/core/ddl/introspect/run-select.ts +6 -4
  29. package/src/core/ddl/introspect/sqlite.ts +56 -11
  30. package/src/core/ddl/introspect/types.ts +0 -1
  31. package/src/core/ddl/introspect/utils.ts +3 -3
  32. package/src/core/ddl/schema-dialect.ts +1 -0
  33. package/src/core/ddl/schema-generator.ts +4 -12
  34. package/src/core/ddl/sql-writing.ts +4 -4
  35. package/src/core/dialect/abstract.ts +18 -6
  36. package/src/core/dialect/base/function-table-formatter.ts +3 -2
  37. package/src/core/dialect/base/join-compiler.ts +5 -3
  38. package/src/core/dialect/base/returning-strategy.ts +1 -0
  39. package/src/core/dialect/base/sql-dialect.ts +3 -3
  40. package/src/core/dialect/mssql/functions.ts +24 -25
  41. package/src/core/dialect/mssql/index.ts +1 -4
  42. package/src/core/dialect/mysql/functions.ts +0 -1
  43. package/src/core/dialect/postgres/functions.ts +33 -34
  44. package/src/core/dialect/postgres/index.ts +1 -0
  45. package/src/core/dialect/sqlite/functions.ts +18 -19
  46. package/src/core/dialect/sqlite/index.ts +2 -0
  47. package/src/core/execution/db-executor.ts +1 -1
  48. package/src/core/execution/executors/mysql-executor.ts +2 -2
  49. package/src/core/execution/executors/postgres-executor.ts +1 -1
  50. package/src/core/execution/pooling/pool.ts +2 -0
  51. package/src/core/functions/datetime.ts +1 -1
  52. package/src/core/functions/numeric.ts +1 -1
  53. package/src/core/functions/text.ts +1 -1
  54. package/src/decorators/bootstrap.ts +27 -8
  55. package/src/decorators/column.ts +3 -11
  56. package/src/decorators/decorator-metadata.ts +3 -9
  57. package/src/decorators/entity.ts +21 -5
  58. package/src/decorators/relations.ts +2 -11
  59. package/src/orm/entity-context.ts +8 -8
  60. package/src/orm/entity-meta.ts +8 -8
  61. package/src/orm/entity-metadata.ts +11 -9
  62. package/src/orm/entity.ts +28 -29
  63. package/src/orm/execute.ts +4 -4
  64. package/src/orm/hydration.ts +42 -39
  65. package/src/orm/identity-map.ts +1 -1
  66. package/src/orm/lazy-batch.ts +9 -9
  67. package/src/orm/orm-session.ts +24 -23
  68. package/src/orm/orm.ts +2 -5
  69. package/src/orm/relation-change-processor.ts +12 -11
  70. package/src/orm/relations/belongs-to.ts +11 -11
  71. package/src/orm/relations/has-many.ts +10 -10
  72. package/src/orm/relations/has-one.ts +8 -7
  73. package/src/orm/relations/many-to-many.ts +13 -13
  74. package/src/orm/runtime-types.ts +4 -4
  75. package/src/orm/save-graph.ts +31 -25
  76. package/src/orm/unit-of-work.ts +17 -17
  77. package/src/query-builder/delete.ts +4 -3
  78. package/src/query-builder/hydration-manager.ts +6 -5
  79. package/src/query-builder/insert.ts +12 -8
  80. package/src/query-builder/query-ast-service.ts +2 -2
  81. package/src/query-builder/raw-column-parser.ts +2 -1
  82. package/src/query-builder/select-helpers.ts +2 -2
  83. package/src/query-builder/select.ts +31 -31
  84. package/src/query-builder/update.ts +4 -3
  85. package/src/schema/column.ts +26 -26
  86. package/src/schema/table.ts +239 -115
  87. package/src/schema/types.ts +22 -22
@@ -141,8 +141,8 @@ export class OrmSession<E extends DomainEvent = OrmDomainEvent> implements Entit
141
141
  * @param pk - The primary key value
142
142
  * @returns The entity or undefined if not found
143
143
  */
144
- getEntity(table: TableDef, pk: any): any | undefined {
145
- return this.unitOfWork.getEntity(table, pk);
144
+ getEntity(table: TableDef, pk: unknown): unknown | undefined {
145
+ return this.unitOfWork.getEntity(table, pk as string | number);
146
146
  }
147
147
 
148
148
  /**
@@ -151,8 +151,8 @@ export class OrmSession<E extends DomainEvent = OrmDomainEvent> implements Entit
151
151
  * @param pk - The primary key value
152
152
  * @param entity - The entity instance
153
153
  */
154
- setEntity(table: TableDef, pk: any, entity: any): void {
155
- this.unitOfWork.setEntity(table, pk, entity);
154
+ setEntity(table: TableDef, pk: unknown, entity: unknown): void {
155
+ this.unitOfWork.setEntity(table, pk as string | number, entity);
156
156
  }
157
157
 
158
158
  /**
@@ -161,8 +161,8 @@ export class OrmSession<E extends DomainEvent = OrmDomainEvent> implements Entit
161
161
  * @param entity - The entity instance
162
162
  * @param pk - Optional primary key value
163
163
  */
164
- trackNew(table: TableDef, entity: any, pk?: any): void {
165
- this.unitOfWork.trackNew(table, entity, pk);
164
+ trackNew(table: TableDef, entity: unknown, pk?: unknown): void {
165
+ this.unitOfWork.trackNew(table, entity, pk as string | number);
166
166
  }
167
167
 
168
168
  /**
@@ -171,15 +171,15 @@ export class OrmSession<E extends DomainEvent = OrmDomainEvent> implements Entit
171
171
  * @param pk - The primary key value
172
172
  * @param entity - The entity instance
173
173
  */
174
- trackManaged(table: TableDef, pk: any, entity: any): void {
175
- this.unitOfWork.trackManaged(table, pk, entity);
174
+ trackManaged(table: TableDef, pk: unknown, entity: unknown): void {
175
+ this.unitOfWork.trackManaged(table, pk as string | number, entity);
176
176
  }
177
177
 
178
178
  /**
179
179
  * Marks an entity as dirty (modified).
180
180
  * @param entity - The entity to mark as dirty
181
181
  */
182
- markDirty(entity: any): void {
182
+ markDirty(entity: unknown): void {
183
183
  this.unitOfWork.markDirty(entity);
184
184
  }
185
185
 
@@ -187,7 +187,7 @@ export class OrmSession<E extends DomainEvent = OrmDomainEvent> implements Entit
187
187
  * Marks an entity as removed.
188
188
  * @param entity - The entity to mark as removed
189
189
  */
190
- markRemoved(entity: any): void {
190
+ markRemoved(entity: unknown): void {
191
191
  this.unitOfWork.markRemoved(entity);
192
192
  }
193
193
 
@@ -201,12 +201,12 @@ export class OrmSession<E extends DomainEvent = OrmDomainEvent> implements Entit
201
201
  * @param change - The relation change
202
202
  */
203
203
  registerRelationChange = (
204
- root: any,
204
+ root: unknown,
205
205
  relationKey: RelationKey,
206
206
  rootTable: TableDef,
207
207
  relationName: string,
208
208
  relation: RelationDef,
209
- change: RelationChange<any>
209
+ change: RelationChange<unknown>
210
210
  ): void => {
211
211
  this.relationChanges.registerChange(
212
212
  buildRelationChangeEntry(root, relationKey, rootTable, relationName, relation, change)
@@ -250,9 +250,9 @@ export class OrmSession<E extends DomainEvent = OrmDomainEvent> implements Entit
250
250
  * @returns The entity instance or null if not found
251
251
  * @throws If entity metadata is not bootstrapped or table has no primary key
252
252
  */
253
- async find<TCtor extends EntityConstructor<any>>(
253
+ async find<TCtor extends EntityConstructor<object>>(
254
254
  entityClass: TCtor,
255
- id: any
255
+ id: unknown
256
256
  ): Promise<InstanceType<TCtor> | null> {
257
257
  const table = getTableDefFromEntity(entityClass);
258
258
  if (!table) {
@@ -269,7 +269,7 @@ export class OrmSession<E extends DomainEvent = OrmDomainEvent> implements Entit
269
269
  }, {});
270
270
  const qb = selectFromEntity(entityClass)
271
271
  .select(columnSelections)
272
- .where(eq(column, id))
272
+ .where(eq(column, id as string | number))
273
273
  .limit(1);
274
274
  const rows = await executeHydrated(this, qb);
275
275
  return (rows[0] ?? null) as InstanceType<TCtor> | null;
@@ -281,7 +281,7 @@ export class OrmSession<E extends DomainEvent = OrmDomainEvent> implements Entit
281
281
  * @param qb - The query builder
282
282
  * @returns The first entity instance or null if not found
283
283
  */
284
- async findOne<TTable extends TableDef>(qb: SelectQueryBuilder<any, TTable>): Promise<EntityInstance<TTable> | null> {
284
+ async findOne<TTable extends TableDef>(qb: SelectQueryBuilder<unknown, TTable>): Promise<EntityInstance<TTable> | null> {
285
285
  const limited = qb.limit(1);
286
286
  const rows = await executeHydrated(this, limited);
287
287
  return rows[0] ?? null;
@@ -293,7 +293,7 @@ export class OrmSession<E extends DomainEvent = OrmDomainEvent> implements Entit
293
293
  * @param qb - The query builder
294
294
  * @returns Array of entity instances
295
295
  */
296
- async findMany<TTable extends TableDef>(qb: SelectQueryBuilder<any, TTable>): Promise<EntityInstance<TTable>[]> {
296
+ async findMany<TTable extends TableDef>(qb: SelectQueryBuilder<unknown, TTable>): Promise<EntityInstance<TTable>[]> {
297
297
  return executeHydrated(this, qb);
298
298
  }
299
299
 
@@ -304,9 +304,9 @@ export class OrmSession<E extends DomainEvent = OrmDomainEvent> implements Entit
304
304
  * @param options - Graph save options
305
305
  * @returns The root entity instance
306
306
  */
307
- async saveGraph<TCtor extends EntityConstructor<any>>(
307
+ async saveGraph<TCtor extends EntityConstructor<object>>(
308
308
  entityClass: TCtor,
309
- payload: Record<string, any>,
309
+ payload: Record<string, unknown>,
310
310
  options?: SaveGraphOptions & { transactional?: boolean }
311
311
  ): Promise<InstanceType<TCtor>> {
312
312
  const { transactional = true, ...graphOptions } = options ?? {};
@@ -326,12 +326,13 @@ export class OrmSession<E extends DomainEvent = OrmDomainEvent> implements Entit
326
326
  if (this.unitOfWork.findTracked(entity)) {
327
327
  return;
328
328
  }
329
- const table = getTableDefFromEntity((entity as any).constructor as EntityConstructor<any>);
329
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
330
+ const table = getTableDefFromEntity((entity as { constructor: EntityConstructor }).constructor);
330
331
  if (!table) {
331
332
  throw new Error('Entity metadata has not been bootstrapped');
332
333
  }
333
334
  const primaryKey = findPrimaryKey(table);
334
- const pkValue = (entity as Record<string, any>)[primaryKey];
335
+ const pkValue = (entity as Record<string, unknown>)[primaryKey];
335
336
  if (pkValue !== undefined && pkValue !== null) {
336
337
  this.trackManaged(table, pkValue, entity);
337
338
  } else {
@@ -449,12 +450,12 @@ export class OrmSession<E extends DomainEvent = OrmDomainEvent> implements Entit
449
450
  }
450
451
 
451
452
  const buildRelationChangeEntry = (
452
- root: any,
453
+ root: unknown,
453
454
  relationKey: RelationKey,
454
455
  rootTable: TableDef,
455
456
  relationName: string,
456
457
  relation: RelationDef,
457
- change: RelationChange<any>
458
+ change: RelationChange<unknown>
458
459
  ): RelationChangeEntry => ({
459
460
  root,
460
461
  relationKey,
package/src/orm/orm.ts CHANGED
@@ -8,9 +8,8 @@ import { OrmSession } from './orm-session.js';
8
8
 
9
9
  /**
10
10
  * Options for creating an ORM instance.
11
- * @template E - The domain event type
12
11
  */
13
- export interface OrmOptions<E extends DomainEvent = OrmDomainEvent> {
12
+ export interface OrmOptions {
14
13
  /** The database dialect */
15
14
  dialect: Dialect;
16
15
  /** The database executor factory */
@@ -61,7 +60,7 @@ export class Orm<E extends DomainEvent = OrmDomainEvent> {
61
60
  * Creates a new ORM instance.
62
61
  * @param opts - ORM options
63
62
  */
64
- constructor(opts: OrmOptions<E>) {
63
+ constructor(opts: OrmOptions) {
65
64
  this.dialect = opts.dialect;
66
65
  this.interceptors = opts.interceptors ?? new InterceptorPipeline();
67
66
  this.namingStrategy = opts.namingStrategy ?? new DefaultNamingStrategy();
@@ -92,8 +91,6 @@ export class Orm<E extends DomainEvent = OrmDomainEvent> {
92
91
  try {
93
92
  // A real transaction scope: begin before running user code, commit/rollback after.
94
93
  return await session.transaction(() => fn(session));
95
- } catch (err) {
96
- throw err;
97
94
  } finally {
98
95
  await session.dispose();
99
96
  }
@@ -86,13 +86,13 @@ export class RelationChangeProcessor {
86
86
  if (rootValue === undefined || rootValue === null) return;
87
87
 
88
88
  if (entry.change.kind === 'add' || entry.change.kind === 'attach') {
89
- this.assignHasManyForeignKey(tracked.entity, relation, rootValue);
89
+ this.assignHasManyForeignKey(tracked.entity as Record<string, unknown>, relation, rootValue);
90
90
  this.unitOfWork.markDirty(tracked.entity);
91
91
  return;
92
92
  }
93
93
 
94
94
  if (entry.change.kind === 'remove') {
95
- this.detachHasManyChild(tracked.entity, relation);
95
+ this.detachHasManyChild(tracked.entity as Record<string, unknown>, relation);
96
96
  }
97
97
  }
98
98
 
@@ -113,13 +113,13 @@ export class RelationChangeProcessor {
113
113
  if (rootValue === undefined || rootValue === null) return;
114
114
 
115
115
  if (entry.change.kind === 'attach' || entry.change.kind === 'add') {
116
- this.assignHasOneForeignKey(tracked.entity, relation, rootValue);
116
+ this.assignHasOneForeignKey(tracked.entity as Record<string, unknown>, relation, rootValue);
117
117
  this.unitOfWork.markDirty(tracked.entity);
118
118
  return;
119
119
  }
120
120
 
121
121
  if (entry.change.kind === 'remove') {
122
- this.detachHasOneChild(tracked.entity, relation);
122
+ this.detachHasOneChild(tracked.entity as Record<string, unknown>, relation);
123
123
  }
124
124
  }
125
125
 
@@ -128,6 +128,7 @@ export class RelationChangeProcessor {
128
128
  * @param _entry - The relation change entry (reserved for future use)
129
129
  */
130
130
  private async handleBelongsToChange(_entry: RelationChangeEntry): Promise<void> {
131
+ void _entry;
131
132
  // Reserved for future cascade/persist behaviors for belongs-to relations.
132
133
  }
133
134
 
@@ -141,7 +142,7 @@ export class RelationChangeProcessor {
141
142
  const rootId = entry.root[rootKey];
142
143
  if (rootId === undefined || rootId === null) return;
143
144
 
144
- const targetId = this.resolvePrimaryKeyValue(entry.change.entity, relation.target);
145
+ const targetId = this.resolvePrimaryKeyValue(entry.change.entity as Record<string, unknown>, relation.target);
145
146
  if (targetId === null) return;
146
147
 
147
148
  if (entry.change.kind === 'attach' || entry.change.kind === 'add') {
@@ -164,7 +165,7 @@ export class RelationChangeProcessor {
164
165
  * @param relation - The has-many relation
165
166
  * @param rootValue - The root entity's primary key value
166
167
  */
167
- private assignHasManyForeignKey(child: any, relation: HasManyRelation, rootValue: unknown): void {
168
+ private assignHasManyForeignKey(child: Record<string, unknown>, relation: HasManyRelation, rootValue: unknown): void {
168
169
  const current = child[relation.foreignKey];
169
170
  if (current === rootValue) return;
170
171
  child[relation.foreignKey] = rootValue;
@@ -175,7 +176,7 @@ export class RelationChangeProcessor {
175
176
  * @param child - The child entity
176
177
  * @param relation - The has-many relation
177
178
  */
178
- private detachHasManyChild(child: any, relation: HasManyRelation): void {
179
+ private detachHasManyChild(child: Record<string, unknown>, relation: HasManyRelation): void {
179
180
  if (relation.cascade === 'all' || relation.cascade === 'remove') {
180
181
  this.unitOfWork.markRemoved(child);
181
182
  return;
@@ -190,7 +191,7 @@ export class RelationChangeProcessor {
190
191
  * @param relation - The has-one relation
191
192
  * @param rootValue - The root entity's primary key value
192
193
  */
193
- private assignHasOneForeignKey(child: any, relation: HasOneRelation, rootValue: unknown): void {
194
+ private assignHasOneForeignKey(child: Record<string, unknown>, relation: HasOneRelation, rootValue: unknown): void {
194
195
  const current = child[relation.foreignKey];
195
196
  if (current === rootValue) return;
196
197
  child[relation.foreignKey] = rootValue;
@@ -201,7 +202,7 @@ export class RelationChangeProcessor {
201
202
  * @param child - The child entity
202
203
  * @param relation - The has-one relation
203
204
  */
204
- private detachHasOneChild(child: any, relation: HasOneRelation): void {
205
+ private detachHasOneChild(child: Record<string, unknown>, relation: HasOneRelation): void {
205
206
  if (relation.cascade === 'all' || relation.cascade === 'remove') {
206
207
  this.unitOfWork.markRemoved(child);
207
208
  return;
@@ -250,11 +251,11 @@ export class RelationChangeProcessor {
250
251
  * @param table - The table definition
251
252
  * @returns The primary key value or null
252
253
  */
253
- private resolvePrimaryKeyValue(entity: any, table: TableDef): string | number | null {
254
+ private resolvePrimaryKeyValue(entity: Record<string, unknown>, table: TableDef): string | number | null {
254
255
  if (!entity) return null;
255
256
  const key = findPrimaryKey(table);
256
257
  const value = entity[key];
257
258
  if (value === undefined || value === null) return null;
258
- return value;
259
+ return (value as string | number | null | undefined) ?? null;
259
260
  }
260
261
  }
@@ -5,11 +5,11 @@ import { BelongsToRelation } from '../../schema/relation.js';
5
5
  import { TableDef } from '../../schema/table.js';
6
6
  import { EntityMeta, getHydrationRecord, hasEntityMeta } from '../entity-meta.js';
7
7
 
8
- type Rows = Record<string, any>;
8
+ type Rows = Record<string, unknown>;
9
9
 
10
10
  const toKey = (value: unknown): string => (value === null || value === undefined ? '' : String(value));
11
11
 
12
- const hideInternal = (obj: any, keys: string[]): void => {
12
+ const hideInternal = (obj: object, keys: string[]): void => {
13
13
  for (const key of keys) {
14
14
  Object.defineProperty(obj, key, {
15
15
  value: obj[key],
@@ -26,13 +26,13 @@ export class DefaultBelongsToReference<TParent> implements BelongsToReference<TP
26
26
 
27
27
  constructor(
28
28
  private readonly ctx: EntityContext,
29
- private readonly meta: EntityMeta<any>,
30
- private readonly root: any,
29
+ private readonly meta: EntityMeta<TableDef>,
30
+ private readonly root: unknown,
31
31
  private readonly relationName: string,
32
32
  private readonly relation: BelongsToRelation,
33
33
  private readonly rootTable: TableDef,
34
34
  private readonly loader: () => Promise<Map<string, Rows>>,
35
- private readonly createEntity: (row: Record<string, any>) => TParent,
35
+ private readonly createEntity: (row: Record<string, unknown>) => TParent,
36
36
  private readonly targetKey: string
37
37
  ) {
38
38
  hideInternal(this, ['ctx', 'meta', 'root', 'relationName', 'relation', 'rootTable', 'loader', 'createEntity', 'targetKey']);
@@ -42,7 +42,7 @@ export class DefaultBelongsToReference<TParent> implements BelongsToReference<TP
42
42
  async load(): Promise<TParent | null> {
43
43
  if (this.loaded) return this.current;
44
44
  const map = await this.loader();
45
- const fkValue = this.root[this.relation.foreignKey];
45
+ const fkValue = (this.root as Record<string, unknown>)[this.relation.foreignKey];
46
46
  if (fkValue === null || fkValue === undefined) {
47
47
  this.current = null;
48
48
  } else {
@@ -60,7 +60,7 @@ export class DefaultBelongsToReference<TParent> implements BelongsToReference<TP
60
60
  set(data: Partial<TParent> | TParent | null): TParent | null {
61
61
  if (data === null) {
62
62
  const previous = this.current;
63
- this.root[this.relation.foreignKey] = null;
63
+ (this.root as Record<string, unknown>)[this.relation.foreignKey] = null;
64
64
  this.current = null;
65
65
  this.ctx.registerRelationChange(
66
66
  this.root,
@@ -73,10 +73,10 @@ export class DefaultBelongsToReference<TParent> implements BelongsToReference<TP
73
73
  return null;
74
74
  }
75
75
 
76
- const entity = hasEntityMeta(data) ? (data as TParent) : this.createEntity(data as Record<string, any>);
77
- const pkValue = (entity as any)[this.targetKey];
76
+ const entity = hasEntityMeta(data) ? (data as TParent) : this.createEntity(data as Record<string, unknown>);
77
+ const pkValue = (entity as Record<string, unknown>)[this.targetKey];
78
78
  if (pkValue !== undefined) {
79
- this.root[this.relation.foreignKey] = pkValue;
79
+ (this.root as Record<string, unknown>)[this.relation.foreignKey] = pkValue;
80
80
  }
81
81
  this.current = entity;
82
82
  this.ctx.registerRelationChange(
@@ -95,7 +95,7 @@ export class DefaultBelongsToReference<TParent> implements BelongsToReference<TP
95
95
  }
96
96
 
97
97
  private populateFromHydrationCache(): void {
98
- const fkValue = this.root[this.relation.foreignKey];
98
+ const fkValue = (this.root as Record<string, unknown>)[this.relation.foreignKey];
99
99
  if (fkValue === undefined || fkValue === null) return;
100
100
  const row = getHydrationRecord(this.meta, this.relationName, fkValue);
101
101
  if (!row) return;
@@ -5,11 +5,11 @@ import { HasManyRelation } from '../../schema/relation.js';
5
5
  import { TableDef } from '../../schema/table.js';
6
6
  import { EntityMeta, getHydrationRows } from '../entity-meta.js';
7
7
 
8
- type Rows = Record<string, any>[];
8
+ type Rows = Record<string, unknown>[];
9
9
 
10
10
  const toKey = (value: unknown): string => (value === null || value === undefined ? '' : String(value));
11
11
 
12
- const hideInternal = (obj: any, keys: string[]): void => {
12
+ const hideInternal = (obj: object, keys: string[]): void => {
13
13
  for (const key of keys) {
14
14
  Object.defineProperty(obj, key, {
15
15
  value: obj[key],
@@ -28,13 +28,13 @@ export class DefaultHasManyCollection<TChild> implements HasManyCollection<TChil
28
28
 
29
29
  constructor(
30
30
  private readonly ctx: EntityContext,
31
- private readonly meta: EntityMeta<any>,
32
- private readonly root: any,
31
+ private readonly meta: EntityMeta<TableDef>,
32
+ private readonly root: unknown,
33
33
  private readonly relationName: string,
34
34
  private readonly relation: HasManyRelation,
35
35
  private readonly rootTable: TableDef,
36
36
  private readonly loader: () => Promise<Map<string, Rows>>,
37
- private readonly createEntity: (row: Record<string, any>) => TChild,
37
+ private readonly createEntity: (row: Record<string, unknown>) => TChild,
38
38
  private readonly localKey: string
39
39
  ) {
40
40
  hideInternal(this, ['ctx', 'meta', 'root', 'relationName', 'relation', 'rootTable', 'loader', 'createEntity', 'localKey']);
@@ -44,7 +44,7 @@ export class DefaultHasManyCollection<TChild> implements HasManyCollection<TChil
44
44
  async load(): Promise<TChild[]> {
45
45
  if (this.loaded) return this.items;
46
46
  const map = await this.loader();
47
- const key = toKey(this.root[this.localKey]);
47
+ const key = toKey((this.root as Record<string, unknown>)[this.localKey]);
48
48
  const rows = map.get(key) ?? [];
49
49
  this.items = rows.map(row => this.createEntity(row));
50
50
  this.loaded = true;
@@ -56,8 +56,8 @@ export class DefaultHasManyCollection<TChild> implements HasManyCollection<TChil
56
56
  }
57
57
 
58
58
  add(data: Partial<TChild>): TChild {
59
- const keyValue = this.root[this.localKey];
60
- const childRow: Record<string, any> = {
59
+ const keyValue = (this.root as Record<string, unknown>)[this.localKey];
60
+ const childRow: Record<string, unknown> = {
61
61
  ...data,
62
62
  [this.relation.foreignKey]: keyValue
63
63
  };
@@ -77,7 +77,7 @@ export class DefaultHasManyCollection<TChild> implements HasManyCollection<TChil
77
77
 
78
78
  attach(entity: TChild): void {
79
79
  const keyValue = this.root[this.localKey];
80
- (entity as Record<string, any>)[this.relation.foreignKey] = keyValue;
80
+ (entity as Record<string, unknown>)[this.relation.foreignKey] = keyValue;
81
81
  this.ctx.markDirty(entity);
82
82
  this.items.push(entity);
83
83
  this.ctx.registerRelationChange(
@@ -114,7 +114,7 @@ export class DefaultHasManyCollection<TChild> implements HasManyCollection<TChil
114
114
  }
115
115
 
116
116
  private hydrateFromCache(): void {
117
- const keyValue = this.root[this.localKey];
117
+ const keyValue = (this.root as Record<string, unknown>)[this.localKey];
118
118
  if (keyValue === undefined || keyValue === null) return;
119
119
  const rows = getHydrationRows(this.meta, this.relationName, keyValue);
120
120
  if (!rows?.length) return;
@@ -5,11 +5,11 @@ import { HasOneRelation } from '../../schema/relation.js';
5
5
  import { TableDef } from '../../schema/table.js';
6
6
  import { EntityMeta, getHydrationRecord, hasEntityMeta } from '../entity-meta.js';
7
7
 
8
- type Row = Record<string, any>;
8
+ type Row = Record<string, unknown>;
9
9
 
10
10
  const toKey = (value: unknown): string => (value === null || value === undefined ? '' : String(value));
11
11
 
12
- const hideInternal = (obj: any, keys: string[]): void => {
12
+ const hideInternal = (obj: object, keys: string[]): void => {
13
13
  for (const key of keys) {
14
14
  Object.defineProperty(obj, key, {
15
15
  value: obj[key],
@@ -26,8 +26,8 @@ export class DefaultHasOneReference<TChild> implements HasOneReference<TChild> {
26
26
 
27
27
  constructor(
28
28
  private readonly ctx: EntityContext,
29
- private readonly meta: EntityMeta<any>,
30
- private readonly root: any,
29
+ private readonly meta: EntityMeta<TableDef>,
30
+ private readonly root: unknown,
31
31
  private readonly relationName: string,
32
32
  private readonly relation: HasOneRelation,
33
33
  private readonly rootTable: TableDef,
@@ -52,7 +52,7 @@ export class DefaultHasOneReference<TChild> implements HasOneReference<TChild> {
52
52
  async load(): Promise<TChild | null> {
53
53
  if (this.loaded) return this.current;
54
54
  const map = await this.loader();
55
- const keyValue = this.root[this.localKey];
55
+ const keyValue = (this.root as Record<string, unknown>)[this.localKey];
56
56
  if (keyValue === undefined || keyValue === null) {
57
57
  this.loaded = true;
58
58
  return this.current;
@@ -121,7 +121,8 @@ export class DefaultHasOneReference<TChild> implements HasOneReference<TChild> {
121
121
  }
122
122
 
123
123
  private assignForeignKey(entity: TChild): void {
124
- const keyValue = this.root[this.localKey];
124
+ const keyValue = (this.root as Record<string, unknown>)[this.localKey];
125
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
125
126
  (entity as Row)[this.relation.foreignKey] = keyValue;
126
127
  }
127
128
 
@@ -130,7 +131,7 @@ export class DefaultHasOneReference<TChild> implements HasOneReference<TChild> {
130
131
  }
131
132
 
132
133
  private populateFromHydrationCache(): void {
133
- const keyValue = this.root[this.localKey];
134
+ const keyValue = (this.root as Record<string, unknown>)[this.localKey];
134
135
  if (keyValue === undefined || keyValue === null) return;
135
136
  const row = getHydrationRecord(this.meta, this.relationName, keyValue);
136
137
  if (!row) return;
@@ -6,11 +6,11 @@ import { TableDef } from '../../schema/table.js';
6
6
  import { findPrimaryKey } from '../../query-builder/hydration-planner.js';
7
7
  import { EntityMeta, getHydrationRows } from '../entity-meta.js';
8
8
 
9
- type Rows = Record<string, any>[];
9
+ type Rows = Record<string, unknown>[];
10
10
 
11
11
  const toKey = (value: unknown): string => (value === null || value === undefined ? '' : String(value));
12
12
 
13
- const hideInternal = (obj: any, keys: string[]): void => {
13
+ const hideInternal = (obj: object, keys: string[]): void => {
14
14
  for (const key of keys) {
15
15
  Object.defineProperty(obj, key, {
16
16
  value: obj[key],
@@ -27,13 +27,13 @@ export class DefaultManyToManyCollection<TTarget> implements ManyToManyCollectio
27
27
 
28
28
  constructor(
29
29
  private readonly ctx: EntityContext,
30
- private readonly meta: EntityMeta<any>,
31
- private readonly root: any,
30
+ private readonly meta: EntityMeta<TableDef>,
31
+ private readonly root: unknown,
32
32
  private readonly relationName: string,
33
33
  private readonly relation: BelongsToManyRelation,
34
34
  private readonly rootTable: TableDef,
35
35
  private readonly loader: () => Promise<Map<string, Rows>>,
36
- private readonly createEntity: (row: Record<string, any>) => TTarget,
36
+ private readonly createEntity: (row: Record<string, unknown>) => TTarget,
37
37
  private readonly localKey: string
38
38
  ) {
39
39
  hideInternal(this, ['ctx', 'meta', 'root', 'relationName', 'relation', 'rootTable', 'loader', 'createEntity', 'localKey']);
@@ -47,8 +47,8 @@ export class DefaultManyToManyCollection<TTarget> implements ManyToManyCollectio
47
47
  const rows = map.get(key) ?? [];
48
48
  this.items = rows.map(row => {
49
49
  const entity = this.createEntity(row);
50
- if ((row as any)._pivot) {
51
- (entity as any)._pivot = row._pivot;
50
+ if ((row as { _pivot?: unknown })._pivot) {
51
+ (entity as { _pivot?: unknown })._pivot = (row as { _pivot?: unknown })._pivot;
52
52
  }
53
53
  return entity;
54
54
  });
@@ -103,7 +103,6 @@ export class DefaultManyToManyCollection<TTarget> implements ManyToManyCollectio
103
103
 
104
104
  async syncByIds(ids: (number | string)[]): Promise<void> {
105
105
  await this.load();
106
- const targetKey = this.relation.targetKey || findPrimaryKey(this.relation.target);
107
106
  const normalized = new Set(ids.map(id => toKey(id)));
108
107
  const currentIds = new Set(this.items.map(item => toKey(this.extractId(item))));
109
108
 
@@ -123,7 +122,7 @@ export class DefaultManyToManyCollection<TTarget> implements ManyToManyCollectio
123
122
 
124
123
  private ensureEntity(target: TTarget | number | string): TTarget {
125
124
  if (typeof target === 'number' || typeof target === 'string') {
126
- const stub: Record<string, any> = {
125
+ const stub: Record<string, unknown> = {
127
126
  [this.targetKey]: target
128
127
  };
129
128
  return this.createEntity(stub);
@@ -136,7 +135,7 @@ export class DefaultManyToManyCollection<TTarget> implements ManyToManyCollectio
136
135
  if (typeof entity === 'number' || typeof entity === 'string') {
137
136
  return entity;
138
137
  }
139
- return (entity as any)[this.targetKey] ?? null;
138
+ return (entity as Record<string, unknown>)[this.targetKey] as string | number | null ?? null;
140
139
  }
141
140
 
142
141
  private get relationKey(): RelationKey {
@@ -148,14 +147,15 @@ export class DefaultManyToManyCollection<TTarget> implements ManyToManyCollectio
148
147
  }
149
148
 
150
149
  private hydrateFromCache(): void {
151
- const keyValue = this.root[this.localKey];
150
+ const keyValue = (this.root as Record<string, unknown>)[this.localKey];
152
151
  if (keyValue === undefined || keyValue === null) return;
153
152
  const rows = getHydrationRows(this.meta, this.relationName, keyValue);
154
153
  if (!rows?.length) return;
155
154
  this.items = rows.map(row => {
156
155
  const entity = this.createEntity(row);
157
- if ((row as any)._pivot) {
158
- (entity as any)._pivot = (row as any)._pivot;
156
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
157
+ if ((row as { _pivot?: unknown })._pivot) {
158
+ (entity as { _pivot?: unknown })._pivot = (row as { _pivot?: unknown })._pivot;
159
159
  }
160
160
  return entity;
161
161
  });
@@ -24,13 +24,13 @@ export interface TrackedEntity {
24
24
  /** The table definition this entity belongs to */
25
25
  table: TableDef;
26
26
  /** The actual entity instance */
27
- entity: any;
27
+ entity: unknown;
28
28
  /** Primary key value of the entity */
29
29
  pk: string | number | null;
30
30
  /** Current status of the entity */
31
31
  status: EntityStatus;
32
32
  /** Original values of the entity when it was loaded */
33
- original: Record<string, any> | null;
33
+ original: Record<string, unknown> | null;
34
34
  }
35
35
 
36
36
  /**
@@ -53,7 +53,7 @@ export type RelationChange<T> =
53
53
  */
54
54
  export interface RelationChangeEntry {
55
55
  /** Root entity that owns the relation */
56
- root: any;
56
+ root: unknown;
57
57
  /** Key of the relation being changed */
58
58
  relationKey: RelationKey;
59
59
  /** Table definition of the root entity */
@@ -63,7 +63,7 @@ export interface RelationChangeEntry {
63
63
  /** Relation definition */
64
64
  relation: RelationDef;
65
65
  /** The change being applied */
66
- change: RelationChange<any>;
66
+ change: RelationChange<unknown>;
67
67
  }
68
68
 
69
69
  /**