metal-orm 1.0.102 → 1.0.104
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 +103 -81
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -8
- package/dist/index.d.ts +6 -8
- package/dist/index.js +103 -81
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/scripts/generate-entities/cli.mjs +1 -1
- package/scripts/generate-entities/generate.mjs +21 -12
- package/scripts/generate-entities/render.mjs +5 -4
- package/scripts/naming-strategy.mjs +19 -3
- package/src/orm/entity-relations.ts +209 -207
- package/src/orm/entity.ts +160 -151
- package/src/orm/relations/belongs-to.ts +130 -126
- package/src/orm/relations/has-many.ts +190 -186
- package/src/orm/relations/has-one.ts +162 -158
- package/src/orm/relations/many-to-many.ts +228 -224
package/package.json
CHANGED
|
@@ -188,7 +188,7 @@ Flags:
|
|
|
188
188
|
--include=tbl1,tbl2 Only include these tables
|
|
189
189
|
--exclude=tbl3,tbl4 Exclude these tables
|
|
190
190
|
--locale=pt-BR Naming locale for class/relation names (default: en)
|
|
191
|
-
--naming-overrides Path to JSON
|
|
191
|
+
--naming-overrides Path to JSON config for naming customizations (see docs)
|
|
192
192
|
--dry-run Print to stdout instead of writing a file
|
|
193
193
|
--out=<file> Override the generated file (defaults to generated-entities.ts or the index inside --out-dir)
|
|
194
194
|
--out-dir=<dir> Emit one file per entity inside this directory plus the shared index
|
|
@@ -5,7 +5,7 @@ import { loadDriver } from './drivers.mjs';
|
|
|
5
5
|
import { renderEntityFile, renderSplitEntityFiles, renderSplitIndexFile } from './render.mjs';
|
|
6
6
|
import { printDryRun, writeSingleFile, writeSplitFiles } from './emit.mjs';
|
|
7
7
|
|
|
8
|
-
const
|
|
8
|
+
const loadNamingOverrides = async (filePath, fsPromises) => {
|
|
9
9
|
const raw = await fsPromises.readFile(filePath, 'utf8');
|
|
10
10
|
let parsed;
|
|
11
11
|
try {
|
|
@@ -13,22 +13,31 @@ const loadIrregulars = async (filePath, fsPromises) => {
|
|
|
13
13
|
} catch (err) {
|
|
14
14
|
throw new Error(`Failed to parse naming overrides at ${filePath}: ${err.message || err}`);
|
|
15
15
|
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
? parsed.irregulars
|
|
20
|
-
: parsed
|
|
21
|
-
: undefined;
|
|
22
|
-
if (!irregulars) {
|
|
23
|
-
throw new Error(`Naming overrides at ${filePath} must be an object or { "irregulars": { ... } }`);
|
|
16
|
+
|
|
17
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
18
|
+
throw new Error(`Naming overrides at ${filePath} must be an object`);
|
|
24
19
|
}
|
|
25
|
-
|
|
20
|
+
|
|
21
|
+
// Support both flat format { "singular": "plural" } and structured { irregulars: {...}, relationOverrides: {...} }
|
|
22
|
+
const hasStructuredFormat = parsed.irregulars || parsed.relationOverrides;
|
|
23
|
+
|
|
24
|
+
const irregulars = hasStructuredFormat
|
|
25
|
+
? (parsed.irregulars && typeof parsed.irregulars === 'object' ? parsed.irregulars : {})
|
|
26
|
+
: parsed;
|
|
27
|
+
|
|
28
|
+
const relationOverrides = hasStructuredFormat && parsed.relationOverrides && typeof parsed.relationOverrides === 'object'
|
|
29
|
+
? parsed.relationOverrides
|
|
30
|
+
: {};
|
|
31
|
+
|
|
32
|
+
return { irregulars, relationOverrides };
|
|
26
33
|
};
|
|
27
34
|
|
|
28
35
|
export const generateEntities = async (opts, context = {}) => {
|
|
29
36
|
const { fs: fsPromises = fs, logger = console } = context;
|
|
30
|
-
const irregulars
|
|
31
|
-
|
|
37
|
+
const { irregulars, relationOverrides } = opts.namingOverrides
|
|
38
|
+
? await loadNamingOverrides(opts.namingOverrides, fsPromises)
|
|
39
|
+
: { irregulars: undefined, relationOverrides: {} };
|
|
40
|
+
const naming = createNamingStrategy(opts.locale, irregulars, relationOverrides);
|
|
32
41
|
|
|
33
42
|
const { executor, cleanup } = await loadDriver(opts.dialect, opts.url, opts.dbPath);
|
|
34
43
|
let schema;
|
|
@@ -259,26 +259,27 @@ const renderEntityClassLines = ({ table, className, naming, relations, resolveCl
|
|
|
259
259
|
for (const rel of relations) {
|
|
260
260
|
const targetClass = resolveClassName(rel.target);
|
|
261
261
|
if (!targetClass) continue;
|
|
262
|
+
const propName = naming.applyRelationOverride(className, rel.property);
|
|
262
263
|
switch (rel.kind) {
|
|
263
264
|
case 'belongsTo':
|
|
264
265
|
lines.push(
|
|
265
266
|
` @BelongsTo({ target: () => ${targetClass}, foreignKey: '${escapeJsString(rel.foreignKey)}' })`
|
|
266
267
|
);
|
|
267
|
-
lines.push(` ${
|
|
268
|
+
lines.push(` ${propName}!: BelongsToReference<${targetClass}>;`);
|
|
268
269
|
lines.push('');
|
|
269
270
|
break;
|
|
270
271
|
case 'hasMany':
|
|
271
272
|
lines.push(
|
|
272
273
|
` @HasMany({ target: () => ${targetClass}, foreignKey: '${escapeJsString(rel.foreignKey)}' })`
|
|
273
274
|
);
|
|
274
|
-
lines.push(` ${
|
|
275
|
+
lines.push(` ${propName}!: HasManyCollection<${targetClass}>;`);
|
|
275
276
|
lines.push('');
|
|
276
277
|
break;
|
|
277
278
|
case 'hasOne':
|
|
278
279
|
lines.push(
|
|
279
280
|
` @HasOne({ target: () => ${targetClass}, foreignKey: '${escapeJsString(rel.foreignKey)}' })`
|
|
280
281
|
);
|
|
281
|
-
lines.push(` ${
|
|
282
|
+
lines.push(` ${propName}!: HasOneReference<${targetClass}>;`);
|
|
282
283
|
lines.push('');
|
|
283
284
|
break;
|
|
284
285
|
case 'belongsToMany': {
|
|
@@ -289,7 +290,7 @@ const renderEntityClassLines = ({ table, className, naming, relations, resolveCl
|
|
|
289
290
|
rel.pivotForeignKeyToRoot
|
|
290
291
|
)}', pivotForeignKeyToTarget: '${escapeJsString(rel.pivotForeignKeyToTarget)}' })`
|
|
291
292
|
);
|
|
292
|
-
lines.push(` ${
|
|
293
|
+
lines.push(` ${propName}!: ManyToManyCollection<${targetClass}>;`);
|
|
293
294
|
lines.push('');
|
|
294
295
|
break;
|
|
295
296
|
}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { resolveInflector } from './inflection/index.mjs';
|
|
2
2
|
|
|
3
3
|
export class BaseNamingStrategy {
|
|
4
|
-
constructor(irregulars = {}, inflector = resolveInflector('en')) {
|
|
4
|
+
constructor(irregulars = {}, inflector = resolveInflector('en'), relationOverrides = {}) {
|
|
5
5
|
this.irregulars = new Map();
|
|
6
6
|
this.inverseIrregulars = new Map();
|
|
7
7
|
this.inflector = inflector;
|
|
8
|
+
this.relationOverrides = new Map();
|
|
9
|
+
|
|
8
10
|
for (const [singular, plural] of Object.entries(irregulars)) {
|
|
9
11
|
if (!singular || !plural) continue;
|
|
10
12
|
const normalize = this.inflector.normalizeForIrregularKey || (value => String(value).toLowerCase());
|
|
@@ -13,6 +15,20 @@ export class BaseNamingStrategy {
|
|
|
13
15
|
this.irregulars.set(singularKey, pluralValue);
|
|
14
16
|
this.inverseIrregulars.set(pluralValue, singularKey);
|
|
15
17
|
}
|
|
18
|
+
|
|
19
|
+
// Build relation overrides map: className -> { originalProp -> newProp }
|
|
20
|
+
for (const [className, overrides] of Object.entries(relationOverrides)) {
|
|
21
|
+
if (!overrides || typeof overrides !== 'object') continue;
|
|
22
|
+
this.relationOverrides.set(className, new Map(Object.entries(overrides)));
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
applyRelationOverride(className, propertyName) {
|
|
27
|
+
const classOverrides = this.relationOverrides.get(className);
|
|
28
|
+
if (classOverrides?.has(propertyName)) {
|
|
29
|
+
return classOverrides.get(propertyName);
|
|
30
|
+
}
|
|
31
|
+
return propertyName;
|
|
16
32
|
}
|
|
17
33
|
|
|
18
34
|
applyIrregular(word, direction) {
|
|
@@ -109,8 +125,8 @@ export class PortugueseNamingStrategy extends BaseNamingStrategy {
|
|
|
109
125
|
}
|
|
110
126
|
}
|
|
111
127
|
|
|
112
|
-
export const createNamingStrategy = (locale = 'en', irregulars) => {
|
|
128
|
+
export const createNamingStrategy = (locale = 'en', irregulars, relationOverrides = {}) => {
|
|
113
129
|
const inflector = resolveInflector(locale);
|
|
114
130
|
const mergedIrregulars = { ...(inflector.defaultIrregulars || {}), ...(irregulars || {}) };
|
|
115
|
-
return new BaseNamingStrategy(mergedIrregulars, inflector);
|
|
131
|
+
return new BaseNamingStrategy(mergedIrregulars, inflector, relationOverrides);
|
|
116
132
|
};
|
|
@@ -1,207 +1,209 @@
|
|
|
1
|
-
import { TableDef } from '../schema/table.js';
|
|
2
|
-
import { EntityInstance, HasManyCollection, HasOneReference, BelongsToReference, ManyToManyCollection } from '../schema/types.js';
|
|
3
|
-
import { EntityMeta, RelationKey } from './entity-meta.js';
|
|
4
|
-
import { DefaultHasManyCollection } from './relations/has-many.js';
|
|
5
|
-
import { DefaultHasOneReference } from './relations/has-one.js';
|
|
6
|
-
import { DefaultBelongsToReference } from './relations/belongs-to.js';
|
|
7
|
-
import { DefaultManyToManyCollection } from './relations/many-to-many.js';
|
|
8
|
-
import { HasManyRelation, HasOneRelation, BelongsToRelation, BelongsToManyRelation, RelationKinds } from '../schema/relation.js';
|
|
9
|
-
import { loadHasManyRelation, loadHasOneRelation, loadBelongsToRelation, loadBelongsToManyRelation } from './lazy-batch.js';
|
|
10
|
-
import { findPrimaryKey } from '../query-builder/hydration-planner.js';
|
|
11
|
-
import { relationLoaderCache } from './entity-relation-cache.js';
|
|
12
|
-
|
|
13
|
-
export type RelationEntityFactory = (
|
|
14
|
-
table: TableDef,
|
|
15
|
-
row: Record<string, unknown>
|
|
16
|
-
) => EntityInstance<TableDef>;
|
|
17
|
-
|
|
18
|
-
const proxifyRelationWrapper = <T extends object>(wrapper: T): T => {
|
|
19
|
-
return new Proxy(wrapper, {
|
|
20
|
-
get(target, prop,
|
|
21
|
-
if (typeof prop === 'symbol') {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
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
|
-
* @param
|
|
85
|
-
* @param
|
|
86
|
-
* @
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
*
|
|
115
|
-
* @param
|
|
116
|
-
* @param
|
|
117
|
-
* @param
|
|
118
|
-
* @
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
const
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
const
|
|
136
|
-
|
|
137
|
-
)
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
const
|
|
154
|
-
|
|
155
|
-
)
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
const
|
|
172
|
-
|
|
173
|
-
)
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
const
|
|
190
|
-
|
|
191
|
-
)
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
1
|
+
import { TableDef } from '../schema/table.js';
|
|
2
|
+
import { EntityInstance, HasManyCollection, HasOneReference, BelongsToReference, ManyToManyCollection } from '../schema/types.js';
|
|
3
|
+
import { EntityMeta, RelationKey } from './entity-meta.js';
|
|
4
|
+
import { DefaultHasManyCollection } from './relations/has-many.js';
|
|
5
|
+
import { DefaultHasOneReference } from './relations/has-one.js';
|
|
6
|
+
import { DefaultBelongsToReference } from './relations/belongs-to.js';
|
|
7
|
+
import { DefaultManyToManyCollection } from './relations/many-to-many.js';
|
|
8
|
+
import { HasManyRelation, HasOneRelation, BelongsToRelation, BelongsToManyRelation, RelationKinds } from '../schema/relation.js';
|
|
9
|
+
import { loadHasManyRelation, loadHasOneRelation, loadBelongsToRelation, loadBelongsToManyRelation } from './lazy-batch.js';
|
|
10
|
+
import { findPrimaryKey } from '../query-builder/hydration-planner.js';
|
|
11
|
+
import { relationLoaderCache } from './entity-relation-cache.js';
|
|
12
|
+
|
|
13
|
+
export type RelationEntityFactory = (
|
|
14
|
+
table: TableDef,
|
|
15
|
+
row: Record<string, unknown>
|
|
16
|
+
) => EntityInstance<TableDef>;
|
|
17
|
+
|
|
18
|
+
const proxifyRelationWrapper = <T extends object>(wrapper: T): T => {
|
|
19
|
+
return new Proxy(wrapper, {
|
|
20
|
+
get(target, prop, _receiver) {
|
|
21
|
+
if (typeof prop === 'symbol') {
|
|
22
|
+
const value = Reflect.get(target, prop, target);
|
|
23
|
+
return typeof value === 'function' ? value.bind(target) : value;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (prop in target) {
|
|
27
|
+
const value = Reflect.get(target, prop, target);
|
|
28
|
+
return typeof value === 'function' ? value.bind(target) : value;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const getItems = (target as { getItems?: () => unknown }).getItems;
|
|
32
|
+
if (typeof getItems === 'function') {
|
|
33
|
+
const items = getItems.call(target);
|
|
34
|
+
if (items && prop in (items as object)) {
|
|
35
|
+
const propName = prop as string;
|
|
36
|
+
const value = (items as Record<string, unknown>)[propName];
|
|
37
|
+
return typeof value === 'function' ? value.bind(items) : value;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const getRef = (target as { get?: () => unknown }).get;
|
|
42
|
+
if (typeof getRef === 'function') {
|
|
43
|
+
const current = getRef.call(target);
|
|
44
|
+
if (current && prop in (current as object)) {
|
|
45
|
+
const propName = prop as string;
|
|
46
|
+
const value = (current as Record<string, unknown>)[propName];
|
|
47
|
+
return typeof value === 'function' ? value.bind(current) : value;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return undefined;
|
|
52
|
+
},
|
|
53
|
+
|
|
54
|
+
set(target, prop, value, _receiver) {
|
|
55
|
+
if (typeof prop === 'symbol') {
|
|
56
|
+
return Reflect.set(target, prop, value, target);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (prop in target) {
|
|
60
|
+
return Reflect.set(target, prop, value, target);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const getRef = (target as { get?: () => unknown }).get;
|
|
64
|
+
if (typeof getRef === 'function') {
|
|
65
|
+
const current = getRef.call(target);
|
|
66
|
+
if (current && typeof current === 'object') {
|
|
67
|
+
return Reflect.set(current as object, prop, value);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const getItems = (target as { getItems?: () => unknown }).getItems;
|
|
72
|
+
if (typeof getItems === 'function') {
|
|
73
|
+
const items = getItems.call(target);
|
|
74
|
+
return Reflect.set(items as object, prop, value);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return Reflect.set(target, prop, value, target);
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Gets a relation wrapper for an entity.
|
|
84
|
+
* @param meta - The entity metadata
|
|
85
|
+
* @param relationName - The relation name
|
|
86
|
+
* @param owner - The owner entity
|
|
87
|
+
* @param createEntity - The entity factory for relation rows
|
|
88
|
+
* @returns The relation wrapper or undefined
|
|
89
|
+
*/
|
|
90
|
+
export const getRelationWrapper = <TTable extends TableDef>(
|
|
91
|
+
meta: EntityMeta<TTable>,
|
|
92
|
+
relationName: RelationKey<TTable> | string,
|
|
93
|
+
owner: unknown,
|
|
94
|
+
createEntity: RelationEntityFactory
|
|
95
|
+
): HasManyCollection<unknown> | HasOneReference<object> | BelongsToReference<object> | ManyToManyCollection<unknown> | undefined => {
|
|
96
|
+
const relationKey = relationName as string;
|
|
97
|
+
|
|
98
|
+
if (meta.relationWrappers.has(relationKey)) {
|
|
99
|
+
return meta.relationWrappers.get(relationKey) as HasManyCollection<unknown>;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const relation = meta.table.relations[relationKey];
|
|
103
|
+
if (!relation) return undefined;
|
|
104
|
+
|
|
105
|
+
const wrapper = instantiateWrapper(meta, relationKey, relation, owner, createEntity);
|
|
106
|
+
if (!wrapper) return undefined;
|
|
107
|
+
|
|
108
|
+
const proxied = proxifyRelationWrapper(wrapper as object);
|
|
109
|
+
meta.relationWrappers.set(relationKey, proxied);
|
|
110
|
+
return proxied as HasManyCollection<unknown>;
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Instantiates the appropriate relation wrapper based on relation type.
|
|
115
|
+
* @param meta - The entity metadata
|
|
116
|
+
* @param relationName - The relation name
|
|
117
|
+
* @param relation - The relation definition
|
|
118
|
+
* @param owner - The owner entity
|
|
119
|
+
* @param createEntity - The entity factory for relation rows
|
|
120
|
+
* @returns The relation wrapper or undefined
|
|
121
|
+
*/
|
|
122
|
+
const instantiateWrapper = <TTable extends TableDef>(
|
|
123
|
+
meta: EntityMeta<TTable>,
|
|
124
|
+
relationName: string,
|
|
125
|
+
relation: HasManyRelation | HasOneRelation | BelongsToRelation | BelongsToManyRelation,
|
|
126
|
+
owner: unknown,
|
|
127
|
+
createEntity: RelationEntityFactory
|
|
128
|
+
): HasManyCollection<unknown> | HasOneReference<object> | BelongsToReference<object> | ManyToManyCollection<unknown> | undefined => {
|
|
129
|
+
const metaBase = meta as unknown as EntityMeta<TableDef>;
|
|
130
|
+
const loadCached = <T extends Map<string, unknown>>(factory: () => Promise<T>) =>
|
|
131
|
+
relationLoaderCache(metaBase, relationName, factory);
|
|
132
|
+
const resolveOptions = () => meta.lazyRelationOptions.get(relationName);
|
|
133
|
+
switch (relation.type) {
|
|
134
|
+
case RelationKinds.HasOne: {
|
|
135
|
+
const hasOne = relation as HasOneRelation;
|
|
136
|
+
const localKey = hasOne.localKey || findPrimaryKey(meta.table);
|
|
137
|
+
const loader = () => loadCached(() =>
|
|
138
|
+
loadHasOneRelation(meta.ctx, meta.table, relationName, hasOne, resolveOptions())
|
|
139
|
+
);
|
|
140
|
+
return new DefaultHasOneReference(
|
|
141
|
+
meta.ctx,
|
|
142
|
+
metaBase,
|
|
143
|
+
owner,
|
|
144
|
+
relationName,
|
|
145
|
+
hasOne,
|
|
146
|
+
meta.table,
|
|
147
|
+
loader,
|
|
148
|
+
(row: Record<string, unknown>) => createEntity(hasOne.target, row),
|
|
149
|
+
localKey
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
case RelationKinds.HasMany: {
|
|
153
|
+
const hasMany = relation as HasManyRelation;
|
|
154
|
+
const localKey = hasMany.localKey || findPrimaryKey(meta.table);
|
|
155
|
+
const loader = () => loadCached(() =>
|
|
156
|
+
loadHasManyRelation(meta.ctx, meta.table, relationName, hasMany, resolveOptions())
|
|
157
|
+
);
|
|
158
|
+
return new DefaultHasManyCollection(
|
|
159
|
+
meta.ctx,
|
|
160
|
+
metaBase,
|
|
161
|
+
owner,
|
|
162
|
+
relationName,
|
|
163
|
+
hasMany,
|
|
164
|
+
meta.table,
|
|
165
|
+
loader,
|
|
166
|
+
(row: Record<string, unknown>) => createEntity(relation.target, row),
|
|
167
|
+
localKey
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
case RelationKinds.BelongsTo: {
|
|
171
|
+
const belongsTo = relation as BelongsToRelation;
|
|
172
|
+
const targetKey = belongsTo.localKey || findPrimaryKey(belongsTo.target);
|
|
173
|
+
const loader = () => loadCached(() =>
|
|
174
|
+
loadBelongsToRelation(meta.ctx, meta.table, relationName, belongsTo, resolveOptions())
|
|
175
|
+
);
|
|
176
|
+
return new DefaultBelongsToReference(
|
|
177
|
+
meta.ctx,
|
|
178
|
+
metaBase,
|
|
179
|
+
owner,
|
|
180
|
+
relationName,
|
|
181
|
+
belongsTo,
|
|
182
|
+
meta.table,
|
|
183
|
+
loader,
|
|
184
|
+
(row: Record<string, unknown>) => createEntity(relation.target, row),
|
|
185
|
+
targetKey
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
case RelationKinds.BelongsToMany: {
|
|
189
|
+
const many = relation as BelongsToManyRelation;
|
|
190
|
+
const localKey = many.localKey || findPrimaryKey(meta.table);
|
|
191
|
+
const loader = () => loadCached(() =>
|
|
192
|
+
loadBelongsToManyRelation(meta.ctx, meta.table, relationName, many, resolveOptions())
|
|
193
|
+
);
|
|
194
|
+
return new DefaultManyToManyCollection(
|
|
195
|
+
meta.ctx,
|
|
196
|
+
metaBase,
|
|
197
|
+
owner,
|
|
198
|
+
relationName,
|
|
199
|
+
many,
|
|
200
|
+
meta.table,
|
|
201
|
+
loader,
|
|
202
|
+
(row: Record<string, unknown>) => createEntity(relation.target, row),
|
|
203
|
+
localKey
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
default:
|
|
207
|
+
return undefined;
|
|
208
|
+
}
|
|
209
|
+
};
|