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.
- package/README.md +133 -121
- package/dist/decorators/index.cjs +2564 -0
- package/dist/decorators/index.cjs.map +1 -0
- package/dist/decorators/index.d.cts +53 -0
- package/dist/decorators/index.d.ts +53 -0
- package/dist/decorators/index.js +2530 -0
- package/dist/decorators/index.js.map +1 -0
- package/dist/index.cjs +4227 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +701 -0
- package/dist/index.d.ts +701 -0
- package/dist/index.js +4131 -0
- package/dist/index.js.map +1 -0
- package/dist/select-654m4qy8.d.cts +1522 -0
- package/dist/select-654m4qy8.d.ts +1522 -0
- package/package.json +27 -20
- package/src/codegen/typescript.ts +405 -393
- package/src/core/ast/aggregate-functions.ts +30 -0
- package/src/core/ast/builders.ts +43 -0
- package/src/core/ast/expression-builders.ts +310 -0
- package/src/core/ast/expression-nodes.ts +211 -0
- package/src/core/ast/expression-visitor.ts +99 -0
- package/src/core/ast/expression.ts +5 -0
- package/src/{utils → core/ast}/join-node.ts +20 -20
- package/src/{ast → core/ast}/join.ts +18 -18
- package/src/{ast → core/ast}/query.ts +113 -113
- package/src/core/ast/window-functions.ts +140 -0
- package/src/{dialect → core/dialect}/abstract.ts +94 -94
- package/src/{dialect → core/dialect}/mssql/index.ts +31 -31
- package/src/{dialect → core/dialect}/mysql/index.ts +31 -31
- package/src/{dialect → core/dialect}/postgres/index.ts +45 -45
- package/src/{dialect → core/dialect}/sqlite/index.ts +45 -45
- package/src/{constants → core/sql}/sql-operator-config.ts +39 -39
- package/src/decorators/bootstrap.ts +126 -0
- package/src/decorators/column.ts +78 -0
- package/src/decorators/entity.ts +36 -0
- package/src/decorators/index.ts +4 -0
- package/src/decorators/relations.ts +107 -0
- package/src/global.d.ts +1 -0
- package/src/index.ts +22 -22
- package/src/orm/db-executor.ts +11 -0
- package/src/orm/domain-event-bus.ts +52 -0
- package/src/{runtime → orm}/entity-meta.ts +52 -52
- package/src/orm/entity-metadata.ts +140 -0
- package/src/{runtime → orm}/entity.ts +252 -252
- package/src/{runtime → orm}/execute.ts +36 -36
- package/src/{runtime → orm}/hydration.ts +103 -103
- package/src/orm/identity-map.ts +37 -0
- package/src/{runtime → orm}/lazy-batch.ts +205 -205
- package/src/orm/orm-context.ts +154 -0
- package/src/orm/relation-change-processor.ts +140 -0
- package/src/{runtime → orm}/relations/belongs-to.ts +92 -92
- package/src/{runtime → orm}/relations/has-many.ts +111 -111
- package/src/{runtime → orm}/relations/many-to-many.ts +149 -149
- package/src/orm/runtime-types.ts +39 -0
- package/src/orm/transaction-runner.ts +17 -0
- package/src/orm/unit-of-work.ts +232 -0
- package/src/{builder/operations → query-builder}/column-selector.ts +78 -78
- package/src/{builder → query-builder}/delete-query-state.ts +38 -42
- package/src/{builder → query-builder}/delete.ts +46 -57
- package/src/{builder → query-builder}/hydration-manager.ts +87 -87
- package/src/{builder → query-builder}/hydration-planner.ts +182 -182
- package/src/{builder → query-builder}/insert-query-state.ts +51 -62
- package/src/{builder → query-builder}/insert.ts +48 -59
- package/src/{builder → query-builder}/query-ast-service.ts +208 -226
- package/src/{utils → query-builder}/raw-column-parser.ts +32 -32
- package/src/{builder → query-builder}/relation-conditions.ts +112 -112
- package/src/{builder/operations → query-builder}/relation-manager.ts +82 -82
- package/src/{builder → query-builder}/relation-projection-helper.ts +101 -101
- package/src/{builder → query-builder}/relation-service.ts +284 -284
- package/src/{builder → query-builder}/relation-types.ts +21 -21
- package/src/{builder → query-builder}/relation-utils.ts +12 -12
- package/src/{builder → query-builder}/select-query-builder-deps.ts +112 -94
- package/src/{builder → query-builder}/select-query-state.ts +179 -179
- package/src/{builder → query-builder}/select.ts +78 -69
- package/src/{builder → query-builder}/update-query-state.ts +55 -59
- package/src/{builder → query-builder}/update.ts +50 -61
- package/src/schema/column.ts +25 -25
- package/src/schema/relation.ts +116 -116
- package/src/schema/table.ts +34 -34
- package/src/schema/types.ts +76 -76
- package/.github/workflows/publish-metal-orm.yml +0 -38
- package/ROADMAP.md +0 -125
- package/docs/CHANGES.md +0 -104
- package/docs/advanced-features.md +0 -176
- package/docs/api-reference.md +0 -31
- package/docs/dml-operations.md +0 -156
- package/docs/getting-started.md +0 -171
- package/docs/hydration.md +0 -115
- package/docs/index.md +0 -36
- package/docs/multi-dialect-support.md +0 -59
- package/docs/query-builder.md +0 -135
- package/docs/runtime.md +0 -105
- package/docs/schema-definition.md +0 -112
- package/metadata.json +0 -5
- package/playground/api/playground-api.ts +0 -94
- package/playground/index.html +0 -15
- package/playground/src/App.css +0 -1
- package/playground/src/App.tsx +0 -114
- package/playground/src/components/CodeDisplay.tsx +0 -43
- package/playground/src/components/QueryExecutor.tsx +0 -189
- package/playground/src/components/ResultsTable.tsx +0 -67
- package/playground/src/components/ResultsTabs.tsx +0 -105
- package/playground/src/components/ScenarioList.tsx +0 -56
- package/playground/src/components/logo.svg +0 -45
- package/playground/src/data/scenarios.ts +0 -2
- package/playground/src/main.tsx +0 -9
- package/playground/src/services/PlaygroundApiService.ts +0 -60
- package/postcss.config.cjs +0 -5
- package/sql_sql-ansi-cheatsheet-2025.md +0 -264
- package/src/ast/expression.ts +0 -658
- package/src/builder/operations/cte-manager.ts +0 -34
- package/src/builder/operations/filter-manager.ts +0 -68
- package/src/builder/operations/join-manager.ts +0 -36
- package/src/builder/operations/pagination-manager.ts +0 -36
- package/src/playground/features/playground/api/types.ts +0 -16
- package/src/playground/features/playground/clients/MockClient.ts +0 -17
- package/src/playground/features/playground/clients/SqliteClient.ts +0 -57
- package/src/playground/features/playground/common/IDatabaseClient.ts +0 -10
- package/src/playground/features/playground/data/scenarios/aggregation.ts +0 -36
- package/src/playground/features/playground/data/scenarios/basics.ts +0 -25
- package/src/playground/features/playground/data/scenarios/edge_cases.ts +0 -57
- package/src/playground/features/playground/data/scenarios/filtering.ts +0 -94
- package/src/playground/features/playground/data/scenarios/hydration.ts +0 -27
- package/src/playground/features/playground/data/scenarios/index.ts +0 -29
- package/src/playground/features/playground/data/scenarios/ordering.ts +0 -25
- package/src/playground/features/playground/data/scenarios/pagination.ts +0 -16
- package/src/playground/features/playground/data/scenarios/relationships.ts +0 -75
- package/src/playground/features/playground/data/scenarios/types.ts +0 -70
- package/src/playground/features/playground/data/schema.ts +0 -91
- package/src/playground/features/playground/data/seed.ts +0 -104
- package/src/playground/features/playground/services/QueryExecutionService.ts +0 -121
- package/src/runtime/orm-context.ts +0 -539
- package/tests/belongs-to-many.test.ts +0 -57
- package/tests/between.test.ts +0 -43
- package/tests/case-expression.test.ts +0 -58
- package/tests/complex-exists.test.ts +0 -230
- package/tests/cte.test.ts +0 -118
- package/tests/dml.test.ts +0 -206
- package/tests/exists.test.ts +0 -127
- package/tests/like.test.ts +0 -33
- package/tests/orm-runtime.test.ts +0 -254
- package/tests/postgres.test.ts +0 -30
- package/tests/right-join.test.ts +0 -89
- package/tests/subquery-having.test.ts +0 -193
- package/tests/window-function.test.ts +0 -151
- package/tsconfig.json +0 -30
- package/tsup.config.ts +0 -10
- package/vite.config.ts +0 -22
- package/vitest.config.ts +0 -14
- /package/src/{constants → core/sql}/sql.ts +0 -0
- /package/src/{runtime → orm}/als.ts +0 -0
- /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
|
-
```
|
package/docs/api-reference.md
DELETED
|
@@ -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
|
package/docs/dml-operations.md
DELETED
|
@@ -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.
|
package/docs/getting-started.md
DELETED
|
@@ -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.
|