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/docs/CHANGES.md DELETED
@@ -1,104 +0,0 @@
1
- # Documentation Updates Summary
2
-
3
- This document summarizes the major updates made to the MetalORM documentation to reflect all new features.
4
-
5
- ## New Documentation Files
6
-
7
- ### `dml-operations.md`
8
- - **New File**: Comprehensive documentation for INSERT, UPDATE, and DELETE operations
9
- - **Features Covered**:
10
- - `InsertQueryBuilder` with single and multi-row inserts
11
- - `UpdateQueryBuilder` with conditional updates
12
- - `DeleteQueryBuilder` with safety best practices
13
- - RETURNING clause support across all DML operations
14
- - Multi-dialect support for all DML operations
15
-
16
- ## Updated Documentation Files
17
-
18
- ### `index.md`
19
- - **Updates**:
20
- - Added DML Operations to the table of contents
21
- - Updated philosophy to include PostgreSQL in multi-dialect support
22
- - Added "Comprehensive Relation Support" to features list
23
- - Added "DML Operations" to features list
24
-
25
- ### `schema-definition.md`
26
- - **Updates**:
27
- - Added `belongsTo` relation type documentation
28
- - Added comprehensive `belongsToMany` relation documentation with pivot table examples
29
- - Updated relation section with all three relation types
30
-
31
- ### `advanced-features.md`
32
- - **Updates**:
33
- - Enhanced window functions section with convenience helpers
34
- - Added examples for `rowNumber()`, `rank()`, `lag()`, `lead()` functions
35
- - Improved CTE examples with better explanations
36
-
37
- ### `multi-dialect-support.md`
38
- - **Updates**:
39
- - Added PostgreSQL dialect to supported dialects
40
- - Added dialect-specific features section
41
- - Added examples showing SQL Server TOP vs LIMIT differences
42
-
43
- ### `api-reference.md`
44
- - **Updates**:
45
- - Added `InsertQueryBuilder`, `UpdateQueryBuilder`, `DeleteQueryBuilder` to core classes
46
- - Added `PostgresDialect` to dialect compilers
47
- - Added `belongsToMany()` to relation definitions
48
- - Added `notLike()`, `notBetween()`, `firstValue()`, `lastValue()`, `ntile()` to utility functions
49
- - Added `isNull()`, `isNotNull()` to null checking functions
50
-
51
- ### `hydration.md`
52
- - **Updates**:
53
- - Enhanced pivot column hydration documentation
54
- - Added comprehensive examples of `_pivot` key usage
55
- - Added advanced hydration options with custom aliases
56
-
57
- ### `query-builder.md`
58
- - **Updates**:
59
- - Added window functions section with examples
60
- - Added CTEs (Common Table Expressions) section
61
- - Added subqueries section
62
- - Enhanced existing sections with more comprehensive examples
63
-
64
- ### `getting-started.md`
65
- - **Updates**:
66
- - Added `rowNumber()` window function to the main example
67
- - Updated imports to include new functions
68
- - Enhanced example output to show window function results
69
-
70
- ## New Features Now Documented
71
-
72
- ### DML Operations
73
- - Full INSERT, UPDATE, DELETE query builder support
74
- - RETURNING clause support for all DML operations
75
- - Multi-dialect compilation for DML
76
-
77
- ### Advanced SQL Features
78
- - Comprehensive window function support (`rowNumber`, `rank`, `denseRank`, `lag`, `lead`, `firstValue`, `lastValue`, `ntile`)
79
- - Enhanced CTE support with recursive CTEs
80
- - Advanced subquery support
81
-
82
- ### Relation Types
83
- - `belongsToMany` relation type with pivot table support
84
- - Pivot column hydration with custom alias support
85
-
86
- ### Dialect Support
87
- - PostgreSQL dialect support
88
- - Dialect-specific feature documentation
89
-
90
- ### Expression Builders
91
- - Additional comparison operators (`notLike`, `notBetween`)
92
- - Null checking functions (`isNull`, `isNotNull`)
93
- - Enhanced window function helpers
94
-
95
- ## Verification
96
-
97
- All documented features have been verified to exist in the codebase:
98
- - ✅ All DML classes exist and are exported
99
- - ✅ All window functions exist and are exported
100
- - ✅ PostgreSQL dialect exists and is exported
101
- - ✅ `belongsToMany` relation function exists and is exported
102
- - ✅ All utility functions exist and are exported
103
-
104
- The documentation now accurately reflects the current state of the MetalORM library with all its advanced features.
@@ -1,176 +0,0 @@
1
- # Advanced Features
2
-
3
- MetalORM supports a wide range of advanced SQL features to handle complex scenarios.
4
-
5
- ## Common Table Expressions (CTEs)
6
-
7
- CTEs help organize complex queries. You can define a CTE using a `SelectQueryBuilder` and reference it in the main query.
8
-
9
- ```typescript
10
- const since = new Date();
11
- since.setDate(since.getDate() - 30);
12
-
13
- const activeUsers = new SelectQueryBuilder(users)
14
- .selectRaw('*')
15
- .where(gt(users.columns.lastLogin, since))
16
- .as('active_users');
17
-
18
- const query = new SelectQueryBuilder(activeUsers)
19
- .with(activeUsers)
20
- .selectRaw('*')
21
- .where(eq(activeUsers.columns.id, 1));
22
- ```
23
-
24
- ## Window Functions
25
-
26
- MetalORM provides comprehensive support for window functions including `ROW_NUMBER()`, `RANK()`, `DENSE_RANK()`, `LAG()`, `LEAD()`, and more.
27
-
28
- ### Basic Window Functions
29
-
30
- ```typescript
31
- const rankedPosts = new SelectQueryBuilder(posts)
32
- .select({
33
- id: posts.columns.id,
34
- title: posts.columns.title,
35
- rank: windowFunction('RANK', [], [posts.columns.userId], [
36
- { column: posts.columns.createdAt, direction: 'DESC' }
37
- ])
38
- });
39
- ```
40
-
41
- ### Convenience Helpers
42
-
43
- MetalORM provides convenience functions for common window functions:
44
-
45
- ```typescript
46
- import { rowNumber, rank, denseRank, lag, lead } from 'metal-orm';
47
-
48
- // Simple row numbering
49
- const query1 = new SelectQueryBuilder(users)
50
- .select({
51
- id: users.columns.id,
52
- name: users.columns.name,
53
- rowNum: rowNumber()
54
- });
55
-
56
- // Ranking with partitioning
57
- const query2 = new SelectQueryBuilder(orders)
58
- .select({
59
- id: orders.columns.id,
60
- customerId: orders.columns.customerId,
61
- amount: orders.columns.amount,
62
- rank: rank()
63
- })
64
- .partitionBy(orders.columns.customerId)
65
- .orderBy(orders.columns.amount, 'DESC');
66
-
67
- // LAG and LEAD functions
68
- const query3 = new SelectQueryBuilder(sales)
69
- .select({
70
- date: sales.columns.date,
71
- amount: sales.columns.amount,
72
- prevAmount: lag(sales.columns.amount, 1, 0),
73
- nextAmount: lead(sales.columns.amount, 1, 0)
74
- });
75
- ```
76
-
77
- ## Subqueries and EXISTS
78
-
79
- You can use subqueries and `EXISTS` to perform complex checks.
80
-
81
- ```typescript
82
- const usersWithPosts = new SelectQueryBuilder(users)
83
- .selectRaw('*')
84
- .where(exists(
85
- new SelectQueryBuilder(posts)
86
- .selectRaw('1')
87
- .where(eq(posts.columns.userId, users.columns.id))
88
- ));
89
- ```
90
-
91
- ## JSON Operations
92
-
93
- MetalORM provides helpers for working with JSON data.
94
-
95
- ```typescript
96
- const userData = defineTable('user_data', {
97
- id: col.int().primaryKey(),
98
- userId: col.int().notNull(),
99
- preferences: col.json().notNull()
100
- });
101
-
102
- const jsonQuery = new SelectQueryBuilder(userData)
103
- .select({
104
- id: userData.columns.id,
105
- theme: jsonPath(userData.columns.preferences, '$.theme')
106
- })
107
- .where(eq(jsonPath(userData.columns.preferences, '$.theme'), 'dark'));
108
- ```
109
-
110
- ## CASE Expressions
111
-
112
- You can use `caseWhen()` to create `CASE` expressions for conditional logic.
113
-
114
- ```typescript
115
- const tieredUsers = new SelectQueryBuilder(users)
116
- .select({
117
- id: users.columns.id,
118
- tier: caseWhen([
119
- { when: gt(count(posts.columns.id), 10), then: 'power user' }
120
- ], 'regular')
121
- })
122
- .groupBy(users.columns.id);
123
-
124
- ## Advanced Runtime Patterns
125
-
126
- When using the OrmContext runtime, you can implement advanced patterns like soft deletes, multi-tenant filtering, and optimistic concurrency.
127
-
128
- ### Soft Deletes
129
-
130
- Use hooks to implement soft deletes:
131
-
132
- ```ts
133
- const users = defineTable('users', {
134
- id: col.int().primaryKey(),
135
- name: col.varchar(255).notNull(),
136
- deletedAt: col.timestamp(),
137
- }, undefined, {
138
- hooks: {
139
- beforeRemove(ctx, user) {
140
- user.deletedAt = new Date();
141
- return false; // prevent actual deletion
142
- },
143
- },
144
- });
145
- ```
146
-
147
- ### Multi-Tenant Filters
148
-
149
- Apply global filters via context:
150
-
151
- ```ts
152
- const ctx = new OrmContext({
153
- dialect: new MySqlDialect(),
154
- db: { /* ... */ },
155
- tenantId: 'tenant-123',
156
- });
157
-
158
- // All queries in this context automatically filter by tenant
159
- const users = await new SelectQueryBuilder(usersTable)
160
- .execute(ctx); // WHERE tenantId = 'tenant-123'
161
- ```
162
-
163
- ### Optimistic Concurrency
164
-
165
- Track version columns for conflict detection:
166
-
167
- ```ts
168
- const posts = defineTable('posts', {
169
- id: col.int().primaryKey(),
170
- title: col.varchar(255).notNull(),
171
- version: col.int().default(1),
172
- });
173
-
174
- ctx.saveChanges(); // throws if version mismatch
175
- ```
176
- ```
@@ -1,31 +0,0 @@
1
- # API Reference
2
-
3
- This section provides a reference for the core classes, key functions, and utility functions in MetalORM.
4
-
5
- ### Core Classes
6
- - `SelectQueryBuilder` - Main query builder class
7
- - `InsertQueryBuilder` - INSERT query builder class
8
- - `UpdateQueryBuilder` - UPDATE query builder class
9
- - `DeleteQueryBuilder` - DELETE query builder class
10
- - `MySqlDialect` / `SQLiteDialect` / `MSSQLDialect` / `PostgresDialect` - SQL dialect compilers
11
- - `HydrationManager` - Handles relation hydration logic
12
- - `OrmContext` - Unit of Work context for entities
13
- - `Entity<TTable>` - Entity proxy wrapping table rows
14
- - `HasManyCollection<T>` - Lazy/batched has-many relation wrapper
15
- - `BelongsToReference<T>` - Belongs-to relation wrapper
16
- - `ManyToManyCollection<T>` - Many-to-many relation wrapper with pivot
17
-
18
- ### Key Functions
19
- - `defineTable()` - Define database tables
20
- - `col.*()` - Column type definitions
21
- - `hasMany()` / `belongsTo()` / `belongsToMany()` - Relation definitions
22
- - `eq()`, `and()`, `or()`, etc. - Expression builders
23
- - `hydrateRows()` - Transform flat rows to nested objects
24
-
25
- ### Utility Functions
26
- - `count()`, `sum()`, `avg()` - Aggregate functions
27
- - `like()`, `notLike()`, `between()`, `notBetween()`, `inList()`, `notInList()` - Comparison operators
28
- - `jsonPath()` - JSON extraction
29
- - `caseWhen()`, `exists()`, `notExists()` - Conditional and subquery helpers
30
- - `rowNumber()`, `rank()`, `denseRank()`, `lag()`, `lead()`, `firstValue()`, `lastValue()`, `ntile()`, `windowFunction()` - Window function helpers
31
- - `isNull()`, `isNotNull()` - Null checking functions
@@ -1,156 +0,0 @@
1
- # DML Operations
2
-
3
- MetalORM provides comprehensive support for Data Manipulation Language (DML) operations including INSERT, UPDATE, and DELETE queries.
4
-
5
- ## INSERT Operations
6
-
7
- The `InsertQueryBuilder` allows you to insert data into your tables with full type safety.
8
-
9
- ### Basic Insert
10
-
11
- ```typescript
12
- import { InsertQueryBuilder } from 'metal-orm';
13
-
14
- const query = new InsertQueryBuilder(users)
15
- .values({
16
- name: 'John Doe',
17
- email: 'john@example.com',
18
- createdAt: new Date()
19
- });
20
-
21
- const { sql, params } = query.compile(new MySqlDialect());
22
- ```
23
-
24
- ### Multi-row Insert
25
-
26
- ```typescript
27
- const query = new InsertQueryBuilder(users)
28
- .values([
29
- { name: 'John Doe', email: 'john@example.com' },
30
- { name: 'Jane Smith', email: 'jane@example.com' }
31
- ]);
32
- ```
33
-
34
- ### RETURNING Clause
35
-
36
- Some databases support returning inserted data:
37
-
38
- ```typescript
39
- const query = new InsertQueryBuilder(users)
40
- .values({ name: 'John Doe', email: 'john@example.com' })
41
- .returning(users.columns.id, users.columns.name);
42
- ```
43
-
44
- ## UPDATE Operations
45
-
46
- The `UpdateQueryBuilder` provides a fluent API for updating records.
47
-
48
- ### Basic Update
49
-
50
- ```typescript
51
- const query = new UpdateQueryBuilder(users)
52
- .set({ name: 'John Updated', email: 'john.updated@example.com' })
53
- .where(eq(users.columns.id, 1));
54
- ```
55
-
56
- ### Conditional Update
57
-
58
- ```typescript
59
- const query = new UpdateQueryBuilder(users)
60
- .set({ lastLogin: new Date() })
61
- .where(and(
62
- eq(users.columns.id, 1),
63
- isNull(users.columns.deletedAt)
64
- ));
65
- ```
66
-
67
- ### RETURNING Clause
68
-
69
- ```typescript
70
- const query = new UpdateQueryBuilder(users)
71
- .set({ status: 'active' })
72
- .where(eq(users.columns.id, 1))
73
- .returning(users.columns.id, users.columns.status);
74
- ```
75
-
76
- ## DELETE Operations
77
-
78
- The `DeleteQueryBuilder` allows you to delete records with safety.
79
-
80
- ### Basic Delete
81
-
82
- ```typescript
83
- const query = new DeleteQueryBuilder(users)
84
- .where(eq(users.columns.id, 1));
85
- ```
86
-
87
- ### Conditional Delete
88
-
89
- ```typescript
90
- const query = new DeleteQueryBuilder(users)
91
- .where(and(
92
- eq(users.columns.status, 'inactive'),
93
- lt(users.columns.lastLogin, new Date('2023-01-01'))
94
- ));
95
- ```
96
-
97
- ### RETURNING Clause
98
-
99
- ```typescript
100
- const query = new DeleteQueryBuilder(users)
101
- .where(eq(users.columns.id, 1))
102
- .returning(users.columns.id, users.columns.name);
103
- ```
104
-
105
- ## Multi-Dialect Support
106
-
107
- All DML operations support the same multi-dialect compilation as SELECT queries:
108
-
109
- ```typescript
110
- // MySQL
111
- const mysqlResult = query.compile(new MySqlDialect());
112
-
113
- // SQLite
114
- const sqliteResult = query.compile(new SQLiteDialect());
115
-
116
- // SQL Server
117
- const mssqlResult = query.compile(new MSSQLDialect());
118
-
119
- // PostgreSQL
120
- const postgresResult = query.compile(new PostgresDialect());
121
- ```
122
-
123
- ## Best Practices
124
-
125
- 1. **Always use WHERE clauses**: For UPDATE and DELETE operations, always include WHERE clauses to avoid accidental mass updates/deletes.
126
-
127
- 2. **Use RETURNING for verification**: When supported by your database, use RETURNING clauses to verify what was affected.
128
-
129
- 3. **Batch operations**: For large datasets, consider batching INSERT operations to avoid parameter limits.
130
-
131
- 4. **Transaction safety**: Wrap DML operations in transactions when performing multiple related operations.
132
-
133
- ## Using the Unit of Work (optional)
134
-
135
- If you're using `OrmContext`, you don't have to manually build `InsertQueryBuilder` / `UpdateQueryBuilder` / `DeleteQueryBuilder` for every change.
136
-
137
- Instead, you can:
138
-
139
- 1. Load entities via the query builder + `execute(ctx)`.
140
- 2. Modify fields and relations in memory.
141
- 3. Call `ctx.saveChanges()` once.
142
-
143
- ```ts
144
- const [user] = await new SelectQueryBuilder(users)
145
- .select({ id: users.columns.id, name: users.columns.name })
146
- .includeLazy('posts')
147
- .where(eq(users.columns.id, 1))
148
- .execute(ctx);
149
-
150
- user.name = 'Updated Name';
151
- user.posts.add({ title: 'New from runtime' });
152
-
153
- await ctx.saveChanges();
154
- ```
155
-
156
- Internally, MetalORM uses the same DML ASTs and dialect compilers described above to generate INSERT, UPDATE, DELETE, and pivot operations.
@@ -1,171 +0,0 @@
1
- # Getting Started
2
-
3
- This guide walks you through:
4
-
5
- 1. Using MetalORM as a **simple query builder**.
6
- 2. Hydrating relations into nested objects.
7
- 3. Taking a first look at the **OrmContext** runtime.
8
-
9
- ## 1. Installation
10
-
11
- ```bash
12
- npm install metal-orm
13
- # or
14
- yarn add metal-orm
15
- # or
16
- pnpm add metal-orm
17
- ```
18
-
19
- ## 2. Your first query (builder only)
20
-
21
- ```typescript
22
- import { defineTable, col, SelectQueryBuilder, eq, MySqlDialect } from 'metal-orm';
23
-
24
- const todos = defineTable('todos', {
25
- id: col.int().primaryKey(),
26
- title: col.varchar(255).notNull(),
27
- done: col.boolean().default(false),
28
- });
29
-
30
- const query = new SelectQueryBuilder(todos)
31
- .select({
32
- id: todos.columns.id,
33
- title: todos.columns.title,
34
- })
35
- .where(eq(todos.columns.done, false));
36
-
37
- const dialect = new MySqlDialect();
38
- const { sql, params } = query.compile(dialect);
39
-
40
- // Execute `sql` + `params` with your DB driver.
41
- ```
42
-
43
- ## 3. Adding relations & hydration
44
-
45
- ```typescript
46
- import {
47
- defineTable,
48
- col,
49
- hasMany,
50
- SelectQueryBuilder,
51
- eq,
52
- count,
53
- rowNumber,
54
- hydrateRows,
55
- } from 'metal-orm';
56
-
57
- const posts = defineTable('posts', {
58
- id: col.int().primaryKey(),
59
- title: col.varchar(255).notNull(),
60
- userId: col.int().notNull(),
61
- createdAt: col.timestamp().default('CURRENT_TIMESTAMP'),
62
- });
63
-
64
- const users = defineTable('users', {
65
- id: col.int().primaryKey(),
66
- name: col.varchar(255).notNull(),
67
- email: col.varchar(255).unique(),
68
- }, {
69
- posts: hasMany(posts, 'userId'),
70
- });
71
-
72
- // Build a query with relation & window function
73
- const builder = new SelectQueryBuilder(users)
74
- .select({
75
- id: users.columns.id,
76
- name: users.columns.name,
77
- email: users.columns.email,
78
- postCount: count(posts.columns.id),
79
- rank: rowNumber(), // window function helper
80
- })
81
- .leftJoin(posts, eq(posts.columns.userId, users.columns.id))
82
- .groupBy(users.columns.id, users.columns.name, users.columns.email)
83
- .orderBy(count(posts.columns.id), 'DESC')
84
- .limit(10)
85
- .include('posts', {
86
- columns: [posts.columns.id, posts.columns.title, posts.columns.createdAt],
87
- }); // eager relation for hydration
88
-
89
- const { sql, params } = builder.compile(dialect);
90
- const [rows] = await connection.execute(sql, params);
91
-
92
- // Turn flat rows into nested objects
93
- const hydrated = hydrateRows(
94
- rows as Record<string, unknown>[],
95
- builder.getHydrationPlan(),
96
- );
97
-
98
- console.log(hydrated);
99
- // [
100
- // {
101
- // id: 1,
102
- // name: 'John Doe',
103
- // email: 'john@example.com',
104
- // postCount: 15,
105
- // rank: 1,
106
- // posts: [
107
- // { id: 101, title: 'Latest Post', createdAt: '2023-05-15T10:00:00Z' },
108
- // // ...
109
- // ],
110
- // },
111
- // // ...
112
- // ]
113
- ```
114
-
115
- ## 4. A taste of the runtime (optional)
116
-
117
- When you're ready to let MetalORM manage entities and relations, you can use the OrmContext:
118
-
119
- ```typescript
120
- import {
121
- OrmContext,
122
- MySqlDialect,
123
- SelectQueryBuilder,
124
- eq,
125
- } from 'metal-orm';
126
-
127
- // 1) Create an OrmContext for this request
128
- const ctx = new OrmContext({
129
- dialect: new MySqlDialect(),
130
- db: {
131
- async executeSql(sql, params) {
132
- const [rows] = await connection.execute(sql, params);
133
- // MetalORM expects columns + values; adapt as needed
134
- return [{
135
- columns: Object.keys(rows[0] ?? {}),
136
- values: rows.map(row => Object.values(row)),
137
- }];
138
- },
139
- },
140
- });
141
-
142
- // 2) Load entities with lazy relations
143
- const [user] = await new SelectQueryBuilder(users)
144
- .select({
145
- id: users.columns.id,
146
- name: users.columns.name,
147
- email: users.columns.email,
148
- })
149
- .includeLazy('posts') // HasMany as a lazy collection
150
- .includeLazy('roles') // BelongsToMany as a lazy collection
151
- .where(eq(users.columns.id, 1))
152
- .execute(ctx);
153
-
154
- // user is an Entity<typeof users>
155
- // scalar props are normal:
156
- user.name = 'Updated Name'; // marks entity as Dirty
157
-
158
- // relations are live collections:
159
- const postsCollection = await user.posts.load(); // batched lazy load
160
- const newPost = user.posts.add({ title: 'Hello from ORM mode' });
161
-
162
- // Many-to-many via pivot:
163
- await user.roles.syncByIds([1, 2, 3]);
164
-
165
- // 3) Persist the entire graph
166
- await ctx.saveChanges();
167
- // INSERT/UPDATE/DELETE + pivot updates happen in a single Unit of Work.
168
-
169
- ```
170
-
171
- See [Runtime & Unit of Work](./runtime.md) for full details on entities and the Unit of Work.