@salesforce/lds-runtime-mobile 1.280.0 → 1.281.0
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 +268 -155
- package/package.json +18 -18
- package/sfdc/main.js +268 -155
package/dist/main.js
CHANGED
|
@@ -8657,24 +8657,48 @@ function findAncesterPath(ancesters) {
|
|
|
8657
8657
|
}
|
|
8658
8658
|
return path;
|
|
8659
8659
|
}
|
|
8660
|
+
function isCategoryDirective(node) {
|
|
8661
|
+
return node.name.value === 'category';
|
|
8662
|
+
}
|
|
8660
8663
|
/**
|
|
8661
8664
|
* checks if the 'SelectionNode' has the potential to have relationship(parent or child) with its ancestor.
|
|
8662
8665
|
* @param node
|
|
8663
8666
|
* @returns
|
|
8664
8667
|
*/
|
|
8665
8668
|
function isCapableRelationship(node) {
|
|
8666
|
-
if (
|
|
8667
|
-
|
|
8668
|
-
|
|
8669
|
-
|
|
8670
|
-
|
|
8671
|
-
|
|
8669
|
+
if (isFieldNode(node)) {
|
|
8670
|
+
if (node.directives !== undefined) {
|
|
8671
|
+
const argNodes = node.directives
|
|
8672
|
+
.flatMap((directive) => {
|
|
8673
|
+
if (isCategoryDirective(directive) === false)
|
|
8674
|
+
return undefined;
|
|
8675
|
+
return directive.arguments;
|
|
8676
|
+
})
|
|
8677
|
+
.filter((x) => x);
|
|
8678
|
+
return argNodes.some((argument) => {
|
|
8679
|
+
if (argument.name.value !== 'name')
|
|
8680
|
+
return false;
|
|
8681
|
+
if (argument.value.kind !== 'StringValue')
|
|
8682
|
+
return false;
|
|
8683
|
+
return (argument.value.value === PARENT_RELATIONSHIP ||
|
|
8684
|
+
argument.value.value === CHILD_RELATIONSHIP ||
|
|
8685
|
+
argument.value.value === POLYMORPHIC_PARENT_RELATIONSHIP);
|
|
8686
|
+
});
|
|
8687
|
+
}
|
|
8688
|
+
}
|
|
8689
|
+
else if (isInlineFragmentNode(node)) {
|
|
8690
|
+
if (!node.selectionSet)
|
|
8672
8691
|
return false;
|
|
8673
|
-
|
|
8674
|
-
|
|
8675
|
-
|
|
8676
|
-
|
|
8677
|
-
|
|
8692
|
+
return node.selectionSet.selections.some((selection) => {
|
|
8693
|
+
if (selection.kind !== Kind.FIELD && selection.kind !== Kind.INLINE_FRAGMENT)
|
|
8694
|
+
return false;
|
|
8695
|
+
// example: Account { Id }
|
|
8696
|
+
if (selection.kind === Kind.FIELD && selection.name.value === 'Id')
|
|
8697
|
+
return true;
|
|
8698
|
+
return selection.selectionSet !== undefined;
|
|
8699
|
+
});
|
|
8700
|
+
}
|
|
8701
|
+
return false;
|
|
8678
8702
|
}
|
|
8679
8703
|
/**
|
|
8680
8704
|
* checks if the 'ArgumentNode' is a specific scope type
|
|
@@ -9412,6 +9436,12 @@ function addResolversToSchema(schema, polyFields) {
|
|
|
9412
9436
|
break;
|
|
9413
9437
|
case 'LastModifiedDate':
|
|
9414
9438
|
field.resolve = ({ recordRepresentation: record }) => {
|
|
9439
|
+
// In UIAPI record reps, LastModifiedDate might be present as a field,
|
|
9440
|
+
// which will include both the value and displayValue
|
|
9441
|
+
if (record.fields['LastModifiedDate']) {
|
|
9442
|
+
return record.fields['LastModifiedDate'];
|
|
9443
|
+
}
|
|
9444
|
+
// If the field is not present, just return the value of the root property
|
|
9415
9445
|
return record.lastModifiedDate
|
|
9416
9446
|
? { value: record.lastModifiedDate }
|
|
9417
9447
|
: null;
|
|
@@ -9539,7 +9569,6 @@ _, { objectInfos }) {
|
|
|
9539
9569
|
}
|
|
9540
9570
|
}
|
|
9541
9571
|
}
|
|
9542
|
-
// TODO [W-14660068]: composite name fields
|
|
9543
9572
|
return null;
|
|
9544
9573
|
}
|
|
9545
9574
|
async function connectionEdgeResolver(obj, _args, context) {
|
|
@@ -10603,6 +10632,9 @@ function growObjectFieldTree(tree, parentNode, entryNode, totalNodes, startNodes
|
|
|
10603
10632
|
}
|
|
10604
10633
|
});
|
|
10605
10634
|
}
|
|
10635
|
+
function isNodeOrEdges(node) {
|
|
10636
|
+
return isFieldNode(node) && (node.name.value === 'node' || node.name.value === 'edges');
|
|
10637
|
+
}
|
|
10606
10638
|
/**
|
|
10607
10639
|
* Build a relationship tree from the top FieldNode 'node'
|
|
10608
10640
|
* @param tree
|
|
@@ -10613,7 +10645,7 @@ function growObjectFieldTree(tree, parentNode, entryNode, totalNodes, startNodes
|
|
|
10613
10645
|
* @param startNodes
|
|
10614
10646
|
*/
|
|
10615
10647
|
function growFieldTree(tree, parentSectionPath, entryNode, parentNode, totalNodes, startNodes) {
|
|
10616
|
-
if (isCapableRelationship(entryNode)) {
|
|
10648
|
+
if (isCapableRelationship(entryNode) || isNodeOrEdges(entryNode)) {
|
|
10617
10649
|
if (isFieldNode(entryNode)) {
|
|
10618
10650
|
const relationType = getRelation(entryNode);
|
|
10619
10651
|
const fieldName = entryNode.name.value;
|
|
@@ -11200,6 +11232,126 @@ function updateIDInfo(fieldNode, idState, draftFunctions) {
|
|
|
11200
11232
|
}
|
|
11201
11233
|
}
|
|
11202
11234
|
}
|
|
11235
|
+
function findIdFieldNode(node) {
|
|
11236
|
+
if (node.selectionSet === undefined)
|
|
11237
|
+
return false;
|
|
11238
|
+
return node.selectionSet.selections.some((selection) => {
|
|
11239
|
+
if (isFieldNode(selection)) {
|
|
11240
|
+
return selection.name.value === 'Id';
|
|
11241
|
+
}
|
|
11242
|
+
return false;
|
|
11243
|
+
});
|
|
11244
|
+
}
|
|
11245
|
+
/**
|
|
11246
|
+
* 1 parentship can return 2 FieldNode which need to be flattened
|
|
11247
|
+
* Concact: { ** Contact { ** ContactId {
|
|
11248
|
+
* Name: { ** Id ** value
|
|
11249
|
+
* value ** } ** }
|
|
11250
|
+
* } **
|
|
11251
|
+
* }
|
|
11252
|
+
* `parentRelationships` is a 2-dimensional array. 1 element at the top level of the array is an array of injected fields(which could has 2 elements) for
|
|
11253
|
+
* one field(`Contact`, for example), For example, `Contact` field could map to field `Contact { Id }` and `ContactId { value }` which are injected.
|
|
11254
|
+
* `Account` field could map to field `Account { Id }` and `AccountID { value }`.
|
|
11255
|
+
* Returned `parentRelationships` would look like [ [`Contact { Id }`, `ContactId { value }`], [`Account { Id }`, `AccountId { value }`]]. It needs to
|
|
11256
|
+
* be flattened to [`Contact { Id }`, `ContactId { value }`, `Account { Id }`, `AccountId { value }`]
|
|
11257
|
+
*/
|
|
11258
|
+
function injectParentRelationships(selections, parentNode, parentPath, ancestors, objectInfos, pathToObjectApiNamesMap) {
|
|
11259
|
+
let parentInjectedNodes = [];
|
|
11260
|
+
for (let i = 0, len = selections.length; i < len; i++) {
|
|
11261
|
+
const selection = selections[i];
|
|
11262
|
+
// have to wrap in the if statement to make rollup happy :(
|
|
11263
|
+
if (isFieldOrInlineFragmentNode(selection)) {
|
|
11264
|
+
if (selection.selectionSet === undefined) {
|
|
11265
|
+
parentInjectedNodes.push(selection);
|
|
11266
|
+
continue;
|
|
11267
|
+
}
|
|
11268
|
+
const segment = isFieldNode(selection)
|
|
11269
|
+
? selection.name.value
|
|
11270
|
+
: selection.typeCondition.name.value;
|
|
11271
|
+
const curPath = `${parentPath}#${segment}`;
|
|
11272
|
+
const spanningSubSelections = [];
|
|
11273
|
+
for (const subSelection of selection.selectionSet.selections) {
|
|
11274
|
+
if (isFieldSpanning(subSelection, selection)) {
|
|
11275
|
+
spanningSubSelections.push(subSelection);
|
|
11276
|
+
}
|
|
11277
|
+
}
|
|
11278
|
+
// Handles multiple level field injection like 'ServiceAppointment' --> 'Account' --> 'Owner'
|
|
11279
|
+
const subInjectedSelections = injectFields(spanningSubSelections, selection, curPath, ancestors, objectInfos, pathToObjectApiNamesMap);
|
|
11280
|
+
const hasIdNode = findIdFieldNode(selection);
|
|
11281
|
+
// For InlineFragment like '... on User', do not create relationship. Relationship is handled at the upper level.
|
|
11282
|
+
if (isFieldNode(selection)) {
|
|
11283
|
+
const fieldName = selection.name.value;
|
|
11284
|
+
const relationshipId = referenceIdFieldForRelationship(fieldName);
|
|
11285
|
+
// check if relation field like 'AccountId' does exist in query
|
|
11286
|
+
const existingRelationFields = [parentNode]
|
|
11287
|
+
.filter(isFieldOrInlineFragmentNode)
|
|
11288
|
+
.reduce(extractSelections, [])
|
|
11289
|
+
.filter(isFieldNode)
|
|
11290
|
+
.filter((subNode) => subNode.name.value === relationshipId);
|
|
11291
|
+
if (existingRelationFields.length === 0) {
|
|
11292
|
+
parentInjectedNodes.push(createFieldNode(relationshipId, FieldValueNodeSelectionSet));
|
|
11293
|
+
}
|
|
11294
|
+
}
|
|
11295
|
+
// For polymorphic fields, the Id field is excluded.
|
|
11296
|
+
const excludeId = isPolymorphicFieldPath(curPath, pathToObjectApiNamesMap, objectInfos);
|
|
11297
|
+
const idSelection = [];
|
|
11298
|
+
if (!excludeId && hasIdNode === false) {
|
|
11299
|
+
idSelection.push(createFieldNode('Id'));
|
|
11300
|
+
}
|
|
11301
|
+
// 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
|
|
11302
|
+
// `typedCondition` of the InlineFragment in the query AST. It is used to match JSON response with AST node. For more detail, please reference 'removeSyntheticFields'.
|
|
11303
|
+
if (isInlineFragmentNode(selection) &&
|
|
11304
|
+
!selection.selectionSet.selections.find((selection) => isFieldNode(selection) && selection.name.value === '__typename')) {
|
|
11305
|
+
idSelection.push(createFieldNode('__typename'));
|
|
11306
|
+
}
|
|
11307
|
+
// 'ServiceAppointment' --> 'Contact' --> 'Id', Inject 'Contact' with Id. 'Id' field is at the sub level.
|
|
11308
|
+
if (idSelection.length > 0 || subInjectedSelections.length > 0) {
|
|
11309
|
+
parentInjectedNodes.push({
|
|
11310
|
+
...selection,
|
|
11311
|
+
selectionSet: {
|
|
11312
|
+
kind: Kind.SELECTION_SET,
|
|
11313
|
+
selections: [...idSelection, ...subInjectedSelections],
|
|
11314
|
+
},
|
|
11315
|
+
});
|
|
11316
|
+
}
|
|
11317
|
+
}
|
|
11318
|
+
}
|
|
11319
|
+
return parentInjectedNodes;
|
|
11320
|
+
}
|
|
11321
|
+
/**
|
|
11322
|
+
* Find any name fields needed for the DisplayValue field
|
|
11323
|
+
* @param param0
|
|
11324
|
+
* @param parentNode
|
|
11325
|
+
* @param objectInfos
|
|
11326
|
+
* @returns
|
|
11327
|
+
*/
|
|
11328
|
+
function injectFieldsForDisplayValue({ selectionSet }, parentNode, objectInfos) {
|
|
11329
|
+
if (selectionSet === undefined)
|
|
11330
|
+
return [];
|
|
11331
|
+
let displayValueNameFields = [];
|
|
11332
|
+
const { selections } = selectionSet;
|
|
11333
|
+
// see if node selection has DisplayValue and needs to inject
|
|
11334
|
+
let displayValue;
|
|
11335
|
+
for (let i = 0, len = selections.length; i < len; i++) {
|
|
11336
|
+
const node = selections[i];
|
|
11337
|
+
if (isFieldNode(node) && node.name.value === 'DisplayValue') {
|
|
11338
|
+
displayValue = node;
|
|
11339
|
+
break;
|
|
11340
|
+
}
|
|
11341
|
+
}
|
|
11342
|
+
if (displayValue !== undefined) {
|
|
11343
|
+
const apiName = parentNode.name.value;
|
|
11344
|
+
const objectInfo = objectInfos[apiName];
|
|
11345
|
+
if (objectInfo !== undefined &&
|
|
11346
|
+
objectInfo.nameFields !== undefined &&
|
|
11347
|
+
objectInfo.nameFields.length > 0) {
|
|
11348
|
+
displayValueNameFields = objectInfo.nameFields.map((fieldName) => {
|
|
11349
|
+
return createFieldNode(fieldName, FieldValueNodeSelectionSet);
|
|
11350
|
+
});
|
|
11351
|
+
}
|
|
11352
|
+
}
|
|
11353
|
+
return displayValueNameFields;
|
|
11354
|
+
}
|
|
11203
11355
|
/**
|
|
11204
11356
|
* injects fields under query
|
|
11205
11357
|
* @param selections selection nodes need to be injected.
|
|
@@ -11210,160 +11362,60 @@ function updateIDInfo(fieldNode, idState, draftFunctions) {
|
|
|
11210
11362
|
* @return injected SelectionNodes used to construct the InlineFragment.
|
|
11211
11363
|
*/
|
|
11212
11364
|
function injectFields(selections, parentNode, parentPath, ancestors, objectInfos, pathToObjectApiNamesMap) {
|
|
11213
|
-
|
|
11214
|
-
* 1 parentship can return 2 FieldNode which need to be flattened
|
|
11215
|
-
* Concact: { ** Contact { ** ContactId {
|
|
11216
|
-
* Name: { ** Id ** value
|
|
11217
|
-
* value ** } ** }
|
|
11218
|
-
* } **
|
|
11219
|
-
* }
|
|
11220
|
-
* `parentRelationships` is a 2-dimensional array. 1 element at the top level of the array is an array of injected fields(which could has 2 elements) for
|
|
11221
|
-
* one field(`Contact`, for example), For example, `Contact` field could map to field `Contact { Id }` and `ContactId { value }` which are injected.
|
|
11222
|
-
* `Account` field could map to field `Account { Id }` and `AccountID { value }`.
|
|
11223
|
-
* Returned `parentRelationships` would look like [ [`Contact { Id }`, `ContactId { value }`], [`Account { Id }`, `AccountId { value }`]]. It needs to
|
|
11224
|
-
* be flattened to [`Contact { Id }`, `ContactId { value }`, `Account { Id }`, `AccountId { value }`]
|
|
11225
|
-
*/
|
|
11226
|
-
const parentRelaltionships = selections.filter(isFieldOrInlineFragmentNode).map((selection) => {
|
|
11227
|
-
if (!selection.selectionSet) {
|
|
11228
|
-
return selection;
|
|
11229
|
-
}
|
|
11230
|
-
const segment = isFieldNode(selection)
|
|
11231
|
-
? selection.name.value
|
|
11232
|
-
: selection.typeCondition.name.value;
|
|
11233
|
-
const curPath = `${parentPath}#${segment}`;
|
|
11234
|
-
const spanningSubSelections = [];
|
|
11235
|
-
for (const subSelection of selection.selectionSet.selections) {
|
|
11236
|
-
if (isFieldSpanning(subSelection, selection)) {
|
|
11237
|
-
spanningSubSelections.push(subSelection);
|
|
11238
|
-
}
|
|
11239
|
-
}
|
|
11240
|
-
// Handles multiple level field injection like 'ServiceAppointment' --> 'Account' --> 'Owner'
|
|
11241
|
-
const subInjectedSelections = injectFields(spanningSubSelections, selection, curPath, ancestors, objectInfos, pathToObjectApiNamesMap);
|
|
11242
|
-
if (!selection.selectionSet) {
|
|
11243
|
-
return selection;
|
|
11244
|
-
}
|
|
11245
|
-
const hasIdAlready = selection.selectionSet.selections
|
|
11246
|
-
.filter(isFieldNode)
|
|
11247
|
-
.find((s) => s.name.value === 'Id');
|
|
11248
|
-
// For InlineFragment like '... on User', do not create relationship. Relationship is handled at the upper level.
|
|
11249
|
-
let injectedRelationshipField = [];
|
|
11250
|
-
if (isFieldNode(selection)) {
|
|
11251
|
-
const fieldName = selection.name.value;
|
|
11252
|
-
const relationshipId = referenceIdFieldForRelationship(fieldName);
|
|
11253
|
-
// check if relation field like 'AccountId' does exist in query
|
|
11254
|
-
const existingRelationFields = [parentNode]
|
|
11255
|
-
.filter(isFieldOrInlineFragmentNode)
|
|
11256
|
-
.reduce(extractSelections, [])
|
|
11257
|
-
.filter(isFieldNode)
|
|
11258
|
-
.filter((subNode) => subNode.name.value === relationshipId);
|
|
11259
|
-
if (existingRelationFields.length === 0) {
|
|
11260
|
-
injectedRelationshipField = [
|
|
11261
|
-
createFieldNode(relationshipId, FieldValueNodeSelectionSet),
|
|
11262
|
-
];
|
|
11263
|
-
}
|
|
11264
|
-
}
|
|
11265
|
-
// For polymorphic fields, the Id field is excluded.
|
|
11266
|
-
const excludeId = isPolymorphicFieldPath(curPath, pathToObjectApiNamesMap, objectInfos);
|
|
11267
|
-
const idSelection = [];
|
|
11268
|
-
if (!excludeId && !hasIdAlready) {
|
|
11269
|
-
idSelection.push(createFieldNode('Id'));
|
|
11270
|
-
}
|
|
11271
|
-
// 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
|
|
11272
|
-
// `typedCondition` of the InlineFragment in the query AST. It is used to match JSON response with AST node. For more detail, please reference 'removeSyntheticFields'.
|
|
11273
|
-
if (isInlineFragmentNode(selection) &&
|
|
11274
|
-
!selection.selectionSet.selections.find((selection) => isFieldNode(selection) && selection.name.value === '__typename')) {
|
|
11275
|
-
idSelection.push(createFieldNode('__typename'));
|
|
11276
|
-
}
|
|
11277
|
-
// 'ServiceAppointment' --> 'Contact' --> 'Id', Inject 'Contact' with Id. 'Id' field is at the sub level.
|
|
11278
|
-
const injectedSelectionIdField = idSelection.length > 0 || subInjectedSelections.length > 0
|
|
11279
|
-
? [
|
|
11280
|
-
{
|
|
11281
|
-
...selection,
|
|
11282
|
-
selectionSet: {
|
|
11283
|
-
kind: Kind.SELECTION_SET,
|
|
11284
|
-
selections: [...idSelection, ...subInjectedSelections],
|
|
11285
|
-
},
|
|
11286
|
-
},
|
|
11287
|
-
]
|
|
11288
|
-
: [];
|
|
11289
|
-
return [...injectedSelectionIdField, ...injectedRelationshipField];
|
|
11290
|
-
});
|
|
11291
|
-
// injects Id if the parent of the 'childRelationship' does not contain an Id field. The logic here only deals with 'parentNode'
|
|
11292
|
-
const idForChildRelationship = [];
|
|
11365
|
+
const parentRelaltionships = injectParentRelationships(selections, parentNode, parentPath, ancestors, objectInfos, pathToObjectApiNamesMap);
|
|
11293
11366
|
// inject related field for the parent of the 'childRelationship'.
|
|
11294
11367
|
const relatedIdForChildRelationship = [];
|
|
11295
11368
|
// injected fields for DisplayValue
|
|
11296
11369
|
let displayValueNameFields = [];
|
|
11370
|
+
let rootQueryIdField = [];
|
|
11297
11371
|
// injects 'childRelatiship' at the 'node' level, it does not matter if the 'selections' is empty or not.
|
|
11298
11372
|
// the operation happens at the same level as the 'childRelationship' field.
|
|
11299
|
-
if (isFieldNode(parentNode) &&
|
|
11300
|
-
|
|
11301
|
-
|
|
11302
|
-
|
|
11303
|
-
|
|
11304
|
-
|
|
11305
|
-
|
|
11306
|
-
|
|
11307
|
-
}
|
|
11308
|
-
}
|
|
11309
|
-
|
|
11310
|
-
|
|
11311
|
-
|
|
11312
|
-
|
|
11313
|
-
|
|
11314
|
-
|
|
11315
|
-
|
|
11316
|
-
|
|
11317
|
-
|
|
11318
|
-
|
|
11319
|
-
|
|
11320
|
-
|
|
11321
|
-
|
|
11322
|
-
|
|
11323
|
-
|
|
11324
|
-
|
|
11325
|
-
|
|
11326
|
-
|
|
11327
|
-
|
|
11328
|
-
|
|
11329
|
-
|
|
11330
|
-
|
|
11331
|
-
|
|
11332
|
-
|
|
11333
|
-
|
|
11334
|
-
|
|
11335
|
-
relatedIdForChildRelationship.push(createFieldNode(injectedParentFieldName, FieldValueNodeSelectionSet));
|
|
11336
|
-
}
|
|
11373
|
+
if (isFieldNode(parentNode) &&
|
|
11374
|
+
parentNode.selectionSet !== undefined &&
|
|
11375
|
+
(parentNode.name.value === 'node' || isCapableRelationship(parentNode))) {
|
|
11376
|
+
//check if the root query has the Id and inject if it needed
|
|
11377
|
+
if (parentNode.name.value === 'node') {
|
|
11378
|
+
const idNode = findIdFieldNode(parentNode);
|
|
11379
|
+
if (idNode === false) {
|
|
11380
|
+
rootQueryIdField.push(createFieldNode('Id'));
|
|
11381
|
+
}
|
|
11382
|
+
}
|
|
11383
|
+
// example { node { Id } }. The operation happens at the 'edges' -> 'node' level of the 'childRelationship' field
|
|
11384
|
+
const parentInfo = findNearestAncesterPath(ancestors, true);
|
|
11385
|
+
if (parentInfo.parentIndex >= 0) {
|
|
11386
|
+
// example node { TimeSheetEntries { edges { node { Id }}}}
|
|
11387
|
+
const parent = parentNode.name.value === 'node' ? parentInfo.node : parentNode;
|
|
11388
|
+
if (isRelationship(parent, CHILD_RELATIONSHIP)) {
|
|
11389
|
+
const unVisitedAncestors = ancestors.slice(0, parentInfo.parentIndex);
|
|
11390
|
+
// path : "TimeSheet"
|
|
11391
|
+
const grandParentPath = findAncesterPath(unVisitedAncestors);
|
|
11392
|
+
if (pathToObjectApiNamesMap &&
|
|
11393
|
+
pathToObjectApiNamesMap[grandParentPath] &&
|
|
11394
|
+
objectInfos &&
|
|
11395
|
+
objectInfos[pathToObjectApiNamesMap[grandParentPath][0]]) {
|
|
11396
|
+
const grandParentObjectInfo = objectInfos[pathToObjectApiNamesMap[grandParentPath][0]];
|
|
11397
|
+
// exmaple "TimeSheetEntries"
|
|
11398
|
+
const parentFieldName = parent.name.value;
|
|
11399
|
+
const targetRelationship = grandParentObjectInfo.childRelationships.find((childRelationship) => {
|
|
11400
|
+
return childRelationship.relationshipName === parentFieldName;
|
|
11401
|
+
});
|
|
11402
|
+
if (targetRelationship !== undefined) {
|
|
11403
|
+
const injectedParentFieldName = targetRelationship.fieldName;
|
|
11404
|
+
if (!parentNode.selectionSet.selections
|
|
11405
|
+
.filter(isFieldNode)
|
|
11406
|
+
.some((sibling) => sibling.name.value === injectedParentFieldName)) {
|
|
11407
|
+
// example: TimeSheetId { value }
|
|
11408
|
+
relatedIdForChildRelationship.push(createFieldNode(injectedParentFieldName, FieldValueNodeSelectionSet));
|
|
11337
11409
|
}
|
|
11338
11410
|
}
|
|
11339
11411
|
}
|
|
11340
|
-
const { selectionSet: { selections }, } = parentNode;
|
|
11341
|
-
// see if node selection has DisplayValue and needs to inject
|
|
11342
|
-
let displayValue;
|
|
11343
|
-
for (let i = 0, len = selections.length; i < len; i++) {
|
|
11344
|
-
const node = selections[i];
|
|
11345
|
-
if (isFieldNode(node) && node.name.value === 'DisplayValue') {
|
|
11346
|
-
displayValue = node;
|
|
11347
|
-
break;
|
|
11348
|
-
}
|
|
11349
|
-
}
|
|
11350
|
-
if (displayValue !== undefined) {
|
|
11351
|
-
const apiName = parent.name.value;
|
|
11352
|
-
const objectInfo = objectInfos[apiName];
|
|
11353
|
-
if (objectInfo !== undefined &&
|
|
11354
|
-
objectInfo.nameFields !== undefined &&
|
|
11355
|
-
objectInfo.nameFields.length > 0) {
|
|
11356
|
-
displayValueNameFields = objectInfo.nameFields.map((fieldName) => {
|
|
11357
|
-
return createFieldNode(fieldName, FieldValueNodeSelectionSet);
|
|
11358
|
-
});
|
|
11359
|
-
}
|
|
11360
|
-
}
|
|
11361
11412
|
}
|
|
11413
|
+
displayValueNameFields = injectFieldsForDisplayValue(parentNode, parent, objectInfos);
|
|
11362
11414
|
}
|
|
11363
11415
|
}
|
|
11364
11416
|
return [
|
|
11417
|
+
...rootQueryIdField,
|
|
11365
11418
|
...flat(parentRelaltionships),
|
|
11366
|
-
...idForChildRelationship,
|
|
11367
11419
|
...relatedIdForChildRelationship,
|
|
11368
11420
|
...displayValueNameFields,
|
|
11369
11421
|
];
|
|
@@ -12135,6 +12187,60 @@ function replayDraftsOnRecord(record, draftMetadata) {
|
|
|
12135
12187
|
}
|
|
12136
12188
|
return recursivelyApplyDraftsToRecord(baseRecord, draftMetadata, draftMetadata.recordOperations);
|
|
12137
12189
|
}
|
|
12190
|
+
/**
|
|
12191
|
+
* checks if updated fields are apart of the compound Name field
|
|
12192
|
+
* will generate a compound Name field if it is not already apart of the draft
|
|
12193
|
+
* @param record
|
|
12194
|
+
* @param draftFields
|
|
12195
|
+
* @param apiName
|
|
12196
|
+
* @param objectInfos
|
|
12197
|
+
* @returns
|
|
12198
|
+
*/
|
|
12199
|
+
function compoundNameFieldFromDraftUpdates(record, draftFields, apiName, objectInfos) {
|
|
12200
|
+
let updatedNameFields = {};
|
|
12201
|
+
const objectInfo = objectInfos.get(apiName);
|
|
12202
|
+
if (draftFields['Name'] !== undefined ||
|
|
12203
|
+
objectInfo === undefined ||
|
|
12204
|
+
objectInfo.nameFields === undefined ||
|
|
12205
|
+
objectInfo.nameFields.length === 0) {
|
|
12206
|
+
return updatedNameFields;
|
|
12207
|
+
}
|
|
12208
|
+
const nameField = objectInfo.nameFields.find((x) => x === 'Name');
|
|
12209
|
+
if (nameField === undefined) {
|
|
12210
|
+
return updatedNameFields;
|
|
12211
|
+
}
|
|
12212
|
+
const { compound, updateable } = objectInfo.fields[nameField];
|
|
12213
|
+
if (objectInfo.nameFields.length <= 1 && compound === false && updateable === true) {
|
|
12214
|
+
return updatedNameFields;
|
|
12215
|
+
}
|
|
12216
|
+
let changedNameFields = {};
|
|
12217
|
+
const filteredNameFields = objectInfo.nameFields.filter((x) => x !== 'Name');
|
|
12218
|
+
for (let i = 0, len = filteredNameFields.length; i < len; i++) {
|
|
12219
|
+
const fieldName = filteredNameFields[i];
|
|
12220
|
+
const fieldValue = draftFields[fieldName];
|
|
12221
|
+
if (fieldValue !== undefined) {
|
|
12222
|
+
changedNameFields[fieldName] = fieldValue;
|
|
12223
|
+
}
|
|
12224
|
+
}
|
|
12225
|
+
if (keys$3(changedNameFields).length > 0) {
|
|
12226
|
+
const newNameValue = filteredNameFields
|
|
12227
|
+
.map((key) => {
|
|
12228
|
+
if (changedNameFields[key] !== undefined) {
|
|
12229
|
+
return changedNameFields[key];
|
|
12230
|
+
}
|
|
12231
|
+
else if (record.fields[key] !== undefined) {
|
|
12232
|
+
return record.fields[key].value;
|
|
12233
|
+
}
|
|
12234
|
+
else {
|
|
12235
|
+
return '';
|
|
12236
|
+
}
|
|
12237
|
+
})
|
|
12238
|
+
.join(' ')
|
|
12239
|
+
.trim();
|
|
12240
|
+
updatedNameFields['Name'] = newNameValue;
|
|
12241
|
+
}
|
|
12242
|
+
return updatedNameFields;
|
|
12243
|
+
}
|
|
12138
12244
|
function recursivelyApplyDraftsToRecord(record, draftMetadata, recordOperations) {
|
|
12139
12245
|
const { luvio, objectInfos, userId, formatDisplayValue, referencedRecords } = draftMetadata;
|
|
12140
12246
|
if (recordOperations.length === 0) {
|
|
@@ -12194,8 +12300,15 @@ function recursivelyApplyDraftsToRecord(record, draftMetadata, recordOperations)
|
|
|
12194
12300
|
record.drafts.deleted = true;
|
|
12195
12301
|
}
|
|
12196
12302
|
// 'lastModifiedById' and 'lastModifiedDate' are modified in 'delete' and 'update' action
|
|
12197
|
-
const
|
|
12303
|
+
const draftOperationFields = draftActionType === 'delete' ? {} : draftOperation.fields;
|
|
12198
12304
|
const apiName = draftOperation.apiName;
|
|
12305
|
+
const injectedCompoundNameField = compoundNameFieldFromDraftUpdates(record, draftOperationFields, apiName, objectInfos);
|
|
12306
|
+
// inject the compound Name field into the DraftOperation so on broadcast it doesnt try to
|
|
12307
|
+
// synthesize the Name field a second time when the durable store change notifier is triggered
|
|
12308
|
+
if (keys$3(injectedCompoundNameField).length > 0 && draftActionType === 'update') {
|
|
12309
|
+
draftOperation.fields['Name'] = injectedCompoundNameField['Name'];
|
|
12310
|
+
}
|
|
12311
|
+
const fields = { ...draftOperationFields, ...injectedCompoundNameField };
|
|
12199
12312
|
// automaticlly add 'lastModifiedById' and 'lastModifiedByDate' and use an internal draft field copy since it is mutable
|
|
12200
12313
|
const internalFields = {
|
|
12201
12314
|
...fields,
|
|
@@ -17981,4 +18094,4 @@ register({
|
|
|
17981
18094
|
});
|
|
17982
18095
|
|
|
17983
18096
|
export { O11Y_NAMESPACE_LDS_MOBILE, getRuntime, registerReportObserver, reportGraphqlQueryParseError };
|
|
17984
|
-
// version: 1.
|
|
18097
|
+
// version: 1.281.0-9a56a08f0
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@salesforce/lds-runtime-mobile",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.281.0",
|
|
4
4
|
"license": "SEE LICENSE IN LICENSE.txt",
|
|
5
5
|
"description": "LDS runtime for mobile/hybrid environments.",
|
|
6
6
|
"main": "dist/main.js",
|
|
@@ -32,25 +32,25 @@
|
|
|
32
32
|
"release:corejar": "yarn build && ../core-build/scripts/core.js --name=lds-runtime-mobile"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@salesforce/lds-adapters-uiapi": "^1.
|
|
36
|
-
"@salesforce/lds-bindings": "^1.
|
|
37
|
-
"@salesforce/lds-instrumentation": "^1.
|
|
38
|
-
"@salesforce/lds-priming": "^1.
|
|
35
|
+
"@salesforce/lds-adapters-uiapi": "^1.281.0",
|
|
36
|
+
"@salesforce/lds-bindings": "^1.281.0",
|
|
37
|
+
"@salesforce/lds-instrumentation": "^1.281.0",
|
|
38
|
+
"@salesforce/lds-priming": "^1.281.0",
|
|
39
39
|
"@salesforce/user": "0.0.21",
|
|
40
40
|
"o11y": "244.0.0"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
|
-
"@salesforce/lds-adapters-graphql": "^1.
|
|
44
|
-
"@salesforce/lds-drafts": "^1.
|
|
45
|
-
"@salesforce/lds-drafts-adapters-uiapi": "^1.
|
|
46
|
-
"@salesforce/lds-graphql-eval": "^1.
|
|
47
|
-
"@salesforce/lds-network-adapter": "^1.
|
|
48
|
-
"@salesforce/lds-network-nimbus": "^1.
|
|
49
|
-
"@salesforce/lds-store-binary": "^1.
|
|
50
|
-
"@salesforce/lds-store-nimbus": "^1.
|
|
51
|
-
"@salesforce/lds-store-sql": "^1.
|
|
52
|
-
"@salesforce/lds-utils-adapters": "^1.
|
|
53
|
-
"@salesforce/nimbus-plugin-lds": "^1.
|
|
43
|
+
"@salesforce/lds-adapters-graphql": "^1.281.0",
|
|
44
|
+
"@salesforce/lds-drafts": "^1.281.0",
|
|
45
|
+
"@salesforce/lds-drafts-adapters-uiapi": "^1.281.0",
|
|
46
|
+
"@salesforce/lds-graphql-eval": "^1.281.0",
|
|
47
|
+
"@salesforce/lds-network-adapter": "^1.281.0",
|
|
48
|
+
"@salesforce/lds-network-nimbus": "^1.281.0",
|
|
49
|
+
"@salesforce/lds-store-binary": "^1.281.0",
|
|
50
|
+
"@salesforce/lds-store-nimbus": "^1.281.0",
|
|
51
|
+
"@salesforce/lds-store-sql": "^1.281.0",
|
|
52
|
+
"@salesforce/lds-utils-adapters": "^1.281.0",
|
|
53
|
+
"@salesforce/nimbus-plugin-lds": "^1.281.0",
|
|
54
54
|
"babel-plugin-dynamic-import-node": "^2.3.3",
|
|
55
55
|
"wait-for-expect": "^3.0.2"
|
|
56
56
|
},
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
"path": "./dist/main.js",
|
|
60
60
|
"maxSize": {
|
|
61
61
|
"none": "800 kB",
|
|
62
|
-
"min": "
|
|
62
|
+
"min": "321 kB",
|
|
63
63
|
"compressed": "150 kB"
|
|
64
64
|
}
|
|
65
65
|
},
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
"path": "./sfdc/main.js",
|
|
68
68
|
"maxSize": {
|
|
69
69
|
"none": "800 kB",
|
|
70
|
-
"min": "
|
|
70
|
+
"min": "321 kB",
|
|
71
71
|
"compressed": "150 kB"
|
|
72
72
|
}
|
|
73
73
|
}
|
package/sfdc/main.js
CHANGED
|
@@ -8657,24 +8657,48 @@ function findAncesterPath(ancesters) {
|
|
|
8657
8657
|
}
|
|
8658
8658
|
return path;
|
|
8659
8659
|
}
|
|
8660
|
+
function isCategoryDirective(node) {
|
|
8661
|
+
return node.name.value === 'category';
|
|
8662
|
+
}
|
|
8660
8663
|
/**
|
|
8661
8664
|
* checks if the 'SelectionNode' has the potential to have relationship(parent or child) with its ancestor.
|
|
8662
8665
|
* @param node
|
|
8663
8666
|
* @returns
|
|
8664
8667
|
*/
|
|
8665
8668
|
function isCapableRelationship(node) {
|
|
8666
|
-
if (
|
|
8667
|
-
|
|
8668
|
-
|
|
8669
|
-
|
|
8670
|
-
|
|
8671
|
-
|
|
8669
|
+
if (isFieldNode(node)) {
|
|
8670
|
+
if (node.directives !== undefined) {
|
|
8671
|
+
const argNodes = node.directives
|
|
8672
|
+
.flatMap((directive) => {
|
|
8673
|
+
if (isCategoryDirective(directive) === false)
|
|
8674
|
+
return undefined;
|
|
8675
|
+
return directive.arguments;
|
|
8676
|
+
})
|
|
8677
|
+
.filter((x) => x);
|
|
8678
|
+
return argNodes.some((argument) => {
|
|
8679
|
+
if (argument.name.value !== 'name')
|
|
8680
|
+
return false;
|
|
8681
|
+
if (argument.value.kind !== 'StringValue')
|
|
8682
|
+
return false;
|
|
8683
|
+
return (argument.value.value === PARENT_RELATIONSHIP ||
|
|
8684
|
+
argument.value.value === CHILD_RELATIONSHIP ||
|
|
8685
|
+
argument.value.value === POLYMORPHIC_PARENT_RELATIONSHIP);
|
|
8686
|
+
});
|
|
8687
|
+
}
|
|
8688
|
+
}
|
|
8689
|
+
else if (isInlineFragmentNode(node)) {
|
|
8690
|
+
if (!node.selectionSet)
|
|
8672
8691
|
return false;
|
|
8673
|
-
|
|
8674
|
-
|
|
8675
|
-
|
|
8676
|
-
|
|
8677
|
-
|
|
8692
|
+
return node.selectionSet.selections.some((selection) => {
|
|
8693
|
+
if (selection.kind !== Kind.FIELD && selection.kind !== Kind.INLINE_FRAGMENT)
|
|
8694
|
+
return false;
|
|
8695
|
+
// example: Account { Id }
|
|
8696
|
+
if (selection.kind === Kind.FIELD && selection.name.value === 'Id')
|
|
8697
|
+
return true;
|
|
8698
|
+
return selection.selectionSet !== undefined;
|
|
8699
|
+
});
|
|
8700
|
+
}
|
|
8701
|
+
return false;
|
|
8678
8702
|
}
|
|
8679
8703
|
/**
|
|
8680
8704
|
* checks if the 'ArgumentNode' is a specific scope type
|
|
@@ -9412,6 +9436,12 @@ function addResolversToSchema(schema, polyFields) {
|
|
|
9412
9436
|
break;
|
|
9413
9437
|
case 'LastModifiedDate':
|
|
9414
9438
|
field.resolve = ({ recordRepresentation: record }) => {
|
|
9439
|
+
// In UIAPI record reps, LastModifiedDate might be present as a field,
|
|
9440
|
+
// which will include both the value and displayValue
|
|
9441
|
+
if (record.fields['LastModifiedDate']) {
|
|
9442
|
+
return record.fields['LastModifiedDate'];
|
|
9443
|
+
}
|
|
9444
|
+
// If the field is not present, just return the value of the root property
|
|
9415
9445
|
return record.lastModifiedDate
|
|
9416
9446
|
? { value: record.lastModifiedDate }
|
|
9417
9447
|
: null;
|
|
@@ -9539,7 +9569,6 @@ _, { objectInfos }) {
|
|
|
9539
9569
|
}
|
|
9540
9570
|
}
|
|
9541
9571
|
}
|
|
9542
|
-
// TODO [W-14660068]: composite name fields
|
|
9543
9572
|
return null;
|
|
9544
9573
|
}
|
|
9545
9574
|
async function connectionEdgeResolver(obj, _args, context) {
|
|
@@ -10603,6 +10632,9 @@ function growObjectFieldTree(tree, parentNode, entryNode, totalNodes, startNodes
|
|
|
10603
10632
|
}
|
|
10604
10633
|
});
|
|
10605
10634
|
}
|
|
10635
|
+
function isNodeOrEdges(node) {
|
|
10636
|
+
return isFieldNode(node) && (node.name.value === 'node' || node.name.value === 'edges');
|
|
10637
|
+
}
|
|
10606
10638
|
/**
|
|
10607
10639
|
* Build a relationship tree from the top FieldNode 'node'
|
|
10608
10640
|
* @param tree
|
|
@@ -10613,7 +10645,7 @@ function growObjectFieldTree(tree, parentNode, entryNode, totalNodes, startNodes
|
|
|
10613
10645
|
* @param startNodes
|
|
10614
10646
|
*/
|
|
10615
10647
|
function growFieldTree(tree, parentSectionPath, entryNode, parentNode, totalNodes, startNodes) {
|
|
10616
|
-
if (isCapableRelationship(entryNode)) {
|
|
10648
|
+
if (isCapableRelationship(entryNode) || isNodeOrEdges(entryNode)) {
|
|
10617
10649
|
if (isFieldNode(entryNode)) {
|
|
10618
10650
|
const relationType = getRelation(entryNode);
|
|
10619
10651
|
const fieldName = entryNode.name.value;
|
|
@@ -11200,6 +11232,126 @@ function updateIDInfo(fieldNode, idState, draftFunctions) {
|
|
|
11200
11232
|
}
|
|
11201
11233
|
}
|
|
11202
11234
|
}
|
|
11235
|
+
function findIdFieldNode(node) {
|
|
11236
|
+
if (node.selectionSet === undefined)
|
|
11237
|
+
return false;
|
|
11238
|
+
return node.selectionSet.selections.some((selection) => {
|
|
11239
|
+
if (isFieldNode(selection)) {
|
|
11240
|
+
return selection.name.value === 'Id';
|
|
11241
|
+
}
|
|
11242
|
+
return false;
|
|
11243
|
+
});
|
|
11244
|
+
}
|
|
11245
|
+
/**
|
|
11246
|
+
* 1 parentship can return 2 FieldNode which need to be flattened
|
|
11247
|
+
* Concact: { ** Contact { ** ContactId {
|
|
11248
|
+
* Name: { ** Id ** value
|
|
11249
|
+
* value ** } ** }
|
|
11250
|
+
* } **
|
|
11251
|
+
* }
|
|
11252
|
+
* `parentRelationships` is a 2-dimensional array. 1 element at the top level of the array is an array of injected fields(which could has 2 elements) for
|
|
11253
|
+
* one field(`Contact`, for example), For example, `Contact` field could map to field `Contact { Id }` and `ContactId { value }` which are injected.
|
|
11254
|
+
* `Account` field could map to field `Account { Id }` and `AccountID { value }`.
|
|
11255
|
+
* Returned `parentRelationships` would look like [ [`Contact { Id }`, `ContactId { value }`], [`Account { Id }`, `AccountId { value }`]]. It needs to
|
|
11256
|
+
* be flattened to [`Contact { Id }`, `ContactId { value }`, `Account { Id }`, `AccountId { value }`]
|
|
11257
|
+
*/
|
|
11258
|
+
function injectParentRelationships(selections, parentNode, parentPath, ancestors, objectInfos, pathToObjectApiNamesMap) {
|
|
11259
|
+
let parentInjectedNodes = [];
|
|
11260
|
+
for (let i = 0, len = selections.length; i < len; i++) {
|
|
11261
|
+
const selection = selections[i];
|
|
11262
|
+
// have to wrap in the if statement to make rollup happy :(
|
|
11263
|
+
if (isFieldOrInlineFragmentNode(selection)) {
|
|
11264
|
+
if (selection.selectionSet === undefined) {
|
|
11265
|
+
parentInjectedNodes.push(selection);
|
|
11266
|
+
continue;
|
|
11267
|
+
}
|
|
11268
|
+
const segment = isFieldNode(selection)
|
|
11269
|
+
? selection.name.value
|
|
11270
|
+
: selection.typeCondition.name.value;
|
|
11271
|
+
const curPath = `${parentPath}#${segment}`;
|
|
11272
|
+
const spanningSubSelections = [];
|
|
11273
|
+
for (const subSelection of selection.selectionSet.selections) {
|
|
11274
|
+
if (isFieldSpanning(subSelection, selection)) {
|
|
11275
|
+
spanningSubSelections.push(subSelection);
|
|
11276
|
+
}
|
|
11277
|
+
}
|
|
11278
|
+
// Handles multiple level field injection like 'ServiceAppointment' --> 'Account' --> 'Owner'
|
|
11279
|
+
const subInjectedSelections = injectFields(spanningSubSelections, selection, curPath, ancestors, objectInfos, pathToObjectApiNamesMap);
|
|
11280
|
+
const hasIdNode = findIdFieldNode(selection);
|
|
11281
|
+
// For InlineFragment like '... on User', do not create relationship. Relationship is handled at the upper level.
|
|
11282
|
+
if (isFieldNode(selection)) {
|
|
11283
|
+
const fieldName = selection.name.value;
|
|
11284
|
+
const relationshipId = referenceIdFieldForRelationship(fieldName);
|
|
11285
|
+
// check if relation field like 'AccountId' does exist in query
|
|
11286
|
+
const existingRelationFields = [parentNode]
|
|
11287
|
+
.filter(isFieldOrInlineFragmentNode)
|
|
11288
|
+
.reduce(extractSelections, [])
|
|
11289
|
+
.filter(isFieldNode)
|
|
11290
|
+
.filter((subNode) => subNode.name.value === relationshipId);
|
|
11291
|
+
if (existingRelationFields.length === 0) {
|
|
11292
|
+
parentInjectedNodes.push(createFieldNode(relationshipId, FieldValueNodeSelectionSet));
|
|
11293
|
+
}
|
|
11294
|
+
}
|
|
11295
|
+
// For polymorphic fields, the Id field is excluded.
|
|
11296
|
+
const excludeId = isPolymorphicFieldPath(curPath, pathToObjectApiNamesMap, objectInfos);
|
|
11297
|
+
const idSelection = [];
|
|
11298
|
+
if (!excludeId && hasIdNode === false) {
|
|
11299
|
+
idSelection.push(createFieldNode('Id'));
|
|
11300
|
+
}
|
|
11301
|
+
// 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
|
|
11302
|
+
// `typedCondition` of the InlineFragment in the query AST. It is used to match JSON response with AST node. For more detail, please reference 'removeSyntheticFields'.
|
|
11303
|
+
if (isInlineFragmentNode(selection) &&
|
|
11304
|
+
!selection.selectionSet.selections.find((selection) => isFieldNode(selection) && selection.name.value === '__typename')) {
|
|
11305
|
+
idSelection.push(createFieldNode('__typename'));
|
|
11306
|
+
}
|
|
11307
|
+
// 'ServiceAppointment' --> 'Contact' --> 'Id', Inject 'Contact' with Id. 'Id' field is at the sub level.
|
|
11308
|
+
if (idSelection.length > 0 || subInjectedSelections.length > 0) {
|
|
11309
|
+
parentInjectedNodes.push({
|
|
11310
|
+
...selection,
|
|
11311
|
+
selectionSet: {
|
|
11312
|
+
kind: Kind.SELECTION_SET,
|
|
11313
|
+
selections: [...idSelection, ...subInjectedSelections],
|
|
11314
|
+
},
|
|
11315
|
+
});
|
|
11316
|
+
}
|
|
11317
|
+
}
|
|
11318
|
+
}
|
|
11319
|
+
return parentInjectedNodes;
|
|
11320
|
+
}
|
|
11321
|
+
/**
|
|
11322
|
+
* Find any name fields needed for the DisplayValue field
|
|
11323
|
+
* @param param0
|
|
11324
|
+
* @param parentNode
|
|
11325
|
+
* @param objectInfos
|
|
11326
|
+
* @returns
|
|
11327
|
+
*/
|
|
11328
|
+
function injectFieldsForDisplayValue({ selectionSet }, parentNode, objectInfos) {
|
|
11329
|
+
if (selectionSet === undefined)
|
|
11330
|
+
return [];
|
|
11331
|
+
let displayValueNameFields = [];
|
|
11332
|
+
const { selections } = selectionSet;
|
|
11333
|
+
// see if node selection has DisplayValue and needs to inject
|
|
11334
|
+
let displayValue;
|
|
11335
|
+
for (let i = 0, len = selections.length; i < len; i++) {
|
|
11336
|
+
const node = selections[i];
|
|
11337
|
+
if (isFieldNode(node) && node.name.value === 'DisplayValue') {
|
|
11338
|
+
displayValue = node;
|
|
11339
|
+
break;
|
|
11340
|
+
}
|
|
11341
|
+
}
|
|
11342
|
+
if (displayValue !== undefined) {
|
|
11343
|
+
const apiName = parentNode.name.value;
|
|
11344
|
+
const objectInfo = objectInfos[apiName];
|
|
11345
|
+
if (objectInfo !== undefined &&
|
|
11346
|
+
objectInfo.nameFields !== undefined &&
|
|
11347
|
+
objectInfo.nameFields.length > 0) {
|
|
11348
|
+
displayValueNameFields = objectInfo.nameFields.map((fieldName) => {
|
|
11349
|
+
return createFieldNode(fieldName, FieldValueNodeSelectionSet);
|
|
11350
|
+
});
|
|
11351
|
+
}
|
|
11352
|
+
}
|
|
11353
|
+
return displayValueNameFields;
|
|
11354
|
+
}
|
|
11203
11355
|
/**
|
|
11204
11356
|
* injects fields under query
|
|
11205
11357
|
* @param selections selection nodes need to be injected.
|
|
@@ -11210,160 +11362,60 @@ function updateIDInfo(fieldNode, idState, draftFunctions) {
|
|
|
11210
11362
|
* @return injected SelectionNodes used to construct the InlineFragment.
|
|
11211
11363
|
*/
|
|
11212
11364
|
function injectFields(selections, parentNode, parentPath, ancestors, objectInfos, pathToObjectApiNamesMap) {
|
|
11213
|
-
|
|
11214
|
-
* 1 parentship can return 2 FieldNode which need to be flattened
|
|
11215
|
-
* Concact: { ** Contact { ** ContactId {
|
|
11216
|
-
* Name: { ** Id ** value
|
|
11217
|
-
* value ** } ** }
|
|
11218
|
-
* } **
|
|
11219
|
-
* }
|
|
11220
|
-
* `parentRelationships` is a 2-dimensional array. 1 element at the top level of the array is an array of injected fields(which could has 2 elements) for
|
|
11221
|
-
* one field(`Contact`, for example), For example, `Contact` field could map to field `Contact { Id }` and `ContactId { value }` which are injected.
|
|
11222
|
-
* `Account` field could map to field `Account { Id }` and `AccountID { value }`.
|
|
11223
|
-
* Returned `parentRelationships` would look like [ [`Contact { Id }`, `ContactId { value }`], [`Account { Id }`, `AccountId { value }`]]. It needs to
|
|
11224
|
-
* be flattened to [`Contact { Id }`, `ContactId { value }`, `Account { Id }`, `AccountId { value }`]
|
|
11225
|
-
*/
|
|
11226
|
-
const parentRelaltionships = selections.filter(isFieldOrInlineFragmentNode).map((selection) => {
|
|
11227
|
-
if (!selection.selectionSet) {
|
|
11228
|
-
return selection;
|
|
11229
|
-
}
|
|
11230
|
-
const segment = isFieldNode(selection)
|
|
11231
|
-
? selection.name.value
|
|
11232
|
-
: selection.typeCondition.name.value;
|
|
11233
|
-
const curPath = `${parentPath}#${segment}`;
|
|
11234
|
-
const spanningSubSelections = [];
|
|
11235
|
-
for (const subSelection of selection.selectionSet.selections) {
|
|
11236
|
-
if (isFieldSpanning(subSelection, selection)) {
|
|
11237
|
-
spanningSubSelections.push(subSelection);
|
|
11238
|
-
}
|
|
11239
|
-
}
|
|
11240
|
-
// Handles multiple level field injection like 'ServiceAppointment' --> 'Account' --> 'Owner'
|
|
11241
|
-
const subInjectedSelections = injectFields(spanningSubSelections, selection, curPath, ancestors, objectInfos, pathToObjectApiNamesMap);
|
|
11242
|
-
if (!selection.selectionSet) {
|
|
11243
|
-
return selection;
|
|
11244
|
-
}
|
|
11245
|
-
const hasIdAlready = selection.selectionSet.selections
|
|
11246
|
-
.filter(isFieldNode)
|
|
11247
|
-
.find((s) => s.name.value === 'Id');
|
|
11248
|
-
// For InlineFragment like '... on User', do not create relationship. Relationship is handled at the upper level.
|
|
11249
|
-
let injectedRelationshipField = [];
|
|
11250
|
-
if (isFieldNode(selection)) {
|
|
11251
|
-
const fieldName = selection.name.value;
|
|
11252
|
-
const relationshipId = referenceIdFieldForRelationship(fieldName);
|
|
11253
|
-
// check if relation field like 'AccountId' does exist in query
|
|
11254
|
-
const existingRelationFields = [parentNode]
|
|
11255
|
-
.filter(isFieldOrInlineFragmentNode)
|
|
11256
|
-
.reduce(extractSelections, [])
|
|
11257
|
-
.filter(isFieldNode)
|
|
11258
|
-
.filter((subNode) => subNode.name.value === relationshipId);
|
|
11259
|
-
if (existingRelationFields.length === 0) {
|
|
11260
|
-
injectedRelationshipField = [
|
|
11261
|
-
createFieldNode(relationshipId, FieldValueNodeSelectionSet),
|
|
11262
|
-
];
|
|
11263
|
-
}
|
|
11264
|
-
}
|
|
11265
|
-
// For polymorphic fields, the Id field is excluded.
|
|
11266
|
-
const excludeId = isPolymorphicFieldPath(curPath, pathToObjectApiNamesMap, objectInfos);
|
|
11267
|
-
const idSelection = [];
|
|
11268
|
-
if (!excludeId && !hasIdAlready) {
|
|
11269
|
-
idSelection.push(createFieldNode('Id'));
|
|
11270
|
-
}
|
|
11271
|
-
// 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
|
|
11272
|
-
// `typedCondition` of the InlineFragment in the query AST. It is used to match JSON response with AST node. For more detail, please reference 'removeSyntheticFields'.
|
|
11273
|
-
if (isInlineFragmentNode(selection) &&
|
|
11274
|
-
!selection.selectionSet.selections.find((selection) => isFieldNode(selection) && selection.name.value === '__typename')) {
|
|
11275
|
-
idSelection.push(createFieldNode('__typename'));
|
|
11276
|
-
}
|
|
11277
|
-
// 'ServiceAppointment' --> 'Contact' --> 'Id', Inject 'Contact' with Id. 'Id' field is at the sub level.
|
|
11278
|
-
const injectedSelectionIdField = idSelection.length > 0 || subInjectedSelections.length > 0
|
|
11279
|
-
? [
|
|
11280
|
-
{
|
|
11281
|
-
...selection,
|
|
11282
|
-
selectionSet: {
|
|
11283
|
-
kind: Kind.SELECTION_SET,
|
|
11284
|
-
selections: [...idSelection, ...subInjectedSelections],
|
|
11285
|
-
},
|
|
11286
|
-
},
|
|
11287
|
-
]
|
|
11288
|
-
: [];
|
|
11289
|
-
return [...injectedSelectionIdField, ...injectedRelationshipField];
|
|
11290
|
-
});
|
|
11291
|
-
// injects Id if the parent of the 'childRelationship' does not contain an Id field. The logic here only deals with 'parentNode'
|
|
11292
|
-
const idForChildRelationship = [];
|
|
11365
|
+
const parentRelaltionships = injectParentRelationships(selections, parentNode, parentPath, ancestors, objectInfos, pathToObjectApiNamesMap);
|
|
11293
11366
|
// inject related field for the parent of the 'childRelationship'.
|
|
11294
11367
|
const relatedIdForChildRelationship = [];
|
|
11295
11368
|
// injected fields for DisplayValue
|
|
11296
11369
|
let displayValueNameFields = [];
|
|
11370
|
+
let rootQueryIdField = [];
|
|
11297
11371
|
// injects 'childRelatiship' at the 'node' level, it does not matter if the 'selections' is empty or not.
|
|
11298
11372
|
// the operation happens at the same level as the 'childRelationship' field.
|
|
11299
|
-
if (isFieldNode(parentNode) &&
|
|
11300
|
-
|
|
11301
|
-
|
|
11302
|
-
|
|
11303
|
-
|
|
11304
|
-
|
|
11305
|
-
|
|
11306
|
-
|
|
11307
|
-
}
|
|
11308
|
-
}
|
|
11309
|
-
|
|
11310
|
-
|
|
11311
|
-
|
|
11312
|
-
|
|
11313
|
-
|
|
11314
|
-
|
|
11315
|
-
|
|
11316
|
-
|
|
11317
|
-
|
|
11318
|
-
|
|
11319
|
-
|
|
11320
|
-
|
|
11321
|
-
|
|
11322
|
-
|
|
11323
|
-
|
|
11324
|
-
|
|
11325
|
-
|
|
11326
|
-
|
|
11327
|
-
|
|
11328
|
-
|
|
11329
|
-
|
|
11330
|
-
|
|
11331
|
-
|
|
11332
|
-
|
|
11333
|
-
|
|
11334
|
-
|
|
11335
|
-
relatedIdForChildRelationship.push(createFieldNode(injectedParentFieldName, FieldValueNodeSelectionSet));
|
|
11336
|
-
}
|
|
11373
|
+
if (isFieldNode(parentNode) &&
|
|
11374
|
+
parentNode.selectionSet !== undefined &&
|
|
11375
|
+
(parentNode.name.value === 'node' || isCapableRelationship(parentNode))) {
|
|
11376
|
+
//check if the root query has the Id and inject if it needed
|
|
11377
|
+
if (parentNode.name.value === 'node') {
|
|
11378
|
+
const idNode = findIdFieldNode(parentNode);
|
|
11379
|
+
if (idNode === false) {
|
|
11380
|
+
rootQueryIdField.push(createFieldNode('Id'));
|
|
11381
|
+
}
|
|
11382
|
+
}
|
|
11383
|
+
// example { node { Id } }. The operation happens at the 'edges' -> 'node' level of the 'childRelationship' field
|
|
11384
|
+
const parentInfo = findNearestAncesterPath(ancestors, true);
|
|
11385
|
+
if (parentInfo.parentIndex >= 0) {
|
|
11386
|
+
// example node { TimeSheetEntries { edges { node { Id }}}}
|
|
11387
|
+
const parent = parentNode.name.value === 'node' ? parentInfo.node : parentNode;
|
|
11388
|
+
if (isRelationship(parent, CHILD_RELATIONSHIP)) {
|
|
11389
|
+
const unVisitedAncestors = ancestors.slice(0, parentInfo.parentIndex);
|
|
11390
|
+
// path : "TimeSheet"
|
|
11391
|
+
const grandParentPath = findAncesterPath(unVisitedAncestors);
|
|
11392
|
+
if (pathToObjectApiNamesMap &&
|
|
11393
|
+
pathToObjectApiNamesMap[grandParentPath] &&
|
|
11394
|
+
objectInfos &&
|
|
11395
|
+
objectInfos[pathToObjectApiNamesMap[grandParentPath][0]]) {
|
|
11396
|
+
const grandParentObjectInfo = objectInfos[pathToObjectApiNamesMap[grandParentPath][0]];
|
|
11397
|
+
// exmaple "TimeSheetEntries"
|
|
11398
|
+
const parentFieldName = parent.name.value;
|
|
11399
|
+
const targetRelationship = grandParentObjectInfo.childRelationships.find((childRelationship) => {
|
|
11400
|
+
return childRelationship.relationshipName === parentFieldName;
|
|
11401
|
+
});
|
|
11402
|
+
if (targetRelationship !== undefined) {
|
|
11403
|
+
const injectedParentFieldName = targetRelationship.fieldName;
|
|
11404
|
+
if (!parentNode.selectionSet.selections
|
|
11405
|
+
.filter(isFieldNode)
|
|
11406
|
+
.some((sibling) => sibling.name.value === injectedParentFieldName)) {
|
|
11407
|
+
// example: TimeSheetId { value }
|
|
11408
|
+
relatedIdForChildRelationship.push(createFieldNode(injectedParentFieldName, FieldValueNodeSelectionSet));
|
|
11337
11409
|
}
|
|
11338
11410
|
}
|
|
11339
11411
|
}
|
|
11340
|
-
const { selectionSet: { selections }, } = parentNode;
|
|
11341
|
-
// see if node selection has DisplayValue and needs to inject
|
|
11342
|
-
let displayValue;
|
|
11343
|
-
for (let i = 0, len = selections.length; i < len; i++) {
|
|
11344
|
-
const node = selections[i];
|
|
11345
|
-
if (isFieldNode(node) && node.name.value === 'DisplayValue') {
|
|
11346
|
-
displayValue = node;
|
|
11347
|
-
break;
|
|
11348
|
-
}
|
|
11349
|
-
}
|
|
11350
|
-
if (displayValue !== undefined) {
|
|
11351
|
-
const apiName = parent.name.value;
|
|
11352
|
-
const objectInfo = objectInfos[apiName];
|
|
11353
|
-
if (objectInfo !== undefined &&
|
|
11354
|
-
objectInfo.nameFields !== undefined &&
|
|
11355
|
-
objectInfo.nameFields.length > 0) {
|
|
11356
|
-
displayValueNameFields = objectInfo.nameFields.map((fieldName) => {
|
|
11357
|
-
return createFieldNode(fieldName, FieldValueNodeSelectionSet);
|
|
11358
|
-
});
|
|
11359
|
-
}
|
|
11360
|
-
}
|
|
11361
11412
|
}
|
|
11413
|
+
displayValueNameFields = injectFieldsForDisplayValue(parentNode, parent, objectInfos);
|
|
11362
11414
|
}
|
|
11363
11415
|
}
|
|
11364
11416
|
return [
|
|
11417
|
+
...rootQueryIdField,
|
|
11365
11418
|
...flat(parentRelaltionships),
|
|
11366
|
-
...idForChildRelationship,
|
|
11367
11419
|
...relatedIdForChildRelationship,
|
|
11368
11420
|
...displayValueNameFields,
|
|
11369
11421
|
];
|
|
@@ -12135,6 +12187,60 @@ function replayDraftsOnRecord(record, draftMetadata) {
|
|
|
12135
12187
|
}
|
|
12136
12188
|
return recursivelyApplyDraftsToRecord(baseRecord, draftMetadata, draftMetadata.recordOperations);
|
|
12137
12189
|
}
|
|
12190
|
+
/**
|
|
12191
|
+
* checks if updated fields are apart of the compound Name field
|
|
12192
|
+
* will generate a compound Name field if it is not already apart of the draft
|
|
12193
|
+
* @param record
|
|
12194
|
+
* @param draftFields
|
|
12195
|
+
* @param apiName
|
|
12196
|
+
* @param objectInfos
|
|
12197
|
+
* @returns
|
|
12198
|
+
*/
|
|
12199
|
+
function compoundNameFieldFromDraftUpdates(record, draftFields, apiName, objectInfos) {
|
|
12200
|
+
let updatedNameFields = {};
|
|
12201
|
+
const objectInfo = objectInfos.get(apiName);
|
|
12202
|
+
if (draftFields['Name'] !== undefined ||
|
|
12203
|
+
objectInfo === undefined ||
|
|
12204
|
+
objectInfo.nameFields === undefined ||
|
|
12205
|
+
objectInfo.nameFields.length === 0) {
|
|
12206
|
+
return updatedNameFields;
|
|
12207
|
+
}
|
|
12208
|
+
const nameField = objectInfo.nameFields.find((x) => x === 'Name');
|
|
12209
|
+
if (nameField === undefined) {
|
|
12210
|
+
return updatedNameFields;
|
|
12211
|
+
}
|
|
12212
|
+
const { compound, updateable } = objectInfo.fields[nameField];
|
|
12213
|
+
if (objectInfo.nameFields.length <= 1 && compound === false && updateable === true) {
|
|
12214
|
+
return updatedNameFields;
|
|
12215
|
+
}
|
|
12216
|
+
let changedNameFields = {};
|
|
12217
|
+
const filteredNameFields = objectInfo.nameFields.filter((x) => x !== 'Name');
|
|
12218
|
+
for (let i = 0, len = filteredNameFields.length; i < len; i++) {
|
|
12219
|
+
const fieldName = filteredNameFields[i];
|
|
12220
|
+
const fieldValue = draftFields[fieldName];
|
|
12221
|
+
if (fieldValue !== undefined) {
|
|
12222
|
+
changedNameFields[fieldName] = fieldValue;
|
|
12223
|
+
}
|
|
12224
|
+
}
|
|
12225
|
+
if (keys$3(changedNameFields).length > 0) {
|
|
12226
|
+
const newNameValue = filteredNameFields
|
|
12227
|
+
.map((key) => {
|
|
12228
|
+
if (changedNameFields[key] !== undefined) {
|
|
12229
|
+
return changedNameFields[key];
|
|
12230
|
+
}
|
|
12231
|
+
else if (record.fields[key] !== undefined) {
|
|
12232
|
+
return record.fields[key].value;
|
|
12233
|
+
}
|
|
12234
|
+
else {
|
|
12235
|
+
return '';
|
|
12236
|
+
}
|
|
12237
|
+
})
|
|
12238
|
+
.join(' ')
|
|
12239
|
+
.trim();
|
|
12240
|
+
updatedNameFields['Name'] = newNameValue;
|
|
12241
|
+
}
|
|
12242
|
+
return updatedNameFields;
|
|
12243
|
+
}
|
|
12138
12244
|
function recursivelyApplyDraftsToRecord(record, draftMetadata, recordOperations) {
|
|
12139
12245
|
const { luvio, objectInfos, userId, formatDisplayValue, referencedRecords } = draftMetadata;
|
|
12140
12246
|
if (recordOperations.length === 0) {
|
|
@@ -12194,8 +12300,15 @@ function recursivelyApplyDraftsToRecord(record, draftMetadata, recordOperations)
|
|
|
12194
12300
|
record.drafts.deleted = true;
|
|
12195
12301
|
}
|
|
12196
12302
|
// 'lastModifiedById' and 'lastModifiedDate' are modified in 'delete' and 'update' action
|
|
12197
|
-
const
|
|
12303
|
+
const draftOperationFields = draftActionType === 'delete' ? {} : draftOperation.fields;
|
|
12198
12304
|
const apiName = draftOperation.apiName;
|
|
12305
|
+
const injectedCompoundNameField = compoundNameFieldFromDraftUpdates(record, draftOperationFields, apiName, objectInfos);
|
|
12306
|
+
// inject the compound Name field into the DraftOperation so on broadcast it doesnt try to
|
|
12307
|
+
// synthesize the Name field a second time when the durable store change notifier is triggered
|
|
12308
|
+
if (keys$3(injectedCompoundNameField).length > 0 && draftActionType === 'update') {
|
|
12309
|
+
draftOperation.fields['Name'] = injectedCompoundNameField['Name'];
|
|
12310
|
+
}
|
|
12311
|
+
const fields = { ...draftOperationFields, ...injectedCompoundNameField };
|
|
12199
12312
|
// automaticlly add 'lastModifiedById' and 'lastModifiedByDate' and use an internal draft field copy since it is mutable
|
|
12200
12313
|
const internalFields = {
|
|
12201
12314
|
...fields,
|
|
@@ -17981,4 +18094,4 @@ register({
|
|
|
17981
18094
|
});
|
|
17982
18095
|
|
|
17983
18096
|
export { O11Y_NAMESPACE_LDS_MOBILE, getRuntime, registerReportObserver, reportGraphqlQueryParseError };
|
|
17984
|
-
// version: 1.
|
|
18097
|
+
// version: 1.281.0-9a56a08f0
|