metal-orm 1.0.4 → 1.0.6

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 (57) hide show
  1. package/README.md +299 -113
  2. package/docs/CHANGES.md +104 -0
  3. package/docs/advanced-features.md +92 -1
  4. package/docs/api-reference.md +13 -4
  5. package/docs/dml-operations.md +156 -0
  6. package/docs/getting-started.md +122 -55
  7. package/docs/hydration.md +77 -3
  8. package/docs/index.md +19 -14
  9. package/docs/multi-dialect-support.md +25 -0
  10. package/docs/query-builder.md +60 -0
  11. package/docs/runtime.md +105 -0
  12. package/docs/schema-definition.md +52 -1
  13. package/package.json +1 -1
  14. package/src/ast/expression.ts +630 -592
  15. package/src/ast/query.ts +110 -49
  16. package/src/builder/delete-query-state.ts +42 -0
  17. package/src/builder/delete.ts +57 -0
  18. package/src/builder/hydration-manager.ts +3 -2
  19. package/src/builder/hydration-planner.ts +163 -107
  20. package/src/builder/insert-query-state.ts +62 -0
  21. package/src/builder/insert.ts +59 -0
  22. package/src/builder/operations/relation-manager.ts +1 -23
  23. package/src/builder/relation-conditions.ts +45 -1
  24. package/src/builder/relation-service.ts +81 -18
  25. package/src/builder/relation-types.ts +15 -0
  26. package/src/builder/relation-utils.ts +12 -0
  27. package/src/builder/select.ts +427 -394
  28. package/src/builder/update-query-state.ts +59 -0
  29. package/src/builder/update.ts +61 -0
  30. package/src/constants/sql-operator-config.ts +3 -0
  31. package/src/constants/sql.ts +38 -32
  32. package/src/dialect/abstract.ts +107 -47
  33. package/src/dialect/mssql/index.ts +31 -6
  34. package/src/dialect/mysql/index.ts +31 -6
  35. package/src/dialect/postgres/index.ts +45 -6
  36. package/src/dialect/sqlite/index.ts +45 -6
  37. package/src/index.ts +22 -11
  38. package/src/playground/features/playground/data/scenarios/hydration.ts +23 -11
  39. package/src/playground/features/playground/data/scenarios/types.ts +18 -15
  40. package/src/playground/features/playground/data/schema.ts +6 -2
  41. package/src/playground/features/playground/services/QueryExecutionService.ts +2 -1
  42. package/src/runtime/entity-meta.ts +52 -0
  43. package/src/runtime/entity.ts +252 -0
  44. package/src/runtime/execute.ts +36 -0
  45. package/src/runtime/hydration.ts +100 -38
  46. package/src/runtime/lazy-batch.ts +205 -0
  47. package/src/runtime/orm-context.ts +539 -0
  48. package/src/runtime/relations/belongs-to.ts +92 -0
  49. package/src/runtime/relations/has-many.ts +111 -0
  50. package/src/runtime/relations/many-to-many.ts +149 -0
  51. package/src/schema/column.ts +15 -1
  52. package/src/schema/relation.ts +105 -40
  53. package/src/schema/table.ts +34 -22
  54. package/src/schema/types.ts +76 -0
  55. package/tests/belongs-to-many.test.ts +57 -0
  56. package/tests/dml.test.ts +206 -0
  57. package/tests/orm-runtime.test.ts +254 -0
