metal-orm 1.1.7 → 1.1.9

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