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.
Files changed (153) hide show
  1. package/README.md +12 -1
  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
@@ -1,112 +1,112 @@
1
- import { TableDef } from '../schema/table';
2
- import { RelationDef, RelationKinds, BelongsToManyRelation } from '../schema/relation';
3
- import { ExpressionNode, eq, and } from '../ast/expression';
4
- import { findPrimaryKey } from './hydration-planner';
5
- import { JoinNode } from '../ast/join';
6
- import { JoinKind } from '../constants/sql';
7
- import { createJoinNode } from '../utils/join-node';
8
-
9
- /**
10
- * Utility function to handle unreachable code paths
11
- * @param value - Value that should never occur
12
- * @throws Error indicating unhandled relation type
13
- */
14
- const assertNever = (value: never): never => {
15
- throw new Error(`Unhandled relation type: ${JSON.stringify(value)}`);
16
- };
17
-
18
- /**
19
- * Builds the base condition for a relation join
20
- * @param root - Root table definition
21
- * @param relation - Relation definition
22
- * @returns Expression node representing the join condition
23
- */
24
- const baseRelationCondition = (root: TableDef, relation: RelationDef): ExpressionNode => {
25
- const defaultLocalKey =
26
- relation.type === RelationKinds.HasMany
27
- ? findPrimaryKey(root)
28
- : findPrimaryKey(relation.target);
29
- const localKey = relation.localKey || defaultLocalKey;
30
-
31
- switch (relation.type) {
32
- case RelationKinds.HasMany:
33
- return eq(
34
- { type: 'Column', table: relation.target.name, name: relation.foreignKey },
35
- { type: 'Column', table: root.name, name: localKey }
36
- );
37
- case RelationKinds.BelongsTo:
38
- return eq(
39
- { type: 'Column', table: relation.target.name, name: localKey },
40
- { type: 'Column', table: root.name, name: relation.foreignKey }
41
- );
42
- case RelationKinds.BelongsToMany:
43
- throw new Error('BelongsToMany relations do not support the standard join condition builder');
44
- default:
45
- return assertNever(relation);
46
- }
47
- };
48
-
49
- /**
50
- * Builds the join nodes required to include a BelongsToMany relation.
51
- */
52
- export const buildBelongsToManyJoins = (
53
- root: TableDef,
54
- relationName: string,
55
- relation: BelongsToManyRelation,
56
- joinKind: JoinKind,
57
- extra?: ExpressionNode
58
- ): JoinNode[] => {
59
- const rootKey = relation.localKey || findPrimaryKey(root);
60
- const targetKey = relation.targetKey || findPrimaryKey(relation.target);
61
-
62
- const pivotCondition = eq(
63
- { type: 'Column', table: relation.pivotTable.name, name: relation.pivotForeignKeyToRoot },
64
- { type: 'Column', table: root.name, name: rootKey }
65
- );
66
-
67
- const pivotJoin = createJoinNode(joinKind, relation.pivotTable.name, pivotCondition);
68
-
69
- let targetCondition: ExpressionNode = eq(
70
- { type: 'Column', table: relation.target.name, name: targetKey },
71
- { type: 'Column', table: relation.pivotTable.name, name: relation.pivotForeignKeyToTarget }
72
- );
73
-
74
- if (extra) {
75
- targetCondition = and(targetCondition, extra);
76
- }
77
-
78
- const targetJoin = createJoinNode(
79
- joinKind,
80
- relation.target.name,
81
- targetCondition,
82
- relationName
83
- );
84
-
85
- return [pivotJoin, targetJoin];
86
- };
87
-
88
- /**
89
- * Builds a relation join condition with optional extra conditions
90
- * @param root - Root table definition
91
- * @param relation - Relation definition
92
- * @param extra - Optional additional expression to combine with AND
93
- * @returns Expression node representing the complete join condition
94
- */
95
- export const buildRelationJoinCondition = (
96
- root: TableDef,
97
- relation: RelationDef,
98
- extra?: ExpressionNode
99
- ): ExpressionNode => {
100
- const base = baseRelationCondition(root, relation);
101
- return extra ? and(base, extra) : base;
102
- };
103
-
104
- /**
105
- * Builds a relation correlation condition for subqueries
106
- * @param root - Root table definition
107
- * @param relation - Relation definition
108
- * @returns Expression node representing the correlation condition
109
- */
110
- export const buildRelationCorrelation = (root: TableDef, relation: RelationDef): ExpressionNode => {
111
- return baseRelationCondition(root, relation);
112
- };
1
+ import { TableDef } from '../schema/table.js';
2
+ import { RelationDef, RelationKinds, BelongsToManyRelation } from '../schema/relation.js';
3
+ import { ExpressionNode, eq, and } from '../core/ast/expression.js';
4
+ import { findPrimaryKey } from './hydration-planner.js';
5
+ import { JoinNode } from '../core/ast/join.js';
6
+ import { JoinKind } from '../core/sql/sql.js';
7
+ import { createJoinNode } from '../core/ast/join-node.js';
8
+
9
+ /**
10
+ * Utility function to handle unreachable code paths
11
+ * @param value - Value that should never occur
12
+ * @throws Error indicating unhandled relation type
13
+ */
14
+ const assertNever = (value: never): never => {
15
+ throw new Error(`Unhandled relation type: ${JSON.stringify(value)}`);
16
+ };
17
+
18
+ /**
19
+ * Builds the base condition for a relation join
20
+ * @param root - Root table definition
21
+ * @param relation - Relation definition
22
+ * @returns Expression node representing the join condition
23
+ */
24
+ const baseRelationCondition = (root: TableDef, relation: RelationDef): ExpressionNode => {
25
+ const defaultLocalKey =
26
+ relation.type === RelationKinds.HasMany
27
+ ? findPrimaryKey(root)
28
+ : findPrimaryKey(relation.target);
29
+ const localKey = relation.localKey || defaultLocalKey;
30
+
31
+ switch (relation.type) {
32
+ case RelationKinds.HasMany:
33
+ return eq(
34
+ { type: 'Column', table: relation.target.name, name: relation.foreignKey },
35
+ { type: 'Column', table: root.name, name: localKey }
36
+ );
37
+ case RelationKinds.BelongsTo:
38
+ return eq(
39
+ { type: 'Column', table: relation.target.name, name: localKey },
40
+ { type: 'Column', table: root.name, name: relation.foreignKey }
41
+ );
42
+ case RelationKinds.BelongsToMany:
43
+ throw new Error('BelongsToMany relations do not support the standard join condition builder');
44
+ default:
45
+ return assertNever(relation);
46
+ }
47
+ };
48
+
49
+ /**
50
+ * Builds the join nodes required to include a BelongsToMany relation.
51
+ */
52
+ export const buildBelongsToManyJoins = (
53
+ root: TableDef,
54
+ relationName: string,
55
+ relation: BelongsToManyRelation,
56
+ joinKind: JoinKind,
57
+ extra?: ExpressionNode
58
+ ): JoinNode[] => {
59
+ const rootKey = relation.localKey || findPrimaryKey(root);
60
+ const targetKey = relation.targetKey || findPrimaryKey(relation.target);
61
+
62
+ const pivotCondition = eq(
63
+ { type: 'Column', table: relation.pivotTable.name, name: relation.pivotForeignKeyToRoot },
64
+ { type: 'Column', table: root.name, name: rootKey }
65
+ );
66
+
67
+ const pivotJoin = createJoinNode(joinKind, relation.pivotTable.name, pivotCondition);
68
+
69
+ let targetCondition: ExpressionNode = eq(
70
+ { type: 'Column', table: relation.target.name, name: targetKey },
71
+ { type: 'Column', table: relation.pivotTable.name, name: relation.pivotForeignKeyToTarget }
72
+ );
73
+
74
+ if (extra) {
75
+ targetCondition = and(targetCondition, extra);
76
+ }
77
+
78
+ const targetJoin = createJoinNode(
79
+ joinKind,
80
+ relation.target.name,
81
+ targetCondition,
82
+ relationName
83
+ );
84
+
85
+ return [pivotJoin, targetJoin];
86
+ };
87
+
88
+ /**
89
+ * Builds a relation join condition with optional extra conditions
90
+ * @param root - Root table definition
91
+ * @param relation - Relation definition
92
+ * @param extra - Optional additional expression to combine with AND
93
+ * @returns Expression node representing the complete join condition
94
+ */
95
+ export const buildRelationJoinCondition = (
96
+ root: TableDef,
97
+ relation: RelationDef,
98
+ extra?: ExpressionNode
99
+ ): ExpressionNode => {
100
+ const base = baseRelationCondition(root, relation);
101
+ return extra ? and(base, extra) : base;
102
+ };
103
+
104
+ /**
105
+ * Builds a relation correlation condition for subqueries
106
+ * @param root - Root table definition
107
+ * @param relation - Relation definition
108
+ * @returns Expression node representing the correlation condition
109
+ */
110
+ export const buildRelationCorrelation = (root: TableDef, relation: RelationDef): ExpressionNode => {
111
+ return baseRelationCondition(root, relation);
112
+ };
@@ -1,82 +1,82 @@
1
- import { ExpressionNode } from '../../ast/expression';
2
- import { SelectQueryNode } from '../../ast/query';
3
- import { SelectQueryBuilderContext, SelectQueryBuilderEnvironment } from '../select-query-builder-deps';
4
- import { JoinKind } from '../../constants/sql';
5
- import { RelationIncludeOptions } from '../relation-types';
6
-
7
- /**
8
- * Manages relation operations (joins, includes, etc.) for query building
9
- */
10
- export class RelationManager {
11
- /**
12
- * Creates a new RelationManager instance
13
- * @param env - Query builder environment
14
- */
15
- constructor(private readonly env: SelectQueryBuilderEnvironment) {}
16
-
17
- /**
18
- * Matches records based on a relation with an optional predicate
19
- * @param context - Current query context
20
- * @param relationName - Name of the relation to match
21
- * @param predicate - Optional predicate expression
22
- * @returns Updated query context with relation match
23
- */
24
- match(context: SelectQueryBuilderContext, relationName: string, predicate?: ExpressionNode): SelectQueryBuilderContext {
25
- const result = this.createService(context).match(relationName, predicate);
26
- return { state: result.state, hydration: result.hydration };
27
- }
28
-
29
- /**
30
- * Joins a relation to the query
31
- * @param context - Current query context
32
- * @param relationName - Name of the relation to join
33
- * @param joinKind - Type of join to use
34
- * @param extraCondition - Additional join condition
35
- * @returns Updated query context with relation join
36
- */
37
- joinRelation(
38
- context: SelectQueryBuilderContext,
39
- relationName: string,
40
- joinKind: JoinKind,
41
- extraCondition?: ExpressionNode
42
- ): SelectQueryBuilderContext {
43
- const result = this.createService(context).joinRelation(relationName, joinKind, extraCondition);
44
- return { state: result.state, hydration: result.hydration };
45
- }
46
-
47
- /**
48
- * Includes a relation in the query result
49
- * @param context - Current query context
50
- * @param relationName - Name of the relation to include
51
- * @param options - Options for relation inclusion
52
- * @returns Updated query context with included relation
53
- */
54
- include(
55
- context: SelectQueryBuilderContext,
56
- relationName: string,
57
- options?: RelationIncludeOptions
58
- ): SelectQueryBuilderContext {
59
- const result = this.createService(context).include(relationName, options);
60
- return { state: result.state, hydration: result.hydration };
61
- }
62
-
63
- /**
64
- * Applies relation correlation to a query AST
65
- * @param context - Current query context
66
- * @param relationName - Name of the relation
67
- * @param ast - Query AST to modify
68
- * @returns Modified query AST with relation correlation
69
- */
70
- applyRelationCorrelation(context: SelectQueryBuilderContext, relationName: string, ast: SelectQueryNode): SelectQueryNode {
71
- return this.createService(context).applyRelationCorrelation(relationName, ast);
72
- }
73
-
74
- /**
75
- * Creates a relation service instance
76
- * @param context - Current query context
77
- * @returns Relation service instance
78
- */
79
- private createService(context: SelectQueryBuilderContext) {
80
- return this.env.deps.createRelationService(this.env.table, context.state, context.hydration);
81
- }
82
- }
1
+ import { ExpressionNode } from '../core/ast/expression.js';
2
+ import { SelectQueryNode } from '../core/ast/query.js';
3
+ import { SelectQueryBuilderContext, SelectQueryBuilderEnvironment } from './select-query-builder-deps.js';
4
+ import { JoinKind } from '../core/sql/sql.js';
5
+ import { RelationIncludeOptions } from './relation-types.js';
6
+
7
+ /**
8
+ * Manages relation operations (joins, includes, etc.) for query building
9
+ */
10
+ export class RelationManager {
11
+ /**
12
+ * Creates a new RelationManager instance
13
+ * @param env - Query builder environment
14
+ */
15
+ constructor(private readonly env: SelectQueryBuilderEnvironment) {}
16
+
17
+ /**
18
+ * Matches records based on a relation with an optional predicate
19
+ * @param context - Current query context
20
+ * @param relationName - Name of the relation to match
21
+ * @param predicate - Optional predicate expression
22
+ * @returns Updated query context with relation match
23
+ */
24
+ match(context: SelectQueryBuilderContext, relationName: string, predicate?: ExpressionNode): SelectQueryBuilderContext {
25
+ const result = this.createService(context).match(relationName, predicate);
26
+ return { state: result.state, hydration: result.hydration };
27
+ }
28
+
29
+ /**
30
+ * Joins a relation to the query
31
+ * @param context - Current query context
32
+ * @param relationName - Name of the relation to join
33
+ * @param joinKind - Type of join to use
34
+ * @param extraCondition - Additional join condition
35
+ * @returns Updated query context with relation join
36
+ */
37
+ joinRelation(
38
+ context: SelectQueryBuilderContext,
39
+ relationName: string,
40
+ joinKind: JoinKind,
41
+ extraCondition?: ExpressionNode
42
+ ): SelectQueryBuilderContext {
43
+ const result = this.createService(context).joinRelation(relationName, joinKind, extraCondition);
44
+ return { state: result.state, hydration: result.hydration };
45
+ }
46
+
47
+ /**
48
+ * Includes a relation in the query result
49
+ * @param context - Current query context
50
+ * @param relationName - Name of the relation to include
51
+ * @param options - Options for relation inclusion
52
+ * @returns Updated query context with included relation
53
+ */
54
+ include(
55
+ context: SelectQueryBuilderContext,
56
+ relationName: string,
57
+ options?: RelationIncludeOptions
58
+ ): SelectQueryBuilderContext {
59
+ const result = this.createService(context).include(relationName, options);
60
+ return { state: result.state, hydration: result.hydration };
61
+ }
62
+
63
+ /**
64
+ * Applies relation correlation to a query AST
65
+ * @param context - Current query context
66
+ * @param relationName - Name of the relation
67
+ * @param ast - Query AST to modify
68
+ * @returns Modified query AST with relation correlation
69
+ */
70
+ applyRelationCorrelation(context: SelectQueryBuilderContext, relationName: string, ast: SelectQueryNode): SelectQueryNode {
71
+ return this.createService(context).applyRelationCorrelation(relationName, ast);
72
+ }
73
+
74
+ /**
75
+ * Creates a relation service instance
76
+ * @param context - Current query context
77
+ * @returns Relation service instance
78
+ */
79
+ private createService(context: SelectQueryBuilderContext) {
80
+ return this.env.deps.createRelationService(this.env.table, context.state, context.hydration);
81
+ }
82
+ }
@@ -1,101 +1,101 @@
1
- import { TableDef } from '../schema/table';
2
- import { ColumnDef } from '../schema/column';
3
- import { SelectQueryState } from './select-query-state';
4
- import { HydrationManager } from './hydration-manager';
5
- import { ColumnNode } from '../ast/expression';
6
- import { findPrimaryKey } from './hydration-planner';
7
- import { isRelationAlias } from '../utils/relation-alias';
8
-
9
- /**
10
- * Result of a relation operation
11
- */
12
- export interface RelationResult {
13
- /**
14
- * Updated query state
15
- */
16
- state: SelectQueryState;
17
- /**
18
- * Updated hydration manager
19
- */
20
- hydration: HydrationManager;
21
- }
22
-
23
- /**
24
- * Callback function for selecting columns
25
- */
26
- type SelectColumnsCallback = (
27
- state: SelectQueryState,
28
- hydration: HydrationManager,
29
- columns: Record<string, ColumnDef>
30
- ) => RelationResult;
31
-
32
- /**
33
- * Helper class for managing relation projections in queries
34
- */
35
- export class RelationProjectionHelper {
36
- /**
37
- * Creates a new RelationProjectionHelper instance
38
- * @param table - Table definition
39
- * @param selectColumns - Callback for selecting columns
40
- */
41
- constructor(
42
- private readonly table: TableDef,
43
- private readonly selectColumns: SelectColumnsCallback
44
- ) {}
45
-
46
- /**
47
- * Ensures base projection is included in the query
48
- * @param state - Current query state
49
- * @param hydration - Hydration manager
50
- * @returns Relation result with updated state and hydration
51
- */
52
- ensureBaseProjection(state: SelectQueryState, hydration: HydrationManager): RelationResult {
53
- const primaryKey = findPrimaryKey(this.table);
54
-
55
- if (!this.hasBaseProjection(state)) {
56
- return this.selectColumns(state, hydration, this.getBaseColumns());
57
- }
58
-
59
- if (primaryKey && !this.hasPrimarySelected(state, primaryKey) && this.table.columns[primaryKey]) {
60
- return this.selectColumns(state, hydration, {
61
- [primaryKey]: this.table.columns[primaryKey]
62
- });
63
- }
64
-
65
- return { state, hydration };
66
- }
67
-
68
- /**
69
- * Checks if base projection exists in the query
70
- * @param state - Current query state
71
- * @returns True if base projection exists
72
- */
73
- private hasBaseProjection(state: SelectQueryState): boolean {
74
- return state.ast.columns.some(col => !isRelationAlias((col as ColumnNode).alias));
75
- }
76
-
77
- /**
78
- * Checks if primary key is selected in the query
79
- * @param state - Current query state
80
- * @param primaryKey - Primary key name
81
- * @returns True if primary key is selected
82
- */
83
- private hasPrimarySelected(state: SelectQueryState, primaryKey: string): boolean {
84
- return state.ast.columns.some(col => {
85
- const alias = (col as ColumnNode).alias;
86
- const name = alias || (col as ColumnNode).name;
87
- return !isRelationAlias(alias) && name === primaryKey;
88
- });
89
- }
90
-
91
- /**
92
- * Gets all base columns for the table
93
- * @returns Record of all table columns
94
- */
95
- private getBaseColumns(): Record<string, ColumnDef> {
96
- return Object.keys(this.table.columns).reduce((acc, key) => {
97
- acc[key] = (this.table.columns as Record<string, ColumnDef>)[key];
98
- return acc;
99
- }, {} as Record<string, ColumnDef>);
100
- }
101
- }
1
+ import { TableDef } from '../schema/table.js';
2
+ import { ColumnDef } from '../schema/column.js';
3
+ import { SelectQueryState } from './select-query-state.js';
4
+ import { HydrationManager } from './hydration-manager.js';
5
+ import { ColumnNode } from '../core/ast/expression.js';
6
+ import { findPrimaryKey } from './hydration-planner.js';
7
+ import { isRelationAlias } from './relation-alias.js';
8
+
9
+ /**
10
+ * Result of a relation operation
11
+ */
12
+ export interface RelationResult {
13
+ /**
14
+ * Updated query state
15
+ */
16
+ state: SelectQueryState;
17
+ /**
18
+ * Updated hydration manager
19
+ */
20
+ hydration: HydrationManager;
21
+ }
22
+
23
+ /**
24
+ * Callback function for selecting columns
25
+ */
26
+ type SelectColumnsCallback = (
27
+ state: SelectQueryState,
28
+ hydration: HydrationManager,
29
+ columns: Record<string, ColumnDef>
30
+ ) => RelationResult;
31
+
32
+ /**
33
+ * Helper class for managing relation projections in queries
34
+ */
35
+ export class RelationProjectionHelper {
36
+ /**
37
+ * Creates a new RelationProjectionHelper instance
38
+ * @param table - Table definition
39
+ * @param selectColumns - Callback for selecting columns
40
+ */
41
+ constructor(
42
+ private readonly table: TableDef,
43
+ private readonly selectColumns: SelectColumnsCallback
44
+ ) {}
45
+
46
+ /**
47
+ * Ensures base projection is included in the query
48
+ * @param state - Current query state
49
+ * @param hydration - Hydration manager
50
+ * @returns Relation result with updated state and hydration
51
+ */
52
+ ensureBaseProjection(state: SelectQueryState, hydration: HydrationManager): RelationResult {
53
+ const primaryKey = findPrimaryKey(this.table);
54
+
55
+ if (!this.hasBaseProjection(state)) {
56
+ return this.selectColumns(state, hydration, this.getBaseColumns());
57
+ }
58
+
59
+ if (primaryKey && !this.hasPrimarySelected(state, primaryKey) && this.table.columns[primaryKey]) {
60
+ return this.selectColumns(state, hydration, {
61
+ [primaryKey]: this.table.columns[primaryKey]
62
+ });
63
+ }
64
+
65
+ return { state, hydration };
66
+ }
67
+
68
+ /**
69
+ * Checks if base projection exists in the query
70
+ * @param state - Current query state
71
+ * @returns True if base projection exists
72
+ */
73
+ private hasBaseProjection(state: SelectQueryState): boolean {
74
+ return state.ast.columns.some(col => !isRelationAlias((col as ColumnNode).alias));
75
+ }
76
+
77
+ /**
78
+ * Checks if primary key is selected in the query
79
+ * @param state - Current query state
80
+ * @param primaryKey - Primary key name
81
+ * @returns True if primary key is selected
82
+ */
83
+ private hasPrimarySelected(state: SelectQueryState, primaryKey: string): boolean {
84
+ return state.ast.columns.some(col => {
85
+ const alias = (col as ColumnNode).alias;
86
+ const name = alias || (col as ColumnNode).name;
87
+ return !isRelationAlias(alias) && name === primaryKey;
88
+ });
89
+ }
90
+
91
+ /**
92
+ * Gets all base columns for the table
93
+ * @returns Record of all table columns
94
+ */
95
+ private getBaseColumns(): Record<string, ColumnDef> {
96
+ return Object.keys(this.table.columns).reduce((acc, key) => {
97
+ acc[key] = (this.table.columns as Record<string, ColumnDef>)[key];
98
+ return acc;
99
+ }, {} as Record<string, ColumnDef>);
100
+ }
101
+ }