@salesforce/lds-runtime-mobile 1.242.0 → 1.242.1

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 +179 -112
  2. package/package.json +3 -3
  3. package/sfdc/main.js +179 -112
package/dist/main.js CHANGED
@@ -554,6 +554,9 @@ function handleDurableStoreRejection(instrument) {
554
554
  }
555
555
 
556
556
  function isStoreEntryError(storeRecord) {
557
+ if (!storeRecord || typeof storeRecord !== 'object') {
558
+ return false;
559
+ }
557
560
  return storeRecord.__type === 'error';
558
561
  }
559
562
 
@@ -8161,6 +8164,10 @@ function isOperationDefinitionNode(node) {
8161
8164
  return node.kind === 'OperationDefinition';
8162
8165
  }
8163
8166
 
8167
+ const POLYMORPHIC_PARENT_RELATIONSHIP = 'polymorphicParentRelationship';
8168
+ const PARENT_RELATIONSHIP = 'parentRelationship';
8169
+ const CHILD_RELATIONSHIP = 'childRelationship';
8170
+ const RECORD_QUERY = 'recordQuery';
8164
8171
  function requestsDraftsField(recordFieldNode) {
8165
8172
  if (!recordFieldNode.selectionSet)
8166
8173
  return false;
@@ -8176,18 +8183,41 @@ function isRecordQuery(recordQueryField) {
8176
8183
  directive.arguments
8177
8184
  .map((argument) => argument.value)
8178
8185
  .filter(isStringValueNode)
8179
- .some((categoryName) => categoryName.value === 'recordQuery'));
8186
+ .some((categoryName) => categoryName.value === RECORD_QUERY));
8180
8187
  });
8181
8188
  }
8182
8189
  return false;
8183
8190
  }
