metal-orm 1.1.7 → 1.1.8
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/dist/index.cjs +262 -202
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +12 -2
- package/dist/index.d.ts +12 -2
- package/dist/index.js +261 -202
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/scripts/generate-entities/schema.mjs +196 -195
- package/src/decorators/decorator-metadata.ts +52 -46
- package/src/decorators/entity.ts +73 -68
- package/src/orm/entity-metadata.ts +301 -301
- package/src/orm/entity.ts +199 -199
- package/src/orm/save-graph.ts +446 -446
- package/src/orm/unit-of-work.ts +6 -6
- package/src/tree/tree-decorator.ts +137 -54
package/src/orm/unit-of-work.ts
CHANGED
|
@@ -6,8 +6,8 @@ import { UpdateQueryBuilder } from '../query-builder/update.js';
|
|
|
6
6
|
import { DeleteQueryBuilder } from '../query-builder/delete.js';
|
|
7
7
|
import { findPrimaryKey } from '../query-builder/hydration-planner.js';
|
|
8
8
|
import type { TableDef, TableHooks } from '../schema/table.js';
|
|
9
|
-
import { payloadResultSets } from '../core/execution/db-executor.js';
|
|
10
|
-
import type { DbExecutor, QueryResult } from '../core/execution/db-executor.js';
|
|
9
|
+
import { payloadResultSets } from '../core/execution/db-executor.js';
|
|
10
|
+
import type { DbExecutor, QueryResult } from '../core/execution/db-executor.js';
|
|
11
11
|
import { IdentityMap } from './identity-map.js';
|
|
12
12
|
import { EntityStatus } from './runtime-types.js';
|
|
13
13
|
import type { TrackedEntity } from './runtime-types.js';
|
|
@@ -323,10 +323,10 @@ export class UnitOfWork {
|
|
|
323
323
|
* @param compiled - The compiled query
|
|
324
324
|
* @returns Query results
|
|
325
325
|
*/
|
|
326
|
-
private async executeCompiled(compiled: CompiledQuery): Promise<QueryResult[]> {
|
|
327
|
-
const payload = await this.executor.executeSql(compiled.sql, compiled.params);
|
|
328
|
-
return payloadResultSets(payload);
|
|
329
|
-
}
|
|
326
|
+
private async executeCompiled(compiled: CompiledQuery): Promise<QueryResult[]> {
|
|
327
|
+
const payload = await this.executor.executeSql(compiled.sql, compiled.params);
|
|
328
|
+
return payloadResultSets(payload);
|
|
329
|
+
}
|
|
330
330
|
|
|
331
331
|
/**
|
|
332
332
|
* Gets columns for RETURNING clause.
|
|
@@ -5,8 +5,16 @@
|
|
|
5
5
|
* Integrates with MetalORM's decorator entity system.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import type { TreeConfig } from './tree-types.js';
|
|
9
|
-
import { resolveTreeConfig } from './tree-types.js';
|
|
8
|
+
import type { TreeConfig } from './tree-types.js';
|
|
9
|
+
import { resolveTreeConfig } from './tree-types.js';
|
|
10
|
+
import { RelationKinds, belongsTo, hasMany } from '../schema/relation.js';
|
|
11
|
+
import { addRelationMetadata, getEntityMetadata, type EntityConstructor } from '../orm/entity-metadata.js';
|
|
12
|
+
import {
|
|
13
|
+
type DecoratorTreeMetadata,
|
|
14
|
+
getOrCreateMetadataBag,
|
|
15
|
+
readMetadataBag,
|
|
16
|
+
readMetadataBagFromConstructor
|
|
17
|
+
} from '../decorators/decorator-metadata.js';
|
|
10
18
|
|
|
11
19
|
/**
|
|
12
20
|
* Symbol key for storing tree metadata on entity classes.
|
|
@@ -73,18 +81,25 @@ export interface TreeDecoratorOptions {
|
|
|
73
81
|
* }
|
|
74
82
|
* ```
|
|
75
83
|
*/
|
|
76
|
-
export function Tree(options: TreeDecoratorOptions = {}) {
|
|
77
|
-
return function <T extends abstract new (...args: unknown[]) => object>(
|
|
78
|
-
target: T
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
}
|
|
84
|
+
export function Tree(options: TreeDecoratorOptions = {}) {
|
|
85
|
+
return function <T extends abstract new (...args: unknown[]) => object>(
|
|
86
|
+
target: T,
|
|
87
|
+
context: ClassDecoratorContext<T>
|
|
88
|
+
): T {
|
|
89
|
+
const config = resolveTreeConfig(options);
|
|
90
|
+
const metadataBag = readMetadataBag(context) ?? readMetadataBagFromConstructor(target);
|
|
91
|
+
const metadata: TreeMetadata = {
|
|
92
|
+
config,
|
|
93
|
+
parentProperty: metadataBag?.tree?.parentProperty,
|
|
94
|
+
childrenProperty: metadataBag?.tree?.childrenProperty
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
setTreeMetadataOnClass(target, metadata);
|
|
98
|
+
registerTreeRelations(target as unknown as EntityConstructor, metadata);
|
|
99
|
+
|
|
100
|
+
return target;
|
|
101
|
+
};
|
|
102
|
+
}
|
|
88
103
|
|
|
89
104
|
/**
|
|
90
105
|
* Decorator to mark a property as the parent relation in a tree entity.
|
|
@@ -95,23 +110,22 @@ export function Tree(options: TreeDecoratorOptions = {}) {
|
|
|
95
110
|
* parent?: Category;
|
|
96
111
|
* ```
|
|
97
112
|
*/
|
|
98
|
-
export function TreeParent() {
|
|
99
|
-
return function <T, V>(
|
|
100
|
-
_value: undefined,
|
|
101
|
-
context: ClassFieldDecoratorContext<T, V>
|
|
102
|
-
): void {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
}
|
|
113
|
+
export function TreeParent() {
|
|
114
|
+
return function <T, V>(
|
|
115
|
+
_value: undefined,
|
|
116
|
+
context: ClassFieldDecoratorContext<T, V>
|
|
117
|
+
): void {
|
|
118
|
+
if (!context.name) {
|
|
119
|
+
throw new Error('TreeParent decorator requires a property name');
|
|
120
|
+
}
|
|
121
|
+
if (context.private) {
|
|
122
|
+
throw new Error('TreeParent decorator does not support private fields');
|
|
123
|
+
}
|
|
124
|
+
const propertyName = String(context.name);
|
|
125
|
+
const bag = getOrCreateMetadataBag(context);
|
|
126
|
+
bag.tree = { ...bag.tree, parentProperty: propertyName };
|
|
127
|
+
};
|
|
128
|
+
}
|
|
115
129
|
|
|
116
130
|
/**
|
|
117
131
|
* Decorator to mark a property as the children relation in a tree entity.
|
|
@@ -122,23 +136,54 @@ export function TreeParent() {
|
|
|
122
136
|
* children?: Category[];
|
|
123
137
|
* ```
|
|
124
138
|
*/
|
|
125
|
-
export function TreeChildren() {
|
|
126
|
-
return function <T, V>(
|
|
127
|
-
_value: undefined,
|
|
128
|
-
context: ClassFieldDecoratorContext<T, V>
|
|
129
|
-
): void {
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
139
|
+
export function TreeChildren() {
|
|
140
|
+
return function <T, V>(
|
|
141
|
+
_value: undefined,
|
|
142
|
+
context: ClassFieldDecoratorContext<T, V>
|
|
143
|
+
): void {
|
|
144
|
+
if (!context.name) {
|
|
145
|
+
throw new Error('TreeChildren decorator requires a property name');
|
|
146
|
+
}
|
|
147
|
+
if (context.private) {
|
|
148
|
+
throw new Error('TreeChildren decorator does not support private fields');
|
|
149
|
+
}
|
|
150
|
+
const propertyName = String(context.name);
|
|
151
|
+
const bag = getOrCreateMetadataBag(context);
|
|
152
|
+
bag.tree = { ...bag.tree, childrenProperty: propertyName };
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Synchronizes tree metadata + self-relations for entities using @Tree decorators.
|
|
158
|
+
* Safe to call multiple times (idempotent).
|
|
159
|
+
*/
|
|
160
|
+
export function syncTreeEntityMetadata(
|
|
161
|
+
ctor: EntityConstructor,
|
|
162
|
+
treeMetadata?: DecoratorTreeMetadata
|
|
163
|
+
): void {
|
|
164
|
+
const current = getTreeMetadata(ctor);
|
|
165
|
+
if (!current) return;
|
|
166
|
+
const metadataBag = readMetadataBagFromConstructor(ctor);
|
|
167
|
+
|
|
168
|
+
const nextParentProperty =
|
|
169
|
+
treeMetadata?.parentProperty ?? metadataBag?.tree?.parentProperty ?? current.parentProperty;
|
|
170
|
+
const nextChildrenProperty =
|
|
171
|
+
treeMetadata?.childrenProperty ?? metadataBag?.tree?.childrenProperty ?? current.childrenProperty;
|
|
172
|
+
|
|
173
|
+
if (nextParentProperty !== current.parentProperty || nextChildrenProperty !== current.childrenProperty) {
|
|
174
|
+
setTreeMetadata(ctor, {
|
|
175
|
+
...current,
|
|
176
|
+
parentProperty: nextParentProperty,
|
|
177
|
+
childrenProperty: nextChildrenProperty
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
registerTreeRelations(ctor, {
|
|
182
|
+
...current,
|
|
183
|
+
parentProperty: nextParentProperty,
|
|
184
|
+
childrenProperty: nextChildrenProperty
|
|
185
|
+
});
|
|
186
|
+
}
|
|
142
187
|
|
|
143
188
|
/**
|
|
144
189
|
* Gets tree metadata from an entity class.
|
|
@@ -152,12 +197,50 @@ export function getTreeMetadata(
|
|
|
152
197
|
/**
|
|
153
198
|
* Sets tree metadata on an entity class.
|
|
154
199
|
*/
|
|
155
|
-
export function setTreeMetadata(
|
|
156
|
-
target: new (...args: unknown[]) => object,
|
|
157
|
-
metadata: TreeMetadata
|
|
158
|
-
): void {
|
|
159
|
-
(target as unknown as Record<symbol, TreeMetadata>)[TREE_METADATA_KEY] = metadata;
|
|
160
|
-
}
|
|
200
|
+
export function setTreeMetadata(
|
|
201
|
+
target: new (...args: unknown[]) => object,
|
|
202
|
+
metadata: TreeMetadata
|
|
203
|
+
): void {
|
|
204
|
+
(target as unknown as Record<symbol, TreeMetadata>)[TREE_METADATA_KEY] = metadata;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const registerTreeRelations = (
|
|
208
|
+
target: EntityConstructor,
|
|
209
|
+
metadata: TreeMetadata
|
|
210
|
+
): void => {
|
|
211
|
+
const entityMeta = getEntityMetadata(target);
|
|
212
|
+
if (!entityMeta) return;
|
|
213
|
+
|
|
214
|
+
if (metadata.parentProperty && !entityMeta.relations[metadata.parentProperty]) {
|
|
215
|
+
addRelationMetadata(target, metadata.parentProperty, {
|
|
216
|
+
kind: RelationKinds.BelongsTo,
|
|
217
|
+
propertyKey: metadata.parentProperty,
|
|
218
|
+
target: () => target,
|
|
219
|
+
foreignKey: metadata.config.parentKey
|
|
220
|
+
});
|
|
221
|
+
if (entityMeta.table && !entityMeta.table.relations[metadata.parentProperty]) {
|
|
222
|
+
entityMeta.table.relations[metadata.parentProperty] = belongsTo(
|
|
223
|
+
entityMeta.table,
|
|
224
|
+
metadata.config.parentKey
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
if (metadata.childrenProperty && !entityMeta.relations[metadata.childrenProperty]) {
|
|
230
|
+
addRelationMetadata(target, metadata.childrenProperty, {
|
|
231
|
+
kind: RelationKinds.HasMany,
|
|
232
|
+
propertyKey: metadata.childrenProperty,
|
|
233
|
+
target: () => target,
|
|
234
|
+
foreignKey: metadata.config.parentKey
|
|
235
|
+
});
|
|
236
|
+
if (entityMeta.table && !entityMeta.table.relations[metadata.childrenProperty]) {
|
|
237
|
+
entityMeta.table.relations[metadata.childrenProperty] = hasMany(
|
|
238
|
+
entityMeta.table,
|
|
239
|
+
metadata.config.parentKey
|
|
240
|
+
);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
};
|
|
161
244
|
|
|
162
245
|
/**
|
|
163
246
|
* Sets tree metadata on an entity class (internal, handles abstract classes).
|