@salesforce/lds-runtime-mobile 1.247.0 → 1.248.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.
Files changed (3) hide show
  1. package/dist/main.js +329 -110
  2. package/package.json +1 -1
  3. package/sfdc/main.js +329 -110
package/dist/main.js CHANGED
@@ -15,7 +15,7 @@ import { withRegistration, register } from '@salesforce/lds-default-luvio';
15
15
  import { setupInstrumentation, instrumentAdapter as instrumentAdapter$1, instrumentLuvio, setLdsAdaptersUiapiInstrumentation, setLdsNetworkAdapterInstrumentation } from '@salesforce/lds-instrumentation';
16
16
  import { HttpStatusCode, StoreKeySet, serializeStructuredKey, StringKeyInMemoryStore, Reader, deepFreeze, emitAdapterEvent, createCustomAdapterEventEmitter, StoreKeyMap, isFileReference, Environment, Luvio, InMemoryStore } from '@luvio/engine';
17
17
  import excludeStaleRecordsGate from '@salesforce/gate/lds.graphqlEvalExcludeStaleRecords';
18
- import { parseAndVisit, Kind, visit, execute, buildSchema, isObjectType, defaultFieldResolver } from '@luvio/graphql-parser';
18
+ import { parseAndVisit, Kind, buildSchema, isObjectType, defaultFieldResolver, visit, execute, parse as parse$7, extendSchema, isScalarType } from '@luvio/graphql-parser';
19
19
  import { RECORD_ID_PREFIX, RECORD_FIELDS_KEY_JUNCTION, isStoreKeyRecordViewEntity, getRecordId18, RECORD_REPRESENTATION_NAME, extractRecordIdFromStoreKey, keyBuilderQuickActionExecutionRepresentation, ingestQuickActionExecutionRepresentation, keyBuilderContentDocumentCompositeRepresentation, getResponseCacheKeysContentDocumentCompositeRepresentation, keyBuilderFromTypeContentDocumentCompositeRepresentation, ingestContentDocumentCompositeRepresentation, keyBuilderRecord, RECORD_VIEW_ENTITY_ID_PREFIX, getTypeCacheKeysRecord, keyBuilderFromTypeRecordRepresentation, ingestRecord, RecordRepresentationRepresentationType, ObjectInfoRepresentationType, getRecordAdapterFactory, getObjectInfoAdapterFactory, getObjectInfosAdapterFactory, getObjectInfoDirectoryAdapterFactory, UiApiNamespace, RecordRepresentationType, RecordRepresentationTTL, RecordRepresentationVersion, keyBuilderObjectInfo, ObjectInfoDirectoryEntryRepresentationType, getRecordsAdapterFactory } from '@salesforce/lds-adapters-uiapi';
20
20
  import caseSensitiveUserId from '@salesforce/user/Id';
21
21
  import { idleDetector, getInstrumentation } from 'o11y/client';
