@salesforce/lds-runtime-mobile 1.129.1 → 1.130.9
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 +119 -29
- package/package.json +3 -3
- package/sfdc/main.js +119 -29
package/dist/main.js
CHANGED
|
@@ -1240,7 +1240,8 @@ function makeDurable(environment, { durableStore, instrumentation }) {
|
|
|
1240
1240
|
for (const cacheKeyMapKey of cacheKeyMapKeys) {
|
|
1241
1241
|
const cacheKey = cacheKeyMap.get(cacheKeyMapKey);
|
|
1242
1242
|
if (cacheKey.mergeable === true) {
|
|
1243
|
-
|
|
1243
|
+
const canonical = environment.storeGetCanonicalKey(cacheKeyMapKey);
|
|
1244
|
+
keysToRevive.add(canonical);
|
|
1244
1245
|
}
|
|
1245
1246
|
}
|
|
1246
1247
|
let snapshotFromMemoryIngest = undefined;
|
|
@@ -2096,6 +2097,7 @@ const recordPrefix = '.data.uiapi.query';
|
|
|
2096
2097
|
const recordSuffix = 'edges';
|
|
2097
2098
|
const pathPrefix = '$';
|
|
2098
2099
|
const recordsCTE = 'recordsCTE';
|
|
2100
|
+
const MultiPickListValueSeparator$1 = ';';
|
|
2099
2101
|
function cteSql() {
|
|
2100
2102
|
return (`WITH ${recordsCTE} AS NOT materialized ` +
|
|
2101
2103
|
`(select data from lds_data where key like 'UiApi::RecordRepresentation:%')`);
|
|
@@ -2264,16 +2266,26 @@ function existsPredicateToSql(exists) {
|
|
|
2264
2266
|
}
|
|
2265
2267
|
function comparisonPredicateToSql(predicate) {
|
|
2266
2268
|
const operator = comparisonOperatorToSql(predicate.operator);
|
|
2267
|
-
|
|
2269
|
+
let { sql: left, bindings: leftBindings } = expressionToSql(predicate.left, undefined, predicate.operator);
|
|
2268
2270
|
if (predicate.right.type === ValueType.DateEnum ||
|
|
2269
2271
|
predicate.right.type === ValueType.DateTimeEnum ||
|
|
2270
2272
|
predicate.right.type === ValueType.DateArray ||
|
|
2271
2273
|
predicate.right.type === ValueType.DateTimeArray ||
|
|
2272
|
-
predicate.right.type === ValueType.DateValue
|
|
2273
|
-
|
|
2274
|
+
predicate.right.type === ValueType.DateValue ||
|
|
2275
|
+
predicate.right.type === ValueType.DateTimeValue) {
|
|
2276
|
+
const dateFunction = predicate.right.type === ValueType.DateTimeEnum ||
|
|
2277
|
+
predicate.right.type === ValueType.DateTimeArray ||
|
|
2278
|
+
predicate.right.type === ValueType.DateTimeValue
|
|
2279
|
+
? 'datetime'
|
|
2280
|
+
: 'date';
|
|
2281
|
+
const fieldDateValue = `${dateFunction}(${left})`;
|
|
2274
2282
|
return comparisonDateLiteralToSql(fieldDateValue, predicate.operator, predicate.right);
|
|
2275
2283
|
}
|
|
2276
|
-
|
|
2284
|
+
if (predicate.right.type === ValueType.RelativeDate) {
|
|
2285
|
+
const dateFunc = predicate.right.hasTime ? 'datetime' : 'date';
|
|
2286
|
+
left = `${dateFunc}(${left})`;
|
|
2287
|
+
}
|
|
2288
|
+
const { sql: right, bindings: rightBindings } = expressionToSql(predicate.right, undefined, predicate.operator);
|
|
2277
2289
|
let bindings = leftBindings.concat(rightBindings);
|
|
2278
2290
|
if (predicate.operator === ComparisonOperator.eq &&
|
|
2279
2291
|
predicate.right.type === ValueType.StringLiteral &&
|
|
@@ -2358,11 +2370,21 @@ function coerceToTargetDataType(initialSql, targetDataType) {
|
|
|
2358
2370
|
return initialSql;
|
|
2359
2371
|
}
|
|
2360
2372
|
}
|
|
2361
|
-
function expressionToSql(expression, targetDataType) {
|
|
2373
|
+
function expressionToSql(expression, targetDataType, operator) {
|
|
2362
2374
|
switch (expression.type) {
|
|
2363
2375
|
case ValueType.Extract: {
|
|
2376
|
+
// displayValue's for Booleans are special, they return null
|
|
2377
|
+
if (expression.subfield === 'displayValue' && targetDataType === 'Boolean') {
|
|
2378
|
+
return { sql: 'null', bindings: [] };
|
|
2379
|
+
}
|
|
2364
2380
|
let path = extractPath(expression.field, expression.subfield);
|
|
2365
|
-
|
|
2381
|
+
// For multiple picklist includes/excluding filtering, we need to prefix and suffix the field value with ';'
|
|
2382
|
+
// to make the match safe.
|
|
2383
|
+
// sample: field value: 'item12;item123', input value is 'item1'; they need to be converted to
|
|
2384
|
+
// ';item12;item123;' and '%;item1;%' first, then do sqlite like operation.
|
|
2385
|
+
let sql = operator === ComparisonOperator.includes || operator === ComparisonOperator.excludes
|
|
2386
|
+
? `'${MultiPickListValueSeparator$1}' || json_extract("${expression.jsonAlias}.JSON", '${pathPrefix}.${path}') || '${MultiPickListValueSeparator$1}'`
|
|
2387
|
+
: `json_extract("${expression.jsonAlias}.JSON", '${pathPrefix}.${path}')`;
|
|
2366
2388
|
if (targetDataType !== undefined) {
|
|
2367
2389
|
sql = coerceToTargetDataType(sql, targetDataType);
|
|
2368
2390
|
}
|
|
@@ -2409,7 +2431,7 @@ function expressionToSql(expression, targetDataType) {
|
|
|
2409
2431
|
case ValueType.StringLiteral:
|
|
2410
2432
|
return stringLiteralToSql(expression);
|
|
2411
2433
|
case ValueType.MultiPicklistSet:
|
|
2412
|
-
return multiPicklistToSql$1(expression);
|
|
2434
|
+
return multiPicklistToSql$1(expression, operator);
|
|
2413
2435
|
}
|
|
2414
2436
|
}
|
|
2415
2437
|
function stringLiteralToSql(string) {
|
|
@@ -2425,14 +2447,18 @@ function expressionArrayToSql(expressions, toSql) {
|
|
|
2425
2447
|
const bindings = results.length > 0 ? results.map((v) => v.bindings).reduce(flatten$1) : [];
|
|
2426
2448
|
return { sql, bindings };
|
|
2427
2449
|
}
|
|
2428
|
-
function multiPicklistToSql$1({ value }) {
|
|
2450
|
+
function multiPicklistToSql$1({ value }, operator) {
|
|
2429
2451
|
// Individual multipicklist terms that delimited by semicolon are stored server-side
|
|
2430
2452
|
// as lexically sorted strings and treated like logical ANDs. We can approximate this
|
|
2431
2453
|
// behavior in SQL with wildcarded `LIKE` SQL operators. Terms with no delimiter can
|
|
2432
2454
|
// be treated as string literals. Multiple terms are logically OR'd together to
|
|
2433
2455
|
// match the behavior described in SOQL documentation (https://sfdc.co/c9j0r)
|
|
2456
|
+
// To make sure the match is safe for includes/excludes. the value is prefix and
|
|
2457
|
+
// suffix with ';', like 'abc' to '%;abc;%'. raw value for eq and ne.
|
|
2434
2458
|
const sql = '?';
|
|
2435
|
-
const binding =
|
|
2459
|
+
const binding = operator === ComparisonOperator.includes || operator === ComparisonOperator.excludes
|
|
2460
|
+
? `%${MultiPickListValueSeparator$1}${value}${MultiPickListValueSeparator$1}%`
|
|
2461
|
+
: value;
|
|
2436
2462
|
return { sql, bindings: [binding] };
|
|
2437
2463
|
}
|
|
2438
2464
|
function relativeDateToSql(expression) {
|
|
@@ -2503,8 +2529,12 @@ function comparisonDateLiteralToSql(leftOperand, operator, dateInput) {
|
|
|
2503
2529
|
}
|
|
2504
2530
|
}
|
|
2505
2531
|
if (dateInput.type === ValueType.DateValue || dateInput.type === ValueType.DateTimeValue) {
|
|
2532
|
+
const dateFunction = dateInput.type === ValueType.DateTimeValue ? 'datetime' : 'date';
|
|
2506
2533
|
const compOperator = comparisonOperatorToSql(operator);
|
|
2507
|
-
return {
|
|
2534
|
+
return {
|
|
2535
|
+
sql: leftOperand + ` ${compOperator} ` + `${dateFunction}(?)`,
|
|
2536
|
+
bindings: [`${dateInput.value}`],
|
|
2537
|
+
};
|
|
2508
2538
|
}
|
|
2509
2539
|
return { sql: '', bindings: [] };
|
|
2510
2540
|
}
|
|
@@ -2735,15 +2765,41 @@ function fieldFilter(fieldName, fieldNode, alias, apiName, input, joins) {
|
|
|
2735
2765
|
return dateRangeComparison(op.value, op.operator, extract);
|
|
2736
2766
|
}
|
|
2737
2767
|
if (op.type === 'MultiPicklistSetOperator') {
|
|
2768
|
+
const operator = op.operator === ComparisonOperator.includes
|
|
2769
|
+
? CompoundOperator.or
|
|
2770
|
+
: CompoundOperator.and;
|
|
2771
|
+
const children = [];
|
|
2772
|
+
const length = op.value.value.length;
|
|
2773
|
+
for (let i = 0; i < length; i++) {
|
|
2774
|
+
const term = op.value.value[i];
|
|
2775
|
+
if (term !== null) {
|
|
2776
|
+
const splittedValue = term.split(MultiPickListValueSeparator$1);
|
|
2777
|
+
if (splittedValue.length === 1) {
|
|
2778
|
+
children.push(comparison(extract, op.operator, {
|
|
2779
|
+
type: ValueType.MultiPicklistSet,
|
|
2780
|
+
value: term,
|
|
2781
|
+
}));
|
|
2782
|
+
}
|
|
2783
|
+
else {
|
|
2784
|
+
children.push({
|
|
2785
|
+
type: PredicateType$1.compound,
|
|
2786
|
+
operator: op.operator === ComparisonOperator.includes
|
|
2787
|
+
? CompoundOperator.and
|
|
2788
|
+
: CompoundOperator.or,
|
|
2789
|
+
children: splittedValue.map((singleValue) => {
|
|
2790
|
+
return comparison(extract, op.operator, {
|
|
2791
|
+
type: ValueType.MultiPicklistSet,
|
|
2792
|
+
value: singleValue,
|
|
2793
|
+
});
|
|
2794
|
+
}),
|
|
2795
|
+
});
|
|
2796
|
+
}
|
|
2797
|
+
}
|
|
2798
|
+
}
|
|
2738
2799
|
return {
|
|
2739
2800
|
type: PredicateType$1.compound,
|
|
2740
|
-
operator
|
|
2741
|
-
children
|
|
2742
|
-
return comparison(extract, op.operator, {
|
|
2743
|
-
type: ValueType.MultiPicklistSet,
|
|
2744
|
-
value: term,
|
|
2745
|
-
});
|
|
2746
|
-
}),
|
|
2801
|
+
operator,
|
|
2802
|
+
children,
|
|
2747
2803
|
};
|
|
2748
2804
|
}
|
|
2749
2805
|
if (op.type === 'StringSetOperator' && op.value.value.includes(null)) {
|
|
@@ -2807,8 +2863,6 @@ function dateRangeComparison(dateRange, operator, compareDate) {
|
|
|
2807
2863
|
return comparison(compareDate, gte, dateRange.start);
|
|
2808
2864
|
}
|
|
2809
2865
|
}
|
|
2810
|
-
const dateRegEx = /^([12]\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01]))$/;
|
|
2811
|
-
const dateTimeRegEx = /^([12]\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01]))T(2[0-3]|[01][0-9]):[0-5][0-9]:[0-5][0-9](\.[0-9]{3})?Z$/;
|
|
2812
2866
|
function dateFunctions(operatorNode, extract, dataType) {
|
|
2813
2867
|
if (dataType !== 'Date' && dataType !== 'DateTime') {
|
|
2814
2868
|
return success([]);
|
|
@@ -2886,7 +2940,7 @@ function isStringOperatorType(value) {
|
|
|
2886
2940
|
return isScalarOperatorType(value) || value === like;
|
|
2887
2941
|
}
|
|
2888
2942
|
function isPicklistOperatorType(value) {
|
|
2889
|
-
let values = [eq, ne];
|
|
2943
|
+
let values = [eq, ne, like, lt, gt, lte, gte];
|
|
2890
2944
|
return values.includes(value);
|
|
2891
2945
|
}
|
|
2892
2946
|
function isCurrencyOperatorType(value) {
|
|
@@ -3237,8 +3291,11 @@ function operatorWithValue(operator, valueNode, objectInfoDataType) {
|
|
|
3237
3291
|
message(`Comparison operator ${operator} is not supported for type ${objectInfoDataType}.`),
|
|
3238
3292
|
]);
|
|
3239
3293
|
}
|
|
3294
|
+
function isValidDate(value) {
|
|
3295
|
+
return isNaN(Date.parse(value)) === false;
|
|
3296
|
+
}
|
|
3240
3297
|
function dateInput(node) {
|
|
3241
|
-
return parseDateNode(node,
|
|
3298
|
+
return parseDateNode(node, false, 'YYYY-MM-DD', isValidDate).map((result) => {
|
|
3242
3299
|
switch (result.type) {
|
|
3243
3300
|
case ValueType.NullValue:
|
|
3244
3301
|
return result;
|
|
@@ -3252,7 +3309,7 @@ function dateInput(node) {
|
|
|
3252
3309
|
});
|
|
3253
3310
|
}
|
|
3254
3311
|
function dateTimeInput(node) {
|
|
3255
|
-
return parseDateNode(node,
|
|
3312
|
+
return parseDateNode(node, true, 'YYYY-MM-DDTHH:MM:SS.SSSZ, YYYY-MM-DDTHH:MM:SSZ, YYYY-MM-DDTHH:MM:SS.SSS+|-HH:MM, or YYYY-MM-DDTHH:MM:SS+|-HH:MM', isValidDate).map((result) => {
|
|
3256
3313
|
switch (result.type) {
|
|
3257
3314
|
case ValueType.NullValue:
|
|
3258
3315
|
return result;
|
|
@@ -3277,7 +3334,7 @@ function parseNullValue(op) {
|
|
|
3277
3334
|
}
|
|
3278
3335
|
return failure(message(`Null can not be compared with ${op}`));
|
|
3279
3336
|
}
|
|
3280
|
-
function parseDateNode(node,
|
|
3337
|
+
function parseDateNode(node, hasTime, dateFormat, isValidDate) {
|
|
3281
3338
|
const typeName = hasTime ? 'DateTime' : 'Date';
|
|
3282
3339
|
if (!isObjectValueNode$1(node)) {
|
|
3283
3340
|
return failure(message(`Comparison value must be a ${typeName} input.`));
|
|
@@ -3285,7 +3342,12 @@ function parseDateNode(node, regex, hasTime, dateFormat) {
|
|
|
3285
3342
|
const valueField = node.fields.value;
|
|
3286
3343
|
if (valueField !== undefined) {
|
|
3287
3344
|
if (is(valueField, 'StringValue')) {
|
|
3288
|
-
|
|
3345
|
+
// check the date is valid
|
|
3346
|
+
// then make sure if it isnt suppose to contain time stamps that it doesnt
|
|
3347
|
+
// and if it should have a timestamp it should contain it
|
|
3348
|
+
const includesTimeStamp = valueField.value.includes('T');
|
|
3349
|
+
if (isValidDate(valueField.value) &&
|
|
3350
|
+
((hasTime && includesTimeStamp) || (!hasTime && !includesTimeStamp))) {
|
|
3289
3351
|
return success(stringLiteral(valueField.value));
|
|
3290
3352
|
}
|
|
3291
3353
|
return failure(message(`${typeName} format must be ${dateFormat}.`));
|
|
@@ -4277,7 +4339,20 @@ function makeStoreEval(preconditioner, objectInfoService, userId, contextProvide
|
|
|
4277
4339
|
// await it here to normalize the input to a snapshot
|
|
4278
4340
|
const nonEvaluatedSnapshot = await nonEvaluatedSnapshotOrPromise;
|
|
4279
4341
|
// if the non-eval result has errors we want to return to caller
|
|
4280
|
-
|
|
4342
|
+
const nonEvaluatedGQLSnapshot = nonEvaluatedSnapshot;
|
|
4343
|
+
if (isErrorSnapshotThatShouldGetReturnedToCaller$1(nonEvaluatedGQLSnapshot)) {
|
|
4344
|
+
const { data: gqlData } = nonEvaluatedGQLSnapshot;
|
|
4345
|
+
if (hasGraphQlErrors$1(gqlData) && gqlData !== undefined) {
|
|
4346
|
+
return {
|
|
4347
|
+
...nonEvaluatedSnapshot,
|
|
4348
|
+
data: undefined,
|
|
4349
|
+
state: 'Error',
|
|
4350
|
+
error: {
|
|
4351
|
+
errorType: 'adapterError',
|
|
4352
|
+
error: gqlData.errors,
|
|
4353
|
+
},
|
|
4354
|
+
};
|
|
4355
|
+
}
|
|
4281
4356
|
return nonEvaluatedSnapshot;
|
|
4282
4357
|
}
|
|
4283
4358
|
let rootQuery;
|
|
@@ -10948,6 +11023,10 @@ function makeEnvironmentUiApiRecordDraftAware(luvio, options, env) {
|
|
|
10948
11023
|
return create$2(adapterSpecificEnvironments, {});
|
|
10949
11024
|
}
|
|
10950
11025
|
|
|
11026
|
+
function clone(obj) {
|
|
11027
|
+
return parse$2(stringify$2(obj));
|
|
11028
|
+
}
|
|
11029
|
+
|
|
10951
11030
|
const DEFAULT_FIELD_CREATED_BY_ID = 'CreatedById';
|
|
10952
11031
|
const DEFAULT_FIELD_CREATED_DATE = 'CreatedDate';
|
|
10953
11032
|
const DEFAULT_FIELD_ID = 'Id';
|
|
@@ -10975,7 +11054,9 @@ function replayDraftsOnRecord(record, draftMetadata) {
|
|
|
10975
11054
|
// no baseRecord
|
|
10976
11055
|
return undefined;
|
|
10977
11056
|
}
|
|
10978
|
-
const { recordOperations } = draftMetadata;
|
|
11057
|
+
const { recordOperations: originalOperations } = draftMetadata;
|
|
11058
|
+
// since replaying drafts is destructive, we need to clone the original operations
|
|
11059
|
+
const recordOperations = clone(originalOperations);
|
|
10979
11060
|
if (recordOperations.length === 0) {
|
|
10980
11061
|
return undefined;
|
|
10981
11062
|
}
|
|
@@ -11006,7 +11087,11 @@ function recursivelyApplyDraftsToRecord(record, draftMetadata, recordOperations)
|
|
|
11006
11087
|
}
|
|
11007
11088
|
const draftActionType = draftOperation.type;
|
|
11008
11089
|
if (draftActionType === 'create') {
|
|
11009
|
-
|
|
11090
|
+
if (record.drafts !== undefined) {
|
|
11091
|
+
throw Error('a create action cannot exist on an existing draft record');
|
|
11092
|
+
}
|
|
11093
|
+
// the draft may have been uploaded already so skip the create operation and apply the rest (if any)
|
|
11094
|
+
return recursivelyApplyDraftsToRecord(record, draftMetadata, recordOperations);
|
|
11010
11095
|
}
|
|
11011
11096
|
// add the draft node
|
|
11012
11097
|
if (record.drafts === undefined) {
|
|
@@ -11769,6 +11854,11 @@ function makeRecordDenormalizingDurableStore(luvio, durableStore, getStoreRecord
|
|
|
11769
11854
|
let record = entry && entry.data;
|
|
11770
11855
|
if (record === undefined) {
|
|
11771
11856
|
record = storeRecords[recordKey];
|
|
11857
|
+
if (record === undefined) {
|
|
11858
|
+
// fields are being published without a record for them existing,
|
|
11859
|
+
// fields cannot exist standalone in the durable store
|
|
11860
|
+
continue;
|
|
11861
|
+
}
|
|
11772
11862
|
}
|
|
11773
11863
|
putRecords[recordId] = true;
|
|
11774
11864
|
if (isStoreRecordError(record)) {
|
|
@@ -15636,4 +15726,4 @@ register({
|
|
|
15636
15726
|
});
|
|
15637
15727
|
|
|
15638
15728
|
export { getRuntime, registerReportObserver, reportGraphqlQueryParseError };
|
|
15639
|
-
// version: 1.
|
|
15729
|
+
// version: 1.130.9-2d38b9869
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@salesforce/lds-runtime-mobile",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.130.9",
|
|
4
4
|
"license": "SEE LICENSE IN LICENSE.txt",
|
|
5
5
|
"description": "LDS runtime for mobile/hybrid environments.",
|
|
6
6
|
"main": "dist/main.js",
|
|
@@ -58,7 +58,7 @@
|
|
|
58
58
|
"path": "./dist/main.js",
|
|
59
59
|
"maxSize": {
|
|
60
60
|
"none": "650 kB",
|
|
61
|
-
"min": "
|
|
61
|
+
"min": "255 kB",
|
|
62
62
|
"compressed": "100 kB"
|
|
63
63
|
}
|
|
64
64
|
},
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
"path": "./sfdc/main.js",
|
|
67
67
|
"maxSize": {
|
|
68
68
|
"none": "650 kB",
|
|
69
|
-
"min": "
|
|
69
|
+
"min": "255 kB",
|
|
70
70
|
"compressed": "100 kB"
|
|
71
71
|
}
|
|
72
72
|
}
|
package/sfdc/main.js
CHANGED
|
@@ -1240,7 +1240,8 @@ function makeDurable(environment, { durableStore, instrumentation }) {
|
|
|
1240
1240
|
for (const cacheKeyMapKey of cacheKeyMapKeys) {
|
|
1241
1241
|
const cacheKey = cacheKeyMap.get(cacheKeyMapKey);
|
|
1242
1242
|
if (cacheKey.mergeable === true) {
|
|
1243
|
-
|
|
1243
|
+
const canonical = environment.storeGetCanonicalKey(cacheKeyMapKey);
|
|
1244
|
+
keysToRevive.add(canonical);
|
|
1244
1245
|
}
|
|
1245
1246
|
}
|
|
1246
1247
|
let snapshotFromMemoryIngest = undefined;
|
|
@@ -2096,6 +2097,7 @@ const recordPrefix = '.data.uiapi.query';
|
|
|
2096
2097
|
const recordSuffix = 'edges';
|
|
2097
2098
|
const pathPrefix = '$';
|
|
2098
2099
|
const recordsCTE = 'recordsCTE';
|
|
2100
|
+
const MultiPickListValueSeparator$1 = ';';
|
|
2099
2101
|
function cteSql() {
|
|
2100
2102
|
return (`WITH ${recordsCTE} AS NOT materialized ` +
|
|
2101
2103
|
`(select data from lds_data where key like 'UiApi::RecordRepresentation:%')`);
|
|
@@ -2264,16 +2266,26 @@ function existsPredicateToSql(exists) {
|
|
|
2264
2266
|
}
|
|
2265
2267
|
function comparisonPredicateToSql(predicate) {
|
|
2266
2268
|
const operator = comparisonOperatorToSql(predicate.operator);
|
|
2267
|
-
|
|
2269
|
+
let { sql: left, bindings: leftBindings } = expressionToSql(predicate.left, undefined, predicate.operator);
|
|
2268
2270
|
if (predicate.right.type === ValueType.DateEnum ||
|
|
2269
2271
|
predicate.right.type === ValueType.DateTimeEnum ||
|
|
2270
2272
|
predicate.right.type === ValueType.DateArray ||
|
|
2271
2273
|
predicate.right.type === ValueType.DateTimeArray ||
|
|
2272
|
-
predicate.right.type === ValueType.DateValue
|
|
2273
|
-
|
|
2274
|
+
predicate.right.type === ValueType.DateValue ||
|
|
2275
|
+
predicate.right.type === ValueType.DateTimeValue) {
|
|
2276
|
+
const dateFunction = predicate.right.type === ValueType.DateTimeEnum ||
|
|
2277
|
+
predicate.right.type === ValueType.DateTimeArray ||
|
|
2278
|
+
predicate.right.type === ValueType.DateTimeValue
|
|
2279
|
+
? 'datetime'
|
|
2280
|
+
: 'date';
|
|
2281
|
+
const fieldDateValue = `${dateFunction}(${left})`;
|
|
2274
2282
|
return comparisonDateLiteralToSql(fieldDateValue, predicate.operator, predicate.right);
|
|
2275
2283
|
}
|
|
2276
|
-
|
|
2284
|
+
if (predicate.right.type === ValueType.RelativeDate) {
|
|
2285
|
+
const dateFunc = predicate.right.hasTime ? 'datetime' : 'date';
|
|
2286
|
+
left = `${dateFunc}(${left})`;
|
|
2287
|
+
}
|
|
2288
|
+
const { sql: right, bindings: rightBindings } = expressionToSql(predicate.right, undefined, predicate.operator);
|
|
2277
2289
|
let bindings = leftBindings.concat(rightBindings);
|
|
2278
2290
|
if (predicate.operator === ComparisonOperator.eq &&
|
|
2279
2291
|
predicate.right.type === ValueType.StringLiteral &&
|
|
@@ -2358,11 +2370,21 @@ function coerceToTargetDataType(initialSql, targetDataType) {
|
|
|
2358
2370
|
return initialSql;
|
|
2359
2371
|
}
|
|
2360
2372
|
}
|
|
2361
|
-
function expressionToSql(expression, targetDataType) {
|
|
2373
|
+
function expressionToSql(expression, targetDataType, operator) {
|
|
2362
2374
|
switch (expression.type) {
|
|
2363
2375
|
case ValueType.Extract: {
|
|
2376
|
+
// displayValue's for Booleans are special, they return null
|
|
2377
|
+
if (expression.subfield === 'displayValue' && targetDataType === 'Boolean') {
|
|
2378
|
+
return { sql: 'null', bindings: [] };
|
|
2379
|
+
}
|
|
2364
2380
|
let path = extractPath(expression.field, expression.subfield);
|
|
2365
|
-
|
|
2381
|
+
// For multiple picklist includes/excluding filtering, we need to prefix and suffix the field value with ';'
|
|
2382
|
+
// to make the match safe.
|
|
2383
|
+
// sample: field value: 'item12;item123', input value is 'item1'; they need to be converted to
|
|
2384
|
+
// ';item12;item123;' and '%;item1;%' first, then do sqlite like operation.
|
|
2385
|
+
let sql = operator === ComparisonOperator.includes || operator === ComparisonOperator.excludes
|
|
2386
|
+
? `'${MultiPickListValueSeparator$1}' || json_extract("${expression.jsonAlias}.JSON", '${pathPrefix}.${path}') || '${MultiPickListValueSeparator$1}'`
|
|
2387
|
+
: `json_extract("${expression.jsonAlias}.JSON", '${pathPrefix}.${path}')`;
|
|
2366
2388
|
if (targetDataType !== undefined) {
|
|
2367
2389
|
sql = coerceToTargetDataType(sql, targetDataType);
|
|
2368
2390
|
}
|
|
@@ -2409,7 +2431,7 @@ function expressionToSql(expression, targetDataType) {
|
|
|
2409
2431
|
case ValueType.StringLiteral:
|
|
2410
2432
|
return stringLiteralToSql(expression);
|
|
2411
2433
|
case ValueType.MultiPicklistSet:
|
|
2412
|
-
return multiPicklistToSql$1(expression);
|
|
2434
|
+
return multiPicklistToSql$1(expression, operator);
|
|
2413
2435
|
}
|
|
2414
2436
|
}
|
|
2415
2437
|
function stringLiteralToSql(string) {
|
|
@@ -2425,14 +2447,18 @@ function expressionArrayToSql(expressions, toSql) {
|
|
|
2425
2447
|
const bindings = results.length > 0 ? results.map((v) => v.bindings).reduce(flatten$1) : [];
|
|
2426
2448
|
return { sql, bindings };
|
|
2427
2449
|
}
|
|
2428
|
-
function multiPicklistToSql$1({ value }) {
|
|
2450
|
+
function multiPicklistToSql$1({ value }, operator) {
|
|
2429
2451
|
// Individual multipicklist terms that delimited by semicolon are stored server-side
|
|
2430
2452
|
// as lexically sorted strings and treated like logical ANDs. We can approximate this
|
|
2431
2453
|
// behavior in SQL with wildcarded `LIKE` SQL operators. Terms with no delimiter can
|
|
2432
2454
|
// be treated as string literals. Multiple terms are logically OR'd together to
|
|
2433
2455
|
// match the behavior described in SOQL documentation (https://sfdc.co/c9j0r)
|
|
2456
|
+
// To make sure the match is safe for includes/excludes. the value is prefix and
|
|
2457
|
+
// suffix with ';', like 'abc' to '%;abc;%'. raw value for eq and ne.
|
|
2434
2458
|
const sql = '?';
|
|
2435
|
-
const binding =
|
|
2459
|
+
const binding = operator === ComparisonOperator.includes || operator === ComparisonOperator.excludes
|
|
2460
|
+
? `%${MultiPickListValueSeparator$1}${value}${MultiPickListValueSeparator$1}%`
|
|
2461
|
+
: value;
|
|
2436
2462
|
return { sql, bindings: [binding] };
|
|
2437
2463
|
}
|
|
2438
2464
|
function relativeDateToSql(expression) {
|
|
@@ -2503,8 +2529,12 @@ function comparisonDateLiteralToSql(leftOperand, operator, dateInput) {
|
|
|
2503
2529
|
}
|
|
2504
2530
|
}
|
|
2505
2531
|
if (dateInput.type === ValueType.DateValue || dateInput.type === ValueType.DateTimeValue) {
|
|
2532
|
+
const dateFunction = dateInput.type === ValueType.DateTimeValue ? 'datetime' : 'date';
|
|
2506
2533
|
const compOperator = comparisonOperatorToSql(operator);
|
|
2507
|
-
return {
|
|
2534
|
+
return {
|
|
2535
|
+
sql: leftOperand + ` ${compOperator} ` + `${dateFunction}(?)`,
|
|
2536
|
+
bindings: [`${dateInput.value}`],
|
|
2537
|
+
};
|
|
2508
2538
|
}
|
|
2509
2539
|
return { sql: '', bindings: [] };
|
|
2510
2540
|
}
|
|
@@ -2735,15 +2765,41 @@ function fieldFilter(fieldName, fieldNode, alias, apiName, input, joins) {
|
|
|
2735
2765
|
return dateRangeComparison(op.value, op.operator, extract);
|
|
2736
2766
|
}
|
|
2737
2767
|
if (op.type === 'MultiPicklistSetOperator') {
|
|
2768
|
+
const operator = op.operator === ComparisonOperator.includes
|
|
2769
|
+
? CompoundOperator.or
|
|
2770
|
+
: CompoundOperator.and;
|
|
2771
|
+
const children = [];
|
|
2772
|
+
const length = op.value.value.length;
|
|
2773
|
+
for (let i = 0; i < length; i++) {
|
|
2774
|
+
const term = op.value.value[i];
|
|
2775
|
+
if (term !== null) {
|
|
2776
|
+
const splittedValue = term.split(MultiPickListValueSeparator$1);
|
|
2777
|
+
if (splittedValue.length === 1) {
|
|
2778
|
+
children.push(comparison(extract, op.operator, {
|
|
2779
|
+
type: ValueType.MultiPicklistSet,
|
|
2780
|
+
value: term,
|
|
2781
|
+
}));
|
|
2782
|
+
}
|
|
2783
|
+
else {
|
|
2784
|
+
children.push({
|
|
2785
|
+
type: PredicateType$1.compound,
|
|
2786
|
+
operator: op.operator === ComparisonOperator.includes
|
|
2787
|
+
? CompoundOperator.and
|
|
2788
|
+
: CompoundOperator.or,
|
|
2789
|
+
children: splittedValue.map((singleValue) => {
|
|
2790
|
+
return comparison(extract, op.operator, {
|
|
2791
|
+
type: ValueType.MultiPicklistSet,
|
|
2792
|
+
value: singleValue,
|
|
2793
|
+
});
|
|
2794
|
+
}),
|
|
2795
|
+
});
|
|
2796
|
+
}
|
|
2797
|
+
}
|
|
2798
|
+
}
|
|
2738
2799
|
return {
|
|
2739
2800
|
type: PredicateType$1.compound,
|
|
2740
|
-
operator
|
|
2741
|
-
children
|
|
2742
|
-
return comparison(extract, op.operator, {
|
|
2743
|
-
type: ValueType.MultiPicklistSet,
|
|
2744
|
-
value: term,
|
|
2745
|
-
});
|
|
2746
|
-
}),
|
|
2801
|
+
operator,
|
|
2802
|
+
children,
|
|
2747
2803
|
};
|
|
2748
2804
|
}
|
|
2749
2805
|
if (op.type === 'StringSetOperator' && op.value.value.includes(null)) {
|
|
@@ -2807,8 +2863,6 @@ function dateRangeComparison(dateRange, operator, compareDate) {
|
|
|
2807
2863
|
return comparison(compareDate, gte, dateRange.start);
|
|
2808
2864
|
}
|
|
2809
2865
|
}
|
|
2810
|
-
const dateRegEx = /^([12]\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01]))$/;
|
|
2811
|
-
const dateTimeRegEx = /^([12]\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01]))T(2[0-3]|[01][0-9]):[0-5][0-9]:[0-5][0-9](\.[0-9]{3})?Z$/;
|
|
2812
2866
|
function dateFunctions(operatorNode, extract, dataType) {
|
|
2813
2867
|
if (dataType !== 'Date' && dataType !== 'DateTime') {
|
|
2814
2868
|
return success([]);
|
|
@@ -2886,7 +2940,7 @@ function isStringOperatorType(value) {
|
|
|
2886
2940
|
return isScalarOperatorType(value) || value === like;
|
|
2887
2941
|
}
|
|
2888
2942
|
function isPicklistOperatorType(value) {
|
|
2889
|
-
let values = [eq, ne];
|
|
2943
|
+
let values = [eq, ne, like, lt, gt, lte, gte];
|
|
2890
2944
|
return values.includes(value);
|
|
2891
2945
|
}
|
|
2892
2946
|
function isCurrencyOperatorType(value) {
|
|
@@ -3237,8 +3291,11 @@ function operatorWithValue(operator, valueNode, objectInfoDataType) {
|
|
|
3237
3291
|
message(`Comparison operator ${operator} is not supported for type ${objectInfoDataType}.`),
|
|
3238
3292
|
]);
|
|
3239
3293
|
}
|
|
3294
|
+
function isValidDate(value) {
|
|
3295
|
+
return isNaN(Date.parse(value)) === false;
|
|
3296
|
+
}
|
|
3240
3297
|
function dateInput(node) {
|
|
3241
|
-
return parseDateNode(node,
|
|
3298
|
+
return parseDateNode(node, false, 'YYYY-MM-DD', isValidDate).map((result) => {
|
|
3242
3299
|
switch (result.type) {
|
|
3243
3300
|
case ValueType.NullValue:
|
|
3244
3301
|
return result;
|
|
@@ -3252,7 +3309,7 @@ function dateInput(node) {
|
|
|
3252
3309
|
});
|
|
3253
3310
|
}
|
|
3254
3311
|
function dateTimeInput(node) {
|
|
3255
|
-
return parseDateNode(node,
|
|
3312
|
+
return parseDateNode(node, true, 'YYYY-MM-DDTHH:MM:SS.SSSZ, YYYY-MM-DDTHH:MM:SSZ, YYYY-MM-DDTHH:MM:SS.SSS+|-HH:MM, or YYYY-MM-DDTHH:MM:SS+|-HH:MM', isValidDate).map((result) => {
|
|
3256
3313
|
switch (result.type) {
|
|
3257
3314
|
case ValueType.NullValue:
|
|
3258
3315
|
return result;
|
|
@@ -3277,7 +3334,7 @@ function parseNullValue(op) {
|
|
|
3277
3334
|
}
|
|
3278
3335
|
return failure(message(`Null can not be compared with ${op}`));
|
|
3279
3336
|
}
|
|
3280
|
-
function parseDateNode(node,
|
|
3337
|
+
function parseDateNode(node, hasTime, dateFormat, isValidDate) {
|
|
3281
3338
|
const typeName = hasTime ? 'DateTime' : 'Date';
|
|
3282
3339
|
if (!isObjectValueNode$1(node)) {
|
|
3283
3340
|
return failure(message(`Comparison value must be a ${typeName} input.`));
|
|
@@ -3285,7 +3342,12 @@ function parseDateNode(node, regex, hasTime, dateFormat) {
|
|
|
3285
3342
|
const valueField = node.fields.value;
|
|
3286
3343
|
if (valueField !== undefined) {
|
|
3287
3344
|
if (is(valueField, 'StringValue')) {
|
|
3288
|
-
|
|
3345
|
+
// check the date is valid
|
|
3346
|
+
// then make sure if it isnt suppose to contain time stamps that it doesnt
|
|
3347
|
+
// and if it should have a timestamp it should contain it
|
|
3348
|
+
const includesTimeStamp = valueField.value.includes('T');
|
|
3349
|
+
if (isValidDate(valueField.value) &&
|
|
3350
|
+
((hasTime && includesTimeStamp) || (!hasTime && !includesTimeStamp))) {
|
|
3289
3351
|
return success(stringLiteral(valueField.value));
|
|
3290
3352
|
}
|
|
3291
3353
|
return failure(message(`${typeName} format must be ${dateFormat}.`));
|
|
@@ -4277,7 +4339,20 @@ function makeStoreEval(preconditioner, objectInfoService, userId, contextProvide
|
|
|
4277
4339
|
// await it here to normalize the input to a snapshot
|
|
4278
4340
|
const nonEvaluatedSnapshot = await nonEvaluatedSnapshotOrPromise;
|
|
4279
4341
|
// if the non-eval result has errors we want to return to caller
|
|
4280
|
-
|
|
4342
|
+
const nonEvaluatedGQLSnapshot = nonEvaluatedSnapshot;
|
|
4343
|
+
if (isErrorSnapshotThatShouldGetReturnedToCaller$1(nonEvaluatedGQLSnapshot)) {
|
|
4344
|
+
const { data: gqlData } = nonEvaluatedGQLSnapshot;
|
|
4345
|
+
if (hasGraphQlErrors$1(gqlData) && gqlData !== undefined) {
|
|
4346
|
+
return {
|
|
4347
|
+
...nonEvaluatedSnapshot,
|
|
4348
|
+
data: undefined,
|
|
4349
|
+
state: 'Error',
|
|
4350
|
+
error: {
|
|
4351
|
+
errorType: 'adapterError',
|
|
4352
|
+
error: gqlData.errors,
|
|
4353
|
+
},
|
|
4354
|
+
};
|
|
4355
|
+
}
|
|
4281
4356
|
return nonEvaluatedSnapshot;
|
|
4282
4357
|
}
|
|
4283
4358
|
let rootQuery;
|
|
@@ -10948,6 +11023,10 @@ function makeEnvironmentUiApiRecordDraftAware(luvio, options, env) {
|
|
|
10948
11023
|
return create$2(adapterSpecificEnvironments, {});
|
|
10949
11024
|
}
|
|
10950
11025
|
|
|
11026
|
+
function clone(obj) {
|
|
11027
|
+
return parse$2(stringify$2(obj));
|
|
11028
|
+
}
|
|
11029
|
+
|
|
10951
11030
|
const DEFAULT_FIELD_CREATED_BY_ID = 'CreatedById';
|
|
10952
11031
|
const DEFAULT_FIELD_CREATED_DATE = 'CreatedDate';
|
|
10953
11032
|
const DEFAULT_FIELD_ID = 'Id';
|
|
@@ -10975,7 +11054,9 @@ function replayDraftsOnRecord(record, draftMetadata) {
|
|
|
10975
11054
|
// no baseRecord
|
|
10976
11055
|
return undefined;
|
|
10977
11056
|
}
|
|
10978
|
-
const { recordOperations } = draftMetadata;
|
|
11057
|
+
const { recordOperations: originalOperations } = draftMetadata;
|
|
11058
|
+
// since replaying drafts is destructive, we need to clone the original operations
|
|
11059
|
+
const recordOperations = clone(originalOperations);
|
|
10979
11060
|
if (recordOperations.length === 0) {
|
|
10980
11061
|
return undefined;
|
|
10981
11062
|
}
|
|
@@ -11006,7 +11087,11 @@ function recursivelyApplyDraftsToRecord(record, draftMetadata, recordOperations)
|
|
|
11006
11087
|
}
|
|
11007
11088
|
const draftActionType = draftOperation.type;
|
|
11008
11089
|
if (draftActionType === 'create') {
|
|
11009
|
-
|
|
11090
|
+
if (record.drafts !== undefined) {
|
|
11091
|
+
throw Error('a create action cannot exist on an existing draft record');
|
|
11092
|
+
}
|
|
11093
|
+
// the draft may have been uploaded already so skip the create operation and apply the rest (if any)
|
|
11094
|
+
return recursivelyApplyDraftsToRecord(record, draftMetadata, recordOperations);
|
|
11010
11095
|
}
|
|
11011
11096
|
// add the draft node
|
|
11012
11097
|
if (record.drafts === undefined) {
|
|
@@ -11769,6 +11854,11 @@ function makeRecordDenormalizingDurableStore(luvio, durableStore, getStoreRecord
|
|
|
11769
11854
|
let record = entry && entry.data;
|
|
11770
11855
|
if (record === undefined) {
|
|
11771
11856
|
record = storeRecords[recordKey];
|
|
11857
|
+
if (record === undefined) {
|
|
11858
|
+
// fields are being published without a record for them existing,
|
|
11859
|
+
// fields cannot exist standalone in the durable store
|
|
11860
|
+
continue;
|
|
11861
|
+
}
|
|
11772
11862
|
}
|
|
11773
11863
|
putRecords[recordId] = true;
|
|
11774
11864
|
if (isStoreRecordError(record)) {
|
|
@@ -15636,4 +15726,4 @@ register({
|
|
|
15636
15726
|
});
|
|
15637
15727
|
|
|
15638
15728
|
export { getRuntime, registerReportObserver, reportGraphqlQueryParseError };
|
|
15639
|
-
// version: 1.
|
|
15729
|
+
// version: 1.130.9-2d38b9869
|