linkgress-orm 0.4.65 → 0.4.67
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.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -4
- package/dist/index.js.map +1 -1
- package/dist/query/mock-row-cache.d.ts +46 -0
- package/dist/query/mock-row-cache.d.ts.map +1 -0
- package/dist/query/mock-row-cache.js +73 -0
- package/dist/query/mock-row-cache.js.map +1 -0
- package/dist/query/query-builder.d.ts +6 -0
- package/dist/query/query-builder.d.ts.map +1 -1
- package/dist/query/query-builder.js +223 -126
- package/dist/query/query-builder.js.map +1 -1
- package/package.json +78 -78
|
@@ -15,6 +15,7 @@ const cte_builder_1 = require("./cte-builder");
|
|
|
15
15
|
const collection_strategy_factory_1 = require("./collection-strategy.factory");
|
|
16
16
|
const union_builder_1 = require("./union-builder");
|
|
17
17
|
const future_query_1 = require("./future-query");
|
|
18
|
+
const mock_row_cache_1 = require("./mock-row-cache");
|
|
18
19
|
const join_utils_1 = require("./join-utils");
|
|
19
20
|
/**
|
|
20
21
|
* Field type categories for optimized result transformation
|
|
@@ -57,6 +58,60 @@ function getRelationEntriesForSchema(schema) {
|
|
|
57
58
|
// Fallback: build the array (for schemas that weren't built with the new TableBuilder)
|
|
58
59
|
return Object.entries(schema.relations);
|
|
59
60
|
}
|
|
61
|
+
/**
|
|
62
|
+
* Mock-row descriptor cache for {@link ReferenceQueryBuilder.createMockTargetRow}.
|
|
63
|
+
*
|
|
64
|
+
* Building a reference mock row costs O(columns + relations) `Object.defineProperty`
|
|
65
|
+
* calls plus fresh closures per row — and deep selectors (cart → items → product →
|
|
66
|
+
* price → …) rebuild that graph from scratch on EVERY query build. All of it is
|
|
67
|
+
* deterministic in (target schema, relation alias, navigation path), so the property
|
|
68
|
+
* descriptors are built once per signature and reused: each new mock row is a bare
|
|
69
|
+
* object + one `Object.defineProperties` call with the shared descriptor map.
|
|
70
|
+
*
|
|
71
|
+
* Per-instance state (the lazy FieldRef cache and the memoized navigation rows)
|
|
72
|
+
* lives in symbol-keyed slots read by the shared getters through `this`, so sharing
|
|
73
|
+
* descriptors across rows is safe. The navigation-path arrays captured at build
|
|
74
|
+
* time are shared by content — nothing downstream mutates them (they are always
|
|
75
|
+
* spread-copied when extended).
|
|
76
|
+
*/
|
|
77
|
+
const MOCK_ROW_FIELD_REFS = Symbol('linkgressMockFieldRefs');
|
|
78
|
+
const MOCK_ROW_NAV_CACHE = Symbol('linkgressMockNavCache');
|
|
79
|
+
const navigationPathSignature = (path) => path
|
|
80
|
+
.map(step => `${step.alias}:${step.targetTable}:${(step.foreignKeys ?? []).join('+')}:${(step.matches ?? []).join('+')}:${step.isMandatory ? 1 : 0}:${step.sourceAlias ?? ''}`)
|
|
81
|
+
.join('>');
|
|
82
|
+
/**
|
|
83
|
+
* Whether `value` is a reference mock row minted by `ReferenceQueryBuilder.createMockTargetRow`.
|
|
84
|
+
* Those rows INHERIT their column/relation getters from a shared prototype (see MockRowCache),
|
|
85
|
+
* so `Object.getPrototypeOf(row) !== Object.prototype` and own-property APIs see no columns —
|
|
86
|
+
* the row's own state slots are the reliable marker.
|
|
87
|
+
*/
|
|
88
|
+
const isReferenceMockRow = (value) => value != null && typeof value === 'object' && Object.prototype.hasOwnProperty.call(value, MOCK_ROW_FIELD_REFS);
|
|
89
|
+
/** `Object.getOwnPropertyDescriptor` that walks the prototype chain (stops before Object.prototype). */
|
|
90
|
+
const findPropertyDescriptor = (value, key) => {
|
|
91
|
+
let current = value;
|
|
92
|
+
while (current != null && current !== Object.prototype) {
|
|
93
|
+
const descriptor = Object.getOwnPropertyDescriptor(current, key);
|
|
94
|
+
if (descriptor) {
|
|
95
|
+
return descriptor;
|
|
96
|
+
}
|
|
97
|
+
current = Object.getPrototypeOf(current);
|
|
98
|
+
}
|
|
99
|
+
return undefined;
|
|
100
|
+
};
|
|
101
|
+
/**
|
|
102
|
+
* First enumerable key (own or inherited) backed by a getter — the "is this a mock row" probe
|
|
103
|
+
* shared by the selection resolvers. Root mocks define their getters as own properties,
|
|
104
|
+
* reference mocks inherit them; column getters are enumerable on both, so the first
|
|
105
|
+
* enumerable getter is always a column and `row[key]` yields its FieldRef.
|
|
106
|
+
*/
|
|
107
|
+
const findFirstGetterKey = (value) => {
|
|
108
|
+
for (const key in value) {
|
|
109
|
+
if (findPropertyDescriptor(value, key)?.get != null) {
|
|
110
|
+
return key;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return undefined;
|
|
114
|
+
};
|
|
60
115
|
/**
|
|
61
116
|
* Performance utility: Get target schema for a relation, using cached version if available
|
|
62
117
|
*/
|
|
@@ -1680,7 +1735,10 @@ class SelectQueryBuilder {
|
|
|
1680
1735
|
// tryBuildFlatNestedSelect flattens. Class instances (collections, SqlFragment,
|
|
1681
1736
|
// Subquery) and collection-result markers must not be walked.
|
|
1682
1737
|
const proto = Object.getPrototypeOf(value);
|
|
1683
|
-
|
|
1738
|
+
// Reference mock rows inherit their getters from a shared prototype (see
|
|
1739
|
+
// createMockTargetRow) yet must keep being walked exactly like the plain-object mocks
|
|
1740
|
+
// they replaced.
|
|
1741
|
+
if ((proto === Object.prototype || proto === null || isReferenceMockRow(value)) && !('__collectionResult' in value)) {
|
|
1684
1742
|
this.collectJsonRowRevivals(value, pathPrefix ? `${pathPrefix}__${key}` : `__nested__${key}`, revivals, textColumns);
|
|
1685
1743
|
}
|
|
1686
1744
|
}
|
|
@@ -3172,11 +3230,11 @@ class SelectQueryBuilder {
|
|
|
3172
3230
|
joinClauses.push(collection.joinClause);
|
|
3173
3231
|
}
|
|
3174
3232
|
// Build the final CTE query
|
|
3175
|
-
const sql = `WITH "__mutation__" AS (
|
|
3176
|
-
${mutationWithReturning}
|
|
3177
|
-
)
|
|
3178
|
-
SELECT ${selectParts.join(', ')}
|
|
3179
|
-
FROM "__mutation__"
|
|
3233
|
+
const sql = `WITH "__mutation__" AS (
|
|
3234
|
+
${mutationWithReturning}
|
|
3235
|
+
)
|
|
3236
|
+
SELECT ${selectParts.join(', ')}
|
|
3237
|
+
FROM "__mutation__"
|
|
3180
3238
|
${joinClauses.join('\n')}`;
|
|
3181
3239
|
return { sql, params: allParams, nestedPaths };
|
|
3182
3240
|
}
|
|
@@ -4075,19 +4133,15 @@ ${joinClauses.join('\n')}`;
|
|
|
4075
4133
|
continue;
|
|
4076
4134
|
}
|
|
4077
4135
|
}
|
|
4078
|
-
// Check if it's a mock object with
|
|
4079
|
-
|
|
4080
|
-
|
|
4081
|
-
|
|
4082
|
-
const
|
|
4083
|
-
if (
|
|
4136
|
+
// Check if it's a mock object with getter-backed properties (navigation property
|
|
4137
|
+
// mock). The getters may be OWN (root mocks) or INHERITED from the shared
|
|
4138
|
+
// prototype (reference mocks) — findFirstGetterKey walks both.
|
|
4139
|
+
{
|
|
4140
|
+
const tableAlias = findFirstGetterKey(value);
|
|
4141
|
+
if (tableAlias) {
|
|
4084
4142
|
// This object has getter properties - likely a navigation mock
|
|
4085
4143
|
// Try to determine if this is a reference navigation by checking the schema relations
|
|
4086
|
-
|
|
4087
|
-
const desc = Object.getOwnPropertyDescriptor(value, k);
|
|
4088
|
-
return desc && desc.get && typeof desc.get === 'function';
|
|
4089
|
-
});
|
|
4090
|
-
if (tableAlias) {
|
|
4144
|
+
{
|
|
4091
4145
|
// Try to get the first property to check if it has __tableAlias
|
|
4092
4146
|
try {
|
|
4093
4147
|
const firstValue = value[tableAlias];
|
|
@@ -4739,15 +4793,12 @@ ${joinClauses.join('\n')}`;
|
|
|
4739
4793
|
// These are treated as SIMPLE because the actual value comes from json_build_object in the row
|
|
4740
4794
|
// The navigation mock is just a placeholder - actual data processing happens via FieldType.SIMPLE
|
|
4741
4795
|
if (value && typeof value === 'object' && !('__dbColumnName' in value) && !('__fieldName' in value) && !('__collectionResult' in value) && !('__isAggregationArray' in value)) {
|
|
4742
|
-
|
|
4743
|
-
if (
|
|
4744
|
-
|
|
4745
|
-
|
|
4746
|
-
|
|
4747
|
-
|
|
4748
|
-
fieldConfigs.push({ key, type: 8 /* FieldType.SIMPLE */, value });
|
|
4749
|
-
continue;
|
|
4750
|
-
}
|
|
4796
|
+
// Getter-backed row (own getters on a root mock, inherited ones on a reference mock).
|
|
4797
|
+
if (findFirstGetterKey(value) != null) {
|
|
4798
|
+
// Navigation mock - treat as simple, data will come from row via json_build_object
|
|
4799
|
+
// If row has no data, convertValue will return undefined
|
|
4800
|
+
fieldConfigs.push({ key, type: 8 /* FieldType.SIMPLE */, value });
|
|
4801
|
+
continue;
|
|
4751
4802
|
}
|
|
4752
4803
|
}
|
|
4753
4804
|
// Collection types
|
|
@@ -5576,120 +5627,166 @@ class ReferenceQueryBuilder {
|
|
|
5576
5627
|
*/
|
|
5577
5628
|
createMockTargetRow() {
|
|
5578
5629
|
if (this.targetTableSchema) {
|
|
5579
|
-
|
|
5580
|
-
//
|
|
5581
|
-
|
|
5582
|
-
//
|
|
5583
|
-
|
|
5584
|
-
|
|
5585
|
-
//
|
|
5586
|
-
|
|
5587
|
-
|
|
5588
|
-
|
|
5589
|
-
|
|
5590
|
-
|
|
5591
|
-
|
|
5592
|
-
|
|
5593
|
-
|
|
5594
|
-
|
|
5595
|
-
|
|
5596
|
-
}
|
|
5597
|
-
|
|
5598
|
-
|
|
5599
|
-
|
|
5600
|
-
|
|
5601
|
-
|
|
5602
|
-
|
|
5603
|
-
|
|
5604
|
-
|
|
5605
|
-
|
|
5606
|
-
|
|
5607
|
-
|
|
5608
|
-
|
|
5609
|
-
|
|
5610
|
-
|
|
5611
|
-
|
|
5612
|
-
|
|
5613
|
-
|
|
5614
|
-
|
|
5615
|
-
|
|
5616
|
-
|
|
5617
|
-
|
|
5618
|
-
|
|
5619
|
-
|
|
5620
|
-
configurable: true,
|
|
5621
|
-
});
|
|
5630
|
+
// Prototype-level cache — see MockRowCache's doc. Everything the getters close over
|
|
5631
|
+
// is fully determined by (target schema object identity, relationName, sourceAlias,
|
|
5632
|
+
// navigation-path content), so rows with the same signature can share one prebuilt
|
|
5633
|
+
// PROTOTYPE carrying every column/relation getter; a new row is then `Object.create`
|
|
5634
|
+
// plus its two own state slots — O(1) instead of one property definition per column.
|
|
5635
|
+
// The cross-row cache is OPT-IN via the static switch (MockRowCache.setEnabled — the
|
|
5636
|
+
// host app flips it from its own config): with it off, each row gets a FRESH
|
|
5637
|
+
// prototype (the pre-0.4.66 memory profile — nothing retained beyond the row's
|
|
5638
|
+
// lifetime), while the per-row FieldRef and navigation slots stay row-scoped either
|
|
5639
|
+
// way (the shared getters read them through `this`).
|
|
5640
|
+
//
|
|
5641
|
+
// Consumers must not probe these rows with OWN-property APIs (`Object.keys`,
|
|
5642
|
+
// `getOwnPropertyNames`, `getOwnPropertyDescriptor` on the row itself) — the getters
|
|
5643
|
+
// are inherited. Use `isReferenceMockRow` / `findFirstGetterKey` instead.
|
|
5644
|
+
const prototype = mock_row_cache_1.MockRowCache.getOrBuild(`${this.targetTable}|${this.relationName}|${this.sourceAlias ?? ''}|${navigationPathSignature(this.navigationPath)}`, () => Object.defineProperties({}, this.buildMockRowDescriptors()));
|
|
5645
|
+
const mock = Object.create(prototype);
|
|
5646
|
+
mock[MOCK_ROW_FIELD_REFS] = {};
|
|
5647
|
+
mock[MOCK_ROW_NAV_CACHE] = {};
|
|
5648
|
+
return mock;
|
|
5649
|
+
}
|
|
5650
|
+
else {
|
|
5651
|
+
// Fallback: use the shared nested proxy that supports deep property access
|
|
5652
|
+
return createNestedFieldRefProxy(this.relationName);
|
|
5653
|
+
}
|
|
5654
|
+
}
|
|
5655
|
+
/**
|
|
5656
|
+
* Builds the shared property-descriptor map for {@link createMockTargetRow}'s cached path.
|
|
5657
|
+
* The getters read per-row state through `this`-bound symbol slots, so one descriptor
|
|
5658
|
+
* map serves every row of the same signature.
|
|
5659
|
+
*/
|
|
5660
|
+
buildMockRowDescriptors() {
|
|
5661
|
+
// Add columns - use pre-computed column name map if available
|
|
5662
|
+
const columnNameMap = getColumnNameMapForSchema(this.targetTableSchema);
|
|
5663
|
+
const tableAlias = this.relationName;
|
|
5664
|
+
// Build a mapper lookup for columns (only when needed)
|
|
5665
|
+
const columnMappers = {};
|
|
5666
|
+
const columnSqlTypes = {};
|
|
5667
|
+
for (const [colName, colBuilder] of Object.entries(this.targetTableSchema.columns)) {
|
|
5668
|
+
const config = colBuilder.build();
|
|
5669
|
+
if (config.mapper) {
|
|
5670
|
+
columnMappers[colName] = config.mapper;
|
|
5622
5671
|
}
|
|
5623
|
-
|
|
5624
|
-
|
|
5625
|
-
// If sourceAlias is empty, we're in the main query and references are joined in the FROM clause
|
|
5626
|
-
let extendedNavPath = [];
|
|
5627
|
-
if (this.sourceAlias) {
|
|
5628
|
-
// Build the current navigation step to include in path for nested collections
|
|
5629
|
-
// This represents the join from sourceAlias to this.relationName (this.targetTable)
|
|
5630
|
-
const currentNavStep = {
|
|
5631
|
-
alias: this.relationName,
|
|
5632
|
-
targetTable: this.targetTable,
|
|
5633
|
-
foreignKeys: this.foreignKeys,
|
|
5634
|
-
matches: this.matches.length > 0 ? this.matches : ['id'], // Default to 'id' if not specified
|
|
5635
|
-
isMandatory: this.isMandatory,
|
|
5636
|
-
sourceAlias: this.sourceAlias,
|
|
5637
|
-
};
|
|
5638
|
-
extendedNavPath = [...this.navigationPath, currentNavStep];
|
|
5672
|
+
if (config.type) {
|
|
5673
|
+
columnSqlTypes[colName] = config.type;
|
|
5639
5674
|
}
|
|
5640
|
-
|
|
5641
|
-
|
|
5642
|
-
|
|
5643
|
-
|
|
5644
|
-
|
|
5645
|
-
|
|
5646
|
-
|
|
5647
|
-
|
|
5648
|
-
|
|
5649
|
-
|
|
5675
|
+
}
|
|
5676
|
+
const sourceTable = this.targetTable; // Actual table name for schema lookup
|
|
5677
|
+
// Collect all navigation aliases from the path leading to this reference
|
|
5678
|
+
// This is needed for WHERE conditions that use multi-level navigation (e.g., task.level.name)
|
|
5679
|
+
const navigationAliases = this.navigationPath.map(nav => nav.alias);
|
|
5680
|
+
const descriptors = {};
|
|
5681
|
+
for (const [colName, dbColumnName] of columnNameMap) {
|
|
5682
|
+
const mapper = columnMappers[colName];
|
|
5683
|
+
descriptors[colName] = {
|
|
5684
|
+
get() {
|
|
5685
|
+
const slots = this;
|
|
5686
|
+
const fieldRefCache = slots[MOCK_ROW_FIELD_REFS] ?? (slots[MOCK_ROW_FIELD_REFS] = {});
|
|
5687
|
+
let cached = fieldRefCache[colName];
|
|
5688
|
+
if (!cached) {
|
|
5689
|
+
cached = fieldRefCache[colName] = {
|
|
5690
|
+
__fieldName: colName,
|
|
5691
|
+
__dbColumnName: dbColumnName,
|
|
5692
|
+
__tableAlias: tableAlias, // Alias for SQL generation
|
|
5693
|
+
__sourceTable: sourceTable, // Actual table name for mapper lookup
|
|
5694
|
+
__mapper: mapper, // Include mapper for toDriver transformation in conditions
|
|
5695
|
+
__sqlType: columnSqlTypes[colName], // Column SQL type — lets flag* emit width-exact mask casts
|
|
5696
|
+
__navigationAliases: navigationAliases, // All intermediate navigation aliases for JOIN resolution
|
|
5697
|
+
};
|
|
5650
5698
|
}
|
|
5651
|
-
|
|
5652
|
-
|
|
5653
|
-
|
|
5654
|
-
|
|
5655
|
-
|
|
5699
|
+
return cached;
|
|
5700
|
+
},
|
|
5701
|
+
enumerable: true,
|
|
5702
|
+
configurable: true,
|
|
5703
|
+
};
|
|
5704
|
+
}
|
|
5705
|
+
// Build extended navigation path for nested collections
|
|
5706
|
+
// Only build navigation path if we have a sourceAlias (meaning we're inside a collection's selector)
|
|
5707
|
+
// If sourceAlias is empty, we're in the main query and references are joined in the FROM clause
|
|
5708
|
+
let extendedNavPath = [];
|
|
5709
|
+
if (this.sourceAlias) {
|
|
5710
|
+
// Build the current navigation step to include in path for nested collections
|
|
5711
|
+
// This represents the join from sourceAlias to this.relationName (this.targetTable)
|
|
5712
|
+
const currentNavStep = {
|
|
5713
|
+
alias: this.relationName,
|
|
5714
|
+
targetTable: this.targetTable,
|
|
5715
|
+
foreignKeys: this.foreignKeys,
|
|
5716
|
+
matches: this.matches.length > 0 ? this.matches : ['id'], // Default to 'id' if not specified
|
|
5717
|
+
isMandatory: this.isMandatory,
|
|
5718
|
+
sourceAlias: this.sourceAlias,
|
|
5719
|
+
};
|
|
5720
|
+
extendedNavPath = [...this.navigationPath, currentNavStep];
|
|
5721
|
+
}
|
|
5722
|
+
// Values captured at descriptor-build time — identical for every row of this
|
|
5723
|
+
// signature (the registry is the process-wide schema registry; `sourceAlias`
|
|
5724
|
+
// determines whether nested references track their join path).
|
|
5725
|
+
const schemaRegistry = this.schemaRegistry;
|
|
5726
|
+
const parentSourceAlias = this.sourceAlias;
|
|
5727
|
+
// Add navigation properties (both collections and references)
|
|
5728
|
+
if (this.targetTableSchema.relations) {
|
|
5729
|
+
for (const [relName, relConfig] of Object.entries(this.targetTableSchema.relations)) {
|
|
5730
|
+
// Try to get target schema from registry (preferred, has full relations) or targetTableBuilder
|
|
5731
|
+
let nestedTargetSchema;
|
|
5732
|
+
if (this.schemaRegistry) {
|
|
5733
|
+
nestedTargetSchema = this.schemaRegistry.get(relConfig.targetTable);
|
|
5734
|
+
}
|
|
5735
|
+
if (!nestedTargetSchema && relConfig.targetTableBuilder) {
|
|
5736
|
+
nestedTargetSchema = relConfig.targetTableBuilder.build();
|
|
5737
|
+
}
|
|
5738
|
+
if (relConfig.type === 'many') {
|
|
5739
|
+
// Collection navigation
|
|
5740
|
+
// Non-enumerable to prevent Object.entries triggering getters (avoids stack overflow)
|
|
5741
|
+
descriptors[relName] = {
|
|
5742
|
+
get() {
|
|
5743
|
+
const slots = this;
|
|
5744
|
+
const navCache = slots[MOCK_ROW_NAV_CACHE] ?? (slots[MOCK_ROW_NAV_CACHE] = {});
|
|
5745
|
+
// Memoize per row: selectors revisit the same navigation repeatedly
|
|
5746
|
+
// (aggregates, predicates), and each fresh visit used to rebuild the
|
|
5747
|
+
// whole sub-graph.
|
|
5748
|
+
let cached = navCache[relName];
|
|
5749
|
+
if (cached === undefined) {
|
|
5656
5750
|
const fk = relConfig.foreignKey || relConfig.foreignKeys?.[0] || '';
|
|
5657
|
-
|
|
5751
|
+
cached = navCache[relName] = new CollectionQueryBuilder(relName, relConfig.targetTable, fk, tableAlias, // Use alias (relationName) for correlation in lateral joins
|
|
5658
5752
|
nestedTargetSchema, // Pass the target schema directly
|
|
5659
|
-
|
|
5753
|
+
schemaRegistry, // Pass schema registry for nested resolution
|
|
5660
5754
|
extendedNavPath, // Pass navigation path for intermediate joins (empty if main query)
|
|
5661
5755
|
relConfig.foreignKeys, // Propagate composite FK / literal predicates
|
|
5662
5756
|
relConfig.matches);
|
|
5663
|
-
}
|
|
5664
|
-
|
|
5665
|
-
|
|
5666
|
-
|
|
5667
|
-
|
|
5668
|
-
|
|
5669
|
-
|
|
5670
|
-
|
|
5671
|
-
|
|
5672
|
-
|
|
5673
|
-
|
|
5757
|
+
}
|
|
5758
|
+
return cached;
|
|
5759
|
+
},
|
|
5760
|
+
enumerable: false,
|
|
5761
|
+
configurable: true,
|
|
5762
|
+
};
|
|
5763
|
+
}
|
|
5764
|
+
else {
|
|
5765
|
+
// Reference navigation
|
|
5766
|
+
// Non-enumerable to prevent Object.entries triggering getters (avoids stack overflow
|
|
5767
|
+
// with circular relations like User->Posts->User)
|
|
5768
|
+
descriptors[relName] = {
|
|
5769
|
+
get() {
|
|
5770
|
+
const slots = this;
|
|
5771
|
+
const navCache = slots[MOCK_ROW_NAV_CACHE] ?? (slots[MOCK_ROW_NAV_CACHE] = {});
|
|
5772
|
+
let cached = navCache[relName];
|
|
5773
|
+
if (cached === undefined) {
|
|
5674
5774
|
const refBuilder = new ReferenceQueryBuilder(relName, relConfig.targetTable, relConfig.foreignKeys || [relConfig.foreignKey || ''], relConfig.matches || [], relConfig.isMandatory ?? false, nestedTargetSchema, // Pass the target schema directly
|
|
5675
|
-
|
|
5775
|
+
schemaRegistry, // Pass schema registry for nested resolution
|
|
5676
5776
|
extendedNavPath, // Pass navigation path for nested collections
|
|
5677
|
-
|
|
5777
|
+
parentSourceAlias ? tableAlias : '' // Only set source if tracking path
|
|
5678
5778
|
);
|
|
5679
|
-
|
|
5680
|
-
}
|
|
5681
|
-
|
|
5682
|
-
|
|
5683
|
-
|
|
5684
|
-
|
|
5779
|
+
cached = navCache[relName] = refBuilder.createMockTargetRow();
|
|
5780
|
+
}
|
|
5781
|
+
return cached;
|
|
5782
|
+
},
|
|
5783
|
+
enumerable: false,
|
|
5784
|
+
configurable: true,
|
|
5785
|
+
};
|
|
5685
5786
|
}
|
|
5686
5787
|
}
|
|
5687
|
-
return mock;
|
|
5688
|
-
}
|
|
5689
|
-
else {
|
|
5690
|
-
// Fallback: use the shared nested proxy that supports deep property access
|
|
5691
|
-
return createNestedFieldRefProxy(this.relationName);
|
|
5692
5788
|
}
|
|
5789
|
+
return descriptors;
|
|
5693
5790
|
}
|
|
5694
5791
|
}
|
|
5695
5792
|
exports.ReferenceQueryBuilder = ReferenceQueryBuilder;
|