metal-orm 1.0.63 → 1.0.65
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 +10 -8
- package/dist/index.cjs +130 -107
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +848 -457
- package/dist/index.d.ts +848 -457
- package/dist/index.js +130 -107
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/core/ast/aggregate-functions.ts +14 -5
- package/src/core/ast/expression-builders.ts +325 -111
- package/src/core/ast/window-functions.ts +62 -52
- package/src/core/functions/array.ts +12 -3
- package/src/core/functions/control-flow.ts +28 -18
- package/src/core/functions/datetime.ts +113 -84
- package/src/core/functions/json.ts +40 -8
- package/src/core/functions/numeric.ts +116 -79
- package/src/core/functions/text.ts +181 -114
- package/src/index.ts +2 -1
- package/src/orm/entity-context.ts +9 -7
- package/src/orm/entity-relations.ts +207 -207
- package/src/orm/entity.ts +124 -124
- package/src/orm/execute.ts +166 -166
- package/src/orm/identity-map.ts +1 -1
- package/src/orm/lazy-batch/shared.ts +1 -1
- package/src/orm/orm-session.ts +54 -54
- package/src/orm/relation-change-processor.ts +3 -3
- package/src/orm/relations/has-many.ts +1 -1
- package/src/orm/runtime-types.ts +5 -5
- package/src/orm/save-graph.ts +161 -161
- package/src/orm/unit-of-work.ts +58 -56
- package/src/query-builder/insert-query-state.ts +156 -155
- package/src/query-builder/insert.ts +5 -2
- package/src/query-builder/select.ts +112 -111
- package/src/schema/column-types.ts +14 -14
- package/src/schema/table.ts +39 -31
- package/src/schema/types.ts +54 -54
|
@@ -1,161 +1,162 @@
|
|
|
1
|
-
import { TableDef } from '../schema/table.js';
|
|
2
|
-
import { InsertQueryNode, SelectQueryNode } from '../core/ast/query.js';
|
|
1
|
+
import { TableDef } from '../schema/table.js';
|
|
2
|
+
import { InsertQueryNode, SelectQueryNode } from '../core/ast/query.js';
|
|
3
3
|
import {
|
|
4
4
|
ColumnNode,
|
|
5
5
|
OperandNode,
|
|
6
6
|
isValueOperandInput,
|
|
7
7
|
valueToOperand
|
|
8
8
|
} from '../core/ast/expression.js';
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
public readonly
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
*
|
|
26
|
-
* @param
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
this.
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
*
|
|
66
|
-
* @
|
|
67
|
-
* @
|
|
68
|
-
* @throws Error if
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
*
|
|
106
|
-
* @
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
return this
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
*
|
|
119
|
-
* @param
|
|
120
|
-
* @
|
|
121
|
-
* @
|
|
122
|
-
* @throws Error if
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
*
|
|
153
|
-
* @
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
}
|
|
9
|
+
import type { ValueOperandInput } from '../core/ast/expression.js';
|
|
10
|
+
import {
|
|
11
|
+
buildColumnNodes,
|
|
12
|
+
createTableNode
|
|
13
|
+
} from '../core/ast/builders.js';
|
|
14
|
+
|
|
15
|
+
type InsertRows = Record<string, ValueOperandInput>[];
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Maintains immutable state for building INSERT queries
|
|
19
|
+
*/
|
|
20
|
+
export class InsertQueryState {
|
|
21
|
+
public readonly table: TableDef;
|
|
22
|
+
public readonly ast: InsertQueryNode;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Creates a new InsertQueryState instance
|
|
26
|
+
* @param table - The table definition for the INSERT query
|
|
27
|
+
* @param ast - Optional initial AST node, defaults to a basic INSERT query
|
|
28
|
+
*/
|
|
29
|
+
constructor(table: TableDef, ast?: InsertQueryNode) {
|
|
30
|
+
this.table = table;
|
|
31
|
+
this.ast = ast ?? {
|
|
32
|
+
type: 'InsertQuery',
|
|
33
|
+
into: createTableNode(table),
|
|
34
|
+
columns: [],
|
|
35
|
+
source: {
|
|
36
|
+
type: 'InsertValues',
|
|
37
|
+
rows: []
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
private clone(nextAst: InsertQueryNode): InsertQueryState {
|
|
43
|
+
return new InsertQueryState(this.table, nextAst);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
private ensureColumnsFromRow(rows: InsertRows): ColumnNode[] {
|
|
47
|
+
if (this.ast.columns.length) return this.ast.columns;
|
|
48
|
+
return buildColumnNodes(this.table, Object.keys(rows[0]));
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
private appendValues(rows: OperandNode[][]): OperandNode[][] {
|
|
52
|
+
if (this.ast.source.type === 'InsertValues') {
|
|
53
|
+
return [...this.ast.source.rows, ...rows];
|
|
54
|
+
}
|
|
55
|
+
return rows;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
private getTableColumns(): ColumnNode[] {
|
|
59
|
+
const names = Object.keys(this.table.columns);
|
|
60
|
+
if (!names.length) return [];
|
|
61
|
+
return buildColumnNodes(this.table, names);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Adds VALUES clause to the INSERT query
|
|
66
|
+
* @param rows - Array of row objects to insert
|
|
67
|
+
* @returns A new InsertQueryState with the VALUES clause added
|
|
68
|
+
* @throws Error if mixing VALUES with SELECT source
|
|
69
|
+
* @throws Error if invalid values are provided
|
|
70
|
+
*/
|
|
71
|
+
withValues(rows: InsertRows): InsertQueryState {
|
|
72
|
+
if (!rows.length) return this;
|
|
73
|
+
|
|
74
|
+
if (this.ast.source.type === 'InsertSelect') {
|
|
75
|
+
throw new Error('Cannot mix INSERT ... VALUES with INSERT ... SELECT source.');
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const definedColumns = this.ensureColumnsFromRow(rows);
|
|
79
|
+
|
|
80
|
+
const newRows: OperandNode[][] = rows.map((row, rowIndex) =>
|
|
81
|
+
definedColumns.map(column => {
|
|
82
|
+
const rawValue = row[column.name];
|
|
83
|
+
|
|
84
|
+
if (!isValueOperandInput(rawValue)) {
|
|
85
|
+
throw new Error(
|
|
86
|
+
`Invalid insert value for column "${column.name}" in row ${rowIndex}: only primitives, null, or OperandNodes are allowed`
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return valueToOperand(rawValue);
|
|
91
|
+
})
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
return this.clone({
|
|
95
|
+
...this.ast,
|
|
96
|
+
columns: definedColumns,
|
|
97
|
+
source: {
|
|
98
|
+
type: 'InsertValues',
|
|
99
|
+
rows: this.appendValues(newRows)
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Sets the columns for the INSERT query
|
|
106
|
+
* @param columns - Column nodes to insert into
|
|
107
|
+
* @returns A new InsertQueryState with the specified columns
|
|
108
|
+
*/
|
|
109
|
+
withColumns(columns: ColumnNode[]): InsertQueryState {
|
|
110
|
+
if (!columns.length) return this;
|
|
111
|
+
return this.clone({
|
|
112
|
+
...this.ast,
|
|
113
|
+
columns: [...columns]
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Adds SELECT source to the INSERT query
|
|
119
|
+
* @param query - The SELECT query to use as source
|
|
120
|
+
* @param columns - Target columns for the INSERT
|
|
121
|
+
* @returns A new InsertQueryState with the SELECT source
|
|
122
|
+
* @throws Error if mixing SELECT with VALUES source
|
|
123
|
+
* @throws Error if no destination columns specified
|
|
124
|
+
*/
|
|
125
|
+
withSelect(query: SelectQueryNode, columns: ColumnNode[]): InsertQueryState {
|
|
126
|
+
const targetColumns =
|
|
127
|
+
columns.length
|
|
128
|
+
? columns
|
|
129
|
+
: this.ast.columns.length
|
|
130
|
+
? this.ast.columns
|
|
131
|
+
: this.getTableColumns();
|
|
132
|
+
|
|
133
|
+
if (!targetColumns.length) {
|
|
134
|
+
throw new Error('INSERT ... SELECT requires specifying destination columns.');
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (this.ast.source.type === 'InsertValues' && this.ast.source.rows.length) {
|
|
138
|
+
throw new Error('Cannot mix INSERT ... SELECT with INSERT ... VALUES source.');
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return this.clone({
|
|
142
|
+
...this.ast,
|
|
143
|
+
columns: [...targetColumns],
|
|
144
|
+
source: {
|
|
145
|
+
type: 'InsertSelect',
|
|
146
|
+
query
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Adds a RETURNING clause to the INSERT query
|
|
153
|
+
* @param columns - Columns to return after insertion
|
|
154
|
+
* @returns A new InsertQueryState with the RETURNING clause added
|
|
155
|
+
*/
|
|
156
|
+
withReturning(columns: ColumnNode[]): InsertQueryState {
|
|
157
|
+
return this.clone({
|
|
158
|
+
...this.ast,
|
|
159
|
+
returning: [...columns]
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { SelectQueryBuilder } from './select.js';
|
|
2
2
|
import { TableDef } from '../schema/table.js';
|
|
3
3
|
import { ColumnDef } from '../schema/column-types.js';
|
|
4
|
-
import { ColumnNode } from '../core/ast/expression.js';
|
|
4
|
+
import { ColumnNode } from '../core/ast/expression.js';
|
|
5
|
+
import type { ValueOperandInput } from '../core/ast/expression.js';
|
|
5
6
|
import { CompiledQuery, InsertCompiler, Dialect } from '../core/dialect/abstract.js';
|
|
6
7
|
import { DialectKey, resolveDialectInput } from '../core/dialect/dialect-factory.js';
|
|
7
8
|
import { InsertQueryNode, SelectQueryNode } from '../core/ast/query.js';
|
|
@@ -36,7 +37,9 @@ export class InsertQueryBuilder<T> {
|
|
|
36
37
|
* @param rowOrRows - Single row object or array of row objects to insert
|
|
37
38
|
* @returns A new InsertQueryBuilder with the VALUES clause added
|
|
38
39
|
*/
|
|
39
|
-
values(
|
|
40
|
+
values(
|
|
41
|
+
rowOrRows: Record<string, ValueOperandInput> | Record<string, ValueOperandInput>[]
|
|
42
|
+
): InsertQueryBuilder<T> {
|
|
40
43
|
const rows = Array.isArray(rowOrRows) ? rowOrRows : [rowOrRows];
|
|
41
44
|
if (!rows.length) return this;
|
|
42
45
|
return this.clone(this.state.withValues(rows));
|