metal-orm 1.0.58 → 1.0.60
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 +34 -31
- package/dist/index.cjs +1583 -901
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +400 -129
- package/dist/index.d.ts +400 -129
- package/dist/index.js +1575 -901
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/core/ddl/schema-generator.ts +44 -1
- package/src/decorators/bootstrap.ts +183 -146
- package/src/decorators/column-decorator.ts +8 -49
- package/src/decorators/decorator-metadata.ts +10 -46
- package/src/decorators/entity.ts +30 -40
- package/src/decorators/relations.ts +30 -56
- package/src/index.ts +7 -7
- package/src/orm/entity-hydration.ts +72 -0
- package/src/orm/entity-meta.ts +13 -11
- package/src/orm/entity-metadata.ts +240 -238
- package/src/orm/entity-relation-cache.ts +39 -0
- package/src/orm/entity-relations.ts +207 -0
- package/src/orm/entity.ts +124 -410
- package/src/orm/execute.ts +4 -4
- package/src/orm/lazy-batch/belongs-to-many.ts +134 -0
- package/src/orm/lazy-batch/belongs-to.ts +108 -0
- package/src/orm/lazy-batch/has-many.ts +69 -0
- package/src/orm/lazy-batch/has-one.ts +68 -0
- package/src/orm/lazy-batch/shared.ts +125 -0
- package/src/orm/lazy-batch.ts +4 -492
- package/src/orm/relations/many-to-many.ts +2 -1
- package/src/query-builder/relation-cte-builder.ts +63 -0
- package/src/query-builder/relation-filter-utils.ts +159 -0
- package/src/query-builder/relation-include-strategies.ts +177 -0
- package/src/query-builder/relation-join-planner.ts +80 -0
- package/src/query-builder/relation-service.ts +119 -479
- package/src/query-builder/relation-types.ts +41 -10
- package/src/query-builder/select/projection-facet.ts +23 -23
- package/src/query-builder/select/select-operations.ts +145 -0
- package/src/query-builder/select.ts +329 -221
- package/src/schema/relation.ts +22 -18
- package/src/schema/table.ts +22 -9
- package/src/schema/types.ts +14 -12
|
@@ -1,265 +1,267 @@
|
|
|
1
|
-
import { ColumnDef } from '../schema/column-types.js';
|
|
2
|
-
import { defineTable, TableDef, TableHooks } from '../schema/table.js';
|
|
3
|
-
import { CascadeMode, RelationKinds } from '../schema/relation.js';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Constructor type for entities.
|
|
7
|
-
* Supports any constructor signature for maximum flexibility with decorator-based entities.
|
|
8
|
-
* @template T - The entity type
|
|
9
|
-
*/
|
|
10
|
-
export type EntityConstructor<T = object> = new (...args: never[]) => T;
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Target that can be an entity constructor or table definition.
|
|
14
|
-
*/
|
|
15
|
-
export type EntityOrTableTarget = EntityConstructor | TableDef;
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Resolver for entity or table target, can be direct or function.
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
/** The
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
1
|
+
import { ColumnDef } from '../schema/column-types.js';
|
|
2
|
+
import { defineTable, TableDef, TableHooks } from '../schema/table.js';
|
|
3
|
+
import { CascadeMode, RelationKinds } from '../schema/relation.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Constructor type for entities.
|
|
7
|
+
* Supports any constructor signature for maximum flexibility with decorator-based entities.
|
|
8
|
+
* @template T - The entity type
|
|
9
|
+
*/
|
|
10
|
+
export type EntityConstructor<T = object> = new (...args: never[]) => T;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Target that can be an entity constructor or table definition.
|
|
14
|
+
*/
|
|
15
|
+
export type EntityOrTableTarget = EntityConstructor | TableDef;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Resolver for entity or table target, can be direct or function.
|
|
19
|
+
* @typeParam T - Specific target type that should be resolved
|
|
20
|
+
*/
|
|
21
|
+
export type EntityOrTableTargetResolver<T extends EntityOrTableTarget = EntityOrTableTarget> =
|
|
22
|
+
T | (() => T);
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Simplified column definition structure used during metadata registration.
|
|
26
|
+
* @template T - Concrete column definition type being extended
|
|
27
|
+
*/
|
|
28
|
+
export type ColumnDefLike<T extends ColumnDef = ColumnDef> = Omit<T, 'name' | 'table'>;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Transforms simplified column metadata into full ColumnDef objects during table building.
|
|
32
|
+
* @template TColumns - Mapping of column names to simplified definitions
|
|
33
|
+
*/
|
|
34
|
+
type MaterializeColumns<TColumns extends Record<string, ColumnDefLike>> = {
|
|
35
|
+
[K in keyof TColumns]: ColumnDef<TColumns[K]['type'], TColumns[K]['tsType']> & Omit<
|
|
36
|
+
TColumns[K],
|
|
37
|
+
'name' | 'table' | 'type' | 'tsType'
|
|
38
|
+
> & { name: string; table: string };
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Common properties shared by all relation metadata types.
|
|
43
|
+
*/
|
|
44
|
+
interface BaseRelationMetadata {
|
|
45
|
+
/** The property key for the relation */
|
|
46
|
+
propertyKey: string;
|
|
47
|
+
/** The target entity or table */
|
|
48
|
+
target: EntityOrTableTargetResolver;
|
|
49
|
+
/** Optional cascade mode */
|
|
50
|
+
cascade?: CascadeMode;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Metadata for has many relations.
|
|
55
|
+
*/
|
|
54
56
|
export interface HasManyRelationMetadata extends BaseRelationMetadata {
|
|
55
57
|
/** The relation kind */
|
|
56
58
|
kind: typeof RelationKinds.HasMany;
|
|
57
59
|
/** The foreign key */
|
|
58
|
-
foreignKey
|
|
60
|
+
foreignKey?: string;
|
|
59
61
|
/** Optional local key */
|
|
60
62
|
localKey?: string;
|
|
61
63
|
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Metadata for has one relations.
|
|
65
|
-
*/
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Metadata for has one relations.
|
|
67
|
+
*/
|
|
66
68
|
export interface HasOneRelationMetadata extends BaseRelationMetadata {
|
|
67
69
|
/** The relation kind */
|
|
68
70
|
kind: typeof RelationKinds.HasOne;
|
|
69
71
|
/** The foreign key */
|
|
70
|
-
foreignKey
|
|
71
|
-
/** Optional local key */
|
|
72
|
-
localKey?: string;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* Metadata for belongs to relations.
|
|
77
|
-
*/
|
|
78
|
-
export interface BelongsToRelationMetadata extends BaseRelationMetadata {
|
|
79
|
-
/** The relation kind */
|
|
80
|
-
kind: typeof RelationKinds.BelongsTo;
|
|
81
|
-
/** The foreign key */
|
|
82
|
-
foreignKey: string;
|
|
72
|
+
foreignKey?: string;
|
|
83
73
|
/** Optional local key */
|
|
84
74
|
localKey?: string;
|
|
85
75
|
}
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* Metadata for belongs to
|
|
89
|
-
*/
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Metadata for belongs to relations.
|
|
79
|
+
*/
|
|
80
|
+
export interface BelongsToRelationMetadata extends BaseRelationMetadata {
|
|
81
|
+
/** The relation kind */
|
|
82
|
+
kind: typeof RelationKinds.BelongsTo;
|
|
83
|
+
/** The foreign key */
|
|
84
|
+
foreignKey: string;
|
|
85
|
+
/** Optional local key */
|
|
86
|
+
localKey?: string;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Metadata for belongs to many relations.
|
|
91
|
+
*/
|
|
90
92
|
export interface BelongsToManyRelationMetadata extends BaseRelationMetadata {
|
|
91
93
|
/** The relation kind */
|
|
92
94
|
kind: typeof RelationKinds.BelongsToMany;
|
|
93
95
|
/** The pivot table */
|
|
94
96
|
pivotTable: EntityOrTableTargetResolver;
|
|
95
97
|
/** The pivot foreign key to root */
|
|
96
|
-
pivotForeignKeyToRoot
|
|
98
|
+
pivotForeignKeyToRoot?: string;
|
|
97
99
|
/** The pivot foreign key to target */
|
|
98
|
-
pivotForeignKeyToTarget
|
|
100
|
+
pivotForeignKeyToTarget?: string;
|
|
99
101
|
/** Optional local key */
|
|
100
102
|
localKey?: string;
|
|
101
103
|
/** Optional target key */
|
|
102
104
|
targetKey?: string;
|
|
103
105
|
/** Optional pivot primary key */
|
|
104
|
-
pivotPrimaryKey?: string;
|
|
105
|
-
/** Optional default pivot columns */
|
|
106
|
-
defaultPivotColumns?: string[];
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* Union type for all relation metadata.
|
|
111
|
-
*/
|
|
112
|
-
export type RelationMetadata =
|
|
113
|
-
| HasManyRelationMetadata
|
|
114
|
-
| HasOneRelationMetadata
|
|
115
|
-
| BelongsToRelationMetadata
|
|
116
|
-
| BelongsToManyRelationMetadata;
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* Metadata for entities.
|
|
120
|
-
* @template TColumns - The columns type
|
|
121
|
-
*/
|
|
122
|
-
export interface EntityMetadata<TColumns extends Record<string, ColumnDefLike> = Record<string, ColumnDefLike>> {
|
|
123
|
-
/** The entity constructor */
|
|
124
|
-
target: EntityConstructor;
|
|
125
|
-
/** The table name */
|
|
126
|
-
tableName: string;
|
|
127
|
-
/** The columns */
|
|
128
|
-
columns: TColumns;
|
|
129
|
-
/** The relations */
|
|
130
|
-
relations: Record<string, RelationMetadata>;
|
|
131
|
-
/** Optional hooks */
|
|
132
|
-
hooks?: TableHooks;
|
|
133
|
-
/** Optional table definition */
|
|
134
|
-
table?: TableDef<MaterializeColumns<TColumns>>;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
const metadataMap = new Map<EntityConstructor, EntityMetadata>();
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
* Registers entity metadata.
|
|
141
|
-
* @param meta - The entity metadata to register
|
|
142
|
-
*/
|
|
143
|
-
export const registerEntityMetadata = (meta: EntityMetadata): void => {
|
|
144
|
-
metadataMap.set(meta.target, meta);
|
|
145
|
-
};
|
|
146
|
-
|
|
147
|
-
/**
|
|
148
|
-
* Ensures entity metadata exists for the target, creating it if necessary.
|
|
149
|
-
* @param target - The entity constructor
|
|
150
|
-
* @returns The entity metadata
|
|
151
|
-
*/
|
|
152
|
-
export const ensureEntityMetadata = (target: EntityConstructor): EntityMetadata => {
|
|
153
|
-
let meta = metadataMap.get(target);
|
|
154
|
-
if (!meta) {
|
|
155
|
-
meta = {
|
|
156
|
-
target,
|
|
157
|
-
tableName: target.name || 'unknown',
|
|
158
|
-
columns: {},
|
|
159
|
-
relations: {}
|
|
160
|
-
};
|
|
161
|
-
metadataMap.set(target, meta);
|
|
162
|
-
}
|
|
163
|
-
return meta;
|
|
164
|
-
};
|
|
165
|
-
|
|
166
|
-
/**
|
|
167
|
-
* Gets entity metadata for the target.
|
|
168
|
-
* @param target - The entity constructor
|
|
169
|
-
* @returns The entity metadata or undefined if not found
|
|
170
|
-
*/
|
|
171
|
-
export const getEntityMetadata = (target: EntityConstructor): EntityMetadata | undefined => {
|
|
172
|
-
return metadataMap.get(target);
|
|
173
|
-
};
|
|
174
|
-
|
|
175
|
-
/**
|
|
176
|
-
* Gets all entity metadata.
|
|
177
|
-
* @returns Array of all entity metadata
|
|
178
|
-
*/
|
|
179
|
-
export const getAllEntityMetadata = (): EntityMetadata[] => {
|
|
180
|
-
return Array.from(metadataMap.values());
|
|
181
|
-
};
|
|
182
|
-
|
|
183
|
-
/**
|
|
184
|
-
* Clears all entity metadata.
|
|
185
|
-
*/
|
|
186
|
-
export const clearEntityMetadata = (): void => {
|
|
187
|
-
metadataMap.clear();
|
|
188
|
-
};
|
|
189
|
-
|
|
190
|
-
/**
|
|
191
|
-
* Adds column metadata to an entity.
|
|
192
|
-
* @param target - The entity constructor
|
|
193
|
-
* @param propertyKey - The property key
|
|
194
|
-
* @param column - The column definition
|
|
195
|
-
*/
|
|
196
|
-
export const addColumnMetadata = (
|
|
197
|
-
target: EntityConstructor,
|
|
198
|
-
propertyKey: string,
|
|
199
|
-
column: ColumnDefLike
|
|
200
|
-
): void => {
|
|
201
|
-
const meta = ensureEntityMetadata(target);
|
|
202
|
-
(meta.columns as Record<string, ColumnDefLike>)[propertyKey] = { ...column };
|
|
203
|
-
};
|
|
204
|
-
|
|
205
|
-
/**
|
|
206
|
-
* Adds relation metadata to an entity.
|
|
207
|
-
* @param target - The entity constructor
|
|
208
|
-
* @param propertyKey - The property key
|
|
209
|
-
* @param relation - The relation metadata
|
|
210
|
-
*/
|
|
211
|
-
export const addRelationMetadata = (
|
|
212
|
-
target: EntityConstructor,
|
|
213
|
-
propertyKey: string,
|
|
214
|
-
relation: RelationMetadata
|
|
215
|
-
): void => {
|
|
216
|
-
const meta = ensureEntityMetadata(target);
|
|
217
|
-
meta.relations[propertyKey] = relation;
|
|
218
|
-
};
|
|
219
|
-
|
|
220
|
-
/**
|
|
221
|
-
* Sets the table name and hooks for an entity.
|
|
222
|
-
* @param target - The entity constructor
|
|
223
|
-
* @param tableName - The table name
|
|
224
|
-
* @param hooks - Optional table hooks
|
|
225
|
-
*/
|
|
226
|
-
export const setEntityTableName = (
|
|
227
|
-
target: EntityConstructor,
|
|
228
|
-
tableName: string,
|
|
229
|
-
hooks?: TableHooks
|
|
230
|
-
): void => {
|
|
231
|
-
const meta = ensureEntityMetadata(target);
|
|
232
|
-
if (tableName && tableName.length > 0) {
|
|
233
|
-
meta.tableName = tableName;
|
|
234
|
-
}
|
|
235
|
-
if (hooks) {
|
|
236
|
-
meta.hooks = hooks;
|
|
237
|
-
}
|
|
238
|
-
};
|
|
239
|
-
|
|
240
|
-
/**
|
|
241
|
-
* Builds a table definition from entity metadata.
|
|
242
|
-
* @template TColumns - The columns type
|
|
243
|
-
* @param meta - The entity metadata
|
|
244
|
-
* @returns The table definition
|
|
245
|
-
*/
|
|
246
|
-
export const buildTableDef = <TColumns extends Record<string, ColumnDefLike>>(meta: EntityMetadata<TColumns>): TableDef<MaterializeColumns<TColumns>> => {
|
|
247
|
-
if (meta.table) {
|
|
248
|
-
return meta.table;
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
// Build columns using a simpler approach that avoids type assertion
|
|
252
|
-
const columns: Record<string, ColumnDef> = {};
|
|
253
|
-
for (const [key, def] of Object.entries(meta.columns)) {
|
|
254
|
-
columns[key] = {
|
|
255
|
-
...def,
|
|
256
|
-
name: key,
|
|
257
|
-
table: meta.tableName
|
|
258
|
-
} as ColumnDef;
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
const table = defineTable(meta.tableName, columns as MaterializeColumns<TColumns>, {}, meta.hooks);
|
|
262
|
-
meta.table = table;
|
|
263
|
-
return table;
|
|
264
|
-
};
|
|
106
|
+
pivotPrimaryKey?: string;
|
|
107
|
+
/** Optional default pivot columns */
|
|
108
|
+
defaultPivotColumns?: string[];
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Union type for all relation metadata.
|
|
113
|
+
*/
|
|
114
|
+
export type RelationMetadata =
|
|
115
|
+
| HasManyRelationMetadata
|
|
116
|
+
| HasOneRelationMetadata
|
|
117
|
+
| BelongsToRelationMetadata
|
|
118
|
+
| BelongsToManyRelationMetadata;
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Metadata for entities.
|
|
122
|
+
* @template TColumns - The columns type
|
|
123
|
+
*/
|
|
124
|
+
export interface EntityMetadata<TColumns extends Record<string, ColumnDefLike> = Record<string, ColumnDefLike>> {
|
|
125
|
+
/** The entity constructor */
|
|
126
|
+
target: EntityConstructor;
|
|
127
|
+
/** The table name */
|
|
128
|
+
tableName: string;
|
|
129
|
+
/** The columns */
|
|
130
|
+
columns: TColumns;
|
|
131
|
+
/** The relations */
|
|
132
|
+
relations: Record<string, RelationMetadata>;
|
|
133
|
+
/** Optional hooks */
|
|
134
|
+
hooks?: TableHooks;
|
|
135
|
+
/** Optional table definition */
|
|
136
|
+
table?: TableDef<MaterializeColumns<TColumns>>;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const metadataMap = new Map<EntityConstructor, EntityMetadata>();
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Registers entity metadata.
|
|
143
|
+
* @param meta - The entity metadata to register
|
|
144
|
+
*/
|
|
145
|
+
export const registerEntityMetadata = (meta: EntityMetadata): void => {
|
|
146
|
+
metadataMap.set(meta.target, meta);
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Ensures entity metadata exists for the target, creating it if necessary.
|
|
151
|
+
* @param target - The entity constructor
|
|
152
|
+
* @returns The entity metadata
|
|
153
|
+
*/
|
|
154
|
+
export const ensureEntityMetadata = (target: EntityConstructor): EntityMetadata => {
|
|
155
|
+
let meta = metadataMap.get(target);
|
|
156
|
+
if (!meta) {
|
|
157
|
+
meta = {
|
|
158
|
+
target,
|
|
159
|
+
tableName: target.name || 'unknown',
|
|
160
|
+
columns: {},
|
|
161
|
+
relations: {}
|
|
162
|
+
};
|
|
163
|
+
metadataMap.set(target, meta);
|
|
164
|
+
}
|
|
165
|
+
return meta;
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Gets entity metadata for the target.
|
|
170
|
+
* @param target - The entity constructor
|
|
171
|
+
* @returns The entity metadata or undefined if not found
|
|
172
|
+
*/
|
|
173
|
+
export const getEntityMetadata = (target: EntityConstructor): EntityMetadata | undefined => {
|
|
174
|
+
return metadataMap.get(target);
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Gets all entity metadata.
|
|
179
|
+
* @returns Array of all entity metadata
|
|
180
|
+
*/
|
|
181
|
+
export const getAllEntityMetadata = (): EntityMetadata[] => {
|
|
182
|
+
return Array.from(metadataMap.values());
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Clears all entity metadata.
|
|
187
|
+
*/
|
|
188
|
+
export const clearEntityMetadata = (): void => {
|
|
189
|
+
metadataMap.clear();
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Adds column metadata to an entity.
|
|
194
|
+
* @param target - The entity constructor
|
|
195
|
+
* @param propertyKey - The property key
|
|
196
|
+
* @param column - The column definition
|
|
197
|
+
*/
|
|
198
|
+
export const addColumnMetadata = (
|
|
199
|
+
target: EntityConstructor,
|
|
200
|
+
propertyKey: string,
|
|
201
|
+
column: ColumnDefLike
|
|
202
|
+
): void => {
|
|
203
|
+
const meta = ensureEntityMetadata(target);
|
|
204
|
+
(meta.columns as Record<string, ColumnDefLike>)[propertyKey] = { ...column };
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Adds relation metadata to an entity.
|
|
209
|
+
* @param target - The entity constructor
|
|
210
|
+
* @param propertyKey - The property key
|
|
211
|
+
* @param relation - The relation metadata
|
|
212
|
+
*/
|
|
213
|
+
export const addRelationMetadata = (
|
|
214
|
+
target: EntityConstructor,
|
|
215
|
+
propertyKey: string,
|
|
216
|
+
relation: RelationMetadata
|
|
217
|
+
): void => {
|
|
218
|
+
const meta = ensureEntityMetadata(target);
|
|
219
|
+
meta.relations[propertyKey] = relation;
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Sets the table name and hooks for an entity.
|
|
224
|
+
* @param target - The entity constructor
|
|
225
|
+
* @param tableName - The table name
|
|
226
|
+
* @param hooks - Optional table hooks
|
|
227
|
+
*/
|
|
228
|
+
export const setEntityTableName = (
|
|
229
|
+
target: EntityConstructor,
|
|
230
|
+
tableName: string,
|
|
231
|
+
hooks?: TableHooks
|
|
232
|
+
): void => {
|
|
233
|
+
const meta = ensureEntityMetadata(target);
|
|
234
|
+
if (tableName && tableName.length > 0) {
|
|
235
|
+
meta.tableName = tableName;
|
|
236
|
+
}
|
|
237
|
+
if (hooks) {
|
|
238
|
+
meta.hooks = hooks;
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Builds a table definition from entity metadata.
|
|
244
|
+
* @template TColumns - The columns type
|
|
245
|
+
* @param meta - The entity metadata
|
|
246
|
+
* @returns The table definition
|
|
247
|
+
*/
|
|
248
|
+
export const buildTableDef = <TColumns extends Record<string, ColumnDefLike>>(meta: EntityMetadata<TColumns>): TableDef<MaterializeColumns<TColumns>> => {
|
|
249
|
+
if (meta.table) {
|
|
250
|
+
return meta.table;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// Build columns using a simpler approach that avoids type assertion
|
|
254
|
+
const columns: Record<string, ColumnDef> = {};
|
|
255
|
+
for (const [key, def] of Object.entries(meta.columns)) {
|
|
256
|
+
columns[key] = {
|
|
257
|
+
...def,
|
|
258
|
+
name: key,
|
|
259
|
+
table: meta.tableName
|
|
260
|
+
} as ColumnDef;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
const table = defineTable(meta.tableName, columns as MaterializeColumns<TColumns>, {}, meta.hooks);
|
|
264
|
+
meta.table = table;
|
|
265
|
+
return table;
|
|
266
|
+
};
|
|
265
267
|
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { TableDef } from '../schema/table.js';
|
|
2
|
+
import { EntityMeta, getEntityMeta } from './entity-meta.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Caches relation loader results across entities of the same type.
|
|
6
|
+
* @template T - The cache type
|
|
7
|
+
* @param meta - The entity metadata
|
|
8
|
+
* @param relationName - The relation name
|
|
9
|
+
* @param factory - The factory function to create the cache
|
|
10
|
+
* @returns Promise with the cached relation data
|
|
11
|
+
*/
|
|
12
|
+
export const relationLoaderCache = <TTable extends TableDef, T extends Map<string, unknown>>(
|
|
13
|
+
meta: EntityMeta<TTable>,
|
|
14
|
+
relationName: string,
|
|
15
|
+
factory: () => Promise<T>
|
|
16
|
+
): Promise<T> => {
|
|
17
|
+
if (meta.relationCache.has(relationName)) {
|
|
18
|
+
return meta.relationCache.get(relationName)! as Promise<T>;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const promise = factory().then(value => {
|
|
22
|
+
for (const tracked of meta.ctx.getEntitiesForTable(meta.table)) {
|
|
23
|
+
const otherMeta = getEntityMeta(tracked.entity);
|
|
24
|
+
if (!otherMeta) continue;
|
|
25
|
+
otherMeta.relationHydration.set(relationName, value);
|
|
26
|
+
}
|
|
27
|
+
return value;
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
meta.relationCache.set(relationName, promise);
|
|
31
|
+
|
|
32
|
+
for (const tracked of meta.ctx.getEntitiesForTable(meta.table)) {
|
|
33
|
+
const otherMeta = getEntityMeta(tracked.entity);
|
|
34
|
+
if (!otherMeta) continue;
|
|
35
|
+
otherMeta.relationCache.set(relationName, promise);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return promise;
|
|
39
|
+
};
|