metal-orm 1.0.7 → 1.0.9

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 (153) hide show
  1. package/README.md +133 -121
  2. package/dist/decorators/index.cjs +2564 -0
  3. package/dist/decorators/index.cjs.map +1 -0
  4. package/dist/decorators/index.d.cts +53 -0
  5. package/dist/decorators/index.d.ts +53 -0
  6. package/dist/decorators/index.js +2530 -0
  7. package/dist/decorators/index.js.map +1 -0
  8. package/dist/index.cjs +4227 -0
  9. package/dist/index.cjs.map +1 -0
  10. package/dist/index.d.cts +701 -0
  11. package/dist/index.d.ts +701 -0
  12. package/dist/index.js +4131 -0
  13. package/dist/index.js.map +1 -0
  14. package/dist/select-654m4qy8.d.cts +1522 -0
  15. package/dist/select-654m4qy8.d.ts +1522 -0
  16. package/package.json +27 -20
  17. package/src/codegen/typescript.ts +405 -393
  18. package/src/core/ast/aggregate-functions.ts +30 -0
  19. package/src/core/ast/builders.ts +43 -0
  20. package/src/core/ast/expression-builders.ts +310 -0
  21. package/src/core/ast/expression-nodes.ts +211 -0
  22. package/src/core/ast/expression-visitor.ts +99 -0
  23. package/src/core/ast/expression.ts +5 -0
  24. package/src/{utils → core/ast}/join-node.ts +20 -20
  25. package/src/{ast → core/ast}/join.ts +18 -18
  26. package/src/{ast → core/ast}/query.ts +113 -113
  27. package/src/core/ast/window-functions.ts +140 -0
  28. package/src/{dialect → core/dialect}/abstract.ts +94 -94
  29. package/src/{dialect → core/dialect}/mssql/index.ts +31 -31
  30. package/src/{dialect → core/dialect}/mysql/index.ts +31 -31
  31. package/src/{dialect → core/dialect}/postgres/index.ts +45 -45
  32. package/src/{dialect → core/dialect}/sqlite/index.ts +45 -45
  33. package/src/{constants → core/sql}/sql-operator-config.ts +39 -39
  34. package/src/decorators/bootstrap.ts +126 -0
  35. package/src/decorators/column.ts +78 -0
  36. package/src/decorators/entity.ts +36 -0
  37. package/src/decorators/index.ts +4 -0
  38. package/src/decorators/relations.ts +107 -0
  39. package/src/global.d.ts +1 -0
  40. package/src/index.ts +22 -22
  41. package/src/orm/db-executor.ts +11 -0
  42. package/src/orm/domain-event-bus.ts +52 -0
  43. package/src/{runtime → orm}/entity-meta.ts +52 -52
  44. package/src/orm/entity-metadata.ts +140 -0
  45. package/src/{runtime → orm}/entity.ts +252 -252
  46. package/src/{runtime → orm}/execute.ts +36 -36
  47. package/src/{runtime → orm}/hydration.ts +103 -103
  48. package/src/orm/identity-map.ts +37 -0
  49. package/src/{runtime → orm}/lazy-batch.ts +205 -205
  50. package/src/orm/orm-context.ts +154 -0
  51. package/src/orm/relation-change-processor.ts +140 -0
  52. package/src/{runtime → orm}/relations/belongs-to.ts +92 -92
  53. package/src/{runtime → orm}/relations/has-many.ts +111 -111
  54. package/src/{runtime → orm}/relations/many-to-many.ts +149 -149
  55. package/src/orm/runtime-types.ts +39 -0
  56. package/src/orm/transaction-runner.ts +17 -0
  57. package/src/orm/unit-of-work.ts +232 -0
  58. package/src/{builder/operations → query-builder}/column-selector.ts +78 -78
  59. package/src/{builder → query-builder}/delete-query-state.ts +38 -42
  60. package/src/{builder → query-builder}/delete.ts +46 -57
  61. package/src/{builder → query-builder}/hydration-manager.ts +87 -87
  62. package/src/{builder → query-builder}/hydration-planner.ts +182 -182
  63. package/src/{builder → query-builder}/insert-query-state.ts +51 -62
  64. package/src/{builder → query-builder}/insert.ts +48 -59
  65. package/src/{builder → query-builder}/query-ast-service.ts +208 -226
  66. package/src/{utils → query-builder}/raw-column-parser.ts +32 -32
  67. package/src/{builder → query-builder}/relation-conditions.ts +112 -112
  68. package/src/{builder/operations → query-builder}/relation-manager.ts +82 -82
  69. package/src/{builder → query-builder}/relation-projection-helper.ts +101 -101
  70. package/src/{builder → query-builder}/relation-service.ts +284 -284
  71. package/src/{builder → query-builder}/relation-types.ts +21 -21
  72. package/src/{builder → query-builder}/relation-utils.ts +12 -12
  73. package/src/{builder → query-builder}/select-query-builder-deps.ts +112 -94
  74. package/src/{builder → query-builder}/select-query-state.ts +179 -179
  75. package/src/{builder → query-builder}/select.ts +78 -69
  76. package/src/{builder → query-builder}/update-query-state.ts +55 -59
  77. package/src/{builder → query-builder}/update.ts +50 -61
  78. package/src/schema/column.ts +25 -25
  79. package/src/schema/relation.ts +116 -116
  80. package/src/schema/table.ts +34 -34
  81. package/src/schema/types.ts +76 -76
  82. package/.github/workflows/publish-metal-orm.yml +0 -38
  83. package/ROADMAP.md +0 -125
  84. package/docs/CHANGES.md +0 -104
  85. package/docs/advanced-features.md +0 -176
  86. package/docs/api-reference.md +0 -31
  87. package/docs/dml-operations.md +0 -156
  88. package/docs/getting-started.md +0 -171
  89. package/docs/hydration.md +0 -115
  90. package/docs/index.md +0 -36
  91. package/docs/multi-dialect-support.md +0 -59
  92. package/docs/query-builder.md +0 -135
  93. package/docs/runtime.md +0 -105
  94. package/docs/schema-definition.md +0 -112
  95. package/metadata.json +0 -5
  96. package/playground/api/playground-api.ts +0 -94
  97. package/playground/index.html +0 -15
  98. package/playground/src/App.css +0 -1
  99. package/playground/src/App.tsx +0 -114
  100. package/playground/src/components/CodeDisplay.tsx +0 -43
  101. package/playground/src/components/QueryExecutor.tsx +0 -189
  102. package/playground/src/components/ResultsTable.tsx +0 -67
  103. package/playground/src/components/ResultsTabs.tsx +0 -105
  104. package/playground/src/components/ScenarioList.tsx +0 -56
  105. package/playground/src/components/logo.svg +0 -45
  106. package/playground/src/data/scenarios.ts +0 -2
  107. package/playground/src/main.tsx +0 -9
  108. package/playground/src/services/PlaygroundApiService.ts +0 -60
  109. package/postcss.config.cjs +0 -5
  110. package/sql_sql-ansi-cheatsheet-2025.md +0 -264
  111. package/src/ast/expression.ts +0 -658
  112. package/src/builder/operations/cte-manager.ts +0 -34
  113. package/src/builder/operations/filter-manager.ts +0 -68
  114. package/src/builder/operations/join-manager.ts +0 -36
  115. package/src/builder/operations/pagination-manager.ts +0 -36
  116. package/src/playground/features/playground/api/types.ts +0 -16
  117. package/src/playground/features/playground/clients/MockClient.ts +0 -17
  118. package/src/playground/features/playground/clients/SqliteClient.ts +0 -57
  119. package/src/playground/features/playground/common/IDatabaseClient.ts +0 -10
  120. package/src/playground/features/playground/data/scenarios/aggregation.ts +0 -36
  121. package/src/playground/features/playground/data/scenarios/basics.ts +0 -25
  122. package/src/playground/features/playground/data/scenarios/edge_cases.ts +0 -57
  123. package/src/playground/features/playground/data/scenarios/filtering.ts +0 -94
  124. package/src/playground/features/playground/data/scenarios/hydration.ts +0 -27
  125. package/src/playground/features/playground/data/scenarios/index.ts +0 -29
  126. package/src/playground/features/playground/data/scenarios/ordering.ts +0 -25
  127. package/src/playground/features/playground/data/scenarios/pagination.ts +0 -16
  128. package/src/playground/features/playground/data/scenarios/relationships.ts +0 -75
  129. package/src/playground/features/playground/data/scenarios/types.ts +0 -70
  130. package/src/playground/features/playground/data/schema.ts +0 -91
  131. package/src/playground/features/playground/data/seed.ts +0 -104
  132. package/src/playground/features/playground/services/QueryExecutionService.ts +0 -121
  133. package/src/runtime/orm-context.ts +0 -539
  134. package/tests/belongs-to-many.test.ts +0 -57
  135. package/tests/between.test.ts +0 -43
  136. package/tests/case-expression.test.ts +0 -58
  137. package/tests/complex-exists.test.ts +0 -230
  138. package/tests/cte.test.ts +0 -118
  139. package/tests/dml.test.ts +0 -206
  140. package/tests/exists.test.ts +0 -127
  141. package/tests/like.test.ts +0 -33
  142. package/tests/orm-runtime.test.ts +0 -254
  143. package/tests/postgres.test.ts +0 -30
  144. package/tests/right-join.test.ts +0 -89
  145. package/tests/subquery-having.test.ts +0 -193
  146. package/tests/window-function.test.ts +0 -151
  147. package/tsconfig.json +0 -30
  148. package/tsup.config.ts +0 -10
  149. package/vite.config.ts +0 -22
  150. package/vitest.config.ts +0 -14
  151. /package/src/{constants → core/sql}/sql.ts +0 -0
  152. /package/src/{runtime → orm}/als.ts +0 -0
  153. /package/src/{utils → query-builder}/relation-alias.ts +0 -0
