metal-orm 1.0.43 → 1.0.44
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 +173 -30
- package/dist/index.cjs +896 -476
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1146 -275
- package/dist/index.d.ts +1146 -275
- package/dist/index.js +896 -474
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/core/ast/adapters.ts +8 -2
- package/src/core/ast/builders.ts +105 -81
- package/src/core/ast/expression-builders.ts +430 -390
- package/src/core/ast/expression-visitor.ts +47 -8
- package/src/core/ast/helpers.ts +23 -0
- package/src/core/ast/join-node.ts +17 -1
- package/src/core/ddl/dialects/base-schema-dialect.ts +7 -1
- package/src/core/ddl/dialects/index.ts +1 -0
- package/src/core/ddl/dialects/mssql-schema-dialect.ts +1 -0
- package/src/core/ddl/dialects/mysql-schema-dialect.ts +1 -0
- package/src/core/ddl/dialects/postgres-schema-dialect.ts +1 -0
- package/src/core/ddl/dialects/sqlite-schema-dialect.ts +1 -0
- package/src/core/ddl/introspect/catalogs/index.ts +1 -0
- package/src/core/ddl/introspect/catalogs/postgres.ts +2 -0
- package/src/core/ddl/introspect/context.ts +6 -0
- package/src/core/ddl/introspect/functions/postgres.ts +13 -0
- package/src/core/ddl/introspect/mssql.ts +11 -0
- package/src/core/ddl/introspect/mysql.ts +2 -0
- package/src/core/ddl/introspect/postgres.ts +14 -0
- package/src/core/ddl/introspect/registry.ts +14 -0
- package/src/core/ddl/introspect/run-select.ts +13 -0
- package/src/core/ddl/introspect/sqlite.ts +22 -0
- package/src/core/ddl/introspect/utils.ts +18 -0
- package/src/core/ddl/naming-strategy.ts +6 -0
- package/src/core/ddl/schema-dialect.ts +19 -6
- package/src/core/ddl/schema-diff.ts +22 -0
- package/src/core/ddl/schema-generator.ts +22 -0
- package/src/core/ddl/schema-plan-executor.ts +6 -0
- package/src/core/ddl/schema-types.ts +6 -0
- package/src/core/dialect/abstract.ts +2 -2
- package/src/core/execution/pooling/pool.ts +12 -7
- package/src/core/functions/datetime.ts +57 -33
- package/src/core/functions/numeric.ts +95 -30
- package/src/core/functions/standard-strategy.ts +35 -0
- package/src/core/functions/text.ts +83 -22
- package/src/core/functions/types.ts +23 -8
- package/src/decorators/bootstrap.ts +16 -4
- package/src/decorators/column.ts +17 -0
- package/src/decorators/decorator-metadata.ts +27 -0
- package/src/decorators/entity.ts +8 -0
- package/src/decorators/index.ts +3 -0
- package/src/decorators/relations.ts +32 -0
- package/src/orm/als.ts +34 -9
- package/src/orm/entity-context.ts +54 -0
- package/src/orm/entity-metadata.ts +122 -9
- package/src/orm/execute.ts +15 -0
- package/src/orm/lazy-batch.ts +68 -98
- package/src/orm/relations/has-many.ts +44 -0
- package/src/query/index.ts +74 -0
- package/src/query/target.ts +46 -0
- package/src/query-builder/delete-query-state.ts +30 -0
- package/src/query-builder/delete.ts +64 -19
- package/src/query-builder/hydration-manager.ts +46 -0
- package/src/query-builder/insert-query-state.ts +30 -0
- package/src/query-builder/insert.ts +46 -2
- package/src/query-builder/query-ast-service.ts +5 -0
- package/src/query-builder/query-resolution.ts +78 -0
- package/src/query-builder/raw-column-parser.ts +5 -0
- package/src/query-builder/relation-alias.ts +7 -0
- package/src/query-builder/relation-conditions.ts +61 -48
- package/src/query-builder/relation-service.ts +68 -63
- package/src/query-builder/relation-utils.ts +3 -0
- package/src/query-builder/select/cte-facet.ts +40 -0
- package/src/query-builder/select/from-facet.ts +80 -0
- package/src/query-builder/select/join-facet.ts +62 -0
- package/src/query-builder/select/predicate-facet.ts +103 -0
- package/src/query-builder/select/projection-facet.ts +69 -0
- package/src/query-builder/select/relation-facet.ts +81 -0
- package/src/query-builder/select/setop-facet.ts +36 -0
- package/src/query-builder/select-helpers.ts +13 -0
- package/src/query-builder/select-query-builder-deps.ts +19 -1
- package/src/query-builder/select-query-state.ts +2 -1
- package/src/query-builder/select.ts +795 -1163
- package/src/query-builder/update-query-state.ts +52 -0
- package/src/query-builder/update.ts +69 -19
- package/src/schema/table-guards.ts +31 -0
|
@@ -20,12 +20,28 @@ const hideInternal = (obj: object, keys: string[]): void => {
|
|
|
20
20
|
}
|
|
21
21
|
};
|
|
22
22
|
|
|
23
|
+
/**
|
|
24
|
+
* Default implementation of HasManyCollection for managing one-to-many relationships.
|
|
25
|
+
* @template TChild - The type of child entities in the collection
|
|
26
|
+
*/
|
|
23
27
|
export class DefaultHasManyCollection<TChild> implements HasManyCollection<TChild> {
|
|
24
28
|
private loaded = false;
|
|
25
29
|
private items: TChild[] = [];
|
|
26
30
|
private readonly added = new Set<TChild>();
|
|
27
31
|
private readonly removed = new Set<TChild>();
|
|
28
32
|
|
|
33
|
+
/**
|
|
34
|
+
* Creates a new DefaultHasManyCollection instance.
|
|
35
|
+
* @param ctx - The entity context
|
|
36
|
+
* @param meta - The entity metadata
|
|
37
|
+
* @param root - The root entity
|
|
38
|
+
* @param relationName - The relation name
|
|
39
|
+
* @param relation - The relation definition
|
|
40
|
+
* @param rootTable - The root table definition
|
|
41
|
+
* @param loader - The loader function for lazy loading
|
|
42
|
+
* @param createEntity - Function to create entities from rows
|
|
43
|
+
* @param localKey - The local key for the relation
|
|
44
|
+
*/
|
|
29
45
|
constructor(
|
|
30
46
|
private readonly ctx: EntityContext,
|
|
31
47
|
private readonly meta: EntityMeta<TableDef>,
|
|
@@ -41,6 +57,10 @@ export class DefaultHasManyCollection<TChild> implements HasManyCollection<TChil
|
|
|
41
57
|
this.hydrateFromCache();
|
|
42
58
|
}
|
|
43
59
|
|
|
60
|
+
/**
|
|
61
|
+
* Loads the related entities if not already loaded.
|
|
62
|
+
* @returns Promise resolving to the array of child entities
|
|
63
|
+
*/
|
|
44
64
|
async load(): Promise<TChild[]> {
|
|
45
65
|
if (this.loaded) return this.items;
|
|
46
66
|
const map = await this.loader();
|
|
@@ -51,10 +71,19 @@ export class DefaultHasManyCollection<TChild> implements HasManyCollection<TChil
|
|
|
51
71
|
return this.items;
|
|
52
72
|
}
|
|
53
73
|
|
|
74
|
+
/**
|
|
75
|
+
* Gets the current items in the collection.
|
|
76
|
+
* @returns Array of child entities
|
|
77
|
+
*/
|
|
54
78
|
getItems(): TChild[] {
|
|
55
79
|
return this.items;
|
|
56
80
|
}
|
|
57
81
|
|
|
82
|
+
/**
|
|
83
|
+
* Adds a new child entity to the collection.
|
|
84
|
+
* @param data - Partial data for the new entity
|
|
85
|
+
* @returns The created entity
|
|
86
|
+
*/
|
|
58
87
|
add(data: Partial<TChild>): TChild {
|
|
59
88
|
const keyValue = (this.root as Record<string, unknown>)[this.localKey];
|
|
60
89
|
const childRow: Record<string, unknown> = {
|
|
@@ -75,6 +104,10 @@ export class DefaultHasManyCollection<TChild> implements HasManyCollection<TChil
|
|
|
75
104
|
return entity;
|
|
76
105
|
}
|
|
77
106
|
|
|
107
|
+
/**
|
|
108
|
+
* Attaches an existing entity to the collection.
|
|
109
|
+
* @param entity - The entity to attach
|
|
110
|
+
*/
|
|
78
111
|
attach(entity: TChild): void {
|
|
79
112
|
const keyValue = this.root[this.localKey];
|
|
80
113
|
(entity as Record<string, unknown>)[this.relation.foreignKey] = keyValue;
|
|
@@ -90,6 +123,10 @@ export class DefaultHasManyCollection<TChild> implements HasManyCollection<TChil
|
|
|
90
123
|
);
|
|
91
124
|
}
|
|
92
125
|
|
|
126
|
+
/**
|
|
127
|
+
* Removes an entity from the collection.
|
|
128
|
+
* @param entity - The entity to remove
|
|
129
|
+
*/
|
|
93
130
|
remove(entity: TChild): void {
|
|
94
131
|
this.items = this.items.filter(item => item !== entity);
|
|
95
132
|
this.removed.add(entity);
|
|
@@ -103,6 +140,9 @@ export class DefaultHasManyCollection<TChild> implements HasManyCollection<TChil
|
|
|
103
140
|
);
|
|
104
141
|
}
|
|
105
142
|
|
|
143
|
+
/**
|
|
144
|
+
* Clears all entities from the collection.
|
|
145
|
+
*/
|
|
106
146
|
clear(): void {
|
|
107
147
|
for (const entity of [...this.items]) {
|
|
108
148
|
this.remove(entity);
|
|
@@ -122,6 +162,10 @@ export class DefaultHasManyCollection<TChild> implements HasManyCollection<TChil
|
|
|
122
162
|
this.loaded = true;
|
|
123
163
|
}
|
|
124
164
|
|
|
165
|
+
/**
|
|
166
|
+
* Returns the items for JSON serialization.
|
|
167
|
+
* @returns Array of child entities
|
|
168
|
+
*/
|
|
125
169
|
toJSON(): TChild[] {
|
|
126
170
|
return this.items;
|
|
127
171
|
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { TableDef } from '../schema/table.js';
|
|
2
|
+
import { SelectQueryBuilder } from '../query-builder/select.js';
|
|
3
|
+
import { InsertQueryBuilder } from '../query-builder/insert.js';
|
|
4
|
+
import { UpdateQueryBuilder } from '../query-builder/update.js';
|
|
5
|
+
import { DeleteQueryBuilder } from '../query-builder/delete.js';
|
|
6
|
+
import { QueryTarget, resolveTable } from './target.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Creates a SELECT query builder for the specified table or entity.
|
|
10
|
+
*
|
|
11
|
+
* @template TTable - The table definition type
|
|
12
|
+
* @param target - The table definition or entity constructor to query from
|
|
13
|
+
* @returns A new SelectQueryBuilder instance for building SELECT queries
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```typescript
|
|
17
|
+
* const query = selectFrom(UserTable).select('id', 'name');
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export const selectFrom = <TTable extends TableDef>(target: QueryTarget<TTable>): SelectQueryBuilder<unknown, TTable> => {
|
|
21
|
+
const table = resolveTable(target);
|
|
22
|
+
return new SelectQueryBuilder(table);
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Creates an INSERT query builder for the specified table or entity.
|
|
27
|
+
*
|
|
28
|
+
* @template TTable - The table definition type
|
|
29
|
+
* @param target - The table definition or entity constructor to insert into
|
|
30
|
+
* @returns A new InsertQueryBuilder instance for building INSERT queries
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```typescript
|
|
34
|
+
* const query = insertInto(UserTable).values({ name: 'John', email: 'john@example.com' });
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
export const insertInto = <TTable extends TableDef>(target: QueryTarget<TTable>): InsertQueryBuilder<unknown> => {
|
|
38
|
+
const table = resolveTable(target);
|
|
39
|
+
return new InsertQueryBuilder(table);
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Creates an UPDATE query builder for the specified table or entity.
|
|
44
|
+
*
|
|
45
|
+
* @template TTable - The table definition type
|
|
46
|
+
* @param target - The table definition or entity constructor to update
|
|
47
|
+
* @returns A new UpdateQueryBuilder instance for building UPDATE queries
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```typescript
|
|
51
|
+
* const query = update(UserTable).set({ name: 'Jane' }).where(eq(UserTable.id, 1));
|
|
52
|
+
* ```
|
|
53
|
+
*/
|
|
54
|
+
export const update = <TTable extends TableDef>(target: QueryTarget<TTable>): UpdateQueryBuilder<unknown> => {
|
|
55
|
+
const table = resolveTable(target);
|
|
56
|
+
return new UpdateQueryBuilder(table);
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Creates a DELETE query builder for the specified table or entity.
|
|
61
|
+
*
|
|
62
|
+
* @template TTable - The table definition type
|
|
63
|
+
* @param target - The table definition or entity constructor to delete from
|
|
64
|
+
* @returns A new DeleteQueryBuilder instance for building DELETE queries
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* ```typescript
|
|
68
|
+
* const query = deleteFrom(UserTable).where(eq(UserTable.id, 1));
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
71
|
+
export const deleteFrom = <TTable extends TableDef>(target: QueryTarget<TTable>): DeleteQueryBuilder<unknown> => {
|
|
72
|
+
const table = resolveTable(target);
|
|
73
|
+
return new DeleteQueryBuilder(table);
|
|
74
|
+
};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { TableDef } from '../schema/table.js';
|
|
2
|
+
import { isTableDef } from '../schema/table-guards.js';
|
|
3
|
+
import { EntityConstructor } from '../orm/entity-metadata.js';
|
|
4
|
+
import { getTableDefFromEntity } from '../decorators/bootstrap.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Represents a target for query operations, which can be either a table definition
|
|
8
|
+
* or an entity constructor. This type allows flexible targeting of database tables
|
|
9
|
+
* through either direct table definitions or entity classes decorated with ORM metadata.
|
|
10
|
+
*
|
|
11
|
+
* @template TTable - The table definition type, defaults to TableDef
|
|
12
|
+
*/
|
|
13
|
+
export type QueryTarget<TTable extends TableDef = TableDef> = TTable | EntityConstructor;
|
|
14
|
+
|
|
15
|
+
const resolveEntityTarget = <TTable extends TableDef>(ctor: EntityConstructor): TTable => {
|
|
16
|
+
const table = getTableDefFromEntity(ctor);
|
|
17
|
+
if (!table) {
|
|
18
|
+
throw new Error(`Entity '${ctor.name}' is not registered with decorators`);
|
|
19
|
+
}
|
|
20
|
+
return table as TTable;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Resolves a QueryTarget to its corresponding table definition.
|
|
25
|
+
*
|
|
26
|
+
* If the target is already a TableDef, it returns it directly.
|
|
27
|
+
* If the target is an EntityConstructor, it retrieves the associated table definition
|
|
28
|
+
* from the entity's metadata.
|
|
29
|
+
*
|
|
30
|
+
* @template TTable - The table definition type
|
|
31
|
+
* @param target - The query target to resolve
|
|
32
|
+
* @returns The resolved table definition
|
|
33
|
+
* @throws Error if the entity constructor is not registered with decorators
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```typescript
|
|
37
|
+
* const table = resolveTable(UserTable); // Returns UserTable directly
|
|
38
|
+
* const table2 = resolveTable(UserEntity); // Returns table def from UserEntity metadata
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
export const resolveTable = <TTable extends TableDef>(target: QueryTarget<TTable>): TTable => {
|
|
42
|
+
if (isTableDef(target)) {
|
|
43
|
+
return target as TTable;
|
|
44
|
+
}
|
|
45
|
+
return resolveEntityTarget(target as EntityConstructor);
|
|
46
|
+
};
|
|
@@ -14,6 +14,11 @@ export class DeleteQueryState {
|
|
|
14
14
|
public readonly table: TableDef;
|
|
15
15
|
public readonly ast: DeleteQueryNode;
|
|
16
16
|
|
|
17
|
+
/**
|
|
18
|
+
* Creates a new DeleteQueryState instance
|
|
19
|
+
* @param table - The table definition for the DELETE query
|
|
20
|
+
* @param ast - Optional initial AST node, defaults to a basic DELETE query
|
|
21
|
+
*/
|
|
17
22
|
constructor(table: TableDef, ast?: DeleteQueryNode) {
|
|
18
23
|
this.table = table;
|
|
19
24
|
this.ast = ast ?? {
|
|
@@ -27,6 +32,11 @@ export class DeleteQueryState {
|
|
|
27
32
|
return new DeleteQueryState(this.table, nextAst);
|
|
28
33
|
}
|
|
29
34
|
|
|
35
|
+
/**
|
|
36
|
+
* Adds a WHERE clause to the DELETE query
|
|
37
|
+
* @param expr - The expression to use as the WHERE condition
|
|
38
|
+
* @returns A new DeleteQueryState with the WHERE clause added
|
|
39
|
+
*/
|
|
30
40
|
withWhere(expr: ExpressionNode): DeleteQueryState {
|
|
31
41
|
return this.clone({
|
|
32
42
|
...this.ast,
|
|
@@ -34,6 +44,11 @@ export class DeleteQueryState {
|
|
|
34
44
|
});
|
|
35
45
|
}
|
|
36
46
|
|
|
47
|
+
/**
|
|
48
|
+
* Adds a RETURNING clause to the DELETE query
|
|
49
|
+
* @param columns - The columns to return after deletion
|
|
50
|
+
* @returns A new DeleteQueryState with the RETURNING clause added
|
|
51
|
+
*/
|
|
37
52
|
withReturning(columns: ColumnNode[]): DeleteQueryState {
|
|
38
53
|
return this.clone({
|
|
39
54
|
...this.ast,
|
|
@@ -41,6 +56,11 @@ export class DeleteQueryState {
|
|
|
41
56
|
});
|
|
42
57
|
}
|
|
43
58
|
|
|
59
|
+
/**
|
|
60
|
+
* Adds a USING clause to the DELETE query
|
|
61
|
+
* @param source - The table source to use in the USING clause
|
|
62
|
+
* @returns A new DeleteQueryState with the USING clause added
|
|
63
|
+
*/
|
|
44
64
|
withUsing(source: TableSourceNode): DeleteQueryState {
|
|
45
65
|
return this.clone({
|
|
46
66
|
...this.ast,
|
|
@@ -48,6 +68,11 @@ export class DeleteQueryState {
|
|
|
48
68
|
});
|
|
49
69
|
}
|
|
50
70
|
|
|
71
|
+
/**
|
|
72
|
+
* Adds a JOIN clause to the DELETE query
|
|
73
|
+
* @param join - The join node to add
|
|
74
|
+
* @returns A new DeleteQueryState with the JOIN clause added
|
|
75
|
+
*/
|
|
51
76
|
withJoin(join: JoinNode): DeleteQueryState {
|
|
52
77
|
return this.clone({
|
|
53
78
|
...this.ast,
|
|
@@ -55,6 +80,11 @@ export class DeleteQueryState {
|
|
|
55
80
|
});
|
|
56
81
|
}
|
|
57
82
|
|
|
83
|
+
/**
|
|
84
|
+
* Sets an alias for the table in the DELETE query
|
|
85
|
+
* @param alias - The alias to assign to the table
|
|
86
|
+
* @returns A new DeleteQueryState with the table alias set
|
|
87
|
+
*/
|
|
58
88
|
withTableAlias(alias: string): DeleteQueryState {
|
|
59
89
|
return this.clone({
|
|
60
90
|
...this.ast,
|
|
@@ -2,12 +2,14 @@ import { TableDef } from '../schema/table.js';
|
|
|
2
2
|
import { ColumnDef } from '../schema/column.js';
|
|
3
3
|
import { ColumnNode, ExpressionNode } from '../core/ast/expression.js';
|
|
4
4
|
import { JOIN_KINDS, JoinKind } from '../core/sql/sql.js';
|
|
5
|
-
import { CompiledQuery,
|
|
5
|
+
import { CompiledQuery, Dialect } from '../core/dialect/abstract.js';
|
|
6
6
|
import { DialectKey, resolveDialectInput } from '../core/dialect/dialect-factory.js';
|
|
7
7
|
import { TableSourceNode, DeleteQueryNode } from '../core/ast/query.js';
|
|
8
8
|
import { DeleteQueryState } from './delete-query-state.js';
|
|
9
9
|
import { createJoinNode } from '../core/ast/join-node.js';
|
|
10
10
|
import { buildColumnNode } from '../core/ast/builders.js';
|
|
11
|
+
import { OrmSession } from '../orm/orm-session.js';
|
|
12
|
+
import { QueryResult } from '../core/execution/db-executor.js';
|
|
11
13
|
|
|
12
14
|
type DeleteDialectInput = Dialect | DialectKey;
|
|
13
15
|
|
|
@@ -18,6 +20,11 @@ export class DeleteQueryBuilder<T> {
|
|
|
18
20
|
private readonly table: TableDef;
|
|
19
21
|
private readonly state: DeleteQueryState;
|
|
20
22
|
|
|
23
|
+
/**
|
|
24
|
+
* Creates a new DeleteQueryBuilder instance
|
|
25
|
+
* @param table - The table definition for the DELETE query
|
|
26
|
+
* @param state - Optional initial query state, defaults to a new DeleteQueryState
|
|
27
|
+
*/
|
|
21
28
|
constructor(table: TableDef, state?: DeleteQueryState) {
|
|
22
29
|
this.table = table;
|
|
23
30
|
this.state = state ?? new DeleteQueryState(table);
|
|
@@ -27,18 +34,41 @@ export class DeleteQueryBuilder<T> {
|
|
|
27
34
|
return new DeleteQueryBuilder(this.table, state);
|
|
28
35
|
}
|
|
29
36
|
|
|
37
|
+
/**
|
|
38
|
+
* Adds a WHERE clause to the DELETE query
|
|
39
|
+
* @param expr - The expression to use as the WHERE condition
|
|
40
|
+
* @returns A new DeleteQueryBuilder with the WHERE clause added
|
|
41
|
+
*/
|
|
30
42
|
where(expr: ExpressionNode): DeleteQueryBuilder<T> {
|
|
31
43
|
return this.clone(this.state.withWhere(expr));
|
|
32
44
|
}
|
|
33
45
|
|
|
46
|
+
/**
|
|
47
|
+
* Sets an alias for the table in the DELETE query
|
|
48
|
+
* @param alias - The alias to assign to the table
|
|
49
|
+
* @returns A new DeleteQueryBuilder with the table alias set
|
|
50
|
+
*/
|
|
34
51
|
as(alias: string): DeleteQueryBuilder<T> {
|
|
35
52
|
return this.clone(this.state.withTableAlias(alias));
|
|
36
53
|
}
|
|
37
54
|
|
|
55
|
+
/**
|
|
56
|
+
* Adds a USING clause to the DELETE query
|
|
57
|
+
* @param source - The table source to use in the USING clause
|
|
58
|
+
* @returns A new DeleteQueryBuilder with the USING clause added
|
|
59
|
+
*/
|
|
38
60
|
using(source: TableDef | TableSourceNode): DeleteQueryBuilder<T> {
|
|
39
61
|
return this.clone(this.state.withUsing(this.resolveTableSource(source)));
|
|
40
62
|
}
|
|
41
63
|
|
|
64
|
+
/**
|
|
65
|
+
* Adds a JOIN clause to the DELETE query
|
|
66
|
+
* @param table - The table to join with
|
|
67
|
+
* @param condition - The join condition expression
|
|
68
|
+
* @param kind - The type of join (defaults to INNER)
|
|
69
|
+
* @param relationName - Optional name for the relation
|
|
70
|
+
* @returns A new DeleteQueryBuilder with the JOIN clause added
|
|
71
|
+
*/
|
|
42
72
|
join(
|
|
43
73
|
table: TableDef | TableSourceNode | string,
|
|
44
74
|
condition: ExpressionNode,
|
|
@@ -50,6 +80,11 @@ export class DeleteQueryBuilder<T> {
|
|
|
50
80
|
return this.clone(this.state.withJoin(joinNode));
|
|
51
81
|
}
|
|
52
82
|
|
|
83
|
+
/**
|
|
84
|
+
* Adds a RETURNING clause to the DELETE query
|
|
85
|
+
* @param columns - The columns to return after deletion
|
|
86
|
+
* @returns A new DeleteQueryBuilder with the RETURNING clause added
|
|
87
|
+
*/
|
|
53
88
|
returning(...columns: (ColumnDef | ColumnNode)[]): DeleteQueryBuilder<T> {
|
|
54
89
|
if (!columns.length) return this;
|
|
55
90
|
const nodes = columns.map(column => buildColumnNode(this.table, column));
|
|
@@ -68,29 +103,39 @@ export class DeleteQueryBuilder<T> {
|
|
|
68
103
|
return this.resolveTableSource(table);
|
|
69
104
|
}
|
|
70
105
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
compile(dialect: DeleteDialectInput): CompiledQuery
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
if (typeof candidate.compileDelete === 'function') {
|
|
81
|
-
// DeleteCompiler path – old behavior
|
|
82
|
-
return candidate.compileDelete(this.state.ast);
|
|
83
|
-
}
|
|
106
|
+
/**
|
|
107
|
+
* Compiles the DELETE query for the specified dialect
|
|
108
|
+
* @param dialect - The SQL dialect to compile for
|
|
109
|
+
* @returns The compiled query with SQL and parameters
|
|
110
|
+
*/
|
|
111
|
+
compile(dialect: DeleteDialectInput): CompiledQuery {
|
|
112
|
+
const resolved = resolveDialectInput(dialect);
|
|
113
|
+
return resolved.compileDelete(this.state.ast);
|
|
114
|
+
}
|
|
84
115
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
116
|
+
/**
|
|
117
|
+
* Returns the SQL string for the DELETE query
|
|
118
|
+
* @param dialect - The SQL dialect to generate SQL for
|
|
119
|
+
* @returns The SQL string representation of the query
|
|
120
|
+
*/
|
|
121
|
+
toSql(dialect: DeleteDialectInput): string {
|
|
122
|
+
return this.compile(dialect).sql;
|
|
88
123
|
}
|
|
89
124
|
|
|
90
|
-
|
|
91
|
-
|
|
125
|
+
/**
|
|
126
|
+
* Executes the DELETE query using the provided session
|
|
127
|
+
* @param session - The ORM session to execute the query with
|
|
128
|
+
* @returns A promise that resolves to the query results
|
|
129
|
+
*/
|
|
130
|
+
async execute(session: OrmSession): Promise<QueryResult[]> {
|
|
131
|
+
const compiled = this.compile(session.dialect);
|
|
132
|
+
return session.executor.executeSql(compiled.sql, compiled.params);
|
|
92
133
|
}
|
|
93
134
|
|
|
135
|
+
/**
|
|
136
|
+
* Returns the Abstract Syntax Tree (AST) representation of the query
|
|
137
|
+
* @returns The AST node for the DELETE query
|
|
138
|
+
*/
|
|
94
139
|
getAST(): DeleteQueryNode {
|
|
95
140
|
return this.state.ast;
|
|
96
141
|
}
|
|
@@ -113,6 +113,11 @@ export class HydrationManager {
|
|
|
113
113
|
return hasPagination && this.hasMultiplyingRelations(plan);
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
+
/**
|
|
117
|
+
* Checks if the hydration plan contains relations that multiply rows
|
|
118
|
+
* @param plan - Hydration plan to check
|
|
119
|
+
* @returns True if plan has HasMany or BelongsToMany relations
|
|
120
|
+
*/
|
|
116
121
|
private hasMultiplyingRelations(plan: HydrationPlan): boolean {
|
|
117
122
|
return plan.relations.some(
|
|
118
123
|
rel => rel.type === RelationKinds.HasMany || rel.type === RelationKinds.BelongsToMany
|
|
@@ -203,6 +208,12 @@ export class HydrationManager {
|
|
|
203
208
|
};
|
|
204
209
|
}
|
|
205
210
|
|
|
211
|
+
/**
|
|
212
|
+
* Generates a unique CTE name by appending a suffix if needed
|
|
213
|
+
* @param existing - Existing CTE nodes
|
|
214
|
+
* @param baseName - Base name for the CTE
|
|
215
|
+
* @returns Unique CTE name
|
|
216
|
+
*/
|
|
206
217
|
private nextCteName(existing: CommonTableExpressionNode[] | undefined, baseName: string): string {
|
|
207
218
|
const names = new Set((existing ?? []).map(cte => cte.name));
|
|
208
219
|
let candidate = baseName;
|
|
@@ -216,6 +227,11 @@ export class HydrationManager {
|
|
|
216
227
|
return candidate;
|
|
217
228
|
}
|
|
218
229
|
|
|
230
|
+
/**
|
|
231
|
+
* Extracts projection names from column nodes
|
|
232
|
+
* @param columns - Projection nodes
|
|
233
|
+
* @returns Array of names or undefined if any column lacks name/alias
|
|
234
|
+
*/
|
|
219
235
|
private getProjectionNames(columns: ProjectionNode[]): string[] | undefined {
|
|
220
236
|
const names: string[] = [];
|
|
221
237
|
for (const col of columns) {
|
|
@@ -227,6 +243,11 @@ export class HydrationManager {
|
|
|
227
243
|
return names;
|
|
228
244
|
}
|
|
229
245
|
|
|
246
|
+
/**
|
|
247
|
+
* Builds a map of column keys to their aliases from projection nodes
|
|
248
|
+
* @param columns - Projection nodes
|
|
249
|
+
* @returns Map of 'table.name' to alias
|
|
250
|
+
*/
|
|
230
251
|
private buildProjectionAliasMap(columns: ProjectionNode[]): Map<string, string> {
|
|
231
252
|
const map = new Map<string, string>();
|
|
232
253
|
for (const col of columns) {
|
|
@@ -238,6 +259,15 @@ export class HydrationManager {
|
|
|
238
259
|
return map;
|
|
239
260
|
}
|
|
240
261
|
|
|
262
|
+
/**
|
|
263
|
+
* Maps order by nodes to use base CTE alias
|
|
264
|
+
* @param orderBy - Original order by nodes
|
|
265
|
+
* @param plan - Hydration plan
|
|
266
|
+
* @param projectionAliases - Map of column aliases
|
|
267
|
+
* @param baseAlias - Base CTE alias
|
|
268
|
+
* @param availableColumns - Set of available column names
|
|
269
|
+
* @returns Mapped order by nodes, null if cannot map
|
|
270
|
+
*/
|
|
241
271
|
private mapOrderBy(
|
|
242
272
|
orderBy: OrderByNode[] | undefined,
|
|
243
273
|
plan: HydrationPlan,
|
|
@@ -261,6 +291,15 @@ export class HydrationManager {
|
|
|
261
291
|
return mapped;
|
|
262
292
|
}
|
|
263
293
|
|
|
294
|
+
/**
|
|
295
|
+
* Maps a single ordering term to use base CTE alias
|
|
296
|
+
* @param term - Ordering term to map
|
|
297
|
+
* @param plan - Hydration plan
|
|
298
|
+
* @param projectionAliases - Map of column aliases
|
|
299
|
+
* @param baseAlias - Base CTE alias
|
|
300
|
+
* @param availableColumns - Set of available column names
|
|
301
|
+
* @returns Mapped term or null if cannot map
|
|
302
|
+
*/
|
|
264
303
|
private mapOrderingTerm(
|
|
265
304
|
term: OrderByNode['term'],
|
|
266
305
|
plan: HydrationPlan,
|
|
@@ -285,6 +324,13 @@ export class HydrationManager {
|
|
|
285
324
|
return null;
|
|
286
325
|
}
|
|
287
326
|
|
|
327
|
+
/**
|
|
328
|
+
* Builds column nodes for paging CTE
|
|
329
|
+
* @param primaryKey - Primary key name
|
|
330
|
+
* @param orderBy - Order by nodes
|
|
331
|
+
* @param tableAlias - Table alias for columns
|
|
332
|
+
* @returns Array of column nodes for paging
|
|
333
|
+
*/
|
|
288
334
|
private buildPagingColumns(primaryKey: string, orderBy: OrderByNode[] | undefined, tableAlias: string): ColumnNode[] {
|
|
289
335
|
const columns: ColumnNode[] = [{ type: 'Column', table: tableAlias, name: primaryKey, alias: primaryKey }];
|
|
290
336
|
|
|
@@ -20,6 +20,11 @@ export class InsertQueryState {
|
|
|
20
20
|
public readonly table: TableDef;
|
|
21
21
|
public readonly ast: InsertQueryNode;
|
|
22
22
|
|
|
23
|
+
/**
|
|
24
|
+
* Creates a new InsertQueryState instance
|
|
25
|
+
* @param table - The table definition for the INSERT query
|
|
26
|
+
* @param ast - Optional initial AST node, defaults to a basic INSERT query
|
|
27
|
+
*/
|
|
23
28
|
constructor(table: TableDef, ast?: InsertQueryNode) {
|
|
24
29
|
this.table = table;
|
|
25
30
|
this.ast = ast ?? {
|
|
@@ -55,6 +60,13 @@ export class InsertQueryState {
|
|
|
55
60
|
return buildColumnNodes(this.table, names);
|
|
56
61
|
}
|
|
57
62
|
|
|
63
|
+
/**
|
|
64
|
+
* Adds VALUES clause to the INSERT query
|
|
65
|
+
* @param rows - Array of row objects to insert
|
|
66
|
+
* @returns A new InsertQueryState with the VALUES clause added
|
|
67
|
+
* @throws Error if mixing VALUES with SELECT source
|
|
68
|
+
* @throws Error if invalid values are provided
|
|
69
|
+
*/
|
|
58
70
|
withValues(rows: Record<string, unknown>[]): InsertQueryState {
|
|
59
71
|
if (!rows.length) return this;
|
|
60
72
|
|
|
@@ -88,6 +100,11 @@ export class InsertQueryState {
|
|
|
88
100
|
});
|
|
89
101
|
}
|
|
90
102
|
|
|
103
|
+
/**
|
|
104
|
+
* Sets the columns for the INSERT query
|
|
105
|
+
* @param columns - Column nodes to insert into
|
|
106
|
+
* @returns A new InsertQueryState with the specified columns
|
|
107
|
+
*/
|
|
91
108
|
withColumns(columns: ColumnNode[]): InsertQueryState {
|
|
92
109
|
if (!columns.length) return this;
|
|
93
110
|
return this.clone({
|
|
@@ -96,6 +113,14 @@ export class InsertQueryState {
|
|
|
96
113
|
});
|
|
97
114
|
}
|
|
98
115
|
|
|
116
|
+
/**
|
|
117
|
+
* Adds SELECT source to the INSERT query
|
|
118
|
+
* @param query - The SELECT query to use as source
|
|
119
|
+
* @param columns - Target columns for the INSERT
|
|
120
|
+
* @returns A new InsertQueryState with the SELECT source
|
|
121
|
+
* @throws Error if mixing SELECT with VALUES source
|
|
122
|
+
* @throws Error if no destination columns specified
|
|
123
|
+
*/
|
|
99
124
|
withSelect(query: SelectQueryNode, columns: ColumnNode[]): InsertQueryState {
|
|
100
125
|
const targetColumns =
|
|
101
126
|
columns.length
|
|
@@ -122,6 +147,11 @@ export class InsertQueryState {
|
|
|
122
147
|
});
|
|
123
148
|
}
|
|
124
149
|
|
|
150
|
+
/**
|
|
151
|
+
* Adds a RETURNING clause to the INSERT query
|
|
152
|
+
* @param columns - Columns to return after insertion
|
|
153
|
+
* @returns A new InsertQueryState with the RETURNING clause added
|
|
154
|
+
*/
|
|
125
155
|
withReturning(columns: ColumnNode[]): InsertQueryState {
|
|
126
156
|
return this.clone({
|
|
127
157
|
...this.ast,
|
|
@@ -17,6 +17,11 @@ export class InsertQueryBuilder<T> {
|
|
|
17
17
|
private readonly table: TableDef;
|
|
18
18
|
private readonly state: InsertQueryState;
|
|
19
19
|
|
|
20
|
+
/**
|
|
21
|
+
* Creates a new InsertQueryBuilder instance
|
|
22
|
+
* @param table - The table definition for the INSERT query
|
|
23
|
+
* @param state - Optional initial query state, defaults to a new InsertQueryState
|
|
24
|
+
*/
|
|
20
25
|
constructor(table: TableDef, state?: InsertQueryState) {
|
|
21
26
|
this.table = table;
|
|
22
27
|
this.state = state ?? new InsertQueryState(table);
|
|
@@ -26,17 +31,34 @@ export class InsertQueryBuilder<T> {
|
|
|
26
31
|
return new InsertQueryBuilder(this.table, state);
|
|
27
32
|
}
|
|
28
33
|
|
|
34
|
+
/**
|
|
35
|
+
* Adds VALUES to the INSERT query
|
|
36
|
+
* @param rowOrRows - Single row object or array of row objects to insert
|
|
37
|
+
* @returns A new InsertQueryBuilder with the VALUES clause added
|
|
38
|
+
*/
|
|
29
39
|
values(rowOrRows: Record<string, unknown> | Record<string, unknown>[]): InsertQueryBuilder<T> {
|
|
30
40
|
const rows = Array.isArray(rowOrRows) ? rowOrRows : [rowOrRows];
|
|
31
41
|
if (!rows.length) return this;
|
|
32
42
|
return this.clone(this.state.withValues(rows));
|
|
33
43
|
}
|
|
34
44
|
|
|
45
|
+
/**
|
|
46
|
+
* Specifies the columns for the INSERT query
|
|
47
|
+
* @param columns - Column definitions or nodes to insert into
|
|
48
|
+
* @returns A new InsertQueryBuilder with the specified columns
|
|
49
|
+
*/
|
|
35
50
|
columns(...columns: (ColumnDef | ColumnNode)[]): InsertQueryBuilder<T> {
|
|
36
51
|
if (!columns.length) return this;
|
|
37
52
|
return this.clone(this.state.withColumns(this.resolveColumnNodes(columns)));
|
|
38
53
|
}
|
|
39
54
|
|
|
55
|
+
/**
|
|
56
|
+
* Sets the source of the INSERT query to a SELECT query
|
|
57
|
+
* @template TSource - The source table type
|
|
58
|
+
* @param query - The SELECT query or query builder to use as source
|
|
59
|
+
* @param columns - Optional target columns for the INSERT
|
|
60
|
+
* @returns A new InsertQueryBuilder with the SELECT source
|
|
61
|
+
*/
|
|
40
62
|
fromSelect<TSource extends TableDef>(
|
|
41
63
|
query: SelectQueryNode | SelectQueryBuilder<unknown, TSource>,
|
|
42
64
|
columns: (ColumnDef | ColumnNode)[] = []
|
|
@@ -46,6 +68,11 @@ export class InsertQueryBuilder<T> {
|
|
|
46
68
|
return this.clone(this.state.withSelect(ast, nodes));
|
|
47
69
|
}
|
|
48
70
|
|
|
71
|
+
/**
|
|
72
|
+
* Adds a RETURNING clause to the INSERT query
|
|
73
|
+
* @param columns - Columns to return after insertion
|
|
74
|
+
* @returns A new InsertQueryBuilder with the RETURNING clause added
|
|
75
|
+
*/
|
|
49
76
|
returning(...columns: (ColumnDef | ColumnNode)[]): InsertQueryBuilder<T> {
|
|
50
77
|
if (!columns.length) return this;
|
|
51
78
|
const nodes = columns.map(column => buildColumnNode(this.table, column));
|
|
@@ -68,9 +95,17 @@ export class InsertQueryBuilder<T> {
|
|
|
68
95
|
|
|
69
96
|
// Existing compiler-based compile stays, but we add a new overload.
|
|
70
97
|
|
|
71
|
-
|
|
98
|
+
/**
|
|
99
|
+
* Compiles the INSERT query
|
|
100
|
+
* @param compiler - The INSERT compiler to use
|
|
101
|
+
* @returns The compiled query with SQL and parameters
|
|
102
|
+
*/
|
|
72
103
|
compile(compiler: InsertCompiler): CompiledQuery;
|
|
73
|
-
|
|
104
|
+
/**
|
|
105
|
+
* Compiles the INSERT query for the specified dialect
|
|
106
|
+
* @param dialect - The SQL dialect to compile for
|
|
107
|
+
* @returns The compiled query with SQL and parameters
|
|
108
|
+
*/
|
|
74
109
|
compile(dialect: InsertDialectInput): CompiledQuery;
|
|
75
110
|
|
|
76
111
|
compile(arg: InsertCompiler | InsertDialectInput): CompiledQuery {
|
|
@@ -85,10 +120,19 @@ export class InsertQueryBuilder<T> {
|
|
|
85
120
|
return dialect.compileInsert(this.state.ast);
|
|
86
121
|
}
|
|
87
122
|
|
|
123
|
+
/**
|
|
124
|
+
* Returns the SQL string for the INSERT query
|
|
125
|
+
* @param arg - The compiler or dialect to generate SQL for
|
|
126
|
+
* @returns The SQL string representation of the query
|
|
127
|
+
*/
|
|
88
128
|
toSql(arg: InsertCompiler | InsertDialectInput): string {
|
|
89
129
|
return this.compile(arg as InsertCompiler).sql;
|
|
90
130
|
}
|
|
91
131
|
|
|
132
|
+
/**
|
|
133
|
+
* Returns the Abstract Syntax Tree (AST) representation of the query
|
|
134
|
+
* @returns The AST node for the INSERT query
|
|
135
|
+
*/
|
|
92
136
|
getAST(): InsertQueryNode {
|
|
93
137
|
return this.state.ast;
|
|
94
138
|
}
|