@@ -0,0 +1,105 @@
1
+ # Runtime & Unit of Work
2
+
3
+ This page describes MetalORM's optional entity runtime:
4
+
5
+ - `OrmContext` – the Unit of Work.
6
+ - entities – proxies wrapping hydrated rows.
7
+ - relation wrappers – lazy, batched collections and references.
8
+
9
+ ## OrmContext
10
+
11
+ `OrmContext` owns:
12
+
13
+ - a SQL dialect,
14
+ - a DB executor (`executeSql(sql, params)`),
15
+ - an identity map (`table + primaryKey → entity`),
16
+ - change tracking for entities and relations,
17
+ - hooks and (optionally) domain event dispatch.
18
+
19
+ ```ts
20
+ const ctx = new OrmContext({
21
+ dialect: new MySqlDialect(),
22
+ db: {
23
+ async executeSql(sql, params) {
24
+ // call your DB driver here
25
+ }
26
+ }
27
+ });
28
+ ```
29
+
30
+ ## Entities
31
+
32
+ Entities are created when you call `.execute(ctx)` on a SelectQueryBuilder.
33
+
34
+ They:
35
+
36
+ - expose table columns as properties (user.id, user.name, …)
37
+ - expose relations as wrappers:
38
+ - HasManyCollection<T> (e.g. user.posts)
39
+ - BelongsToReference<T> (e.g. post.author)
40
+ - ManyToManyCollection<T> (e.g. user.roles)
41
+ - track changes to fields and collections for the Unit of Work.
42
+
43
+ ```ts
44
+ const [user] = await new SelectQueryBuilder(users)
45
+ .select({ id: users.columns.id, name: users.columns.name })
46
+ .includeLazy('posts')
47
+ .execute(ctx);
48
+
49
+ user.name = 'Updated Name'; // marks entity as Dirty
50
+ const posts = await user.posts.load(); // lazy-batched load
51
+ ```
52
+
53
+ ## Unit of Work
54
+
55
+ Each entity in an OrmContext has a status:
56
+
57
+ - New – created in memory and not yet persisted.
58
+ - Managed – loaded from the database and unchanged.
59
+ - Dirty – modified scalar properties.
60
+ - Removed – scheduled for deletion.
61
+
62
+ Relations track:
63
+
64
+ - additions (add, attach, syncByIds),
65
+ - removals (remove, detach).
66
+
67
+ `ctx.saveChanges()`:
68
+
69
+ - runs hooks / interceptors,
70
+ - flushes entity changes as INSERT / UPDATE / DELETE,
71
+ - flushes relation changes (FK / pivot),
72
+ - dispatches domain events (optional),
73
+ - resets tracking.
74
+
75
+ ```ts
76
+ user.posts.add({ title: 'From entities' });
77
+ user.posts.remove(posts[0]);
78
+
79
+ await ctx.saveChanges();
80
+ ```
81
+
82
+ ## Hooks & Domain Events
83
+
84
+ Each TableDef can define hooks:
85
+
86
+ ```ts
87
+ const users = defineTable('users', { /* ... */ }, undefined, {
88
+ hooks: {
89
+ beforeInsert(ctx, user) {
90
+ user.createdAt = new Date();
91
+ },
92
+ afterUpdate(ctx, user) {
93
+ // log audit event
94
+ },
95
+ },
96
+ });
97
+ ```
98
+
99
+ Entities may accumulate domain events:
100
+
101
+ ```ts
102
+ addDomainEvent(user, new UserRegisteredEvent(user.id));
103
+ ```
104
+
105
+ After flushing, the context dispatches these events to registered handlers or writes them to an outbox table.
@@ -37,7 +37,9 @@ You can also chain modifiers to define column constraints:
37
37
 
38
38
  ## Relations
39
39
 
40
- You can define relations between tables using `hasMany` and `belongsTo`:
40
+ You can define relations between tables using `hasMany`, `belongsTo`, and `belongsToMany`:
41
+
42
+ ### One-to-Many Relations
41
43
 
42
44
  ```typescript
43
45
  import { defineTable, col, hasMany } from 'metal-orm';
@@ -59,3 +61,52 @@ const users = defineTable(
59
61
  }
60
62
  );
61
63
  ```
64
+
65
+ ### Many-to-One Relations
66
+
67
+ ```typescript
68
+ const posts = defineTable('posts', {
69
+ id: col.int().primaryKey(),
70
+ title: col.varchar(255).notNull(),
71
+ userId: col.int().notNull(),
72
+ }, {
73
+ author: belongsTo(users, 'userId')
74
+ });
75
+ ```
76
+
77
+ ### Many-to-Many Relations
78
+
79
+ ```typescript
80
+ const projects = defineTable('projects', {
81
+ id: col.int().primaryKey(),
82
+ name: col.varchar(255).notNull(),
83
+ });
84
+
85
+ const projectAssignments = defineTable('project_assignments', {
86
+ id: col.int().primaryKey(),
87
+ userId: col.int().notNull(),
88
+ projectId: col.int().notNull(),
89
+ role: col.varchar(50),
90
+ assignedAt: col.timestamp(),
91
+ });
92
+
93
+ const users = defineTable('users', {
94
+ id: col.int().primaryKey(),
95
+ name: col.varchar(255).notNull(),
96
+ }, {
97
+ projects: belongsToMany(
98
+ projects,
99
+ projectAssignments,
100
+ {
101
+ pivotForeignKeyToRoot: 'userId',
102
+ pivotForeignKeyToTarget: 'projectId',
103
+ defaultPivotColumns: ['role', 'assignedAt']
104
+ }
105
+ )
106
+ });
107
+
108
+ > **Note**: When using the runtime, relation definitions (`hasMany`, `belongsTo`, `belongsToMany`) are also used to:
109
+ > - generate hydration plans for eager loading
110
+ > - configure lazy relation loaders
111
+ > - control cascade behavior in `OrmContext.saveChanges()`.
112
+ ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "metal-orm",
3
- "version": "1.0.4",
3
+ "version": "1.0.6",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {