@salesforce/lds-worker-api 1.229.0-dev1 → 1.229.0-dev10
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/sfdc/es/ldsWorkerApi.js +1 -1
- package/dist/standalone/es/lds-worker-api.js +545 -309
- package/dist/standalone/umd/lds-worker-api.js +545 -309
- package/package.json +10 -10
|
@@ -31,12 +31,15 @@
|
|
|
31
31
|
const { isArray: isArray$9 } = Array;
|
|
32
32
|
const { push: push$5, indexOf, slice: slice$2 } = Array.prototype;
|
|
33
33
|
const { parse: parse$a, stringify: stringify$a } = JSON;
|
|
34
|
+
const WeakSetCtor = WeakSet;
|
|
34
35
|
|
|
36
|
+
const deeplyFrozen = new WeakSetCtor();
|
|
35
37
|
function deepFreeze(value) {
|
|
36
|
-
// No need to freeze primitives
|
|
37
|
-
if (typeof value !== 'object' || value === null) {
|
|
38
|
+
// No need to freeze primitives or already frozen stuff
|
|
39
|
+
if (typeof value !== 'object' || value === null || deeplyFrozen.has(value)) {
|
|
38
40
|
return;
|
|
39
41
|
}
|
|
42
|
+
deeplyFrozen.add(value);
|
|
40
43
|
if (isArray$9(value)) {
|
|
41
44
|
for (let i = 0, len = value.length; i < len; i += 1) {
|
|
42
45
|
deepFreeze(value[i]);
|
|
@@ -1733,6 +1736,10 @@
|
|
|
1733
1736
|
}
|
|
1734
1737
|
}
|
|
1735
1738
|
markVisited(canonicalKey) {
|
|
1739
|
+
if (typeof canonicalKey === 'string') {
|
|
1740
|
+
this.fallbackStringKeyInMemoryStore.markVisited(canonicalKey);
|
|
1741
|
+
return;
|
|
1742
|
+
}
|
|
1736
1743
|
const { visitedIdsSet, reverseRedirectKeysMap } = this;
|
|
1737
1744
|
let redirectKey = canonicalKey;
|
|
1738
1745
|
// mark all redirects leading up to the canonical key as visited so
|
|
@@ -2044,7 +2051,7 @@
|
|
|
2044
2051
|
if (isStoreRecordError$1(linked)) {
|
|
2045
2052
|
return new GraphNodeError(this.store, linked);
|
|
2046
2053
|
}
|
|
2047
|
-
return new GraphNode(this.store, linked);
|
|
2054
|
+
return new GraphNode(this.store, linked, __ref);
|
|
2048
2055
|
}
|
|
2049
2056
|
linkData() {
|
|
2050
2057
|
return this.data.data;
|
|
@@ -2054,10 +2061,11 @@
|
|
|
2054
2061
|
}
|
|
2055
2062
|
}
|
|
2056
2063
|
class GraphNode {
|
|
2057
|
-
constructor(store, data) {
|
|
2064
|
+
constructor(store, data, storeKey) {
|
|
2058
2065
|
this.type = GraphNodeType$1.Node;
|
|
2059
2066
|
this.store = store;
|
|
2060
2067
|
this.data = data;
|
|
2068
|
+
this.storeKey = storeKey;
|
|
2061
2069
|
}
|
|
2062
2070
|
object(propertyName) {
|
|
2063
2071
|
const value = this.data[propertyName];
|
|
@@ -2067,7 +2075,8 @@
|
|
|
2067
2075
|
if (typeof value !== 'object' || value === null) {
|
|
2068
2076
|
throw new Error(`Cannot walk to path ${String(propertyName)}. "${String(propertyName)}" is a scalar: "${value}"`);
|
|
2069
2077
|
}
|
|
2070
|
-
|
|
2078
|
+
// We're walking to an object property on the current store record, pass the storeKey down.
|
|
2079
|
+
return new GraphNode(this.store, value, this.storeKey);
|
|
2071
2080
|
}
|
|
2072
2081
|
link(propertyName) {
|
|
2073
2082
|
const value = this.data[propertyName];
|
|
@@ -2097,6 +2106,8 @@
|
|
|
2097
2106
|
}
|
|
2098
2107
|
write(propertyName, value) {
|
|
2099
2108
|
this.data[propertyName] = value;
|
|
2109
|
+
const canonicalKey = this.store.getCanonicalRecordId(this.storeKey);
|
|
2110
|
+
this.store.markVisited(canonicalKey);
|
|
2100
2111
|
}
|
|
2101
2112
|
isUndefined(propertyName) {
|
|
2102
2113
|
return this.data[propertyName] === undefined;
|
|
@@ -2281,6 +2292,34 @@
|
|
|
2281
2292
|
const FRAGMENT_READ_RESULT_MISSING = {
|
|
2282
2293
|
state: FragmentReadResultState$1.Missing,
|
|
2283
2294
|
};
|
|
2295
|
+
function resolveLink$1(reader, storeLink, version) {
|
|
2296
|
+
const { StoreLinkStateValues } = reader;
|
|
2297
|
+
const linkState = reader.getLinkState(storeLink);
|
|
2298
|
+
switch (linkState.state) {
|
|
2299
|
+
case StoreLinkStateValues.RefNotPresent:
|
|
2300
|
+
case StoreLinkStateValues.NotPresent:
|
|
2301
|
+
case StoreLinkStateValues.Missing:
|
|
2302
|
+
reader.markMissingLink(storeLink.__ref);
|
|
2303
|
+
reader.markMissing();
|
|
2304
|
+
return;
|
|
2305
|
+
case StoreLinkStateValues.Pending:
|
|
2306
|
+
reader.markPending();
|
|
2307
|
+
return;
|
|
2308
|
+
case StoreLinkStateValues.Null:
|
|
2309
|
+
return;
|
|
2310
|
+
}
|
|
2311
|
+
const { key: __ref } = linkState;
|
|
2312
|
+
return reader.read({
|
|
2313
|
+
recordId: __ref,
|
|
2314
|
+
node: {
|
|
2315
|
+
kind: 'Fragment',
|
|
2316
|
+
private: [],
|
|
2317
|
+
opaque: true,
|
|
2318
|
+
version,
|
|
2319
|
+
},
|
|
2320
|
+
variables: {},
|
|
2321
|
+
});
|
|
2322
|
+
}
|
|
2284
2323
|
class Reader {
|
|
2285
2324
|
constructor(store, variables, refresh, baseSnapshot, ttlStrategy) {
|
|
2286
2325
|
this.store = store;
|
|
@@ -3231,9 +3270,9 @@
|
|
|
3231
3270
|
if (value === undefined) {
|
|
3232
3271
|
return null;
|
|
3233
3272
|
}
|
|
3234
|
-
return this.wrapNormalizedGraphNode(value, store);
|
|
3273
|
+
return this.wrapNormalizedGraphNode(value, key, store);
|
|
3235
3274
|
}
|
|
3236
|
-
wrapNormalizedGraphNode(normalized, storeOverride) {
|
|
3275
|
+
wrapNormalizedGraphNode(normalized, key, storeOverride) {
|
|
3237
3276
|
if (normalized === null) {
|
|
3238
3277
|
return null;
|
|
3239
3278
|
}
|
|
@@ -3241,7 +3280,7 @@
|
|
|
3241
3280
|
if (isStoreRecordError$1(normalized)) {
|
|
3242
3281
|
return new GraphNodeError(store, normalized);
|
|
3243
3282
|
}
|
|
3244
|
-
return new GraphNode(store, normalized);
|
|
3283
|
+
return new GraphNode(store, normalized, key);
|
|
3245
3284
|
}
|
|
3246
3285
|
withContext(adapter, options) {
|
|
3247
3286
|
const { contextId, onContextLoaded } = options;
|
|
@@ -3536,8 +3575,8 @@
|
|
|
3536
3575
|
getNode(key) {
|
|
3537
3576
|
return this.environment.getNode(key);
|
|
3538
3577
|
}
|
|
3539
|
-
wrapNormalizedGraphNode(normalized) {
|
|
3540
|
-
return this.environment.wrapNormalizedGraphNode(normalized);
|
|
3578
|
+
wrapNormalizedGraphNode(normalized, key) {
|
|
3579
|
+
return this.environment.wrapNormalizedGraphNode(normalized, key);
|
|
3541
3580
|
}
|
|
3542
3581
|
instrument(paramsBuilder) {
|
|
3543
3582
|
const { instrument } = this.options;
|
|
@@ -3847,7 +3886,7 @@
|
|
|
3847
3886
|
}
|
|
3848
3887
|
return resourceParams;
|
|
3849
3888
|
}
|
|
3850
|
-
// engine version: 0.
|
|
3889
|
+
// engine version: 0.146.0-dev5-a2ec6e3f
|
|
3851
3890
|
|
|
3852
3891
|
/**
|
|
3853
3892
|
* Copyright (c) 2022, Salesforce, Inc.,
|
|
@@ -3974,7 +4013,7 @@
|
|
|
3974
4013
|
}
|
|
3975
4014
|
callbacks.push(callback);
|
|
3976
4015
|
}
|
|
3977
|
-
// version: 1.229.0-
|
|
4016
|
+
// version: 1.229.0-dev10-bc9ef2513
|
|
3978
4017
|
|
|
3979
4018
|
// TODO [TD-0081508]: once that TD is fulfilled we can probably change this file
|
|
3980
4019
|
function instrumentAdapter$1(createFunction, _metadata) {
|
|
@@ -15435,7 +15474,7 @@
|
|
|
15435
15474
|
}
|
|
15436
15475
|
return superResult;
|
|
15437
15476
|
}
|
|
15438
|
-
// version: 1.229.0-
|
|
15477
|
+
// version: 1.229.0-dev10-bc9ef2513
|
|
15439
15478
|
|
|
15440
15479
|
function unwrap(data) {
|
|
15441
15480
|
// The lwc-luvio bindings import a function from lwc called "unwrap".
|
|
@@ -15536,14 +15575,15 @@
|
|
|
15536
15575
|
return undefined;
|
|
15537
15576
|
});
|
|
15538
15577
|
}
|
|
15539
|
-
const { isArray: isArray$8 } = Array;
|
|
15540
|
-
const { stringify: stringify$9 } = JSON;
|
|
15541
15578
|
|
|
15542
15579
|
function isPromise$1(value) {
|
|
15543
15580
|
// check for Thenable due to test frameworks using custom Promise impls
|
|
15544
15581
|
return value.then !== undefined;
|
|
15545
15582
|
}
|
|
15546
15583
|
|
|
15584
|
+
const { isArray: isArray$8 } = Array;
|
|
15585
|
+
const { stringify: stringify$9 } = JSON;
|
|
15586
|
+
|
|
15547
15587
|
/**
|
|
15548
15588
|
* (Re)throws an error after adding a prefix to the message.
|
|
15549
15589
|
*
|
|
@@ -16358,7 +16398,7 @@
|
|
|
16358
16398
|
const { apiFamily, name } = metadata;
|
|
16359
16399
|
return createGraphQLWireAdapterConstructor$1(adapter, `${apiFamily}.${name}`, luvio, astResolver);
|
|
16360
16400
|
}
|
|
16361
|
-
// version: 1.229.0-
|
|
16401
|
+
// version: 1.229.0-dev10-bc9ef2513
|
|
16362
16402
|
|
|
16363
16403
|
/**
|
|
16364
16404
|
* Copyright (c) 2022, Salesforce, Inc.,
|
|
@@ -16457,11 +16497,11 @@
|
|
|
16457
16497
|
TypeCheckShapes[TypeCheckShapes["Integer"] = 3] = "Integer";
|
|
16458
16498
|
TypeCheckShapes[TypeCheckShapes["Unsupported"] = 4] = "Unsupported";
|
|
16459
16499
|
})(TypeCheckShapes || (TypeCheckShapes = {}));
|
|
16460
|
-
// engine version: 0.
|
|
16500
|
+
// engine version: 0.146.0-dev5-a2ec6e3f
|
|
16461
16501
|
|
|
16462
16502
|
const { keys: ObjectKeys$3, create: ObjectCreate$3 } = Object;
|
|
16463
16503
|
|
|
16464
|
-
const { assign: assign$9, create: create$9, freeze: freeze$4, keys: keys$b } = Object;
|
|
16504
|
+
const { assign: assign$9, create: create$9, freeze: freeze$4, isFrozen: isFrozen$2, keys: keys$b } = Object;
|
|
16465
16505
|
|
|
16466
16506
|
ObjectCreate$3(null);
|
|
16467
16507
|
|
|
@@ -16831,7 +16871,7 @@
|
|
|
16831
16871
|
}
|
|
16832
16872
|
const keyPrefix$1 = 'UiApi';
|
|
16833
16873
|
|
|
16834
|
-
const { assign: assign$8, create: create$8, freeze: freeze$3, keys: keys$a } = Object;
|
|
16874
|
+
const { assign: assign$8, create: create$8, freeze: freeze$3, isFrozen: isFrozen$1, keys: keys$a } = Object;
|
|
16835
16875
|
const { hasOwnProperty: hasOwnProperty$1 } = Object.prototype;
|
|
16836
16876
|
const { split, endsWith } = String.prototype;
|
|
16837
16877
|
const { isArray: isArray$7 } = Array;
|
|
@@ -19800,7 +19840,7 @@
|
|
|
19800
19840
|
extractTrackedFieldsToTrie(spanningLink.data.__ref, spanning, next, config, spanningVisitedRecordIds, depth + 1);
|
|
19801
19841
|
// For a spanning record that is detected to be a circular reference, we add the field along with Id and Name.
|
|
19802
19842
|
// It's possible for spanning record lookup fields to sometimes be circular, and sometimes not - depending on the value of the lookup field.
|
|
19803
|
-
// For more information on scenarios that caused this fix:
|
|
19843
|
+
// For more information on scenarios that caused this fix: search "LDS Recursive Spanning Fields Problem" in Quip
|
|
19804
19844
|
if (keys$a(next.children).length === 0) {
|
|
19805
19845
|
addScalarFieldId(next);
|
|
19806
19846
|
addScalarFieldName(next);
|
|
@@ -19953,7 +19993,11 @@
|
|
|
19953
19993
|
}
|
|
19954
19994
|
const link = fieldValueRepresentation.link(fieldName);
|
|
19955
19995
|
const resolved = link.follow();
|
|
19956
|
-
if (isGraphNode(resolved) &&
|
|
19996
|
+
if (isGraphNode(resolved) &&
|
|
19997
|
+
resolved.isScalar('value') &&
|
|
19998
|
+
path.length > 0 &&
|
|
19999
|
+
// TODO [W-14082782]: temporary fix
|
|
20000
|
+
!isFrozen$1(link.data)) {
|
|
19957
20001
|
const linkState = link.linkData();
|
|
19958
20002
|
const fields = linkState === undefined ? [] : linkState.fields;
|
|
19959
20003
|
link.writeLinkData({
|
|
@@ -19981,22 +20025,12 @@
|
|
|
19981
20025
|
const fieldValueRepresentation = record.object('fields');
|
|
19982
20026
|
const fieldName = path.shift();
|
|
19983
20027
|
if (fieldValueRepresentation.isUndefined(fieldName) === true) {
|
|
19984
|
-
|
|
19985
|
-
// an undefined/non-present __ref if isMissing is present
|
|
19986
|
-
fieldValueRepresentation.write(fieldName, {
|
|
19987
|
-
__ref: undefined,
|
|
19988
|
-
isMissing: true,
|
|
19989
|
-
});
|
|
20028
|
+
writeMissingFieldToStore(fieldValueRepresentation, fieldName);
|
|
19990
20029
|
return;
|
|
19991
20030
|
}
|
|
19992
20031
|
const link = fieldValueRepresentation.link(fieldName);
|
|
19993
20032
|
if (link.isPending()) {
|
|
19994
|
-
|
|
19995
|
-
// an undefined/non-present __ref if isMissing is present
|
|
19996
|
-
fieldValueRepresentation.write(fieldName, {
|
|
19997
|
-
__ref: undefined,
|
|
19998
|
-
isMissing: true,
|
|
19999
|
-
});
|
|
20033
|
+
writeMissingFieldToStore(fieldValueRepresentation, fieldName);
|
|
20000
20034
|
}
|
|
20001
20035
|
else if (path.length > 0 && link.isMissing() === false) {
|
|
20002
20036
|
const fieldValue = link.follow();
|
|
@@ -20012,6 +20046,19 @@
|
|
|
20012
20046
|
}
|
|
20013
20047
|
}
|
|
20014
20048
|
}
|
|
20049
|
+
/**
|
|
20050
|
+
* Graph Node Directly modifies store entries, which is generally a non-starter.
|
|
20051
|
+
* Until we can refactor this mess, you need to use this function to safely mark the RecordRepresentation
|
|
20052
|
+
* as a seenId in the store when you perform this mutation.
|
|
20053
|
+
*/
|
|
20054
|
+
function writeMissingFieldToStore(field, fieldName) {
|
|
20055
|
+
// TODO [W-6900046]: remove cast, make RecordRepresentationNormalized['fields'] accept
|
|
20056
|
+
// an undefined/non-present __ref if isMissing is present
|
|
20057
|
+
field.write(fieldName, {
|
|
20058
|
+
__ref: undefined,
|
|
20059
|
+
isMissing: true,
|
|
20060
|
+
});
|
|
20061
|
+
}
|
|
20015
20062
|
/**
|
|
20016
20063
|
* Tells you if an objectApiName is supported by UI API or not.
|
|
20017
20064
|
* Note: Luvio does not currently support all the entities, the list is limited to UI API supported entities
|
|
@@ -20143,8 +20190,11 @@
|
|
|
20143
20190
|
return existing;
|
|
20144
20191
|
}
|
|
20145
20192
|
function mergeRecordConflict(luvio, incoming, existing, recordConflictMap) {
|
|
20146
|
-
const
|
|
20147
|
-
|
|
20193
|
+
const recordKey = keyBuilder$1U(luvio, {
|
|
20194
|
+
recordId: incoming.id,
|
|
20195
|
+
});
|
|
20196
|
+
const incomingNode = luvio.wrapNormalizedGraphNode(incoming, recordKey);
|
|
20197
|
+
const existingNode = luvio.wrapNormalizedGraphNode(existing, recordKey);
|
|
20148
20198
|
const incomingTrackedFieldsTrieRoot = {
|
|
20149
20199
|
name: incoming.apiName,
|
|
20150
20200
|
children: {},
|
|
@@ -20153,9 +20203,6 @@
|
|
|
20153
20203
|
name: existing.apiName,
|
|
20154
20204
|
children: {},
|
|
20155
20205
|
};
|
|
20156
|
-
const recordKey = keyBuilder$1U(luvio, {
|
|
20157
|
-
recordId: incoming.id,
|
|
20158
|
-
});
|
|
20159
20206
|
const trackedFieldsConfig = {
|
|
20160
20207
|
maxDepth: configurationForRestAdapters$1.getTrackedFieldDepthOnCacheMergeConflict(),
|
|
20161
20208
|
onlyFetchLeafNodeIdAndName: configurationForRestAdapters$1.getTrackedFieldLeafNodeIdAndNameOnly(),
|
|
@@ -24866,7 +24913,7 @@
|
|
|
24866
24913
|
// Temp fix until we can mimic the server behavior for non-layoutable entities.
|
|
24867
24914
|
let layoutMap = {};
|
|
24868
24915
|
if (hasOwnProperty$1.call(layouts, apiName)) {
|
|
24869
|
-
layoutMap = layouts[apiName][recordTypeId];
|
|
24916
|
+
layoutMap = layouts[apiName][recordTypeId] || {};
|
|
24870
24917
|
}
|
|
24871
24918
|
return {
|
|
24872
24919
|
layoutMap,
|
|
@@ -25044,18 +25091,28 @@
|
|
|
25044
25091
|
* These are intermediate lookups to check if the record is in the L2 cache
|
|
25045
25092
|
* @param {Luvio} luvio
|
|
25046
25093
|
* @param {GetRecordLayoutTypeConfig} config
|
|
25047
|
-
* @param {BuildCachedSnapshot<BuildSnapshotContext} cachedSnapshot
|
|
25094
|
+
* @param {BuildCachedSnapshot<BuildSnapshotContext>} cachedSnapshot
|
|
25048
25095
|
*/
|
|
25049
25096
|
function makeCacheOnlySnapshot(luvio, config, adapterContext, cachedSnapshot) {
|
|
25050
|
-
return luvio.applyCachePolicy(
|
|
25051
|
-
|
|
25052
|
-
|
|
25053
|
-
|
|
25054
|
-
},
|
|
25055
|
-
}, { config, luvio, adapterContext }, cachedSnapshot,
|
|
25056
|
-
// this won't be invoked since we're requesting only-if-cached
|
|
25097
|
+
return luvio.applyCachePolicy(
|
|
25098
|
+
// Pass empty context so environment will use its default cache-policy
|
|
25099
|
+
{}, { config, luvio, adapterContext }, cachedSnapshot,
|
|
25100
|
+
// disallow hitting the network by returning a gateway timeout
|
|
25057
25101
|
() => {
|
|
25058
|
-
|
|
25102
|
+
return new Promise((resolve) => {
|
|
25103
|
+
resolve({
|
|
25104
|
+
state: 'Error',
|
|
25105
|
+
data: undefined,
|
|
25106
|
+
error: {
|
|
25107
|
+
body: undefined,
|
|
25108
|
+
headers: {},
|
|
25109
|
+
ok: false,
|
|
25110
|
+
status: 504,
|
|
25111
|
+
statusText: 'Gateway Timeout',
|
|
25112
|
+
errorType: 'fetchResponse',
|
|
25113
|
+
},
|
|
25114
|
+
});
|
|
25115
|
+
});
|
|
25059
25116
|
});
|
|
25060
25117
|
}
|
|
25061
25118
|
/**
|
|
@@ -25266,7 +25323,7 @@
|
|
|
25266
25323
|
const responsePromises = [];
|
|
25267
25324
|
for (let i = 0, len = entries.length; i < len; i++) {
|
|
25268
25325
|
const { key, record } = entries[i];
|
|
25269
|
-
const node = luvio.wrapNormalizedGraphNode(record);
|
|
25326
|
+
const node = luvio.wrapNormalizedGraphNode(record, key);
|
|
25270
25327
|
const optionalFields = getTrackedFields(key, node, {
|
|
25271
25328
|
maxDepth: configurationForRestAdapters$1.getTrackedFieldDepthOnNotifyChange(),
|
|
25272
25329
|
onlyFetchLeafNodeIdAndName: configurationForRestAdapters$1.getTrackedFieldLeafNodeIdAndNameOnly(),
|
|
@@ -41164,7 +41221,16 @@
|
|
|
41164
41221
|
throttle(60, 60000, createLDSAdapter(luvio, 'notifyListInfoUpdateAvailable', notifyUpdateAvailableFactory$1));
|
|
41165
41222
|
throttle(60, 60000, createLDSAdapter(luvio, 'notifyQuickActionDefaultsUpdateAvailable', notifyUpdateAvailableFactory));
|
|
41166
41223
|
});
|
|
41167
|
-
// version: 1.229.0-
|
|
41224
|
+
// version: 1.229.0-dev10-abb060196
|
|
41225
|
+
|
|
41226
|
+
var ldsIdempotencyWriteDisabled = {
|
|
41227
|
+
isOpen: function (e) {
|
|
41228
|
+
return e.fallback;
|
|
41229
|
+
},
|
|
41230
|
+
hasError: function () {
|
|
41231
|
+
return !0;
|
|
41232
|
+
},
|
|
41233
|
+
};
|
|
41168
41234
|
|
|
41169
41235
|
var caseSensitiveUserId = '005B0000000GR4OIAW';
|
|
41170
41236
|
|
|
@@ -41795,6 +41861,9 @@
|
|
|
41795
41861
|
}
|
|
41796
41862
|
|
|
41797
41863
|
function isStoreEntryError(storeRecord) {
|
|
41864
|
+
if (!storeRecord || typeof storeRecord !== 'object') {
|
|
41865
|
+
return false;
|
|
41866
|
+
}
|
|
41798
41867
|
return storeRecord.__type === 'error';
|
|
41799
41868
|
}
|
|
41800
41869
|
|
|
@@ -42379,12 +42448,12 @@
|
|
|
42379
42448
|
}
|
|
42380
42449
|
return environment.getNode(key, ingestStagingStore);
|
|
42381
42450
|
};
|
|
42382
|
-
const wrapNormalizedGraphNode = function (normalized) {
|
|
42451
|
+
const wrapNormalizedGraphNode = function (normalized, key) {
|
|
42383
42452
|
validateNotDisposed();
|
|
42384
42453
|
if (ingestStagingStore === null) {
|
|
42385
42454
|
ingestStagingStore = buildIngestStagingStore(environment);
|
|
42386
42455
|
}
|
|
42387
|
-
return environment.wrapNormalizedGraphNode(normalized, ingestStagingStore);
|
|
42456
|
+
return environment.wrapNormalizedGraphNode(normalized, key, ingestStagingStore);
|
|
42388
42457
|
};
|
|
42389
42458
|
const rebuildSnapshot = function (snapshot, onRebuild) {
|
|
42390
42459
|
validateNotDisposed();
|
|
@@ -44023,6 +44092,7 @@
|
|
|
44023
44092
|
'Email',
|
|
44024
44093
|
'TextArea',
|
|
44025
44094
|
'Percent',
|
|
44095
|
+
'EncryptedString',
|
|
44026
44096
|
].includes(type);
|
|
44027
44097
|
}
|
|
44028
44098
|
|
|
@@ -45503,8 +45573,12 @@
|
|
|
45503
45573
|
// If there is no metadata for this query or it somehow lacks a timestamp
|
|
45504
45574
|
// skip setting the root timestamp
|
|
45505
45575
|
if (queryMetadata !== undefined && queryMetadata.ingestionTimestamp !== undefined) {
|
|
45506
|
-
|
|
45507
|
-
|
|
45576
|
+
const timestamp = Number(queryMetadata.ingestionTimestamp);
|
|
45577
|
+
if (!isNaN(timestamp)) {
|
|
45578
|
+
// adjust the timestamp to account for ingestion processing time
|
|
45579
|
+
// 30s is used because this is the default record TTL
|
|
45580
|
+
input.rootTimestamp = timestamp - 30000;
|
|
45581
|
+
}
|
|
45508
45582
|
}
|
|
45509
45583
|
}
|
|
45510
45584
|
return recordQuery(selection, alias, apiName, [], input);
|
|
@@ -46317,8 +46391,12 @@
|
|
|
46317
46391
|
|
|
46318
46392
|
const HTTP_HEADER_RETRY_AFTER = 'Retry-After';
|
|
46319
46393
|
const HTTP_HEADER_IDEMPOTENCY_KEY = 'Idempotency-Key';
|
|
46394
|
+
const ERROR_CODE_IDEMPOTENCY_FEATURE_NOT_ENABLED = 'IDEMPOTENCY_FEATURE_NOT_ENABLED';
|
|
46395
|
+
const ERROR_CODE_IDEMPOTENCY_NOT_SUPPORTED = 'IDEMPOTENCY_NOT_SUPPORTED';
|
|
46320
46396
|
const ERROR_CODE_IDEMPOTENCY_KEY_USED_DIFFERENT_USER = 'IDEMPOTENCY_KEY_USED_DIFFERENT_USER';
|
|
46321
46397
|
const ERROR_CODE_IDEMPOTENCY_CONCURRENT_REQUEST = 'IDEMPOTENCY_CONCURRENT_REQUEST';
|
|
46398
|
+
const ERROR_CODE_IDEMPOTENCY_KEY_ALREADY_USED = 'IDEMPOTENCY_KEY_ALREADY_USED';
|
|
46399
|
+
const ERROR_CODE_IDEMPOTENCY_BACKEND_OPERATION_ERROR = 'IDEMPOTENCY_BACKEND_OPERATION_ERROR';
|
|
46322
46400
|
/**
|
|
46323
46401
|
* Get the retry after in milliseconds from the response headers, undefined if not specified.
|
|
46324
46402
|
* The header could have two different format.
|
|
@@ -46348,7 +46426,9 @@
|
|
|
46348
46426
|
const dispatchResourceRequest = async function (resourceRequest, _context) {
|
|
46349
46427
|
const resourceRequestCopy = clone$1(resourceRequest);
|
|
46350
46428
|
resourceRequestCopy.headers = resourceRequestCopy.headers || {};
|
|
46351
|
-
|
|
46429
|
+
if (handler.hasIdempotencySupport()) {
|
|
46430
|
+
resourceRequestCopy.headers[HTTP_HEADER_IDEMPOTENCY_KEY] = uuidv4();
|
|
46431
|
+
}
|
|
46352
46432
|
// enable return extra fields for record creation and record update http call
|
|
46353
46433
|
if (resourceRequest.basePath === '/ui-api/records' &&
|
|
46354
46434
|
(resourceRequest.method === 'post' || resourceRequest.method === 'patch')) {
|
|
@@ -47170,6 +47250,12 @@
|
|
|
47170
47250
|
// the luvio store redirect table, during which a new draft might be enqueued
|
|
47171
47251
|
// which would not see a necessary mapping.
|
|
47172
47252
|
this.ephemeralRedirects = {};
|
|
47253
|
+
// determined by Server setup.
|
|
47254
|
+
this.isIdempotencySupported = true;
|
|
47255
|
+
// idempotency write flag set by lds
|
|
47256
|
+
this.isLdsIdempotencyWriteDisabled = ldsIdempotencyWriteDisabled.isOpen({
|
|
47257
|
+
fallback: false,
|
|
47258
|
+
});
|
|
47173
47259
|
}
|
|
47174
47260
|
enqueue(data) {
|
|
47175
47261
|
return this.draftQueue.enqueue(this.handlerId, data);
|
|
@@ -47199,21 +47285,43 @@
|
|
|
47199
47285
|
retryDelayInMs = getRetryAfterInMs(response.headers);
|
|
47200
47286
|
shouldRetry = true;
|
|
47201
47287
|
break;
|
|
47202
|
-
case HttpStatusCode$1.ServerError:
|
|
47288
|
+
case HttpStatusCode$1.ServerError: {
|
|
47203
47289
|
shouldRetry = true;
|
|
47290
|
+
if (this.handleIdempotencyServerError(response.body, updatedAction, false, ERROR_CODE_IDEMPOTENCY_BACKEND_OPERATION_ERROR)) {
|
|
47291
|
+
this.isIdempotencySupported = false;
|
|
47292
|
+
retryDelayInMs = 0;
|
|
47293
|
+
actionDataChanged = true;
|
|
47294
|
+
}
|
|
47204
47295
|
break;
|
|
47296
|
+
}
|
|
47205
47297
|
case 409 /* IdempotentWriteSpecificHttpStatusCode.Conflict */: {
|
|
47206
|
-
|
|
47207
|
-
|
|
47208
|
-
|
|
47209
|
-
|
|
47298
|
+
if (this.isUiApiErrors(response.body)) {
|
|
47299
|
+
const errorCode = response.body[0].errorCode;
|
|
47300
|
+
if (this.handleIdempotencyServerError(response.body, updatedAction, true, ERROR_CODE_IDEMPOTENCY_KEY_USED_DIFFERENT_USER)) {
|
|
47301
|
+
retryDelayInMs = 0;
|
|
47302
|
+
actionDataChanged = true;
|
|
47303
|
+
}
|
|
47304
|
+
else if (errorCode === ERROR_CODE_IDEMPOTENCY_CONCURRENT_REQUEST) {
|
|
47305
|
+
retryDelayInMs = getRetryAfterInMs(response.headers);
|
|
47306
|
+
}
|
|
47307
|
+
shouldRetry = true;
|
|
47308
|
+
}
|
|
47309
|
+
break;
|
|
47310
|
+
}
|
|
47311
|
+
case HttpStatusCode$1.BadRequest: {
|
|
47312
|
+
if (this.handleIdempotencyServerError(response.body, updatedAction, false, ERROR_CODE_IDEMPOTENCY_FEATURE_NOT_ENABLED, ERROR_CODE_IDEMPOTENCY_NOT_SUPPORTED)) {
|
|
47210
47313
|
retryDelayInMs = 0;
|
|
47211
47314
|
actionDataChanged = true;
|
|
47315
|
+
shouldRetry = true;
|
|
47212
47316
|
}
|
|
47213
|
-
|
|
47214
|
-
|
|
47317
|
+
break;
|
|
47318
|
+
}
|
|
47319
|
+
case 422 /* IdempotentWriteSpecificHttpStatusCode.UnProcessableEntity */: {
|
|
47320
|
+
if (this.handleIdempotencyServerError(response.body, updatedAction, true, ERROR_CODE_IDEMPOTENCY_KEY_ALREADY_USED)) {
|
|
47321
|
+
retryDelayInMs = 0;
|
|
47322
|
+
actionDataChanged = true;
|
|
47323
|
+
shouldRetry = true;
|
|
47215
47324
|
}
|
|
47216
|
-
shouldRetry = true;
|
|
47217
47325
|
break;
|
|
47218
47326
|
}
|
|
47219
47327
|
}
|
|
@@ -47232,6 +47340,27 @@
|
|
|
47232
47340
|
return ProcessActionResult.NETWORK_ERROR;
|
|
47233
47341
|
}
|
|
47234
47342
|
}
|
|
47343
|
+
// true if response is an idempotency server error. updates or deletes idempotency key if the reponse is idempotency related error. Idempotency related error is in format of UiApiError array.
|
|
47344
|
+
handleIdempotencyServerError(responseBody, action, updateIdempotencyKey, ...targetErrorCodes) {
|
|
47345
|
+
if (this.isUiApiErrors(responseBody)) {
|
|
47346
|
+
const errorCode = responseBody[0].errorCode;
|
|
47347
|
+
if (targetErrorCodes.includes(errorCode)) {
|
|
47348
|
+
action.data.headers = action.data.headers || {};
|
|
47349
|
+
if (updateIdempotencyKey) {
|
|
47350
|
+
action.data.headers[HTTP_HEADER_IDEMPOTENCY_KEY] = uuidv4();
|
|
47351
|
+
}
|
|
47352
|
+
else {
|
|
47353
|
+
delete action.data.headers[HTTP_HEADER_IDEMPOTENCY_KEY];
|
|
47354
|
+
}
|
|
47355
|
+
return true;
|
|
47356
|
+
}
|
|
47357
|
+
}
|
|
47358
|
+
return false;
|
|
47359
|
+
}
|
|
47360
|
+
// checks if the body is an array of UiApiError. Sometimes the body has `enhancedErrorType` field as an error indicator(one example is the field validation failure). In such case Action being processed updates to an Error Action.
|
|
47361
|
+
isUiApiErrors(body) {
|
|
47362
|
+
return body !== undefined && Array.isArray(body) && body.length > 0 && body[0].errorCode;
|
|
47363
|
+
}
|
|
47235
47364
|
async buildPendingAction(request, queue) {
|
|
47236
47365
|
const targetId = await this.getIdFromRequest(request);
|
|
47237
47366
|
if (targetId === undefined) {
|
|
@@ -47445,6 +47574,10 @@
|
|
|
47445
47574
|
...targetData,
|
|
47446
47575
|
body: this.mergeRequestBody(targetBody, sourceBody),
|
|
47447
47576
|
};
|
|
47577
|
+
// Updates Idempotency key if target has one
|
|
47578
|
+
if (targetData.headers && targetData.headers[HTTP_HEADER_IDEMPOTENCY_KEY]) {
|
|
47579
|
+
merged.data.headers[HTTP_HEADER_IDEMPOTENCY_KEY] = uuidv4();
|
|
47580
|
+
}
|
|
47448
47581
|
// overlay metadata
|
|
47449
47582
|
merged.metadata = { ...targetMetadata, ...sourceMetadata };
|
|
47450
47583
|
// put status back to pending to auto upload if queue is active and targed is at the head.
|
|
@@ -47481,6 +47614,9 @@
|
|
|
47481
47614
|
getDraftIdsFromAction(action) {
|
|
47482
47615
|
return [action.targetId];
|
|
47483
47616
|
}
|
|
47617
|
+
hasIdempotencySupport() {
|
|
47618
|
+
return this.isIdempotencySupported && !this.isLdsIdempotencyWriteDisabled;
|
|
47619
|
+
}
|
|
47484
47620
|
async ingestResponses(responses, action) {
|
|
47485
47621
|
const luvio = this.getLuvio();
|
|
47486
47622
|
await luvio.handleSuccessResponse(() => {
|
|
@@ -49286,6 +49422,10 @@
|
|
|
49286
49422
|
return node.kind === 'OperationDefinition';
|
|
49287
49423
|
}
|
|
49288
49424
|
|
|
49425
|
+
const POLYMORPHIC_PARENT_RELATIONSHIP = 'polymorphicParentRelationship';
|
|
49426
|
+
const PARENT_RELATIONSHIP = 'parentRelationship';
|
|
49427
|
+
const CHILD_RELATIONSHIP = 'childRelationship';
|
|
49428
|
+
const RECORD_QUERY = 'recordQuery';
|
|
49289
49429
|
function requestsDraftsField(recordFieldNode) {
|
|
49290
49430
|
if (!recordFieldNode.selectionSet)
|
|
49291
49431
|
return false;
|
|
@@ -49301,18 +49441,41 @@
|
|
|
49301
49441
|
directive.arguments
|
|
49302
49442
|
.map((argument) => argument.value)
|
|
49303
49443
|
.filter(isStringValueNode)
|
|
49304
|
-
.some((categoryName) => categoryName.value ===
|
|
49444
|
+
.some((categoryName) => categoryName.value === RECORD_QUERY));
|
|
49305
49445
|
});
|
|
49306
49446
|
}
|
|
49307
49447
|
return false;
|
|
49308
49448
|
}
|
|
49309
|
-
// finds field with 'recordQuery' and 'childRelationship' directive
|
|
49310
|
-
function
|
|
49311
|
-
const
|
|
49312
|
-
return
|
|
49449
|
+
// finds connection field with 'recordQuery' and 'childRelationship' directive.
|
|
49450
|
+
function findNearestConnection(ancestors) {
|
|
49451
|
+
const connectionAncestor = findNearestAncesterPath(ancestors, true).node;
|
|
49452
|
+
return connectionAncestor === undefined ? undefined : connectionAncestor;
|
|
49453
|
+
}
|
|
49454
|
+
// convinient method to find nearest connection with its path
|
|
49455
|
+
function findNearestConnectionWithPath(ancestors) {
|
|
49456
|
+
const closestAncestorPath = findNearestAncesterPath(ancestors, true);
|
|
49457
|
+
let connection = undefined;
|
|
49458
|
+
let connectionPath = undefined;
|
|
49459
|
+
if (closestAncestorPath.parentIndex > 0) {
|
|
49460
|
+
const connectionAncestor = closestAncestorPath.node;
|
|
49461
|
+
const connectionAncestors = ancestors.slice(0, closestAncestorPath.parentIndex);
|
|
49462
|
+
connection =
|
|
49463
|
+
connectionAncestor === undefined ? undefined : connectionAncestor;
|
|
49464
|
+
if (connection !== undefined) {
|
|
49465
|
+
const ancesterPath = findAncesterPath(connectionAncestors);
|
|
49466
|
+
connectionPath =
|
|
49467
|
+
ancesterPath === ''
|
|
49468
|
+
? connection.name.value
|
|
49469
|
+
: `${ancesterPath}#${connection.name.value}`;
|
|
49470
|
+
}
|
|
49471
|
+
}
|
|
49472
|
+
return {
|
|
49473
|
+
connection,
|
|
49474
|
+
path: connectionPath,
|
|
49475
|
+
};
|
|
49313
49476
|
}
|
|
49314
|
-
// finds
|
|
49315
|
-
function findNearestAncesterPath(ancestors,
|
|
49477
|
+
// finds closest ancestor. If node with 'parentRelationship' is the ancester, the end result could be 'InlineFragmentNode' since it inherits the 'parent' relationship. 'InlineFragmentNode' makes sure that only one 'apiName' returns when tree is traversed.
|
|
49478
|
+
function findNearestAncesterPath(ancestors, connectionOnly) {
|
|
49316
49479
|
let recordQueryPath = { node: undefined, parentIndex: -1 };
|
|
49317
49480
|
let relationship = '';
|
|
49318
49481
|
for (let i = ancestors.length - 1; i >= 0; i--) {
|
|
@@ -49326,9 +49489,11 @@
|
|
|
49326
49489
|
continue;
|
|
49327
49490
|
for (let arg of directive.arguments) {
|
|
49328
49491
|
if (arg.value &&
|
|
49329
|
-
(arg.value.value ===
|
|
49330
|
-
arg.value.value ===
|
|
49331
|
-
(!
|
|
49492
|
+
(arg.value.value === RECORD_QUERY ||
|
|
49493
|
+
arg.value.value === CHILD_RELATIONSHIP ||
|
|
49494
|
+
(!connectionOnly &&
|
|
49495
|
+
(arg.value.value === PARENT_RELATIONSHIP ||
|
|
49496
|
+
arg.value.value === POLYMORPHIC_PARENT_RELATIONSHIP)))) {
|
|
49332
49497
|
recordQueryPath = { node: node, parentIndex: i };
|
|
49333
49498
|
relationship = arg.value.value;
|
|
49334
49499
|
break;
|
|
@@ -49343,17 +49508,19 @@
|
|
|
49343
49508
|
//checks if nearest ancester could be an inline fragment
|
|
49344
49509
|
if (recordQueryPath.node !== undefined &&
|
|
49345
49510
|
recordQueryPath.node.selectionSet &&
|
|
49346
|
-
relationship ===
|
|
49347
|
-
//
|
|
49348
|
-
|
|
49349
|
-
|
|
49350
|
-
|
|
49351
|
-
if (
|
|
49511
|
+
(relationship === PARENT_RELATIONSHIP || relationship === POLYMORPHIC_PARENT_RELATIONSHIP)) {
|
|
49512
|
+
// InlineFragment is usually 3 steps aways from its FieldNode parent within ancester hierarchy if it exists. The below search
|
|
49513
|
+
// is applied to adapt to future AST structure change
|
|
49514
|
+
let parentIndex = recordQueryPath.parentIndex + 1;
|
|
49515
|
+
while (parentIndex < ancestors.length) {
|
|
49516
|
+
if (isInlineFragmentNode(ancestors[parentIndex])) {
|
|
49352
49517
|
recordQueryPath = {
|
|
49353
|
-
node: ancestors[
|
|
49354
|
-
parentIndex
|
|
49518
|
+
node: ancestors[parentIndex],
|
|
49519
|
+
parentIndex,
|
|
49355
49520
|
};
|
|
49521
|
+
break;
|
|
49356
49522
|
}
|
|
49523
|
+
parentIndex++;
|
|
49357
49524
|
}
|
|
49358
49525
|
}
|
|
49359
49526
|
return recordQueryPath;
|
|
@@ -49377,7 +49544,7 @@
|
|
|
49377
49544
|
? sectionPath
|
|
49378
49545
|
: sectionPath === ''
|
|
49379
49546
|
? path
|
|
49380
|
-
: `${sectionPath}
|
|
49547
|
+
: `${sectionPath}#${path}`;
|
|
49381
49548
|
}
|
|
49382
49549
|
}
|
|
49383
49550
|
boundaryIndex = parentIndex;
|
|
@@ -49435,9 +49602,9 @@
|
|
|
49435
49602
|
const relationships = args
|
|
49436
49603
|
.map((arg) => arg.value)
|
|
49437
49604
|
.filter(isStringValueNode)
|
|
49438
|
-
.filter((valueNode) => valueNode.value ===
|
|
49439
|
-
valueNode.value ===
|
|
49440
|
-
valueNode.value ===
|
|
49605
|
+
.filter((valueNode) => valueNode.value === CHILD_RELATIONSHIP ||
|
|
49606
|
+
valueNode.value === PARENT_RELATIONSHIP ||
|
|
49607
|
+
valueNode.value === POLYMORPHIC_PARENT_RELATIONSHIP)
|
|
49441
49608
|
.map((relationshipNode) => relationshipNode.value);
|
|
49442
49609
|
if (relationships.length > 0) {
|
|
49443
49610
|
return relationships[0];
|
|
@@ -49494,8 +49661,8 @@
|
|
|
49494
49661
|
*/
|
|
49495
49662
|
function isParentRelationship(node) {
|
|
49496
49663
|
return (node &&
|
|
49497
|
-
(isRelationship(node,
|
|
49498
|
-
isRelationship(node,
|
|
49664
|
+
(isRelationship(node, PARENT_RELATIONSHIP) ||
|
|
49665
|
+
isRelationship(node, POLYMORPHIC_PARENT_RELATIONSHIP)));
|
|
49499
49666
|
}
|
|
49500
49667
|
/*
|
|
49501
49668
|
checks if the InlineFragment spans
|
|
@@ -49801,6 +49968,26 @@
|
|
|
49801
49968
|
return values$1(objectInfo.fields).find((field) => field.apiName === fieldName ||
|
|
49802
49969
|
(field.dataType === 'Reference' && field.relationshipName === fieldName));
|
|
49803
49970
|
}
|
|
49971
|
+
async function readIngestionTimestampForKey(key, query) {
|
|
49972
|
+
let ingestionTimestamp = 0;
|
|
49973
|
+
const sql = `
|
|
49974
|
+
SELECT json_extract(metadata, '${JSON_EXTRACT_PATH_INGESTION_TIMESTAMP}')
|
|
49975
|
+
FROM lds_data
|
|
49976
|
+
WHERE key IS ?
|
|
49977
|
+
`;
|
|
49978
|
+
const results = await query(sql, [key]);
|
|
49979
|
+
const [timestamp] = results.rows.map((row) => row[0]);
|
|
49980
|
+
if (timestamp !== null) {
|
|
49981
|
+
const numericalTimestamp = Number(timestamp);
|
|
49982
|
+
if (isNaN(numericalTimestamp)) {
|
|
49983
|
+
return ingestionTimestamp;
|
|
49984
|
+
}
|
|
49985
|
+
// adjust the timestamp to account for ingestion processing time
|
|
49986
|
+
// 30s is used because this is the default record TTL
|
|
49987
|
+
ingestionTimestamp = numericalTimestamp - 30000;
|
|
49988
|
+
}
|
|
49989
|
+
return ingestionTimestamp;
|
|
49990
|
+
}
|
|
49804
49991
|
|
|
49805
49992
|
function findSpanningField(name) {
|
|
49806
49993
|
return (field) => {
|
|
@@ -50320,17 +50507,7 @@
|
|
|
50320
50507
|
const key = buildKeyStringForRecordQuery(operation,
|
|
50321
50508
|
// join varables passed from query to the argument variables given from the AST
|
|
50322
50509
|
{ ...variableValues, ...args }, info.fieldNodes[0].arguments, apiName);
|
|
50323
|
-
|
|
50324
|
-
SELECT json_extract(metadata, '${JSON_EXTRACT_PATH_INGESTION_TIMESTAMP}')
|
|
50325
|
-
FROM lds_data
|
|
50326
|
-
WHERE key IS ?
|
|
50327
|
-
`;
|
|
50328
|
-
const results = await query(sql, [key]);
|
|
50329
|
-
const [timestamp] = results.rows.map((row) => row[0]);
|
|
50330
|
-
if (timestamp !== null && typeof timestamp === 'number') {
|
|
50331
|
-
//go back 10 ms to adjust for margin of error when top level query is stored and when raml objects are stored
|
|
50332
|
-
ingestionTimestamp = timestamp - 10;
|
|
50333
|
-
}
|
|
50510
|
+
return readIngestionTimestampForKey(key, query);
|
|
50334
50511
|
}
|
|
50335
50512
|
return ingestionTimestamp;
|
|
50336
50513
|
}
|
|
@@ -50378,26 +50555,20 @@
|
|
|
50378
50555
|
let recordConnections = ``;
|
|
50379
50556
|
const polymorphicFieldTypeNames = new Set();
|
|
50380
50557
|
let typedScalars = new Set();
|
|
50558
|
+
let parentRelationshipFields = new Set();
|
|
50381
50559
|
for (const objectInfo of values$1(objectInfos)) {
|
|
50382
50560
|
const { apiName, childRelationships } = objectInfo;
|
|
50383
50561
|
let fields = ``;
|
|
50384
50562
|
typedScalars.add(`${apiName}_Filter`);
|
|
50385
50563
|
typedScalars.add(`${apiName}_OrderBy`);
|
|
50386
|
-
for (const childRelationship of childRelationships) {
|
|
50387
|
-
const { childObjectApiName } = childRelationship;
|
|
50388
|
-
// Only add the relationship if there is relevant objectinfos for it,
|
|
50389
|
-
// otherwise we'd be defining types we cannot satisfy and aren't referenced in
|
|
50390
|
-
// the query.
|
|
50391
|
-
if (objectInfos[childObjectApiName] !== undefined) {
|
|
50392
|
-
fields += `${childRelationship.relationshipName}(first: Int, where: ${childObjectApiName}_Filter, orderBy: ${childObjectApiName}_OrderBy, scope: SupportedScopes): ${childObjectApiName}Connection \n`;
|
|
50393
|
-
typedScalars.add(`${childObjectApiName}_Filter`);
|
|
50394
|
-
typedScalars.add(`${childObjectApiName}_OrderBy`);
|
|
50395
|
-
}
|
|
50396
|
-
}
|
|
50397
50564
|
for (const field of values$1(objectInfo.fields)) {
|
|
50398
50565
|
if (!fieldsStaticallyAdded.includes(field.apiName)) {
|
|
50399
50566
|
fields += `${field.apiName}: ${dataTypeToType(field.dataType, field.apiName)}\n`;
|
|
50400
50567
|
}
|
|
50568
|
+
//handles parent relationship
|
|
50569
|
+
if (field.relationshipName === null) {
|
|
50570
|
+
continue;
|
|
50571
|
+
}
|
|
50401
50572
|
// For spanning parent relationships with no union types
|
|
50402
50573
|
if (field.referenceToInfos.length === 1) {
|
|
50403
50574
|
const [relation] = field.referenceToInfos;
|
|
@@ -50405,11 +50576,13 @@
|
|
|
50405
50576
|
// otherwise we'd be defining types we cannot satisfy and aren't referenced in
|
|
50406
50577
|
// the query.
|
|
50407
50578
|
if (objectInfos[relation.apiName] !== undefined) {
|
|
50579
|
+
parentRelationshipFields.add(field.relationshipName);
|
|
50408
50580
|
fields += `${field.relationshipName}: ${relation.apiName}\n`;
|
|
50409
50581
|
}
|
|
50410
50582
|
// For polymorphic field, its type is 'Record' inteface. The concrete entity type name is saved for field resolving of next phase
|
|
50411
50583
|
}
|
|
50412
50584
|
else if (field.referenceToInfos.length > 1) {
|
|
50585
|
+
parentRelationshipFields.add(field.relationshipName);
|
|
50413
50586
|
fields += `${field.relationshipName}: Record\n`;
|
|
50414
50587
|
for (const relation of field.referenceToInfos) {
|
|
50415
50588
|
if (objectInfos[relation.apiName] !== undefined) {
|
|
@@ -50418,6 +50591,20 @@
|
|
|
50418
50591
|
}
|
|
50419
50592
|
}
|
|
50420
50593
|
}
|
|
50594
|
+
// handles child relationship
|
|
50595
|
+
for (const childRelationship of childRelationships) {
|
|
50596
|
+
const { childObjectApiName } = childRelationship;
|
|
50597
|
+
// Only add the relationship if there is relevant objectinfos for it,
|
|
50598
|
+
// otherwise we'd be defining types we cannot satisfy and aren't referenced in
|
|
50599
|
+
// the query.
|
|
50600
|
+
// If one field has both parent relationship and child relationship with the same name, the child relationship is ignored. This is how the server GQL has implemented as date of 08/07/2023
|
|
50601
|
+
if (objectInfos[childObjectApiName] !== undefined &&
|
|
50602
|
+
!parentRelationshipFields.has(childRelationship.relationshipName)) {
|
|
50603
|
+
fields += `${childRelationship.relationshipName}(first: Int, where: ${childObjectApiName}_Filter, orderBy: ${childObjectApiName}_OrderBy, scope: SupportedScopes): ${childObjectApiName}Connection \n`;
|
|
50604
|
+
typedScalars.add(`${childObjectApiName}_Filter`);
|
|
50605
|
+
typedScalars.add(`${childObjectApiName}_OrderBy`);
|
|
50606
|
+
}
|
|
50607
|
+
}
|
|
50421
50608
|
recordQueries += `${apiName}(first: Int, where: ${apiName}_Filter, orderBy: ${apiName}_OrderBy, scope: SupportedScopes): ${apiName}Connection\n`;
|
|
50422
50609
|
const isServiceAppointment = apiName === 'ServiceAppointment';
|
|
50423
50610
|
recordConnections += /* GraphQL */ `
|
|
@@ -50492,6 +50679,8 @@
|
|
|
50492
50679
|
return 'PercentValue';
|
|
50493
50680
|
case 'Int':
|
|
50494
50681
|
return 'IntValue';
|
|
50682
|
+
case 'EncryptedString':
|
|
50683
|
+
return 'EncryptedStringValue';
|
|
50495
50684
|
// ! do the rest of the custom types
|
|
50496
50685
|
default:
|
|
50497
50686
|
return 'String';
|
|
@@ -50577,7 +50766,7 @@
|
|
|
50577
50766
|
},
|
|
50578
50767
|
value: {
|
|
50579
50768
|
kind: Kind.STRING,
|
|
50580
|
-
value:
|
|
50769
|
+
value: PARENT_RELATIONSHIP,
|
|
50581
50770
|
block: false,
|
|
50582
50771
|
},
|
|
50583
50772
|
},
|
|
@@ -50591,8 +50780,8 @@
|
|
|
50591
50780
|
// example 2 'ServiceAppointment' -> ['Owner']; 'Owner' -> ['User', 'Group']
|
|
50592
50781
|
const objectNodeInfoTree = {};
|
|
50593
50782
|
// save the field path to apiName map
|
|
50594
|
-
// example 1: 'ServiceAppointment' -> ['ServiceAppointment']; '
|
|
50595
|
-
const
|
|
50783
|
+
// example 1: 'ServiceAppointment' -> ['ServiceAppointment']; 'ServiceAppointment#ccount' -> ['Account']; 'ServiceAppointment#Account#Owner' -> ['User']
|
|
50784
|
+
const pathToObjectApiNamesMap = {};
|
|
50596
50785
|
let startNodes = new Set();
|
|
50597
50786
|
let totalNodes = new Set();
|
|
50598
50787
|
let objectInfos = {};
|
|
@@ -50606,11 +50795,11 @@
|
|
|
50606
50795
|
visit(originalAST, {
|
|
50607
50796
|
Argument: {
|
|
50608
50797
|
enter(node, key, parent, path, ancestors) {
|
|
50609
|
-
const
|
|
50610
|
-
if (!
|
|
50798
|
+
const { connection: recordConnectionNode, path: ancesterPath } = findNearestConnectionWithPath(ancestors);
|
|
50799
|
+
if (!recordConnectionNode || !ancesterPath)
|
|
50611
50800
|
return;
|
|
50612
|
-
if (!objectNodeInfoTree[
|
|
50613
|
-
objectNodeInfoTree[
|
|
50801
|
+
if (!objectNodeInfoTree[ancesterPath]) {
|
|
50802
|
+
objectNodeInfoTree[ancesterPath] = [];
|
|
50614
50803
|
}
|
|
50615
50804
|
switch (node.name.value) {
|
|
50616
50805
|
case 'orderBy':
|
|
@@ -50618,12 +50807,12 @@
|
|
|
50618
50807
|
if (node.value.kind !== 'ObjectValue') {
|
|
50619
50808
|
return;
|
|
50620
50809
|
}
|
|
50621
|
-
totalNodes.add(
|
|
50810
|
+
totalNodes.add(ancesterPath);
|
|
50622
50811
|
// 'childRelationship' node is not taken as the startNode of the 'NodeInfoTree' graph. The field scanning will construct the graph which lead here.
|
|
50623
|
-
if (isRecordQuery(
|
|
50624
|
-
startNodes.add(
|
|
50812
|
+
if (isRecordQuery(recordConnectionNode)) {
|
|
50813
|
+
startNodes.add(recordConnectionNode.name.value);
|
|
50625
50814
|
}
|
|
50626
|
-
growObjectFieldTree(objectNodeInfoTree,
|
|
50815
|
+
growObjectFieldTree(objectNodeInfoTree, ancesterPath, node.value, totalNodes, startNodes);
|
|
50627
50816
|
break;
|
|
50628
50817
|
case 'scope':
|
|
50629
50818
|
if (!isScopeArgumentNodeWithType(node, 'ASSIGNEDTOME', variables)) {
|
|
@@ -50638,17 +50827,16 @@
|
|
|
50638
50827
|
name: 'ServiceResources',
|
|
50639
50828
|
});
|
|
50640
50829
|
}
|
|
50641
|
-
if (objectNodeInfoTree['ServiceResources'] === undefined) {
|
|
50642
|
-
objectNodeInfoTree['ServiceResources'] = [
|
|
50643
|
-
|
|
50644
|
-
|
|
50645
|
-
|
|
50646
|
-
|
|
50647
|
-
|
|
50648
|
-
});
|
|
50830
|
+
if (objectNodeInfoTree['ServiceAppointment#ServiceResources'] === undefined) {
|
|
50831
|
+
objectNodeInfoTree['ServiceAppointment#ServiceResources'] = [
|
|
50832
|
+
{
|
|
50833
|
+
relation: 'parent',
|
|
50834
|
+
name: 'ServiceResource',
|
|
50835
|
+
},
|
|
50836
|
+
];
|
|
50649
50837
|
}
|
|
50650
|
-
if (objectNodeInfoTree['ServiceResource'] === undefined) {
|
|
50651
|
-
objectNodeInfoTree['ServiceResource'] = [];
|
|
50838
|
+
if (objectNodeInfoTree['ServiceAppointment#ServiceResources#ServiceResource'] === undefined) {
|
|
50839
|
+
objectNodeInfoTree['ServiceAppointment#ServiceResources#ServiceResource'] = [];
|
|
50652
50840
|
}
|
|
50653
50841
|
break;
|
|
50654
50842
|
default:
|
|
@@ -50662,7 +50850,7 @@
|
|
|
50662
50850
|
return;
|
|
50663
50851
|
if (!node.selectionSet)
|
|
50664
50852
|
return;
|
|
50665
|
-
const recordQueryField =
|
|
50853
|
+
const recordQueryField = findNearestConnection(ancestors);
|
|
50666
50854
|
//only injects fields for 'recordQuery' field. ignores the 'childRelationship' field since it will be traversed as the child of the 'recordQuery'
|
|
50667
50855
|
if (isRecordQuery(recordQueryField) && recordQueryField) {
|
|
50668
50856
|
totalNodes.add(recordQueryField.name.value);
|
|
@@ -50673,21 +50861,21 @@
|
|
|
50673
50861
|
},
|
|
50674
50862
|
});
|
|
50675
50863
|
if (objectInfoService && startNodes.size > 0) {
|
|
50676
|
-
objectInfos = await resolveObjectInfos(objectNodeInfoTree,
|
|
50864
|
+
objectInfos = await resolveObjectInfos(objectNodeInfoTree, pathToObjectApiNamesMap, startNodes, objectInfoService);
|
|
50677
50865
|
}
|
|
50678
50866
|
// read pass; gather whats needed
|
|
50679
50867
|
visit(originalAST, {
|
|
50680
50868
|
Argument: {
|
|
50681
50869
|
leave(node, key, parent, path, ancestors) {
|
|
50682
|
-
const recordQueryField =
|
|
50870
|
+
const recordQueryField = findNearestConnection(ancestors);
|
|
50683
50871
|
if (!recordQueryField)
|
|
50684
50872
|
return;
|
|
50685
50873
|
const ancestorPath = findAncesterPath(ancestors);
|
|
50686
50874
|
if (!inlineFragmentSelections[ancestorPath]) {
|
|
50687
50875
|
inlineFragmentSelections[ancestorPath] = [];
|
|
50688
50876
|
}
|
|
50689
|
-
const recordQueryApiName =
|
|
50690
|
-
?
|
|
50877
|
+
const recordQueryApiName = pathToObjectApiNamesMap[ancestorPath]
|
|
50878
|
+
? pathToObjectApiNamesMap[ancestorPath][0]
|
|
50691
50879
|
: recordQueryField.name.value;
|
|
50692
50880
|
// The record node acts as the reference. The duplicated field in the record node is not injected
|
|
50693
50881
|
const recordReferenceNode = [recordQueryField]
|
|
@@ -50701,7 +50889,7 @@
|
|
|
50701
50889
|
case 'scope':
|
|
50702
50890
|
// Hanle 'MINE' field
|
|
50703
50891
|
if (isScopeArgumentNodeWithType(node, 'MINE', variables)) {
|
|
50704
|
-
if (isMineScopeAvailable(ancestorPath,
|
|
50892
|
+
if (isMineScopeAvailable(ancestorPath, pathToObjectApiNamesMap, objectInfos)) {
|
|
50705
50893
|
// 'typeConditon' is added when the 'InlineFragmentNode' is appended at the write pass
|
|
50706
50894
|
inlineFragmentSelections[ancestorPath].push(...mineFragmentSelections);
|
|
50707
50895
|
}
|
|
@@ -50727,7 +50915,7 @@
|
|
|
50727
50915
|
case 'where': {
|
|
50728
50916
|
inlineFragmentSelections[ancestorPath] = [
|
|
50729
50917
|
...inlineFragmentSelections[ancestorPath],
|
|
50730
|
-
...injectFilter(node, idState, ancestorPath, objectInfos,
|
|
50918
|
+
...injectFilter(node, idState, ancestorPath, false, objectInfos, pathToObjectApiNamesMap, draftFunctions, recordReferenceNode),
|
|
50731
50919
|
];
|
|
50732
50920
|
break;
|
|
50733
50921
|
}
|
|
@@ -50743,7 +50931,7 @@
|
|
|
50743
50931
|
if (!node.selectionSet)
|
|
50744
50932
|
return;
|
|
50745
50933
|
// it could be 'recordQuery' or 'childRelationship'
|
|
50746
|
-
const recordQueryField =
|
|
50934
|
+
const recordQueryField = findNearestConnection(ancestors);
|
|
50747
50935
|
if (!recordQueryField)
|
|
50748
50936
|
return;
|
|
50749
50937
|
const ancestorPath = findAncesterPath(ancestors);
|
|
@@ -50755,7 +50943,7 @@
|
|
|
50755
50943
|
spanningSelections.push(selection);
|
|
50756
50944
|
}
|
|
50757
50945
|
}
|
|
50758
|
-
const injectedFields = injectFields(spanningSelections, node, ancestors, objectInfos,
|
|
50946
|
+
const injectedFields = injectFields(spanningSelections, node, ancestorPath, ancestors, objectInfos, pathToObjectApiNamesMap);
|
|
50759
50947
|
const mergedInjectedFields = mergeSelectionNodes$1(inlineFragmentSelections[ancestorPath], injectedFields);
|
|
50760
50948
|
inlineFragmentSelections[ancestorPath] = mergedInjectedFields;
|
|
50761
50949
|
},
|
|
@@ -50768,7 +50956,7 @@
|
|
|
50768
50956
|
// removes 'ServicesResources' query field node if 'assignedtome' scope shows up
|
|
50769
50957
|
if (assignedtomeQueryFieldNode !== undefined &&
|
|
50770
50958
|
node.name.value === 'ServiceResources') {
|
|
50771
|
-
const serviceResourcesAncestor =
|
|
50959
|
+
const serviceResourcesAncestor = findNearestConnection(ancestors);
|
|
50772
50960
|
if (serviceResourcesAncestor === assignedtomeQueryFieldNode) {
|
|
50773
50961
|
return null;
|
|
50774
50962
|
}
|
|
@@ -50777,7 +50965,7 @@
|
|
|
50777
50965
|
return;
|
|
50778
50966
|
if (!node.selectionSet)
|
|
50779
50967
|
return;
|
|
50780
|
-
const recordQueryField =
|
|
50968
|
+
const recordQueryField = findNearestConnection(ancestors);
|
|
50781
50969
|
if (!recordQueryField)
|
|
50782
50970
|
return;
|
|
50783
50971
|
const ancestorPath = findAncesterPath(ancestors);
|
|
@@ -50786,8 +50974,8 @@
|
|
|
50786
50974
|
return;
|
|
50787
50975
|
//const recordQueryPath = findAncesterPath(ancestors);
|
|
50788
50976
|
// 'apiName' has to be at index 0 since 'node' record type could only be of 'recordQuery' or 'childRelationship'. They can not have the 'InlineFragmentNode' as its children.
|
|
50789
|
-
const recordQueryApiName =
|
|
50790
|
-
?
|
|
50977
|
+
const recordQueryApiName = pathToObjectApiNamesMap[ancestorPath]
|
|
50978
|
+
? pathToObjectApiNamesMap[ancestorPath][0]
|
|
50791
50979
|
: recordQueryField.name.value;
|
|
50792
50980
|
const nodeWithFragments = {
|
|
50793
50981
|
...node,
|
|
@@ -50824,7 +51012,7 @@
|
|
|
50824
51012
|
if (node.name.value === 'where') {
|
|
50825
51013
|
const ancestorPath = findAncesterPath(ancestors);
|
|
50826
51014
|
if (idState.paths.includes(ancestorPath)) {
|
|
50827
|
-
const apiName =
|
|
51015
|
+
const apiName = pathToObjectApiNamesMap[ancestorPath][0];
|
|
50828
51016
|
const objectInfo = objectInfos[apiName];
|
|
50829
51017
|
const swappedIdFilter = swapIdField(node.value, objectInfo, false, idState, draftFunctions);
|
|
50830
51018
|
return {
|
|
@@ -50890,8 +51078,8 @@
|
|
|
50890
51078
|
};
|
|
50891
51079
|
}
|
|
50892
51080
|
}
|
|
50893
|
-
function isMineScopeAvailable(apiNamePath,
|
|
50894
|
-
const apiName =
|
|
51081
|
+
function isMineScopeAvailable(apiNamePath, pathToObjectApiNamesMap, objectInfos) {
|
|
51082
|
+
const apiName = pathToObjectApiNamesMap[apiNamePath];
|
|
50895
51083
|
if (!apiName)
|
|
50896
51084
|
return false;
|
|
50897
51085
|
const objectInfo = objectInfos[apiName[0]];
|
|
@@ -50980,15 +51168,16 @@
|
|
|
50980
51168
|
}
|
|
50981
51169
|
// example: 'Account'
|
|
50982
51170
|
const childNode = objectFieldNode.name.value;
|
|
51171
|
+
const childNodepath = `${parentNode}#${childNode}`;
|
|
50983
51172
|
if (!tree[parentNode].some((child) => child.name === childNode)) {
|
|
50984
51173
|
tree[parentNode].push({
|
|
50985
51174
|
relation: 'parent',
|
|
50986
51175
|
name: childNode,
|
|
50987
51176
|
});
|
|
50988
|
-
totalNodes.add(
|
|
51177
|
+
totalNodes.add(childNodepath);
|
|
50989
51178
|
}
|
|
50990
51179
|
// recursively go to deeper level of filter.
|
|
50991
|
-
growObjectFieldTree(tree,
|
|
51180
|
+
growObjectFieldTree(tree, childNodepath, objectFieldNode.value, totalNodes, startNodes);
|
|
50992
51181
|
}
|
|
50993
51182
|
}
|
|
50994
51183
|
}
|
|
@@ -51023,19 +51212,20 @@
|
|
|
51023
51212
|
}
|
|
51024
51213
|
if (!tree[parentSectionPath].some((field) => field.name === fieldName)) {
|
|
51025
51214
|
tree[parentSectionPath].push({
|
|
51026
|
-
relation: relationType ===
|
|
51027
|
-
relationType ===
|
|
51215
|
+
relation: relationType === PARENT_RELATIONSHIP ||
|
|
51216
|
+
relationType === POLYMORPHIC_PARENT_RELATIONSHIP
|
|
51028
51217
|
? 'parent'
|
|
51029
51218
|
: 'child',
|
|
51030
51219
|
name: fieldName,
|
|
51031
51220
|
});
|
|
51032
|
-
totalNodes.add(fieldName);
|
|
51221
|
+
totalNodes.add(`${parentSectionPath}#${fieldName}`);
|
|
51033
51222
|
}
|
|
51034
51223
|
if (entryNode.selectionSet && entryNode.selectionSet.selections) {
|
|
51035
51224
|
const childNodes = entryNode.selectionSet.selections.filter(isFieldOrInlineFragmentNode);
|
|
51036
51225
|
// recursively build the traversal tree
|
|
51037
51226
|
for (const child of childNodes) {
|
|
51038
|
-
|
|
51227
|
+
const path = `${parentSectionPath}#${fieldName}`;
|
|
51228
|
+
growFieldTree(tree, path, child, entryNode, totalNodes, startNodes);
|
|
51039
51229
|
}
|
|
51040
51230
|
}
|
|
51041
51231
|
}
|
|
@@ -51065,23 +51255,23 @@
|
|
|
51065
51255
|
}
|
|
51066
51256
|
if (!tree[parentSectionPath].some((field) => field.name === conditionName)) {
|
|
51067
51257
|
tree[parentSectionPath].push({
|
|
51068
|
-
relation: relationType ===
|
|
51069
|
-
relationType ===
|
|
51258
|
+
relation: relationType === PARENT_RELATIONSHIP ||
|
|
51259
|
+
relationType === POLYMORPHIC_PARENT_RELATIONSHIP
|
|
51070
51260
|
? 'parent'
|
|
51071
51261
|
: 'child',
|
|
51072
51262
|
name: conditionName,
|
|
51073
51263
|
});
|
|
51074
|
-
|
|
51264
|
+
const path = `${parentSectionPath}#${conditionName}`;
|
|
51265
|
+
totalNodes.add(path);
|
|
51075
51266
|
}
|
|
51076
51267
|
}
|
|
51077
51268
|
}
|
|
51078
51269
|
// dive deep immediately for 'InlineFragment'
|
|
51079
51270
|
const childNodes = entryNode.selectionSet.selections.filter(isFieldOrInlineFragmentNode);
|
|
51271
|
+
const path = `${parentSectionPath}${entryNode.typeCondition ? '#' + entryNode.typeCondition.name.value : ''}`;
|
|
51080
51272
|
// Navigates into InLineFragment
|
|
51081
51273
|
for (const child of childNodes) {
|
|
51082
|
-
growFieldTree(tree, entryNode
|
|
51083
|
-
? entryNode.typeCondition.name.value
|
|
51084
|
-
: parentSectionPath, child, entryNode, totalNodes, startNodes);
|
|
51274
|
+
growFieldTree(tree, path, child, entryNode, totalNodes, startNodes);
|
|
51085
51275
|
}
|
|
51086
51276
|
}
|
|
51087
51277
|
}
|
|
@@ -51093,7 +51283,7 @@
|
|
|
51093
51283
|
* @param startNodes start nodes of the tree. It can be used to fetch ObjectInfo immediately
|
|
51094
51284
|
* @param path
|
|
51095
51285
|
*/
|
|
51096
|
-
async function resolveObjectInfos(objectInfotree,
|
|
51286
|
+
async function resolveObjectInfos(objectInfotree, pathToObjectApiNamesMap, startNodes, objectInfoService) {
|
|
51097
51287
|
let objectInfos;
|
|
51098
51288
|
try {
|
|
51099
51289
|
objectInfos = await objectInfoService.getObjectInfos(Array.from(startNodes));
|
|
@@ -51107,9 +51297,9 @@
|
|
|
51107
51297
|
throw new Error(`Unable to resolve ObjectInfo(s) for ${Array.from(startNodes)}`);
|
|
51108
51298
|
}
|
|
51109
51299
|
for (const startNode of startNodes) {
|
|
51110
|
-
|
|
51300
|
+
pathToObjectApiNamesMap[startNode] = [startNode];
|
|
51111
51301
|
const children = objectInfotree[startNode];
|
|
51112
|
-
const subObjectInfoMap = await fetchObjectInfos(objectInfotree,
|
|
51302
|
+
const subObjectInfoMap = await fetchObjectInfos(objectInfotree, pathToObjectApiNamesMap, objectInfos, children, startNode, objectInfoService);
|
|
51113
51303
|
objectInfos = { ...objectInfos, ...subObjectInfoMap };
|
|
51114
51304
|
}
|
|
51115
51305
|
return objectInfos;
|
|
@@ -51117,15 +51307,15 @@
|
|
|
51117
51307
|
// example 1: 'parentPath': 'ServiceAppointment', 'nodesAtSameLevel': ['Account']
|
|
51118
51308
|
// example 2: 'parentPath': 'ServiceAppointment', 'nodesAtSameLevel': ['Owner'], this example has 2 apiName for the node 'Owner'
|
|
51119
51309
|
// example 3: 'parentPath': 'ServiceAppointment_Owner', 'nodesAtSameLevel': ['User', 'Group']
|
|
51120
|
-
async function fetchObjectInfos(objectInfotree,
|
|
51121
|
-
const objectInfoApiNames =
|
|
51310
|
+
async function fetchObjectInfos(objectInfotree, pathToObjectApiNamesMap, objectInfoMap, nodesAtSameLevel, parentPath, objectInfoService) {
|
|
51311
|
+
const objectInfoApiNames = pathToObjectApiNamesMap[parentPath];
|
|
51122
51312
|
if (!objectInfoApiNames) {
|
|
51123
51313
|
// eslint-disable-next-line
|
|
51124
51314
|
throw new Error(`Object Info does not exist for ${parentPath}`);
|
|
51125
51315
|
}
|
|
51126
51316
|
const validObjectInfoNodes = [];
|
|
51127
51317
|
let updatedObjectInfoMap = {};
|
|
51128
|
-
// InlineFragment and polymorphic field support fits into this scenario
|
|
51318
|
+
// InlineFragment and polymorphic field support fits into this scenario pathToObjectApiNamesMap Entry: 'ServiceAppointment#Owner' -> ['User', 'Group']; ServiceAppointment#Owner#User' -> ['User']
|
|
51129
51319
|
if (objectInfoApiNames.length > 0 &&
|
|
51130
51320
|
nodesAtSameLevel.length > 0 &&
|
|
51131
51321
|
objectInfoApiNames.includes(nodesAtSameLevel[0].name)) {
|
|
@@ -51137,8 +51327,8 @@
|
|
|
51137
51327
|
// eslint-disable-next-line
|
|
51138
51328
|
throw new Error(`Condition ${field.name} does not exists for ${parentPath}`);
|
|
51139
51329
|
}
|
|
51140
|
-
const path = `${parentPath}
|
|
51141
|
-
|
|
51330
|
+
const path = `${parentPath}#${field.name}`;
|
|
51331
|
+
pathToObjectApiNamesMap[path] = [field.name];
|
|
51142
51332
|
}
|
|
51143
51333
|
validObjectInfoNodes.push(...nodesAtSameLevel);
|
|
51144
51334
|
updatedObjectInfoMap = { ...objectInfoMap };
|
|
@@ -51153,7 +51343,7 @@
|
|
|
51153
51343
|
let apiNames = [];
|
|
51154
51344
|
for (const nodeInfo of nodesAtSameLevel) {
|
|
51155
51345
|
const field = nodeInfo.name;
|
|
51156
|
-
const path = `${parentPath}
|
|
51346
|
+
const path = `${parentPath}#${field}`;
|
|
51157
51347
|
// Handle 'parentRelationship'
|
|
51158
51348
|
if (nodeInfo.relation === 'parent') {
|
|
51159
51349
|
const relationshipId = referenceIdFieldForRelationship(field);
|
|
@@ -51171,21 +51361,21 @@
|
|
|
51171
51361
|
}
|
|
51172
51362
|
}
|
|
51173
51363
|
// This is a polymorphic field
|
|
51174
|
-
if (fieldDefinition.referenceToInfos.length > 1 && objectInfotree[
|
|
51364
|
+
if (fieldDefinition.referenceToInfos.length > 1 && objectInfotree[path]) {
|
|
51175
51365
|
// Fields needs to expand and heterogenous entity ObjectInfo needs to be fetched
|
|
51176
|
-
const referencedNodeInfos = objectInfotree[
|
|
51366
|
+
const referencedNodeInfos = objectInfotree[path];
|
|
51177
51367
|
const requestedApiNames = referencedNodeInfos.map((referenceNodeInfo) => referenceNodeInfo.name);
|
|
51178
51368
|
// Fetches requested ObjectInfo only. Some entity's relation field could define more than 6 references. Only references show up in query need to be handled.
|
|
51179
|
-
if (requestedApiNames.length > 0 && objectInfotree[
|
|
51369
|
+
if (requestedApiNames.length > 0 && objectInfotree[path]) {
|
|
51180
51370
|
fieldDefinition.referenceToInfos
|
|
51181
51371
|
.filter((referenceToInfo) => requestedApiNames.includes(referenceToInfo.apiName))
|
|
51182
51372
|
.forEach((ref) => {
|
|
51183
|
-
if (!
|
|
51184
|
-
|
|
51373
|
+
if (!pathToObjectApiNamesMap[path]) {
|
|
51374
|
+
pathToObjectApiNamesMap[path] = [];
|
|
51185
51375
|
}
|
|
51186
51376
|
// 'ServiceAppointment_Owner' ->['User', 'Group']
|
|
51187
|
-
if (!
|
|
51188
|
-
|
|
51377
|
+
if (!pathToObjectApiNamesMap[path].includes(ref.apiName)) {
|
|
51378
|
+
pathToObjectApiNamesMap[path].push(ref.apiName);
|
|
51189
51379
|
}
|
|
51190
51380
|
if (!apiNames.includes(ref.apiName)) {
|
|
51191
51381
|
apiNames.push(ref.apiName);
|
|
@@ -51195,11 +51385,11 @@
|
|
|
51195
51385
|
}
|
|
51196
51386
|
else if (fieldDefinition.referenceToInfos.length === 1) {
|
|
51197
51387
|
const ref = fieldDefinition.referenceToInfos[0];
|
|
51198
|
-
if (!
|
|
51199
|
-
|
|
51388
|
+
if (!pathToObjectApiNamesMap[path]) {
|
|
51389
|
+
pathToObjectApiNamesMap[path] = [];
|
|
51200
51390
|
}
|
|
51201
|
-
if (!
|
|
51202
|
-
|
|
51391
|
+
if (!pathToObjectApiNamesMap[path].includes(ref.apiName)) {
|
|
51392
|
+
pathToObjectApiNamesMap[path].push(ref.apiName);
|
|
51203
51393
|
}
|
|
51204
51394
|
if (!apiNames.includes(ref.apiName)) {
|
|
51205
51395
|
apiNames.push(ref.apiName);
|
|
@@ -51210,11 +51400,11 @@
|
|
|
51210
51400
|
// handles 'childRelationship'
|
|
51211
51401
|
const childRelationship = parentObjectInfo.childRelationships.find((childRelationship) => childRelationship.relationshipName === field);
|
|
51212
51402
|
if (childRelationship) {
|
|
51213
|
-
if (!
|
|
51214
|
-
|
|
51403
|
+
if (!pathToObjectApiNamesMap[path]) {
|
|
51404
|
+
pathToObjectApiNamesMap[path] = [];
|
|
51215
51405
|
}
|
|
51216
|
-
if (!
|
|
51217
|
-
|
|
51406
|
+
if (!pathToObjectApiNamesMap[path].includes(childRelationship.childObjectApiName)) {
|
|
51407
|
+
pathToObjectApiNamesMap[path].push(childRelationship.childObjectApiName);
|
|
51218
51408
|
}
|
|
51219
51409
|
if (!apiNames.includes(childRelationship.childObjectApiName)) {
|
|
51220
51410
|
apiNames.push(childRelationship.childObjectApiName);
|
|
@@ -51236,10 +51426,10 @@
|
|
|
51236
51426
|
}
|
|
51237
51427
|
for (const nodeInfo of validObjectInfoNodes) {
|
|
51238
51428
|
const field = nodeInfo.name;
|
|
51239
|
-
const
|
|
51240
|
-
const
|
|
51429
|
+
const path = `${parentPath}#${field}`;
|
|
51430
|
+
const subLevelFields = objectInfotree[path];
|
|
51241
51431
|
if (subLevelFields && subLevelFields.length > 0) {
|
|
51242
|
-
const subObjectInfos = await fetchObjectInfos(objectInfotree,
|
|
51432
|
+
const subObjectInfos = await fetchObjectInfos(objectInfotree, pathToObjectApiNamesMap, updatedObjectInfoMap, subLevelFields, path, objectInfoService);
|
|
51243
51433
|
updatedObjectInfoMap = { ...updatedObjectInfoMap, ...subObjectInfos };
|
|
51244
51434
|
}
|
|
51245
51435
|
}
|
|
@@ -51254,27 +51444,29 @@
|
|
|
51254
51444
|
* 'path' and 'queryNode' is 1 level above the 'filterNode'
|
|
51255
51445
|
* @param filterNode filter node which needs to be injected. For example, 'State' ObjectFieldNode within filter 'where: { State: { eq: "Nova Scotia" }}'
|
|
51256
51446
|
* @param idState ID state will be updated to determine if the ID fields in AST need to be swapped. The swapping happens later.
|
|
51257
|
-
* @param
|
|
51447
|
+
* @param parentPath path to the current filterNode's parent. For example, path could be 'ServiceApointment' when filterNode is 'State'. If the path does not exist in 'pathToObjectApiNamesMap', parent node is not an field of relationship or recordQuery
|
|
51448
|
+
* @param isParentPolymorphic true if parent points to a polymorphic field.
|
|
51258
51449
|
* @param queryNode referece FieldNode which provides the information if 'filterNode' exist in it nor not.
|
|
51259
51450
|
* @param objectInfos ObjectInfo map used in injection. If ObjectInfo misses or field does not exist in ObjectInfo, the error will be thrown
|
|
51260
|
-
* @param
|
|
51451
|
+
* @param pathToObjectApiNamesMap map used to locate the ObjectInfo. The key is path to a field, value is the ObjectInfo's apiName array. In the case of polymorphic fields, the apiName array have 2 or more elements. For example, 'ServiceAppointment' -> ['ServiceAppointment']; 'ServiceAppointment_Account' -> ['Account'], 'ServiceAppointment_Owner' -> ['User', 'Group'].
|
|
51261
51452
|
* @param draftFunctions functions for working with record ids that may be draft-created ids
|
|
51262
51453
|
* @returns an array of nodes with injected fields
|
|
51263
51454
|
*/
|
|
51264
|
-
function injectFilter(filterNode, idState,
|
|
51455
|
+
function injectFilter(filterNode, idState, parentPath, isParentPolymorphic, objectInfos, pathToObjectApiNamesMap, draftFunctions, queryNode) {
|
|
51265
51456
|
const injectedSelections = [];
|
|
51457
|
+
let isPolymorphicField = false;
|
|
51266
51458
|
switch (filterNode.kind) {
|
|
51267
51459
|
case Kind.ARGUMENT:
|
|
51268
51460
|
if (filterNode.value.kind !== 'ObjectValue')
|
|
51269
51461
|
return [];
|
|
51270
51462
|
filterNode.value.fields.forEach((objectFieldNode) => {
|
|
51271
|
-
let subResults = injectFilter(objectFieldNode, idState,
|
|
51463
|
+
let subResults = injectFilter(objectFieldNode, idState, parentPath, isParentPolymorphic, objectInfos, pathToObjectApiNamesMap, draftFunctions, queryNode);
|
|
51272
51464
|
for (const subResult of subResults) {
|
|
51273
51465
|
mergeOrAddToGroup(injectedSelections, subResult);
|
|
51274
51466
|
}
|
|
51275
51467
|
// multiple Ids might need to be swapped. remember their paths for faster write.
|
|
51276
51468
|
if (idState.swapNeeded) {
|
|
51277
|
-
idState.paths.push(
|
|
51469
|
+
idState.paths.push(parentPath);
|
|
51278
51470
|
}
|
|
51279
51471
|
});
|
|
51280
51472
|
return injectedSelections;
|
|
@@ -51283,7 +51475,7 @@
|
|
|
51283
51475
|
case Kind.LIST: {
|
|
51284
51476
|
filterNode.value.values.filter(isObjectValueNode).forEach((objectValueNode) => {
|
|
51285
51477
|
objectValueNode.fields.forEach((objectFieldNode) => {
|
|
51286
|
-
const subResults = injectFilter(objectFieldNode, idState,
|
|
51478
|
+
const subResults = injectFilter(objectFieldNode, idState, parentPath, isParentPolymorphic, objectInfos, pathToObjectApiNamesMap, draftFunctions, queryNode);
|
|
51287
51479
|
for (const subResult of subResults) {
|
|
51288
51480
|
mergeOrAddToGroup(injectedSelections, subResult);
|
|
51289
51481
|
}
|
|
@@ -51294,7 +51486,7 @@
|
|
|
51294
51486
|
case Kind.OBJECT: {
|
|
51295
51487
|
if (filterNode.name.value === 'not') {
|
|
51296
51488
|
filterNode.value.fields.forEach((objectFieldNode) => {
|
|
51297
|
-
const subResults = injectFilter(objectFieldNode, idState,
|
|
51489
|
+
const subResults = injectFilter(objectFieldNode, idState, parentPath, isParentPolymorphic, objectInfos, pathToObjectApiNamesMap, draftFunctions, queryNode);
|
|
51298
51490
|
for (const subResult of subResults) {
|
|
51299
51491
|
mergeOrAddToGroup(injectedSelections, subResult);
|
|
51300
51492
|
}
|
|
@@ -51304,15 +51496,15 @@
|
|
|
51304
51496
|
let apiNames = [];
|
|
51305
51497
|
let isScalarField = false;
|
|
51306
51498
|
//It is possible that this is a polymorphic field
|
|
51307
|
-
apiNames =
|
|
51308
|
-
// example: path: '
|
|
51499
|
+
apiNames = pathToObjectApiNamesMap[parentPath];
|
|
51500
|
+
// example: path: 'ServiceAppointment#LastModifiedDate'; filterNode: '{eq: {literal: LAST_WEEK}}'. queryNode: 'LastModifedDate { value}' FilterNode's parent has been verifed as a valid node
|
|
51309
51501
|
if (apiNames === undefined) {
|
|
51310
51502
|
isScalarField = true;
|
|
51311
51503
|
}
|
|
51312
51504
|
else {
|
|
51313
51505
|
if (apiNames.some((apiName) => objectInfos[apiName] === undefined)) {
|
|
51314
51506
|
// eslint-disable-next-line
|
|
51315
|
-
throw new Error(`ObjectInfo is missing for ${
|
|
51507
|
+
throw new Error(`ObjectInfo is missing for ${parentPath}`);
|
|
51316
51508
|
}
|
|
51317
51509
|
}
|
|
51318
51510
|
if (isScalarField) {
|
|
@@ -51334,29 +51526,19 @@
|
|
|
51334
51526
|
}
|
|
51335
51527
|
});
|
|
51336
51528
|
let isSpanning = false;
|
|
51529
|
+
// if true, current node is a polymorphic concrete type node. For example, field node `User` under `Owner`
|
|
51337
51530
|
let isInlineFragment = false;
|
|
51338
|
-
let isPolymorphicField = false;
|
|
51339
51531
|
let isTypeNameExisting = false;
|
|
51340
51532
|
let curPath;
|
|
51341
51533
|
let fieldName = filterNode.name.value;
|
|
51342
|
-
curPath = `${
|
|
51343
|
-
if (
|
|
51534
|
+
curPath = `${parentPath}#${fieldName}`;
|
|
51535
|
+
if (pathToObjectApiNamesMap[curPath] &&
|
|
51536
|
+
pathToObjectApiNamesMap[curPath].length > 0) {
|
|
51344
51537
|
isSpanning = true;
|
|
51345
|
-
|
|
51346
|
-
|
|
51347
|
-
|
|
51348
|
-
|
|
51349
|
-
isInlineFragment = true;
|
|
51350
|
-
}
|
|
51351
|
-
}
|
|
51352
|
-
// Checks if the current filter node is a polymorphic field. 'ServiceAppointment_Owner' --> ['User']; 'ServiceAppointment_Owner_User' --> ['User']
|
|
51353
|
-
const childApiName = objectInfoApiMap[curPath][0];
|
|
51354
|
-
const trialApiNames = objectInfoApiMap[`${curPath}_${childApiName}`];
|
|
51355
|
-
if (trialApiNames !== undefined &&
|
|
51356
|
-
trialApiNames.length === 1 &&
|
|
51357
|
-
trialApiNames[0] === childApiName) {
|
|
51358
|
-
isPolymorphicField = true;
|
|
51359
|
-
}
|
|
51538
|
+
isInlineFragment =
|
|
51539
|
+
isParentPolymorphic &&
|
|
51540
|
+
pathToObjectApiNamesMap[curPath].length === 1;
|
|
51541
|
+
isPolymorphicField = isPolymorphicFieldPath(curPath, pathToObjectApiNamesMap, objectInfos);
|
|
51360
51542
|
}
|
|
51361
51543
|
// When filter node is at InLineFragment Level(a concrete entity of polymorphic field), query node is one level up. For example, ObjectFieldNode is ...{User:{...}}, queryNode is Owner:[User]
|
|
51362
51544
|
if (isInlineFragment) {
|
|
@@ -51400,23 +51582,25 @@
|
|
|
51400
51582
|
throw new Error(`Field ${fieldName} does not exist in ${apiNames[0]}`);
|
|
51401
51583
|
}
|
|
51402
51584
|
}
|
|
51403
|
-
const objectInfoName =
|
|
51404
|
-
?
|
|
51405
|
-
:
|
|
51585
|
+
const objectInfoName = pathToObjectApiNamesMap[curPath] !== undefined
|
|
51586
|
+
? pathToObjectApiNamesMap[curPath][0]
|
|
51587
|
+
: pathToObjectApiNamesMap[parentPath][0];
|
|
51406
51588
|
const isIdField = isFieldAnIdField(filterNode.name.value, objectInfos[objectInfoName]);
|
|
51407
51589
|
if (!isIdField) {
|
|
51408
51590
|
let subSelectionNodes = [];
|
|
51409
51591
|
let subFieldsHasId = false;
|
|
51410
|
-
|
|
51411
|
-
|
|
51412
|
-
|
|
51413
|
-
|
|
51414
|
-
|
|
51415
|
-
|
|
51416
|
-
|
|
51417
|
-
|
|
51418
|
-
|
|
51419
|
-
|
|
51592
|
+
if (isSpanning) {
|
|
51593
|
+
filterNode.value.fields.forEach((subFieldNode) => {
|
|
51594
|
+
// Check if the filter field has the 'Id'
|
|
51595
|
+
if (isFieldAnIdField(subFieldNode.name.value, objectInfos[objectInfoName])) {
|
|
51596
|
+
subFieldsHasId = true;
|
|
51597
|
+
updateIDInfo(subFieldNode, idState, draftFunctions);
|
|
51598
|
+
}
|
|
51599
|
+
// try injecting the fields within predicate no matter it has relation or not.
|
|
51600
|
+
let subResults = injectFilter(subFieldNode, idState, curPath, isPolymorphicField, objectInfos, pathToObjectApiNamesMap, draftFunctions, existingFields ? existingFields[0] : undefined);
|
|
51601
|
+
subSelectionNodes = subSelectionNodes.concat(subResults);
|
|
51602
|
+
});
|
|
51603
|
+
}
|
|
51420
51604
|
if (!subFieldsHasId) {
|
|
51421
51605
|
// Check if the query field has the 'Id'
|
|
51422
51606
|
const existingIdsInQuery = existingFields &&
|
|
@@ -51445,6 +51629,7 @@
|
|
|
51445
51629
|
}
|
|
51446
51630
|
//Inject Conditions: 1. Same field does not exist 2. Same fields has different children. 3. Filter spanning field does not have Id. 4. InLineFragment does not have the '__typename' field
|
|
51447
51631
|
if (!existingFields ||
|
|
51632
|
+
existingFields.length === 0 ||
|
|
51448
51633
|
subSelectionNodes.length > 0 ||
|
|
51449
51634
|
(isSpanning && !subFieldsHasId) ||
|
|
51450
51635
|
(isInlineFragment && !isTypeNameExisting)) {
|
|
@@ -51575,6 +51760,44 @@
|
|
|
51575
51760
|
}
|
|
51576
51761
|
group.push(element);
|
|
51577
51762
|
}
|
|
51763
|
+
// checks if the path points to a polymorphic field. For example, for the below `pathToObjectApiNamesMap`
|
|
51764
|
+
// {
|
|
51765
|
+
// 'ServiceAppointment' -> ['ServiceAppointment']
|
|
51766
|
+
// 'ServiceAppointment#Owner' --> ['User'],
|
|
51767
|
+
// 'ServiceAppointment#Owner#User' --> ['User']
|
|
51768
|
+
// }
|
|
51769
|
+
// path `ServiceAppointment#Owner` points to a polymorphic field, but path `ServiceAppointment#Owner#User` does not.
|
|
51770
|
+
function isPolymorphicFieldPath(path, pathToObjectApiNamesMap, objectInfos) {
|
|
51771
|
+
const lastSegmentIndex = path.lastIndexOf('#');
|
|
51772
|
+
if (lastSegmentIndex < 0) {
|
|
51773
|
+
return false;
|
|
51774
|
+
}
|
|
51775
|
+
const lastSegment = path.slice(lastSegmentIndex + 1);
|
|
51776
|
+
const parentApiPath = path.slice(0, lastSegmentIndex);
|
|
51777
|
+
if (pathToObjectApiNamesMap[parentApiPath] === undefined) {
|
|
51778
|
+
return false;
|
|
51779
|
+
}
|
|
51780
|
+
const parentObjectApiNames = pathToObjectApiNamesMap[parentApiPath];
|
|
51781
|
+
// If the last segment is a Polymorphic field, its immediate parent is a concrete object entity, which has 1 objectApiName mapped to the parent path in `pathToObjectApiNamesMap`.
|
|
51782
|
+
// For example, we like to check if `ServiceAppointment#Owner` path is polymorphic. The last segment is `Owner` and its parent `ServiceAppointment` has one element (which is also `ServiceAppointment`) array as its value.
|
|
51783
|
+
// Below are the entries in `pathToObjectApiNamesMap`
|
|
51784
|
+
// {
|
|
51785
|
+
// `ServiceAppointmen`t: [`ServiceAppointment`],
|
|
51786
|
+
// `ServiceAppointment#Owner`: [`User`, `Group`],
|
|
51787
|
+
// `ServiceAppointment#Owner#User`: [`User`],
|
|
51788
|
+
// `ServiceAppointment#Owner#Group`: [`Group`],
|
|
51789
|
+
// }
|
|
51790
|
+
if (parentObjectApiNames.length !== 1) {
|
|
51791
|
+
return false;
|
|
51792
|
+
}
|
|
51793
|
+
const parentObjectInfo = objectInfos[parentObjectApiNames[0]];
|
|
51794
|
+
const relationshipField = referenceIdFieldForRelationship(lastSegment);
|
|
51795
|
+
let fieldDefinition = parentObjectInfo.fields[relationshipField];
|
|
51796
|
+
if (fieldDefinition === undefined) {
|
|
51797
|
+
return false;
|
|
51798
|
+
}
|
|
51799
|
+
return fieldDefinition.polymorphicForeignKey;
|
|
51800
|
+
}
|
|
51578
51801
|
function isFieldAnIdField(fieldName, objectInfo) {
|
|
51579
51802
|
if (fieldName === 'Id')
|
|
51580
51803
|
return true;
|
|
@@ -51627,10 +51850,10 @@
|
|
|
51627
51850
|
* @param parentNode parent node of param 1
|
|
51628
51851
|
* @param ancestors ancester of param 1
|
|
51629
51852
|
* @param objectInfos ObjectInfo map used in injection. If ObjectInfo misses or field does not exist in ObjectInfo, the error will be thrown
|
|
51630
|
-
* @param
|
|
51853
|
+
* @param pathToObjectApiNamesMap map used to locate the ObjectInfo. The key is path to a field, value is the ObjectInfo's apiName array. In the case of polymorphic fields, the apiName array have 2 or more elements. For example, 'ServiceAppointment' -> ['ServiceAppointment']; 'ServiceAppointment#Account' -> ['Account'], 'ServiceAppointment#Owner' -> ['User', 'Group'].
|
|
51631
51854
|
* @return injected SelectionNodes used to construct the InlineFragment.
|
|
51632
51855
|
*/
|
|
51633
|
-
function injectFields(selections, parentNode, ancestors, objectInfos,
|
|
51856
|
+
function injectFields(selections, parentNode, parentPath, ancestors, objectInfos, pathToObjectApiNamesMap) {
|
|
51634
51857
|
/**
|
|
51635
51858
|
* 1 parentship can return 2 FieldNode which need to be flattened
|
|
51636
51859
|
* Concact: { ** Contact { ** ContactId {
|
|
@@ -51648,6 +51871,10 @@
|
|
|
51648
51871
|
if (!selection.selectionSet) {
|
|
51649
51872
|
return selection;
|
|
51650
51873
|
}
|
|
51874
|
+
const segment = isFieldNode(selection)
|
|
51875
|
+
? selection.name.value
|
|
51876
|
+
: selection.typeCondition.name.value;
|
|
51877
|
+
const curPath = `${parentPath}#${segment}`;
|
|
51651
51878
|
const spanningSubSelections = [];
|
|
51652
51879
|
for (const subSelection of selection.selectionSet.selections) {
|
|
51653
51880
|
if (isFieldSpanning(subSelection, selection)) {
|
|
@@ -51655,7 +51882,7 @@
|
|
|
51655
51882
|
}
|
|
51656
51883
|
}
|
|
51657
51884
|
// Handles multiple level field injection like 'ServiceAppointment' --> 'Account' --> 'Owner'
|
|
51658
|
-
const subInjectedSelections = injectFields(spanningSubSelections, selection, ancestors, objectInfos,
|
|
51885
|
+
const subInjectedSelections = injectFields(spanningSubSelections, selection, curPath, ancestors, objectInfos, pathToObjectApiNamesMap);
|
|
51659
51886
|
if (!selection.selectionSet) {
|
|
51660
51887
|
return selection;
|
|
51661
51888
|
}
|
|
@@ -51698,7 +51925,7 @@
|
|
|
51698
51925
|
}
|
|
51699
51926
|
}
|
|
51700
51927
|
// For polymorphic fields, the Id field is excluded.
|
|
51701
|
-
const excludeId =
|
|
51928
|
+
const excludeId = isPolymorphicFieldPath(curPath, pathToObjectApiNamesMap, objectInfos);
|
|
51702
51929
|
const idSelection = [];
|
|
51703
51930
|
if (!excludeId && !hasIdAlready) {
|
|
51704
51931
|
idSelection.push({
|
|
@@ -51709,8 +51936,8 @@
|
|
|
51709
51936
|
},
|
|
51710
51937
|
});
|
|
51711
51938
|
}
|
|
51712
|
-
// Inject '__typename' for
|
|
51713
|
-
// please reference 'removeSyntheticFields'.
|
|
51939
|
+
// Inject '__typename' for InlineFragment. '__typename' field acts as a reference to concrete type of a polymorphic field or a standard field in the returned GQL response, which equals to
|
|
51940
|
+
// `typedCondition` of the InlineFragment in the query AST. It is used to match JSON response with AST node. For more detail, please reference 'removeSyntheticFields'.
|
|
51714
51941
|
if (isInlineFragmentNode(selection) &&
|
|
51715
51942
|
!selection.selectionSet.selections.find((selection) => isFieldNode(selection) && selection.name.value === '__typename')) {
|
|
51716
51943
|
idSelection.push({
|
|
@@ -51744,7 +51971,7 @@
|
|
|
51744
51971
|
if (isFieldNode(parentNode) && parentNode.selectionSet && parentNode.name.value === 'node') {
|
|
51745
51972
|
if (parentNode.selectionSet.selections
|
|
51746
51973
|
.filter(isFieldOrInlineFragmentNode)
|
|
51747
|
-
.some((selectionNode) => isRelationship(selectionNode,
|
|
51974
|
+
.some((selectionNode) => isRelationship(selectionNode, CHILD_RELATIONSHIP))) {
|
|
51748
51975
|
if (!parentNode.selectionSet.selections
|
|
51749
51976
|
.filter(isFieldNode)
|
|
51750
51977
|
.some((sibling) => sibling.name.value === 'Id')) {
|
|
@@ -51763,15 +51990,15 @@
|
|
|
51763
51990
|
if (parentInfo.parentIndex >= 0) {
|
|
51764
51991
|
// example node { TimeSheetEntries { edges { node { Id }}}}
|
|
51765
51992
|
const parent = parentInfo.node;
|
|
51766
|
-
if (isRelationship(parent,
|
|
51993
|
+
if (isRelationship(parent, CHILD_RELATIONSHIP)) {
|
|
51767
51994
|
const unVisitedAncestors = ancestors.slice(0, parentInfo.parentIndex);
|
|
51768
51995
|
// path : "TimeSheet"
|
|
51769
51996
|
const grandParentPath = findAncesterPath(unVisitedAncestors);
|
|
51770
|
-
if (
|
|
51771
|
-
|
|
51997
|
+
if (pathToObjectApiNamesMap &&
|
|
51998
|
+
pathToObjectApiNamesMap[grandParentPath] &&
|
|
51772
51999
|
objectInfos &&
|
|
51773
|
-
objectInfos[
|
|
51774
|
-
const grandParentObjectInfo = objectInfos[
|
|
52000
|
+
objectInfos[pathToObjectApiNamesMap[grandParentPath][0]]) {
|
|
52001
|
+
const grandParentObjectInfo = objectInfos[pathToObjectApiNamesMap[grandParentPath][0]];
|
|
51775
52002
|
// exmaple "TimeSheetEntries"
|
|
51776
52003
|
const parentFieldName = parent.name.value;
|
|
51777
52004
|
const targetRelationship = grandParentObjectInfo.childRelationships.find((childRelationship) => {
|
|
@@ -51892,7 +52119,7 @@
|
|
|
51892
52119
|
},
|
|
51893
52120
|
value: {
|
|
51894
52121
|
kind: 'StringValue',
|
|
51895
|
-
value:
|
|
52122
|
+
value: CHILD_RELATIONSHIP,
|
|
51896
52123
|
block: false,
|
|
51897
52124
|
},
|
|
51898
52125
|
},
|
|
@@ -51984,7 +52211,7 @@
|
|
|
51984
52211
|
},
|
|
51985
52212
|
value: {
|
|
51986
52213
|
kind: 'StringValue',
|
|
51987
|
-
value:
|
|
52214
|
+
value: PARENT_RELATIONSHIP,
|
|
51988
52215
|
block: false,
|
|
51989
52216
|
},
|
|
51990
52217
|
},
|
|
@@ -52121,7 +52348,9 @@
|
|
|
52121
52348
|
jsonOutput[fieldName] = null;
|
|
52122
52349
|
return;
|
|
52123
52350
|
}
|
|
52124
|
-
jsonOutput[fieldName]
|
|
52351
|
+
if (jsonOutput[fieldName] === undefined) {
|
|
52352
|
+
jsonOutput[fieldName] = {};
|
|
52353
|
+
}
|
|
52125
52354
|
createUserJsonOutput(selection, jsonInput[fieldName], jsonOutput[fieldName]);
|
|
52126
52355
|
}
|
|
52127
52356
|
else {
|
|
@@ -52853,34 +53082,42 @@
|
|
|
52853
53082
|
}
|
|
52854
53083
|
const { dataType, relationshipName, referenceToInfos } = fieldInfo;
|
|
52855
53084
|
const draftFieldValue = record.fields[draftField].value;
|
|
52856
|
-
if (dataType === 'Reference' && relationshipName !== null
|
|
52857
|
-
if (
|
|
52858
|
-
|
|
53085
|
+
if (dataType === 'Reference' && relationshipName !== null) {
|
|
53086
|
+
if (draftFieldValue === null) {
|
|
53087
|
+
recordFields[relationshipName] = {
|
|
53088
|
+
displayValue: null,
|
|
53089
|
+
value: null,
|
|
53090
|
+
};
|
|
52859
53091
|
}
|
|
52860
|
-
|
|
52861
|
-
|
|
52862
|
-
|
|
52863
|
-
displayValue: null,
|
|
52864
|
-
value: createLink$2(key),
|
|
52865
|
-
};
|
|
52866
|
-
// for custom objects, we select the 'Name' field
|
|
52867
|
-
// otherwise we check the object info for name fields.
|
|
52868
|
-
//if there are multiple we select 'Name' if it exists, otherwise the first one
|
|
52869
|
-
if (referencedRecord !== undefined && referenceToInfos.length > 0) {
|
|
52870
|
-
let nameField;
|
|
52871
|
-
const referenceToInfo = referenceToInfos[0];
|
|
52872
|
-
const nameFields = referenceToInfo.nameFields;
|
|
52873
|
-
if (nameFields.length !== 0) {
|
|
52874
|
-
nameField = nameFields.find((x) => x === 'Name');
|
|
52875
|
-
if (nameField === undefined) {
|
|
52876
|
-
nameField = nameFields[0];
|
|
52877
|
-
}
|
|
53092
|
+
else {
|
|
53093
|
+
if (typeof draftFieldValue !== 'string') {
|
|
53094
|
+
throw Error('reference field value is not a string');
|
|
52878
53095
|
}
|
|
52879
|
-
|
|
52880
|
-
|
|
52881
|
-
|
|
52882
|
-
|
|
52883
|
-
|
|
53096
|
+
const key = getRecordKeyForId(luvio, draftFieldValue);
|
|
53097
|
+
const referencedRecord = referencedRecords.get(key);
|
|
53098
|
+
recordFields[relationshipName] = {
|
|
53099
|
+
displayValue: null,
|
|
53100
|
+
value: createLink$2(key),
|
|
53101
|
+
};
|
|
53102
|
+
// for custom objects, we select the 'Name' field
|
|
53103
|
+
// otherwise we check the object info for name fields.
|
|
53104
|
+
//if there are multiple we select 'Name' if it exists, otherwise the first one
|
|
53105
|
+
if (referencedRecord !== undefined && referenceToInfos.length > 0) {
|
|
53106
|
+
let nameField;
|
|
53107
|
+
const referenceToInfo = referenceToInfos[0];
|
|
53108
|
+
const nameFields = referenceToInfo.nameFields;
|
|
53109
|
+
if (nameFields.length !== 0) {
|
|
53110
|
+
nameField = nameFields.find((x) => x === 'Name');
|
|
53111
|
+
if (nameField === undefined) {
|
|
53112
|
+
nameField = nameFields[0];
|
|
53113
|
+
}
|
|
53114
|
+
}
|
|
53115
|
+
if (nameField !== undefined) {
|
|
53116
|
+
const nameFieldRef = referencedRecord.fields[nameField];
|
|
53117
|
+
if (nameFieldRef) {
|
|
53118
|
+
recordFields[relationshipName].displayValue =
|
|
53119
|
+
(_a = nameFieldRef.displayValue) !== null && _a !== void 0 ? _a : nameFieldRef.value;
|
|
53120
|
+
}
|
|
52884
53121
|
}
|
|
52885
53122
|
}
|
|
52886
53123
|
}
|
|
@@ -53173,17 +53410,8 @@
|
|
|
53173
53410
|
};
|
|
53174
53411
|
for (const fieldName of keys$3(recordWithSpanningRefLinks.fields)) {
|
|
53175
53412
|
const fieldKey = buildRecordFieldStoreKey(key, fieldName);
|
|
53176
|
-
|
|
53177
|
-
|
|
53178
|
-
normalizedRecord.fields[fieldName] = { __ref: fieldKey };
|
|
53179
|
-
publishData(fieldKey, fieldData);
|
|
53180
|
-
}
|
|
53181
|
-
else if (recordWithSpanningRefLinks.fields[fieldName] &&
|
|
53182
|
-
recordWithSpanningRefLinks.fields[fieldName].value &&
|
|
53183
|
-
recordWithSpanningRefLinks.fields[fieldName].value.__ref !== undefined) {
|
|
53184
|
-
normalizedRecord.fields[fieldName] = { __ref: fieldKey };
|
|
53185
|
-
publishData(fieldKey, recordWithSpanningRefLinks.fields[fieldName]);
|
|
53186
|
-
}
|
|
53413
|
+
normalizedRecord.fields[fieldName] = { __ref: fieldKey };
|
|
53414
|
+
publishData(fieldKey, recordWithSpanningRefLinks.fields[fieldName]);
|
|
53187
53415
|
}
|
|
53188
53416
|
// publish the normalized record
|
|
53189
53417
|
publishData(key, normalizedRecord);
|
|
@@ -54103,7 +54331,7 @@
|
|
|
54103
54331
|
// Fulfilled snapshot (this only happens in this code path if
|
|
54104
54332
|
// the error is network error or 504), otherwise we spread over
|
|
54105
54333
|
// the non-eval'ed snapshot (which will be either Fulfilled or Stale)
|
|
54106
|
-
|
|
54334
|
+
const resultSnapshot = nonEvaluatedSnapshot.state === 'Error'
|
|
54107
54335
|
? createLocalEvalSnapshot(gqlResult, seenRecords, recordId, rebuildWithLocalEval)
|
|
54108
54336
|
: {
|
|
54109
54337
|
...nonEvaluatedSnapshot,
|
|
@@ -54112,6 +54340,22 @@
|
|
|
54112
54340
|
seenRecords,
|
|
54113
54341
|
rebuildWithLocalEval,
|
|
54114
54342
|
};
|
|
54343
|
+
const { refresh, state } = resultSnapshot;
|
|
54344
|
+
if (state !== 'Error' && refresh) {
|
|
54345
|
+
// after refreshing a graphql snapshot, we want to force a rebuild regardless
|
|
54346
|
+
// of if the call failed or not or if the data changed or not because we want
|
|
54347
|
+
// to make sure any potential new drafts are picked up
|
|
54348
|
+
resultSnapshot.refresh = {
|
|
54349
|
+
...refresh,
|
|
54350
|
+
resolve: (config) => {
|
|
54351
|
+
return refresh.resolve(config).finally(() => {
|
|
54352
|
+
luvio.storePublish(resultSnapshot.recordId, undefined);
|
|
54353
|
+
luvio.storeBroadcast();
|
|
54354
|
+
});
|
|
54355
|
+
},
|
|
54356
|
+
};
|
|
54357
|
+
}
|
|
54358
|
+
return resultSnapshot;
|
|
54115
54359
|
};
|
|
54116
54360
|
}
|
|
54117
54361
|
|
|
@@ -55165,7 +55409,10 @@
|
|
|
55165
55409
|
* @returns the merged record
|
|
55166
55410
|
*/
|
|
55167
55411
|
function mergeAggregateUiResponse(response, mergeFunc) {
|
|
55168
|
-
|
|
55412
|
+
if (response.ok === false) {
|
|
55413
|
+
return response;
|
|
55414
|
+
}
|
|
55415
|
+
const body = response.body;
|
|
55169
55416
|
try {
|
|
55170
55417
|
if (body === null ||
|
|
55171
55418
|
body === undefined ||
|
|
@@ -56996,6 +57243,9 @@
|
|
|
56996
57243
|
this.ldsRecordRefresher = config.ldsRecordRefresher;
|
|
56997
57244
|
this.networkWorkerPool = new AsyncWorkerPool(this.concurrency);
|
|
56998
57245
|
this.useBatchGQL = ldsPrimingGraphqlBatch.isOpen({ fallback: false });
|
|
57246
|
+
if (this.useBatchGQL) {
|
|
57247
|
+
this.batchSize = this.batchSize / DEFAULT_GQL_QUERY_BATCH_SIZE;
|
|
57248
|
+
}
|
|
56999
57249
|
this.conflictPool = new ConflictPool(config.store, this.objectInfoLoader);
|
|
57000
57250
|
}
|
|
57001
57251
|
// function that enqueues priming work
|
|
@@ -57852,7 +58102,7 @@
|
|
|
57852
58102
|
id: '@salesforce/lds-network-adapter',
|
|
57853
58103
|
instrument: instrument$1,
|
|
57854
58104
|
});
|
|
57855
|
-
// version: 1.229.0-
|
|
58105
|
+
// version: 1.229.0-dev10-bc9ef2513
|
|
57856
58106
|
|
|
57857
58107
|
const { create: create$2, keys: keys$2 } = Object;
|
|
57858
58108
|
const { stringify: stringify$1, parse: parse$1 } = JSON;
|
|
@@ -71176,7 +71426,7 @@
|
|
|
71176
71426
|
}
|
|
71177
71427
|
}
|
|
71178
71428
|
|
|
71179
|
-
const { assign, create: create$1, freeze: freeze$1, keys: keys$1 } = Object;
|
|
71429
|
+
const { assign, create: create$1, freeze: freeze$1, isFrozen, keys: keys$1 } = Object;
|
|
71180
71430
|
const { isArray: isArray$1 } = Array;
|
|
71181
71431
|
const { concat, filter, includes, push, reduce } = Array.prototype;
|
|
71182
71432
|
|
|
@@ -72615,6 +72865,7 @@
|
|
|
72615
72865
|
}
|
|
72616
72866
|
if (fieldData === null) {
|
|
72617
72867
|
reader.assignScalar(requestedFieldName, sink, fieldData);
|
|
72868
|
+
reader.exitPath();
|
|
72618
72869
|
return sink;
|
|
72619
72870
|
}
|
|
72620
72871
|
const fieldType = getFieldType(sel);
|
|
@@ -72640,17 +72891,8 @@
|
|
|
72640
72891
|
return sink;
|
|
72641
72892
|
}
|
|
72642
72893
|
function selectTypeLink(sel, fieldData, reader, key, sink, variables, fragments, version, selectFn, isCursorConnection) {
|
|
72643
|
-
const resolvedLink = reader
|
|
72644
|
-
|
|
72645
|
-
node: {
|
|
72646
|
-
kind: 'Fragment',
|
|
72647
|
-
private: [],
|
|
72648
|
-
opaque: true,
|
|
72649
|
-
version,
|
|
72650
|
-
},
|
|
72651
|
-
variables: {}
|
|
72652
|
-
});
|
|
72653
|
-
if (resolvedLink.data !== undefined) {
|
|
72894
|
+
const resolvedLink = resolveLink$1(reader, fieldData, version);
|
|
72895
|
+
if (resolvedLink && resolvedLink.data !== undefined) {
|
|
72654
72896
|
if (isCursorConnection) {
|
|
72655
72897
|
selectTypeLinkWithPagination(resolvedLink, sel, fieldData, reader, key, sink, variables, fragments, selectFn);
|
|
72656
72898
|
}
|
|
@@ -73226,19 +73468,11 @@
|
|
|
73226
73468
|
}
|
|
73227
73469
|
case 'PolymorphicParentRelationship':
|
|
73228
73470
|
case 'RecordRepresentation': {
|
|
73229
|
-
const spanningFieldLink = reader
|
|
73230
|
-
|
|
73231
|
-
|
|
73232
|
-
kind: 'Fragment',
|
|
73233
|
-
private: [],
|
|
73234
|
-
opaque: true,
|
|
73235
|
-
version: VERSION$f,
|
|
73236
|
-
},
|
|
73237
|
-
variables: {},
|
|
73238
|
-
});
|
|
73239
|
-
reader.markSeenId(fieldData.__ref);
|
|
73240
|
-
const resolvedSpanningFieldValue = spanningFieldLink.data;
|
|
73471
|
+
const spanningFieldLink = resolveLink$1(reader, fieldData, VERSION$f);
|
|
73472
|
+
const resolvedSpanningFieldValue = spanningFieldLink && spanningFieldLink.data;
|
|
73473
|
+
const fieldDataRef = fieldData.__ref;
|
|
73241
73474
|
if (resolvedSpanningFieldValue !== undefined) {
|
|
73475
|
+
reader.markSeenId(fieldDataRef);
|
|
73242
73476
|
const { value: spanningFieldResult } = resolvedSpanningFieldValue;
|
|
73243
73477
|
// Handle null values - graphql will return it at the field level, not return nested { value: null }
|
|
73244
73478
|
if (spanningFieldResult === null || typeof spanningFieldResult !== 'object') {
|
|
@@ -73262,7 +73496,9 @@
|
|
|
73262
73496
|
}
|
|
73263
73497
|
}
|
|
73264
73498
|
else {
|
|
73265
|
-
|
|
73499
|
+
if (fieldDataRef !== undefined) {
|
|
73500
|
+
reader.markMissingLink(fieldDataRef);
|
|
73501
|
+
}
|
|
73266
73502
|
reader.markMissing();
|
|
73267
73503
|
}
|
|
73268
73504
|
break;
|
|
@@ -76298,7 +76534,7 @@
|
|
|
76298
76534
|
configuration: { ...configurationForGraphQLAdapters },
|
|
76299
76535
|
instrument,
|
|
76300
76536
|
});
|
|
76301
|
-
// version: 1.229.0-
|
|
76537
|
+
// version: 1.229.0-dev10-abb060196
|
|
76302
76538
|
|
|
76303
76539
|
// On core the unstable adapters are re-exported with different names,
|
|
76304
76540
|
|
|
@@ -78545,7 +78781,7 @@
|
|
|
78545
78781
|
unstable_graphQL_imperative = createImperativeAdapter(luvio, createInstrumentedAdapter(ldsAdapter, adapterMetadata), adapterMetadata);
|
|
78546
78782
|
graphQLImperative = ldsAdapter;
|
|
78547
78783
|
});
|
|
78548
|
-
// version: 1.229.0-
|
|
78784
|
+
// version: 1.229.0-dev10-abb060196
|
|
78549
78785
|
|
|
78550
78786
|
var gqlApi = /*#__PURE__*/Object.freeze({
|
|
78551
78787
|
__proto__: null,
|
|
@@ -79276,4 +79512,4 @@
|
|
|
79276
79512
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
79277
79513
|
|
|
79278
79514
|
}));
|
|
79279
|
-
// version: 1.229.0-
|
|
79515
|
+
// version: 1.229.0-dev10-bc9ef2513
|