metal-orm 1.0.13 → 1.0.15

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 (115) hide show
  1. package/README.md +75 -82
  2. package/dist/decorators/index.cjs +1600 -27
  3. package/dist/decorators/index.cjs.map +1 -1
  4. package/dist/decorators/index.d.cts +6 -2
  5. package/dist/decorators/index.d.ts +6 -2
  6. package/dist/decorators/index.js +1599 -27
  7. package/dist/decorators/index.js.map +1 -1
  8. package/dist/index.cjs +4608 -3429
  9. package/dist/index.cjs.map +1 -1
  10. package/dist/index.d.cts +511 -159
  11. package/dist/index.d.ts +511 -159
  12. package/dist/index.js +4526 -3415
  13. package/dist/index.js.map +1 -1
  14. package/dist/{select-CCp1oz9p.d.cts → select-Bkv8g8u_.d.cts} +193 -67
  15. package/dist/{select-CCp1oz9p.d.ts → select-Bkv8g8u_.d.ts} +193 -67
  16. package/package.json +1 -1
  17. package/src/codegen/typescript.ts +38 -35
  18. package/src/core/ast/adapters.ts +21 -0
  19. package/src/core/ast/aggregate-functions.ts +13 -13
  20. package/src/core/ast/builders.ts +56 -43
  21. package/src/core/ast/expression-builders.ts +34 -34
  22. package/src/core/ast/expression-nodes.ts +18 -16
  23. package/src/core/ast/expression-visitor.ts +122 -69
  24. package/src/core/ast/expression.ts +6 -4
  25. package/src/core/ast/join-metadata.ts +15 -0
  26. package/src/core/ast/join-node.ts +22 -20
  27. package/src/core/ast/join.ts +5 -5
  28. package/src/core/ast/query.ts +52 -88
  29. package/src/core/ast/types.ts +20 -0
  30. package/src/core/ast/window-functions.ts +55 -55
  31. package/src/core/ddl/dialects/base-schema-dialect.ts +20 -6
  32. package/src/core/ddl/dialects/mssql-schema-dialect.ts +32 -8
  33. package/src/core/ddl/dialects/mysql-schema-dialect.ts +21 -10
  34. package/src/core/ddl/dialects/postgres-schema-dialect.ts +52 -7
  35. package/src/core/ddl/dialects/sqlite-schema-dialect.ts +23 -9
  36. package/src/core/ddl/introspect/catalogs/index.ts +1 -0
  37. package/src/core/ddl/introspect/catalogs/postgres.ts +143 -0
  38. package/src/core/ddl/introspect/context.ts +9 -0
  39. package/src/core/ddl/introspect/functions/postgres.ts +26 -0
  40. package/src/core/ddl/introspect/mssql.ts +149 -149
  41. package/src/core/ddl/introspect/mysql.ts +99 -99
  42. package/src/core/ddl/introspect/postgres.ts +245 -154
  43. package/src/core/ddl/introspect/registry.ts +26 -0
  44. package/src/core/ddl/introspect/run-select.ts +25 -0
  45. package/src/core/ddl/introspect/sqlite.ts +7 -7
  46. package/src/core/ddl/introspect/types.ts +23 -19
  47. package/src/core/ddl/introspect/utils.ts +1 -1
  48. package/src/core/ddl/naming-strategy.ts +10 -0
  49. package/src/core/ddl/schema-dialect.ts +41 -0
  50. package/src/core/ddl/schema-diff.ts +211 -179
  51. package/src/core/ddl/schema-generator.ts +16 -90
  52. package/src/core/ddl/schema-introspect.ts +25 -32
  53. package/src/core/ddl/schema-plan-executor.ts +17 -0
  54. package/src/core/ddl/schema-types.ts +46 -39
  55. package/src/core/ddl/sql-writing.ts +170 -0
  56. package/src/core/dialect/abstract.ts +144 -126
  57. package/src/core/dialect/base/cte-compiler.ts +33 -0
  58. package/src/core/dialect/base/function-table-formatter.ts +132 -0
  59. package/src/core/dialect/base/groupby-compiler.ts +21 -0
  60. package/src/core/dialect/base/join-compiler.ts +26 -0
  61. package/src/core/dialect/base/orderby-compiler.ts +21 -0
  62. package/src/core/dialect/base/pagination-strategy.ts +32 -0
  63. package/src/core/dialect/base/returning-strategy.ts +56 -0
  64. package/src/core/dialect/base/sql-dialect.ts +181 -204
  65. package/src/core/dialect/dialect-factory.ts +91 -0
  66. package/src/core/dialect/mssql/functions.ts +101 -0
  67. package/src/core/dialect/mssql/index.ts +128 -126
  68. package/src/core/dialect/mysql/functions.ts +101 -0
  69. package/src/core/dialect/mysql/index.ts +20 -18
  70. package/src/core/dialect/postgres/functions.ts +95 -0
  71. package/src/core/dialect/postgres/index.ts +30 -28
  72. package/src/core/dialect/sqlite/functions.ts +115 -0
  73. package/src/core/dialect/sqlite/index.ts +30 -28
  74. package/src/core/driver/database-driver.ts +11 -0
  75. package/src/core/driver/mssql-driver.ts +20 -0
  76. package/src/core/driver/mysql-driver.ts +20 -0
  77. package/src/core/driver/postgres-driver.ts +20 -0
  78. package/src/core/driver/sqlite-driver.ts +20 -0
  79. package/src/core/execution/db-executor.ts +63 -0
  80. package/src/core/execution/executors/mssql-executor.ts +39 -0
  81. package/src/core/execution/executors/mysql-executor.ts +47 -0
  82. package/src/core/execution/executors/postgres-executor.ts +32 -0
  83. package/src/core/execution/executors/sqlite-executor.ts +31 -0
  84. package/src/core/functions/datetime.ts +132 -0
  85. package/src/core/functions/numeric.ts +179 -0
  86. package/src/core/functions/standard-strategy.ts +47 -0
  87. package/src/core/functions/text.ts +147 -0
  88. package/src/core/functions/types.ts +18 -0
  89. package/src/core/hydration/types.ts +57 -0
  90. package/src/decorators/bootstrap.ts +10 -0
  91. package/src/decorators/relations.ts +15 -0
  92. package/src/index.ts +30 -19
  93. package/src/orm/entity-metadata.ts +7 -0
  94. package/src/orm/entity.ts +58 -27
  95. package/src/orm/hydration.ts +25 -17
  96. package/src/orm/lazy-batch.ts +46 -2
  97. package/src/orm/orm-context.ts +60 -60
  98. package/src/orm/query-logger.ts +1 -1
  99. package/src/orm/relation-change-processor.ts +43 -2
  100. package/src/orm/relations/has-one.ts +139 -0
  101. package/src/orm/transaction-runner.ts +1 -1
  102. package/src/orm/unit-of-work.ts +60 -60
  103. package/src/query-builder/delete.ts +22 -5
  104. package/src/query-builder/hydration-manager.ts +2 -1
  105. package/src/query-builder/hydration-planner.ts +8 -7
  106. package/src/query-builder/insert.ts +22 -5
  107. package/src/query-builder/relation-conditions.ts +9 -8
  108. package/src/query-builder/relation-service.ts +3 -2
  109. package/src/query-builder/select.ts +66 -61
  110. package/src/query-builder/update.ts +22 -5
  111. package/src/schema/column.ts +246 -246
  112. package/src/schema/relation.ts +35 -1
  113. package/src/schema/table.ts +28 -28
  114. package/src/schema/types.ts +41 -31
  115. package/src/orm/db-executor.ts +0 -11
