@salesforce/lds-runtime-mobile 1.229.0-dev2 → 1.229.0-dev3

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.
Files changed (3) hide show
  1. package/dist/main.js +222 -148
  2. package/package.json +18 -18
  3. 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 === 'recordQuery'));
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 findNearestRecordQuery(ancestors) {
8082
- const recordQueryAncester = findNearestAncesterPath(ancestors, true).node;
8083
- return recordQueryAncester === undefined ? undefined : recordQueryAncester;
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 cloeset ancester. If 'parentRelationship' is allowed, it could be 'InlineFragmentNode' since it inherits the 'parent' relationship. 'InlineFragmentNode' makes sure that only one 'apiName' returns when tree is traversed.
8086
- function findNearestAncesterPath(ancestors, recordQueryOnly) {
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 === 'recordQuery' ||
8101
- arg.value.value === 'childRelationship' ||
8102
- (!recordQueryOnly && arg.value.value === 'parentRelationship'))) {
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 === 'parentRelationship') {
8118
- //
8119
- if (recordQueryPath.node.selectionSet.selections.every(isInlineFragmentNode)) {
8120
- //
8121
- const inlineFragmentLoc = recordQueryPath.parentIndex + 2;
8122
- if (inlineFragmentLoc < ancestors.length && ancestors[inlineFragmentLoc]) {
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[inlineFragmentLoc],
8125
- parentIndex: inlineFragmentLoc,
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}_${path}`;
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 === 'childRelationship' ||
8210
- valueNode.value === 'parentRelationship' ||
8211
- valueNode.value === 'polymorphicParentRelationship')
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, 'parentRelationship') ||
8269
- isRelationship(node, 'polymorphicParentRelationship')));
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: 'parentRelationship',
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']; 'ServiceAppointment_Account' -> ['Account']; 'ServiceAppointment_Account_Owner' -> ['User']
9376
- const objectInfoApiMap = {};
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 recordQueryNode = findNearestRecordQuery(ancestors);
9391
- if (!recordQueryNode)
9424
+ const { connection: recordConnectionNode, path: ancesterPath } = findNearestConnectionWithPath(ancestors);
9425
+ if (!recordConnectionNode || !ancesterPath)
9392
9426
  return;
9393
- if (!objectNodeInfoTree[recordQueryNode.name.value]) {
9394
- objectNodeInfoTree[recordQueryNode.name.value] = [];
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(recordQueryNode.name.value);
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(recordQueryNode)) {
9405
- startNodes.add(recordQueryNode.name.value);
9438
+ if (isRecordQuery(recordConnectionNode)) {
9439
+ startNodes.add(recordConnectionNode.name.value);
9406
9440
  }
9407
- growObjectFieldTree(objectNodeInfoTree, recordQueryNode.name.value, node.value, totalNodes, startNodes);
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
- if (!objectNodeInfoTree['ServiceResources'].some((child) => child.name === 'ServiceResource')) {
9426
- objectNodeInfoTree['ServiceResources'].push({
9427
- relation: 'parent',
9428
- name: 'ServiceResource',
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 = findNearestRecordQuery(ancestors);
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, objectInfoApiMap, startNodes, objectInfoService);
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 = findNearestRecordQuery(ancestors);
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 = objectInfoApiMap[ancestorPath]
9471
- ? objectInfoApiMap[ancestorPath][0]
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, objectInfoApiMap, objectInfos)) {
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, objectInfoApiMap, draftFunctions, recordReferenceNode),
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 = findNearestRecordQuery(ancestors);
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, objectInfoApiMap);
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 = findNearestRecordQuery(ancestors);
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 = findNearestRecordQuery(ancestors);
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 = objectInfoApiMap[ancestorPath]
9571
- ? objectInfoApiMap[ancestorPath][0]
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 = objectInfoApiMap[ancestorPath][0];
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, objectInfoApiMap, objectInfos) {
9675
- const apiName = objectInfoApiMap[apiNamePath];
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(childNode);
9803
+ totalNodes.add(childNodepath);
9770
9804
  }
9771
9805
  // recursively go to deeper level of filter.
9772
- growObjectFieldTree(tree, childNode, objectFieldNode.value, totalNodes, startNodes);
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 === 'parentRelationship' ||
9808
- relationType === 'polymorphicParentRelationship'
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
- growFieldTree(tree, fieldName, child, entryNode, totalNodes, startNodes);
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 === 'parentRelationship' ||
9850
- relationType === 'polymorphicParentRelationship'
9884
+ relation: relationType === PARENT_RELATIONSHIP ||
9885
+ relationType === POLYMORPHIC_PARENT_RELATIONSHIP
9851
9886
  ? 'parent'
9852
9887
  : 'child',
9853
9888
  name: conditionName,
9854
9889
  });
9855
- totalNodes.add(conditionName);
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.typeCondition
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, objectInfoApiMap, startNodes, objectInfoService) {
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
- objectInfoApiMap[startNode] = [startNode];
9926
+ pathToObjectApiNamesMap[startNode] = [startNode];
9892
9927
  const children = objectInfotree[startNode];
9893
- const subObjectInfoMap = await fetchObjectInfos(objectInfotree, objectInfoApiMap, objectInfos, children, startNode, objectInfoService);
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, objectInfoApiMap, objectInfoMap, nodesAtSameLevel, parentPath, objectInfoService) {
9902
- const objectInfoApiNames = objectInfoApiMap[parentPath];
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 ObjectInfoApiMap Entry: 'ServiceAppointment_Owner' -> ['User', 'Group']; ServiceAppointment_Owner_User' -> ['User']
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}_${field.name}`;
9922
- objectInfoApiMap[path] = [field.name];
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}_${field}`;
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[field]) {
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[field];
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[field]) {
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 (!objectInfoApiMap[path]) {
9965
- objectInfoApiMap[path] = [];
9999
+ if (!pathToObjectApiNamesMap[path]) {
10000
+ pathToObjectApiNamesMap[path] = [];
9966
10001
  }
9967
10002
  // 'ServiceAppointment_Owner' ->['User', 'Group']
9968
- if (!objectInfoApiMap[path].includes(ref.apiName)) {
9969
- objectInfoApiMap[path].push(ref.apiName);
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 (!objectInfoApiMap[path]) {
9980
- objectInfoApiMap[path] = [];
10014
+ if (!pathToObjectApiNamesMap[path]) {
10015
+ pathToObjectApiNamesMap[path] = [];
9981
10016
  }
9982
- if (!objectInfoApiMap[path].includes(ref.apiName)) {
9983
- objectInfoApiMap[path].push(ref.apiName);
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 (!objectInfoApiMap[path]) {
9995
- objectInfoApiMap[path] = [];
10029
+ if (!pathToObjectApiNamesMap[path]) {
10030
+ pathToObjectApiNamesMap[path] = [];
9996
10031
  }
9997
- if (!objectInfoApiMap[path].includes(childRelationship.childObjectApiName)) {
9998
- objectInfoApiMap[path].push(childRelationship.childObjectApiName);
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 subLevelFields = objectInfotree[field];
10021
- const path = `${parentPath}_${field}`;
10055
+ const path = `${parentPath}#${field}`;
10056
+ const subLevelFields = objectInfotree[path];
10022
10057
  if (subLevelFields && subLevelFields.length > 0) {
10023
- const subObjectInfos = await fetchObjectInfos(objectInfotree, objectInfoApiMap, updatedObjectInfoMap, subLevelFields, path, objectInfoService);
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 path path to the current filterNode's parent. For example, path could be 'ServiceApointment' when filterNode is 'State'. If the path does not exist in 'objectInfoApiMap', parent node is not an field of relationship or recordQuery
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 objectInfoApiMap 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'].
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, path, objectInfos, objectInfoApiMap, draftFunctions, queryNode) {
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, path, objectInfos, objectInfoApiMap, draftFunctions, queryNode);
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(path);
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, path, objectInfos, objectInfoApiMap, draftFunctions, queryNode);
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, path, objectInfos, objectInfoApiMap, draftFunctions, queryNode);
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 = objectInfoApiMap[path];
10089
- // example: path: 'ServiceAppointment_LastModifiedDate'; filterNode: '{eq: {literal: LAST_WEEK}}'. queryNode: 'LastModifedDate { value}' FilterNode's parent has been verifed as a valid node
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 ${path}`);
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 = `${path}_${fieldName}`;
10124
- if (objectInfoApiMap[curPath] && objectInfoApiMap[curPath].length > 0) {
10160
+ curPath = `${parentPath}#${fieldName}`;
10161
+ if (pathToObjectApiNamesMap[curPath] &&
10162
+ pathToObjectApiNamesMap[curPath].length > 0) {
10125
10163
  isSpanning = true;
10126
- if (objectInfoApiMap[curPath].length === 1) {
10127
- if (objectInfoApiMap[path] &&
10128
- objectInfoApiMap[path].length >= 1 &&
10129
- objectInfoApiMap[path].includes(objectInfoApiMap[curPath][0])) {
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 = objectInfoApiMap[curPath] !== undefined
10185
- ? objectInfoApiMap[curPath][0]
10186
- : objectInfoApiMap[path][0];
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, objectInfoApiMap, draftFunctions, existingFields ? existingFields[0] : undefined);
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 objectInfoApiMap 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'].
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, objectInfoApiMap) {
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, objectInfoApiMap);
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 = selection.selectionSet.selections.every(isInlineFragmentNode);
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 polymorphic fields. '__typename' field acts as a reference to concrete type of a polymorphic field and is used to match JSON response with AST node. For more detail,
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, 'childRelationship'))) {
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, 'childRelationship')) {
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 (objectInfoApiMap &&
10552
- objectInfoApiMap[grandParentPath] &&
10620
+ if (pathToObjectApiNamesMap &&
10621
+ pathToObjectApiNamesMap[grandParentPath] &&
10553
10622
  objectInfos &&
10554
- objectInfos[objectInfoApiMap[grandParentPath][0]]) {
10555
- const grandParentObjectInfo = objectInfos[objectInfoApiMap[grandParentPath][0]];
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: 'childRelationship',
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: 'parentRelationship',
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-dev2-e9832aaff
16848
+ // version: 1.229.0-dev3-175ac936b