@salesforce/lds-runtime-bridge 1.292.0 → 1.294.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/ldsRuntimeBridge.js +293 -191
- package/package.json +8 -8
package/dist/ldsRuntimeBridge.js
CHANGED
|
@@ -1110,7 +1110,7 @@ function makeDurable(environment, { durableStore, instrumentation, useRevivingSt
|
|
|
1110
1110
|
});
|
|
1111
1111
|
}
|
|
1112
1112
|
|
|
1113
|
-
const { keys: keys$2, create: create$2, assign: assign$2, entries: entries$
|
|
1113
|
+
const { keys: keys$2, create: create$2, assign: assign$2, entries: entries$2, values: values$2 } = Object;
|
|
1114
1114
|
const { stringify: stringify$1, parse: parse$1 } = JSON;
|
|
1115
1115
|
|
|
1116
1116
|
function selectColumnsFromTableWhereKeyIn(columnNames, table, keyColumnName, whereIn) {
|
|
@@ -1366,6 +1366,9 @@ class NimbusSqliteStore {
|
|
|
1366
1366
|
isEvalSupported() {
|
|
1367
1367
|
return true;
|
|
1368
1368
|
}
|
|
1369
|
+
isBatchUpdateSupported() {
|
|
1370
|
+
return this.supportsBatchUpdates;
|
|
1371
|
+
}
|
|
1369
1372
|
query(sql, params) {
|
|
1370
1373
|
return new Promise((resolve, reject) => {
|
|
1371
1374
|
this.plugin.query(sql, params, (result) => {
|
|
@@ -1764,7 +1767,7 @@ function buildQueryTypeStringKey(args) {
|
|
|
1764
1767
|
*/
|
|
1765
1768
|
|
|
1766
1769
|
|
|
1767
|
-
const { create: create$1, keys: keys$1, values: values$1, entries, assign: assign$1 } = Object;
|
|
1770
|
+
const { create: create$1, keys: keys$1, values: values$1, entries: entries$1, assign: assign$1 } = Object;
|
|
1768
1771
|
const { stringify, parse } = JSON;
|
|
1769
1772
|
const { isArray, from } = Array;
|
|
1770
1773
|
|
|
@@ -2452,7 +2455,7 @@ function filterToPredicates(where, recordType, alias, objectInfoMap, joins, draf
|
|
|
2452
2455
|
}
|
|
2453
2456
|
else {
|
|
2454
2457
|
//`field` match the filedInfo's apiName
|
|
2455
|
-
for (const [op, value] of entries(where[field])) {
|
|
2458
|
+
for (const [op, value] of entries$1(where[field])) {
|
|
2456
2459
|
const operator = operatorToSql(op);
|
|
2457
2460
|
/**
|
|
2458
2461
|
Two types ID processing might be needed. Draft ID swapping is optional, which depends on DraftFunctions existence.
|
|
@@ -2911,6 +2914,7 @@ function buildQuery(config) {
|
|
|
2911
2914
|
${predicates.sql}
|
|
2912
2915
|
${orderBy.sql}
|
|
2913
2916
|
LIMIT ?
|
|
2917
|
+
OFFSET ?
|
|
2914
2918
|
`
|
|
2915
2919
|
.split('\n')
|
|
2916
2920
|
.map((line) => line.trim())
|
|
@@ -2923,6 +2927,7 @@ function buildQuery(config) {
|
|
|
2923
2927
|
...predicates.bindings,
|
|
2924
2928
|
// limit binding
|
|
2925
2929
|
config.limit || 10,
|
|
2930
|
+
config.offset || 0,
|
|
2926
2931
|
];
|
|
2927
2932
|
return { sql: sql.trim(), bindings };
|
|
2928
2933
|
}
|
|
@@ -3067,32 +3072,6 @@ async function readIngestionTimestampForKey(key, query) {
|
|
|
3067
3072
|
return ingestionTimestamp;
|
|
3068
3073
|
}
|
|
3069
3074
|
|
|
3070
|
-
// Code lifted from https://github.com/MaxArt2501/base64-js/blob/master/base64.js
|
|
3071
|
-
// base64 character set, plus padding character (=)
|
|
3072
|
-
const b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
|
|
3073
|
-
function btoaPolyfill(input) {
|
|
3074
|
-
let bitmap, a, b, c;
|
|
3075
|
-
let result = '', i = 0;
|
|
3076
|
-
const rest = input.length % 3; // To determine the final padding
|
|
3077
|
-
for (; i < input.length;) {
|
|
3078
|
-
if ((a = input.charCodeAt(i++)) > 255 ||
|
|
3079
|
-
(b = input.charCodeAt(i++)) > 255 ||
|
|
3080
|
-
(c = input.charCodeAt(i++)) > 255) {
|
|
3081
|
-
throw new TypeError('Failed base64ToAscii encoding: The string to be encoded contains characters outside of the Latin1 range. ' +
|
|
3082
|
-
input);
|
|
3083
|
-
}
|
|
3084
|
-
bitmap = (a << 16) | (b << 8) | c;
|
|
3085
|
-
result +=
|
|
3086
|
-
b64.charAt((bitmap >> 18) & 63) +
|
|
3087
|
-
b64.charAt((bitmap >> 12) & 63) +
|
|
3088
|
-
b64.charAt((bitmap >> 6) & 63) +
|
|
3089
|
-
b64.charAt(bitmap & 63);
|
|
3090
|
-
}
|
|
3091
|
-
// If there's need of padding, replace the last 'A's with equal signs
|
|
3092
|
-
return rest ? result.slice(0, rest - 3) + '==='.substring(rest) : result;
|
|
3093
|
-
}
|
|
3094
|
-
const base64encode = typeof btoa === 'function' ? btoa : btoaPolyfill;
|
|
3095
|
-
|
|
3096
3075
|
function findSpanningField(name) {
|
|
3097
3076
|
return (field) => {
|
|
3098
3077
|
return (field.apiName === name ||
|
|
@@ -3239,9 +3218,228 @@ function scopeToPredicates(scope = '', settings) {
|
|
|
3239
3218
|
];
|
|
3240
3219
|
}
|
|
3241
3220
|
|
|
3242
|
-
|
|
3243
|
-
|
|
3221
|
+
// Code lifted from https://github.com/MaxArt2501/base64-js/blob/master/base64.js
|
|
3222
|
+
// base64 character set, plus padding character (=)
|
|
3223
|
+
const b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
|
|
3224
|
+
const b64re = /^(?:[A-Za-z\d+/]{4})*?(?:[A-Za-z\d+/]{2}(?:==)?|[A-Za-z\d+/]{3}=?)?$/;
|
|
3225
|
+
function btoaPolyfill(input) {
|
|
3226
|
+
let bitmap, a, b, c;
|
|
3227
|
+
let result = '', i = 0;
|
|
3228
|
+
const rest = input.length % 3; // To determine the final padding
|
|
3229
|
+
for (; i < input.length;) {
|
|
3230
|
+
if ((a = input.charCodeAt(i++)) > 255 ||
|
|
3231
|
+
(b = input.charCodeAt(i++)) > 255 ||
|
|
3232
|
+
(c = input.charCodeAt(i++)) > 255) {
|
|
3233
|
+
throw new TypeError('Failed base64ToAscii encoding: The string to be encoded contains characters outside of the Latin1 range. ' +
|
|
3234
|
+
input);
|
|
3235
|
+
}
|
|
3236
|
+
bitmap = (a << 16) | (b << 8) | c;
|
|
3237
|
+
result +=
|
|
3238
|
+
b64.charAt((bitmap >> 18) & 63) +
|
|
3239
|
+
b64.charAt((bitmap >> 12) & 63) +
|
|
3240
|
+
b64.charAt((bitmap >> 6) & 63) +
|
|
3241
|
+
b64.charAt(bitmap & 63);
|
|
3242
|
+
}
|
|
3243
|
+
// If there's need of padding, replace the last 'A's with equal signs
|
|
3244
|
+
return rest ? result.slice(0, rest - 3) + '==='.substring(rest) : result;
|
|
3245
|
+
}
|
|
3246
|
+
function atobPolyfill(data) {
|
|
3247
|
+
// atob can work with strings with whitespaces, even inside the encoded part,
|
|
3248
|
+
// but only \t, \n, \f, \r and ' ', which can be stripped.
|
|
3249
|
+
let string = String(data).replace(/[\t\n\f\r ]+/g, '');
|
|
3250
|
+
if (!b64re.test(string))
|
|
3251
|
+
throw new TypeError("Failed to execute 'atob' on 'Window': The string to be decoded is not correctly encoded.");
|
|
3252
|
+
// Adding the padding if missing, for semplicity
|
|
3253
|
+
string += '=='.slice(2 - (string.length & 3));
|
|
3254
|
+
var bitmap, result = '', r1, r2, i = 0;
|
|
3255
|
+
for (; i < string.length;) {
|
|
3256
|
+
bitmap =
|
|
3257
|
+
(b64.indexOf(string.charAt(i++)) << 18) |
|
|
3258
|
+
(b64.indexOf(string.charAt(i++)) << 12) |
|
|
3259
|
+
((r1 = b64.indexOf(string.charAt(i++))) << 6) |
|
|
3260
|
+
(r2 = b64.indexOf(string.charAt(i++)));
|
|
3261
|
+
result +=
|
|
3262
|
+
r1 === 64
|
|
3263
|
+
? String.fromCharCode((bitmap >> 16) & 255)
|
|
3264
|
+
: r2 === 64
|
|
3265
|
+
? String.fromCharCode((bitmap >> 16) & 255, (bitmap >> 8) & 255)
|
|
3266
|
+
: String.fromCharCode((bitmap >> 16) & 255, (bitmap >> 8) & 255, bitmap & 255);
|
|
3267
|
+
}
|
|
3268
|
+
return result;
|
|
3269
|
+
}
|
|
3270
|
+
const base64encode = typeof btoa === 'function' ? btoa : btoaPolyfill;
|
|
3271
|
+
const base64decode = typeof atob === 'function' ? atob : atobPolyfill;
|
|
3272
|
+
|
|
3273
|
+
function cursorResolver(source) {
|
|
3274
|
+
return encodeV1Cursor(source.index);
|
|
3275
|
+
}
|
|
3276
|
+
function pageInfoResolver(source) {
|
|
3277
|
+
if (source.length === 0) {
|
|
3278
|
+
return {
|
|
3279
|
+
startCursor: null,
|
|
3280
|
+
endCursor: null,
|
|
3281
|
+
};
|
|
3282
|
+
}
|
|
3283
|
+
let startIndex = source[0].index;
|
|
3284
|
+
let endIndex = source[source.length - 1].index;
|
|
3285
|
+
return {
|
|
3286
|
+
startCursor: encodeV1Cursor(startIndex),
|
|
3287
|
+
endCursor: encodeV1Cursor(endIndex),
|
|
3288
|
+
};
|
|
3289
|
+
}
|
|
3290
|
+
function pageResultCountResolver(source) {
|
|
3291
|
+
return source.length;
|
|
3292
|
+
}
|
|
3293
|
+
function encodeV1Cursor(index) {
|
|
3294
|
+
return base64encode(`v1:${index}`);
|
|
3295
|
+
}
|
|
3296
|
+
const cursorRegex = /^v1:(?<index>\d+)$/;
|
|
3297
|
+
function decodeV1Cursor(base64cursor) {
|
|
3298
|
+
const cursor = base64decode(base64cursor);
|
|
3299
|
+
if (!cursor) {
|
|
3300
|
+
// eslint-disable-next-line @salesforce/lds/no-error-in-production
|
|
3301
|
+
throw new Error('Unable to parse cursor');
|
|
3302
|
+
}
|
|
3303
|
+
const found = cursor.match(cursorRegex);
|
|
3304
|
+
if (!found || !found.groups) {
|
|
3305
|
+
// eslint-disable-next-line @salesforce/lds/no-error-in-production
|
|
3306
|
+
throw new Error('Unable to parse cursor');
|
|
3307
|
+
}
|
|
3308
|
+
return Number(found.groups.index);
|
|
3309
|
+
}
|
|
3310
|
+
|
|
3311
|
+
/*
|
|
3312
|
+
resolves connections...
|
|
3313
|
+
*/
|
|
3314
|
+
async function connectionResolver(obj, args, context, info) {
|
|
3315
|
+
let { recordRepresentation: parentRecord, ingestionTimestamp = 0 } = obj;
|
|
3316
|
+
if (!parentRecord && excludeStaleRecordsGate.isOpen({ fallback: false })) {
|
|
3317
|
+
// at our record query we fetch each ingestion time stamp and pass it down to each lower resolver to query against
|
|
3318
|
+
ingestionTimestamp = await fetchIngestionTimeStampFromDatabase(info.fieldName, info, args, context.query);
|
|
3319
|
+
}
|
|
3320
|
+
const { query, objectInfos, draftFunctions } = context;
|
|
3321
|
+
let joins = [];
|
|
3322
|
+
let alias = info.fieldName;
|
|
3323
|
+
let childRelationshipFieldName = undefined;
|
|
3324
|
+
if (parentRecord) {
|
|
3325
|
+
context.seenRecordIds.add(parentRecord.id);
|
|
3326
|
+
const parentApiName = parentRecord.apiName;
|
|
3327
|
+
const parentObjectInfo = objectInfos[parentApiName];
|
|
3328
|
+
const childRelationship = parentObjectInfo &&
|
|
3329
|
+
parentObjectInfo.childRelationships.find((rel) => rel.relationshipName === info.fieldName);
|
|
3330
|
+
// or emit/throw if we want to report it
|
|
3331
|
+
if (!childRelationship)
|
|
3332
|
+
return [];
|
|
3333
|
+
alias = childRelationship.childObjectApiName;
|
|
3334
|
+
childRelationshipFieldName = childRelationship.fieldName;
|
|
3335
|
+
}
|
|
3336
|
+
// Alias starts as entity's ApiName
|
|
3337
|
+
const predicates = [
|
|
3338
|
+
...filterToPredicates(args.where, alias, alias, context.objectInfos, joins, draftFunctions),
|
|
3339
|
+
...scopeToPredicates(args.scope, context.settings),
|
|
3340
|
+
...childRelationshipToPredicates(childRelationshipFieldName, parentRecord ? parentRecord.id : undefined),
|
|
3341
|
+
];
|
|
3342
|
+
const scopeJoins = scopeToJoins(args.scope, context.settings);
|
|
3343
|
+
joins.push(...scopeJoins);
|
|
3344
|
+
let offset = 0;
|
|
3345
|
+
if (args.after) {
|
|
3346
|
+
offset = decodeV1Cursor(args.after) + 1;
|
|
3347
|
+
}
|
|
3348
|
+
// Alias starts as entity's ApiName
|
|
3349
|
+
const queryConfig = {
|
|
3350
|
+
alias,
|
|
3351
|
+
joins,
|
|
3352
|
+
predicates,
|
|
3353
|
+
orderBy: orderByToPredicate(args.orderBy, alias, alias, context.objectInfos),
|
|
3354
|
+
limit: args.first,
|
|
3355
|
+
offset: offset,
|
|
3356
|
+
ingestionTimestamp,
|
|
3357
|
+
};
|
|
3358
|
+
const { sql, bindings } = buildQuery(queryConfig);
|
|
3359
|
+
const results = await query(sql, bindings);
|
|
3360
|
+
//map each sql result with the ingestion timestamp to pass it down a level
|
|
3361
|
+
return results.rows
|
|
3362
|
+
.map((row) => parse(row[0]))
|
|
3363
|
+
.map((recordRepresentation, index) => {
|
|
3364
|
+
context.seenRecordIds.add(recordRepresentation.id);
|
|
3365
|
+
return {
|
|
3366
|
+
recordRepresentation,
|
|
3367
|
+
ingestionTimestamp,
|
|
3368
|
+
index: index + offset,
|
|
3369
|
+
};
|
|
3370
|
+
});
|
|
3371
|
+
}
|
|
3372
|
+
/**
|
|
3373
|
+
* Converts a childRelationship into a predicate
|
|
3374
|
+
* @param childRelationshipFieldName Reference ID field name to its parent record. A defined `childRelationshipFieldName` string indicates that a child relationship exists
|
|
3375
|
+
* and a relationship predicate needs to be put into place. For example, `ServiceAppointment` has a child relationship `ServiceResources`, whose entity name is `AssignedResource`.
|
|
3376
|
+
* Once the parent `ServiceAppointment` record comes back, its child connection starts to resolve. Child `AssignedResource` record needs to reference to parent Id using field `ServiceAppointmentId`.
|
|
3377
|
+
* @param parentId prarent record Id
|
|
3378
|
+
* @returns predicate array consists at most 1 predicate
|
|
3379
|
+
*/
|
|
3380
|
+
function childRelationshipToPredicates(childRelationshipFieldName, parentId) {
|
|
3381
|
+
const predicates = [];
|
|
3382
|
+
if (childRelationshipFieldName !== undefined && parentId !== undefined) {
|
|
3383
|
+
predicates.push({
|
|
3384
|
+
type: PredicateType.single,
|
|
3385
|
+
leftPath: `$.fields.${childRelationshipFieldName}.value`,
|
|
3386
|
+
operator: '=',
|
|
3387
|
+
value: parentId,
|
|
3388
|
+
});
|
|
3389
|
+
}
|
|
3390
|
+
return predicates;
|
|
3391
|
+
}
|
|
3392
|
+
/**
|
|
3393
|
+
* fetches a query level ingestion time stamp from the L2 cache
|
|
3394
|
+
* if no query has been seen then the timestamp is 0
|
|
3395
|
+
* @param apiName
|
|
3396
|
+
* @param info
|
|
3397
|
+
* @param args
|
|
3398
|
+
* @param query
|
|
3399
|
+
* @returns
|
|
3400
|
+
*/
|
|
3401
|
+
async function fetchIngestionTimeStampFromDatabase(apiName, info, args, query) {
|
|
3402
|
+
const { operation, variableValues } = info;
|
|
3403
|
+
// if we cannot find the query key in the database then default to 0 as we assume we have not seen the query
|
|
3404
|
+
// and all the data is not stale
|
|
3405
|
+
let ingestionTimestamp = 0;
|
|
3406
|
+
if (info.fieldNodes.length > 0 && info.fieldNodes[0].arguments !== undefined) {
|
|
3407
|
+
const key = buildKeyStringForRecordQuery(operation,
|
|
3408
|
+
// join varables passed from query to the argument variables given from the AST
|
|
3409
|
+
{ ...variableValues, ...args }, info.fieldNodes[0].arguments, apiName);
|
|
3410
|
+
return readIngestionTimestampForKey(key, query);
|
|
3411
|
+
}
|
|
3412
|
+
return ingestionTimestamp;
|
|
3413
|
+
}
|
|
3414
|
+
/**
|
|
3415
|
+
* Builds the top level record query key based on AST data
|
|
3416
|
+
* @param operation
|
|
3417
|
+
* @param variables
|
|
3418
|
+
* @param argumentNodes
|
|
3419
|
+
* @param currentFieldName
|
|
3420
|
+
* @returns
|
|
3421
|
+
*/
|
|
3422
|
+
function buildKeyStringForRecordQuery(operation, variables, argumentNodes, currentFieldName) {
|
|
3423
|
+
const queryKey = buildQueryTypeStringKey({
|
|
3424
|
+
luvio: {},
|
|
3425
|
+
keyPrefix: 'UiApi',
|
|
3426
|
+
schemaName: 'uiapi',
|
|
3427
|
+
queryTypeName: 'Query',
|
|
3428
|
+
operationNode: operation,
|
|
3429
|
+
variables,
|
|
3430
|
+
fragmentMap: {},
|
|
3431
|
+
});
|
|
3432
|
+
const filteredArgumentNodes = assign$1([], argumentNodes).filter((node) => node.name.value !== 'first' && node.name.value !== 'after');
|
|
3433
|
+
const argumentString = filteredArgumentNodes.length > 0
|
|
3434
|
+
? '__' + serializeFieldArguments(filteredArgumentNodes, variables)
|
|
3435
|
+
: '';
|
|
3436
|
+
return `${queryKey}__uiapi__query__${currentFieldName}${argumentString}`;
|
|
3437
|
+
}
|
|
3438
|
+
|
|
3439
|
+
function passThroughResolver(source) {
|
|
3440
|
+
return source;
|
|
3244
3441
|
}
|
|
3442
|
+
|
|
3245
3443
|
/**
|
|
3246
3444
|
*
|
|
3247
3445
|
* @param schema GraphQL Schema generated from ObjectInfos
|
|
@@ -3274,13 +3472,13 @@ function addResolversToSchema(schema, polyFields) {
|
|
|
3274
3472
|
}
|
|
3275
3473
|
if (type.name === 'Query') {
|
|
3276
3474
|
for (const field of fields) {
|
|
3277
|
-
field.resolve =
|
|
3475
|
+
field.resolve = passThroughResolver;
|
|
3278
3476
|
}
|
|
3279
3477
|
}
|
|
3280
3478
|
if (type.name === 'UIAPI') {
|
|
3281
3479
|
for (const field of fields) {
|
|
3282
3480
|
if (field.name === 'query') {
|
|
3283
|
-
field.resolve =
|
|
3481
|
+
field.resolve = passThroughResolver;
|
|
3284
3482
|
}
|
|
3285
3483
|
else {
|
|
3286
3484
|
const fieldName = field.name;
|
|
@@ -3307,23 +3505,7 @@ function addResolversToSchema(schema, polyFields) {
|
|
|
3307
3505
|
// Fields of the `RecordQuery` type are the record queries for the entity types
|
|
3308
3506
|
// supported for the org
|
|
3309
3507
|
for (const recordQuery of fields) {
|
|
3310
|
-
recordQuery.resolve =
|
|
3311
|
-
const { name: currentFieldName } = recordQuery;
|
|
3312
|
-
let ingestionTimestamp = 0;
|
|
3313
|
-
if (excludeStaleRecordsGate.isOpen({ fallback: false })) {
|
|
3314
|
-
// at our record query we fetch each ingestion time stamp and pass it down to each lower resolver to query against
|
|
3315
|
-
ingestionTimestamp = await fetchIngestionTimeStampFromDatabase(currentFieldName, info, args, query);
|
|
3316
|
-
}
|
|
3317
|
-
// In the SF schema, the relevant arguments are passed into RecordQuery fields, but actually used
|
|
3318
|
-
// down in the edge resolvers. For this resolver, we can just return what was passed in
|
|
3319
|
-
// to make it available to the next execution step
|
|
3320
|
-
return {
|
|
3321
|
-
parentArgs: args,
|
|
3322
|
-
parentRecord: record,
|
|
3323
|
-
currentFieldName,
|
|
3324
|
-
ingestionTimestamp,
|
|
3325
|
-
};
|
|
3326
|
-
};
|
|
3508
|
+
recordQuery.resolve = connectionResolver;
|
|
3327
3509
|
}
|
|
3328
3510
|
}
|
|
3329
3511
|
if (type.name.endsWith('Connection')) {
|
|
@@ -3344,7 +3526,13 @@ function addResolversToSchema(schema, polyFields) {
|
|
|
3344
3526
|
for (const field of fields) {
|
|
3345
3527
|
switch (field.name) {
|
|
3346
3528
|
case 'edges':
|
|
3347
|
-
field.resolve =
|
|
3529
|
+
field.resolve = passThroughResolver;
|
|
3530
|
+
break;
|
|
3531
|
+
case 'pageInfo':
|
|
3532
|
+
field.resolve = pageInfoResolver;
|
|
3533
|
+
break;
|
|
3534
|
+
case 'pageResultCount':
|
|
3535
|
+
field.resolve = pageResultCountResolver;
|
|
3348
3536
|
break;
|
|
3349
3537
|
default:
|
|
3350
3538
|
field.resolve = defaultFieldResolver;
|
|
@@ -3367,17 +3555,10 @@ function addResolversToSchema(schema, polyFields) {
|
|
|
3367
3555
|
// }
|
|
3368
3556
|
for (const field of fields) {
|
|
3369
3557
|
if (field.name === 'node') {
|
|
3370
|
-
field.resolve =
|
|
3371
|
-
const { record, ingestionTimestamp } = obj;
|
|
3372
|
-
const recordRepresentation = parse(record);
|
|
3373
|
-
seenRecordIds.add(recordRepresentation.id);
|
|
3374
|
-
return { recordRepresentation, ingestionTimestamp };
|
|
3375
|
-
};
|
|
3558
|
+
field.resolve = passThroughResolver;
|
|
3376
3559
|
}
|
|
3377
3560
|
else if (field.name === 'cursor') {
|
|
3378
|
-
field.resolve =
|
|
3379
|
-
return base64encode(`v1:${index}`);
|
|
3380
|
-
};
|
|
3561
|
+
field.resolve = cursorResolver;
|
|
3381
3562
|
}
|
|
3382
3563
|
}
|
|
3383
3564
|
}
|
|
@@ -3492,16 +3673,7 @@ function addResolversToSchema(schema, polyFields) {
|
|
|
3492
3673
|
else if (isObjectType(recordFieldType) &&
|
|
3493
3674
|
field.type.name.endsWith('Connection')) {
|
|
3494
3675
|
// spanning field to a connection
|
|
3495
|
-
field.resolve =
|
|
3496
|
-
seenRecordIds.add(recordRepresentation.id);
|
|
3497
|
-
const { name: currentFieldName } = field;
|
|
3498
|
-
return {
|
|
3499
|
-
parentArgs: args,
|
|
3500
|
-
parentRecord: recordRepresentation,
|
|
3501
|
-
currentFieldName,
|
|
3502
|
-
ingestionTimestamp,
|
|
3503
|
-
};
|
|
3504
|
-
};
|
|
3676
|
+
field.resolve = connectionResolver;
|
|
3505
3677
|
}
|
|
3506
3678
|
else {
|
|
3507
3679
|
field.resolve = function recordFieldResolver({ recordRepresentation: record, }) {
|
|
@@ -3556,123 +3728,10 @@ _, { objectInfos }) {
|
|
|
3556
3728
|
}
|
|
3557
3729
|
return null;
|
|
3558
3730
|
}
|
|
3559
|
-
async function connectionEdgeResolver(obj, _args, context) {
|
|
3560
|
-
const { parentArgs = {}, parentRecord, currentFieldName, ingestionTimestamp } = obj;
|
|
3561
|
-
const { query, objectInfos, draftFunctions } = context;
|
|
3562
|
-
let joins = [];
|
|
3563
|
-
let alias = currentFieldName;
|
|
3564
|
-
let childRelationshipFieldName = undefined;
|
|
3565
|
-
if (parentRecord.id) {
|
|
3566
|
-
const parentApiName = parentRecord.apiName;
|
|
3567
|
-
const parentObjectInfo = objectInfos[parentApiName];
|
|
3568
|
-
const childRelationship = parentObjectInfo &&
|
|
3569
|
-
parentObjectInfo.childRelationships.find((rel) => rel.relationshipName === currentFieldName);
|
|
3570
|
-
// or emit/throw if we want to report it
|
|
3571
|
-
if (!childRelationship)
|
|
3572
|
-
return [];
|
|
3573
|
-
alias = childRelationship.childObjectApiName;
|
|
3574
|
-
childRelationshipFieldName = childRelationship.fieldName;
|
|
3575
|
-
}
|
|
3576
|
-
// Alias starts as entity's ApiName
|
|
3577
|
-
const predicates = [
|
|
3578
|
-
...filterToPredicates(parentArgs.where, alias, alias, context.objectInfos, joins, draftFunctions),
|
|
3579
|
-
...scopeToPredicates(parentArgs.scope, context.settings),
|
|
3580
|
-
...childRelationshipToPredicates(childRelationshipFieldName, parentRecord.id),
|
|
3581
|
-
];
|
|
3582
|
-
const scopeJoins = scopeToJoins(parentArgs.scope, context.settings);
|
|
3583
|
-
joins.push(...scopeJoins);
|
|
3584
|
-
// Alias starts as entity's ApiName
|
|
3585
|
-
const queryConfig = {
|
|
3586
|
-
alias,
|
|
3587
|
-
joins,
|
|
3588
|
-
predicates,
|
|
3589
|
-
orderBy: orderByToPredicate(parentArgs.orderBy, alias, alias, context.objectInfos),
|
|
3590
|
-
limit: parentArgs.first,
|
|
3591
|
-
ingestionTimestamp,
|
|
3592
|
-
};
|
|
3593
|
-
const { sql, bindings } = buildQuery(queryConfig);
|
|
3594
|
-
const results = await query(sql, bindings);
|
|
3595
|
-
//map each sql result with the ingestion timestamp to pass it down a level
|
|
3596
|
-
return results.rows
|
|
3597
|
-
.map((row) => row[0])
|
|
3598
|
-
.map((record, index) => {
|
|
3599
|
-
return {
|
|
3600
|
-
record,
|
|
3601
|
-
ingestionTimestamp,
|
|
3602
|
-
index,
|
|
3603
|
-
};
|
|
3604
|
-
});
|
|
3605
|
-
}
|
|
3606
|
-
/**
|
|
3607
|
-
* Converts a childRelationship into a predicate
|
|
3608
|
-
* @param childRelationshipFieldName Reference ID field name to its parent record. A defined `childRelationshipFieldName` string indicates that a child relationship exists
|
|
3609
|
-
* and a relationship predicate needs to be put into place. For example, `ServiceAppointment` has a child relationship `ServiceResources`, whose entity name is `AssignedResource`.
|
|
3610
|
-
* Once the parent `ServiceAppointment` record comes back, its child connection starts to resolve. Child `AssignedResource` record needs to reference to parent Id using field `ServiceAppointmentId`.
|
|
3611
|
-
* @param parentId prarent record Id
|
|
3612
|
-
* @returns predicate array consists at most 1 predicate
|
|
3613
|
-
*/
|
|
3614
|
-
function childRelationshipToPredicates(childRelationshipFieldName, parentId) {
|
|
3615
|
-
const predicates = [];
|
|
3616
|
-
if (childRelationshipFieldName !== undefined && parentId !== undefined) {
|
|
3617
|
-
predicates.push({
|
|
3618
|
-
type: PredicateType.single,
|
|
3619
|
-
leftPath: `$.fields.${childRelationshipFieldName}.value`,
|
|
3620
|
-
operator: '=',
|
|
3621
|
-
value: parentId,
|
|
3622
|
-
});
|
|
3623
|
-
}
|
|
3624
|
-
return predicates;
|
|
3625
|
-
}
|
|
3626
3731
|
function isRecordType(type) {
|
|
3627
3732
|
const interfaces = type.getInterfaces();
|
|
3628
3733
|
return Boolean(interfaces.find((iface) => iface.name === 'Record'));
|
|
3629
3734
|
}
|
|
3630
|
-
/**
|
|
3631
|
-
* Builds the top level record query key based on AST data
|
|
3632
|
-
* @param operation
|
|
3633
|
-
* @param variables
|
|
3634
|
-
* @param argumentNodes
|
|
3635
|
-
* @param currentFieldName
|
|
3636
|
-
* @returns
|
|
3637
|
-
*/
|
|
3638
|
-
function buildKeyStringForRecordQuery(operation, variables, argumentNodes, currentFieldName) {
|
|
3639
|
-
const queryKey = buildQueryTypeStringKey({
|
|
3640
|
-
luvio: {},
|
|
3641
|
-
keyPrefix: 'UiApi',
|
|
3642
|
-
schemaName: 'uiapi',
|
|
3643
|
-
queryTypeName: 'Query',
|
|
3644
|
-
operationNode: operation,
|
|
3645
|
-
variables,
|
|
3646
|
-
fragmentMap: {},
|
|
3647
|
-
});
|
|
3648
|
-
const filteredArgumentNodes = assign$1([], argumentNodes).filter((node) => node.name.value !== 'first' && node.name.value !== 'after');
|
|
3649
|
-
const argumentString = filteredArgumentNodes.length > 0
|
|
3650
|
-
? '__' + serializeFieldArguments(filteredArgumentNodes, variables)
|
|
3651
|
-
: '';
|
|
3652
|
-
return `${queryKey}__uiapi__query__${currentFieldName}${argumentString}`;
|
|
3653
|
-
}
|
|
3654
|
-
/**
|
|
3655
|
-
* fetches a query level ingestion time stamp from the L2 cache
|
|
3656
|
-
* if no query has been seen then the timestamp is 0
|
|
3657
|
-
* @param apiName
|
|
3658
|
-
* @param info
|
|
3659
|
-
* @param args
|
|
3660
|
-
* @param query
|
|
3661
|
-
* @returns
|
|
3662
|
-
*/
|
|
3663
|
-
async function fetchIngestionTimeStampFromDatabase(apiName, info, args, query) {
|
|
3664
|
-
const { operation, variableValues } = info;
|
|
3665
|
-
// if we cannot find the query key in the database then default to 0 as we assume we have not seen the query
|
|
3666
|
-
// and all the data is not stale
|
|
3667
|
-
let ingestionTimestamp = 0;
|
|
3668
|
-
if (info.fieldNodes.length > 0 && info.fieldNodes[0].arguments !== undefined) {
|
|
3669
|
-
const key = buildKeyStringForRecordQuery(operation,
|
|
3670
|
-
// join varables passed from query to the argument variables given from the AST
|
|
3671
|
-
{ ...variableValues, ...args }, info.fieldNodes[0].arguments, apiName);
|
|
3672
|
-
return readIngestionTimestampForKey(key, query);
|
|
3673
|
-
}
|
|
3674
|
-
return ingestionTimestamp;
|
|
3675
|
-
}
|
|
3676
3735
|
|
|
3677
3736
|
var uiapiSchemaString = "scalar String\nscalar DateTime\nscalar Currency\nscalar ID\nscalar Boolean\nscalar Longitude\nscalar Float\nscalar MultiPicklist\nscalar Base64\nscalar Url\nscalar PhoneNumber\nscalar Email\nscalar TextArea\nscalar Latitude\nscalar Picklist\nscalar RichTextArea\nscalar EncryptedString\nscalar Double\nscalar Long\nscalar JSON\nscalar Time\nscalar Int\nscalar Percent\nscalar LongTextArea\nscalar IdOrRef\nscalar Date\ntype PercentAggregate implements FieldValue {\n value: Percent\n displayValue: String\n avg: DoubleValue\n count: LongValue\n countDistinct: LongValue\n format: String\n max: PercentValue\n min: PercentValue\n sum: PercentValue\n}\n\ntype StringAggregate implements FieldValue {\n value: String\n displayValue: String\n count: LongValue\n countDistinct: LongValue\n grouping: IntValue\n label: String\n max: StringValue\n min: StringValue\n}\n\ntype Query {\n uiapi: UIAPI!\n setup: Setup__Setup!\n}\n\ninput EmailOperators {\n eq: Email\n ne: Email\n like: Email\n lt: Email\n gt: Email\n lte: Email\n gte: Email\n in: [Email]\n nin: [Email]\n}\n\ninput PolymorphicParentRelationshipRecordOrderBy @generic {\n RecordOrderBy: RecordOrderBy @fieldCategory\n}\n\ninput DoubleOperators {\n eq: Double\n ne: Double\n lt: Double\n gt: Double\n lte: Double\n gte: Double\n in: [Double]\n nin: [Double]\n}\n\ntype DateOnlyAggregation {\n value: Date\n format: String\n}\n\ntype RecordCreatePayload @generic {\n Record: RecordRepresentation\n}\n\ntype DateAggregate implements FieldValue {\n value: Date\n displayValue: String\n calendarMonth: DateFunctionAggregation\n calendarQuarter: DateFunctionAggregation\n calendarYear: DateFunctionAggregation\n count: LongValue\n countDistinct: LongValue\n dayInMonth: DateFunctionAggregation\n dayInWeek: DateFunctionAggregation\n dayInYear: DateFunctionAggregation\n fiscalMonth: DateFunctionAggregation\n fiscalQuarter: DateFunctionAggregation\n fiscalYear: DateFunctionAggregation\n format: String\n grouping: IntValue\n max: DateValue\n min: DateValue\n weekInMonth: DateFunctionAggregation\n weekInYear: DateFunctionAggregation\n}\n\ninput PolymorphicParentRelationshipGroupBy @generic {\n RecordGroupBy: RecordGroupBy @fieldCategory\n}\n\nenum GroupByFunction {\n DAY_IN_WEEK\n DAY_IN_MONTH\n DAY_IN_YEAR\n WEEK_IN_MONTH\n WEEK_IN_YEAR\n CALENDAR_MONTH\n CALENDAR_QUARTER\n CALENDAR_YEAR\n FISCAL_MONTH\n FISCAL_QUARTER\n FISCAL_YEAR\n DAY_ONLY\n HOUR_IN_DAY\n}\n\ntype RecordTypeInfo {\n available: Boolean!\n defaultRecordTypeMapping: Boolean!\n master: Boolean!\n name: String\n recordTypeId: ID\n}\n\ninput UIAPIMutationsInput {\n allOrNone: Boolean = true\n}\n\ntype BooleanValue implements FieldValue {\n value: Boolean\n displayValue: String\n}\n\ntype ReferenceToInfo {\n ApiName: String!\n nameFields: [String]!\n objectInfo: ObjectInfo\n}\n\ninterface FieldValue {\n displayValue: String\n}\n\ntype LongitudeValue implements FieldValue {\n value: Longitude\n displayValue: String\n}\n\ntype StringValue implements FieldValue {\n value: String\n displayValue: String\n label: String\n}\n\ntype IntValue implements FieldValue {\n value: Int\n displayValue: String\n format: String\n}\n\ntype UrlValue implements FieldValue {\n value: Url\n displayValue: String\n}\n\ninput IdOperators {\n eq: ID\n ne: ID\n lt: ID\n gt: ID\n lte: ID\n gte: ID\n in: [ID]\n nin: [ID]\n inq: JoinInput\n ninq: JoinInput\n}\n\ninput Setup__SetupOrderBy @generic {\n orderableField: OrderByClause @fieldCategory\n orderableGeolocationField: OrderByGeolocationClause @fieldCategory\n orderableParentRelationship: Setup__SetupOrderBy @fieldCategory\n orderablePolymorphicParentRelationship: Setup__SetupPolymorphicParentRelationshipRecordOrderBy @fieldCategory\n}\n\ntype LongAggregate implements FieldValue {\n value: Long\n displayValue: String\n avg: DoubleValue\n count: LongValue\n countDistinct: LongValue\n format: String\n grouping: IntValue\n max: LongValue\n min: LongValue\n sum: LongValue\n}\n\ntype PhoneNumberAggregate implements FieldValue {\n value: PhoneNumber\n displayValue: String\n count: LongValue\n countDistinct: LongValue\n grouping: IntValue\n max: PhoneNumberValue\n min: PhoneNumberValue\n}\n\ninput TimeOperators {\n eq: Time\n ne: Time\n lt: Time\n gt: Time\n lte: Time\n gte: Time\n in: [Time]\n nin: [Time]\n}\n\ntype PicklistValue implements FieldValue {\n value: Picklist\n displayValue: String\n label: String\n}\n\ntype CurrencyAggregate implements FieldValue {\n value: Currency\n displayValue: String\n avg: DoubleValue\n count: LongValue\n countDistinct: LongValue\n format: String\n max: CurrencyValue\n min: CurrencyValue\n sum: CurrencyValue\n}\n\ntype RelatedListInfo {\n childApiName: String!\n relatedListName: String!\n label: String!\n displayColumns: [ListColumn!]!\n orderedByInfo: [ListOrder!]!\n parentApiName: String!\n fieldApiName: String!\n}\n\ninput StringOperators {\n eq: String\n ne: String\n like: String\n lt: String\n gt: String\n lte: String\n gte: String\n in: [String]\n nin: [String]\n}\n\ntype UIAPI {\n query: RecordQuery!\n aggregate: RecordQueryAggregate!\n objectInfos(apiNames: [String], locale: String): [ObjectInfo]\n relatedListByName(parentApiName: String!, relatedListName: String!): RelatedListInfo\n}\n\ninput MultiPicklistOperators {\n eq: MultiPicklist\n ne: MultiPicklist\n includes: [MultiPicklist]\n excludes: [MultiPicklist]\n}\n\ntype DateTimeAggregate implements FieldValue {\n value: DateTime\n displayValue: String\n calendarMonth: DateFunctionAggregation\n calendarQuarter: DateFunctionAggregation\n calendarYear: DateFunctionAggregation\n count: LongValue\n countDistinct: LongValue\n dayInMonth: DateFunctionAggregation\n dayInWeek: DateFunctionAggregation\n dayInYear: DateFunctionAggregation\n dayOnly: DateOnlyAggregation\n fiscalMonth: DateFunctionAggregation\n fiscalQuarter: DateFunctionAggregation\n fiscalYear: DateFunctionAggregation\n format: String\n hourInDay: DateFunctionAggregation\n max: DateTimeValue\n min: DateTimeValue\n weekInMonth: DateFunctionAggregation\n weekInYear: DateFunctionAggregation\n}\n\ninput BooleanOperators {\n eq: Boolean\n ne: Boolean\n}\n\ntype EmailAggregate implements FieldValue {\n value: Email\n displayValue: String\n count: LongValue\n countDistinct: LongValue\n grouping: IntValue\n max: EmailValue\n min: EmailValue\n}\n\n#enum OrderByType {\n#}\n\ninput GroupByDateFunction {\n function: GroupByFunction\n}\n\ntype RichTextAreaValue implements FieldValue {\n value: RichTextArea\n displayValue: String\n}\n\ntype MultiPicklistValue implements FieldValue {\n value: MultiPicklist\n displayValue: String\n label: String\n}\n\ntype Setup__SetupEdge @generic {\n node: Setup__EntityRepresentation\n cursor: String!\n}\n\ninput DatePrimitiveOperators {\n eq: Date\n ne: Date\n lt: Date\n gt: Date\n lte: Date\n gte: Date\n in: [Date]\n nin: [Date]\n}\n\ntype TimeAggregate implements FieldValue {\n value: Time\n displayValue: String\n format: String\n hourInDay: DateFunctionAggregation\n}\n\ntype __Type {\n kind: __TypeKind!\n name: String\n description: String\n fields(includeDeprecated: Boolean = false): [__Field!]\n interfaces: [__Type!]\n possibleTypes: [__Type!]\n enumValues(includeDeprecated: Boolean = false): [__EnumValue!]\n inputFields: [__InputValue!]\n ofType: __Type\n}\n\ntype ListColumn {\n fieldApiName: String!\n label: String!\n lookupId: String\n sortable: Boolean\n}\n\ntype Setup__SetupQuery {\n recordQuery(first: Int, after: String, where: Setup__SetupFilter, orderBy: Setup__SetupOrderBy, scope: String, upperBound: Int): Setup__SetupConnection @fieldCategory\n}\n\ntype Setup__EntityRepresentation @generic {\n Id: ID!\n ApiName: String!\n IntValue: IntValue @fieldCategory\n StringValue: StringValue @fieldCategory\n BooleanValue: BooleanValue @fieldCategory\n IDValue: IDValue @fieldCategory\n DateTimeValue: DateTimeValue @fieldCategory\n TimeValue: TimeValue @fieldCategory\n DateValue: DateValue @fieldCategory\n TextAreaValue: TextAreaValue @fieldCategory\n LongTextAreaValue: LongTextAreaValue @fieldCategory\n RichTextAreaValue: RichTextAreaValue @fieldCategory\n PhoneNumberValue: PhoneNumberValue @fieldCategory\n EmailValue: EmailValue @fieldCategory\n UrlValue: UrlValue @fieldCategory\n EncryptedStringValue: EncryptedStringValue @fieldCategory\n CurrencyValue: CurrencyValue @fieldCategory\n LongitudeValue: LongitudeValue @fieldCategory\n LatitudeValue: LatitudeValue @fieldCategory\n PicklistValue: PicklistValue @fieldCategory\n MultiPicklistValue: MultiPicklistValue @fieldCategory\n LongValue: LongValue @fieldCategory\n DoubleValue: DoubleValue @fieldCategory\n PercentValue: PercentValue @fieldCategory\n Base64Value: Base64Value @fieldCategory\n JSONValue: JSONValue @fieldCategory\n parentRelationship: Setup__EntityRepresentation @fieldCategory\n polymorphicParentRelationship: Setup__SetupPolymorphicParentRelationship @fieldCategory\n childRelationship(first: Int, after: String, where: Setup__SetupFilter, orderBy: Setup__SetupOrderBy, upperBound: Int): Setup__SetupConnection @fieldCategory\n CompoundField: CompoundField @fieldCategory\n}\n\ntype LatitudeAggregate implements FieldValue {\n value: Latitude\n displayValue: String\n avg: DoubleValue\n count: LongValue\n countDistinct: LongValue\n max: LatitudeValue\n min: LatitudeValue\n sum: DoubleValue\n}\n\ninput CurrencyOperators {\n eq: Currency\n ne: Currency\n lt: Currency\n gt: Currency\n lte: Currency\n gte: Currency\n in: [Currency]\n nin: [Currency]\n}\n\ninput DistanceInput {\n latitude: Latitude!\n longitude: Longitude!\n}\n\nunion PolymorphicParentRelationship @generic = RecordRepresentation\n\nenum AggregateOrderByNumberFunction {\n AVG\n COUNT\n COUNT_DISTINCT\n MAX\n MIN\n SUM\n}\n\ntype LongTextAreaValue implements FieldValue {\n value: LongTextArea\n displayValue: String\n}\n\ntype LatitudeValue implements FieldValue {\n value: Latitude\n displayValue: String\n}\n\ninput OrderByClause {\n order: ResultOrder\n nulls: NullOrder\n}\n\ninput AggregateOrderBy @generic {\n orderableNumberField: AggregateOrderByNumberClause @fieldCategory\n orderableStringField: AggregateOrderByStringClause @fieldCategory\n orderableField: NoFunctionAggregateOrderByClause @fieldCategory\n orderableGeolocationField: OrderByGeolocationClause @fieldCategory\n orderableParentRelationship: AggregateOrderBy @fieldCategory\n orderablePolymorphicParentRelationship: PolymorphicParentRelationshipOrderBy @fieldCategory\n type: String = ORDER_BY\n}\n\ninput GroupByClause {\n group: Boolean\n}\n\ntype RecordAggregateConnection @generic {\n edges: [RecordAggregateEdge]\n pageInfo: PageInfo!\n totalCount: Int!\n}\n\ntype LongitudeAggregate implements FieldValue {\n value: Longitude\n displayValue: String\n avg: DoubleValue\n count: LongValue\n countDistinct: LongValue\n max: LongitudeValue\n min: LongitudeValue\n sum: DoubleValue\n}\n\ntype RecordEdge @generic {\n node: RecordRepresentation\n cursor: String!\n}\n\nunion Setup__SetupPolymorphicParentRelationship @generic = Setup__EntityRepresentation\n\ntype DateValue implements FieldValue {\n value: Date\n displayValue: String\n format: String\n}\n\ninput URLOperators {\n eq: Url\n ne: Url\n like: Url\n lt: Url\n gt: Url\n lte: Url\n gte: Url\n in: [Url]\n nin: [Url]\n}\n\ninput LongOperators {\n eq: Long\n ne: Long\n lt: Long\n gt: Long\n lte: Long\n gte: Long\n in: [Long]\n nin: [Long]\n}\n\nenum DataType {\n STRING\n TEXTAREA\n PHONE\n EMAIL\n URL\n ENCRYPTEDSTRING\n BOOLEAN\n CURRENCY\n INT\n LONG\n DOUBLE\n PERCENT\n DATETIME\n TIME\n DATE\n REFERENCE\n PICKLIST\n MULTIPICKLIST\n ADDRESS\n LOCATION\n BASE64\n COMPLEXVALUE\n COMBOBOX\n JSON\n JUNCTIONIDLIST\n ANYTYPE\n}\n\nenum NullOrder {\n FIRST\n LAST\n}\n\ntype PhoneNumberValue implements FieldValue {\n value: PhoneNumber\n displayValue: String\n}\n\n# Cannot have empty enum\n# enum RecordScope @generic {\n# }\n\ninput Setup__SetupFilter @generic {\n and: [Setup__SetupFilter]\n or: [Setup__SetupFilter]\n not: Setup__SetupFilter\n parentRelationshipRecordFilter: Setup__SetupFilter @fieldCategory\n polymorphicParentRelationshipRecordFilter: Setup__SetupPolymorphicParentRelationshipRecordFilter @fieldCategory\n IntegerOperator: IntegerOperators @fieldCategory\n LongOperator: LongOperators @fieldCategory\n StringOperator: StringOperators @fieldCategory\n DoubleOperator: DoubleOperators @fieldCategory\n PercentOperator: PercentOperators @fieldCategory\n LongitudeOperator: LongitudeOperators @fieldCategory\n LatitudeOperator: LatitudeOperators @fieldCategory\n EmailOperator: EmailOperators @fieldCategory\n TextAreaOperator: TextAreaOperators @fieldCategory\n LongTextAreaOperator: LongTextAreaOperators @fieldCategory\n URLOperator: URLOperators @fieldCategory\n PhoneNumberOperator: PhoneNumberOperators @fieldCategory\n BooleanOperator: BooleanOperators @fieldCategory\n Setup__IdOperator: Setup__IdOperators @fieldCategory\n CurrencyOperator: CurrencyOperators @fieldCategory\n TimeOperator: TimeOperators @fieldCategory\n DateOperator: DateOperators @fieldCategory\n DateTimeOperator: DateTimeOperators @fieldCategory\n PicklistOperator: PicklistOperators @fieldCategory\n MultiPicklistOperator: MultiPicklistOperators @fieldCategory\n GeolocationOperator: GeolocationOperators @fieldCategory\n}\n\ntype DoubleAggregate implements FieldValue {\n value: Double\n displayValue: String\n avg: DoubleValue\n count: LongValue\n countDistinct: LongValue\n format: String\n max: DoubleValue\n min: DoubleValue\n sum: DoubleValue\n}\n\ntype __Field {\n name: String!\n description: String\n args: [__InputValue!]!\n type: __Type!\n isDeprecated: Boolean!\n deprecationReason: String\n}\n\ninput DateOperators {\n eq: DateInput\n ne: DateInput\n lt: DateInput\n gt: DateInput\n lte: DateInput\n gte: DateInput\n in: [DateInput]\n nin: [DateInput]\n DAY_IN_WEEK: DateFunctionInput\n DAY_IN_MONTH: DateFunctionInput\n DAY_IN_YEAR: DateFunctionInput\n WEEK_IN_MONTH: DateFunctionInput\n WEEK_IN_YEAR: DateFunctionInput\n CALENDAR_MONTH: DateFunctionInput\n CALENDAR_QUARTER: DateFunctionInput\n CALENDAR_YEAR: DateFunctionInput\n FISCAL_MONTH: DateFunctionInput\n FISCAL_QUARTER: DateFunctionInput\n FISCAL_YEAR: DateFunctionInput\n}\n\ninput GeolocationInput {\n latitude: Latitude!\n longitude: Longitude!\n radius: Float!\n unit: Unit!\n}\n\ninput JoinInput {\n Record: RecordFilter @fieldCategory\n ApiName: String\n}\n\ninput TextAreaOperators {\n eq: TextArea\n ne: TextArea\n like: TextArea\n lt: TextArea\n gt: TextArea\n lte: TextArea\n gte: TextArea\n in: [TextArea]\n nin: [TextArea]\n}\n\ntype TextAreaValue implements FieldValue {\n value: TextArea\n displayValue: String\n}\n\ntype RecordUpdatePayload @generic {\n success: Boolean\n}\n\ninput PercentOperators {\n eq: Percent\n ne: Percent\n lt: Percent\n gt: Percent\n lte: Percent\n gte: Percent\n in: [Percent]\n nin: [Percent]\n}\n\ninput Setup__SetupPolymorphicParentRelationshipRecordOrderBy @generic {\n Setup__SetupOrderBy: Setup__SetupOrderBy @fieldCategory\n}\n\ntype DoubleValue implements FieldValue {\n value: Double\n displayValue: String\n format: String\n}\n\ntype IDAggregate implements FieldValue {\n value: ID\n displayValue: String\n count: LongValue\n countDistinct: LongValue\n grouping: IntValue\n max: IDValue\n min: IDValue\n}\n\ntype __InputValue {\n name: String!\n description: String\n type: __Type!\n defaultValue: String\n}\n\ntype RecordAggregateEdge @generic {\n node: RecordResult\n cursor: String!\n}\n\ntype __Directive {\n name: String\n description: String\n locations: [__DirectiveLocation!]\n args: [__InputValue!]!\n}\n\ninput RecordCreateInput @generic {\n record: RecordCreateRepresentation! @fieldCategory\n}\n\ntype ThemeInfo {\n color: String\n iconUrl: String\n}\n\ninput AggregateOrderByStringClause {\n function: AggregateOrderByStringFunction\n order: ResultsOrder\n nulls: NullsOrder\n}\n\ntype RecordDeletePayload {\n Id: ID\n}\n\ntype UrlAggregate implements FieldValue {\n value: Url\n displayValue: String\n count: LongValue\n countDistinct: LongValue\n grouping: IntValue\n max: UrlValue\n min: UrlValue\n}\n\nenum DateLiteral {\n LAST_YEAR\n LAST_WEEK\n THIS_QUARTER\n NEXT_FISCAL_YEAR\n LAST_QUARTER\n TOMORROW\n NEXT_FISCAL_QUARTER\n YESTERDAY\n NEXT_QUARTER\n THIS_FISCAL_QUARTER\n THIS_WEEK\n LAST_MONTH\n LAST_90_DAYS\n NEXT_90_DAYS\n THIS_FISCAL_YEAR\n NEXT_WEEK\n TODAY\n NEXT_YEAR\n NEXT_MONTH\n LAST_FISCAL_QUARTER\n THIS_MONTH\n LAST_FISCAL_YEAR\n THIS_YEAR\n}\n\ntype __EnumValue {\n name: String!\n description: String\n isDeprecated: Boolean!\n deprecationReason: String\n}\n\ntype RecordRepresentation implements Record @generic {\n Id: ID!\n ApiName: String!\n WeakEtag: Long!\n DisplayValue: String\n LastModifiedById: IDValue\n LastModifiedDate: DateTimeValue\n SystemModstamp: DateTimeValue\n RecordTypeId(fallback: Boolean): IDValue\n IntValue: IntValue @fieldCategory\n StringValue: StringValue @fieldCategory\n BooleanValue: BooleanValue @fieldCategory\n IDValue: IDValue @fieldCategory\n DateTimeValue: DateTimeValue @fieldCategory\n TimeValue: TimeValue @fieldCategory\n DateValue: DateValue @fieldCategory\n TextAreaValue: TextAreaValue @fieldCategory\n LongTextAreaValue: LongTextAreaValue @fieldCategory\n RichTextAreaValue: RichTextAreaValue @fieldCategory\n PhoneNumberValue: PhoneNumberValue @fieldCategory\n EmailValue: EmailValue @fieldCategory\n UrlValue: UrlValue @fieldCategory\n EncryptedStringValue: EncryptedStringValue @fieldCategory\n CurrencyValue: CurrencyValue @fieldCategory\n LongitudeValue: LongitudeValue @fieldCategory\n LatitudeValue: LatitudeValue @fieldCategory\n PicklistValue: PicklistValue @fieldCategory\n MultiPicklistValue: MultiPicklistValue @fieldCategory\n LongValue: LongValue @fieldCategory\n DoubleValue: DoubleValue @fieldCategory\n PercentValue: PercentValue @fieldCategory\n Base64Value: Base64Value @fieldCategory\n JSONValue: JSONValue @fieldCategory\n parentRelationship: RecordRepresentation @fieldCategory\n polymorphicParentRelationship: PolymorphicParentRelationship @fieldCategory\n childRelationship(first: Int, after: String, where: RecordFilter, orderBy: RecordOrderBy, upperBound: Int): RecordConnection @fieldCategory\n CompoundField: CompoundField @fieldCategory\n}\n\ntype IDValue implements FieldValue {\n value: ID\n displayValue: String\n}\n\nenum Unit {\n MI\n KM\n}\n\ninput PolymorphicParentRelationshipOrderBy @generic {\n AggregateOrderBy: AggregateOrderBy @fieldCategory\n}\n\ninput OrderByGeolocationClause {\n distance: DistanceInput\n order: ResultOrder\n nulls: NullOrder\n}\n\ninput Setup__IdOperators {\n eq: ID\n ne: ID\n lt: ID\n gt: ID\n lte: ID\n gte: ID\n in: [ID]\n nin: [ID]\n inq: Setup__JoinInput\n ninq: Setup__JoinInput\n}\n\nenum NullsOrder {\n FIRST\n LAST\n}\n\ntype TextAreaAggregate implements FieldValue {\n value: TextArea\n displayValue: String\n count: LongValue\n countDistinct: LongValue\n grouping: IntValue\n max: TextAreaValue\n min: TextAreaValue\n}\n\nenum GroupByType {\n GROUP_BY\n ROLLUP\n CUBE\n}\n\nenum ResultOrder {\n ASC\n DESC\n}\n\ninput RecordOrderBy @generic {\n orderableField: OrderByClause @fieldCategory\n orderableGeolocationField: OrderByGeolocationClause @fieldCategory\n orderableParentRelationship: RecordOrderBy @fieldCategory\n orderablePolymorphicParentRelationship: PolymorphicParentRelationshipRecordOrderBy @fieldCategory\n}\n\ninput Setup__JoinInput {\n Record: Setup__SetupFilter @fieldCategory\n ApiName: String\n}\n\ninput PicklistOperators {\n eq: Picklist\n ne: Picklist\n in: [Picklist]\n nin: [Picklist]\n like: Picklist\n lt: Picklist\n gt: Picklist\n lte: Picklist\n gte: Picklist\n}\n\nenum ResultsOrder {\n ASC\n DESC\n}\n\ninput RecordFilter @generic {\n and: [RecordFilter]\n or: [RecordFilter]\n not: RecordFilter\n parentRelationshipRecordFilter: RecordFilter @fieldCategory\n polymorphicParentRelationshipRecordFilter: PolymorphicParentRelationshipRecordFilter @fieldCategory\n IntegerOperator: IntegerOperators @fieldCategory\n LongOperator: LongOperators @fieldCategory\n StringOperator: StringOperators @fieldCategory\n DoubleOperator: DoubleOperators @fieldCategory\n PercentOperator: PercentOperators @fieldCategory\n LongitudeOperator: LongitudeOperators @fieldCategory\n LatitudeOperator: LatitudeOperators @fieldCategory\n EmailOperator: EmailOperators @fieldCategory\n TextAreaOperator: TextAreaOperators @fieldCategory\n LongTextAreaOperator: LongTextAreaOperators @fieldCategory\n URLOperator: URLOperators @fieldCategory\n PhoneNumberOperator: PhoneNumberOperators @fieldCategory\n BooleanOperator: BooleanOperators @fieldCategory\n IdOperator: IdOperators @fieldCategory\n CurrencyOperator: CurrencyOperators @fieldCategory\n TimeOperator: TimeOperators @fieldCategory\n DateOperator: DateOperators @fieldCategory\n DateTimeOperator: DateTimeOperators @fieldCategory\n PicklistOperator: PicklistOperators @fieldCategory\n MultiPicklistOperator: MultiPicklistOperators @fieldCategory\n GeolocationOperator: GeolocationOperators @fieldCategory\n}\n\ntype TimeValue implements FieldValue {\n value: Time\n displayValue: String\n format: String\n}\n\ninput GeolocationOperators {\n lt: GeolocationInput\n gt: GeolocationInput\n}\n\ntype PicklistAggregate implements FieldValue {\n value: Picklist\n displayValue: String\n count: LongValue\n countDistinct: LongValue\n grouping: IntValue\n label: String\n max: PicklistValue\n min: PicklistValue\n}\n\ninput LatitudeOperators {\n eq: Latitude\n ne: Latitude\n lt: Latitude\n gt: Latitude\n lte: Latitude\n gte: Latitude\n in: [Latitude]\n nin: [Latitude]\n}\n\ninput RecordUpdateRepresentation @generic {\n Int: Int @fieldCategory\n String: String @fieldCategory\n Boolean: Boolean @fieldCategory\n ID: IdOrRef @fieldCategory\n DateTime: DateTime @fieldCategory\n Time: Time @fieldCategory\n Date: Date @fieldCategory\n TextArea: TextArea @fieldCategory\n LongTextArea: LongTextArea @fieldCategory\n RichTextArea: RichTextArea @fieldCategory\n PhoneNumber: PhoneNumber @fieldCategory\n Email: Email @fieldCategory\n Url: Url @fieldCategory\n EncryptedString: EncryptedString @fieldCategory\n Currency: Currency @fieldCategory\n Longitude: Longitude @fieldCategory\n Latitude: Latitude @fieldCategory\n Picklist: Picklist @fieldCategory\n MultiPicklist: MultiPicklist @fieldCategory\n Long: Long @fieldCategory\n Double: Double @fieldCategory\n Percent: Percent @fieldCategory\n Base64: Base64 @fieldCategory\n JSON: JSON @fieldCategory\n}\n\ntype DateTimeValue implements FieldValue {\n value: DateTime\n displayValue: String\n format: String\n}\n\ninput RecordDeleteInput {\n Id: IdOrRef!\n}\n\nenum __DirectiveLocation {\n QUERY\n MUTATION\n FIELD\n FRAGMENT_DEFINITION\n FRAGMENT_SPREAD\n INLINE_FRAGMENT\n SCHEMA\n SCALAR\n OBJECT\n FIELD_DEFINITION\n ARGUMENT_DEFINITION\n INTERFACE\n UNION\n ENUM\n ENUM_VALUE\n INPUT_OBJECT\n INPUT_FIELD_DEFINITION\n}\n\ntype IntAggregate implements FieldValue {\n value: Int\n displayValue: String\n avg: DoubleValue\n count: LongValue\n countDistinct: LongValue\n format: String\n grouping: IntValue\n max: IntValue\n min: IntValue\n sum: LongValue\n}\n\ntype ListOrder {\n fieldApiName: String!\n sortDirection: ResultOrder\n}\n\ntype RecordAggregate @generic {\n ApiName: String!\n BooleanAggregate: BooleanAggregate @fieldCategory\n CurrencyAggregate: CurrencyAggregate @fieldCategory\n DateAggregate: DateAggregate @fieldCategory\n DoubleAggregate: DoubleAggregate @fieldCategory\n EmailAggregate: EmailAggregate @fieldCategory\n IDAggregate: IDAggregate @fieldCategory\n IntAggregate: IntAggregate @fieldCategory\n LatitudeAggregate: LatitudeAggregate @fieldCategory\n LongitudeAggregate: LongitudeAggregate @fieldCategory\n LongAggregate: LongAggregate @fieldCategory\n PercentAggregate: PercentAggregate @fieldCategory\n PhoneNumberAggregate: PhoneNumberAggregate @fieldCategory\n PicklistAggregate: PicklistAggregate @fieldCategory\n StringAggregate: StringAggregate @fieldCategory\n TextAreaAggregate: TextAreaAggregate @fieldCategory\n TimeAggregate: TimeAggregate @fieldCategory\n UrlAggregate: UrlAggregate @fieldCategory\n}\n\ntype JSONValue implements FieldValue {\n value: JSON\n displayValue: String\n}\n\ntype EmailValue implements FieldValue {\n value: Email\n displayValue: String\n}\n\ntype Setup__Setup {\n query: Setup__SetupQuery!\n}\n\nenum AggregateOrderByStringFunction {\n COUNT\n COUNT_DISTINCT\n MAX\n MIN\n}\n\ntype LongValue implements FieldValue {\n value: Long\n displayValue: String\n format: String\n}\n\ninput DateFunctionInput {\n value: LongOperators\n convertTimezoneValue: LongOperators\n}\n\n# Mutations aren't supported yet.\n#type Mutation {\n# uiapi(input: UIAPIMutationsInput): UIAPIMutations!\n#}\n\ntype DependentField {\n controllingField: String!\n dependentFields: [String]!\n}\n\ninput LongTextAreaOperators {\n eq: LongTextArea\n ne: LongTextArea\n like: LongTextArea\n lt: LongTextArea\n gt: LongTextArea\n lte: LongTextArea\n gte: LongTextArea\n in: [LongTextArea]\n nin: [LongTextArea]\n}\n\nenum __TypeKind {\n SCALAR\n OBJECT\n INTERFACE\n UNION\n ENUM\n INPUT_OBJECT\n LIST\n NON_NULL\n}\n\ntype Setup__SetupConnection @generic {\n edges: [Setup__SetupEdge]\n pageInfo: PageInfo!\n totalCount: Int!\n pageResultCount: Int!\n}\n\ntype PercentValue implements FieldValue {\n value: Percent\n displayValue: String\n format: String\n}\n\ninput DateTimeOperators {\n eq: DateTimeInput\n ne: DateTimeInput\n lt: DateTimeInput\n gt: DateTimeInput\n lte: DateTimeInput\n gte: DateTimeInput\n in: [DateTimeInput]\n nin: [DateTimeInput]\n DAY_IN_WEEK: DateFunctionInput\n DAY_IN_MONTH: DateFunctionInput\n DAY_IN_YEAR: DateFunctionInput\n WEEK_IN_MONTH: DateFunctionInput\n WEEK_IN_YEAR: DateFunctionInput\n CALENDAR_MONTH: DateFunctionInput\n CALENDAR_QUARTER: DateFunctionInput\n CALENDAR_YEAR: DateFunctionInput\n FISCAL_MONTH: DateFunctionInput\n FISCAL_QUARTER: DateFunctionInput\n FISCAL_YEAR: DateFunctionInput\n DAY_ONLY: DateTimeFunctionInput\n HOUR_IN_DAY: DateFunctionInput\n}\n\ninput NoFunctionAggregateOrderByClause {\n order: ResultsOrder\n nulls: NullsOrder\n}\n\ntype BooleanAggregate implements FieldValue {\n value: Boolean\n displayValue: String\n grouping: IntValue\n}\n\ntype RecordQueryAggregate {\n # RecordScope is replaced with String\n recordQueryAggregate(first: Int, after: String, where: RecordFilter, orderBy: AggregateOrderBy, scope: String, groupBy: RecordGroupBy, upperBound: Int): RecordAggregateConnection @fieldCategory\n}\n\ntype RecordConnection @generic {\n edges: [RecordEdge]\n pageInfo: PageInfo!\n totalCount: Int!\n pageResultCount: Int!\n}\n\ntype FilteredLookupInfo {\n controllingFields: [String]!\n dependent: Boolean!\n optionalFilter: Boolean!\n}\n\ninput PhoneNumberOperators {\n eq: PhoneNumber\n ne: PhoneNumber\n like: PhoneNumber\n lt: PhoneNumber\n gt: PhoneNumber\n lte: PhoneNumber\n gte: PhoneNumber\n in: [PhoneNumber]\n nin: [PhoneNumber]\n}\n\ntype ObjectInfo {\n ApiName: String!\n childRelationships: [ChildRelationship]!\n createable: Boolean!\n custom: Boolean!\n defaultRecordTypeId: ID\n deletable: Boolean!\n dependentFields: [DependentField]!\n feedEnabled: Boolean!\n fields: [Field]!\n keyPrefix: String\n label: String\n labelPlural: String\n layoutable: Boolean!\n mruEnabled: Boolean!\n nameFields: [String]!\n queryable: Boolean!\n recordTypeInfos: [RecordTypeInfo]!\n searchable: Boolean!\n themeInfo: ThemeInfo\n updateable: Boolean!\n locale: String\n}\n\ninput LongitudeOperators {\n eq: Longitude\n ne: Longitude\n lt: Longitude\n gt: Longitude\n lte: Longitude\n gte: Longitude\n in: [Longitude]\n nin: [Longitude]\n}\n\ninput RecordCreateRepresentation @generic {\n Int: Int @fieldCategory\n String: String @fieldCategory\n Boolean: Boolean @fieldCategory\n ID: IdOrRef @fieldCategory\n DateTime: DateTime @fieldCategory\n Time: Time @fieldCategory\n Date: Date @fieldCategory\n TextArea: TextArea @fieldCategory\n LongTextArea: LongTextArea @fieldCategory\n RichTextArea: RichTextArea @fieldCategory\n PhoneNumber: PhoneNumber @fieldCategory\n Email: Email @fieldCategory\n Url: Url @fieldCategory\n EncryptedString: EncryptedString @fieldCategory\n Currency: Currency @fieldCategory\n Longitude: Longitude @fieldCategory\n Latitude: Latitude @fieldCategory\n Picklist: Picklist @fieldCategory\n MultiPicklist: MultiPicklist @fieldCategory\n Long: Long @fieldCategory\n Double: Double @fieldCategory\n Percent: Percent @fieldCategory\n Base64: Base64 @fieldCategory\n JSON: JSON @fieldCategory\n}\n\ntype Field {\n ApiName: String!\n calculated: Boolean!\n compound: Boolean!\n compoundComponentName: String\n compoundFieldName: String\n controllerName: String\n controllingFields: [String]!\n createable: Boolean!\n custom: Boolean!\n dataType: DataType\n extraTypeInfo: FieldExtraTypeInfo\n filterable: Boolean!\n filteredLookupInfo: FilteredLookupInfo\n highScaleNumber: Boolean!\n htmlFormatted: Boolean!\n inlineHelpText: String\n label: String\n nameField: Boolean!\n polymorphicForeignKey: Boolean!\n precision: Int\n reference: Boolean!\n referenceTargetField: String\n referenceToInfos: [ReferenceToInfo]!\n relationshipName: String\n required: Boolean!\n scale: Int\n searchPrefilterable: Boolean\n sortable: Boolean!\n updateable: Boolean!\n}\n\nenum FieldExtraTypeInfo {\n IMAGE_URL\n EXTERNAL_LOOKUP\n INDIRECT_LOOKUP\n PERSONNAME\n SWITCHABLE_PERSONNAME\n PLAINTEXTAREA\n RICHTEXTAREA\n}\n\ntype RateLimit {\n cost: Long\n limit: Long\n remaining: Long\n resetAt: DateTime\n}\n\ninput DateRange {\n last_n_days: Int\n next_n_days: Int\n last_n_weeks: Int\n next_n_weeks: Int\n last_n_months: Int\n next_n_months: Int\n last_n_quarters: Int\n next_n_quarters: Int\n last_n_fiscal_quarters: Int\n next_n_fiscal_quarters: Int\n last_n_years: Int\n next_n_years: Int\n last_n_fiscal_years: Int\n next_n_fiscal_years: Int\n n_days_ago: Int\n n_weeks_ago: Int\n n_months_ago: Int\n n_quarters_ago: Int\n n_years_ago: Int\n n_fiscal_quarters_ago: Int\n n_fiscal_years_ago: Int\n}\n\ntype UIAPIMutations {\n recordCreate(input: RecordCreateInput!): RecordCreatePayload @fieldCategory\n recordDelete(input: RecordDeleteInput!): RecordDeletePayload @fieldCategory\n recordUpdate(input: RecordUpdateInput!): RecordUpdatePayload @fieldCategory\n}\n\ninput DateTimeFunctionInput {\n value: DatePrimitiveOperators\n convertTimezoneValue: DatePrimitiveOperators\n}\n\ntype Base64Value implements FieldValue {\n value: Base64\n displayValue: String\n}\n\ninput IntegerOperators {\n eq: Int\n ne: Int\n lt: Int\n gt: Int\n lte: Int\n gte: Int\n in: [Int]\n nin: [Int]\n}\n\ntype EncryptedStringValue implements FieldValue {\n value: EncryptedString\n displayValue: String\n}\n\ninterface Record {\n Id: ID!\n ApiName: String!\n WeakEtag: Long!\n DisplayValue: String\n LastModifiedById: IDValue\n LastModifiedDate: DateTimeValue\n SystemModstamp: DateTimeValue\n RecordTypeId(fallback: Boolean): IDValue\n}\n\ninput PolymorphicParentRelationshipRecordFilter @generic {\n RecordFilter: RecordFilter @fieldCategory\n}\n\ninput AggregateOrderByNumberClause {\n function: AggregateOrderByNumberFunction\n order: ResultsOrder\n nulls: NullsOrder\n}\n\ntype __Schema {\n types: [__Type!]!\n queryType: __Type!\n mutationType: __Type\n directives: [__Directive!]!\n subscriptionType: __Type\n}\n\ninput Setup__SetupPolymorphicParentRelationshipRecordFilter @generic {\n Setup__SetupFilter: Setup__SetupFilter @fieldCategory\n}\n\ntype CompoundField @generic {\n IntValue: IntValue @fieldCategory\n StringValue: StringValue @fieldCategory\n BooleanValue: BooleanValue @fieldCategory\n IDValue: IDValue @fieldCategory\n DateTimeValue: DateTimeValue @fieldCategory\n TimeValue: TimeValue @fieldCategory\n DateValue: DateValue @fieldCategory\n TextAreaValue: TextAreaValue @fieldCategory\n LongTextAreaValue: LongTextAreaValue @fieldCategory\n RichTextAreaValue: RichTextAreaValue @fieldCategory\n PhoneNumberValue: PhoneNumberValue @fieldCategory\n EmailValue: EmailValue @fieldCategory\n UrlValue: UrlValue @fieldCategory\n EncryptedStringValue: EncryptedStringValue @fieldCategory\n CurrencyValue: CurrencyValue @fieldCategory\n LongitudeValue: LongitudeValue @fieldCategory\n LatitudeValue: LatitudeValue @fieldCategory\n PicklistValue: PicklistValue @fieldCategory\n MultiPicklistValue: MultiPicklistValue @fieldCategory\n LongValue: LongValue @fieldCategory\n DoubleValue: DoubleValue @fieldCategory\n PercentValue: PercentValue @fieldCategory\n Base64Value: Base64Value @fieldCategory\n JSONValue: JSONValue @fieldCategory\n}\n\ninput RecordUpdateInput @generic {\n Id: IdOrRef!\n record: RecordUpdateRepresentation! @fieldCategory\n}\n\ninput DateTimeInput {\n value: DateTime\n literal: DateLiteral\n range: DateRange\n}\n\ntype ChildRelationship {\n childObjectApiName: String!\n fieldName: String\n junctionIdListNames: [String]!\n junctionReferenceTo: [String]!\n relationshipName: String\n objectInfo: ObjectInfo\n}\n\ntype RecordResult @generic {\n aggregate: RecordAggregate\n}\n\ntype PageInfo {\n hasNextPage: Boolean!\n hasPreviousPage: Boolean!\n startCursor: String\n endCursor: String\n}\n\ntype CurrencyValue implements FieldValue {\n value: Currency\n displayValue: String\n format: String\n}\n\ninput DateInput {\n value: Date\n literal: DateLiteral\n range: DateRange\n}\n\ninput RecordGroupBy @generic {\n groupableField: GroupByClause @fieldCategory\n groupableDateField: GroupByDateFunction @fieldCategory\n groupableParentRelationship: RecordGroupBy @fieldCategory\n groupablePolymorphicParentRelationship: PolymorphicParentRelationshipGroupBy @fieldCategory\n type: GroupByType = GROUP_BY\n}\n\ntype DateFunctionAggregation {\n value: Long\n format: String\n}\n\ntype RecordQuery {\n # scope should be type RecordScope but that's empty enum.\n recordQuery(first: Int, after: String, where: RecordFilter, orderBy: RecordOrderBy, scope: String, upperBound: Int): RecordConnection @fieldCategory\n}\n\ndirective @generic on OBJECT | INTERFACE | UNION | ENUM | INPUT_OBJECT\ndirective @fieldCategory on FIELD_DEFINITION | ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION | ENUM_VALUE\ndirective @category(name: String!) on FIELD";
|
|
3678
3737
|
|
|
@@ -3755,7 +3814,7 @@ function buildBaseSchema() {
|
|
|
3755
3814
|
*/
|
|
3756
3815
|
|
|
3757
3816
|
|
|
3758
|
-
const { keys, values, create, assign, freeze } = Object;
|
|
3817
|
+
const { keys, values, create, assign, freeze, entries } = Object;
|
|
3759
3818
|
|
|
3760
3819
|
function createLink(key) {
|
|
3761
3820
|
return { __ref: key };
|
|
@@ -3869,7 +3928,7 @@ function getDenormalizedKey(originalKey, recordId, luvio) {
|
|
|
3869
3928
|
}
|
|
3870
3929
|
return keyBuilderRecord(luvio, { recordId });
|
|
3871
3930
|
}
|
|
3872
|
-
function makeRecordDenormalizingDurableStore(luvio, durableStore, getStoreRecords, getStoreMetadata, getStore) {
|
|
3931
|
+
function makeRecordDenormalizingDurableStore(luvio, durableStore, getStoreRecords, getStoreMetadata, getStore, sqlStore) {
|
|
3873
3932
|
const getEntries = function (entries, segment) {
|
|
3874
3933
|
// this HOF only inspects records in the default segment
|
|
3875
3934
|
if (segment !== DefaultDurableSegment) {
|
|
@@ -3931,7 +3990,10 @@ function makeRecordDenormalizingDurableStore(luvio, durableStore, getStoreRecord
|
|
|
3931
3990
|
});
|
|
3932
3991
|
};
|
|
3933
3992
|
const denormalizeEntries = function (entries) {
|
|
3993
|
+
let hasEntries = false;
|
|
3994
|
+
let hasMetadata = false;
|
|
3934
3995
|
const putEntries = create(null);
|
|
3996
|
+
const putMetadata = create(null);
|
|
3935
3997
|
const keys$1 = keys(entries);
|
|
3936
3998
|
const putRecords = {};
|
|
3937
3999
|
const putRecordViews = {};
|
|
@@ -3974,6 +4036,7 @@ function makeRecordDenormalizingDurableStore(luvio, durableStore, getStoreRecord
|
|
|
3974
4036
|
putRecords[recordId] = true;
|
|
3975
4037
|
}
|
|
3976
4038
|
if (isStoreRecordError(record)) {
|
|
4039
|
+
hasEntries = true;
|
|
3977
4040
|
putEntries[recordKey] = value;
|
|
3978
4041
|
continue;
|
|
3979
4042
|
}
|
|
@@ -3986,24 +4049,43 @@ function makeRecordDenormalizingDurableStore(luvio, durableStore, getStoreRecord
|
|
|
3986
4049
|
}
|
|
3987
4050
|
const denormalizedRecord = buildDurableRecordRepresentation(record, storeRecords, recordEntries, store);
|
|
3988
4051
|
if (denormalizedRecord !== undefined) {
|
|
4052
|
+
hasEntries = true;
|
|
3989
4053
|
putEntries[recordKey] = {
|
|
3990
4054
|
data: denormalizedRecord,
|
|
3991
4055
|
metadata,
|
|
3992
4056
|
};
|
|
4057
|
+
// if undefined then it is pending
|
|
4058
|
+
// we should still update metadata on pending records
|
|
4059
|
+
}
|
|
4060
|
+
else {
|
|
4061
|
+
hasMetadata = true;
|
|
4062
|
+
metadata.expirationTimestamp = metadata.ingestionTimestamp;
|
|
4063
|
+
putMetadata[recordKey] = {
|
|
4064
|
+
metadata,
|
|
4065
|
+
};
|
|
3993
4066
|
}
|
|
3994
4067
|
}
|
|
3995
4068
|
else {
|
|
4069
|
+
hasEntries = true;
|
|
3996
4070
|
putEntries[key] = value;
|
|
3997
4071
|
}
|
|
3998
4072
|
}
|
|
3999
|
-
return putEntries;
|
|
4073
|
+
return { putEntries, putMetadata, hasEntries, hasMetadata };
|
|
4000
4074
|
};
|
|
4001
4075
|
const setEntries = function (entries, segment) {
|
|
4002
4076
|
if (segment !== DefaultDurableSegment) {
|
|
4003
4077
|
return durableStore.setEntries(entries, segment);
|
|
4004
4078
|
}
|
|
4005
|
-
const putEntries = denormalizeEntries(entries);
|
|
4006
|
-
|
|
4079
|
+
const { putEntries, putMetadata, hasEntries, hasMetadata } = denormalizeEntries(entries);
|
|
4080
|
+
const promises = [
|
|
4081
|
+
hasEntries ? durableStore.setEntries(putEntries, segment) : undefined,
|
|
4082
|
+
];
|
|
4083
|
+
if (sqlStore !== undefined && sqlStore.isBatchUpdateSupported()) {
|
|
4084
|
+
promises.push(hasMetadata && sqlStore !== undefined
|
|
4085
|
+
? durableStore.setMetadata(putMetadata, segment)
|
|
4086
|
+
: undefined);
|
|
4087
|
+
}
|
|
4088
|
+
return Promise.all(promises).then(() => { });
|
|
4007
4089
|
};
|
|
4008
4090
|
const batchOperations = function (operations) {
|
|
4009
4091
|
const operationsWithDenormedRecords = [];
|
|
@@ -4020,10 +4102,20 @@ function makeRecordDenormalizingDurableStore(luvio, durableStore, getStoreRecord
|
|
|
4020
4102
|
// this is determined by the plugin supporting update batch calls before it gets to this HOF.
|
|
4021
4103
|
// so we only need to check one entry to confirm this for performance
|
|
4022
4104
|
if (firstEntry.data !== undefined) {
|
|
4105
|
+
const { putEntries, putMetadata, hasMetadata } = denormalizeEntries(operation.entries);
|
|
4023
4106
|
operationsWithDenormedRecords.push({
|
|
4024
4107
|
...operation,
|
|
4025
|
-
entries:
|
|
4108
|
+
entries: putEntries,
|
|
4026
4109
|
});
|
|
4110
|
+
if (hasMetadata &&
|
|
4111
|
+
sqlStore !== undefined &&
|
|
4112
|
+
sqlStore.isBatchUpdateSupported() === true) {
|
|
4113
|
+
operationsWithDenormedRecords.push({
|
|
4114
|
+
...operation,
|
|
4115
|
+
entries: putMetadata,
|
|
4116
|
+
type: 'setMetadata',
|
|
4117
|
+
});
|
|
4118
|
+
}
|
|
4027
4119
|
}
|
|
4028
4120
|
else {
|
|
4029
4121
|
operationsWithDenormedRecords.push(operation);
|
|
@@ -4035,10 +4127,20 @@ function makeRecordDenormalizingDurableStore(luvio, durableStore, getStoreRecord
|
|
|
4035
4127
|
operationsWithDenormedRecords.push(operation);
|
|
4036
4128
|
continue;
|
|
4037
4129
|
}
|
|
4130
|
+
const { putEntries, putMetadata, hasMetadata } = denormalizeEntries(operation.entries);
|
|
4038
4131
|
operationsWithDenormedRecords.push({
|
|
4039
4132
|
...operation,
|
|
4040
|
-
entries:
|
|
4133
|
+
entries: putEntries,
|
|
4041
4134
|
});
|
|
4135
|
+
if (hasMetadata &&
|
|
4136
|
+
sqlStore !== undefined &&
|
|
4137
|
+
sqlStore.isBatchUpdateSupported() === true) {
|
|
4138
|
+
operationsWithDenormedRecords.push({
|
|
4139
|
+
...operation,
|
|
4140
|
+
entries: putMetadata,
|
|
4141
|
+
type: 'setMetadata',
|
|
4142
|
+
});
|
|
4143
|
+
}
|
|
4042
4144
|
}
|
|
4043
4145
|
return durableStore.batchOperations(operationsWithDenormedRecords);
|
|
4044
4146
|
};
|
|
@@ -4133,4 +4235,4 @@ function ldsRuntimeBridge() {
|
|
|
4133
4235
|
}
|
|
4134
4236
|
|
|
4135
4237
|
export { ldsRuntimeBridge as default };
|
|
4136
|
-
// version: 1.
|
|
4238
|
+
// version: 1.294.0-06a44f23f
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@salesforce/lds-runtime-bridge",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.294.0",
|
|
4
4
|
"license": "SEE LICENSE IN LICENSE.txt",
|
|
5
5
|
"description": "LDS runtime for bridge.app.",
|
|
6
6
|
"main": "dist/ldsRuntimeBridge.js",
|
|
@@ -34,17 +34,17 @@
|
|
|
34
34
|
"release:corejar": "yarn build && ../core-build/scripts/core.js --name=lds-runtime-bridge"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@salesforce/lds-adapters-uiapi": "^1.
|
|
38
|
-
"@salesforce/lds-instrumentation": "^1.
|
|
37
|
+
"@salesforce/lds-adapters-uiapi": "^1.294.0",
|
|
38
|
+
"@salesforce/lds-instrumentation": "^1.294.0",
|
|
39
39
|
"@salesforce/user": "0.0.21",
|
|
40
40
|
"o11y": "250.7.0"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
|
-
"@salesforce/lds-drafts-adapters-uiapi": "^1.
|
|
44
|
-
"@salesforce/lds-network-aura": "^1.
|
|
45
|
-
"@salesforce/lds-runtime-aura": "^1.
|
|
46
|
-
"@salesforce/lds-store-nimbus": "^1.
|
|
47
|
-
"@salesforce/nimbus-plugin-lds": "^1.
|
|
43
|
+
"@salesforce/lds-drafts-adapters-uiapi": "^1.294.0",
|
|
44
|
+
"@salesforce/lds-network-aura": "^1.294.0",
|
|
45
|
+
"@salesforce/lds-runtime-aura": "^1.294.0",
|
|
46
|
+
"@salesforce/lds-store-nimbus": "^1.294.0",
|
|
47
|
+
"@salesforce/nimbus-plugin-lds": "^1.294.0",
|
|
48
48
|
"babel-plugin-dynamic-import-node": "^2.3.3"
|
|
49
49
|
},
|
|
50
50
|
"luvioBundlesize": [
|