@@ -7077,7 +7077,7 @@ function isArrayLike(x) {
7077
7077
 
7078
7078
  const { create: create$4, keys: keys$4, values: values$2, entries: entries$3, assign: assign$4 } = Object;
7079
7079
  const { stringify: stringify$4, parse: parse$4 } = JSON;
7080
- const { isArray: isArray$2 } = Array;
7080
+ const { isArray: isArray$2, from: from$1 } = Array;
7081
7081
 
7082
7082
  function recordLoaderFactory(query) {
7083
7083
  async function batchRecordQuery(ids) {
@@ -9308,25 +9308,6 @@ const additionalSchemaDefinitions = /* GraphQL */ `
9308
9308
  }
9309
9309
  `;
9310
9310
  const baseTypeDefinitions = uiapiSchemaString + additionalSchemaDefinitions;
9311
- /**
9312
- *
9313
- * @param objectInfos
9314
- * @returns Type definition string and entity type names which support polymorphism.
9315
- */
9316
- function generateTypeDefinitions(objectInfos) {
9317
- if (keys$4(objectInfos).length === 0)
9318
- return { typeDefs: baseTypeDefinitions, polyFieldTypeNames: [] };
9319
- const { recordQueries, recordConnections, polyFieldTypeNameArr } = generateRecordQueries(objectInfos);
9320
- const typeDefs = `
9321
- ${baseTypeDefinitions}
9322
-
9323
- extend type RecordQuery {
9324
- ${recordQueries}
9325
- }
9326
- ${recordConnections}
9327
- `;
9328
- return { typeDefs, polyFieldTypeNames: polyFieldTypeNameArr };
9329
- }
9330
9311
  const fieldsStaticallyAdded = [
9331
9312
  'ApiName',
9332
9313
  'DisplayValue',
@@ -9336,99 +9317,340 @@ const fieldsStaticallyAdded = [
9336
9317
  'SystemModstamp',
9337
9318
  'WeakEtag',
9338
9319
  ];
9339
- function generateRecordQueries(objectInfos) {
9320
+ class CachedGraphQLSchema {
9321
+ constructor() {
9322
+ this._schema = buildBaseSchema();
9323
+ this._polymorphicFieldTypeNames = [];
9324
+ }
9325
+ getSchema() {
9326
+ return this._schema;
9327
+ }
9328
+ setSchema(value) {
9329
+ this._schema = value;
9330
+ }
9331
+ getPolymorphicFieldTypeNames() {
9332
+ return this._polymorphicFieldTypeNames;
9333
+ }
9334
+ setPolymorphicFieldTypeNames(value) {
9335
+ this._polymorphicFieldTypeNames = value;
9336
+ }
9337
+ set(schema, polymorphicFieldTypeNames) {
9338
+ this._schema = schema;
9339
+ this._polymorphicFieldTypeNames = polymorphicFieldTypeNames;
9340
+ }
9341
+ }
9342
+ /**
9343
+ * Looks at the injected object info map and checks to see if the existing objects
9344
+ * are within the current schema. It will extend the cached schema if it is not included.
9345
+ * @param objectInfos
9346
+ * @param cache
9347
+ * @returns GraphQLSchema
9348
+ */
9349
+ function createSchemaWithCache(objectInfos, cache) {
9350
+ const updatedCache = extendSchemaWithObjectInfos(cache, objectInfos);
9351
+ // set the new values to the passed cached schema & polymorphic field names
9352
+ cache.set(updatedCache.getSchema(), updatedCache.getPolymorphicFieldTypeNames());
9353
+ return cache.getSchema();
9354
+ }
9355
+ /**
9356
+ * Extends the current GraphQL Schema with new types based on the given object info map
9357
+ *
9358
+ * @param cache the existing cached schema object
9359
+ * @param objectInfoMap map of object info and apiname for key
9360
+ * @returns CachedGraphQLSchema
9361
+ */
9362
+ function extendSchemaWithObjectInfos(cache, objectInfoMap) {
9363
+ const { recordQueries, recordConnections, recordExtensions, polyFieldTypeNameArr } = generateRecordQueries(cache.getSchema(), objectInfoMap);
9364
+ const typeDefs = `
9365
+ ${recordQueries}
9366
+ ${recordConnections}
9367
+ ${recordExtensions}
9368
+ `;
9369
+ // if nothing new is added then return the current cache
9370
+ if (typeDefs.trim().length === 0) {
9371
+ return cache;
9372
+ }
9373
+ // parse extensions into DocumentNode to extend the schema
9374
+ const extensions = parse$7(typeDefs);
9375
+ const polymorphicFieldTypeNames = [
9376
+ ...polyFieldTypeNameArr,
9377
+ ...cache.getPolymorphicFieldTypeNames(),
9378
+ ];
9379
+ // extend the schema and add resolvers
9380
+ const schema = addResolversToSchema(extendSchema(cache.getSchema(), extensions), polymorphicFieldTypeNames);
9381
+ cache.setSchema(schema);
9382
+ return cache;
9383
+ }
9384
+ /**
9385
+ * Builds the base schema from uiapi graphql adapter with resolvers attached
9386
+ * @returns GraphQLSchema
9387
+ */
9388
+ function buildBaseSchema() {
9389
+ return addResolversToSchema(buildSchema(baseTypeDefinitions), []);
9390
+ }
9391
+ /**
9392
+ * Given the existing schema and the object infos it will create a new type for the schema
9393
+ * or extend an existing type to add new fields to it.
9394
+ *
9395
+ * Extends RecordQuery to add new top level queries
9396
+ * extend type RecordQuery {
9397
+ * Account(predicates): AccountConnection
9398
+ * }
9399
+ * @param schema
9400
+ * @param objectInfoMap
9401
+ * @returns
9402
+ */
9403
+ function generateRecordQueries(schema, objectInfoMap) {
9340
9404
  let recordQueries = ``;
9341
9405
  let recordConnections = ``;
9342
- const polymorphicFieldTypeNames = new Set();
9406
+ let recordExtensions = ``;
9407
+ // use a set to not allow duplicate scalars causing error(s)
9408
+ let addedTypedScalars = new Set();
9409
+ let allPolymorphicFieldTypeNames = new Set();
9410
+ for (const name of keys$4(objectInfoMap)) {
9411
+ const objectInfo = objectInfoMap[name];
9412
+ const { apiName } = objectInfo;
9413
+ const type = schema.getType(apiName);
9414
+ // if type is an ObjectType it exists in the schema
9415
+ if (isObjectType(type)) {
9416
+ const { recordExtension, typedScalars, polymorphicFieldTypeNames } = extendExistingRecordType(schema, type, objectInfo, objectInfoMap);
9417
+ recordExtensions += recordExtension;
9418
+ addedTypedScalars = new Set([...addedTypedScalars, ...typedScalars]);
9419
+ allPolymorphicFieldTypeNames = new Set([
9420
+ ...allPolymorphicFieldTypeNames,
9421
+ ...polymorphicFieldTypeNames,
9422
+ ]);
9423
+ }
9424
+ else {
9425
+ const { recordQueries: newRecordQueries, recordConnections: newRecordConnections, typedScalars, polymorphicFieldTypeNames, } = createNewRecordQuery(schema, objectInfo, objectInfoMap);
9426
+ recordQueries += newRecordQueries;
9427
+ recordConnections += newRecordConnections;
9428
+ addedTypedScalars = new Set([...addedTypedScalars, ...typedScalars]);
9429
+ allPolymorphicFieldTypeNames = new Set([
9430
+ ...allPolymorphicFieldTypeNames,
9431
+ ...polymorphicFieldTypeNames,
9432
+ ]);
9433
+ }
9434
+ }
9435
+ // transform added scalar types into a list of scalars in string
9436
+ const scalars = [...addedTypedScalars].map((scalar) => `scalar ${scalar}`).join('\n');
9437
+ recordConnections += scalars;
9438
+ // return empty string if no recordQueries were extended
9439
+ const extensionWrapper = recordQueries.length > 0
9440
+ ? `
9441
+ extend type RecordQuery {
9442
+ ${recordQueries}
9443
+ }`
9444
+ : '';
9445
+ return {
9446
+ recordQueries: extensionWrapper,
9447
+ recordConnections,
9448
+ recordExtensions,
9449
+ polyFieldTypeNameArr: from$1(allPolymorphicFieldTypeNames),
9450
+ };
9451
+ }
9452
+ /**
9453
+ * Will create a new record query extension for something that does not already exist in the schema
9454
+ *
9455
+ * generates:
9456
+ *
9457
+ * type {typename} implements Record {
9458
+ * ...scalar fields
9459
+ * Id: IDValue
9460
+ * ...spanning parent records
9461
+ * User: Parent
9462
+ * ...spanning children queries
9463
+ * Accounts(predicates): AccountConnection
9464
+ * }
9465
+ *
9466
+ * scalars SomeAddedScalar
9467
+ *
9468
+ * @param schema
9469
+ * @param objectInfo
9470
+ * @param objectInfoMap
9471
+ * @returns
9472
+ */
9473
+ function createNewRecordQuery(schema, objectInfo, objectInfoMap) {
9343
9474
  let typedScalars = new Set();
9344
9475
  let parentRelationshipFields = new Set();
9345
- for (const objectInfo of values$2(objectInfos)) {
9346
- const { apiName, childRelationships } = objectInfo;
9347
- let fields = ``;
9348
- typedScalars.add(`${apiName}_Filter`);
9349
- typedScalars.add(`${apiName}_OrderBy`);
9350
- for (const field of values$2(objectInfo.fields)) {
9351
- if (!fieldsStaticallyAdded.includes(field.apiName)) {
9352
- fields += `${field.apiName}: ${dataTypeToType(field.dataType, field.apiName)}\n`;
9353
- }
9354
- //handles parent relationship
9355
- if (field.relationshipName === null) {
9356
- continue;
9476
+ const { apiName, childRelationships, fields: fieldsRepresentation } = objectInfo;
9477
+ typedScalars.add(`${apiName}_Filter`);
9478
+ typedScalars.add(`${apiName}_OrderBy`);
9479
+ const { fields, polymorphicFieldTypeNames } = makeRecordField(values$2(fieldsRepresentation), objectInfoMap, parentRelationshipFields, 'Missing');
9480
+ // handles child relationship
9481
+ const { spanningRecordConnections, typedScalars: spanningConnectionTypedScalars } = makeSpanningRecordConnections(schema, childRelationships, objectInfoMap, parentRelationshipFields);
9482
+ typedScalars = new Set([...typedScalars, ...spanningConnectionTypedScalars]);
9483
+ const recordQueries = `${apiName}(first: Int, where: ${apiName}_Filter, orderBy: ${apiName}_OrderBy, scope: SupportedScopes): ${apiName}Connection\n`;
9484
+ const isServiceAppointment = apiName === 'ServiceAppointment';
9485
+ const recordConnections = /* GraphQL */ `
9486
+ ${isServiceAppointment ? `scalar ${apiName.toUpperCase()}_SCOPE` : ''}
9487
+
9488
+ type ${apiName} implements Record {
9489
+ ApiName: String!
9490
+ DisplayValue: String
9491
+ LastModifiedById: IDValue
9492
+ LastModifiedDate: DateTimeValue
9493
+ RecordTypeId(fallback: Boolean): IDValue
9494
+ SystemModstamp: DateTimeValue
9495
+ WeakEtag: Long!
9496
+ _drafts: JSON
9497
+ ${fields}
9498
+ ${spanningRecordConnections}
9357
9499
  }
9358
- // For spanning parent relationships with no union types
9359
- if (field.referenceToInfos.length === 1) {
9360
- const [relation] = field.referenceToInfos;
9361
- // Only add the relationship if there is relevant objectinfos for it,
9362
- // otherwise we'd be defining types we cannot satisfy and aren't referenced in
9363
- // the query.
9364
- if (objectInfos[relation.apiName] !== undefined) {
9365
- parentRelationshipFields.add(field.relationshipName);
9366
- fields += `${field.relationshipName}: ${relation.apiName}\n`;
9367
- }
9368
- // For polymorphic field, its type is 'Record' inteface. The concrete entity type name is saved for field resolving of next phase
9369
- }
9370
- else if (field.referenceToInfos.length > 1) {
9371
- parentRelationshipFields.add(field.relationshipName);
9372
- fields += `${field.relationshipName}: Record\n`;
9373
- for (const relation of field.referenceToInfos) {
9374
- if (objectInfos[relation.apiName] !== undefined) {
9375
- polymorphicFieldTypeNames.add(relation.apiName);
9376
- }
9377
- }
9500
+
9501
+ type ${apiName}Connection {
9502
+ edges: [${apiName}Edge]
9503
+ pageInfo: PageInfo!
9504
+ totalCount: Int!
9378
9505
  }
9506
+
9507
+ type ${apiName}Edge {
9508
+ node: ${apiName}
9509
+ cursor: String!
9510
+ }
9511
+
9512
+ `;
9513
+ return { recordQueries, recordConnections, typedScalars, polymorphicFieldTypeNames };
9514
+ }
9515
+ /**
9516
+ * Takes the current schema and will extend missing fields to the record.
9517
+ * Assume all scalar fields have already been added, but will extend spanning fields
9518
+ *
9519
+ * extend type Account {
9520
+ * ...spanning parent records
9521
+ * User: User
9522
+ * ...spanning children queries
9523
+ * Users(predicates): UserConnection
9524
+ * }
9525
+ *
9526
+ * @param schema
9527
+ * @param type
9528
+ * @param objectInfo
9529
+ * @param objectInfoMap
9530
+ * @returns
9531
+ */
9532
+ function extendExistingRecordType(schema, type, objectInfo, objectInfoMap) {
9533
+ // use a set to not allow duplicate scalars causing error(s)
9534
+ let typedScalars = new Set();
9535
+ let parentRelationshipFields = new Set();
9536
+ const existingFields = keys$4(type.getFields());
9537
+ const missingFields = values$2(objectInfo.fields).filter((field) => existingFields.includes(field.apiName) === false);
9538
+ const { fields, polymorphicFieldTypeNames } = makeRecordField(missingFields, objectInfoMap, parentRelationshipFields, 'Cached');
9539
+ const { apiName, childRelationships } = objectInfo;
9540
+ // handles child relationship
9541
+ const { spanningRecordConnections, typedScalars: spanningConnectionTypedScalars } = makeSpanningRecordConnections(schema, childRelationships, objectInfoMap, parentRelationshipFields, existingFields);
9542
+ typedScalars = new Set([...typedScalars, ...spanningConnectionTypedScalars]);
9543
+ const hasExtensions = fields.length > 0 || spanningRecordConnections.length > 0;
9544
+ const recordExtension = hasExtensions
9545
+ ? `
9546
+ extend type ${apiName} {
9547
+ ${fields}
9548
+ ${spanningRecordConnections}
9549
+ }\n`
9550
+ : '';
9551
+ return { recordExtension, typedScalars, polymorphicFieldTypeNames };
9552
+ }
9553
+ /**
9554
+ * Converts child relationships into spanning record connections to be added to record types
9555
+ *
9556
+ * type Record {
9557
+ * Generates -> AccountConnection(first: Int, where: Account_Filter, etc...): AccountConnection
9558
+ * }
9559
+ *
9560
+ * will also generate typed scalars if they have not been added to the existing schema for the spanning connection
9561
+ * example: Account_Filter or Account_OrderBy scalars needed to be defined as predicate types
9562
+ * @param schema
9563
+ * @param childRelationships
9564
+ * @param objectInfoMap
9565
+ * @param existingParentRelationships
9566
+ * @param existingFields
9567
+ * @returns
9568
+ */
9569
+ function makeSpanningRecordConnections(schema, childRelationships, objectInfoMap, existingParentRelationships, existingFields = []) {
9570
+ let spanningRecordConnections = ``;
9571
+ let typedScalars = new Set();
9572
+ for (const childRelationship of childRelationships) {
9573
+ const { childObjectApiName, relationshipName } = childRelationship;
9574
+ // Only add the relationship if there is relevant objectinfos for it,
9575
+ // otherwise we'd be defining types we cannot satisfy and aren't referenced in
9576
+ // the query.
9577
+ // If one field has both parent relationship and child relationship with the same name, the child relationship is ignored. This is how the server GQL has implemented as date of 08/07/2023
9578
+ if (existingFields.length > 0 && existingFields.includes(relationshipName)) {
9579
+ continue;
9379
9580
  }
9380
- // handles child relationship
9381
- for (const childRelationship of childRelationships) {
9382
- const { childObjectApiName } = childRelationship;
9383
- // Only add the relationship if there is relevant objectinfos for it,
9384
- // otherwise we'd be defining types we cannot satisfy and aren't referenced in
9385
- // the query.
9386
- // If one field has both parent relationship and child relationship with the same name, the child relationship is ignored. This is how the server GQL has implemented as date of 08/07/2023
9387
- if (objectInfos[childObjectApiName] !== undefined &&
9388
- !parentRelationshipFields.has(childRelationship.relationshipName)) {
9389
- fields += `${childRelationship.relationshipName}(first: Int, where: ${childObjectApiName}_Filter, orderBy: ${childObjectApiName}_OrderBy, scope: SupportedScopes): ${childObjectApiName}Connection \n`;
9581
+ if (objectInfoMap[childObjectApiName] !== undefined &&
9582
+ !existingParentRelationships.has(relationshipName)) {
9583
+ spanningRecordConnections += `${relationshipName}(first: Int, where: ${childObjectApiName}_Filter, orderBy: ${childObjectApiName}_OrderBy, scope: SupportedScopes): ${childObjectApiName}Connection \n`;
9584
+ // if the record type has already been extended then these additional scalars have already been added
9585
+ // to add them again would throw an error
9586
+ const filterScalarType = schema.getType(`${childObjectApiName}_Filter`);
9587
+ if (isScalarType(filterScalarType) === false) {
9390
9588
  typedScalars.add(`${childObjectApiName}_Filter`);
9589
+ }
9590
+ const orderByScalarType = schema.getType(`${childObjectApiName}_OrderBy`);
9591
+ if (isScalarType(orderByScalarType) === false) {
9391
9592
  typedScalars.add(`${childObjectApiName}_OrderBy`);
9392
9593
  }
9393
9594
  }
9394
- recordQueries += `${apiName}(first: Int, where: ${apiName}_Filter, orderBy: ${apiName}_OrderBy, scope: SupportedScopes): ${apiName}Connection\n`;
9395
- const isServiceAppointment = apiName === 'ServiceAppointment';
9396
- recordConnections += /* GraphQL */ `
9397
- ${isServiceAppointment ? `scalar ${apiName.toUpperCase()}_SCOPE` : ''}
9398
-
9399
- type ${apiName} implements Record {
9400
- ApiName: String!
9401
- DisplayValue: String
9402
- LastModifiedById: IDValue
9403
- LastModifiedDate: DateTimeValue
9404
- RecordTypeId(fallback: Boolean): IDValue
9405
- SystemModstamp: DateTimeValue
9406
- WeakEtag: Long!
9407
- _drafts: JSON
9408
- ${fields}
9409
- }
9410
-
9411
- type ${apiName}Connection {
9412
- edges: [${apiName}Edge]
9413
- pageInfo: PageInfo!
9414
- totalCount: Int!
9415
- }
9416
-
9417
- type ${apiName}Edge {
9418
- node: ${apiName}
9419
- cursor: String!
9595
+ }
9596
+ return { spanningRecordConnections, typedScalars };
9597
+ }
9598
+ /**
9599
+ * Creates scalar and parent relationship fields for a record type
9600
+ *
9601
+ * type RecordName {
9602
+ * generates scalar -> Id: IDValue
9603
+ * generates relationship -> Account: Record
9604
+ * }
9605
+ *
9606
+ * can be used in a type definition or an extension
9607
+ * @param fieldRepresentations
9608
+ * @param objectInfoMap
9609
+ * @param existingParentRelationships
9610
+ * @param recordTypeInSchema
9611
+ * @returns
9612
+ */
9613
+ function makeRecordField(fieldRepresentations, objectInfoMap, existingParentRelationships, recordTypeInSchema) {
9614
+ const polymorphicFieldTypeNames = new Set();
9615
+ let fields = ``;
9616
+ for (const field of values$2(fieldRepresentations)) {
9617
+ if (!fieldsStaticallyAdded.includes(field.apiName) && recordTypeInSchema === 'Missing') {
9618
+ fields += `${field.apiName}: ${dataTypeToType(field.dataType, field.apiName)}\n`;
9619
+ }
9620
+ //handles parent relationship
9621
+ if (field.relationshipName === null) {
9622
+ continue;
9623
+ }
9624
+ // For spanning parent relationships with no union types
9625
+ if (field.referenceToInfos.length === 1) {
9626
+ const [relation] = field.referenceToInfos;
9627
+ // Only add the relationship if there is relevant objectinfos for it,
9628
+ // otherwise we'd be defining types we cannot satisfy and aren't referenced in
9629
+ // the query.
9630
+ if (objectInfoMap[relation.apiName] !== undefined) {
9631
+ existingParentRelationships.add(field.relationshipName);
9632
+ fields += `${field.relationshipName}: ${relation.apiName}\n`;
9633
+ }
9634
+ // For polymorphic field, its type is 'Record' inteface. The concrete entity type name is saved for field resolving of next phase
9635
+ }
9636
+ else if (field.referenceToInfos.length > 1) {
9637
+ existingParentRelationships.add(field.relationshipName);
9638
+ fields += `${field.relationshipName}: Record\n`;
9639
+ for (const relation of field.referenceToInfos) {
9640
+ if (objectInfoMap[relation.apiName] !== undefined) {
9641
+ polymorphicFieldTypeNames.add(relation.apiName);
9642
+ }
9643
+ }
9420
9644
  }
9421
-
9422
- `;
9423
9645
  }
9424
- const scalars = [...typedScalars].reduce((accu, typed) => {
9425
- return accu + `scalar ${typed}\n`;
9426
- }, ``);
9427
- recordConnections += scalars;
9428
- const polyFieldTypeNameArr = [];
9429
- polymorphicFieldTypeNames.forEach((fieldType) => polyFieldTypeNameArr.push(fieldType));
9430
- return { recordQueries, recordConnections, polyFieldTypeNameArr };
9646
+ return { fields, polymorphicFieldTypeNames };
9431
9647
  }
9648
+ /**
9649
+ * converts the ObjectInfoRepresentation data type into a defined schema scalar type
9650
+ * @param objectInfoDataType
9651
+ * @param apiName
9652
+ * @returns
9653
+ */
9432
9654
  function dataTypeToType(objectInfoDataType, apiName) {
9433
9655
  if (apiName && apiName === 'Id') {
9434
9656
  return `ID!`;
@@ -9470,13 +9692,8 @@ function dataTypeToType(objectInfoDataType, apiName) {
9470
9692
  return 'String';
9471
9693
  }
9472
9694
  }
9473
- function createSchema(objectInfos) {
9474
- const { typeDefs: typeDefinitions, polyFieldTypeNames } = generateTypeDefinitions(objectInfos);
9475
- const schema = buildSchema(typeDefinitions);
9476
- return addResolversToSchema(schema, polyFieldTypeNames);
9477
- }
9478
9695
 
9479
- async function evaluate(config, observers, settings, objectInfos, store, snapshot, draftFunctions) {
9696
+ async function evaluate(config, observers, settings, objectInfos, store, snapshot, cache, draftFunctions) {
9480
9697
  const eventEmitter = createCustomAdapterEventEmitter(GRAPHQL_EVAL_NAMESPACE, observers);
9481
9698
  // this is only wrapped in a try to execute the event after the result was returned
9482
9699
  try {
@@ -9517,7 +9734,7 @@ async function evaluate(config, observers, settings, objectInfos, store, snapsho
9517
9734
  const contextValue = createContext(store, objectInfos, eventEmitter, settings, snapshot, draftFunctions);
9518
9735
  // We're building this from scratch from each request. If this becomes a
9519
9736
  // hotspot we can pull it up and memoize it later
9520
- const schema = createSchema(objectInfos);
9737
+ const schema = createSchemaWithCache(objectInfos, cache);
9521
9738
  eventEmitter({ type: 'graphql-schema-created' });
9522
9739
  // execute document against schema/context
9523
9740
  let result = (await execute({
@@ -13012,6 +13229,8 @@ const replaceDraftIdsInVariables = (variables, draftFunctions, unmappedDraftIDs)
13012
13229
  }, {});
13013
13230
  return newVariables;
13014
13231
  };
13232
+ // create the runtime cache for the graphql schema when the factory creates the adapter
13233
+ const graphqlSchemaCache = new CachedGraphQLSchema();
13015
13234
  function draftAwareGraphQLAdapterFactory(userId, objectInfoService, store, luvio, isDraftId) {
13016
13235
  const getCanonicalId = (id) => {
13017
13236
  var _a;
@@ -13085,7 +13304,7 @@ function draftAwareGraphQLAdapterFactory(userId, objectInfoService, store, luvio
13085
13304
  ...config,
13086
13305
  //need to create another copy of the ast for future writes
13087
13306
  query: parse$3(stringify$3(injectedAST)),
13088
- }, observers, { userId }, objectInfoNeeded, store, nonEvaluatedSnapshot));
13307
+ }, observers, { userId }, objectInfoNeeded, store, nonEvaluatedSnapshot, graphqlSchemaCache));
13089
13308
  }
13090
13309
  catch (throwable) {
13091
13310
  const error = throwable;
@@ -13114,7 +13333,7 @@ function draftAwareGraphQLAdapterFactory(userId, objectInfoService, store, luvio
13114
13333
  let { result: rebuildResult, seenRecordIds } = await evaluate({
13115
13334
  ...config,
13116
13335
  query: injectedAST,
13117
- }, observers, { userId }, objectInfoNeeded, store, originalSnapshot, draftFunctions);
13336
+ }, observers, { userId }, objectInfoNeeded, store, originalSnapshot, graphqlSchemaCache, draftFunctions);
13118
13337
  if (!rebuildResult.errors) {
13119
13338
  rebuildResult = removeSyntheticFields(rebuildResult, config.query);
13120
13339
  }
@@ -17288,4 +17507,4 @@ register({
17288
17507
  });
17289
17508
 
17290
17509
  export { getRuntime, registerReportObserver, reportGraphqlQueryParseError };
17291
- // version: 1.247.0-4fe38c091
17510
+ // version: 1.248.0-1f7f01112
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salesforce/lds-runtime-mobile",
3
- "version": "1.247.0",
3
+ "version": "1.248.0",
4
4
  "license": "SEE LICENSE IN LICENSE.txt",
5
5
  "description": "LDS runtime for mobile/hybrid environments.",
6
6
  "main": "dist/main.js",
package/sfdc/main.js CHANGED
@@ -15,7 +15,7 @@ import { withRegistration, register } from 'native/ldsEngineMobile';
15
15
  import { setupInstrumentation, instrumentAdapter as instrumentAdapter$1, instrumentLuvio, setLdsAdaptersUiapiInstrumentation, setLdsNetworkAdapterInstrumentation } from 'force/ldsInstrumentation';
16
16
  import { HttpStatusCode, StoreKeySet, serializeStructuredKey, StringKeyInMemoryStore, Reader, deepFreeze, emitAdapterEvent, createCustomAdapterEventEmitter, StoreKeyMap, isFileReference, Environment, Luvio, InMemoryStore } from 'force/luvioEngine';
17
17
  import excludeStaleRecordsGate from '@salesforce/gate/lds.graphqlEvalExcludeStaleRecords';
18
- import { parseAndVisit, Kind, visit, execute, buildSchema, isObjectType, defaultFieldResolver } from 'force/ldsGraphqlParser';
18
+ import { parseAndVisit, Kind, buildSchema, isObjectType, defaultFieldResolver, visit, execute, parse as parse$7, extendSchema, isScalarType } from 'force/ldsGraphqlParser';
19
19
  import { RECORD_ID_PREFIX, RECORD_FIELDS_KEY_JUNCTION, isStoreKeyRecordViewEntity, getRecordId18, RECORD_REPRESENTATION_NAME, extractRecordIdFromStoreKey, keyBuilderQuickActionExecutionRepresentation, ingestQuickActionExecutionRepresentation, keyBuilderContentDocumentCompositeRepresentation, getResponseCacheKeysContentDocumentCompositeRepresentation, keyBuilderFromTypeContentDocumentCompositeRepresentation, ingestContentDocumentCompositeRepresentation, keyBuilderRecord, RECORD_VIEW_ENTITY_ID_PREFIX, getTypeCacheKeysRecord, keyBuilderFromTypeRecordRepresentation, ingestRecord, RecordRepresentationRepresentationType, ObjectInfoRepresentationType, getRecordAdapterFactory, getObjectInfoAdapterFactory, getObjectInfosAdapterFactory, getObjectInfoDirectoryAdapterFactory, UiApiNamespace, RecordRepresentationType, RecordRepresentationTTL, RecordRepresentationVersion, keyBuilderObjectInfo, ObjectInfoDirectoryEntryRepresentationType, getRecordsAdapterFactory } from 'force/ldsAdaptersUiapi';
20
20
  import caseSensitiveUserId from '@salesforce/user/Id';
21
21
  import { idleDetector, getInstrumentation } from 'o11y/client';
@@ -7077,7 +7077,7 @@ function isArrayLike(x) {
7077
7077
 
7078
7078
  const { create: create$4, keys: keys$4, values: values$2, entries: entries$3, assign: assign$4 } = Object;
7079
7079
  const { stringify: stringify$4, parse: parse$4 } = JSON;
7080
- const { isArray: isArray$2 } = Array;
7080
+ const { isArray: isArray$2, from: from$1 } = Array;
7081
7081
 
7082
7082
  function recordLoaderFactory(query) {
7083
7083
  async function batchRecordQuery(ids) {
@@ -9308,25 +9308,6 @@ const additionalSchemaDefinitions = /* GraphQL */ `
9308
9308
  }
9309
9309
  `;
9310
9310
  const baseTypeDefinitions = uiapiSchemaString + additionalSchemaDefinitions;
9311
- /**
9312
- *
9313
- * @param objectInfos
9314
- * @returns Type definition string and entity type names which support polymorphism.
9315
- */
9316
- function generateTypeDefinitions(objectInfos) {
9317
- if (keys$4(objectInfos).length === 0)
9318
- return { typeDefs: baseTypeDefinitions, polyFieldTypeNames: [] };
9319
- const { recordQueries, recordConnections, polyFieldTypeNameArr } = generateRecordQueries(objectInfos);
9320
- const typeDefs = `
9321
- ${baseTypeDefinitions}
9322
-
9323
- extend type RecordQuery {
9324
- ${recordQueries}
9325
- }
9326
- ${recordConnections}
9327
- `;
9328
- return { typeDefs, polyFieldTypeNames: polyFieldTypeNameArr };
9329
- }
9330
9311
  const fieldsStaticallyAdded = [
9331
9312
  'ApiName',
9332
9313
  'DisplayValue',
@@ -9336,99 +9317,340 @@ const fieldsStaticallyAdded = [
9336
9317
  'SystemModstamp',
9337
9318
  'WeakEtag',
9338
9319
  ];
9339
- function generateRecordQueries(objectInfos) {
9320
+ class CachedGraphQLSchema {
9321
+ constructor() {
9322
+ this._schema = buildBaseSchema();
9323
+ this._polymorphicFieldTypeNames = [];
9324
+ }
9325
+ getSchema() {
9326
+ return this._schema;
9327
+ }
9328
+ setSchema(value) {
9329
+ this._schema = value;
9330
+ }
9331
+ getPolymorphicFieldTypeNames() {
9332
+ return this._polymorphicFieldTypeNames;
9333
+ }
9334
+ setPolymorphicFieldTypeNames(value) {
9335
+ this._polymorphicFieldTypeNames = value;
9336
+ }
9337
+ set(schema, polymorphicFieldTypeNames) {
9338
+ this._schema = schema;
9339
+ this._polymorphicFieldTypeNames = polymorphicFieldTypeNames;
9340
+ }
9341
+ }
9342
+ /**
9343
+ * Looks at the injected object info map and checks to see if the existing objects
9344
+ * are within the current schema. It will extend the cached schema if it is not included.
9345
+ * @param objectInfos
9346
+ * @param cache
9347
+ * @returns GraphQLSchema
9348
+ */
9349
+ function createSchemaWithCache(objectInfos, cache) {
9350
+ const updatedCache = extendSchemaWithObjectInfos(cache, objectInfos);
9351
+ // set the new values to the passed cached schema & polymorphic field names
9352
+ cache.set(updatedCache.getSchema(), updatedCache.getPolymorphicFieldTypeNames());
9353
+ return cache.getSchema();
9354
+ }
9355
+ /**
9356
+ * Extends the current GraphQL Schema with new types based on the given object info map
9357
+ *
9358
+ * @param cache the existing cached schema object
9359
+ * @param objectInfoMap map of object info and apiname for key
9360
+ * @returns CachedGraphQLSchema
9361
+ */
9362
+ function extendSchemaWithObjectInfos(cache, objectInfoMap) {
9363
+ const { recordQueries, recordConnections, recordExtensions, polyFieldTypeNameArr } = generateRecordQueries(cache.getSchema(), objectInfoMap);
9364
+ const typeDefs = `
9365
+ ${recordQueries}
9366
+ ${recordConnections}
9367
+ ${recordExtensions}
9368
+ `;
9369
+ // if nothing new is added then return the current cache
9370
+ if (typeDefs.trim().length === 0) {
9371
+ return cache;
9372
+ }
9373
+ // parse extensions into DocumentNode to extend the schema
9374
+ const extensions = parse$7(typeDefs);
9375
+ const polymorphicFieldTypeNames = [
9376
+ ...polyFieldTypeNameArr,
9377
+ ...cache.getPolymorphicFieldTypeNames(),
9378
+ ];
9379
+ // extend the schema and add resolvers
9380
+ const schema = addResolversToSchema(extendSchema(cache.getSchema(), extensions), polymorphicFieldTypeNames);
9381
+ cache.setSchema(schema);
9382
+ return cache;
9383
+ }
9384
+ /**
9385
+ * Builds the base schema from uiapi graphql adapter with resolvers attached
9386
+ * @returns GraphQLSchema
9387
+ */
9388
+ function buildBaseSchema() {
9389
+ return addResolversToSchema(buildSchema(baseTypeDefinitions), []);
9390
+ }
9391
+ /**
9392
+ * Given the existing schema and the object infos it will create a new type for the schema
9393
+ * or extend an existing type to add new fields to it.
9394
+ *
9395
+ * Extends RecordQuery to add new top level queries
9396
+ * extend type RecordQuery {
9397
+ * Account(predicates): AccountConnection
9398
+ * }
9399
+ * @param schema
9400
+ * @param objectInfoMap
9401
+ * @returns
9402
+ */
9403
+ function generateRecordQueries(schema, objectInfoMap) {
9340
9404
  let recordQueries = ``;
9341
9405
  let recordConnections = ``;
9342
- const polymorphicFieldTypeNames = new Set();
9406
+ let recordExtensions = ``;
9407
+ // use a set to not allow duplicate scalars causing error(s)
9408
+ let addedTypedScalars = new Set();
9409
+ let allPolymorphicFieldTypeNames = new Set();
9410
+ for (const name of keys$4(objectInfoMap)) {
9411
+ const objectInfo = objectInfoMap[name];
9412
+ const { apiName } = objectInfo;
9413
+ const type = schema.getType(apiName);
9414
+ // if type is an ObjectType it exists in the schema
9415
+ if (isObjectType(type)) {
9416
+ const { recordExtension, typedScalars, polymorphicFieldTypeNames } = extendExistingRecordType(schema, type, objectInfo, objectInfoMap);
9417
+ recordExtensions += recordExtension;
9418
+ addedTypedScalars = new Set([...addedTypedScalars, ...typedScalars]);
9419
+ allPolymorphicFieldTypeNames = new Set([
9420
+ ...allPolymorphicFieldTypeNames,
9421
+ ...polymorphicFieldTypeNames,
9422
+ ]);
9423
+ }
9424
+ else {
9425
+ const { recordQueries: newRecordQueries, recordConnections: newRecordConnections, typedScalars, polymorphicFieldTypeNames, } = createNewRecordQuery(schema, objectInfo, objectInfoMap);
9426
+ recordQueries += newRecordQueries;
9427
+ recordConnections += newRecordConnections;
9428
+ addedTypedScalars = new Set([...addedTypedScalars, ...typedScalars]);
9429
+ allPolymorphicFieldTypeNames = new Set([
9430
+ ...allPolymorphicFieldTypeNames,
9431
+ ...polymorphicFieldTypeNames,
9432
+ ]);
9433
+ }
9434
+ }
9435
+ // transform added scalar types into a list of scalars in string
9436
+ const scalars = [...addedTypedScalars].map((scalar) => `scalar ${scalar}`).join('\n');
9437
+ recordConnections += scalars;
9438
+ // return empty string if no recordQueries were extended
9439
+ const extensionWrapper = recordQueries.length > 0
9440
+ ? `
9441
+ extend type RecordQuery {
9442
+ ${recordQueries}
9443
+ }`
9444
+ : '';
9445
+ return {
9446
+ recordQueries: extensionWrapper,
9447
+ recordConnections,
9448
+ recordExtensions,
9449
+ polyFieldTypeNameArr: from$1(allPolymorphicFieldTypeNames),
9450
+ };
9451
+ }
9452
+ /**
9453
+ * Will create a new record query extension for something that does not already exist in the schema
9454
+ *
9455
+ * generates:
9456
+ *
9457
+ * type {typename} implements Record {
9458
+ * ...scalar fields
9459
+ * Id: IDValue
9460
+ * ...spanning parent records
9461
+ * User: Parent
9462
+ * ...spanning children queries
9463
+ * Accounts(predicates): AccountConnection
9464
+ * }
9465
+ *
9466
+ * scalars SomeAddedScalar
9467
+ *
9468
+ * @param schema
9469
+ * @param objectInfo
9470
+ * @param objectInfoMap
9471
+ * @returns
9472
+ */
9473
+ function createNewRecordQuery(schema, objectInfo, objectInfoMap) {
9343
9474
  let typedScalars = new Set();
9344
9475
  let parentRelationshipFields = new Set();
9345
- for (const objectInfo of values$2(objectInfos)) {
9346
- const { apiName, childRelationships } = objectInfo;
9347
- let fields = ``;
9348
- typedScalars.add(`${apiName}_Filter`);
9349
- typedScalars.add(`${apiName}_OrderBy`);
9350
- for (const field of values$2(objectInfo.fields)) {
9351
- if (!fieldsStaticallyAdded.includes(field.apiName)) {
9352
- fields += `${field.apiName}: ${dataTypeToType(field.dataType, field.apiName)}\n`;
9353
- }
9354
- //handles parent relationship
9355
- if (field.relationshipName === null) {
9356
- continue;
9476
+ const { apiName, childRelationships, fields: fieldsRepresentation } = objectInfo;
9477
+ typedScalars.add(`${apiName}_Filter`);
9478
+ typedScalars.add(`${apiName}_OrderBy`);
9479
+ const { fields, polymorphicFieldTypeNames } = makeRecordField(values$2(fieldsRepresentation), objectInfoMap, parentRelationshipFields, 'Missing');
9480
+ // handles child relationship
9481
+ const { spanningRecordConnections, typedScalars: spanningConnectionTypedScalars } = makeSpanningRecordConnections(schema, childRelationships, objectInfoMap, parentRelationshipFields);
9482
+ typedScalars = new Set([...typedScalars, ...spanningConnectionTypedScalars]);
9483
+ const recordQueries = `${apiName}(first: Int, where: ${apiName}_Filter, orderBy: ${apiName}_OrderBy, scope: SupportedScopes): ${apiName}Connection\n`;
9484
+ const isServiceAppointment = apiName === 'ServiceAppointment';
9485
+ const recordConnections = /* GraphQL */ `
9486
+ ${isServiceAppointment ? `scalar ${apiName.toUpperCase()}_SCOPE` : ''}
9487
+
9488
+ type ${apiName} implements Record {
9489
+ ApiName: String!
9490
+ DisplayValue: String
9491
+ LastModifiedById: IDValue
9492
+ LastModifiedDate: DateTimeValue
9493
+ RecordTypeId(fallback: Boolean): IDValue
9494
+ SystemModstamp: DateTimeValue
9495
+ WeakEtag: Long!
9496
+ _drafts: JSON
9497
+ ${fields}
9498
+ ${spanningRecordConnections}
9357
9499
  }
9358
- // For spanning parent relationships with no union types
9359
- if (field.referenceToInfos.length === 1) {
9360
- const [relation] = field.referenceToInfos;
9361
- // Only add the relationship if there is relevant objectinfos for it,
9362
- // otherwise we'd be defining types we cannot satisfy and aren't referenced in
9363
- // the query.
9364
- if (objectInfos[relation.apiName] !== undefined) {
9365
- parentRelationshipFields.add(field.relationshipName);
9366
- fields += `${field.relationshipName}: ${relation.apiName}\n`;
9367
- }
9368
- // For polymorphic field, its type is 'Record' inteface. The concrete entity type name is saved for field resolving of next phase
9369
- }
9370
- else if (field.referenceToInfos.length > 1) {
9371
- parentRelationshipFields.add(field.relationshipName);
9372
- fields += `${field.relationshipName}: Record\n`;
9373
- for (const relation of field.referenceToInfos) {
9374
- if (objectInfos[relation.apiName] !== undefined) {
9375
- polymorphicFieldTypeNames.add(relation.apiName);
9376
- }
9377
- }
9500
+
9501
+ type ${apiName}Connection {
9502
+ edges: [${apiName}Edge]
9503
+ pageInfo: PageInfo!
9504
+ totalCount: Int!
9378
9505
  }
9506
+
9507
+ type ${apiName}Edge {
9508
+ node: ${apiName}
9509
+ cursor: String!
9510
+ }
9511
+
9512
+ `;
9513
+ return { recordQueries, recordConnections, typedScalars, polymorphicFieldTypeNames };
9514
+ }
9515
+ /**
9516
+ * Takes the current schema and will extend missing fields to the record.
9517
+ * Assume all scalar fields have already been added, but will extend spanning fields
9518
+ *
9519
+ * extend type Account {
9520
+ * ...spanning parent records
9521
+ * User: User
9522
+ * ...spanning children queries
9523
+ * Users(predicates): UserConnection
9524
+ * }
9525
+ *
9526
+ * @param schema
9527
+ * @param type
9528
+ * @param objectInfo
9529
+ * @param objectInfoMap
9530
+ * @returns
9531
+ */
9532
+ function extendExistingRecordType(schema, type, objectInfo, objectInfoMap) {
9533
+ // use a set to not allow duplicate scalars causing error(s)
9534
+ let typedScalars = new Set();
9535
+ let parentRelationshipFields = new Set();
9536
+ const existingFields = keys$4(type.getFields());
9537
+ const missingFields = values$2(objectInfo.fields).filter((field) => existingFields.includes(field.apiName) === false);
9538
+ const { fields, polymorphicFieldTypeNames } = makeRecordField(missingFields, objectInfoMap, parentRelationshipFields, 'Cached');
9539
+ const { apiName, childRelationships } = objectInfo;
9540
+ // handles child relationship
9541
+ const { spanningRecordConnections, typedScalars: spanningConnectionTypedScalars } = makeSpanningRecordConnections(schema, childRelationships, objectInfoMap, parentRelationshipFields, existingFields);
9542
+ typedScalars = new Set([...typedScalars, ...spanningConnectionTypedScalars]);
9543
+ const hasExtensions = fields.length > 0 || spanningRecordConnections.length > 0;
9544
+ const recordExtension = hasExtensions
9545
+ ? `
9546
+ extend type ${apiName} {
9547
+ ${fields}
9548
+ ${spanningRecordConnections}
9549
+ }\n`
9550
+ : '';
9551
+ return { recordExtension, typedScalars, polymorphicFieldTypeNames };
9552
+ }
9553
+ /**
9554
+ * Converts child relationships into spanning record connections to be added to record types
9555
+ *
9556
+ * type Record {
9557
+ * Generates -> AccountConnection(first: Int, where: Account_Filter, etc...): AccountConnection
9558
+ * }
9559
+ *
9560
+ * will also generate typed scalars if they have not been added to the existing schema for the spanning connection
9561
+ * example: Account_Filter or Account_OrderBy scalars needed to be defined as predicate types
9562
+ * @param schema
9563
+ * @param childRelationships
9564
+ * @param objectInfoMap
9565
+ * @param existingParentRelationships
9566
+ * @param existingFields
9567
+ * @returns
9568
+ */
9569
+ function makeSpanningRecordConnections(schema, childRelationships, objectInfoMap, existingParentRelationships, existingFields = []) {
9570
+ let spanningRecordConnections = ``;
9571
+ let typedScalars = new Set();
9572
+ for (const childRelationship of childRelationships) {
9573
+ const { childObjectApiName, relationshipName } = childRelationship;
9574
+ // Only add the relationship if there is relevant objectinfos for it,
9575
+ // otherwise we'd be defining types we cannot satisfy and aren't referenced in
9576
+ // the query.
9577
+ // If one field has both parent relationship and child relationship with the same name, the child relationship is ignored. This is how the server GQL has implemented as date of 08/07/2023
9578
+ if (existingFields.length > 0 && existingFields.includes(relationshipName)) {
9579
+ continue;
9379
9580
  }
9380
- // handles child relationship
9381
- for (const childRelationship of childRelationships) {
9382
- const { childObjectApiName } = childRelationship;
9383
- // Only add the relationship if there is relevant objectinfos for it,
9384
- // otherwise we'd be defining types we cannot satisfy and aren't referenced in
9385
- // the query.
9386
- // If one field has both parent relationship and child relationship with the same name, the child relationship is ignored. This is how the server GQL has implemented as date of 08/07/2023
9387
- if (objectInfos[childObjectApiName] !== undefined &&
9388
- !parentRelationshipFields.has(childRelationship.relationshipName)) {
9389
- fields += `${childRelationship.relationshipName}(first: Int, where: ${childObjectApiName}_Filter, orderBy: ${childObjectApiName}_OrderBy, scope: SupportedScopes): ${childObjectApiName}Connection \n`;
9581
+ if (objectInfoMap[childObjectApiName] !== undefined &&
9582
+ !existingParentRelationships.has(relationshipName)) {
9583
+ spanningRecordConnections += `${relationshipName}(first: Int, where: ${childObjectApiName}_Filter, orderBy: ${childObjectApiName}_OrderBy, scope: SupportedScopes): ${childObjectApiName}Connection \n`;
9584
+ // if the record type has already been extended then these additional scalars have already been added
9585
+ // to add them again would throw an error
9586
+ const filterScalarType = schema.getType(`${childObjectApiName}_Filter`);
9587
+ if (isScalarType(filterScalarType) === false) {
9390
9588
  typedScalars.add(`${childObjectApiName}_Filter`);
9589
+ }
9590
+ const orderByScalarType = schema.getType(`${childObjectApiName}_OrderBy`);
9591
+ if (isScalarType(orderByScalarType) === false) {
9391
9592
  typedScalars.add(`${childObjectApiName}_OrderBy`);
9392
9593
  }
9393
9594
  }
9394
- recordQueries += `${apiName}(first: Int, where: ${apiName}_Filter, orderBy: ${apiName}_OrderBy, scope: SupportedScopes): ${apiName}Connection\n`;
9395
- const isServiceAppointment = apiName === 'ServiceAppointment';
9396
- recordConnections += /* GraphQL */ `
9397
- ${isServiceAppointment ? `scalar ${apiName.toUpperCase()}_SCOPE` : ''}
9398
-
9399
- type ${apiName} implements Record {
9400
- ApiName: String!
9401
- DisplayValue: String
9402
- LastModifiedById: IDValue
9403
- LastModifiedDate: DateTimeValue
9404
- RecordTypeId(fallback: Boolean): IDValue
9405
- SystemModstamp: DateTimeValue
9406
- WeakEtag: Long!
9407
- _drafts: JSON
9408
- ${fields}
9409
- }
9410
-
9411
- type ${apiName}Connection {
9412
- edges: [${apiName}Edge]
9413
- pageInfo: PageInfo!
9414
- totalCount: Int!
9415
- }
9416
-
9417
- type ${apiName}Edge {
9418
- node: ${apiName}
9419
- cursor: String!
9595
+ }
9596
+ return { spanningRecordConnections, typedScalars };
9597
+ }
9598
+ /**
9599
+ * Creates scalar and parent relationship fields for a record type
9600
+ *
9601
+ * type RecordName {
9602
+ * generates scalar -> Id: IDValue
9603
+ * generates relationship -> Account: Record
9604
+ * }
9605
+ *
9606
+ * can be used in a type definition or an extension
9607
+ * @param fieldRepresentations
9608
+ * @param objectInfoMap
9609
+ * @param existingParentRelationships
9610
+ * @param recordTypeInSchema
9611
+ * @returns
9612
+ */
9613
+ function makeRecordField(fieldRepresentations, objectInfoMap, existingParentRelationships, recordTypeInSchema) {
9614
+ const polymorphicFieldTypeNames = new Set();
9615
+ let fields = ``;
9616
+ for (const field of values$2(fieldRepresentations)) {
9617
+ if (!fieldsStaticallyAdded.includes(field.apiName) && recordTypeInSchema === 'Missing') {
9618
+ fields += `${field.apiName}: ${dataTypeToType(field.dataType, field.apiName)}\n`;
9619
+ }
9620
+ //handles parent relationship
9621
+ if (field.relationshipName === null) {
9622
+ continue;
9623
+ }
9624
+ // For spanning parent relationships with no union types
9625
+ if (field.referenceToInfos.length === 1) {
9626
+ const [relation] = field.referenceToInfos;
9627
+ // Only add the relationship if there is relevant objectinfos for it,
9628
+ // otherwise we'd be defining types we cannot satisfy and aren't referenced in
9629
+ // the query.
9630
+ if (objectInfoMap[relation.apiName] !== undefined) {
9631
+ existingParentRelationships.add(field.relationshipName);
9632
+ fields += `${field.relationshipName}: ${relation.apiName}\n`;
9633
+ }
9634
+ // For polymorphic field, its type is 'Record' inteface. The concrete entity type name is saved for field resolving of next phase
9635
+ }
9636
+ else if (field.referenceToInfos.length > 1) {
9637
+ existingParentRelationships.add(field.relationshipName);
9638
+ fields += `${field.relationshipName}: Record\n`;
9639
+ for (const relation of field.referenceToInfos) {
9640
+ if (objectInfoMap[relation.apiName] !== undefined) {
9641
+ polymorphicFieldTypeNames.add(relation.apiName);
9642
+ }
9643
+ }
9420
9644
  }
9421
-
9422
- `;
9423
9645
  }
9424
- const scalars = [...typedScalars].reduce((accu, typed) => {
9425
- return accu + `scalar ${typed}\n`;
9426
- }, ``);
9427
- recordConnections += scalars;
9428
- const polyFieldTypeNameArr = [];
9429
- polymorphicFieldTypeNames.forEach((fieldType) => polyFieldTypeNameArr.push(fieldType));
9430
- return { recordQueries, recordConnections, polyFieldTypeNameArr };
9646
+ return { fields, polymorphicFieldTypeNames };
9431
9647
  }
9648
+ /**
9649
+ * converts the ObjectInfoRepresentation data type into a defined schema scalar type
9650
+ * @param objectInfoDataType
9651
+ * @param apiName
9652
+ * @returns
9653
+ */
9432
9654
  function dataTypeToType(objectInfoDataType, apiName) {
9433
9655
  if (apiName && apiName === 'Id') {
9434
9656
  return `ID!`;
@@ -9470,13 +9692,8 @@ function dataTypeToType(objectInfoDataType, apiName) {
9470
9692
  return 'String';
9471
9693
  }
9472
9694
  }
9473
- function createSchema(objectInfos) {
9474
- const { typeDefs: typeDefinitions, polyFieldTypeNames } = generateTypeDefinitions(objectInfos);
9475
- const schema = buildSchema(typeDefinitions);
9476
- return addResolversToSchema(schema, polyFieldTypeNames);
9477
- }
9478
9695
 
9479
- async function evaluate(config, observers, settings, objectInfos, store, snapshot, draftFunctions) {
9696
+ async function evaluate(config, observers, settings, objectInfos, store, snapshot, cache, draftFunctions) {
9480
9697
  const eventEmitter = createCustomAdapterEventEmitter(GRAPHQL_EVAL_NAMESPACE, observers);
9481
9698
  // this is only wrapped in a try to execute the event after the result was returned
9482
9699
  try {
@@ -9517,7 +9734,7 @@ async function evaluate(config, observers, settings, objectInfos, store, snapsho
9517
9734
  const contextValue = createContext(store, objectInfos, eventEmitter, settings, snapshot, draftFunctions);
9518
9735
  // We're building this from scratch from each request. If this becomes a
9519
9736
  // hotspot we can pull it up and memoize it later
9520
- const schema = createSchema(objectInfos);
9737
+ const schema = createSchemaWithCache(objectInfos, cache);
9521
9738
  eventEmitter({ type: 'graphql-schema-created' });
9522
9739
  // execute document against schema/context
9523
9740
  let result = (await execute({
@@ -13012,6 +13229,8 @@ const replaceDraftIdsInVariables = (variables, draftFunctions, unmappedDraftIDs)
13012
13229
  }, {});
13013
13230
  return newVariables;
13014
13231
  };
13232
+ // create the runtime cache for the graphql schema when the factory creates the adapter
13233
+ const graphqlSchemaCache = new CachedGraphQLSchema();
13015
13234
  function draftAwareGraphQLAdapterFactory(userId, objectInfoService, store, luvio, isDraftId) {
13016
13235
  const getCanonicalId = (id) => {
13017
13236
  var _a;
@@ -13085,7 +13304,7 @@ function draftAwareGraphQLAdapterFactory(userId, objectInfoService, store, luvio
13085
13304
  ...config,
13086
13305
  //need to create another copy of the ast for future writes
13087
13306
  query: parse$3(stringify$3(injectedAST)),
13088
- }, observers, { userId }, objectInfoNeeded, store, nonEvaluatedSnapshot));
13307
+ }, observers, { userId }, objectInfoNeeded, store, nonEvaluatedSnapshot, graphqlSchemaCache));
13089
13308
  }
13090
13309
  catch (throwable) {
13091
13310
  const error = throwable;
@@ -13114,7 +13333,7 @@ function draftAwareGraphQLAdapterFactory(userId, objectInfoService, store, luvio
13114
13333
  let { result: rebuildResult, seenRecordIds } = await evaluate({
13115
13334
  ...config,
13116
13335
  query: injectedAST,
13117
- }, observers, { userId }, objectInfoNeeded, store, originalSnapshot, draftFunctions);
13336
+ }, observers, { userId }, objectInfoNeeded, store, originalSnapshot, graphqlSchemaCache, draftFunctions);
13118
13337
  if (!rebuildResult.errors) {
13119
13338
  rebuildResult = removeSyntheticFields(rebuildResult, config.query);
13120
13339
  }
@@ -17288,4 +17507,4 @@ register({
17288
17507
  });
17289
17508
 
17290
17509
  export { getRuntime, registerReportObserver, reportGraphqlQueryParseError };
17291
- // version: 1.247.0-4fe38c091
17510
+ // version: 1.248.0-1f7f01112