metal-orm 1.0.8 → 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 +12 -1
- 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/src/schema/relation.ts
CHANGED
|
@@ -1,69 +1,69 @@
|
|
|
1
|
-
import { TableDef } from './table';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Types of relationships supported between tables
|
|
5
|
-
*/
|
|
6
|
-
export const RelationKinds = {
|
|
7
|
-
/** One-to-many relationship */
|
|
8
|
-
HasMany: 'HAS_MANY',
|
|
9
|
-
/** Many-to-one relationship */
|
|
10
|
-
BelongsTo: 'BELONGS_TO',
|
|
11
|
-
/** Many-to-many relationship with pivot metadata */
|
|
12
|
-
BelongsToMany: 'BELONGS_TO_MANY'
|
|
13
|
-
} as const;
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Type representing the supported relationship kinds
|
|
17
|
-
*/
|
|
18
|
-
export type RelationType = (typeof RelationKinds)[keyof typeof RelationKinds];
|
|
19
|
-
|
|
20
|
-
export type CascadeMode = 'none' | 'all' | 'persist' | 'remove' | 'link';
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* One-to-many relationship definition
|
|
24
|
-
*/
|
|
25
|
-
export interface HasManyRelation<TTarget extends TableDef = TableDef> {
|
|
26
|
-
type: typeof RelationKinds.HasMany;
|
|
27
|
-
target: TTarget;
|
|
28
|
-
foreignKey: string;
|
|
29
|
-
localKey?: string;
|
|
30
|
-
cascade?: CascadeMode;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Many-to-one relationship definition
|
|
35
|
-
*/
|
|
36
|
-
export interface BelongsToRelation<TTarget extends TableDef = TableDef> {
|
|
37
|
-
type: typeof RelationKinds.BelongsTo;
|
|
38
|
-
target: TTarget;
|
|
39
|
-
foreignKey: string;
|
|
40
|
-
localKey?: string;
|
|
41
|
-
cascade?: CascadeMode;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Many-to-many relationship definition with rich pivot metadata
|
|
46
|
-
*/
|
|
47
|
-
export interface BelongsToManyRelation<TTarget extends TableDef = TableDef> {
|
|
48
|
-
type: typeof RelationKinds.BelongsToMany;
|
|
49
|
-
target: TTarget;
|
|
50
|
-
pivotTable: TableDef;
|
|
51
|
-
pivotForeignKeyToRoot: string;
|
|
52
|
-
pivotForeignKeyToTarget: string;
|
|
53
|
-
localKey?: string;
|
|
54
|
-
targetKey?: string;
|
|
55
|
-
pivotPrimaryKey?: string;
|
|
56
|
-
defaultPivotColumns?: string[];
|
|
57
|
-
cascade?: CascadeMode;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Union type representing any supported relationship definition
|
|
62
|
-
*/
|
|
63
|
-
export type RelationDef =
|
|
64
|
-
| HasManyRelation
|
|
65
|
-
| BelongsToRelation
|
|
66
|
-
| BelongsToManyRelation;
|
|
1
|
+
import { TableDef } from './table.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Types of relationships supported between tables
|
|
5
|
+
*/
|
|
6
|
+
export const RelationKinds = {
|
|
7
|
+
/** One-to-many relationship */
|
|
8
|
+
HasMany: 'HAS_MANY',
|
|
9
|
+
/** Many-to-one relationship */
|
|
10
|
+
BelongsTo: 'BELONGS_TO',
|
|
11
|
+
/** Many-to-many relationship with pivot metadata */
|
|
12
|
+
BelongsToMany: 'BELONGS_TO_MANY'
|
|
13
|
+
} as const;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Type representing the supported relationship kinds
|
|
17
|
+
*/
|
|
18
|
+
export type RelationType = (typeof RelationKinds)[keyof typeof RelationKinds];
|
|
19
|
+
|
|
20
|
+
export type CascadeMode = 'none' | 'all' | 'persist' | 'remove' | 'link';
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* One-to-many relationship definition
|
|
24
|
+
*/
|
|
25
|
+
export interface HasManyRelation<TTarget extends TableDef = TableDef> {
|
|
26
|
+
type: typeof RelationKinds.HasMany;
|
|
27
|
+
target: TTarget;
|
|
28
|
+
foreignKey: string;
|
|
29
|
+
localKey?: string;
|
|
30
|
+
cascade?: CascadeMode;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Many-to-one relationship definition
|
|
35
|
+
*/
|
|
36
|
+
export interface BelongsToRelation<TTarget extends TableDef = TableDef> {
|
|
37
|
+
type: typeof RelationKinds.BelongsTo;
|
|
38
|
+
target: TTarget;
|
|
39
|
+
foreignKey: string;
|
|
40
|
+
localKey?: string;
|
|
41
|
+
cascade?: CascadeMode;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Many-to-many relationship definition with rich pivot metadata
|
|
46
|
+
*/
|
|
47
|
+
export interface BelongsToManyRelation<TTarget extends TableDef = TableDef> {
|
|
48
|
+
type: typeof RelationKinds.BelongsToMany;
|
|
49
|
+
target: TTarget;
|
|
50
|
+
pivotTable: TableDef;
|
|
51
|
+
pivotForeignKeyToRoot: string;
|
|
52
|
+
pivotForeignKeyToTarget: string;
|
|
53
|
+
localKey?: string;
|
|
54
|
+
targetKey?: string;
|
|
55
|
+
pivotPrimaryKey?: string;
|
|
56
|
+
defaultPivotColumns?: string[];
|
|
57
|
+
cascade?: CascadeMode;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Union type representing any supported relationship definition
|
|
62
|
+
*/
|
|
63
|
+
export type RelationDef =
|
|
64
|
+
| HasManyRelation
|
|
65
|
+
| BelongsToRelation
|
|
66
|
+
| BelongsToManyRelation;
|
|
67
67
|
|
|
68
68
|
/**
|
|
69
69
|
* Creates a one-to-many relationship definition
|
|
@@ -77,18 +77,18 @@ export type RelationDef =
|
|
|
77
77
|
* hasMany(usersTable, 'user_id')
|
|
78
78
|
* ```
|
|
79
79
|
*/
|
|
80
|
-
export const hasMany = <TTarget extends TableDef>(
|
|
81
|
-
target: TTarget,
|
|
82
|
-
foreignKey: string,
|
|
83
|
-
localKey?: string,
|
|
84
|
-
cascade?: CascadeMode
|
|
85
|
-
): HasManyRelation<TTarget> => ({
|
|
86
|
-
type: RelationKinds.HasMany,
|
|
87
|
-
target,
|
|
88
|
-
foreignKey,
|
|
89
|
-
localKey,
|
|
90
|
-
cascade
|
|
91
|
-
});
|
|
80
|
+
export const hasMany = <TTarget extends TableDef>(
|
|
81
|
+
target: TTarget,
|
|
82
|
+
foreignKey: string,
|
|
83
|
+
localKey?: string,
|
|
84
|
+
cascade?: CascadeMode
|
|
85
|
+
): HasManyRelation<TTarget> => ({
|
|
86
|
+
type: RelationKinds.HasMany,
|
|
87
|
+
target,
|
|
88
|
+
foreignKey,
|
|
89
|
+
localKey,
|
|
90
|
+
cascade
|
|
91
|
+
});
|
|
92
92
|
|
|
93
93
|
/**
|
|
94
94
|
* Creates a many-to-one relationship definition
|
|
@@ -102,18 +102,18 @@ export const hasMany = <TTarget extends TableDef>(
|
|
|
102
102
|
* belongsTo(usersTable, 'user_id')
|
|
103
103
|
* ```
|
|
104
104
|
*/
|
|
105
|
-
export const belongsTo = <TTarget extends TableDef>(
|
|
106
|
-
target: TTarget,
|
|
107
|
-
foreignKey: string,
|
|
108
|
-
localKey?: string,
|
|
109
|
-
cascade?: CascadeMode
|
|
110
|
-
): BelongsToRelation<TTarget> => ({
|
|
111
|
-
type: RelationKinds.BelongsTo,
|
|
112
|
-
target,
|
|
113
|
-
foreignKey,
|
|
114
|
-
localKey,
|
|
115
|
-
cascade
|
|
116
|
-
});
|
|
105
|
+
export const belongsTo = <TTarget extends TableDef>(
|
|
106
|
+
target: TTarget,
|
|
107
|
+
foreignKey: string,
|
|
108
|
+
localKey?: string,
|
|
109
|
+
cascade?: CascadeMode
|
|
110
|
+
): BelongsToRelation<TTarget> => ({
|
|
111
|
+
type: RelationKinds.BelongsTo,
|
|
112
|
+
target,
|
|
113
|
+
foreignKey,
|
|
114
|
+
localKey,
|
|
115
|
+
cascade
|
|
116
|
+
});
|
|
117
117
|
|
|
118
118
|
/**
|
|
119
119
|
* Creates a many-to-many relationship definition with pivot metadata
|
|
@@ -122,29 +122,29 @@ export const belongsTo = <TTarget extends TableDef>(
|
|
|
122
122
|
* @param options - Pivot metadata configuration
|
|
123
123
|
* @returns BelongsToManyRelation definition
|
|
124
124
|
*/
|
|
125
|
-
export const belongsToMany = <
|
|
126
|
-
TTarget extends TableDef
|
|
127
|
-
>(
|
|
128
|
-
target: TTarget,
|
|
129
|
-
pivotTable: TableDef,
|
|
130
|
-
options: {
|
|
131
|
-
pivotForeignKeyToRoot: string;
|
|
132
|
-
pivotForeignKeyToTarget: string;
|
|
133
|
-
localKey?: string;
|
|
134
|
-
targetKey?: string;
|
|
135
|
-
pivotPrimaryKey?: string;
|
|
136
|
-
defaultPivotColumns?: string[];
|
|
137
|
-
cascade?: CascadeMode;
|
|
138
|
-
}
|
|
139
|
-
): BelongsToManyRelation<TTarget> => ({
|
|
140
|
-
type: RelationKinds.BelongsToMany,
|
|
141
|
-
target,
|
|
142
|
-
pivotTable,
|
|
143
|
-
pivotForeignKeyToRoot: options.pivotForeignKeyToRoot,
|
|
144
|
-
pivotForeignKeyToTarget: options.pivotForeignKeyToTarget,
|
|
145
|
-
localKey: options.localKey,
|
|
146
|
-
targetKey: options.targetKey,
|
|
147
|
-
pivotPrimaryKey: options.pivotPrimaryKey,
|
|
148
|
-
defaultPivotColumns: options.defaultPivotColumns,
|
|
149
|
-
cascade: options.cascade
|
|
150
|
-
});
|
|
125
|
+
export const belongsToMany = <
|
|
126
|
+
TTarget extends TableDef
|
|
127
|
+
>(
|
|
128
|
+
target: TTarget,
|
|
129
|
+
pivotTable: TableDef,
|
|
130
|
+
options: {
|
|
131
|
+
pivotForeignKeyToRoot: string;
|
|
132
|
+
pivotForeignKeyToTarget: string;
|
|
133
|
+
localKey?: string;
|
|
134
|
+
targetKey?: string;
|
|
135
|
+
pivotPrimaryKey?: string;
|
|
136
|
+
defaultPivotColumns?: string[];
|
|
137
|
+
cascade?: CascadeMode;
|
|
138
|
+
}
|
|
139
|
+
): BelongsToManyRelation<TTarget> => ({
|
|
140
|
+
type: RelationKinds.BelongsToMany,
|
|
141
|
+
target,
|
|
142
|
+
pivotTable,
|
|
143
|
+
pivotForeignKeyToRoot: options.pivotForeignKeyToRoot,
|
|
144
|
+
pivotForeignKeyToTarget: options.pivotForeignKeyToTarget,
|
|
145
|
+
localKey: options.localKey,
|
|
146
|
+
targetKey: options.targetKey,
|
|
147
|
+
pivotPrimaryKey: options.pivotPrimaryKey,
|
|
148
|
+
defaultPivotColumns: options.defaultPivotColumns,
|
|
149
|
+
cascade: options.cascade
|
|
150
|
+
});
|
package/src/schema/table.ts
CHANGED
|
@@ -1,29 +1,29 @@
|
|
|
1
|
-
import { ColumnDef } from './column';
|
|
2
|
-
import { RelationDef } from './relation';
|
|
3
|
-
|
|
4
|
-
export interface TableHooks {
|
|
5
|
-
beforeInsert?(ctx: unknown, entity: any): Promise<void> | void;
|
|
6
|
-
afterInsert?(ctx: unknown, entity: any): Promise<void> | void;
|
|
7
|
-
beforeUpdate?(ctx: unknown, entity: any): Promise<void> | void;
|
|
8
|
-
afterUpdate?(ctx: unknown, entity: any): Promise<void> | void;
|
|
9
|
-
beforeDelete?(ctx: unknown, entity: any): Promise<void> | void;
|
|
10
|
-
afterDelete?(ctx: unknown, entity: any): Promise<void> | void;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Definition of a database table with its columns and relationships
|
|
15
|
-
* @typeParam T - Type of the columns record
|
|
16
|
-
*/
|
|
17
|
-
export interface TableDef<T extends Record<string, ColumnDef> = Record<string, ColumnDef>> {
|
|
18
|
-
/** Name of the table */
|
|
19
|
-
name: string;
|
|
20
|
-
/** Record of column definitions keyed by column name */
|
|
21
|
-
columns: T;
|
|
22
|
-
/** Record of relationship definitions keyed by relation name */
|
|
23
|
-
relations: Record<string, RelationDef>;
|
|
24
|
-
/** Optional lifecycle hooks */
|
|
25
|
-
hooks?: TableHooks;
|
|
26
|
-
}
|
|
1
|
+
import { ColumnDef } from './column.js';
|
|
2
|
+
import { RelationDef } from './relation.js';
|
|
3
|
+
|
|
4
|
+
export interface TableHooks {
|
|
5
|
+
beforeInsert?(ctx: unknown, entity: any): Promise<void> | void;
|
|
6
|
+
afterInsert?(ctx: unknown, entity: any): Promise<void> | void;
|
|
7
|
+
beforeUpdate?(ctx: unknown, entity: any): Promise<void> | void;
|
|
8
|
+
afterUpdate?(ctx: unknown, entity: any): Promise<void> | void;
|
|
9
|
+
beforeDelete?(ctx: unknown, entity: any): Promise<void> | void;
|
|
10
|
+
afterDelete?(ctx: unknown, entity: any): Promise<void> | void;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Definition of a database table with its columns and relationships
|
|
15
|
+
* @typeParam T - Type of the columns record
|
|
16
|
+
*/
|
|
17
|
+
export interface TableDef<T extends Record<string, ColumnDef> = Record<string, ColumnDef>> {
|
|
18
|
+
/** Name of the table */
|
|
19
|
+
name: string;
|
|
20
|
+
/** Record of column definitions keyed by column name */
|
|
21
|
+
columns: T;
|
|
22
|
+
/** Record of relationship definitions keyed by relation name */
|
|
23
|
+
relations: Record<string, RelationDef>;
|
|
24
|
+
/** Optional lifecycle hooks */
|
|
25
|
+
hooks?: TableHooks;
|
|
26
|
+
}
|
|
27
27
|
|
|
28
28
|
/**
|
|
29
29
|
* Creates a table definition with columns and relationships
|
|
@@ -42,17 +42,17 @@ export interface TableDef<T extends Record<string, ColumnDef> = Record<string, C
|
|
|
42
42
|
* });
|
|
43
43
|
* ```
|
|
44
44
|
*/
|
|
45
|
-
export const defineTable = <T extends Record<string, ColumnDef>>(
|
|
46
|
-
name: string,
|
|
47
|
-
columns: T,
|
|
48
|
-
relations: Record<string, RelationDef> = {},
|
|
49
|
-
hooks?: TableHooks
|
|
50
|
-
): TableDef<T> => {
|
|
45
|
+
export const defineTable = <T extends Record<string, ColumnDef>>(
|
|
46
|
+
name: string,
|
|
47
|
+
columns: T,
|
|
48
|
+
relations: Record<string, RelationDef> = {},
|
|
49
|
+
hooks?: TableHooks
|
|
50
|
+
): TableDef<T> => {
|
|
51
51
|
// Runtime mutability to assign names to column definitions for convenience
|
|
52
52
|
const colsWithNames = Object.entries(columns).reduce((acc, [key, def]) => {
|
|
53
53
|
(acc as any)[key] = { ...def, name: key, table: name };
|
|
54
54
|
return acc;
|
|
55
55
|
}, {} as T);
|
|
56
56
|
|
|
57
|
-
return { name, columns: colsWithNames, relations, hooks };
|
|
58
|
-
};
|
|
57
|
+
return { name, columns: colsWithNames, relations, hooks };
|
|
58
|
+
};
|
package/src/schema/types.ts
CHANGED
|
@@ -1,76 +1,76 @@
|
|
|
1
|
-
import { ColumnDef } from './column';
|
|
2
|
-
import { TableDef } from './table';
|
|
3
|
-
import {
|
|
4
|
-
RelationDef,
|
|
5
|
-
HasManyRelation,
|
|
6
|
-
BelongsToRelation,
|
|
7
|
-
BelongsToManyRelation
|
|
8
|
-
} from './relation';
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Maps a ColumnDef to its TypeScript type representation
|
|
12
|
-
*/
|
|
13
|
-
export type ColumnToTs<T extends ColumnDef> =
|
|
14
|
-
T['type'] extends 'INT' | 'INTEGER' | 'int' | 'integer' ? number :
|
|
15
|
-
T['type'] extends 'BOOLEAN' | 'boolean' ? boolean :
|
|
16
|
-
T['type'] extends 'JSON' | 'json' ? unknown :
|
|
17
|
-
string;
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Infers a row shape from a table definition
|
|
21
|
-
*/
|
|
22
|
-
export type InferRow<TTable extends TableDef> = {
|
|
23
|
-
[K in keyof TTable['columns']]: ColumnToTs<TTable['columns'][K]>;
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
type RelationResult<T extends RelationDef> =
|
|
27
|
-
T extends HasManyRelation<infer TTarget> ? InferRow<TTarget>[] :
|
|
28
|
-
T extends BelongsToRelation<infer TTarget> ? InferRow<TTarget> | null :
|
|
29
|
-
T extends BelongsToManyRelation<infer TTarget> ? (InferRow<TTarget> & { _pivot?: any })[] :
|
|
30
|
-
never;
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Maps relation names to the expected row results
|
|
34
|
-
*/
|
|
35
|
-
export type RelationMap<TTable extends TableDef> = {
|
|
36
|
-
[K in keyof TTable['relations']]: RelationResult<TTable['relations'][K]>;
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
export interface HasManyCollection<TChild> {
|
|
40
|
-
load(): Promise<TChild[]>;
|
|
41
|
-
getItems(): TChild[];
|
|
42
|
-
add(data: Partial<TChild>): TChild;
|
|
43
|
-
attach(entity: TChild): void;
|
|
44
|
-
remove(entity: TChild): void;
|
|
45
|
-
clear(): void;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export interface BelongsToReference<TParent> {
|
|
49
|
-
load(): Promise<TParent | null>;
|
|
50
|
-
get(): TParent | null;
|
|
51
|
-
set(data: Partial<TParent> | TParent | null): TParent | null;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export interface ManyToManyCollection<TTarget> {
|
|
55
|
-
load(): Promise<TTarget[]>;
|
|
56
|
-
getItems(): TTarget[];
|
|
57
|
-
attach(target: TTarget | number | string): void;
|
|
58
|
-
detach(target: TTarget | number | string): void;
|
|
59
|
-
syncByIds(ids: (number | string)[]): Promise<void>;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
export type Entity<
|
|
63
|
-
TTable extends TableDef,
|
|
64
|
-
TRow = InferRow<TTable>
|
|
65
|
-
> = TRow & {
|
|
66
|
-
[K in keyof RelationMap<TTable>]:
|
|
67
|
-
TTable['relations'][K] extends HasManyRelation<infer TTarget>
|
|
68
|
-
? HasManyCollection<Entity<TTarget>>
|
|
69
|
-
: TTable['relations'][K] extends BelongsToManyRelation<infer TTarget>
|
|
70
|
-
? ManyToManyCollection<Entity<TTarget>>
|
|
71
|
-
: TTable['relations'][K] extends BelongsToRelation<infer TTarget>
|
|
72
|
-
? BelongsToReference<Entity<TTarget>>
|
|
73
|
-
: never;
|
|
74
|
-
} & {
|
|
75
|
-
$load<K extends keyof RelationMap<TTable>>(relation: K): Promise<RelationMap<TTable>[K]>;
|
|
76
|
-
};
|
|
1
|
+
import { ColumnDef } from './column.js';
|
|
2
|
+
import { TableDef } from './table.js';
|
|
3
|
+
import {
|
|
4
|
+
RelationDef,
|
|
5
|
+
HasManyRelation,
|
|
6
|
+
BelongsToRelation,
|
|
7
|
+
BelongsToManyRelation
|
|
8
|
+
} from './relation.js';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Maps a ColumnDef to its TypeScript type representation
|
|
12
|
+
*/
|
|
13
|
+
export type ColumnToTs<T extends ColumnDef> =
|
|
14
|
+
T['type'] extends 'INT' | 'INTEGER' | 'int' | 'integer' ? number :
|
|
15
|
+
T['type'] extends 'BOOLEAN' | 'boolean' ? boolean :
|
|
16
|
+
T['type'] extends 'JSON' | 'json' ? unknown :
|
|
17
|
+
string;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Infers a row shape from a table definition
|
|
21
|
+
*/
|
|
22
|
+
export type InferRow<TTable extends TableDef> = {
|
|
23
|
+
[K in keyof TTable['columns']]: ColumnToTs<TTable['columns'][K]>;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
type RelationResult<T extends RelationDef> =
|
|
27
|
+
T extends HasManyRelation<infer TTarget> ? InferRow<TTarget>[] :
|
|
28
|
+
T extends BelongsToRelation<infer TTarget> ? InferRow<TTarget> | null :
|
|
29
|
+
T extends BelongsToManyRelation<infer TTarget> ? (InferRow<TTarget> & { _pivot?: any })[] :
|
|
30
|
+
never;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Maps relation names to the expected row results
|
|
34
|
+
*/
|
|
35
|
+
export type RelationMap<TTable extends TableDef> = {
|
|
36
|
+
[K in keyof TTable['relations']]: RelationResult<TTable['relations'][K]>;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export interface HasManyCollection<TChild> {
|
|
40
|
+
load(): Promise<TChild[]>;
|
|
41
|
+
getItems(): TChild[];
|
|
42
|
+
add(data: Partial<TChild>): TChild;
|
|
43
|
+
attach(entity: TChild): void;
|
|
44
|
+
remove(entity: TChild): void;
|
|
45
|
+
clear(): void;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export interface BelongsToReference<TParent> {
|
|
49
|
+
load(): Promise<TParent | null>;
|
|
50
|
+
get(): TParent | null;
|
|
51
|
+
set(data: Partial<TParent> | TParent | null): TParent | null;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export interface ManyToManyCollection<TTarget> {
|
|
55
|
+
load(): Promise<TTarget[]>;
|
|
56
|
+
getItems(): TTarget[];
|
|
57
|
+
attach(target: TTarget | number | string): void;
|
|
58
|
+
detach(target: TTarget | number | string): void;
|
|
59
|
+
syncByIds(ids: (number | string)[]): Promise<void>;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export type Entity<
|
|
63
|
+
TTable extends TableDef,
|
|
64
|
+
TRow = InferRow<TTable>
|
|
65
|
+
> = TRow & {
|
|
66
|
+
[K in keyof RelationMap<TTable>]:
|
|
67
|
+
TTable['relations'][K] extends HasManyRelation<infer TTarget>
|
|
68
|
+
? HasManyCollection<Entity<TTarget>>
|
|
69
|
+
: TTable['relations'][K] extends BelongsToManyRelation<infer TTarget>
|
|
70
|
+
? ManyToManyCollection<Entity<TTarget>>
|
|
71
|
+
: TTable['relations'][K] extends BelongsToRelation<infer TTarget>
|
|
72
|
+
? BelongsToReference<Entity<TTarget>>
|
|
73
|
+
: never;
|
|
74
|
+
} & {
|
|
75
|
+
$load<K extends keyof RelationMap<TTable>>(relation: K): Promise<RelationMap<TTable>[K]>;
|
|
76
|
+
};
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
name: Publish metal-orm to npm
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
branches:
|
|
6
|
-
- main
|
|
7
|
-
|
|
8
|
-
permissions:
|
|
9
|
-
contents: read
|
|
10
|
-
id-token: write # OIDC for Trusted Publishing
|
|
11
|
-
packages: write
|
|
12
|
-
|
|
13
|
-
jobs:
|
|
14
|
-
publish:
|
|
15
|
-
runs-on: ubuntu-latest
|
|
16
|
-
|
|
17
|
-
steps:
|
|
18
|
-
- name: Checkout
|
|
19
|
-
uses: actions/checkout@v4
|
|
20
|
-
|
|
21
|
-
- name: Setup Node
|
|
22
|
-
uses: actions/setup-node@v4
|
|
23
|
-
with:
|
|
24
|
-
node-version: '20'
|
|
25
|
-
registry-url: 'https://registry.npmjs.org'
|
|
26
|
-
|
|
27
|
-
- name: Install deps
|
|
28
|
-
run: npm ci
|
|
29
|
-
|
|
30
|
-
- name: Test
|
|
31
|
-
run: npm test
|
|
32
|
-
continue-on-error: true # ou remove se quiser quebrar se falhar
|
|
33
|
-
|
|
34
|
-
- name: Build
|
|
35
|
-
run: npm run build
|
|
36
|
-
|
|
37
|
-
- name: Publish (Trusted Publishing)
|
|
38
|
-
run: npm publish --provenance --access public
|
package/ROADMAP.md
DELETED
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
# Metal ORM Roadmap
|
|
2
|
-
|
|
3
|
-
## Current ORM Capabilities
|
|
4
|
-
|
|
5
|
-
The current implementation supports:
|
|
6
|
-
|
|
7
|
-
- Basic SELECT with projections and aliases
|
|
8
|
-
- INNER/LEFT JOINs with manual conditions
|
|
9
|
-
- Smart relationship joins via `joinRelation()`
|
|
10
|
-
- Eager loading with `include()` for 1:1 and 1:N relationships
|
|
11
|
-
- Basic WHERE clauses with operators (eq, gt, like, in, null checks)
|
|
12
|
-
- GROUP BY, ORDER BY, LIMIT, OFFSET
|
|
13
|
-
- Aggregation functions (COUNT, SUM, AVG)
|
|
14
|
-
- JSON path extraction (dialect-specific)
|
|
15
|
-
- Hydration of nested objects from flat SQL results
|
|
16
|
-
- EXISTS and NOT EXISTS subqueries
|
|
17
|
-
- Scalar correlated subqueries in SELECT and WHERE
|
|
18
|
-
- CASE expressions (simple and searched)
|
|
19
|
-
- HAVING clause for post-aggregation filtering
|
|
20
|
-
|
|
21
|
-
## Identified Absences
|
|
22
|
-
|
|
23
|
-
### 1. CTE (Common Table Expressions) ✅
|
|
24
|
-
|
|
25
|
-
**Completed:** Full CTE support has been implemented
|
|
26
|
-
|
|
27
|
-
- Features: Simple CTEs, Recursive CTEs, Multiple CTEs, CTE with column aliases
|
|
28
|
-
- **Implementation:** CTE AST node and dialect compilation for SQLite, MySQL, and MSSQL
|
|
29
|
-
- Recursive CTEs properly handle the `WITH RECURSIVE` keyword (SQLite/MySQL only, MSSQL uses plain `WITH`)
|
|
30
|
-
- Mixed recursive and non-recursive CTEs are supported
|
|
31
|
-
|
|
32
|
-
### 2. Window Functions ✅
|
|
33
|
-
|
|
34
|
-
**Completed:** Comprehensive window function support has been implemented
|
|
35
|
-
|
|
36
|
-
- Features: `ROW_NUMBER()`, `RANK()`, `DENSE_RANK()`, `LAG()`, `LEAD()`, `NTILE()`, `FIRST_VALUE()`, `LAST_VALUE()`
|
|
37
|
-
- **Implementation:** Window function AST nodes with `PARTITION BY` and `ORDER BY` support
|
|
38
|
-
- All three dialects (SQLite, MySQL, MSSQL) support window functions
|
|
39
|
-
|
|
40
|
-
### 3. RIGHT JOIN Support
|
|
41
|
-
|
|
42
|
-
**Missing:** Only INNER, LEFT, and CROSS joins are defined
|
|
43
|
-
|
|
44
|
-
- **Required Addition:** RIGHT JOIN support in join.ts and dialect compilation
|
|
45
|
-
|
|
46
|
-
### 4. Complex Aggregation Functions
|
|
47
|
-
|
|
48
|
-
**Missing:** Limited aggregation functions
|
|
49
|
-
|
|
50
|
-
- Queries: `5-top-platform-contributor-per-project`, `5-mega-user-engagement-analytics`
|
|
51
|
-
- **Required Addition:** MIN, MAX, AVG functions, and GROUP_CONCAT
|
|
52
|
-
|
|
53
|
-
### 5. Parameterized Queries
|
|
54
|
-
|
|
55
|
-
**Missing:** No parameter binding support
|
|
56
|
-
|
|
57
|
-
- Queries: `1-1-parameterized-user-by-twitter`
|
|
58
|
-
- **Required Addition:** Parameter placeholder support and binding mechanism
|
|
59
|
-
|
|
60
|
-
### 6. Advanced JSON Operations
|
|
61
|
-
|
|
62
|
-
**Missing:** Limited JSON functionality
|
|
63
|
-
|
|
64
|
-
- Queries: `1-1-profile-json-as-subquery-column`, `5-mega-user-engagement-analytics`
|
|
65
|
-
- **Required Addition:** JSON_OBJECT, JSON_ARRAYAGG functions
|
|
66
|
-
|
|
67
|
-
### 7. Recursive CTEs ✅
|
|
68
|
-
|
|
69
|
-
**Completed:** See Section 1 (CTE) above
|
|
70
|
-
|
|
71
|
-
- Recursive CTEs are fully supported as part of the CTE implementation
|
|
72
|
-
|
|
73
|
-
### 8. Complex Ordering
|
|
74
|
-
|
|
75
|
-
**Missing:** Limited ORDER BY expressions
|
|
76
|
-
|
|
77
|
-
- Queries: `1-1-order-by-subquery-profile-field`, `5-mega-user-engagement-analytics`
|
|
78
|
-
- **Required Addition:** ORDER BY with expressions and NULLS FIRST/LAST
|
|
79
|
-
|
|
80
|
-
### 9. DISTINCT ON (PostgreSQL-style)
|
|
81
|
-
|
|
82
|
-
**Missing:** No DISTINCT ON support
|
|
83
|
-
|
|
84
|
-
- **Required Addition:** Dialect-specific DISTINCT ON compilation
|
|
85
|
-
|
|
86
|
-
### 10. Subquery Aliasing
|
|
87
|
-
|
|
88
|
-
**Missing:** No support for subqueries as derived tables
|
|
89
|
-
|
|
90
|
-
- **Required Addition:** Derived table AST node
|
|
91
|
-
|
|
92
|
-
### 11. Advanced EXISTS Patterns
|
|
93
|
-
|
|
94
|
-
**Missing:** EXISTS with complex correlated subqueries
|
|
95
|
-
|
|
96
|
-
- Queries: `1-1-boolean-flag-from-subquery-on-profile`
|
|
97
|
-
- **Required Addition:** Complex correlation support
|
|
98
|
-
|
|
99
|
-
## Priority Implementation Order
|
|
100
|
-
|
|
101
|
-
### Completed ✅
|
|
102
|
-
|
|
103
|
-
- ~~CTE support~~ (Completed)
|
|
104
|
-
- ~~Window functions~~ (Completed)
|
|
105
|
-
- ~~Recursive CTEs~~ (Completed)
|
|
106
|
-
|
|
107
|
-
### High Priority:
|
|
108
|
-
|
|
109
|
-
- Parameterized queries
|
|
110
|
-
- RIGHT JOIN
|
|
111
|
-
- Complex aggregation functions (MIN, MAX, GROUP_CONCAT)
|
|
112
|
-
|
|
113
|
-
### Medium Priority:
|
|
114
|
-
|
|
115
|
-
- Advanced JSON operations
|
|
116
|
-
- Complex ordering (expressions, NULLS FIRST/LAST)
|
|
117
|
-
|
|
118
|
-
### Lower Priority:
|
|
119
|
-
|
|
120
|
-
- Subquery Aliasing (Derived tables)
|
|
121
|
-
- Advanced EXISTS Patterns
|
|
122
|
-
|
|
123
|
-
## Implementation Notes
|
|
124
|
-
|
|
125
|
-
The current ORM is well-architected with a clear AST structure and dialect abstraction, making it relatively straightforward to add these missing features by extending the existing patterns.
|