@salesforce/lds-runtime-mobile 1.229.0-dev2 → 1.229.0-dev4
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/main.js +222 -148
- package/package.json +18 -18
- package/sfdc/main.js +222 -148
package/dist/main.js
CHANGED
|
@@ -552,6 +552,9 @@ function handleDurableStoreRejection(instrument) {
|
|
|
552
552
|
}
|
|
553
553
|
|
|
554
554
|
function isStoreEntryError(storeRecord) {
|
|
555
|
+
if (!storeRecord || typeof storeRecord !== 'object') {
|
|
556
|
+
return false;
|
|
557
|
+
}
|
|
555
558
|
return storeRecord.__type === 'error';
|
|
556
559
|
}
|
|
557
560
|
|
|
@@ -8057,6 +8060,10 @@ function isOperationDefinitionNode(node) {
|
|
|
8057
8060
|
return node.kind === 'OperationDefinition';
|
|
8058
8061
|
}
|
|
8059
8062
|
|
|
8063
|
+
const POLYMORPHIC_PARENT_RELATIONSHIP = 'polymorphicParentRelationship';
|
|
8064
|
+
const PARENT_RELATIONSHIP = 'parentRelationship';
|
|
8065
|
+
const CHILD_RELATIONSHIP = 'childRelationship';
|
|
8066
|
+
const RECORD_QUERY = 'recordQuery';
|
|
8060
8067
|
function requestsDraftsField(recordFieldNode) {
|
|
8061
8068
|
if (!recordFieldNode.selectionSet)
|
|
8062
8069
|
return false;
|
|
@@ -8072,18 +8079,41 @@ function isRecordQuery(recordQueryField) {
|
|
|
8072
8079
|
directive.arguments
|
|
8073
8080
|
.map((argument) => argument.value)
|
|
8074
8081
|
.filter(isStringValueNode)
|
|
8075
|
-
.some((categoryName) => categoryName.value ===
|
|
8082
|
+
.some((categoryName) => categoryName.value === RECORD_QUERY));
|
|
8076
8083
|
});
|
|
8077
8084
|
}
|
|
8078
8085
|
return false;
|
|
8079
8086
|
}
|
|
8080
|
-
// finds field with 'recordQuery' and 'childRelationship' directive
|
|
8081
|
-
function
|
|
8082
|
-
const
|
|
8083
|
-
return
|
|
8087
|
+
// finds connection field with 'recordQuery' and 'childRelationship' directive.
|
|
8088
|
+
function findNearestConnection(ancestors) {
|
|
8089
|
+
const connectionAncestor = findNearestAncesterPath(ancestors, true).node;
|
|
8090
|
+
return connectionAncestor === undefined ? undefined : connectionAncestor;
|
|
8091
|
+
}
|
|
8092
|
+
// convinient method to find nearest connection with its path
|
|
8093
|
+
function findNearestConnectionWithPath(ancestors) {
|
|
8094
|
+
const closestAncestorPath = findNearestAncesterPath(ancestors, true);
|
|
8095
|
+
let connection = undefined;
|
|
8096
|
+
let connectionPath = undefined;
|
|
8097
|
+
if (closestAncestorPath.parentIndex > 0) {
|
|
8098
|
+
const connectionAncestor = closestAncestorPath.node;
|
|
8099
|
+
const connectionAncestors = ancestors.slice(0, closestAncestorPath.parentIndex);
|
|
8100
|
+
connection =
|
|
8101
|
+
connectionAncestor === undefined ? undefined : connectionAncestor;
|
|
8102
|
+
if (connection !== undefined) {
|
|
8103
|
+
const ancesterPath = findAncesterPath(connectionAncestors);
|
|
8104
|
+
connectionPath =
|
|
8105
|
+
ancesterPath === ''
|
|
8106
|
+
? connection.name.value
|
|
8107
|
+
: `${ancesterPath}#${connection.name.value}`;
|
|
8108
|
+
}
|
|
8109
|
+
}
|
|
8110
|
+
return {
|
|
8111
|
+
connection,
|
|
8112
|
+
path: connectionPath,
|
|
8113
|
+
};
|
|
8084
8114
|
}
|
|
8085
|
-
// finds
|
|
8086
|
-
function findNearestAncesterPath(ancestors,
|
|
8115
|
+
// 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.
|
|
8116
|
+
function findNearestAncesterPath(ancestors, connectionOnly) {
|
|
8087
8117
|
let recordQueryPath = { node: undefined, parentIndex: -1 };
|
|
8088
8118
|
let relationship = '';
|
|
8089
8119
|
for (let i = ancestors.length - 1; i >= 0; i--) {
|
|
@@ -8097,9 +8127,11 @@ function findNearestAncesterPath(ancestors, recordQueryOnly) {
|
|
|
8097
8127
|
continue;
|
|
8098
8128
|
for (let arg of directive.arguments) {
|
|
8099
8129
|
if (arg.value &&
|
|
8100
|
-
(arg.value.value ===
|
|
8101
|
-
arg.value.value ===
|
|
8102
|
-
(!
|
|
8130
|
+
(arg.value.value === RECORD_QUERY ||
|
|
8131
|
+
arg.value.value === CHILD_RELATIONSHIP ||
|
|
8132
|
+
(!connectionOnly &&
|
|
8133
|
+
(arg.value.value === PARENT_RELATIONSHIP ||
|
|
8134
|
+
arg.value.value === POLYMORPHIC_PARENT_RELATIONSHIP)))) {
|
|
8103
8135
|
recordQueryPath = { node: node, parentIndex: i };
|
|
8104
8136
|
relationship = arg.value.value;
|
|
8105
8137
|
break;
|
|
@@ -8114,17 +8146,19 @@ function findNearestAncesterPath(ancestors, recordQueryOnly) {
|
|
|
8114
8146
|
//checks if nearest ancester could be an inline fragment
|
|
8115
8147
|
if (recordQueryPath.node !== undefined &&
|
|
8116
8148
|
recordQueryPath.node.selectionSet &&
|
|
8117
|
-
relationship ===
|
|
8118
|
-
//
|
|
8119
|
-
|
|
8120
|
-
|
|
8121
|
-
|
|
8122
|
-
if (
|
|
8149
|
+
(relationship === PARENT_RELATIONSHIP || relationship === POLYMORPHIC_PARENT_RELATIONSHIP)) {
|
|
8150
|
+
// InlineFragment is usually 3 steps aways from its FieldNode parent within ancester hierarchy if it exists. The below search
|
|
8151
|
+
// is applied to adapt to future AST structure change
|
|
8152
|
+
let parentIndex = recordQueryPath.parentIndex + 1;
|
|
8153
|
+
while (parentIndex < ancestors.length) {
|
|
8154
|
+
if (isInlineFragmentNode(ancestors[parentIndex])) {
|
|
8123
8155
|
recordQueryPath = {
|
|
8124
|
-
node: ancestors[
|
|
8125
|
-
parentIndex
|
|
8156
|
+
node: ancestors[parentIndex],
|
|
8157
|
+
parentIndex,
|
|
8126
8158
|
};
|
|
8159
|
+
break;
|
|
8127
8160
|
}
|
|
8161
|
+
parentIndex++;
|
|
8128
8162
|
}
|
|
8129
8163
|
}
|
|
8130
8164
|
return recordQueryPath;
|
|
@@ -8148,7 +8182,7 @@ function findAncesterPath(ancesters) {
|
|
|
8148
8182
|
? sectionPath
|
|
8149
8183
|
: sectionPath === ''
|
|
8150
8184
|
? path
|
|
8151
|
-
: `${sectionPath}
|
|
8185
|
+
: `${sectionPath}#${path}`;
|
|
8152
8186
|
}
|
|
8153
8187
|
}
|
|
8154
8188
|
boundaryIndex = parentIndex;
|
|
@@ -8206,9 +8240,9 @@ function getRelation(node) {
|
|
|
8206
8240
|
const relationships = args
|
|
8207
8241
|
.map((arg) => arg.value)
|
|
8208
8242
|
.filter(isStringValueNode)
|
|
8209
|
-
.filter((valueNode) => valueNode.value ===
|
|
8210
|
-
valueNode.value ===
|
|
8211
|
-
valueNode.value ===
|
|
8243
|
+
.filter((valueNode) => valueNode.value === CHILD_RELATIONSHIP ||
|
|
8244
|
+
valueNode.value === PARENT_RELATIONSHIP ||
|
|
8245
|
+
valueNode.value === POLYMORPHIC_PARENT_RELATIONSHIP)
|
|
8212
8246
|
.map((relationshipNode) => relationshipNode.value);
|
|
8213
8247
|
if (relationships.length > 0) {
|
|
8214
8248
|
return relationships[0];
|
|
@@ -8265,8 +8299,8 @@ function isFieldSpanning(node, parentNode) {
|
|
|
8265
8299
|
*/
|
|
8266
8300
|
function isParentRelationship(node) {
|
|
8267
8301
|
return (node &&
|
|
8268
|
-
(isRelationship(node,
|
|
8269
|
-
isRelationship(node,
|
|
8302
|
+
(isRelationship(node, PARENT_RELATIONSHIP) ||
|
|
8303
|
+
isRelationship(node, POLYMORPHIC_PARENT_RELATIONSHIP)));
|
|
8270
8304
|
}
|
|
8271
8305
|
/*
|
|
8272
8306
|
checks if the InlineFragment spans
|
|
@@ -9358,7 +9392,7 @@ const parentRelationshipDirective = {
|
|
|
9358
9392
|
},
|
|
9359
9393
|
value: {
|
|
9360
9394
|
kind: Kind.STRING,
|
|
9361
|
-
value:
|
|
9395
|
+
value: PARENT_RELATIONSHIP,
|
|
9362
9396
|
block: false,
|
|
9363
9397
|
},
|
|
9364
9398
|
},
|
|
@@ -9372,8 +9406,8 @@ async function injectSyntheticFields(originalAST, objectInfoService, draftFuncti
|
|
|
9372
9406
|
// example 2 'ServiceAppointment' -> ['Owner']; 'Owner' -> ['User', 'Group']
|
|
9373
9407
|
const objectNodeInfoTree = {};
|
|
9374
9408
|
// save the field path to apiName map
|
|
9375
|
-
// example 1: 'ServiceAppointment' -> ['ServiceAppointment']; '
|
|
9376
|
-
const
|
|
9409
|
+
// example 1: 'ServiceAppointment' -> ['ServiceAppointment']; 'ServiceAppointment#ccount' -> ['Account']; 'ServiceAppointment#Account#Owner' -> ['User']
|
|
9410
|
+
const pathToObjectApiNamesMap = {};
|
|
9377
9411
|
let startNodes = new Set();
|
|
9378
9412
|
let totalNodes = new Set();
|
|
9379
9413
|
let objectInfos = {};
|
|
@@ -9387,11 +9421,11 @@ async function injectSyntheticFields(originalAST, objectInfoService, draftFuncti
|
|
|
9387
9421
|
visit(originalAST, {
|
|
9388
9422
|
Argument: {
|
|
9389
9423
|
enter(node, key, parent, path, ancestors) {
|
|
9390
|
-
const
|
|
9391
|
-
if (!
|
|
9424
|
+
const { connection: recordConnectionNode, path: ancesterPath } = findNearestConnectionWithPath(ancestors);
|
|
9425
|
+
if (!recordConnectionNode || !ancesterPath)
|
|
9392
9426
|
return;
|
|
9393
|
-
if (!objectNodeInfoTree[
|
|
9394
|
-
objectNodeInfoTree[
|
|
9427
|
+
if (!objectNodeInfoTree[ancesterPath]) {
|
|
9428
|
+
objectNodeInfoTree[ancesterPath] = [];
|
|
9395
9429
|
}
|
|
9396
9430
|
switch (node.name.value) {
|
|
9397
9431
|
case 'orderBy':
|
|
@@ -9399,12 +9433,12 @@ async function injectSyntheticFields(originalAST, objectInfoService, draftFuncti
|
|
|
9399
9433
|
if (node.value.kind !== 'ObjectValue') {
|
|
9400
9434
|
return;
|
|
9401
9435
|
}
|
|
9402
|
-
totalNodes.add(
|
|
9436
|
+
totalNodes.add(ancesterPath);
|
|
9403
9437
|
// 'childRelationship' node is not taken as the startNode of the 'NodeInfoTree' graph. The field scanning will construct the graph which lead here.
|
|
9404
|
-
if (isRecordQuery(
|
|
9405
|
-
startNodes.add(
|
|
9438
|
+
if (isRecordQuery(recordConnectionNode)) {
|
|
9439
|
+
startNodes.add(recordConnectionNode.name.value);
|
|
9406
9440
|
}
|
|
9407
|
-
growObjectFieldTree(objectNodeInfoTree,
|
|
9441
|
+
growObjectFieldTree(objectNodeInfoTree, ancesterPath, node.value, totalNodes, startNodes);
|
|
9408
9442
|
break;
|
|
9409
9443
|
case 'scope':
|
|
9410
9444
|
if (!isScopeArgumentNodeWithType(node, 'ASSIGNEDTOME', variables)) {
|
|
@@ -9419,17 +9453,16 @@ async function injectSyntheticFields(originalAST, objectInfoService, draftFuncti
|
|
|
9419
9453
|
name: 'ServiceResources',
|
|
9420
9454
|
});
|
|
9421
9455
|
}
|
|
9422
|
-
if (objectNodeInfoTree['ServiceResources'] === undefined) {
|
|
9423
|
-
objectNodeInfoTree['ServiceResources'] = [
|
|
9424
|
-
|
|
9425
|
-
|
|
9426
|
-
|
|
9427
|
-
|
|
9428
|
-
|
|
9429
|
-
});
|
|
9456
|
+
if (objectNodeInfoTree['ServiceAppointment#ServiceResources'] === undefined) {
|
|
9457
|
+
objectNodeInfoTree['ServiceAppointment#ServiceResources'] = [
|
|
9458
|
+
{
|
|
9459
|
+
relation: 'parent',
|
|
9460
|
+
name: 'ServiceResource',
|
|
9461
|
+
},
|
|
9462
|
+
];
|
|
9430
9463
|
}
|
|
9431
|
-
if (objectNodeInfoTree['ServiceResource'] === undefined) {
|
|
9432
|
-
objectNodeInfoTree['ServiceResource'] = [];
|
|
9464
|
+
if (objectNodeInfoTree['ServiceAppointment#ServiceResources#ServiceResource'] === undefined) {
|
|
9465
|
+
objectNodeInfoTree['ServiceAppointment#ServiceResources#ServiceResource'] = [];
|
|
9433
9466
|
}
|
|
9434
9467
|
break;
|
|
9435
9468
|
default:
|
|
@@ -9443,7 +9476,7 @@ async function injectSyntheticFields(originalAST, objectInfoService, draftFuncti
|
|
|
9443
9476
|
return;
|
|
9444
9477
|
if (!node.selectionSet)
|
|
9445
9478
|
return;
|
|
9446
|
-
const recordQueryField =
|
|
9479
|
+
const recordQueryField = findNearestConnection(ancestors);
|
|
9447
9480
|
//only injects fields for 'recordQuery' field. ignores the 'childRelationship' field since it will be traversed as the child of the 'recordQuery'
|
|
9448
9481
|
if (isRecordQuery(recordQueryField) && recordQueryField) {
|
|
9449
9482
|
totalNodes.add(recordQueryField.name.value);
|
|
@@ -9454,21 +9487,21 @@ async function injectSyntheticFields(originalAST, objectInfoService, draftFuncti
|
|
|
9454
9487
|
},
|
|
9455
9488
|
});
|
|
9456
9489
|
if (objectInfoService && startNodes.size > 0) {
|
|
9457
|
-
objectInfos = await resolveObjectInfos(objectNodeInfoTree,
|
|
9490
|
+
objectInfos = await resolveObjectInfos(objectNodeInfoTree, pathToObjectApiNamesMap, startNodes, objectInfoService);
|
|
9458
9491
|
}
|
|
9459
9492
|
// read pass; gather whats needed
|
|
9460
9493
|
visit(originalAST, {
|
|
9461
9494
|
Argument: {
|
|
9462
9495
|
leave(node, key, parent, path, ancestors) {
|
|
9463
|
-
const recordQueryField =
|
|
9496
|
+
const recordQueryField = findNearestConnection(ancestors);
|
|
9464
9497
|
if (!recordQueryField)
|
|
9465
9498
|
return;
|
|
9466
9499
|
const ancestorPath = findAncesterPath(ancestors);
|
|
9467
9500
|
if (!inlineFragmentSelections[ancestorPath]) {
|
|
9468
9501
|
inlineFragmentSelections[ancestorPath] = [];
|
|
9469
9502
|
}
|
|
9470
|
-
const recordQueryApiName =
|
|
9471
|
-
?
|
|
9503
|
+
const recordQueryApiName = pathToObjectApiNamesMap[ancestorPath]
|
|
9504
|
+
? pathToObjectApiNamesMap[ancestorPath][0]
|
|
9472
9505
|
: recordQueryField.name.value;
|
|
9473
9506
|
// The record node acts as the reference. The duplicated field in the record node is not injected
|
|
9474
9507
|
const recordReferenceNode = [recordQueryField]
|
|
@@ -9482,7 +9515,7 @@ async function injectSyntheticFields(originalAST, objectInfoService, draftFuncti
|
|
|
9482
9515
|
case 'scope':
|
|
9483
9516
|
// Hanle 'MINE' field
|
|
9484
9517
|
if (isScopeArgumentNodeWithType(node, 'MINE', variables)) {
|
|
9485
|
-
if (isMineScopeAvailable(ancestorPath,
|
|
9518
|
+
if (isMineScopeAvailable(ancestorPath, pathToObjectApiNamesMap, objectInfos)) {
|
|
9486
9519
|
// 'typeConditon' is added when the 'InlineFragmentNode' is appended at the write pass
|
|
9487
9520
|
inlineFragmentSelections[ancestorPath].push(...mineFragmentSelections);
|
|
9488
9521
|
}
|
|
@@ -9508,7 +9541,7 @@ async function injectSyntheticFields(originalAST, objectInfoService, draftFuncti
|
|
|
9508
9541
|
case 'where': {
|
|
9509
9542
|
inlineFragmentSelections[ancestorPath] = [
|
|
9510
9543
|
...inlineFragmentSelections[ancestorPath],
|
|
9511
|
-
...injectFilter(node, idState, ancestorPath, objectInfos,
|
|
9544
|
+
...injectFilter(node, idState, ancestorPath, false, objectInfos, pathToObjectApiNamesMap, draftFunctions, recordReferenceNode),
|
|
9512
9545
|
];
|
|
9513
9546
|
break;
|
|
9514
9547
|
}
|
|
@@ -9524,7 +9557,7 @@ async function injectSyntheticFields(originalAST, objectInfoService, draftFuncti
|
|
|
9524
9557
|
if (!node.selectionSet)
|
|
9525
9558
|
return;
|
|
9526
9559
|
// it could be 'recordQuery' or 'childRelationship'
|
|
9527
|
-
const recordQueryField =
|
|
9560
|
+
const recordQueryField = findNearestConnection(ancestors);
|
|
9528
9561
|
if (!recordQueryField)
|
|
9529
9562
|
return;
|
|
9530
9563
|
const ancestorPath = findAncesterPath(ancestors);
|
|
@@ -9536,7 +9569,7 @@ async function injectSyntheticFields(originalAST, objectInfoService, draftFuncti
|
|
|
9536
9569
|
spanningSelections.push(selection);
|
|
9537
9570
|
}
|
|
9538
9571
|
}
|
|
9539
|
-
const injectedFields = injectFields(spanningSelections, node, ancestors, objectInfos,
|
|
9572
|
+
const injectedFields = injectFields(spanningSelections, node, ancestorPath, ancestors, objectInfos, pathToObjectApiNamesMap);
|
|
9540
9573
|
const mergedInjectedFields = mergeSelectionNodes(inlineFragmentSelections[ancestorPath], injectedFields);
|
|
9541
9574
|
inlineFragmentSelections[ancestorPath] = mergedInjectedFields;
|
|
9542
9575
|
},
|
|
@@ -9549,7 +9582,7 @@ async function injectSyntheticFields(originalAST, objectInfoService, draftFuncti
|
|
|
9549
9582
|
// removes 'ServicesResources' query field node if 'assignedtome' scope shows up
|
|
9550
9583
|
if (assignedtomeQueryFieldNode !== undefined &&
|
|
9551
9584
|
node.name.value === 'ServiceResources') {
|
|
9552
|
-
const serviceResourcesAncestor =
|
|
9585
|
+
const serviceResourcesAncestor = findNearestConnection(ancestors);
|
|
9553
9586
|
if (serviceResourcesAncestor === assignedtomeQueryFieldNode) {
|
|
9554
9587
|
return null;
|
|
9555
9588
|
}
|
|
@@ -9558,7 +9591,7 @@ async function injectSyntheticFields(originalAST, objectInfoService, draftFuncti
|
|
|
9558
9591
|
return;
|
|
9559
9592
|
if (!node.selectionSet)
|
|
9560
9593
|
return;
|
|
9561
|
-
const recordQueryField =
|
|
9594
|
+
const recordQueryField = findNearestConnection(ancestors);
|
|
9562
9595
|
if (!recordQueryField)
|
|
9563
9596
|
return;
|
|
9564
9597
|
const ancestorPath = findAncesterPath(ancestors);
|
|
@@ -9567,8 +9600,8 @@ async function injectSyntheticFields(originalAST, objectInfoService, draftFuncti
|
|
|
9567
9600
|
return;
|
|
9568
9601
|
//const recordQueryPath = findAncesterPath(ancestors);
|
|
9569
9602
|
// '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.
|
|
9570
|
-
const recordQueryApiName =
|
|
9571
|
-
?
|
|
9603
|
+
const recordQueryApiName = pathToObjectApiNamesMap[ancestorPath]
|
|
9604
|
+
? pathToObjectApiNamesMap[ancestorPath][0]
|
|
9572
9605
|
: recordQueryField.name.value;
|
|
9573
9606
|
const nodeWithFragments = {
|
|
9574
9607
|
...node,
|
|
@@ -9605,7 +9638,7 @@ async function injectSyntheticFields(originalAST, objectInfoService, draftFuncti
|
|
|
9605
9638
|
if (node.name.value === 'where') {
|
|
9606
9639
|
const ancestorPath = findAncesterPath(ancestors);
|
|
9607
9640
|
if (idState.paths.includes(ancestorPath)) {
|
|
9608
|
-
const apiName =
|
|
9641
|
+
const apiName = pathToObjectApiNamesMap[ancestorPath][0];
|
|
9609
9642
|
const objectInfo = objectInfos[apiName];
|
|
9610
9643
|
const swappedIdFilter = swapIdField(node.value, objectInfo, false, idState, draftFunctions);
|
|
9611
9644
|
return {
|
|
@@ -9671,8 +9704,8 @@ function swapIdField(filterFields, objectInfo, swapped, idState, draftFunctions)
|
|
|
9671
9704
|
};
|
|
9672
9705
|
}
|
|
9673
9706
|
}
|
|
9674
|
-
function isMineScopeAvailable(apiNamePath,
|
|
9675
|
-
const apiName =
|
|
9707
|
+
function isMineScopeAvailable(apiNamePath, pathToObjectApiNamesMap, objectInfos) {
|
|
9708
|
+
const apiName = pathToObjectApiNamesMap[apiNamePath];
|
|
9676
9709
|
if (!apiName)
|
|
9677
9710
|
return false;
|
|
9678
9711
|
const objectInfo = objectInfos[apiName[0]];
|
|
@@ -9761,15 +9794,16 @@ function growObjectFieldTree(tree, parentNode, entryNode, totalNodes, startNodes
|
|
|
9761
9794
|
}
|
|
9762
9795
|
// example: 'Account'
|
|
9763
9796
|
const childNode = objectFieldNode.name.value;
|
|
9797
|
+
const childNodepath = `${parentNode}#${childNode}`;
|
|
9764
9798
|
if (!tree[parentNode].some((child) => child.name === childNode)) {
|
|
9765
9799
|
tree[parentNode].push({
|
|
9766
9800
|
relation: 'parent',
|
|
9767
9801
|
name: childNode,
|
|
9768
9802
|
});
|
|
9769
|
-
totalNodes.add(
|
|
9803
|
+
totalNodes.add(childNodepath);
|
|
9770
9804
|
}
|
|
9771
9805
|
// recursively go to deeper level of filter.
|
|
9772
|
-
growObjectFieldTree(tree,
|
|
9806
|
+
growObjectFieldTree(tree, childNodepath, objectFieldNode.value, totalNodes, startNodes);
|
|
9773
9807
|
}
|
|
9774
9808
|
}
|
|
9775
9809
|
}
|
|
@@ -9804,19 +9838,20 @@ function growFieldTree(tree, parentSectionPath, entryNode, parentNode, totalNode
|
|
|
9804
9838
|
}
|
|
9805
9839
|
if (!tree[parentSectionPath].some((field) => field.name === fieldName)) {
|
|
9806
9840
|
tree[parentSectionPath].push({
|
|
9807
|
-
relation: relationType ===
|
|
9808
|
-
relationType ===
|
|
9841
|
+
relation: relationType === PARENT_RELATIONSHIP ||
|
|
9842
|
+
relationType === POLYMORPHIC_PARENT_RELATIONSHIP
|
|
9809
9843
|
? 'parent'
|
|
9810
9844
|
: 'child',
|
|
9811
9845
|
name: fieldName,
|
|
9812
9846
|
});
|
|
9813
|
-
totalNodes.add(fieldName);
|
|
9847
|
+
totalNodes.add(`${parentSectionPath}#${fieldName}`);
|
|
9814
9848
|
}
|
|
9815
9849
|
if (entryNode.selectionSet && entryNode.selectionSet.selections) {
|
|
9816
9850
|
const childNodes = entryNode.selectionSet.selections.filter(isFieldOrInlineFragmentNode);
|
|
9817
9851
|
// recursively build the traversal tree
|
|
9818
9852
|
for (const child of childNodes) {
|
|
9819
|
-
|
|
9853
|
+
const path = `${parentSectionPath}#${fieldName}`;
|
|
9854
|
+
growFieldTree(tree, path, child, entryNode, totalNodes, startNodes);
|
|
9820
9855
|
}
|
|
9821
9856
|
}
|
|
9822
9857
|
}
|
|
@@ -9846,23 +9881,23 @@ function growFieldTree(tree, parentSectionPath, entryNode, parentNode, totalNode
|
|
|
9846
9881
|
}
|
|
9847
9882
|
if (!tree[parentSectionPath].some((field) => field.name === conditionName)) {
|
|
9848
9883
|
tree[parentSectionPath].push({
|
|
9849
|
-
relation: relationType ===
|
|
9850
|
-
relationType ===
|
|
9884
|
+
relation: relationType === PARENT_RELATIONSHIP ||
|
|
9885
|
+
relationType === POLYMORPHIC_PARENT_RELATIONSHIP
|
|
9851
9886
|
? 'parent'
|
|
9852
9887
|
: 'child',
|
|
9853
9888
|
name: conditionName,
|
|
9854
9889
|
});
|
|
9855
|
-
|
|
9890
|
+
const path = `${parentSectionPath}#${conditionName}`;
|
|
9891
|
+
totalNodes.add(path);
|
|
9856
9892
|
}
|
|
9857
9893
|
}
|
|
9858
9894
|
}
|
|
9859
9895
|
// dive deep immediately for 'InlineFragment'
|
|
9860
9896
|
const childNodes = entryNode.selectionSet.selections.filter(isFieldOrInlineFragmentNode);
|
|
9897
|
+
const path = `${parentSectionPath}${entryNode.typeCondition ? '#' + entryNode.typeCondition.name.value : ''}`;
|
|
9861
9898
|
// Navigates into InLineFragment
|
|
9862
9899
|
for (const child of childNodes) {
|
|
9863
|
-
growFieldTree(tree, entryNode
|
|
9864
|
-
? entryNode.typeCondition.name.value
|
|
9865
|
-
: parentSectionPath, child, entryNode, totalNodes, startNodes);
|
|
9900
|
+
growFieldTree(tree, path, child, entryNode, totalNodes, startNodes);
|
|
9866
9901
|
}
|
|
9867
9902
|
}
|
|
9868
9903
|
}
|
|
@@ -9874,7 +9909,7 @@ function growFieldTree(tree, parentSectionPath, entryNode, parentNode, totalNode
|
|
|
9874
9909
|
* @param startNodes start nodes of the tree. It can be used to fetch ObjectInfo immediately
|
|
9875
9910
|
* @param path
|
|
9876
9911
|
*/
|
|
9877
|
-
async function resolveObjectInfos(objectInfotree,
|
|
9912
|
+
async function resolveObjectInfos(objectInfotree, pathToObjectApiNamesMap, startNodes, objectInfoService) {
|
|
9878
9913
|
let objectInfos;
|
|
9879
9914
|
try {
|
|
9880
9915
|
objectInfos = await objectInfoService.getObjectInfos(Array.from(startNodes));
|
|
@@ -9888,9 +9923,9 @@ async function resolveObjectInfos(objectInfotree, objectInfoApiMap, startNodes,
|
|
|
9888
9923
|
throw new Error(`Unable to resolve ObjectInfo(s) for ${Array.from(startNodes)}`);
|
|
9889
9924
|
}
|
|
9890
9925
|
for (const startNode of startNodes) {
|
|
9891
|
-
|
|
9926
|
+
pathToObjectApiNamesMap[startNode] = [startNode];
|
|
9892
9927
|
const children = objectInfotree[startNode];
|
|
9893
|
-
const subObjectInfoMap = await fetchObjectInfos(objectInfotree,
|
|
9928
|
+
const subObjectInfoMap = await fetchObjectInfos(objectInfotree, pathToObjectApiNamesMap, objectInfos, children, startNode, objectInfoService);
|
|
9894
9929
|
objectInfos = { ...objectInfos, ...subObjectInfoMap };
|
|
9895
9930
|
}
|
|
9896
9931
|
return objectInfos;
|
|
@@ -9898,15 +9933,15 @@ async function resolveObjectInfos(objectInfotree, objectInfoApiMap, startNodes,
|
|
|
9898
9933
|
// example 1: 'parentPath': 'ServiceAppointment', 'nodesAtSameLevel': ['Account']
|
|
9899
9934
|
// example 2: 'parentPath': 'ServiceAppointment', 'nodesAtSameLevel': ['Owner'], this example has 2 apiName for the node 'Owner'
|
|
9900
9935
|
// example 3: 'parentPath': 'ServiceAppointment_Owner', 'nodesAtSameLevel': ['User', 'Group']
|
|
9901
|
-
async function fetchObjectInfos(objectInfotree,
|
|
9902
|
-
const objectInfoApiNames =
|
|
9936
|
+
async function fetchObjectInfos(objectInfotree, pathToObjectApiNamesMap, objectInfoMap, nodesAtSameLevel, parentPath, objectInfoService) {
|
|
9937
|
+
const objectInfoApiNames = pathToObjectApiNamesMap[parentPath];
|
|
9903
9938
|
if (!objectInfoApiNames) {
|
|
9904
9939
|
// eslint-disable-next-line
|
|
9905
9940
|
throw new Error(`Object Info does not exist for ${parentPath}`);
|
|
9906
9941
|
}
|
|
9907
9942
|
const validObjectInfoNodes = [];
|
|
9908
9943
|
let updatedObjectInfoMap = {};
|
|
9909
|
-
// InlineFragment and polymorphic field support fits into this scenario
|
|
9944
|
+
// InlineFragment and polymorphic field support fits into this scenario pathToObjectApiNamesMap Entry: 'ServiceAppointment#Owner' -> ['User', 'Group']; ServiceAppointment#Owner#User' -> ['User']
|
|
9910
9945
|
if (objectInfoApiNames.length > 0 &&
|
|
9911
9946
|
nodesAtSameLevel.length > 0 &&
|
|
9912
9947
|
objectInfoApiNames.includes(nodesAtSameLevel[0].name)) {
|
|
@@ -9918,8 +9953,8 @@ async function fetchObjectInfos(objectInfotree, objectInfoApiMap, objectInfoMap,
|
|
|
9918
9953
|
// eslint-disable-next-line
|
|
9919
9954
|
throw new Error(`Condition ${field.name} does not exists for ${parentPath}`);
|
|
9920
9955
|
}
|
|
9921
|
-
const path = `${parentPath}
|
|
9922
|
-
|
|
9956
|
+
const path = `${parentPath}#${field.name}`;
|
|
9957
|
+
pathToObjectApiNamesMap[path] = [field.name];
|
|
9923
9958
|
}
|
|
9924
9959
|
validObjectInfoNodes.push(...nodesAtSameLevel);
|
|
9925
9960
|
updatedObjectInfoMap = { ...objectInfoMap };
|
|
@@ -9934,7 +9969,7 @@ async function fetchObjectInfos(objectInfotree, objectInfoApiMap, objectInfoMap,
|
|
|
9934
9969
|
let apiNames = [];
|
|
9935
9970
|
for (const nodeInfo of nodesAtSameLevel) {
|
|
9936
9971
|
const field = nodeInfo.name;
|
|
9937
|
-
const path = `${parentPath}
|
|
9972
|
+
const path = `${parentPath}#${field}`;
|
|
9938
9973
|
// Handle 'parentRelationship'
|
|
9939
9974
|
if (nodeInfo.relation === 'parent') {
|
|
9940
9975
|
const relationshipId = referenceIdFieldForRelationship(field);
|
|
@@ -9952,21 +9987,21 @@ async function fetchObjectInfos(objectInfotree, objectInfoApiMap, objectInfoMap,
|
|
|
9952
9987
|
}
|
|
9953
9988
|
}
|
|
9954
9989
|
// This is a polymorphic field
|
|
9955
|
-
if (fieldDefinition.referenceToInfos.length > 1 && objectInfotree[
|
|
9990
|
+
if (fieldDefinition.referenceToInfos.length > 1 && objectInfotree[path]) {
|
|
9956
9991
|
// Fields needs to expand and heterogenous entity ObjectInfo needs to be fetched
|
|
9957
|
-
const referencedNodeInfos = objectInfotree[
|
|
9992
|
+
const referencedNodeInfos = objectInfotree[path];
|
|
9958
9993
|
const requestedApiNames = referencedNodeInfos.map((referenceNodeInfo) => referenceNodeInfo.name);
|
|
9959
9994
|
// 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.
|
|
9960
|
-
if (requestedApiNames.length > 0 && objectInfotree[
|
|
9995
|
+
if (requestedApiNames.length > 0 && objectInfotree[path]) {
|
|
9961
9996
|
fieldDefinition.referenceToInfos
|
|
9962
9997
|
.filter((referenceToInfo) => requestedApiNames.includes(referenceToInfo.apiName))
|
|
9963
9998
|
.forEach((ref) => {
|
|
9964
|
-
if (!
|
|
9965
|
-
|
|
9999
|
+
if (!pathToObjectApiNamesMap[path]) {
|
|
10000
|
+
pathToObjectApiNamesMap[path] = [];
|
|
9966
10001
|
}
|
|
9967
10002
|
// 'ServiceAppointment_Owner' ->['User', 'Group']
|
|
9968
|
-
if (!
|
|
9969
|
-
|
|
10003
|
+
if (!pathToObjectApiNamesMap[path].includes(ref.apiName)) {
|
|
10004
|
+
pathToObjectApiNamesMap[path].push(ref.apiName);
|
|
9970
10005
|
}
|
|
9971
10006
|
if (!apiNames.includes(ref.apiName)) {
|
|
9972
10007
|
apiNames.push(ref.apiName);
|
|
@@ -9976,11 +10011,11 @@ async function fetchObjectInfos(objectInfotree, objectInfoApiMap, objectInfoMap,
|
|
|
9976
10011
|
}
|
|
9977
10012
|
else if (fieldDefinition.referenceToInfos.length === 1) {
|
|
9978
10013
|
const ref = fieldDefinition.referenceToInfos[0];
|
|
9979
|
-
if (!
|
|
9980
|
-
|
|
10014
|
+
if (!pathToObjectApiNamesMap[path]) {
|
|
10015
|
+
pathToObjectApiNamesMap[path] = [];
|
|
9981
10016
|
}
|
|
9982
|
-
if (!
|
|
9983
|
-
|
|
10017
|
+
if (!pathToObjectApiNamesMap[path].includes(ref.apiName)) {
|
|
10018
|
+
pathToObjectApiNamesMap[path].push(ref.apiName);
|
|
9984
10019
|
}
|
|
9985
10020
|
if (!apiNames.includes(ref.apiName)) {
|
|
9986
10021
|
apiNames.push(ref.apiName);
|
|
@@ -9991,11 +10026,11 @@ async function fetchObjectInfos(objectInfotree, objectInfoApiMap, objectInfoMap,
|
|
|
9991
10026
|
// handles 'childRelationship'
|
|
9992
10027
|
const childRelationship = parentObjectInfo.childRelationships.find((childRelationship) => childRelationship.relationshipName === field);
|
|
9993
10028
|
if (childRelationship) {
|
|
9994
|
-
if (!
|
|
9995
|
-
|
|
10029
|
+
if (!pathToObjectApiNamesMap[path]) {
|
|
10030
|
+
pathToObjectApiNamesMap[path] = [];
|
|
9996
10031
|
}
|
|
9997
|
-
if (!
|
|
9998
|
-
|
|
10032
|
+
if (!pathToObjectApiNamesMap[path].includes(childRelationship.childObjectApiName)) {
|
|
10033
|
+
pathToObjectApiNamesMap[path].push(childRelationship.childObjectApiName);
|
|
9999
10034
|
}
|
|
10000
10035
|
if (!apiNames.includes(childRelationship.childObjectApiName)) {
|
|
10001
10036
|
apiNames.push(childRelationship.childObjectApiName);
|
|
@@ -10017,10 +10052,10 @@ async function fetchObjectInfos(objectInfotree, objectInfoApiMap, objectInfoMap,
|
|
|
10017
10052
|
}
|
|
10018
10053
|
for (const nodeInfo of validObjectInfoNodes) {
|
|
10019
10054
|
const field = nodeInfo.name;
|
|
10020
|
-
const
|
|
10021
|
-
const
|
|
10055
|
+
const path = `${parentPath}#${field}`;
|
|
10056
|
+
const subLevelFields = objectInfotree[path];
|
|
10022
10057
|
if (subLevelFields && subLevelFields.length > 0) {
|
|
10023
|
-
const subObjectInfos = await fetchObjectInfos(objectInfotree,
|
|
10058
|
+
const subObjectInfos = await fetchObjectInfos(objectInfotree, pathToObjectApiNamesMap, updatedObjectInfoMap, subLevelFields, path, objectInfoService);
|
|
10024
10059
|
updatedObjectInfoMap = { ...updatedObjectInfoMap, ...subObjectInfos };
|
|
10025
10060
|
}
|
|
10026
10061
|
}
|
|
@@ -10035,27 +10070,29 @@ async function fetchObjectInfos(objectInfotree, objectInfoApiMap, objectInfoMap,
|
|
|
10035
10070
|
* 'path' and 'queryNode' is 1 level above the 'filterNode'
|
|
10036
10071
|
* @param filterNode filter node which needs to be injected. For example, 'State' ObjectFieldNode within filter 'where: { State: { eq: "Nova Scotia" }}'
|
|
10037
10072
|
* @param idState ID state will be updated to determine if the ID fields in AST need to be swapped. The swapping happens later.
|
|
10038
|
-
* @param
|
|
10073
|
+
* @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
|
|
10074
|
+
* @param isParentPolymorphic true if parent points to a polymorphic field.
|
|
10039
10075
|
* @param queryNode referece FieldNode which provides the information if 'filterNode' exist in it nor not.
|
|
10040
10076
|
* @param objectInfos ObjectInfo map used in injection. If ObjectInfo misses or field does not exist in ObjectInfo, the error will be thrown
|
|
10041
|
-
* @param
|
|
10077
|
+
* @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'].
|
|
10042
10078
|
* @param draftFunctions functions for working with record ids that may be draft-created ids
|
|
10043
10079
|
* @returns an array of nodes with injected fields
|
|
10044
10080
|
*/
|
|
10045
|
-
function injectFilter(filterNode, idState,
|
|
10081
|
+
function injectFilter(filterNode, idState, parentPath, isParentPolymorphic, objectInfos, pathToObjectApiNamesMap, draftFunctions, queryNode) {
|
|
10046
10082
|
const injectedSelections = [];
|
|
10083
|
+
let isPolymorphicField = false;
|
|
10047
10084
|
switch (filterNode.kind) {
|
|
10048
10085
|
case Kind.ARGUMENT:
|
|
10049
10086
|
if (filterNode.value.kind !== 'ObjectValue')
|
|
10050
10087
|
return [];
|
|
10051
10088
|
filterNode.value.fields.forEach((objectFieldNode) => {
|
|
10052
|
-
let subResults = injectFilter(objectFieldNode, idState,
|
|
10089
|
+
let subResults = injectFilter(objectFieldNode, idState, parentPath, isParentPolymorphic, objectInfos, pathToObjectApiNamesMap, draftFunctions, queryNode);
|
|
10053
10090
|
for (const subResult of subResults) {
|
|
10054
10091
|
mergeOrAddToGroup(injectedSelections, subResult);
|
|
10055
10092
|
}
|
|
10056
10093
|
// multiple Ids might need to be swapped. remember their paths for faster write.
|
|
10057
10094
|
if (idState.swapNeeded) {
|
|
10058
|
-
idState.paths.push(
|
|
10095
|
+
idState.paths.push(parentPath);
|
|
10059
10096
|
}
|
|
10060
10097
|
});
|
|
10061
10098
|
return injectedSelections;
|
|
@@ -10064,7 +10101,7 @@ function injectFilter(filterNode, idState, path, objectInfos, objectInfoApiMap,
|
|
|
10064
10101
|
case Kind.LIST: {
|
|
10065
10102
|
filterNode.value.values.filter(isObjectValueNode).forEach((objectValueNode) => {
|
|
10066
10103
|
objectValueNode.fields.forEach((objectFieldNode) => {
|
|
10067
|
-
const subResults = injectFilter(objectFieldNode, idState,
|
|
10104
|
+
const subResults = injectFilter(objectFieldNode, idState, parentPath, isParentPolymorphic, objectInfos, pathToObjectApiNamesMap, draftFunctions, queryNode);
|
|
10068
10105
|
for (const subResult of subResults) {
|
|
10069
10106
|
mergeOrAddToGroup(injectedSelections, subResult);
|
|
10070
10107
|
}
|
|
@@ -10075,7 +10112,7 @@ function injectFilter(filterNode, idState, path, objectInfos, objectInfoApiMap,
|
|
|
10075
10112
|
case Kind.OBJECT: {
|
|
10076
10113
|
if (filterNode.name.value === 'not') {
|
|
10077
10114
|
filterNode.value.fields.forEach((objectFieldNode) => {
|
|
10078
|
-
const subResults = injectFilter(objectFieldNode, idState,
|
|
10115
|
+
const subResults = injectFilter(objectFieldNode, idState, parentPath, isParentPolymorphic, objectInfos, pathToObjectApiNamesMap, draftFunctions, queryNode);
|
|
10079
10116
|
for (const subResult of subResults) {
|
|
10080
10117
|
mergeOrAddToGroup(injectedSelections, subResult);
|
|
10081
10118
|
}
|
|
@@ -10085,15 +10122,15 @@ function injectFilter(filterNode, idState, path, objectInfos, objectInfoApiMap,
|
|
|
10085
10122
|
let apiNames = [];
|
|
10086
10123
|
let isScalarField = false;
|
|
10087
10124
|
//It is possible that this is a polymorphic field
|
|
10088
|
-
apiNames =
|
|
10089
|
-
// example: path: '
|
|
10125
|
+
apiNames = pathToObjectApiNamesMap[parentPath];
|
|
10126
|
+
// example: path: 'ServiceAppointment#LastModifiedDate'; filterNode: '{eq: {literal: LAST_WEEK}}'. queryNode: 'LastModifedDate { value}' FilterNode's parent has been verifed as a valid node
|
|
10090
10127
|
if (apiNames === undefined) {
|
|
10091
10128
|
isScalarField = true;
|
|
10092
10129
|
}
|
|
10093
10130
|
else {
|
|
10094
10131
|
if (apiNames.some((apiName) => objectInfos[apiName] === undefined)) {
|
|
10095
10132
|
// eslint-disable-next-line
|
|
10096
|
-
throw new Error(`ObjectInfo is missing for ${
|
|
10133
|
+
throw new Error(`ObjectInfo is missing for ${parentPath}`);
|
|
10097
10134
|
}
|
|
10098
10135
|
}
|
|
10099
10136
|
if (isScalarField) {
|
|
@@ -10115,29 +10152,19 @@ function injectFilter(filterNode, idState, path, objectInfos, objectInfoApiMap,
|
|
|
10115
10152
|
}
|
|
10116
10153
|
});
|
|
10117
10154
|
let isSpanning = false;
|
|
10155
|
+
// if true, current node is a polymorphic concrete type node. For example, field node `User` under `Owner`
|
|
10118
10156
|
let isInlineFragment = false;
|
|
10119
|
-
let isPolymorphicField = false;
|
|
10120
10157
|
let isTypeNameExisting = false;
|
|
10121
10158
|
let curPath;
|
|
10122
10159
|
let fieldName = filterNode.name.value;
|
|
10123
|
-
curPath = `${
|
|
10124
|
-
if (
|
|
10160
|
+
curPath = `${parentPath}#${fieldName}`;
|
|
10161
|
+
if (pathToObjectApiNamesMap[curPath] &&
|
|
10162
|
+
pathToObjectApiNamesMap[curPath].length > 0) {
|
|
10125
10163
|
isSpanning = true;
|
|
10126
|
-
|
|
10127
|
-
|
|
10128
|
-
|
|
10129
|
-
|
|
10130
|
-
isInlineFragment = true;
|
|
10131
|
-
}
|
|
10132
|
-
}
|
|
10133
|
-
// Checks if the current filter node is a polymorphic field. 'ServiceAppointment_Owner' --> ['User']; 'ServiceAppointment_Owner_User' --> ['User']
|
|
10134
|
-
const childApiName = objectInfoApiMap[curPath][0];
|
|
10135
|
-
const trialApiNames = objectInfoApiMap[`${curPath}_${childApiName}`];
|
|
10136
|
-
if (trialApiNames !== undefined &&
|
|
10137
|
-
trialApiNames.length === 1 &&
|
|
10138
|
-
trialApiNames[0] === childApiName) {
|
|
10139
|
-
isPolymorphicField = true;
|
|
10140
|
-
}
|
|
10164
|
+
isInlineFragment =
|
|
10165
|
+
isParentPolymorphic &&
|
|
10166
|
+
pathToObjectApiNamesMap[curPath].length === 1;
|
|
10167
|
+
isPolymorphicField = isPolymorphicFieldPath(curPath, pathToObjectApiNamesMap, objectInfos);
|
|
10141
10168
|
}
|
|
10142
10169
|
// 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]
|
|
10143
10170
|
if (isInlineFragment) {
|
|
@@ -10181,9 +10208,9 @@ function injectFilter(filterNode, idState, path, objectInfos, objectInfoApiMap,
|
|
|
10181
10208
|
throw new Error(`Field ${fieldName} does not exist in ${apiNames[0]}`);
|
|
10182
10209
|
}
|
|
10183
10210
|
}
|
|
10184
|
-
const objectInfoName =
|
|
10185
|
-
?
|
|
10186
|
-
:
|
|
10211
|
+
const objectInfoName = pathToObjectApiNamesMap[curPath] !== undefined
|
|
10212
|
+
? pathToObjectApiNamesMap[curPath][0]
|
|
10213
|
+
: pathToObjectApiNamesMap[parentPath][0];
|
|
10187
10214
|
const isIdField = isFieldAnIdField(filterNode.name.value, objectInfos[objectInfoName]);
|
|
10188
10215
|
if (!isIdField) {
|
|
10189
10216
|
let subSelectionNodes = [];
|
|
@@ -10195,7 +10222,7 @@ function injectFilter(filterNode, idState, path, objectInfos, objectInfoApiMap,
|
|
|
10195
10222
|
updateIDInfo(subFieldNode, idState, draftFunctions);
|
|
10196
10223
|
}
|
|
10197
10224
|
// try injecting the fields within predicate no matter it has relation or not.
|
|
10198
|
-
let subResults = injectFilter(subFieldNode, idState, curPath, objectInfos,
|
|
10225
|
+
let subResults = injectFilter(subFieldNode, idState, curPath, isPolymorphicField, objectInfos, pathToObjectApiNamesMap, draftFunctions, existingFields ? existingFields[0] : undefined);
|
|
10199
10226
|
subSelectionNodes = subSelectionNodes.concat(subResults);
|
|
10200
10227
|
});
|
|
10201
10228
|
if (!subFieldsHasId) {
|
|
@@ -10356,6 +10383,44 @@ function mergeOrAddToGroup(group, element) {
|
|
|
10356
10383
|
}
|
|
10357
10384
|
group.push(element);
|
|
10358
10385
|
}
|
|
10386
|
+
// checks if the path points to a polymorphic field. For example, for the below `pathToObjectApiNamesMap`
|
|
10387
|
+
// {
|
|
10388
|
+
// 'ServiceAppointment' -> ['ServiceAppointment']
|
|
10389
|
+
// 'ServiceAppointment#Owner' --> ['User'],
|
|
10390
|
+
// 'ServiceAppointment#Owner#User' --> ['User']
|
|
10391
|
+
// }
|
|
10392
|
+
// path `ServiceAppointment#Owner` points to a polymorphic field, but path `ServiceAppointment#Owner#User` does not.
|
|
10393
|
+
function isPolymorphicFieldPath(path, pathToObjectApiNamesMap, objectInfos) {
|
|
10394
|
+
const lastSegmentIndex = path.lastIndexOf('#');
|
|
10395
|
+
if (lastSegmentIndex < 0) {
|
|
10396
|
+
return false;
|
|
10397
|
+
}
|
|
10398
|
+
const lastSegment = path.slice(lastSegmentIndex + 1);
|
|
10399
|
+
const parentApiPath = path.slice(0, lastSegmentIndex);
|
|
10400
|
+
if (pathToObjectApiNamesMap[parentApiPath] === undefined) {
|
|
10401
|
+
return false;
|
|
10402
|
+
}
|
|
10403
|
+
const parentObjectApiNames = pathToObjectApiNamesMap[parentApiPath];
|
|
10404
|
+
// 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`.
|
|
10405
|
+
// 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.
|
|
10406
|
+
// Below are the entries in `pathToObjectApiNamesMap`
|
|
10407
|
+
// {
|
|
10408
|
+
// `ServiceAppointmen`t: [`ServiceAppointment`],
|
|
10409
|
+
// `ServiceAppointment#Owner`: [`User`, `Group`],
|
|
10410
|
+
// `ServiceAppointment#Owner#User`: [`User`],
|
|
10411
|
+
// `ServiceAppointment#Owner#Group`: [`Group`],
|
|
10412
|
+
// }
|
|
10413
|
+
if (parentObjectApiNames.length !== 1) {
|
|
10414
|
+
return false;
|
|
10415
|
+
}
|
|
10416
|
+
const parentObjectInfo = objectInfos[parentObjectApiNames[0]];
|
|
10417
|
+
const relationshipField = referenceIdFieldForRelationship(lastSegment);
|
|
10418
|
+
let fieldDefinition = parentObjectInfo.fields[relationshipField];
|
|
10419
|
+
if (fieldDefinition === undefined) {
|
|
10420
|
+
return false;
|
|
10421
|
+
}
|
|
10422
|
+
return fieldDefinition.polymorphicForeignKey;
|
|
10423
|
+
}
|
|
10359
10424
|
function isFieldAnIdField(fieldName, objectInfo) {
|
|
10360
10425
|
if (fieldName === 'Id')
|
|
10361
10426
|
return true;
|
|
@@ -10408,10 +10473,10 @@ function updateIDInfo(fieldNode, idState, draftFunctions) {
|
|
|
10408
10473
|
* @param parentNode parent node of param 1
|
|
10409
10474
|
* @param ancestors ancester of param 1
|
|
10410
10475
|
* @param objectInfos ObjectInfo map used in injection. If ObjectInfo misses or field does not exist in ObjectInfo, the error will be thrown
|
|
10411
|
-
* @param
|
|
10476
|
+
* @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'].
|
|
10412
10477
|
* @return injected SelectionNodes used to construct the InlineFragment.
|
|
10413
10478
|
*/
|
|
10414
|
-
function injectFields(selections, parentNode, ancestors, objectInfos,
|
|
10479
|
+
function injectFields(selections, parentNode, parentPath, ancestors, objectInfos, pathToObjectApiNamesMap) {
|
|
10415
10480
|
/**
|
|
10416
10481
|
* 1 parentship can return 2 FieldNode which need to be flattened
|
|
10417
10482
|
* Concact: { ** Contact { ** ContactId {
|
|
@@ -10429,6 +10494,10 @@ function injectFields(selections, parentNode, ancestors, objectInfos, objectInfo
|
|
|
10429
10494
|
if (!selection.selectionSet) {
|
|
10430
10495
|
return selection;
|
|
10431
10496
|
}
|
|
10497
|
+
const segment = isFieldNode(selection)
|
|
10498
|
+
? selection.name.value
|
|
10499
|
+
: selection.typeCondition.name.value;
|
|
10500
|
+
const curPath = `${parentPath}#${segment}`;
|
|
10432
10501
|
const spanningSubSelections = [];
|
|
10433
10502
|
for (const subSelection of selection.selectionSet.selections) {
|
|
10434
10503
|
if (isFieldSpanning(subSelection, selection)) {
|
|
@@ -10436,7 +10505,7 @@ function injectFields(selections, parentNode, ancestors, objectInfos, objectInfo
|
|
|
10436
10505
|
}
|
|
10437
10506
|
}
|
|
10438
10507
|
// Handles multiple level field injection like 'ServiceAppointment' --> 'Account' --> 'Owner'
|
|
10439
|
-
const subInjectedSelections = injectFields(spanningSubSelections, selection, ancestors, objectInfos,
|
|
10508
|
+
const subInjectedSelections = injectFields(spanningSubSelections, selection, curPath, ancestors, objectInfos, pathToObjectApiNamesMap);
|
|
10440
10509
|
if (!selection.selectionSet) {
|
|
10441
10510
|
return selection;
|
|
10442
10511
|
}
|
|
@@ -10479,7 +10548,7 @@ function injectFields(selections, parentNode, ancestors, objectInfos, objectInfo
|
|
|
10479
10548
|
}
|
|
10480
10549
|
}
|
|
10481
10550
|
// For polymorphic fields, the Id field is excluded.
|
|
10482
|
-
const excludeId =
|
|
10551
|
+
const excludeId = isPolymorphicFieldPath(curPath, pathToObjectApiNamesMap, objectInfos);
|
|
10483
10552
|
const idSelection = [];
|
|
10484
10553
|
if (!excludeId && !hasIdAlready) {
|
|
10485
10554
|
idSelection.push({
|
|
@@ -10490,8 +10559,8 @@ function injectFields(selections, parentNode, ancestors, objectInfos, objectInfo
|
|
|
10490
10559
|
},
|
|
10491
10560
|
});
|
|
10492
10561
|
}
|
|
10493
|
-
// Inject '__typename' for
|
|
10494
|
-
// please reference 'removeSyntheticFields'.
|
|
10562
|
+
// 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
|
|
10563
|
+
// `typedCondition` of the InlineFragment in the query AST. It is used to match JSON response with AST node. For more detail, please reference 'removeSyntheticFields'.
|
|
10495
10564
|
if (isInlineFragmentNode(selection) &&
|
|
10496
10565
|
!selection.selectionSet.selections.find((selection) => isFieldNode(selection) && selection.name.value === '__typename')) {
|
|
10497
10566
|
idSelection.push({
|
|
@@ -10525,7 +10594,7 @@ function injectFields(selections, parentNode, ancestors, objectInfos, objectInfo
|
|
|
10525
10594
|
if (isFieldNode(parentNode) && parentNode.selectionSet && parentNode.name.value === 'node') {
|
|
10526
10595
|
if (parentNode.selectionSet.selections
|
|
10527
10596
|
.filter(isFieldOrInlineFragmentNode)
|
|
10528
|
-
.some((selectionNode) => isRelationship(selectionNode,
|
|
10597
|
+
.some((selectionNode) => isRelationship(selectionNode, CHILD_RELATIONSHIP))) {
|
|
10529
10598
|
if (!parentNode.selectionSet.selections
|
|
10530
10599
|
.filter(isFieldNode)
|
|
10531
10600
|
.some((sibling) => sibling.name.value === 'Id')) {
|
|
@@ -10544,15 +10613,15 @@ function injectFields(selections, parentNode, ancestors, objectInfos, objectInfo
|
|
|
10544
10613
|
if (parentInfo.parentIndex >= 0) {
|
|
10545
10614
|
// example node { TimeSheetEntries { edges { node { Id }}}}
|
|
10546
10615
|
const parent = parentInfo.node;
|
|
10547
|
-
if (isRelationship(parent,
|
|
10616
|
+
if (isRelationship(parent, CHILD_RELATIONSHIP)) {
|
|
10548
10617
|
const unVisitedAncestors = ancestors.slice(0, parentInfo.parentIndex);
|
|
10549
10618
|
// path : "TimeSheet"
|
|
10550
10619
|
const grandParentPath = findAncesterPath(unVisitedAncestors);
|
|
10551
|
-
if (
|
|
10552
|
-
|
|
10620
|
+
if (pathToObjectApiNamesMap &&
|
|
10621
|
+
pathToObjectApiNamesMap[grandParentPath] &&
|
|
10553
10622
|
objectInfos &&
|
|
10554
|
-
objectInfos[
|
|
10555
|
-
const grandParentObjectInfo = objectInfos[
|
|
10623
|
+
objectInfos[pathToObjectApiNamesMap[grandParentPath][0]]) {
|
|
10624
|
+
const grandParentObjectInfo = objectInfos[pathToObjectApiNamesMap[grandParentPath][0]];
|
|
10556
10625
|
// exmaple "TimeSheetEntries"
|
|
10557
10626
|
const parentFieldName = parent.name.value;
|
|
10558
10627
|
const targetRelationship = grandParentObjectInfo.childRelationships.find((childRelationship) => {
|
|
@@ -10673,7 +10742,7 @@ const assignedToMeFragmentSelections = [
|
|
|
10673
10742
|
},
|
|
10674
10743
|
value: {
|
|
10675
10744
|
kind: 'StringValue',
|
|
10676
|
-
value:
|
|
10745
|
+
value: CHILD_RELATIONSHIP,
|
|
10677
10746
|
block: false,
|
|
10678
10747
|
},
|
|
10679
10748
|
},
|
|
@@ -10765,7 +10834,7 @@ const assignedToMeFragmentSelections = [
|
|
|
10765
10834
|
},
|
|
10766
10835
|
value: {
|
|
10767
10836
|
kind: 'StringValue',
|
|
10768
|
-
value:
|
|
10837
|
+
value: PARENT_RELATIONSHIP,
|
|
10769
10838
|
block: false,
|
|
10770
10839
|
},
|
|
10771
10840
|
},
|
|
@@ -10902,7 +10971,9 @@ function handleNonArrayJsonProperty(selection, fieldName, jsonInput, jsonOutput)
|
|
|
10902
10971
|
jsonOutput[fieldName] = null;
|
|
10903
10972
|
return;
|
|
10904
10973
|
}
|
|
10905
|
-
jsonOutput[fieldName]
|
|
10974
|
+
if (jsonOutput[fieldName] === undefined) {
|
|
10975
|
+
jsonOutput[fieldName] = {};
|
|
10976
|
+
}
|
|
10906
10977
|
createUserJsonOutput(selection, jsonInput[fieldName], jsonOutput[fieldName]);
|
|
10907
10978
|
}
|
|
10908
10979
|
else {
|
|
@@ -15910,6 +15981,9 @@ class PrimingSession extends EventEmitter {
|
|
|
15910
15981
|
this.ldsRecordRefresher = config.ldsRecordRefresher;
|
|
15911
15982
|
this.networkWorkerPool = new AsyncWorkerPool(this.concurrency);
|
|
15912
15983
|
this.useBatchGQL = ldsPrimingGraphqlBatch.isOpen({ fallback: false });
|
|
15984
|
+
if (this.useBatchGQL) {
|
|
15985
|
+
this.batchSize = this.batchSize / DEFAULT_GQL_QUERY_BATCH_SIZE;
|
|
15986
|
+
}
|
|
15913
15987
|
this.conflictPool = new ConflictPool(config.store, this.objectInfoLoader);
|
|
15914
15988
|
}
|
|
15915
15989
|
// function that enqueues priming work
|
|
@@ -16771,4 +16845,4 @@ register({
|
|
|
16771
16845
|
});
|
|
16772
16846
|
|
|
16773
16847
|
export { getRuntime, registerReportObserver, reportGraphqlQueryParseError };
|
|
16774
|
-
// version: 1.229.0-
|
|
16848
|
+
// version: 1.229.0-dev4-07d38781a
|