metal-orm 1.0.42 β†’ 1.0.44

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 (122) hide show
  1. package/README.md +195 -37
  2. package/dist/index.cjs +1014 -538
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.d.cts +1267 -371
  5. package/dist/index.d.ts +1267 -371
  6. package/dist/index.js +1012 -536
  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/adapters.ts +8 -2
  12. package/src/core/ast/builders.ts +105 -76
  13. package/src/core/ast/expression-builders.ts +430 -392
  14. package/src/core/ast/expression-nodes.ts +14 -5
  15. package/src/core/ast/expression-visitor.ts +56 -14
  16. package/src/core/ast/helpers.ts +23 -0
  17. package/src/core/ast/join-node.ts +18 -2
  18. package/src/core/ast/query.ts +6 -6
  19. package/src/core/ast/window-functions.ts +10 -2
  20. package/src/core/ddl/dialects/base-schema-dialect.ts +37 -4
  21. package/src/core/ddl/dialects/index.ts +1 -0
  22. package/src/core/ddl/dialects/mssql-schema-dialect.ts +5 -0
  23. package/src/core/ddl/dialects/mysql-schema-dialect.ts +3 -0
  24. package/src/core/ddl/dialects/postgres-schema-dialect.ts +14 -1
  25. package/src/core/ddl/dialects/render-reference.test.ts +69 -0
  26. package/src/core/ddl/dialects/sqlite-schema-dialect.ts +10 -0
  27. package/src/core/ddl/introspect/catalogs/index.ts +1 -0
  28. package/src/core/ddl/introspect/catalogs/postgres.ts +2 -0
  29. package/src/core/ddl/introspect/context.ts +6 -0
  30. package/src/core/ddl/introspect/functions/postgres.ts +13 -0
  31. package/src/core/ddl/introspect/mssql.ts +53 -8
  32. package/src/core/ddl/introspect/mysql.ts +32 -6
  33. package/src/core/ddl/introspect/postgres.ts +102 -34
  34. package/src/core/ddl/introspect/registry.ts +14 -0
  35. package/src/core/ddl/introspect/run-select.ts +19 -4
  36. package/src/core/ddl/introspect/sqlite.ts +78 -11
  37. package/src/core/ddl/introspect/types.ts +0 -1
  38. package/src/core/ddl/introspect/utils.ts +21 -3
  39. package/src/core/ddl/naming-strategy.ts +6 -0
  40. package/src/core/ddl/schema-dialect.ts +20 -6
  41. package/src/core/ddl/schema-diff.ts +22 -0
  42. package/src/core/ddl/schema-generator.ts +26 -12
  43. package/src/core/ddl/schema-plan-executor.ts +6 -0
  44. package/src/core/ddl/schema-types.ts +6 -0
  45. package/src/core/ddl/sql-writing.ts +4 -4
  46. package/src/core/dialect/abstract.ts +19 -7
  47. package/src/core/dialect/base/function-table-formatter.ts +3 -2
  48. package/src/core/dialect/base/join-compiler.ts +5 -3
  49. package/src/core/dialect/base/returning-strategy.ts +1 -0
  50. package/src/core/dialect/base/sql-dialect.ts +3 -3
  51. package/src/core/dialect/mssql/functions.ts +24 -25
  52. package/src/core/dialect/mssql/index.ts +1 -4
  53. package/src/core/dialect/mysql/functions.ts +0 -1
  54. package/src/core/dialect/postgres/functions.ts +33 -34
  55. package/src/core/dialect/postgres/index.ts +1 -0
  56. package/src/core/dialect/sqlite/functions.ts +18 -19
  57. package/src/core/dialect/sqlite/index.ts +2 -0
  58. package/src/core/execution/db-executor.ts +1 -1
  59. package/src/core/execution/executors/mysql-executor.ts +2 -2
  60. package/src/core/execution/executors/postgres-executor.ts +1 -1
  61. package/src/core/execution/pooling/pool.ts +12 -5
  62. package/src/core/functions/datetime.ts +58 -34
  63. package/src/core/functions/numeric.ts +96 -31
  64. package/src/core/functions/standard-strategy.ts +35 -0
  65. package/src/core/functions/text.ts +84 -23
  66. package/src/core/functions/types.ts +23 -8
  67. package/src/decorators/bootstrap.ts +42 -11
  68. package/src/decorators/column.ts +20 -11
  69. package/src/decorators/decorator-metadata.ts +30 -9
  70. package/src/decorators/entity.ts +29 -5
  71. package/src/decorators/index.ts +3 -0
  72. package/src/decorators/relations.ts +34 -11
  73. package/src/orm/als.ts +34 -9
  74. package/src/orm/entity-context.ts +62 -8
  75. package/src/orm/entity-meta.ts +8 -8
  76. package/src/orm/entity-metadata.ts +131 -16
  77. package/src/orm/entity.ts +28 -29
  78. package/src/orm/execute.ts +19 -4
  79. package/src/orm/hydration.ts +42 -39
  80. package/src/orm/identity-map.ts +1 -1
  81. package/src/orm/lazy-batch.ts +74 -104
  82. package/src/orm/orm-session.ts +24 -23
  83. package/src/orm/orm.ts +2 -5
  84. package/src/orm/relation-change-processor.ts +12 -11
  85. package/src/orm/relations/belongs-to.ts +11 -11
  86. package/src/orm/relations/has-many.ts +54 -10
  87. package/src/orm/relations/has-one.ts +8 -7
  88. package/src/orm/relations/many-to-many.ts +13 -13
  89. package/src/orm/runtime-types.ts +4 -4
  90. package/src/orm/save-graph.ts +31 -25
  91. package/src/orm/unit-of-work.ts +17 -17
  92. package/src/query/index.ts +74 -0
  93. package/src/query/target.ts +46 -0
  94. package/src/query-builder/delete-query-state.ts +30 -0
  95. package/src/query-builder/delete.ts +64 -18
  96. package/src/query-builder/hydration-manager.ts +52 -5
  97. package/src/query-builder/insert-query-state.ts +30 -0
  98. package/src/query-builder/insert.ts +58 -10
  99. package/src/query-builder/query-ast-service.ts +7 -2
  100. package/src/query-builder/query-resolution.ts +78 -0
  101. package/src/query-builder/raw-column-parser.ts +7 -1
  102. package/src/query-builder/relation-alias.ts +7 -0
  103. package/src/query-builder/relation-conditions.ts +61 -48
  104. package/src/query-builder/relation-service.ts +68 -63
  105. package/src/query-builder/relation-utils.ts +3 -0
  106. package/src/query-builder/select/cte-facet.ts +40 -0
  107. package/src/query-builder/select/from-facet.ts +80 -0
  108. package/src/query-builder/select/join-facet.ts +62 -0
  109. package/src/query-builder/select/predicate-facet.ts +103 -0
  110. package/src/query-builder/select/projection-facet.ts +69 -0
  111. package/src/query-builder/select/relation-facet.ts +81 -0
  112. package/src/query-builder/select/setop-facet.ts +36 -0
  113. package/src/query-builder/select-helpers.ts +15 -2
  114. package/src/query-builder/select-query-builder-deps.ts +19 -1
  115. package/src/query-builder/select-query-state.ts +2 -1
  116. package/src/query-builder/select.ts +795 -1163
  117. package/src/query-builder/update-query-state.ts +52 -0
  118. package/src/query-builder/update.ts +69 -18
  119. package/src/schema/column.ts +26 -26
  120. package/src/schema/table-guards.ts +31 -0
  121. package/src/schema/table.ts +47 -18
  122. package/src/schema/types.ts +22 -22
