metal-orm 1.1.8 → 1.1.10
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 +769 -764
- package/dist/index.cjs +2352 -226
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +605 -40
- package/dist/index.d.ts +605 -40
- package/dist/index.js +2324 -226
- package/dist/index.js.map +1 -1
- package/package.json +22 -17
- package/src/bulk/bulk-context.ts +83 -0
- package/src/bulk/bulk-delete-executor.ts +89 -0
- package/src/bulk/bulk-executor.base.ts +73 -0
- package/src/bulk/bulk-insert-executor.ts +74 -0
- package/src/bulk/bulk-types.ts +70 -0
- package/src/bulk/bulk-update-executor.ts +192 -0
- package/src/bulk/bulk-upsert-executor.ts +95 -0
- package/src/bulk/bulk-utils.ts +91 -0
- package/src/bulk/index.ts +18 -0
- package/src/codegen/typescript.ts +30 -21
- package/src/core/ast/expression-builders.ts +107 -10
- package/src/core/ast/expression-nodes.ts +52 -22
- package/src/core/ast/expression-visitor.ts +23 -13
- package/src/core/dialect/abstract.ts +30 -17
- package/src/core/dialect/mysql/index.ts +20 -5
- package/src/core/execution/db-executor.ts +96 -64
- package/src/core/execution/executors/better-sqlite3-executor.ts +94 -0
- package/src/core/execution/executors/mssql-executor.ts +66 -34
- package/src/core/execution/executors/mysql-executor.ts +98 -66
- package/src/core/execution/executors/postgres-executor.ts +33 -11
- package/src/core/execution/executors/sqlite-executor.ts +86 -30
- package/src/decorators/bootstrap.ts +482 -398
- package/src/decorators/column-decorator.ts +87 -96
- package/src/decorators/decorator-metadata.ts +100 -24
- package/src/decorators/entity.ts +27 -24
- package/src/decorators/relations.ts +231 -149
- package/src/decorators/transformers/transformer-decorators.ts +26 -29
- package/src/decorators/validators/country-validators-decorators.ts +9 -15
- package/src/dto/apply-filter.ts +568 -551
- package/src/index.ts +16 -9
- package/src/orm/entity-hydration.ts +116 -72
- package/src/orm/entity-metadata.ts +347 -301
- package/src/orm/entity-relations.ts +264 -207
- package/src/orm/entity.ts +199 -199
- package/src/orm/execute.ts +13 -13
- package/src/orm/lazy-batch/morph-many.ts +70 -0
- package/src/orm/lazy-batch/morph-one.ts +69 -0
- package/src/orm/lazy-batch/morph-to.ts +59 -0
- package/src/orm/lazy-batch.ts +4 -1
- package/src/orm/orm-session.ts +170 -104
- package/src/orm/pooled-executor-factory.ts +99 -58
- package/src/orm/query-logger.ts +49 -40
- package/src/orm/relation-change-processor.ts +198 -96
- package/src/orm/relations/belongs-to.ts +143 -143
- package/src/orm/relations/has-many.ts +204 -204
- package/src/orm/relations/has-one.ts +174 -174
- package/src/orm/relations/many-to-many.ts +288 -288
- package/src/orm/relations/morph-many.ts +156 -0
- package/src/orm/relations/morph-one.ts +151 -0
- package/src/orm/relations/morph-to.ts +162 -0
- package/src/orm/save-graph.ts +116 -1
- package/src/query-builder/expression-table-mapper.ts +5 -0
- package/src/query-builder/hydration-manager.ts +345 -345
- package/src/query-builder/hydration-planner.ts +178 -148
- package/src/query-builder/relation-conditions.ts +171 -151
- package/src/query-builder/relation-cte-builder.ts +5 -1
- package/src/query-builder/relation-filter-utils.ts +9 -6
- package/src/query-builder/relation-include-strategies.ts +44 -2
- package/src/query-builder/relation-join-strategies.ts +8 -1
- package/src/query-builder/relation-service.ts +250 -241
- package/src/query-builder/select/cursor-pagination.ts +323 -0
- package/src/query-builder/select/select-operations.ts +110 -105
- package/src/query-builder/select.ts +42 -1
- package/src/query-builder/update-include.ts +4 -0
- package/src/schema/relation.ts +296 -188
- package/src/schema/types.ts +138 -123
- package/src/tree/tree-decorator.ts +127 -137
package/src/schema/types.ts
CHANGED
|
@@ -1,105 +1,120 @@
|
|
|
1
|
-
import type { ColumnDef } from './column-types.js';
|
|
2
|
-
export type { ColumnDef };
|
|
3
|
-
import { TableDef } from './table.js';
|
|
4
|
-
import {
|
|
5
|
-
RelationDef,
|
|
6
|
-
HasManyRelation,
|
|
7
|
-
HasOneRelation,
|
|
8
|
-
BelongsToRelation,
|
|
9
|
-
BelongsToManyRelation
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
TRel extends
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
NormalizedColumnType<T> extends '
|
|
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
|
-
|
|
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
|
-
|
|
1
|
+
import type { ColumnDef } from './column-types.js';
|
|
2
|
+
export type { ColumnDef };
|
|
3
|
+
import { TableDef } from './table.js';
|
|
4
|
+
import {
|
|
5
|
+
RelationDef,
|
|
6
|
+
HasManyRelation,
|
|
7
|
+
HasOneRelation,
|
|
8
|
+
BelongsToRelation,
|
|
9
|
+
BelongsToManyRelation,
|
|
10
|
+
MorphToRelation,
|
|
11
|
+
MorphOneRelation,
|
|
12
|
+
MorphManyRelation
|
|
13
|
+
} from './relation.js';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Resolves a relation definition to its target table type.
|
|
17
|
+
*/
|
|
18
|
+
export type RelationTargetTable<TRel extends RelationDef> =
|
|
19
|
+
TRel extends HasManyRelation<infer TTarget> ? TTarget :
|
|
20
|
+
TRel extends HasOneRelation<infer TTarget> ? TTarget :
|
|
21
|
+
TRel extends BelongsToRelation<infer TTarget> ? TTarget :
|
|
22
|
+
TRel extends BelongsToManyRelation<infer TTarget, TableDef> ? TTarget :
|
|
23
|
+
TRel extends MorphOneRelation<infer TTarget> ? TTarget :
|
|
24
|
+
TRel extends MorphManyRelation<infer TTarget> ? TTarget :
|
|
25
|
+
TRel extends MorphToRelation ? never :
|
|
26
|
+
never;
|
|
27
|
+
|
|
28
|
+
export type JsonValue = string | number | boolean | null | JsonArray | JsonObject;
|
|
29
|
+
export type JsonArray = Array<JsonValue>;
|
|
30
|
+
export interface JsonObject { [key: string]: JsonValue }
|
|
31
|
+
|
|
32
|
+
type NormalizedColumnType<T extends ColumnDef> = Lowercase<T['type'] & string>;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Maps a ColumnDef to its TypeScript type representation
|
|
36
|
+
*/
|
|
37
|
+
export type ColumnToTs<T extends ColumnDef> =
|
|
38
|
+
[unknown] extends [T['tsType']]
|
|
39
|
+
? NormalizedColumnType<T> extends 'int' | 'integer' ? number :
|
|
40
|
+
NormalizedColumnType<T> extends 'bigint' ? number | bigint :
|
|
41
|
+
NormalizedColumnType<T> extends 'decimal' | 'float' | 'double' ? number :
|
|
42
|
+
NormalizedColumnType<T> extends 'boolean' ? boolean :
|
|
43
|
+
NormalizedColumnType<T> extends 'json' ? JsonValue :
|
|
44
|
+
NormalizedColumnType<T> extends 'blob' | 'binary' | 'varbinary' | 'bytea' ? Buffer :
|
|
45
|
+
NormalizedColumnType<T> extends 'date' | 'datetime' | 'timestamp' | 'timestamptz' ? string :
|
|
46
|
+
string
|
|
47
|
+
: Exclude<T['tsType'], undefined>;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Infers a row shape from a table definition
|
|
51
|
+
*/
|
|
52
|
+
export type InferRow<TTable extends TableDef> = {
|
|
53
|
+
[K in keyof TTable['columns']]: ColumnToTs<TTable['columns'][K]>;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
type RelationResult<T extends RelationDef> =
|
|
57
|
+
T extends HasManyRelation<infer TTarget> ? InferRow<TTarget>[] :
|
|
58
|
+
T extends HasOneRelation<infer TTarget> ? InferRow<TTarget> | null :
|
|
59
|
+
T extends BelongsToRelation<infer TTarget> ? InferRow<TTarget> | null :
|
|
60
|
+
T extends BelongsToManyRelation<infer TTarget, infer TPivot> ? (InferRow<TTarget> & { _pivot?: InferRow<TPivot> })[] :
|
|
61
|
+
T extends MorphOneRelation<infer TTarget> ? InferRow<TTarget> | null :
|
|
62
|
+
T extends MorphManyRelation<infer TTarget> ? InferRow<TTarget>[] :
|
|
63
|
+
T extends MorphToRelation ? Record<string, unknown> | null :
|
|
64
|
+
never;
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Maps relation names to the expected row results
|
|
68
|
+
*/
|
|
69
|
+
export type RelationMap<TTable extends TableDef> = {
|
|
70
|
+
[K in keyof TTable['relations']]: RelationResult<TTable['relations'][K]>;
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
type RelationWrapper<TRel extends RelationDef> =
|
|
74
|
+
TRel extends HasManyRelation<infer TTarget>
|
|
75
|
+
? HasManyCollection<EntityInstance<TTarget>> & ReadonlyArray<EntityInstance<TTarget>>
|
|
76
|
+
: TRel extends HasOneRelation<infer TTarget>
|
|
77
|
+
? HasOneReference<EntityInstance<TTarget>>
|
|
78
|
+
: TRel extends BelongsToManyRelation<infer TTarget, infer TPivot>
|
|
79
|
+
? ManyToManyCollection<EntityInstance<TTarget> & { _pivot?: InferRow<TPivot> }>
|
|
80
|
+
& ReadonlyArray<EntityInstance<TTarget> & { _pivot?: InferRow<TPivot> }>
|
|
81
|
+
: TRel extends BelongsToRelation<infer TTarget>
|
|
82
|
+
? BelongsToReference<EntityInstance<TTarget>>
|
|
83
|
+
: TRel extends MorphOneRelation<infer TTarget>
|
|
84
|
+
? HasOneReference<EntityInstance<TTarget>>
|
|
85
|
+
: TRel extends MorphManyRelation<infer TTarget>
|
|
86
|
+
? HasManyCollection<EntityInstance<TTarget>> & ReadonlyArray<EntityInstance<TTarget>>
|
|
87
|
+
: TRel extends MorphToRelation
|
|
88
|
+
? BelongsToReference<EntityInstance<TableDef>>
|
|
89
|
+
: never;
|
|
90
|
+
|
|
91
|
+
export interface HasManyCollection<TChild> {
|
|
92
|
+
length: number;
|
|
93
|
+
[Symbol.iterator](): Iterator<TChild>;
|
|
94
|
+
load(): Promise<TChild[]>;
|
|
95
|
+
getItems(): TChild[];
|
|
96
|
+
add(data: Partial<TChild>): TChild;
|
|
97
|
+
attach(entity: TChild): void;
|
|
98
|
+
remove(entity: TChild): void;
|
|
99
|
+
clear(): void;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export interface BelongsToReferenceApi<TParent extends object = object> {
|
|
103
|
+
load(): Promise<TParent | null>;
|
|
104
|
+
get(): TParent | null;
|
|
105
|
+
set(data: Partial<TParent> | TParent | null): TParent | null;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export type BelongsToReference<TParent extends object = object> = BelongsToReferenceApi<TParent> & Partial<TParent>;
|
|
109
|
+
|
|
110
|
+
export interface HasOneReferenceApi<TChild extends object = object> {
|
|
111
|
+
load(): Promise<TChild | null>;
|
|
112
|
+
get(): TChild | null;
|
|
113
|
+
set(data: Partial<TChild> | TChild | null): TChild | null;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export type HasOneReference<TChild extends object = object> = HasOneReferenceApi<TChild> & Partial<TChild>;
|
|
117
|
+
|
|
103
118
|
export interface ManyToManyCollection<TTarget, TPivot extends object | undefined = undefined> {
|
|
104
119
|
length: number;
|
|
105
120
|
[Symbol.iterator](): Iterator<TTarget>;
|
|
@@ -111,24 +126,24 @@ export interface ManyToManyCollection<TTarget, TPivot extends object | undefined
|
|
|
111
126
|
/** @internal Type-level marker for the related pivot entity */
|
|
112
127
|
readonly __pivotType?: TPivot;
|
|
113
128
|
}
|
|
114
|
-
|
|
115
|
-
export type EntityInstance<
|
|
116
|
-
TTable extends TableDef,
|
|
117
|
-
TRow = InferRow<TTable>
|
|
118
|
-
> = TRow & {
|
|
119
|
-
[K in keyof RelationMap<TTable>]: RelationWrapper<TTable['relations'][K]>;
|
|
120
|
-
} & {
|
|
121
|
-
$load<K extends keyof RelationMap<TTable>>(relation: K): Promise<RelationMap<TTable>[K]>;
|
|
122
|
-
};
|
|
123
|
-
|
|
124
|
-
export type Primitive = string | number | boolean | Date | bigint | Buffer | null | undefined;
|
|
125
|
-
|
|
126
|
-
type IsAny<T> = 0 extends (1 & T) ? true : false;
|
|
127
|
-
|
|
128
|
-
export type SelectableKeys<T> = {
|
|
129
|
-
[K in keyof T]-?: IsAny<T[K]> extends true
|
|
130
|
-
? never
|
|
131
|
-
: NonNullable<T[K]> extends Primitive
|
|
132
|
-
? K
|
|
133
|
-
: never
|
|
134
|
-
}[keyof T];
|
|
129
|
+
|
|
130
|
+
export type EntityInstance<
|
|
131
|
+
TTable extends TableDef,
|
|
132
|
+
TRow = InferRow<TTable>
|
|
133
|
+
> = TRow & {
|
|
134
|
+
[K in keyof RelationMap<TTable>]: RelationWrapper<TTable['relations'][K]>;
|
|
135
|
+
} & {
|
|
136
|
+
$load<K extends keyof RelationMap<TTable>>(relation: K): Promise<RelationMap<TTable>[K]>;
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
export type Primitive = string | number | boolean | Date | bigint | Buffer | null | undefined;
|
|
140
|
+
|
|
141
|
+
type IsAny<T> = 0 extends (1 & T) ? true : false;
|
|
142
|
+
|
|
143
|
+
export type SelectableKeys<T> = {
|
|
144
|
+
[K in keyof T]-?: IsAny<T[K]> extends true
|
|
145
|
+
? never
|
|
146
|
+
: NonNullable<T[K]> extends Primitive
|
|
147
|
+
? K
|
|
148
|
+
: never
|
|
149
|
+
}[keyof T];
|
|
@@ -5,16 +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';
|
|
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
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
} from '../decorators/decorator-metadata.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
|
+
readMetadataBag,
|
|
15
|
+
readMetadataBagFromConstructor,
|
|
16
|
+
resolveFieldDecoratorInfo
|
|
17
|
+
} from '../decorators/decorator-metadata.js';
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
20
|
* Symbol key for storing tree metadata on entity classes.
|
|
@@ -81,25 +81,27 @@ export interface TreeDecoratorOptions {
|
|
|
81
81
|
* }
|
|
82
82
|
* ```
|
|
83
83
|
*/
|
|
84
|
-
export function Tree(options: TreeDecoratorOptions = {}) {
|
|
85
|
-
return function <T extends abstract new (...args: unknown[]) => object>(
|
|
86
|
-
target: T,
|
|
87
|
-
context
|
|
88
|
-
): T {
|
|
89
|
-
const config = resolveTreeConfig(options);
|
|
90
|
-
const metadataBag =
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
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 = context
|
|
91
|
+
? readMetadataBag(context) ?? readMetadataBagFromConstructor(target)
|
|
92
|
+
: readMetadataBagFromConstructor(target);
|
|
93
|
+
const metadata: TreeMetadata = {
|
|
94
|
+
config,
|
|
95
|
+
parentProperty: metadataBag?.tree?.parentProperty,
|
|
96
|
+
childrenProperty: metadataBag?.tree?.childrenProperty
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
setTreeMetadataOnClass(target, metadata);
|
|
100
|
+
registerTreeRelations(target as unknown as EntityConstructor, metadata);
|
|
101
|
+
|
|
102
|
+
return target;
|
|
103
|
+
};
|
|
104
|
+
}
|
|
103
105
|
|
|
104
106
|
/**
|
|
105
107
|
* Decorator to mark a property as the parent relation in a tree entity.
|
|
@@ -110,22 +112,16 @@ export function Tree(options: TreeDecoratorOptions = {}) {
|
|
|
110
112
|
* parent?: Category;
|
|
111
113
|
* ```
|
|
112
114
|
*/
|
|
113
|
-
export function TreeParent() {
|
|
114
|
-
return function
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
}
|
|
124
|
-
const propertyName = String(context.name);
|
|
125
|
-
const bag = getOrCreateMetadataBag(context);
|
|
126
|
-
bag.tree = { ...bag.tree, parentProperty: propertyName };
|
|
127
|
-
};
|
|
128
|
-
}
|
|
115
|
+
export function TreeParent() {
|
|
116
|
+
return function (targetOrValue: unknown, contextOrProperty: unknown): void {
|
|
117
|
+
const { propertyName, bag } = resolveFieldDecoratorInfo(
|
|
118
|
+
targetOrValue,
|
|
119
|
+
contextOrProperty,
|
|
120
|
+
'TreeParent'
|
|
121
|
+
);
|
|
122
|
+
bag.tree = { ...bag.tree, parentProperty: propertyName };
|
|
123
|
+
};
|
|
124
|
+
}
|
|
129
125
|
|
|
130
126
|
/**
|
|
131
127
|
* Decorator to mark a property as the children relation in a tree entity.
|
|
@@ -136,54 +132,48 @@ export function TreeParent() {
|
|
|
136
132
|
* children?: Category[];
|
|
137
133
|
* ```
|
|
138
134
|
*/
|
|
139
|
-
export function TreeChildren() {
|
|
140
|
-
return function
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
const
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
registerTreeRelations(ctor, {
|
|
182
|
-
...current,
|
|
183
|
-
parentProperty: nextParentProperty,
|
|
184
|
-
childrenProperty: nextChildrenProperty
|
|
185
|
-
});
|
|
186
|
-
}
|
|
135
|
+
export function TreeChildren() {
|
|
136
|
+
return function (targetOrValue: unknown, contextOrProperty: unknown): void {
|
|
137
|
+
const { propertyName, bag } = resolveFieldDecoratorInfo(
|
|
138
|
+
targetOrValue,
|
|
139
|
+
contextOrProperty,
|
|
140
|
+
'TreeChildren'
|
|
141
|
+
);
|
|
142
|
+
bag.tree = { ...bag.tree, childrenProperty: propertyName };
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Synchronizes tree metadata + self-relations for entities using @Tree decorators.
|
|
148
|
+
* Safe to call multiple times (idempotent).
|
|
149
|
+
*/
|
|
150
|
+
export function syncTreeEntityMetadata(
|
|
151
|
+
ctor: EntityConstructor,
|
|
152
|
+
treeMetadata?: DecoratorTreeMetadata
|
|
153
|
+
): void {
|
|
154
|
+
const current = getTreeMetadata(ctor);
|
|
155
|
+
if (!current) return;
|
|
156
|
+
const metadataBag = readMetadataBagFromConstructor(ctor);
|
|
157
|
+
|
|
158
|
+
const nextParentProperty =
|
|
159
|
+
treeMetadata?.parentProperty ?? metadataBag?.tree?.parentProperty ?? current.parentProperty;
|
|
160
|
+
const nextChildrenProperty =
|
|
161
|
+
treeMetadata?.childrenProperty ?? metadataBag?.tree?.childrenProperty ?? current.childrenProperty;
|
|
162
|
+
|
|
163
|
+
if (nextParentProperty !== current.parentProperty || nextChildrenProperty !== current.childrenProperty) {
|
|
164
|
+
setTreeMetadata(ctor, {
|
|
165
|
+
...current,
|
|
166
|
+
parentProperty: nextParentProperty,
|
|
167
|
+
childrenProperty: nextChildrenProperty
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
registerTreeRelations(ctor, {
|
|
172
|
+
...current,
|
|
173
|
+
parentProperty: nextParentProperty,
|
|
174
|
+
childrenProperty: nextChildrenProperty
|
|
175
|
+
});
|
|
176
|
+
}
|
|
187
177
|
|
|
188
178
|
/**
|
|
189
179
|
* Gets tree metadata from an entity class.
|
|
@@ -197,50 +187,50 @@ export function getTreeMetadata(
|
|
|
197
187
|
/**
|
|
198
188
|
* Sets tree metadata on an entity class.
|
|
199
189
|
*/
|
|
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
|
-
};
|
|
190
|
+
export function setTreeMetadata(
|
|
191
|
+
target: new (...args: unknown[]) => object,
|
|
192
|
+
metadata: TreeMetadata
|
|
193
|
+
): void {
|
|
194
|
+
(target as unknown as Record<symbol, TreeMetadata>)[TREE_METADATA_KEY] = metadata;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const registerTreeRelations = (
|
|
198
|
+
target: EntityConstructor,
|
|
199
|
+
metadata: TreeMetadata
|
|
200
|
+
): void => {
|
|
201
|
+
const entityMeta = getEntityMetadata(target);
|
|
202
|
+
if (!entityMeta) return;
|
|
203
|
+
|
|
204
|
+
if (metadata.parentProperty && !entityMeta.relations[metadata.parentProperty]) {
|
|
205
|
+
addRelationMetadata(target, metadata.parentProperty, {
|
|
206
|
+
kind: RelationKinds.BelongsTo,
|
|
207
|
+
propertyKey: metadata.parentProperty,
|
|
208
|
+
target: () => target,
|
|
209
|
+
foreignKey: metadata.config.parentKey
|
|
210
|
+
});
|
|
211
|
+
if (entityMeta.table && !entityMeta.table.relations[metadata.parentProperty]) {
|
|
212
|
+
entityMeta.table.relations[metadata.parentProperty] = belongsTo(
|
|
213
|
+
entityMeta.table,
|
|
214
|
+
metadata.config.parentKey
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
if (metadata.childrenProperty && !entityMeta.relations[metadata.childrenProperty]) {
|
|
220
|
+
addRelationMetadata(target, metadata.childrenProperty, {
|
|
221
|
+
kind: RelationKinds.HasMany,
|
|
222
|
+
propertyKey: metadata.childrenProperty,
|
|
223
|
+
target: () => target,
|
|
224
|
+
foreignKey: metadata.config.parentKey
|
|
225
|
+
});
|
|
226
|
+
if (entityMeta.table && !entityMeta.table.relations[metadata.childrenProperty]) {
|
|
227
|
+
entityMeta.table.relations[metadata.childrenProperty] = hasMany(
|
|
228
|
+
entityMeta.table,
|
|
229
|
+
metadata.config.parentKey
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
};
|
|
244
234
|
|
|
245
235
|
/**
|
|
246
236
|
* Sets tree metadata on an entity class (internal, handles abstract classes).
|