8184
- // finds field with 'recordQuery' and 'childRelationship' directive
8185
- function findNearestRecordQuery(ancestors) {
8186
- const recordQueryAncester = findNearestAncesterPath(ancestors, true).node;
8187
- return recordQueryAncester === undefined ? undefined : recordQueryAncester;
8191
+ // finds connection field with 'recordQuery' and 'childRelationship' directive.
8192
+ function findNearestConnection(ancestors) {
8193
+ const connectionAncestor = findNearestAncesterPath(ancestors, true).node;
8194
+ return connectionAncestor === undefined ? undefined : connectionAncestor;
8195
+ }
8196
+ // convinient method to find nearest connection with its path
8197
+ function findNearestConnectionWithPath(ancestors) {
8198
+ const closestAncestorPath = findNearestAncesterPath(ancestors, true);
8199
+ let connection = undefined;
8200
+ let connectionPath = undefined;
8201
+ if (closestAncestorPath.parentIndex > 0) {
8202
+ const connectionAncestor = closestAncestorPath.node;
8203
+ const connectionAncestors = ancestors.slice(0, closestAncestorPath.parentIndex);
8204
+ connection =
8205
+ connectionAncestor === undefined ? undefined : connectionAncestor;
8206
+ if (connection !== undefined) {
8207
+ const ancesterPath = findAncesterPath(connectionAncestors);
8208
+ connectionPath =
8209
+ ancesterPath === ''
8210
+ ? connection.name.value
8211
+ : `${ancesterPath}#${connection.name.value}`;
8212
+ }
8213
+ }
8214
+ return {
8215
+ connection,
8216
+ path: connectionPath,
8217
+ };
8188
8218
  }
8189
- // 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.
8190
- function findNearestAncesterPath(ancestors, recordQueryOnly) {
8219
+ // 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.
8220
+ function findNearestAncesterPath(ancestors, connectionOnly) {
8191
8221
  let recordQueryPath = { node: undefined, parentIndex: -1 };
8192
8222
  let relationship = '';
8193
8223
  for (let i = ancestors.length - 1; i >= 0; i--) {
@@ -8201,9 +8231,11 @@ function findNearestAncesterPath(ancestors, recordQueryOnly) {
8201
8231
  continue;
8202
8232
  for (let arg of directive.arguments) {
8203
8233
  if (arg.value &&
8204
- (arg.value.value === 'recordQuery' ||
8205
- arg.value.value === 'childRelationship' ||
8206
- (!recordQueryOnly && arg.value.value === 'parentRelationship'))) {
8234
+ (arg.value.value === RECORD_QUERY ||
8235
+ arg.value.value === CHILD_RELATIONSHIP ||
8236
+ (!connectionOnly &&
8237
+ (arg.value.value === PARENT_RELATIONSHIP ||
8238
+ arg.value.value === POLYMORPHIC_PARENT_RELATIONSHIP)))) {
8207
8239
  recordQueryPath = { node: node, parentIndex: i };
8208
8240
  relationship = arg.value.value;
8209
8241
  break;
@@ -8218,17 +8250,19 @@ function findNearestAncesterPath(ancestors, recordQueryOnly) {
8218
8250
  //checks if nearest ancester could be an inline fragment
8219
8251
  if (recordQueryPath.node !== undefined &&
8220
8252
  recordQueryPath.node.selectionSet &&
8221
- relationship === 'parentRelationship') {
8222
- //
8223
- if (recordQueryPath.node.selectionSet.selections.every(isInlineFragmentNode)) {
8224
- //
8225
- const inlineFragmentLoc = recordQueryPath.parentIndex + 2;
8226
- if (inlineFragmentLoc < ancestors.length && ancestors[inlineFragmentLoc]) {
8253
+ (relationship === PARENT_RELATIONSHIP || relationship === POLYMORPHIC_PARENT_RELATIONSHIP)) {
8254
+ // InlineFragment is usually 3 steps aways from its FieldNode parent within ancester hierarchy if it exists. The below search
8255
+ // is applied to adapt to future AST structure change
8256
+ let parentIndex = recordQueryPath.parentIndex + 1;
8257
+ while (parentIndex < ancestors.length) {
8258
+ if (isInlineFragmentNode(ancestors[parentIndex])) {
8227
8259
  recordQueryPath = {
8228
- node: ancestors[inlineFragmentLoc],
8229
- parentIndex: inlineFragmentLoc,
8260
+ node: ancestors[parentIndex],
8261
+ parentIndex,
8230
8262
  };
8263
+ break;
8231
8264
  }
8265
+ parentIndex++;
8232
8266
  }
8233
8267
  }
8234
8268
  return recordQueryPath;
@@ -8252,7 +8286,7 @@ function findAncesterPath(ancesters) {
8252
8286
  ? sectionPath
8253
8287
  : sectionPath === ''
8254
8288
  ? path
8255
- : `${sectionPath}_${path}`;
8289
+ : `${sectionPath}#${path}`;
8256
8290
  }
8257
8291
  }
8258
8292
  boundaryIndex = parentIndex;
@@ -8310,9 +8344,9 @@ function getRelation(node) {
8310
8344
  const relationships = args
8311
8345
  .map((arg) => arg.value)
8312
8346
  .filter(isStringValueNode)
8313
- .filter((valueNode) => valueNode.value === 'childRelationship' ||
8314
- valueNode.value === 'parentRelationship' ||
8315
- valueNode.value === 'polymorphicParentRelationship')
8347
+ .filter((valueNode) => valueNode.value === CHILD_RELATIONSHIP ||
8348
+ valueNode.value === PARENT_RELATIONSHIP ||
8349
+ valueNode.value === POLYMORPHIC_PARENT_RELATIONSHIP)
8316
8350
  .map((relationshipNode) => relationshipNode.value);
8317
8351
  if (relationships.length > 0) {
8318
8352
  return relationships[0];
@@ -8369,8 +8403,8 @@ function isFieldSpanning(node, parentNode) {
8369
8403
  */
8370
8404
  function isParentRelationship(node) {
8371
8405
  return (node &&
8372
- (isRelationship(node, 'parentRelationship') ||
8373
- isRelationship(node, 'polymorphicParentRelationship')));
8406
+ (isRelationship(node, PARENT_RELATIONSHIP) ||
8407
+ isRelationship(node, POLYMORPHIC_PARENT_RELATIONSHIP)));
8374
8408
  }
8375
8409
  /*
8376
8410
  checks if the InlineFragment spans
@@ -9462,7 +9496,7 @@ const parentRelationshipDirective = {
9462
9496
  },
9463
9497
  value: {
9464
9498
  kind: Kind.STRING,
9465
- value: 'parentRelationship',
9499
+ value: PARENT_RELATIONSHIP,
9466
9500
  block: false,
9467
9501
  },
9468
9502
  },
@@ -9476,7 +9510,7 @@ async function injectSyntheticFields(originalAST, objectInfoService, draftFuncti
9476
9510
  // example 2 'ServiceAppointment' -> ['Owner']; 'Owner' -> ['User', 'Group']
9477
9511
  const objectNodeInfoTree = {};
9478
9512
  // save the field path to apiName map
9479
- // example 1: 'ServiceAppointment' -> ['ServiceAppointment']; 'ServiceAppointment_Account' -> ['Account']; 'ServiceAppointment_Account_Owner' -> ['User']
9513
+ // example 1: 'ServiceAppointment' -> ['ServiceAppointment']; 'ServiceAppointment#ccount' -> ['Account']; 'ServiceAppointment#Account#Owner' -> ['User']
9480
9514
  const pathToObjectApiNamesMap = {};
9481
9515
  let startNodes = new Set();
9482
9516
  let totalNodes = new Set();
@@ -9491,11 +9525,11 @@ async function injectSyntheticFields(originalAST, objectInfoService, draftFuncti
9491
9525
  visit(originalAST, {
9492
9526
  Argument: {
9493
9527
  enter(node, key, parent, path, ancestors) {
9494
- const recordQueryNode = findNearestRecordQuery(ancestors);
9495
- if (!recordQueryNode)
9528
+ const { connection: recordConnectionNode, path: ancesterPath } = findNearestConnectionWithPath(ancestors);
9529
+ if (!recordConnectionNode || !ancesterPath)
9496
9530
  return;
9497
- if (!objectNodeInfoTree[recordQueryNode.name.value]) {
9498
- objectNodeInfoTree[recordQueryNode.name.value] = [];
9531
+ if (!objectNodeInfoTree[ancesterPath]) {
9532
+ objectNodeInfoTree[ancesterPath] = [];
9499
9533
  }
9500
9534
  switch (node.name.value) {
9501
9535
  case 'orderBy':
@@ -9503,12 +9537,12 @@ async function injectSyntheticFields(originalAST, objectInfoService, draftFuncti
9503
9537
  if (node.value.kind !== 'ObjectValue') {
9504
9538
  return;
9505
9539
  }
9506
- totalNodes.add(recordQueryNode.name.value);
9540
+ totalNodes.add(ancesterPath);
9507
9541
  // 'childRelationship' node is not taken as the startNode of the 'NodeInfoTree' graph. The field scanning will construct the graph which lead here.
9508
- if (isRecordQuery(recordQueryNode)) {
9509
- startNodes.add(recordQueryNode.name.value);
9542
+ if (isRecordQuery(recordConnectionNode)) {
9543
+ startNodes.add(recordConnectionNode.name.value);
9510
9544
  }
9511
- growObjectFieldTree(objectNodeInfoTree, recordQueryNode.name.value, node.value, totalNodes, startNodes);
9545
+ growObjectFieldTree(objectNodeInfoTree, ancesterPath, node.value, totalNodes, startNodes);
9512
9546
  break;
9513
9547
  case 'scope':
9514
9548
  if (!isScopeArgumentNodeWithType(node, 'ASSIGNEDTOME', variables)) {
@@ -9523,17 +9557,16 @@ async function injectSyntheticFields(originalAST, objectInfoService, draftFuncti
9523
9557
  name: 'ServiceResources',
9524
9558
  });
9525
9559
  }
9526
- if (objectNodeInfoTree['ServiceResources'] === undefined) {
9527
- objectNodeInfoTree['ServiceResources'] = [];
9528
- }
9529
- if (!objectNodeInfoTree['ServiceResources'].some((child) => child.name === 'ServiceResource')) {
9530
- objectNodeInfoTree['ServiceResources'].push({
9531
- relation: 'parent',
9532
- name: 'ServiceResource',
9533
- });
9560
+ if (objectNodeInfoTree['ServiceAppointment#ServiceResources'] === undefined) {
9561
+ objectNodeInfoTree['ServiceAppointment#ServiceResources'] = [
9562
+ {
9563
+ relation: 'parent',
9564
+ name: 'ServiceResource',
9565
+ },
9566
+ ];
9534
9567
  }
9535
- if (objectNodeInfoTree['ServiceResource'] === undefined) {
9536
- objectNodeInfoTree['ServiceResource'] = [];
9568
+ if (objectNodeInfoTree['ServiceAppointment#ServiceResources#ServiceResource'] === undefined) {
9569
+ objectNodeInfoTree['ServiceAppointment#ServiceResources#ServiceResource'] = [];
9537
9570
  }
9538
9571
  break;
9539
9572
  default:
@@ -9547,7 +9580,7 @@ async function injectSyntheticFields(originalAST, objectInfoService, draftFuncti
9547
9580
  return;
9548
9581
  if (!node.selectionSet)
9549
9582
  return;
9550
- const recordQueryField = findNearestRecordQuery(ancestors);
9583
+ const recordQueryField = findNearestConnection(ancestors);
9551
9584
  //only injects fields for 'recordQuery' field. ignores the 'childRelationship' field since it will be traversed as the child of the 'recordQuery'
9552
9585
  if (isRecordQuery(recordQueryField) && recordQueryField) {
9553
9586
  totalNodes.add(recordQueryField.name.value);
@@ -9564,7 +9597,7 @@ async function injectSyntheticFields(originalAST, objectInfoService, draftFuncti
9564
9597
  visit(originalAST, {
9565
9598
  Argument: {
9566
9599
  leave(node, key, parent, path, ancestors) {
9567
- const recordQueryField = findNearestRecordQuery(ancestors);
9600
+ const recordQueryField = findNearestConnection(ancestors);
9568
9601
  if (!recordQueryField)
9569
9602
  return;
9570
9603
  const ancestorPath = findAncesterPath(ancestors);
@@ -9612,7 +9645,7 @@ async function injectSyntheticFields(originalAST, objectInfoService, draftFuncti
9612
9645
  case 'where': {
9613
9646
  inlineFragmentSelections[ancestorPath] = [
9614
9647
  ...inlineFragmentSelections[ancestorPath],
9615
- ...injectFilter(node, idState, ancestorPath, objectInfos, pathToObjectApiNamesMap, draftFunctions, recordReferenceNode),
9648
+ ...injectFilter(node, idState, ancestorPath, false, objectInfos, pathToObjectApiNamesMap, draftFunctions, recordReferenceNode),
9616
9649
  ];
9617
9650
  break;
9618
9651
  }
@@ -9628,7 +9661,7 @@ async function injectSyntheticFields(originalAST, objectInfoService, draftFuncti
9628
9661
  if (!node.selectionSet)
9629
9662
  return;
9630
9663
  // it could be 'recordQuery' or 'childRelationship'
9631
- const recordQueryField = findNearestRecordQuery(ancestors);
9664
+ const recordQueryField = findNearestConnection(ancestors);
9632
9665
  if (!recordQueryField)
9633
9666
  return;
9634
9667
  const ancestorPath = findAncesterPath(ancestors);
@@ -9640,7 +9673,7 @@ async function injectSyntheticFields(originalAST, objectInfoService, draftFuncti
9640
9673
  spanningSelections.push(selection);
9641
9674
  }
9642
9675
  }
9643
- const injectedFields = injectFields(spanningSelections, node, ancestors, objectInfos, pathToObjectApiNamesMap);
9676
+ const injectedFields = injectFields(spanningSelections, node, ancestorPath, ancestors, objectInfos, pathToObjectApiNamesMap);
9644
9677
  const mergedInjectedFields = mergeSelectionNodes(inlineFragmentSelections[ancestorPath], injectedFields);
9645
9678
  inlineFragmentSelections[ancestorPath] = mergedInjectedFields;
9646
9679
  },
@@ -9653,7 +9686,7 @@ async function injectSyntheticFields(originalAST, objectInfoService, draftFuncti
9653
9686
  // removes 'ServicesResources' query field node if 'assignedtome' scope shows up
9654
9687
  if (assignedtomeQueryFieldNode !== undefined &&
9655
9688
  node.name.value === 'ServiceResources') {
9656
- const serviceResourcesAncestor = findNearestRecordQuery(ancestors);
9689
+ const serviceResourcesAncestor = findNearestConnection(ancestors);
9657
9690
  if (serviceResourcesAncestor === assignedtomeQueryFieldNode) {
9658
9691
  return null;
9659
9692
  }
@@ -9662,7 +9695,7 @@ async function injectSyntheticFields(originalAST, objectInfoService, draftFuncti
9662
9695
  return;
9663
9696
  if (!node.selectionSet)
9664
9697
  return;
9665
- const recordQueryField = findNearestRecordQuery(ancestors);
9698
+ const recordQueryField = findNearestConnection(ancestors);
9666
9699
  if (!recordQueryField)
9667
9700
  return;
9668
9701
  const ancestorPath = findAncesterPath(ancestors);
@@ -9865,15 +9898,16 @@ function growObjectFieldTree(tree, parentNode, entryNode, totalNodes, startNodes
9865
9898
  }
9866
9899
  // example: 'Account'
9867
9900
  const childNode = objectFieldNode.name.value;
9901
+ const childNodepath = `${parentNode}#${childNode}`;
9868
9902
  if (!tree[parentNode].some((child) => child.name === childNode)) {
9869
9903
  tree[parentNode].push({
9870
9904
  relation: 'parent',
9871
9905
  name: childNode,
9872
9906
  });
9873
- totalNodes.add(childNode);
9907
+ totalNodes.add(childNodepath);
9874
9908
  }
9875
9909
  // recursively go to deeper level of filter.
9876
- growObjectFieldTree(tree, childNode, objectFieldNode.value, totalNodes, startNodes);
9910
+ growObjectFieldTree(tree, childNodepath, objectFieldNode.value, totalNodes, startNodes);
9877
9911
  }
9878
9912
  }
9879
9913
  }
@@ -9908,19 +9942,20 @@ function growFieldTree(tree, parentSectionPath, entryNode, parentNode, totalNode
9908
9942
  }
9909
9943
  if (!tree[parentSectionPath].some((field) => field.name === fieldName)) {
9910
9944
  tree[parentSectionPath].push({
9911
- relation: relationType === 'parentRelationship' ||
9912
- relationType === 'polymorphicParentRelationship'
9945
+ relation: relationType === PARENT_RELATIONSHIP ||
9946
+ relationType === POLYMORPHIC_PARENT_RELATIONSHIP
9913
9947
  ? 'parent'
9914
9948
  : 'child',
9915
9949
  name: fieldName,
9916
9950
  });
9917
- totalNodes.add(fieldName);
9951
+ totalNodes.add(`${parentSectionPath}#${fieldName}`);
9918
9952
  }
9919
9953
  if (entryNode.selectionSet && entryNode.selectionSet.selections) {
9920
9954
  const childNodes = entryNode.selectionSet.selections.filter(isFieldOrInlineFragmentNode);
9921
9955
  // recursively build the traversal tree
9922
9956
  for (const child of childNodes) {
9923
- growFieldTree(tree, fieldName, child, entryNode, totalNodes, startNodes);
9957
+ const path = `${parentSectionPath}#${fieldName}`;
9958
+ growFieldTree(tree, path, child, entryNode, totalNodes, startNodes);
9924
9959
  }
9925
9960
  }
9926
9961
  }
@@ -9950,23 +9985,23 @@ function growFieldTree(tree, parentSectionPath, entryNode, parentNode, totalNode
9950
9985
  }
9951
9986
  if (!tree[parentSectionPath].some((field) => field.name === conditionName)) {
9952
9987
  tree[parentSectionPath].push({
9953
- relation: relationType === 'parentRelationship' ||
9954
- relationType === 'polymorphicParentRelationship'
9988
+ relation: relationType === PARENT_RELATIONSHIP ||
9989
+ relationType === POLYMORPHIC_PARENT_RELATIONSHIP
9955
9990
  ? 'parent'
9956
9991
  : 'child',
9957
9992
  name: conditionName,
9958
9993
  });
9959
- totalNodes.add(conditionName);
9994
+ const path = `${parentSectionPath}#${conditionName}`;
9995
+ totalNodes.add(path);
9960
9996
  }
9961
9997
  }
9962
9998
  }
9963
9999
  // dive deep immediately for 'InlineFragment'
9964
10000
  const childNodes = entryNode.selectionSet.selections.filter(isFieldOrInlineFragmentNode);
10001
+ const path = `${parentSectionPath}${entryNode.typeCondition ? '#' + entryNode.typeCondition.name.value : ''}`;
9965
10002
  // Navigates into InLineFragment
9966
10003
  for (const child of childNodes) {
9967
- growFieldTree(tree, entryNode.typeCondition
9968
- ? entryNode.typeCondition.name.value
9969
- : parentSectionPath, child, entryNode, totalNodes, startNodes);
10004
+ growFieldTree(tree, path, child, entryNode, totalNodes, startNodes);
9970
10005
  }
9971
10006
  }
9972
10007
  }
@@ -10010,7 +10045,7 @@ async function fetchObjectInfos(objectInfotree, pathToObjectApiNamesMap, objectI
10010
10045
  }
10011
10046
  const validObjectInfoNodes = [];
10012
10047
  let updatedObjectInfoMap = {};
10013
- // InlineFragment and polymorphic field support fits into this scenario pathToObjectApiNamesMap Entry: 'ServiceAppointment_Owner' -> ['User', 'Group']; ServiceAppointment_Owner_User' -> ['User']
10048
+ // InlineFragment and polymorphic field support fits into this scenario pathToObjectApiNamesMap Entry: 'ServiceAppointment#Owner' -> ['User', 'Group']; ServiceAppointment#Owner#User' -> ['User']
10014
10049
  if (objectInfoApiNames.length > 0 &&
10015
10050
  nodesAtSameLevel.length > 0 &&
10016
10051
  objectInfoApiNames.includes(nodesAtSameLevel[0].name)) {
@@ -10022,7 +10057,7 @@ async function fetchObjectInfos(objectInfotree, pathToObjectApiNamesMap, objectI
10022
10057
  // eslint-disable-next-line
10023
10058
  throw new Error(`Condition ${field.name} does not exists for ${parentPath}`);
10024
10059
  }
10025
- const path = `${parentPath}_${field.name}`;
10060
+ const path = `${parentPath}#${field.name}`;
10026
10061
  pathToObjectApiNamesMap[path] = [field.name];
10027
10062
  }
10028
10063
  validObjectInfoNodes.push(...nodesAtSameLevel);
@@ -10038,7 +10073,7 @@ async function fetchObjectInfos(objectInfotree, pathToObjectApiNamesMap, objectI
10038
10073
  let apiNames = [];
10039
10074
  for (const nodeInfo of nodesAtSameLevel) {
10040
10075
  const field = nodeInfo.name;
10041
- const path = `${parentPath}_${field}`;
10076
+ const path = `${parentPath}#${field}`;
10042
10077
  // Handle 'parentRelationship'
10043
10078
  if (nodeInfo.relation === 'parent') {
10044
10079
  const relationshipId = referenceIdFieldForRelationship(field);
@@ -10056,12 +10091,12 @@ async function fetchObjectInfos(objectInfotree, pathToObjectApiNamesMap, objectI
10056
10091
  }
10057
10092
  }
10058
10093
  // This is a polymorphic field
10059
- if (fieldDefinition.referenceToInfos.length > 1 && objectInfotree[field]) {
10094
+ if (fieldDefinition.referenceToInfos.length > 1 && objectInfotree[path]) {
10060
10095
  // Fields needs to expand and heterogenous entity ObjectInfo needs to be fetched
10061
- const referencedNodeInfos = objectInfotree[field];
10096
+ const referencedNodeInfos = objectInfotree[path];
10062
10097
  const requestedApiNames = referencedNodeInfos.map((referenceNodeInfo) => referenceNodeInfo.name);
10063
10098
  // 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.
10064
- if (requestedApiNames.length > 0 && objectInfotree[field]) {
10099
+ if (requestedApiNames.length > 0 && objectInfotree[path]) {
10065
10100
  fieldDefinition.referenceToInfos
10066
10101
  .filter((referenceToInfo) => requestedApiNames.includes(referenceToInfo.apiName))
10067
10102
  .forEach((ref) => {
@@ -10121,8 +10156,8 @@ async function fetchObjectInfos(objectInfotree, pathToObjectApiNamesMap, objectI
10121
10156
  }
10122
10157
  for (const nodeInfo of validObjectInfoNodes) {
10123
10158
  const field = nodeInfo.name;
10124
- const subLevelFields = objectInfotree[field];
10125
- const path = `${parentPath}_${field}`;
10159
+ const path = `${parentPath}#${field}`;
10160
+ const subLevelFields = objectInfotree[path];
10126
10161
  if (subLevelFields && subLevelFields.length > 0) {
10127
10162
  const subObjectInfos = await fetchObjectInfos(objectInfotree, pathToObjectApiNamesMap, updatedObjectInfoMap, subLevelFields, path, objectInfoService);
10128
10163
  updatedObjectInfoMap = { ...updatedObjectInfoMap, ...subObjectInfos };
@@ -10139,27 +10174,29 @@ async function fetchObjectInfos(objectInfotree, pathToObjectApiNamesMap, objectI
10139
10174
  * 'path' and 'queryNode' is 1 level above the 'filterNode'
10140
10175
  * @param filterNode filter node which needs to be injected. For example, 'State' ObjectFieldNode within filter 'where: { State: { eq: "Nova Scotia" }}'
10141
10176
  * @param idState ID state will be updated to determine if the ID fields in AST need to be swapped. The swapping happens later.
10142
- * @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 'pathToObjectApiNamesMap', parent node is not an field of relationship or recordQuery
10177
+ * @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
10178
+ * @param isParentPolymorphic true if parent points to a polymorphic field.
10143
10179
  * @param queryNode referece FieldNode which provides the information if 'filterNode' exist in it nor not.
10144
10180
  * @param objectInfos ObjectInfo map used in injection. If ObjectInfo misses or field does not exist in ObjectInfo, the error will be thrown
10145
10181
  * @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'].
10146
10182
  * @param draftFunctions functions for working with record ids that may be draft-created ids
10147
10183
  * @returns an array of nodes with injected fields
10148
10184
  */
10149
- function injectFilter(filterNode, idState, path, objectInfos, pathToObjectApiNamesMap, draftFunctions, queryNode) {
10185
+ function injectFilter(filterNode, idState, parentPath, isParentPolymorphic, objectInfos, pathToObjectApiNamesMap, draftFunctions, queryNode) {
10150
10186
  const injectedSelections = [];
10187
+ let isPolymorphicField = false;
10151
10188
  switch (filterNode.kind) {
10152
10189
  case Kind.ARGUMENT:
10153
10190
  if (filterNode.value.kind !== 'ObjectValue')
10154
10191
  return [];
10155
10192
  filterNode.value.fields.forEach((objectFieldNode) => {
10156
- let subResults = injectFilter(objectFieldNode, idState, path, objectInfos, pathToObjectApiNamesMap, draftFunctions, queryNode);
10193
+ let subResults = injectFilter(objectFieldNode, idState, parentPath, isParentPolymorphic, objectInfos, pathToObjectApiNamesMap, draftFunctions, queryNode);
10157
10194
  for (const subResult of subResults) {
10158
10195
  mergeOrAddToGroup(injectedSelections, subResult);
10159
10196
  }
10160
10197
  // multiple Ids might need to be swapped. remember their paths for faster write.
10161
10198
  if (idState.swapNeeded) {
10162
- idState.paths.push(path);
10199
+ idState.paths.push(parentPath);
10163
10200
  }
10164
10201
  });
10165
10202
  return injectedSelections;
@@ -10168,7 +10205,7 @@ function injectFilter(filterNode, idState, path, objectInfos, pathToObjectApiNam
10168
10205
  case Kind.LIST: {
10169
10206
  filterNode.value.values.filter(isObjectValueNode).forEach((objectValueNode) => {
10170
10207
  objectValueNode.fields.forEach((objectFieldNode) => {
10171
- const subResults = injectFilter(objectFieldNode, idState, path, objectInfos, pathToObjectApiNamesMap, draftFunctions, queryNode);
10208
+ const subResults = injectFilter(objectFieldNode, idState, parentPath, isParentPolymorphic, objectInfos, pathToObjectApiNamesMap, draftFunctions, queryNode);
10172
10209
  for (const subResult of subResults) {
10173
10210
  mergeOrAddToGroup(injectedSelections, subResult);
10174
10211
  }
@@ -10179,7 +10216,7 @@ function injectFilter(filterNode, idState, path, objectInfos, pathToObjectApiNam
10179
10216
  case Kind.OBJECT: {
10180
10217
  if (filterNode.name.value === 'not') {
10181
10218
  filterNode.value.fields.forEach((objectFieldNode) => {
10182
- const subResults = injectFilter(objectFieldNode, idState, path, objectInfos, pathToObjectApiNamesMap, draftFunctions, queryNode);
10219
+ const subResults = injectFilter(objectFieldNode, idState, parentPath, isParentPolymorphic, objectInfos, pathToObjectApiNamesMap, draftFunctions, queryNode);
10183
10220
  for (const subResult of subResults) {
10184
10221
  mergeOrAddToGroup(injectedSelections, subResult);
10185
10222
  }
@@ -10189,15 +10226,15 @@ function injectFilter(filterNode, idState, path, objectInfos, pathToObjectApiNam
10189
10226
  let apiNames = [];
10190
10227
  let isScalarField = false;
10191
10228
  //It is possible that this is a polymorphic field
10192
- apiNames = pathToObjectApiNamesMap[path];
10193
- // example: path: 'ServiceAppointment_LastModifiedDate'; filterNode: '{eq: {literal: LAST_WEEK}}'. queryNode: 'LastModifedDate { value}' FilterNode's parent has been verifed as a valid node
10229
+ apiNames = pathToObjectApiNamesMap[parentPath];
10230
+ // example: path: 'ServiceAppointment#LastModifiedDate'; filterNode: '{eq: {literal: LAST_WEEK}}'. queryNode: 'LastModifedDate { value}' FilterNode's parent has been verifed as a valid node
10194
10231
  if (apiNames === undefined) {
10195
10232
  isScalarField = true;
10196
10233
  }
10197
10234
  else {
10198
10235
  if (apiNames.some((apiName) => objectInfos[apiName] === undefined)) {
10199
10236
  // eslint-disable-next-line
10200
- throw new Error(`ObjectInfo is missing for ${path}`);
10237
+ throw new Error(`ObjectInfo is missing for ${parentPath}`);
10201
10238
  }
10202
10239
  }
10203
10240
  if (isScalarField) {
@@ -10221,21 +10258,17 @@ function injectFilter(filterNode, idState, path, objectInfos, pathToObjectApiNam
10221
10258
  let isSpanning = false;
10222
10259
  // if true, current node is a polymorphic concrete type node. For example, field node `User` under `Owner`
10223
10260
  let isInlineFragment = false;
10224
- let isPolymorphicField = false;
10225
10261
  let isTypeNameExisting = false;
10226
10262
  let curPath;
10227
10263
  let fieldName = filterNode.name.value;
10228
- curPath = `${path}_${fieldName}`;
10264
+ curPath = `${parentPath}#${fieldName}`;
10229
10265
  if (pathToObjectApiNamesMap[curPath] &&
10230
10266
  pathToObjectApiNamesMap[curPath].length > 0) {
10231
10267
  isSpanning = true;
10232
- if (pathToObjectApiNamesMap[curPath].length === 1 &&
10233
- pathToObjectApiNamesMap[path] &&
10234
- pathToObjectApiNamesMap[path].length >= 1 &&
10235
- pathToObjectApiNamesMap[path].includes(pathToObjectApiNamesMap[curPath][0])) {
10236
- isInlineFragment = isPolymorphicFieldPath(path, pathToObjectApiNamesMap);
10237
- }
10238
- isPolymorphicField = isPolymorphicFieldPath(curPath, pathToObjectApiNamesMap);
10268
+ isInlineFragment =
10269
+ isParentPolymorphic &&
10270
+ pathToObjectApiNamesMap[curPath].length === 1;
10271
+ isPolymorphicField = isPolymorphicFieldPath(curPath, pathToObjectApiNamesMap, objectInfos);
10239
10272
  }
10240
10273
  // 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]
10241
10274
  if (isInlineFragment) {
@@ -10281,7 +10314,7 @@ function injectFilter(filterNode, idState, path, objectInfos, pathToObjectApiNam
10281
10314
  }
10282
10315
  const objectInfoName = pathToObjectApiNamesMap[curPath] !== undefined
10283
10316
  ? pathToObjectApiNamesMap[curPath][0]
10284
- : pathToObjectApiNamesMap[path][0];
10317
+ : pathToObjectApiNamesMap[parentPath][0];
10285
10318
  const isIdField = isFieldAnIdField(filterNode.name.value, objectInfos[objectInfoName]);
10286
10319
  if (!isIdField) {
10287
10320
  let subSelectionNodes = [];
@@ -10293,7 +10326,7 @@ function injectFilter(filterNode, idState, path, objectInfos, pathToObjectApiNam
10293
10326
  updateIDInfo(subFieldNode, idState, draftFunctions);
10294
10327
  }
10295
10328
  // try injecting the fields within predicate no matter it has relation or not.
10296
- let subResults = injectFilter(subFieldNode, idState, curPath, objectInfos, pathToObjectApiNamesMap, draftFunctions, existingFields ? existingFields[0] : undefined);
10329
+ let subResults = injectFilter(subFieldNode, idState, curPath, isPolymorphicField, objectInfos, pathToObjectApiNamesMap, draftFunctions, existingFields ? existingFields[0] : undefined);
10297
10330
  subSelectionNodes = subSelectionNodes.concat(subResults);
10298
10331
  });
10299
10332
  if (!subFieldsHasId) {
@@ -10454,15 +10487,43 @@ function mergeOrAddToGroup(group, element) {
10454
10487
  }
10455
10488
  group.push(element);
10456
10489
  }
10457
- // checks if the path points to a polymorphic field. If path points to a polymorphic field, its entry within `pathToObjectApiNamesMap` has the format {"Path" : ["elem1", "elem2"]}.
10458
- // There must be also two entries pointing to concrete polymorphic field path. The two entries are like {"Path_elem1" : ["elem1"]} and {"Path_elem2" : ["elem2"]}
10459
- // For example ServiceAppointment_Owner' --> ['User', 'Group']; 'ServiceAppointment_Owner_User' --> ['User'], 'ServiceAppointment_Owner_Group' --> ['Group']
10460
- function isPolymorphicFieldPath(path, pathToObjectApiNamesMap) {
10461
- const apiName = pathToObjectApiNamesMap[path][0];
10462
- const apiNamesAtChildPath = pathToObjectApiNamesMap[`${path}_${apiName}`];
10463
- return (apiNamesAtChildPath !== undefined &&
10464
- apiNamesAtChildPath.length === 1 &&
10465
- apiNamesAtChildPath[0] === apiName);
10490
+ // checks if the path points to a polymorphic field. For example, for the below `pathToObjectApiNamesMap`
10491
+ // {
10492
+ // 'ServiceAppointment' -> ['ServiceAppointment']
10493
+ // 'ServiceAppointment#Owner' --> ['User'],
10494
+ // 'ServiceAppointment#Owner#User' --> ['User']
10495
+ // }
10496
+ // path `ServiceAppointment#Owner` points to a polymorphic field, but path `ServiceAppointment#Owner#User` does not.
10497
+ function isPolymorphicFieldPath(path, pathToObjectApiNamesMap, objectInfos) {
10498
+ const lastSegmentIndex = path.lastIndexOf('#');
10499
+ if (lastSegmentIndex < 0) {
10500
+ return false;
10501
+ }
10502
+ const lastSegment = path.slice(lastSegmentIndex + 1);
10503
+ const parentApiPath = path.slice(0, lastSegmentIndex);
10504
+ if (pathToObjectApiNamesMap[parentApiPath] === undefined) {
10505
+ return false;
10506
+ }
10507
+ const parentObjectApiNames = pathToObjectApiNamesMap[parentApiPath];
10508
+ // 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`.
10509
+ // 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.
10510
+ // Below are the entries in `pathToObjectApiNamesMap`
10511
+ // {
10512
+ // `ServiceAppointmen`t: [`ServiceAppointment`],
10513
+ // `ServiceAppointment#Owner`: [`User`, `Group`],
10514
+ // `ServiceAppointment#Owner#User`: [`User`],
10515
+ // `ServiceAppointment#Owner#Group`: [`Group`],
10516
+ // }
10517
+ if (parentObjectApiNames.length !== 1) {
10518
+ return false;
10519
+ }
10520
+ const parentObjectInfo = objectInfos[parentObjectApiNames[0]];
10521
+ const relationshipField = referenceIdFieldForRelationship(lastSegment);
10522
+ let fieldDefinition = parentObjectInfo.fields[relationshipField];
10523
+ if (fieldDefinition === undefined) {
10524
+ return false;
10525
+ }
10526
+ return fieldDefinition.polymorphicForeignKey;
10466
10527
  }
10467
10528
  function isFieldAnIdField(fieldName, objectInfo) {
10468
10529
  if (fieldName === 'Id')
@@ -10516,10 +10577,10 @@ function updateIDInfo(fieldNode, idState, draftFunctions) {
10516
10577
  * @param parentNode parent node of param 1
10517
10578
  * @param ancestors ancester of param 1
10518
10579
  * @param objectInfos ObjectInfo map used in injection. If ObjectInfo misses or field does not exist in ObjectInfo, the error will be thrown
10519
- * @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'].
10580
+ * @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'].
10520
10581
  * @return injected SelectionNodes used to construct the InlineFragment.
10521
10582
  */
10522
- function injectFields(selections, parentNode, ancestors, objectInfos, pathToObjectApiNamesMap) {
10583
+ function injectFields(selections, parentNode, parentPath, ancestors, objectInfos, pathToObjectApiNamesMap) {
10523
10584
  /**
10524
10585
  * 1 parentship can return 2 FieldNode which need to be flattened
10525
10586
  * Concact: { ** Contact { ** ContactId {
@@ -10537,6 +10598,10 @@ function injectFields(selections, parentNode, ancestors, objectInfos, pathToObje
10537
10598
  if (!selection.selectionSet) {
10538
10599
  return selection;
10539
10600
  }
10601
+ const segment = isFieldNode(selection)
10602
+ ? selection.name.value
10603
+ : selection.typeCondition.name.value;
10604
+ const curPath = `${parentPath}#${segment}`;
10540
10605
  const spanningSubSelections = [];
10541
10606
  for (const subSelection of selection.selectionSet.selections) {
10542
10607
  if (isFieldSpanning(subSelection, selection)) {
@@ -10544,7 +10609,7 @@ function injectFields(selections, parentNode, ancestors, objectInfos, pathToObje
10544
10609
  }
10545
10610
  }
10546
10611
  // Handles multiple level field injection like 'ServiceAppointment' --> 'Account' --> 'Owner'
10547
- const subInjectedSelections = injectFields(spanningSubSelections, selection, ancestors, objectInfos, pathToObjectApiNamesMap);
10612
+ const subInjectedSelections = injectFields(spanningSubSelections, selection, curPath, ancestors, objectInfos, pathToObjectApiNamesMap);
10548
10613
  if (!selection.selectionSet) {
10549
10614
  return selection;
10550
10615
  }
@@ -10587,7 +10652,7 @@ function injectFields(selections, parentNode, ancestors, objectInfos, pathToObje
10587
10652
  }
10588
10653
  }
10589
10654
  // For polymorphic fields, the Id field is excluded.
10590
- const excludeId = selection.selectionSet.selections.every(isInlineFragmentNode);
10655
+ const excludeId = isPolymorphicFieldPath(curPath, pathToObjectApiNamesMap, objectInfos);
10591
10656
  const idSelection = [];
10592
10657
  if (!excludeId && !hasIdAlready) {
10593
10658
  idSelection.push({
@@ -10598,8 +10663,8 @@ function injectFields(selections, parentNode, ancestors, objectInfos, pathToObje
10598
10663
  },
10599
10664
  });
10600
10665
  }
10601
- // 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,
10602
- // please reference 'removeSyntheticFields'.
10666
+ // 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
10667
+ // `typedCondition` of the InlineFragment in the query AST. It is used to match JSON response with AST node. For more detail, please reference 'removeSyntheticFields'.
10603
10668
  if (isInlineFragmentNode(selection) &&
10604
10669
  !selection.selectionSet.selections.find((selection) => isFieldNode(selection) && selection.name.value === '__typename')) {
10605
10670
  idSelection.push({
@@ -10633,7 +10698,7 @@ function injectFields(selections, parentNode, ancestors, objectInfos, pathToObje
10633
10698
  if (isFieldNode(parentNode) && parentNode.selectionSet && parentNode.name.value === 'node') {
10634
10699
  if (parentNode.selectionSet.selections
10635
10700
  .filter(isFieldOrInlineFragmentNode)
10636
- .some((selectionNode) => isRelationship(selectionNode, 'childRelationship'))) {
10701
+ .some((selectionNode) => isRelationship(selectionNode, CHILD_RELATIONSHIP))) {
10637
10702
  if (!parentNode.selectionSet.selections
10638
10703
  .filter(isFieldNode)
10639
10704
  .some((sibling) => sibling.name.value === 'Id')) {
@@ -10652,7 +10717,7 @@ function injectFields(selections, parentNode, ancestors, objectInfos, pathToObje
10652
10717
  if (parentInfo.parentIndex >= 0) {
10653
10718
  // example node { TimeSheetEntries { edges { node { Id }}}}
10654
10719
  const parent = parentInfo.node;
10655
- if (isRelationship(parent, 'childRelationship')) {
10720
+ if (isRelationship(parent, CHILD_RELATIONSHIP)) {
10656
10721
  const unVisitedAncestors = ancestors.slice(0, parentInfo.parentIndex);
10657
10722
  // path : "TimeSheet"
10658
10723
  const grandParentPath = findAncesterPath(unVisitedAncestors);
@@ -10781,7 +10846,7 @@ const assignedToMeFragmentSelections = [
10781
10846
  },
10782
10847
  value: {
10783
10848
  kind: 'StringValue',
10784
- value: 'childRelationship',
10849
+ value: CHILD_RELATIONSHIP,
10785
10850
  block: false,
10786
10851
  },
10787
10852
  },
@@ -10873,7 +10938,7 @@ const assignedToMeFragmentSelections = [
10873
10938
  },
10874
10939
  value: {
10875
10940
  kind: 'StringValue',
10876
- value: 'parentRelationship',
10941
+ value: PARENT_RELATIONSHIP,
10877
10942
  block: false,
10878
10943
  },
10879
10944
  },
@@ -11010,7 +11075,9 @@ function handleNonArrayJsonProperty(selection, fieldName, jsonInput, jsonOutput)
11010
11075
  jsonOutput[fieldName] = null;
11011
11076
  return;
11012
11077
  }
11013
- jsonOutput[fieldName] = {};
11078
+ if (jsonOutput[fieldName] === undefined) {
11079
+ jsonOutput[fieldName] = {};
11080
+ }
11014
11081
  createUserJsonOutput(selection, jsonInput[fieldName], jsonOutput[fieldName]);
11015
11082
  }
11016
11083
  else {
@@ -17046,4 +17113,4 @@ register({
17046
17113
  });
17047
17114
 
17048
17115
  export { getRuntime, registerReportObserver, reportGraphqlQueryParseError };
17049
- // version: 1.242.0-57237c3b6
17116
+ // version: 1.242.1-58f8f4bb1