@@ -0,0 +1,179 @@
1
+ // Pure AST Builders - No Dialect Logic Here!
2
+
3
+ import { ColumnDef } from '../../schema/column.js';
4
+ import { columnOperand, valueToOperand } from '../ast/expression-builders.js';
5
+ import { FunctionNode, OperandNode, isOperandNode } from '../ast/expression.js';
6
+
7
+ type OperandInput = OperandNode | ColumnDef | string | number | boolean | null;
8
+
9
+ const isColumnDef = (val: any): val is ColumnDef => !!val && typeof val === 'object' && 'type' in val && 'name' in val;
10
+
11
+ const toOperand = (input: OperandInput): OperandNode => {
12
+ if (isOperandNode(input)) return input;
13
+ if (isColumnDef(input)) return columnOperand(input);
14
+ return valueToOperand(input as any);
15
+ };
16
+
17
+ const fn = (key: string, args: OperandInput[]): FunctionNode => ({
18
+ type: 'Function',
19
+ name: key,
20
+ fn: key,
21
+ args: args.map(toOperand)
22
+ });
23
+
24
+ // ----------------------
25
+ // Helper Functions
26
+ // ----------------------
27
+
28
+ /**
29
+ * Helper: ABS(x) - Returns the absolute value of a number
30
+ */
31
+ export const abs = (value: OperandInput): FunctionNode => fn('ABS', [value]);
32
+
33
+ /**
34
+ * Helper: ACOS(x) - Returns the arccosine (inverse cosine)
35
+ */
36
+ export const acos = (value: OperandInput): FunctionNode => fn('ACOS', [value]);
37
+
38
+ /**
39
+ * Helper: ASIN(x) - Returns the arcsine (inverse sine)
40
+ */
41
+ export const asin = (value: OperandInput): FunctionNode => fn('ASIN', [value]);
42
+
43
+ /**
44
+ * Helper: ATAN(x) - Returns the arctangent (inverse tangent)
45
+ */
46
+ export const atan = (value: OperandInput): FunctionNode => fn('ATAN', [value]);
47
+
48
+ /**
49
+ * Helper: ATAN2(y, x) - Returns the arctangent of the two arguments
50
+ */
51
+ export const atan2 = (y: OperandInput, x: OperandInput): FunctionNode => fn('ATAN2', [y, x]);
52
+
53
+ /**
54
+ * Helper: CEIL(x) / CEILING(x) - Returns the smallest integer >= x
55
+ */
56
+ export const ceil = (value: OperandInput): FunctionNode => fn('CEIL', [value]);
57
+
58
+ /**
59
+ * Helper: CEILING(x) - Alias for CEIL
60
+ */
61
+ export const ceiling = (value: OperandInput): FunctionNode => fn('CEILING', [value]);
62
+
63
+ /**
64
+ * Helper: COS(x) - Returns the cosine of a number (in radians)
65
+ */
66
+ export const cos = (value: OperandInput): FunctionNode => fn('COS', [value]);
67
+
68
+ /**
69
+ * Helper: COT(x) - Returns the cotangent of a number
70
+ */
71
+ export const cot = (value: OperandInput): FunctionNode => fn('COT', [value]);
72
+
73
+ /**
74
+ * Helper: DEGREES(x) - Converts radians to degrees
75
+ */
76
+ export const degrees = (value: OperandInput): FunctionNode => fn('DEGREES', [value]);
77
+
78
+ /**
79
+ * Helper: EXP(x) - Returns e raised to the power of the argument
80
+ */
81
+ export const exp = (value: OperandInput): FunctionNode => fn('EXP', [value]);
82
+
83
+ /**
84
+ * Helper: FLOOR(x) - Returns the largest integer <= x
85
+ */
86
+ export const floor = (value: OperandInput): FunctionNode => fn('FLOOR', [value]);
87
+
88
+ /**
89
+ * Helper: LN(x) - Returns the natural logarithm (base e)
90
+ */
91
+ export const ln = (value: OperandInput): FunctionNode => fn('LN', [value]);
92
+
93
+ /**
94
+ * Helper: LOG(x) - Returns the base-10 logarithm
95
+ */
96
+ export const log = (value: OperandInput): FunctionNode => fn('LOG', [value]);
97
+
98
+ /**
99
+ * Helper: LOG10(x) - Returns the base-10 logarithm
100
+ */
101
+ export const log10 = (value: OperandInput): FunctionNode => fn('LOG10', [value]);
102
+
103
+ /**
104
+ * Helper: LOG(base, x) - Returns the logarithm of x for a specific base
105
+ */
106
+ export const logBase = (base: OperandInput, value: OperandInput): FunctionNode => fn('LOG_BASE', [base, value]);
107
+
108
+ /**
109
+ * Helper: MOD(x, y) - Returns the remainder of x/y
110
+ */
111
+ export const mod = (x: OperandInput, y: OperandInput): FunctionNode => fn('MOD', [x, y]);
112
+
113
+ /**
114
+ * Helper: PI() - Returns the value of PI (approx. 3.14159...)
115
+ */
116
+ export const pi = (): FunctionNode => fn('PI', []);
117
+
118
+ /**
119
+ * Helper: POWER(x, y) - Returns x raised to the power of y
120
+ */
121
+ export const power = (x: OperandInput, y: OperandInput): FunctionNode => fn('POWER', [x, y]);
122
+
123
+ /**
124
+ * Helper: POW(x, y) - Alias for POWER
125
+ */
126
+ export const pow = (x: OperandInput, y: OperandInput): FunctionNode => fn('POW', [x, y]);
127
+
128
+ /**
129
+ * Helper: RADIANS(x) - Converts degrees to radians
130
+ */
131
+ export const radians = (value: OperandInput): FunctionNode => fn('RADIANS', [value]);
132
+
133
+ /**
134
+ * Helper: RAND() / RANDOM() - Returns a random number
135
+ */
136
+ export const random = (): FunctionNode => fn('RANDOM', []);
137
+
138
+ /**
139
+ * Helper: RAND() - Alias for RANDOM (returns float 0-1)
140
+ */
141
+ export const rand = (): FunctionNode => fn('RAND', []);
142
+
143
+ /**
144
+ * Helper: ROUND(x[, decimals]) - Rounds a number to specified decimal places
145
+ */
146
+ export const round = (value: OperandInput, decimals?: OperandInput): FunctionNode =>
147
+ decimals === undefined ? fn('ROUND', [value]) : fn('ROUND', [value, decimals]);
148
+
149
+ /**
150
+ * Helper: SIGN(x) - Returns the sign of a number (-1, 0, 1)
151
+ */
152
+ export const sign = (value: OperandInput): FunctionNode => fn('SIGN', [value]);
153
+
154
+ /**
155
+ * Helper: SIN(x) - Returns the sine of a number (in radians)
156
+ */
157
+ export const sin = (value: OperandInput): FunctionNode => fn('SIN', [value]);
158
+
159
+ /**
160
+ * Helper: SQRT(x) - Returns the square root of a number
161
+ */
162
+ export const sqrt = (value: OperandInput): FunctionNode => fn('SQRT', [value]);
163
+
164
+ /**
165
+ * Helper: TAN(x) - Returns the tangent of a number (in radians)
166
+ */
167
+ export const tan = (value: OperandInput): FunctionNode => fn('TAN', [value]);
168
+
169
+ /**
170
+ * Helper: TRUNC(x[, decimals]) / TRUNCATE(x, decimals) - Truncates a number without rounding
171
+ */
172
+ export const trunc = (value: OperandInput, decimals?: OperandInput): FunctionNode =>
173
+ decimals === undefined ? fn('TRUNC', [value]) : fn('TRUNC', [value, decimals]);
174
+
175
+ /**
176
+ * Helper: TRUNCATE(x, decimals) - Alias for TRUNC
177
+ */
178
+ export const truncate = (value: OperandInput, decimals: OperandInput): FunctionNode =>
179
+ fn('TRUNCATE', [value, decimals]);
@@ -0,0 +1,47 @@
1
+ import { FunctionStrategy, FunctionRenderer, FunctionRenderContext } from './types.js';
2
+
3
+ export class StandardFunctionStrategy implements FunctionStrategy {
4
+ protected renderers: Map<string, FunctionRenderer> = new Map();
5
+
6
+ constructor() {
7
+ this.registerStandard();
8
+ }
9
+
10
+ protected registerStandard() {
11
+ // Register ANSI standard implementations
12
+ this.add('ABS', ({ compiledArgs }) => `ABS(${compiledArgs[0]})`);
13
+ this.add('UPPER', ({ compiledArgs }) => `UPPER(${compiledArgs[0]})`);
14
+ this.add('LOWER', ({ compiledArgs }) => `LOWER(${compiledArgs[0]})`);
15
+ this.add('LENGTH', ({ compiledArgs }) => `LENGTH(${compiledArgs[0]})`);
16
+ this.add('TRIM', ({ compiledArgs }) => `TRIM(${compiledArgs[0]})`);
17
+ this.add('LTRIM', ({ compiledArgs }) => `LTRIM(${compiledArgs[0]})`);
18
+ this.add('RTRIM', ({ compiledArgs }) => `RTRIM(${compiledArgs[0]})`);
19
+ this.add('SUBSTRING', ({ compiledArgs }) => `SUBSTRING(${compiledArgs.join(', ')})`);
20
+ this.add('CONCAT', ({ compiledArgs }) => `CONCAT(${compiledArgs.join(', ')})`);
21
+ this.add('NOW', () => `NOW()`);
22
+ this.add('CURRENT_DATE', () => `CURRENT_DATE`);
23
+ this.add('CURRENT_TIME', () => `CURRENT_TIME`);
24
+ this.add('EXTRACT', ({ compiledArgs }) => `EXTRACT(${compiledArgs[0]} FROM ${compiledArgs[1]})`);
25
+ this.add('YEAR', ({ compiledArgs }) => `EXTRACT(YEAR FROM ${compiledArgs[0]})`);
26
+ this.add('MONTH', ({ compiledArgs }) => `EXTRACT(MONTH FROM ${compiledArgs[0]})`);
27
+ this.add('DAY', ({ compiledArgs }) => `EXTRACT(DAY FROM ${compiledArgs[0]})`);
28
+ this.add('DATE_ADD', ({ compiledArgs }) => `(${compiledArgs[0]} + INTERVAL ${compiledArgs[1]} ${compiledArgs[2]})`);
29
+ this.add('DATE_SUB', ({ compiledArgs }) => `(${compiledArgs[0]} - INTERVAL ${compiledArgs[1]} ${compiledArgs[2]})`);
30
+ this.add('DATE_DIFF', ({ compiledArgs }) => `DATEDIFF(${compiledArgs[0]}, ${compiledArgs[1]})`);
31
+ this.add('DATE_FORMAT', ({ compiledArgs }) => `DATE_FORMAT(${compiledArgs[0]}, ${compiledArgs[1]})`);
32
+ this.add('UNIX_TIMESTAMP', () => `UNIX_TIMESTAMP()`);
33
+ this.add('FROM_UNIXTIME', ({ compiledArgs }) => `FROM_UNIXTIME(${compiledArgs[0]})`);
34
+ this.add('END_OF_MONTH', ({ compiledArgs }) => `LAST_DAY(${compiledArgs[0]})`);
35
+ this.add('DAY_OF_WEEK', ({ compiledArgs }) => `DAYOFWEEK(${compiledArgs[0]})`);
36
+ this.add('WEEK_OF_YEAR', ({ compiledArgs }) => `WEEKOFYEAR(${compiledArgs[0]})`);
37
+ this.add('DATE_TRUNC', ({ compiledArgs }) => `DATE_TRUNC(${compiledArgs[0]}, ${compiledArgs[1]})`);
38
+ }
39
+
40
+ protected add(name: string, renderer: FunctionRenderer) {
41
+ this.renderers.set(name, renderer);
42
+ }
43
+
44
+ getRenderer(name: string): FunctionRenderer | undefined {
45
+ return this.renderers.get(name);
46
+ }
47
+ }
@@ -0,0 +1,147 @@
1
+ // Pure AST Builders - No Dialect Logic Here!
2
+
3
+ import { ColumnDef } from '../../schema/column.js';
4
+ import { columnOperand, valueToOperand } from '../ast/expression-builders.js';
5
+ import { FunctionNode, OperandNode, isOperandNode } from '../ast/expression.js';
6
+
7
+ type OperandInput = OperandNode | ColumnDef | string | number | boolean | null;
8
+
9
+ const isColumnDef = (val: any): val is ColumnDef => !!val && typeof val === 'object' && 'type' in val && 'name' in val;
10
+
11
+ const toOperand = (input: OperandInput): OperandNode => {
12
+ if (isOperandNode(input)) return input;
13
+ if (isColumnDef(input)) return columnOperand(input);
14
+ return valueToOperand(input as any);
15
+ };
16
+
17
+ const fn = (key: string, args: OperandInput[]): FunctionNode => ({
18
+ type: 'Function',
19
+ name: key,
20
+ fn: key,
21
+ args: args.map(toOperand)
22
+ });
23
+
24
+ /**
25
+ * Helper: LOWER(str)
26
+ */
27
+ export const lower = (value: OperandInput): FunctionNode => fn('LOWER', [value]);
28
+
29
+ /**
30
+ * Helper: UPPER(str)
31
+ */
32
+ export const upper = (value: OperandInput): FunctionNode => fn('UPPER', [value]);
33
+
34
+ /**
35
+ * Helper: ASCII(str)
36
+ */
37
+ export const ascii = (value: OperandInput): FunctionNode => fn('ASCII', [value]);
38
+
39
+ /**
40
+ * Helper: CHAR(code[, code...])
41
+ */
42
+ export const char = (...codes: OperandInput[]): FunctionNode => {
43
+ if (codes.length === 0) throw new Error('char() expects at least 1 argument');
44
+ return fn('CHAR', codes);
45
+ };
46
+
47
+ /**
48
+ * Helper: CHAR_LENGTH(str)
49
+ */
50
+ export const charLength = (value: OperandInput): FunctionNode => fn('CHAR_LENGTH', [value]);
51
+
52
+ /**
53
+ * Helper: LENGTH(str)
54
+ */
55
+ export const length = (value: OperandInput): FunctionNode => fn('LENGTH', [value]);
56
+
57
+ /**
58
+ * Helper: TRIM([chars FROM] str)
59
+ */
60
+ export const trim = (value: OperandInput, chars?: OperandInput): FunctionNode =>
61
+ chars === undefined ? fn('TRIM', [value]) : fn('TRIM', [value, chars]);
62
+
63
+ /**
64
+ * Helper: LTRIM(str)
65
+ */
66
+ export const ltrim = (value: OperandInput): FunctionNode => fn('LTRIM', [value]);
67
+
68
+ /**
69
+ * Helper: RTRIM(str)
70
+ */
71
+ export const rtrim = (value: OperandInput): FunctionNode => fn('RTRIM', [value]);
72
+
73
+ /**
74
+ * Helper: CONCAT(arg1, arg2, ...)
75
+ */
76
+ export const concat = (...args: OperandInput[]): FunctionNode => {
77
+ if (args.length < 2) throw new Error('concat() expects at least 2 arguments');
78
+ return fn('CONCAT', args);
79
+ };
80
+
81
+ /**
82
+ * Helper: CONCAT_WS(separator, arg1, arg2, ...)
83
+ */
84
+ export const concatWs = (separator: OperandInput, ...args: OperandInput[]): FunctionNode => {
85
+ if (args.length < 1) throw new Error('concatWs() expects at least 2 arguments including the separator');
86
+ return fn('CONCAT_WS', [separator, ...args]);
87
+ };
88
+
89
+ /**
90
+ * Helper: SUBSTR(str, start[, length])
91
+ */
92
+ export const substr = (value: OperandInput, start: OperandInput, length?: OperandInput): FunctionNode =>
93
+ length === undefined ? fn('SUBSTR', [value, start]) : fn('SUBSTR', [value, start, length]);
94
+
95
+ /**
96
+ * Helper: LEFT(str, length)
97
+ */
98
+ export const left = (value: OperandInput, len: OperandInput): FunctionNode => fn('LEFT', [value, len]);
99
+
100
+ /**
101
+ * Helper: RIGHT(str, length)
102
+ */
103
+ export const right = (value: OperandInput, len: OperandInput): FunctionNode => fn('RIGHT', [value, len]);
104
+
105
+ /**
106
+ * Helper: POSITION(substring IN string)
107
+ */
108
+ export const position = (substring: OperandInput, value: OperandInput): FunctionNode => fn('POSITION', [substring, value]);
109
+
110
+ /**
111
+ * Helper: INSTR(string, substring)
112
+ */
113
+ export const instr = (value: OperandInput, substring: OperandInput): FunctionNode => fn('INSTR', [value, substring]);
114
+
115
+ /**
116
+ * Helper: LOCATE(substring, string[, start])
117
+ */
118
+ export const locate = (substring: OperandInput, value: OperandInput, start?: OperandInput): FunctionNode =>
119
+ start === undefined ? fn('LOCATE', [substring, value]) : fn('LOCATE', [substring, value, start]);
120
+
121
+ /**
122
+ * Helper: REPLACE(string, search, replace)
123
+ */
124
+ export const replace = (value: OperandInput, search: OperandInput, replacement: OperandInput): FunctionNode =>
125
+ fn('REPLACE', [value, search, replacement]);
126
+
127
+ /**
128
+ * Helper: REPEAT(string, count)
129
+ */
130
+ export const repeat = (value: OperandInput, count: OperandInput): FunctionNode => fn('REPEAT', [value, count]);
131
+
132
+ /**
133
+ * Helper: LPAD(string, length, padstr)
134
+ */
135
+ export const lpad = (value: OperandInput, len: OperandInput, pad: OperandInput): FunctionNode =>
136
+ fn('LPAD', [value, len, pad]);
137
+
138
+ /**
139
+ * Helper: RPAD(string, length, padstr)
140
+ */
141
+ export const rpad = (value: OperandInput, len: OperandInput, pad: OperandInput): FunctionNode =>
142
+ fn('RPAD', [value, len, pad]);
143
+
144
+ /**
145
+ * Helper: SPACE(count)
146
+ */
147
+ export const space = (count: OperandInput): FunctionNode => fn('SPACE', [count]);
@@ -0,0 +1,18 @@
1
+ import { FunctionNode } from '../ast/expression.js';
2
+
3
+ export interface FunctionRenderContext {
4
+ node: FunctionNode;
5
+ compiledArgs: string[];
6
+ // Helper to allow dialects to call back into the compiler if needed
7
+ // compileOperand: (node: OperandNode) => string;
8
+ }
9
+
10
+ export type FunctionRenderer = (ctx: FunctionRenderContext) => string;
11
+
12
+ export interface FunctionStrategy {
13
+ /**
14
+ * Returns a renderer for a specific function name (e.g. "DATE_ADD").
15
+ * Returns undefined if this dialect doesn't support the function.
16
+ */
17
+ getRenderer(functionName: string): FunctionRenderer | undefined;
18
+ }
@@ -0,0 +1,57 @@
1
+ import { RelationType } from '../../schema/relation.js';
2
+
3
+ /**
4
+ * Plan describing pivot columns needed for hydration
5
+ */
6
+ export interface HydrationPivotPlan {
7
+ table: string;
8
+ primaryKey: string;
9
+ aliasPrefix: string;
10
+ columns: string[];
11
+ }
12
+
13
+ /**
14
+ * Plan for hydrating relationship data
15
+ */
16
+ export interface HydrationRelationPlan {
17
+ /** Name of the relationship */
18
+ name: string;
19
+ /** Alias prefix for the relationship */
20
+ aliasPrefix: string;
21
+ /** Type of relationship */
22
+ type: RelationType;
23
+ /** Target table name */
24
+ targetTable: string;
25
+ /** Target table primary key */
26
+ targetPrimaryKey: string;
27
+ /** Foreign key column */
28
+ foreignKey: string;
29
+ /** Local key column */
30
+ localKey: string;
31
+ /** Columns to include */
32
+ columns: string[];
33
+ /** Optional pivot plan for many-to-many relationships */
34
+ pivot?: HydrationPivotPlan;
35
+ }
36
+
37
+ /**
38
+ * Complete hydration plan for a query
39
+ */
40
+ export interface HydrationPlan {
41
+ /** Root table name */
42
+ rootTable: string;
43
+ /** Root table primary key */
44
+ rootPrimaryKey: string;
45
+ /** Root table columns */
46
+ rootColumns: string[];
47
+ /** Relationship hydration plans */
48
+ relations: HydrationRelationPlan[];
49
+ }
50
+
51
+ /**
52
+ * Metadata bag for attaching hydration to query ASTs without coupling AST types.
53
+ */
54
+ export interface HydrationMetadata {
55
+ hydration?: HydrationPlan;
56
+ [key: string]: unknown;
57
+ }
@@ -1,6 +1,7 @@
1
1
  import { SelectQueryBuilder } from '../query-builder/select.js';