package/README.md CHANGED
@@ -8,8 +8,8 @@
8
8
 
9
9
  MetalORM is a TypeScript-first, AST-driven SQL toolkit:
10
10
 
11
- - At the **base level**, it's a clear, deterministic query builder with schema definitions and relation-aware hydration.:contentReference[oaicite:0]{index=0}
12
- - At the **next level**, it becomes an **ORM runtime** with entities, lazy/batched relations, and a Unit of Work (`OrmContext`) that flushes graph changes in one `saveChanges()`.
11
+ - At the **base level**, it's a clear, deterministic query builder with schema definitions and relation-aware hydration.
12
+ - At the **next level**, it becomes an **ORM runtime** with entities, lazy/batched relations, and a Unit of Work (`OrmContext`) that flushes graph changes in one `saveChanges()`.
13
13
 
14
14
  Use only the parts you need: query builder + hydration for read-heavy/reporting code, or the full ORM runtime for application/business logic.
15
15
 
@@ -17,18 +17,18 @@ Use only the parts you need: query builder + hydration for read-heavy/reporting
17
17
 
18
18
  ## Documentation
19
19
 
20
- Full docs live in the `docs/` folder:
21
-
22
- - [Introduction](docs/index.md)
23
- - [Getting Started](docs/getting-started.md)
24
- - [Schema Definition](docs/schema-definition.md)
25
- - [Query Builder](docs/query-builder.md)
26
- - [DML Operations](docs/dml-operations.md)
27
- - [Hydration & Entities](docs/hydration.md)
28
- - [Runtime & Unit of Work](docs/runtime.md)
29
- - [Advanced Features](docs/advanced-features.md)
30
- - [Multi-Dialect Support](docs/multi-dialect-support.md)
31
- - [API Reference](docs/api-reference.md)
20
+ Full docs live in the `docs/` folder:
21
+
22
+ - [Introduction](https://github.com/celsowm/metal-orm/blob/main/docs/index.md)
23
+ - [Getting Started](https://github.com/celsowm/metal-orm/blob/main/docs/getting-started.md)
24
+ - [Schema Definition](https://github.com/celsowm/metal-orm/blob/main/docs/schema-definition.md)
25
+ - [Query Builder](https://github.com/celsowm/metal-orm/blob/main/docs/query-builder.md)
26
+ - [DML Operations](https://github.com/celsowm/metal-orm/blob/main/docs/dml-operations.md)
27
+ - [Hydration & Entities](https://github.com/celsowm/metal-orm/blob/main/docs/hydration.md)
28
+ - [Runtime & Unit of Work](https://github.com/celsowm/metal-orm/blob/main/docs/runtime.md)
29
+ - [Advanced Features](https://github.com/celsowm/metal-orm/blob/main/docs/advanced-features.md)
30
+ - [Multi-Dialect Support](https://github.com/celsowm/metal-orm/blob/main/docs/multi-dialect-support.md)
31
+ - [API Reference](https://github.com/celsowm/metal-orm/blob/main/docs/api-reference.md)
32
32
 
33
33
  ---
34
34
 
@@ -36,12 +36,12 @@ Full docs live in the `docs/` folder:
36
36
 
37
37
  **As a query builder:**
38
38
 
39
- - **Declarative schema definition** with `defineTable`, `col.*`, and typed relations.:contentReference[oaicite:1]{index=1}
40
- - **Fluent query builder** over a real SQL AST (`SelectQueryBuilder`, `InsertQueryBuilder`, `UpdateQueryBuilder`, `DeleteQueryBuilder`).
41
- - **Advanced SQL**: CTEs, aggregates, window functions, subqueries, JSON, CASE, EXISTS.
42
- - **Relation hydration**: turn flat rows into nested objects (`user.posts`, `user.roles`, etc.).:contentReference[oaicite:4]{index=4}
43
- - **Multi-dialect**: compile once, run on MySQL, PostgreSQL, SQLite, or SQL Server.:contentReference[oaicite:5]{index=5}
44
- - **DML**: type-safe INSERT / UPDATE / DELETE with `RETURNING` where supported.:contentReference[oaicite:6]{index=6}
39
+ - **Declarative schema definition** with `defineTable`, `col.*`, and typed relations.
40
+ - **Fluent query builder** over a real SQL AST (`SelectQueryBuilder`, `InsertQueryBuilder`, `UpdateQueryBuilder`, `DeleteQueryBuilder`).
41
+ - **Advanced SQL**: CTEs, aggregates, window functions, subqueries, JSON, CASE, EXISTS.
42
+ - **Relation hydration**: turn flat rows into nested objects (`user.posts`, `user.roles`, etc.).
43
+ - **Multi-dialect**: compile once, run on MySQL, PostgreSQL, SQLite, or SQL Server.
44
+ - **DML**: type-safe INSERT / UPDATE / DELETE with `RETURNING` where supported.
45
45
 
46
46
  **As an ORM runtime (optional):**
47
47
 
@@ -62,27 +62,40 @@ npm install metal-orm
62
62
  # yarn
63
63
  yarn add metal-orm
64
64
 
65
- # pnpm
66
- pnpm add metal-orm
67
-
68
-
69
- MetalORM compiles SQL; you bring your own driver:
70
-
71
- Dialect Driver Install
72
- MySQL / MariaDB mysql2 npm install mysql2
73
- SQLite sqlite3 npm install sqlite3
74
- PostgreSQL pg npm install pg
75
- SQL Server tedious npm install tedious
76
-
77
- Pick the matching dialect (MySqlDialect, SQLiteDialect, PostgresDialect, MSSQLDialect) when compiling queries.
78
-
79
- README
80
-
81
- 1. Start simple: tiny table, tiny query
82
-
83
- MetalORM can be just a straightforward query builder.
84
-
85
- import mysql from 'mysql2/promise';
65
+ # pnpm
66
+ pnpm add metal-orm
67
+ ```
68
+
69
+ MetalORM compiles SQL; you bring your own driver:
70
+
71
+ | Dialect | Driver | Install |
72
+ | --- | --- | --- |
73
+ | MySQL / MariaDB | `mysql2` | `npm install mysql2` |
74
+ | SQLite | `sqlite3` | `npm install sqlite3` |
75
+ | PostgreSQL | `pg` | `npm install pg` |
76
+ | SQL Server | `tedious` | `npm install tedious` |
77
+
78
+ Pick the matching dialect (MySqlDialect, SQLiteDialect, PostgresDialect, MSSQLDialect) when compiling queries.
79
+
80
+ > Drivers are declared as optional peer dependencies. Install only the ones you actually use in your project.
81
+
82
+ ### Playground (optional)
83
+
84
+ The React playground lives in `playground/` and is no longer part of the published package or its dependency tree. To run it locally:
85
+
86
+ 1. `cd playground && npm install`
87
+ 2. `npm run dev` (uses the root `vite.config.ts`)
88
+
89
+ It boots against an in-memory SQLite database seeded from the fixtures under `playground/shared/`.
90
+
91
+ ## Quick start
92
+
93
+ 1. Start simple: tiny table, tiny query
94
+
95
+ MetalORM can be just a straightforward query builder.
96
+
97
+ ```ts
98
+ import mysql from 'mysql2/promise';
86
99
  import {
87
100
  defineTable,
88
101
  col,
@@ -114,22 +127,24 @@ const { sql, params } = listOpenTodos.compile(dialect);
114
127
 
115
128
  // 4) Run with your favorite driver
116
129
  const connection = await mysql.createConnection({ /* ... */ });
117
- const [rows] = await connection.execute(sql, params);
118
-
119
- console.log(rows);
120
- // [
121
- // { id: 1, title: 'Write docs', done: 0 },
122
- // { id: 2, title: 'Ship feature', done: 0 },
123
- // ]
130
+ const [rows] = await connection.execute(sql, params);
131
+
132
+ console.log(rows);
133
+ // [
134
+ // { id: 1, title: 'Write docs', done: 0 },
135
+ // { id: 2, title: 'Ship feature', done: 0 },
136
+ // ]
137
+ ```
124
138
 
125
139
 
126
140
  That’s it: schema, query, SQL, done.
127
141
 
128
142
  2. Relations & hydration: nested results without an ORM
129
143
 
130
- Now lets add relations and get nested objects, still without committing to a full ORM.
131
-
132
- import {
144
+ Now let's add relations and get nested objects, still without committing to a full ORM.
145
+
146
+ ```ts
147
+ import {
133
148
  defineTable,
134
149
  col,
135
150
  hasMany,
@@ -172,41 +187,43 @@ const builder = new SelectQueryBuilder(users)
172
187
  columns: [posts.columns.id, posts.columns.title, posts.columns.createdAt],
173
188
  }); // eager relation for hydration
174
189
 
175
- const { sql, params } = builder.compile(dialect);
176
- const [rows] = await connection.execute(sql, params);
177
-
178
- // Turn flat rows into nested objects
179
- const hydrated = hydrateRows(
180
- rows as Record<string, unknown>[],
181
- builder.getHydrationPlan(),
182
- );
183
-
184
- console.log(hydrated);
185
- // [
186
- // {
187
- // id: 1,
188
- // name: 'John Doe',
189
- // email: 'john@example.com',
190
- // postCount: 15,
191
- // rank: 1,
192
- // posts: [
193
- // { id: 101, title: 'Latest Post', createdAt: '2023-05-15T10:00:00Z' },
194
- // // ...
195
- // ],
196
- // },
197
- // // ...
198
- // ]
190
+ const { sql, params } = builder.compile(dialect);
191
+ const [rows] = await connection.execute(sql, params);
192
+
193
+ // Turn flat rows into nested objects
194
+ const hydrated = hydrateRows(
195
+ rows as Record<string, unknown>[],
196
+ builder.getHydrationPlan(),
197
+ );
198
+
199
+ console.log(hydrated);
200
+ // [
201
+ // {
202
+ // id: 1,
203
+ // name: 'John Doe',
204
+ // email: 'john@example.com',
205
+ // postCount: 15,
206
+ // rank: 1,
207
+ // posts: [
208
+ // { id: 101, title: 'Latest Post', createdAt: '2023-05-15T10:00:00Z' },
209
+ // // ...
210
+ // ],
211
+ // },
212
+ // // ...
213
+ // ]
214
+ ```
199
215
 
200
216
 
201
217
  Use this mode anywhere you want powerful SQL + nice nested results, without changing how you manage your models.
202
218
 
203
219
  3. Turn it up: entities + Unit of Work (ORM mode)
204
220
 
205
- When youre ready, you can let MetalORM manage entities and relations for you.
206
-
207
- Instead of naked objects”, your queries can return entities attached to an OrmContext:
208
-
209
- import {
221
+ When you're ready, you can let MetalORM manage entities and relations for you.
222
+
223
+ Instead of "naked objects", your queries can return entities attached to an OrmContext:
224
+
225
+ ```ts
226
+ import {
210
227
  OrmContext,
211
228
  MySqlDialect,
212
229
  SelectQueryBuilder,
@@ -251,49 +268,44 @@ const newPost = user.posts.add({ title: 'Hello from ORM mode' });
251
268
  // Many-to-many via pivot:
252
269
  await user.roles.syncByIds([1, 2, 3]);
253
270
 
254
- // 3) Persist the entire graph
255
- await ctx.saveChanges();
256
- // INSERT/UPDATE/DELETE + pivot updates happen in a single Unit of Work.
257
-
271
+ // 3) Persist the entire graph
272
+ await ctx.saveChanges();
273
+ // INSERT/UPDATE/DELETE + pivot updates happen in a single Unit of Work.
274
+ ```
258
275
 
259
- Here’s what the runtime gives you:
260
276
 
261
- Identity map: the same row ↔ the same entity instance within a context.
262
-
263
- Change tracking: field writes mark entities as dirty.
264
-
265
- Relation tracking: add/remove/sync on relation collections emits relation changes.
266
-
267
- Cascades: relation definitions can opt into cascade: 'all' | 'persist' | 'remove' | 'link'.
268
-
269
- Single flush: ctx.saveChanges() figures out inserts, updates, deletes, and pivot changes.
277
+ Here's what the runtime gives you:
278
+
279
+ - Identity map: the same row becomes the same entity instance within a context.
280
+ - Change tracking: field writes mark entities as dirty.
281
+ - Relation tracking: add/remove/sync on relation collections emits relation changes.
282
+ - Cascades: relation definitions can opt into cascade: 'all' | 'persist' | 'remove' | 'link'.
283
+ - Single flush: `ctx.saveChanges()` figures out inserts, updates, deletes, and pivot changes.
270
284
 
271
285
  You can start your project using only the query builder + hydration and gradually migrate hot paths to entities as you implement the runtime primitives.
272
286
 
273
- When to use which mode?
274
-
275
- Query builder + hydration only
276
-
277
- Great for reporting, analytics, and places where you already have a model layer.
278
-
279
- You keep full control over how objects map to rows.
280
-
281
- Entity + Unit of Work runtime
282
-
283
- Great for request-scoped application logic and domain modeling.
284
-
285
- You want lazy relations, cascades, and less boilerplate around update/delete logic.
286
-
287
- Both modes share the same schema, AST, and dialects, so you don't have to pick one forever.
288
-
289
- Contributing
290
-
291
- Issues and PRs are welcome! If you're interested in pushing the runtime/ORM side further (soft deletes, multi-tenant filters, outbox patterns, etc.), contributions are especially appreciated.
292
-
293
- See the Contributing Guide
294
- for details.
295
-
296
- License
297
-
298
- MetalORM is MIT licensed
299
- .
287
+ ## When to use which mode?
288
+
289
+ ### Query builder + hydration only
290
+
291
+ Great for reporting, analytics, and places where you already have a model layer.
292
+
293
+ You keep full control over how objects map to rows.
294
+
295
+ ### Entity + Unit of Work runtime
296
+
297
+ Great for request-scoped application logic and domain modeling.
298
+
299
+ You want lazy relations, cascades, and less boilerplate around update/delete logic.
300
+
301
+ Both modes share the same schema, AST, and dialects, so you don't have to pick one forever.
302
+
303
+ ## Contributing
304
+
305
+ Issues and PRs are welcome! If you're interested in pushing the runtime/ORM side further (soft deletes, multi-tenant filters, outbox patterns, etc.), contributions are especially appreciated.
306
+
307
+ See the contributing guide for details.
308
+
309
+ ## License
310
+
311
+ MetalORM is MIT licensed.