package/README.md CHANGED
@@ -1,19 +1,53 @@
1
- # MetalORM βš™οΈ - Type-safe SQL, layered ORM, decorator-based entities – all on the same core.
1
+ # MetalORM βš™οΈ
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/metal-orm.svg)](https://www.npmjs.com/package/metal-orm)
4
4
  [![license](https://img.shields.io/npm/l/metal-orm.svg)](https://github.com/celsowm/metal-orm/blob/main/LICENSE)
5
5
  [![TypeScript](https://img.shields.io/badge/%3C%2F%3E-TypeScript-%23007ACC.svg)](https://www.typescriptlang.org/)
6
6
 
7
- MetalORM is a TypeScript-first, AST-driven SQL toolkit you can dial up or down depending on how β€œORM-y” you want to be:
7
+ > **TypeScript-first ORM that adapts to your needs**: use it as a type-safe query builder, a full-featured ORM runtime, or anything in between.
8
8
 
9
- - **Level 1 – Query builder & hydration 🧩**
9
+ ## Why MetalORM? πŸ’‘
10
+
11
+ - 🎯 **Gradual adoption**: Start with just SQL building, add ORM features when you need them
12
+ - πŸ”’ **Exceptionally strongly typed**: Built with TypeScript generics and type inferenceβ€”**zero** `any` types in the entire codebase
13
+ - πŸ—οΈ **Well-architected**: Implements proven design patterns (Strategy, Visitor, Builder, Unit of Work, Identity Map, Interceptor, and more)
14
+ - 🎨 **One AST, multiple levels**: All features share the same SQL AST foundationβ€”no magic, just composable layers
15
+ - πŸš€ **Multi-dialect from the start**: MySQL, PostgreSQL, SQLite, SQL Server support built-in
16
+
17
+ ---
18
+
19
+ ## ⚑ 30-Second Quick Start
20
+
21
+ ```ts
22
+ import { defineTable, col, selectFrom, MySqlDialect } from 'metal-orm';
23
+
24
+ const users = defineTable('users', {
25
+ id: col.primaryKey(col.int()),
26
+ name: col.varchar(255),
27
+ });
28
+
29
+ const query = selectFrom(users).select('id', 'name').limit(10);
30
+ const { sql, params } = query.compile(new MySqlDialect());
31
+ // That's it! Use sql + params with any driver.
32
+ // ↑ Fully typedβ€”no casting, no 'any', just strong types all the way down
33
+ ```
34
+
35
+ ---
36
+
37
+ ## Three Levels of Abstraction
38
+
39
+ MetalORM is a TypeScript-first, AST-driven SQL toolkit you can dial up or down depending on how "ORM-y" you want to be:
40
+
41
+ - **Level 1 – Query builder & hydration 🧩**
10
42
  Define tables with `defineTable` / `col.*`, build strongly-typed queries on a real SQL AST, and hydrate flat result sets into nested objects – no ORM runtime involved.
11
- - **Level 2 – ORM runtime (entities + Unit of Work 🧠)**
43
+
44
+ - **Level 2 – ORM runtime (entities + Unit of Work 🧠)**
12
45
  Let `OrmSession` (created from `Orm`) turn rows into tracked entities with lazy relations, cascades, and a [Unit of Work](https://en.wikipedia.org/wiki/Unit_of_work) that flushes changes with `session.commit()`.
13
- - **Level 3 – Decorator entities (classes + metadata ✨)**
46
+
47
+ - **Level 3 – Decorator entities (classes + metadata ✨)**
14
48
  Use `@Entity`, `@Column`, `@PrimaryKey`, relation decorators, `bootstrapEntities()` (or the lazy bootstrapping in `getTableDefFromEntity` / `selectFromEntity`) to describe your model classes. MetalORM bootstraps schema & relations from metadata and plugs them into the same runtime and query builder.
15
49
 
16
- Use only the layer you need in each part of your codebase.
50
+ **Use only the layer you need in each part of your codebase.**
17
51
 
18
52
  ---
19
53
 
@@ -28,7 +62,10 @@ Use only the layer you need in each part of your codebase.
28
62
  - [Level 2 – Entities + Unit of Work](#level-2)
29
63
  - [Level 3 – Decorator entities](#level-3)
30
64
  - [When to use which level?](#when-to-use-which-level)
31
- - [Design notes](#design-notes)
65
+ - [Design & Architecture](#design-notes)
66
+ - [FAQ](#frequently-asked-questions-)
67
+ - [Performance & Production](#performance--production-)
68
+ - [Community & Support](#community--support-)
32
69
  - [Contributing](#contributing)
33
70
  - [License](#license)
34
71
 
@@ -173,7 +210,7 @@ import {
173
210
  defineTable,
174
211
  tableRef,
175
212
  col,
176
- SelectQueryBuilder,
213
+ selectFrom,
177
214
  eq,
178
215
  MySqlDialect,
179
216
  } from 'metal-orm';
@@ -192,8 +229,8 @@ todos.columns.done.default = false;
192
229
  const t = tableRef(todos);
193
230
 
194
231
  // 2) Build a simple query
195
- const listOpenTodos = new SelectQueryBuilder(todos)
196
- .selectColumns('id', 'title', 'done')
232
+ const listOpenTodos = selectFrom(todos)
233
+ .select('id', 'title', 'done')
197
234
  .where(eq(t.done, false))
198
235
  .orderBy(t.id, 'ASC');
199
236
 
@@ -221,8 +258,8 @@ That’s it: schema, query, SQL, done.
221
258
  ```ts
222
259
  const t = tableRef(todos);
223
260
 
224
- const listOpenTodos = new SelectQueryBuilder(todos)
225
- .selectColumns('id', 'title', 'done') // typed shorthand for the same fields
261
+ const listOpenTodos = selectFrom(todos)
262
+ .select('id', 'title', 'done') // typed shorthand for the same fields
226
263
  .where(eq(t.done, false))
227
264
  .orderBy(t.id, 'ASC');
228
265
  ```
@@ -234,19 +271,19 @@ const listOpenTodos = new SelectQueryBuilder(todos)
234
271
  If you still want the convenience of accessing columns without spelling `.columns`, you can opt-in with `tableRef()`:
235
272
 
236
273
  ```ts
237
- import { tableRef, eq } from 'metal-orm';
274
+ import { tableRef, eq, selectFrom } from 'metal-orm';
238
275
 
239
276
  // Existing style (always works)
240
- const listOpenTodos = new SelectQueryBuilder(todos)
241
- .selectColumns('id', 'title', 'done')
277
+ const listOpenTodos = selectFrom(todos)
278
+ .select('id', 'title', 'done')
242
279
  .where(eq(todos.columns.done, false))
243
280
  .orderBy(todos.columns.id, 'ASC');
244
281
 
245
282
  // Opt-in ergonomic style
246
283
  const t = tableRef(todos);
247
284
 
248
- const listOpenTodos2 = new SelectQueryBuilder(todos)
249
- .selectColumns('id', 'title', 'done')
285
+ const listOpenTodos2 = selectFrom(todos)
286
+ .select('id', 'title', 'done')
250
287
  .where(eq(t.done, false))
251
288
  .orderBy(t.id, 'ASC');
252
289
  ```
@@ -265,10 +302,11 @@ import {
265
302
  defineTable,
266
303
  col,
267
304
  hasMany,
268
- SelectQueryBuilder,
305
+ selectFrom,
269
306
  eq,
270
307
  count,
271
308
  rowNumber,
309
+ MySqlDialect,
272
310
  sel,
273
311
  hydrateRows,
274
312
  } from 'metal-orm';
@@ -298,18 +336,24 @@ users.columns.name.notNull = true;
298
336
  users.columns.email.unique = true;
299
337
 
300
338
  // Build a query with relation & window function
301
- const builder = new SelectQueryBuilder(users)
339
+ const u = sel(users, 'id', 'name', 'email');
340
+ const p = sel(posts, 'id', 'userId');
341
+
342
+ const builder = selectFrom(users)
302
343
  .select({
303
- ...sel(users, 'id', 'name', 'email'),
304
- postCount: count(posts.columns.id),
344
+ ...u,
345
+ postCount: count(p.id),
305
346
  rank: rowNumber(), // window function helper
306
347
  })
307
- .leftJoin(posts, eq(posts.columns.userId, users.columns.id))
308
- .groupBy(users.columns.id, users.columns.name, users.columns.email)
309
- .orderBy(count(posts.columns.id), 'DESC')
348
+ .leftJoin(posts, eq(p.userId, u.id))
349
+ .groupBy(u.id)
350
+ .groupBy(u.name)
351
+ .groupBy(u.email)
352
+ .orderBy(count(p.id), 'DESC')
310
353
  .limit(10)
311
354
  .includePick('posts', ['id', 'title', 'createdAt']); // eager relation for hydration
312
355
 
356
+ const dialect = new MySqlDialect();
313
357
  const { sql, params } = builder.compile(dialect);
314
358
  const [rows] = await connection.execute(sql, params);
315
359
 
@@ -351,8 +395,9 @@ import {
351
395
  Orm,
352
396
  OrmSession,
353
397
  MySqlDialect,
354
- SelectQueryBuilder,
398
+ selectFrom,
355
399
  eq,
400
+ tableRef,
356
401
  createMysqlExecutor,
357
402
  } from 'metal-orm';
358
403
 
@@ -365,16 +410,19 @@ const orm = new Orm({
365
410
  executorFactory: {
366
411
  createExecutor: () => executor,
367
412
  createTransactionalExecutor: () => executor,
413
+ dispose: async () => {},
368
414
  },
369
415
  });
370
416
  const session = new OrmSession({ orm, executor });
371
417
 
418
+ const u = tableRef(users);
419
+
372
420
  // 2) Load entities with lazy relations
373
- const [user] = await new SelectQueryBuilder(users)
374
- .selectColumns('id', 'name', 'email')
421
+ const [user] = await selectFrom(users)
422
+ .select('id', 'name', 'email')
375
423
  .includeLazy('posts') // HasMany as a lazy collection
376
424
  .includeLazy('roles') // BelongsToMany as a lazy collection
377
- .where(eq(users.columns.id, 1))
425
+ .where(eq(u.id, 1))
378
426
  .execute(session);
379
427
 
380
428
  // user is an EntityInstance<typeof users>
@@ -422,6 +470,8 @@ import {
422
470
  BelongsTo,
423
471
  bootstrapEntities,
424
472
  selectFromEntity,
473
+ entityRef,
474
+ eq,
425
475
  } from 'metal-orm';
426
476
 
427
477
  @Entity()
@@ -472,15 +522,17 @@ const orm = new Orm({
472
522
  executorFactory: {
473
523
  createExecutor: () => executor,
474
524
  createTransactionalExecutor: () => executor,
525
+ dispose: async () => {},
475
526
  },
476
527
  });
477
528
  const session = new OrmSession({ orm, executor });
478
529
 
479
530
  // 3) Query starting from the entity class
531
+ const U = entityRef(User);
480
532
  const [user] = await selectFromEntity(User)
481
533
  .selectColumns('id', 'name')
482
534
  .includeLazy('posts')
483
- .where(/* same eq()/and() API as before */)
535
+ .where(eq(U.id, 1))
484
536
  .execute(session);
485
537
 
486
538
  user.posts.add({ title: 'From decorators' });
@@ -513,17 +565,123 @@ All three levels share the same schema, AST, and dialects, so you can mix them a
513
565
  ---
514
566
 
515
567
  <a id="design-notes"></a>
516
- ## Design notes 🧱
568
+ ## Design & Architecture πŸ—οΈ
569
+
570
+ MetalORM is built on solid software engineering principles and proven design patterns.
571
+
572
+ ### Architecture Layers
517
573
 
518
- Under the hood, MetalORM leans on well-known patterns:
574
+ ```
575
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
576
+ β”‚ Your Application β”‚
577
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
578
+ β”‚
579
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
580
+ β”‚ β”‚ β”‚
581
+ β–Ό β–Ό β–Ό
582
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
583
+ β”‚ Level 1 β”‚ β”‚ Level 2 β”‚ β”‚ Level 3 β”‚
584
+ β”‚ Query │◄────── ORM │◄──────Decoratorsβ”‚
585
+ β”‚ Builder β”‚ β”‚ Runtime β”‚ β”‚ β”‚
586
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
587
+ β”‚ β”‚ β”‚
588
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
589
+ β–Ό
590
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
591
+ β”‚ SQL AST β”‚
592
+ β”‚ (Typed Nodes) β”‚
593
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
594
+ β–Ό
595
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
596
+ β”‚ Strategy Pattern: Dialects β”‚
597
+ β”‚ MySQL | PostgreSQL | SQLite | SQL Server β”‚
598
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
599
+ β–Ό
600
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
601
+ β”‚ Database β”‚
602
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
603
+ ```
604
+
605
+ ### Design Patterns
606
+
607
+ - **Strategy Pattern**: Pluggable dialects (MySQL, PostgreSQL, SQLite, SQL Server) and function renderers allow the same query to target different databases
608
+ - **Visitor Pattern**: AST traversal for SQL compilation and expression processing
609
+ - **Builder Pattern**: Fluent query builders (Select, Insert, Update, Delete) for constructing queries step-by-step
610
+ - **Factory Pattern**: Dialect factory and executor creation abstract instantiation logic
611
+ - **Unit of Work**: Change tracking and batch persistence in `OrmSession` coordinate all modifications
612
+ - **Identity Map**: One entity instance per row within a session prevents duplicate object issues
613
+ - **Interceptor/Pipeline**: Query interceptors and flush lifecycle hooks enable cross-cutting concerns
614
+ - **Adapter Pattern**: Connection pooling adapters allow different pool implementations
615
+
616
+ ### Type Safety
617
+
618
+ - **Zero `any` types**: The entire src codebase contains zero `any` typesβ€”every value is properly typed
619
+ - **100% typed public API**: Every public method, parameter, and return value is fully typed
620
+ - **Full type inference**: From schema definition through query building to result hydration
621
+ - **Compile-time safety**: Catch SQL errors at TypeScript compile time, not runtime
622
+ - **Generic-driven**: Leverages TypeScript generics extensively for type propagation
623
+
624
+ ### Separation of Concerns
625
+
626
+ Each layer has a clear, focused responsibility:
627
+
628
+ - **Core AST layer**: SQL representation independent of any specific dialect
629
+ - **Dialect layer**: Vendor-specific SQL compilation (MySQL, PostgreSQL, etc.)
630
+ - **Schema layer**: Table and column definitions with relations
631
+ - **Query builder layer**: Fluent API for building type-safe queries
632
+ - **Hydration layer**: Transforms flat result sets into nested object graphs
633
+ - **ORM runtime layer**: Entity management, change tracking, lazy relations, transactions
634
+
635
+ You can use just the layers you need and stay at the low level (AST + dialects) or adopt higher levels when beneficial.
636
+
637
+ ---
638
+
639
+ ## Frequently Asked Questions ❓
640
+
641
+ **Q: How does MetalORM differ from other ORMs?**
642
+ A: MetalORM's unique three-level architecture lets you choose your abstraction levelβ€”use just the query builder, add the ORM runtime when needed, or go full decorator-based entities. This gradual adoption path is uncommon in the TypeScript ecosystem. You're not locked into an all-or-nothing ORM approach.
643
+
644
+ **Q: Can I use this in production?**
645
+ A: Yes! MetalORM is designed for production use with robust patterns like Unit of Work, Identity Map, and connection pooling support. The type-safe query builder ensures SQL correctness at compile time.
646
+
647
+ **Q: Do I need to use all three levels?**
648
+ A: No! Use only what you need. Many projects stay at Level 1 (query builder) for its type-safe SQL building without any ORM overhead. Add runtime features (Level 2) or decorators (Level 3) only where they provide value.
649
+
650
+ **Q: What about migrations?**
651
+ A: MetalORM provides schema generation via DDL builders. See the [Schema Generation docs](./docs/schema-generation.md) for details on generating CREATE TABLE statements from your table definitions.
652
+
653
+ **Q: How type-safe is it really?**
654
+ A: Exceptionally. The entire codebase contains **zero** `any` typesβ€”every value is properly typed with TypeScript generics and inference. All public APIs are fully typed, and your queries, entities, and results get full TypeScript checking at compile time.
655
+
656
+ **Q: What design patterns are used?**
657
+ A: MetalORM implements several well-known patterns: Strategy (dialects & functions), Visitor (AST traversal), Builder (query construction), Factory (dialect & executor creation), Unit of Work (change tracking), Identity Map (entity caching), Interceptor (query hooks), and Adapter (pooling). This makes the codebase maintainable and extensible.
658
+
659
+ ---
660
+
661
+ ## Performance & Production πŸš€
662
+
663
+ - **Zero runtime overhead for Level 1** (query builder) - it's just SQL compilation and hydration
664
+ - **Efficient batching** for Level 2 lazy relations minimizes database round-trips
665
+ - **Identity Map** prevents duplicate entity instances and unnecessary queries
666
+ - **Connection pooling** supported via executor factory pattern (see [pooling docs](./docs/pooling.md))
667
+ - **Prepared statements** with parameterized queries protect against SQL injection
668
+
669
+ **Production checklist:**
670
+ - βœ… Use connection pooling for better resource management
671
+ - βœ… Enable query logging in development for debugging
672
+ - βœ… Set up proper error handling and retries
673
+ - βœ… Use transactions for multi-statement operations
674
+ - βœ… Monitor query performance with interceptors
675
+
676
+ ---
519
677
 
520
- - **AST + dialect abstraction**: SQL is modeled as typed AST nodes, compiled by dialects that you can extend.
521
- - **Separation of concerns**: schema, AST, SQL compilation, execution, and ORM runtime are separate layers.
522
- - **Executor abstraction**: built-in executor creators (`createMysqlExecutor`, `createPostgresExecutor`, etc.) provide a clean separation between database drivers and ORM operations.
523
- - **Unit of Work + Identity Map**: `OrmSession` coordinates changes and enforces one entity instance per row, following the [Unit of Work](https://en.wikipedia.org/wiki/Unit_of_work) and [Identity map](https://en.wikipedia.org/wiki/Identity_map_pattern) patterns.
524
- - **Domain events + interceptors**: decouple side-effects from persistence and let cross-cutting concerns hook into flush points, similar in spirit to domain events in [Domain-driven design](https://en.wikipedia.org/wiki/Domain-driven_design).
678
+ ## Community & Support πŸ’¬
525
679
 
526
- You can stay at the low level (just AST + dialects) or adopt the higher levels when it makes your code simpler.
680
+ - πŸ› **Issues:** [GitHub Issues](https://github.com/celsowm/metal-orm/issues)
681
+ - πŸ’‘ **Discussions:** [GitHub Discussions](https://github.com/celsowm/metal-orm/discussions)
682
+ - πŸ“– **Documentation:** [Full docs](./docs/index.md)
683
+ - πŸ—ΊοΈ **Roadmap:** [See what's planned](./ROADMAP.md)
684
+ - πŸ“¦ **Changelog:** [View releases](https://github.com/celsowm/metal-orm/releases)
527
685
 
528
686
  ---
529
687