2
2
  import {
3
3
  hasMany,
4
+ hasOne,
4
5
  belongsTo,
5
6
  belongsToMany,
6
7
  RelationKinds,
@@ -51,6 +52,15 @@ const buildRelationDefinitions = (
51
52
 
52
53
  for (const [name, relation] of Object.entries(meta.relations)) {
53
54
  switch (relation.kind) {
55
+ case RelationKinds.HasOne: {
56
+ relations[name] = hasOne(
57
+ resolveTableTarget(relation.target, tableMap),
58
+ relation.foreignKey,
59
+ relation.localKey,
60
+ relation.cascade
61
+ );
62
+ break;
63
+ }
54
64
  case RelationKinds.HasMany: {
55
65
  relations[name] = hasMany(
56
66
  resolveTableTarget(relation.target, tableMap),
@@ -16,6 +16,10 @@ export interface HasManyOptions extends BaseRelationOptions {
16
16
  foreignKey: string;
17
17
  }
18
18
 
19
+ export interface HasOneOptions extends BaseRelationOptions {
20
+ foreignKey: string;
21
+ }
22
+
19
23
  export interface BelongsToOptions extends BaseRelationOptions {
20
24
  foreignKey: string;
21
25
  }
@@ -79,6 +83,17 @@ export function HasMany(options: HasManyOptions) {
79
83
  }));
80
84
  }
81
85
 
86
+ export function HasOne(options: HasOneOptions) {
87
+ return createFieldDecorator(propertyName => ({
88
+ kind: RelationKinds.HasOne,
89
+ propertyKey: propertyName,
90
+ target: options.target,
91
+ foreignKey: options.foreignKey,
92
+ localKey: options.localKey,
93
+ cascade: options.cascade
94
+ }));
95
+ }
96
+
82
97
  export function BelongsTo(options: BelongsToOptions) {
83
98
  return createFieldDecorator(propertyName => ({
84
99
  kind: RelationKinds.BelongsTo,
package/src/index.ts CHANGED
@@ -1,28 +1,39 @@
1
-
2
1
  export * from './schema/table.js';
3
2
  export * from './schema/column.js';
4
3
  export * from './schema/relation.js';
5
4
  export * from './schema/types.js';
6
- export * from './query-builder/select.js';
7
- export * from './query-builder/insert.js';
8
- export * from './query-builder/update.js';
9
- export * from './query-builder/delete.js';
10
- export * from './core/ast/expression.js';
11
- export * from './core/dialect/mysql/index.js';
12
- export * from './core/dialect/mssql/index.js';
13
- export * from './core/dialect/sqlite/index.js';
14
- export * from './core/dialect/postgres/index.js';
15
- export * from './core/ddl/schema-generator.js';
16
- export * from './core/ddl/schema-types.js';
17
- export * from './core/ddl/schema-diff.js';
18
- export * from './core/ddl/schema-introspect.js';
19
- export * from './orm/als.js';
20
- export * from './orm/hydration.js';
21
- export * from './codegen/typescript.js';
22
- export * from './orm/orm-context.js';
23
- export * from './orm/entity.js';
5
+ export * from './query-builder/select.js';
6
+ export * from './query-builder/insert.js';
7
+ export * from './query-builder/update.js';
8
+ export * from './query-builder/delete.js';
9
+ export * from './core/ast/expression.js';
10
+ export * from './core/hydration/types.js';
11
+ export * from './core/dialect/mysql/index.js';
12
+ export * from './core/dialect/mssql/index.js';
13
+ export * from './core/dialect/sqlite/index.js';
14
+ export * from './core/dialect/postgres/index.js';
15
+ export * from './core/ddl/schema-generator.js';
16
+ export * from './core/ddl/schema-types.js';
17
+ export * from './core/ddl/schema-diff.js';
18
+ export * from './core/ddl/schema-introspect.js';
19
+ export * from './core/ddl/introspect/registry.js';
20
+ export * from './core/functions/text.js';
21
+ export * from './core/functions/numeric.js';
22
+ export * from './core/functions/datetime.js';
23
+ export * from './orm/als.js';
24
+ export * from './orm/hydration.js';
25
+ export * from './codegen/typescript.js';
26
+ export * from './orm/orm-context.js';
27
+ export * from './orm/entity.js';
24
28
  export * from './orm/lazy-batch.js';
25
29
  export * from './orm/relations/has-many.js';
26
30
  export * from './orm/relations/belongs-to.js';
27
31
  export * from './orm/relations/many-to-many.js';
28
32
  export * from './orm/execute.js';
33
+
34
+ // NEW: execution abstraction + helpers
35
+ export * from './core/execution/db-executor.js';
36
+ export * from './core/execution/executors/postgres-executor.js';
37
+ export * from './core/execution/executors/mysql-executor.js';
38
+ export * from './core/execution/executors/sqlite-executor.js';
39
+ export * from './core/execution/executors/mssql-executor.js';
@@ -25,6 +25,12 @@ export interface HasManyRelationMetadata extends BaseRelationMetadata {
25
25
  localKey?: string;
26
26
  }
27
27
 
28
+ export interface HasOneRelationMetadata extends BaseRelationMetadata {
29
+ kind: typeof RelationKinds.HasOne;
30
+ foreignKey: string;
31
+ localKey?: string;
32
+ }
33
+
28
34
  export interface BelongsToRelationMetadata extends BaseRelationMetadata {
29
35
  kind: typeof RelationKinds.BelongsTo;
30
36
  foreignKey: string;
@@ -44,6 +50,7 @@ export interface BelongsToManyRelationMetadata extends BaseRelationMetadata {
44
50
 
45
51
  export type RelationMetadata =
46
52
  | HasManyRelationMetadata
53
+ | HasOneRelationMetadata
47
54
  | BelongsToRelationMetadata
48
55
  | BelongsToManyRelationMetadata;
49
56