@osdk/client 2.2.0-beta.1 → 2.2.0-beta.10
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/CHANGELOG.md +144 -0
- package/build/browser/Client.js +1 -1
- package/build/browser/Client.js.map +1 -1
- package/build/browser/MinimalClientContext.js.map +1 -1
- package/build/browser/actions/ActionValidationError.js +1 -1
- package/build/browser/actions/ActionValidationError.js.map +1 -1
- package/build/browser/actions/actions.test.js +164 -87
- package/build/browser/actions/actions.test.js.map +1 -1
- package/build/browser/actions/applyAction.js +21 -15
- package/build/browser/actions/applyAction.js.map +1 -1
- package/build/browser/createClient.js +19 -8
- package/build/browser/createClient.js.map +1 -1
- package/build/browser/createClient.test.js +14 -6
- package/build/browser/createClient.test.js.map +1 -1
- package/build/browser/createMinimalClient.js +2 -2
- package/build/browser/createMinimalClient.js.map +1 -1
- package/build/browser/createMinimalClientHelper.js +25 -0
- package/build/browser/createMinimalClientHelper.js.map +1 -0
- package/build/browser/derivedProperties/createWithPropertiesObjectSet.test.js +2 -2
- package/build/browser/derivedProperties/createWithPropertiesObjectSet.test.js.map +1 -1
- package/build/browser/fetchMetadata.test.js +11 -9
- package/build/browser/fetchMetadata.test.js.map +1 -1
- package/build/browser/index.js +1 -0
- package/build/browser/index.js.map +1 -1
- package/build/browser/intellisense.test.js +5 -1
- package/build/browser/intellisense.test.js.map +1 -1
- package/build/browser/internal/conversions/modernToLegacyGroupByClause.js +7 -0
- package/build/browser/internal/conversions/modernToLegacyGroupByClause.js.map +1 -1
- package/build/browser/internal/conversions/modernToLegacyWhereClause.js +1 -1
- package/build/browser/internal/conversions/modernToLegacyWhereClause.js.map +1 -1
- package/build/browser/logger/BaseLogger.js +53 -0
- package/build/browser/logger/BaseLogger.js.map +1 -0
- package/build/{esm → browser/logger}/Logger.js.map +1 -1
- package/build/browser/logger/MinimalLogger.js +41 -0
- package/build/browser/logger/MinimalLogger.js.map +1 -0
- package/build/browser/object/AttachmentUpload.js +3 -0
- package/build/browser/object/AttachmentUpload.js.map +1 -1
- package/build/browser/object/SimpleOsdkProperties.js +2 -0
- package/build/browser/object/SimpleOsdkProperties.js.map +1 -0
- package/build/browser/object/aggregate.test.js +12 -2
- package/build/browser/object/aggregate.test.js.map +1 -1
- package/build/browser/object/attachment.test.js +20 -7
- package/build/browser/object/attachment.test.js.map +1 -1
- package/build/browser/object/convertWireToOsdkObjects/BaseHolder.js +2 -0
- package/build/browser/object/convertWireToOsdkObjects/BaseHolder.js.map +1 -0
- package/build/browser/object/convertWireToOsdkObjects/InterfaceHolder.js.map +1 -1
- package/build/browser/object/convertWireToOsdkObjects/ObjectHolder.js.map +1 -1
- package/build/browser/object/convertWireToOsdkObjects/createOsdkInterface.js +25 -0
- package/build/browser/object/convertWireToOsdkObjects/createOsdkInterface.js.map +1 -1
- package/build/browser/object/convertWireToOsdkObjects/createOsdkObject.js +10 -3
- package/build/browser/object/convertWireToOsdkObjects/createOsdkObject.js.map +1 -1
- package/build/browser/object/convertWireToOsdkObjects/getDollarAs.js.map +1 -1
- package/build/browser/object/convertWireToOsdkObjects/getDollarLink.js.map +1 -1
- package/build/browser/object/convertWireToOsdkObjects.js +13 -4
- package/build/browser/object/convertWireToOsdkObjects.js.map +1 -1
- package/build/browser/object/convertWireToOsdkObjects.test.js +17 -11
- package/build/browser/object/convertWireToOsdkObjects.test.js.map +1 -1
- package/build/{esm/observable/internal/ChangedObjects.js → browser/object/createObjectSpecifierFromPrimaryKey.js} +3 -7
- package/build/browser/object/createObjectSpecifierFromPrimaryKey.js.map +1 -0
- package/build/browser/object/fetchPage.js +13 -1
- package/build/browser/object/fetchPage.js.map +1 -1
- package/build/browser/object/fetchPage.test.js +56 -2
- package/build/browser/object/fetchPage.test.js.map +1 -1
- package/build/browser/object/geotimeseriesreference.test.js +56 -134
- package/build/browser/object/geotimeseriesreference.test.js.map +1 -1
- package/build/browser/object/media.test.js +19 -14
- package/build/browser/object/media.test.js.map +1 -1
- package/build/browser/object/object.test.js +166 -66
- package/build/browser/object/object.test.js.map +1 -1
- package/build/browser/object/timeseries.test.js +119 -85
- package/build/browser/object/timeseries.test.js.map +1 -1
- package/build/browser/objectSet/InterfaceObjectSet.test.js +37 -17
- package/build/browser/objectSet/InterfaceObjectSet.test.js.map +1 -1
- package/build/browser/objectSet/ObjectSet.test.js +117 -109
- package/build/browser/objectSet/ObjectSet.test.js.map +1 -1
- package/build/browser/objectSet/ObjectSetListenerWebsocket.js +18 -14
- package/build/browser/objectSet/ObjectSetListenerWebsocket.js.map +1 -1
- package/build/browser/objectSet/ObjectSetListenerWebsocket.test.js +16 -9
- package/build/browser/objectSet/ObjectSetListenerWebsocket.test.js.map +1 -1
- package/build/browser/objectSet/createObjectSet.js.map +1 -1
- package/build/browser/observable/ListPayload.js.map +1 -1
- package/build/browser/observable/ObjectPayload.js.map +1 -1
- package/build/browser/observable/ObservableClient.js.map +1 -1
- package/build/browser/observable/OptimisticBuilder.js.map +1 -1
- package/build/browser/observable/internal/ActionApplication.js +102 -0
- package/build/browser/observable/internal/ActionApplication.js.map +1 -0
- package/build/browser/observable/internal/BulkObjectLoader.js +93 -0
- package/build/browser/observable/internal/BulkObjectLoader.js.map +1 -0
- package/build/browser/observable/internal/BulkObjectLoader.test.js +112 -0
- package/build/browser/observable/internal/BulkObjectLoader.test.js.map +1 -0
- package/build/browser/observable/internal/CacheKey.js +38 -1
- package/build/browser/observable/internal/CacheKey.js.map +1 -1
- package/build/browser/observable/internal/CacheKeys.js +4 -4
- package/build/browser/observable/internal/CacheKeys.js.map +1 -1
- package/build/browser/observable/internal/Changes.js +58 -0
- package/build/browser/observable/internal/Changes.js.map +1 -0
- package/build/browser/observable/internal/Layer.js +6 -3
- package/build/browser/observable/internal/Layer.js.map +1 -1
- package/build/browser/observable/internal/ListQuery.js +495 -129
- package/build/browser/observable/internal/ListQuery.js.map +1 -1
- package/build/browser/observable/internal/ObjectQuery.js +40 -14
- package/build/browser/observable/internal/ObjectQuery.js.map +1 -1
- package/build/browser/observable/internal/ObservableClientImpl.js +4 -12
- package/build/browser/observable/internal/ObservableClientImpl.js.map +1 -1
- package/build/browser/observable/internal/OptimisticJob.js +30 -29
- package/build/browser/observable/internal/OptimisticJob.js.map +1 -1
- package/build/browser/observable/internal/OrderByCanonicalizer.js +73 -0
- package/build/browser/observable/internal/OrderByCanonicalizer.js.map +1 -0
- package/build/browser/observable/internal/OrderByCanonicalizer.test.js +78 -0
- package/build/browser/observable/internal/OrderByCanonicalizer.test.js.map +1 -0
- package/build/browser/observable/internal/Query.js +79 -6
- package/build/browser/observable/internal/Query.js.map +1 -1
- package/build/browser/observable/internal/RefCounts.js +7 -2
- package/build/browser/observable/internal/RefCounts.js.map +1 -1
- package/build/browser/observable/internal/SimpleWhereClause.js +2 -0
- package/build/browser/observable/internal/SimpleWhereClause.js.map +1 -0
- package/build/browser/observable/internal/Store.js +138 -188
- package/build/browser/observable/internal/Store.js.map +1 -1
- package/build/browser/observable/internal/Store.test.js +664 -255
- package/build/browser/observable/internal/Store.test.js.map +1 -1
- package/build/browser/observable/internal/WhereClauseCanonicalizer.js +11 -3
- package/build/browser/observable/internal/WhereClauseCanonicalizer.js.map +1 -1
- package/build/browser/observable/internal/objectMatchesWhereClause.js +0 -4
- package/build/browser/observable/internal/objectMatchesWhereClause.js.map +1 -1
- package/build/browser/observable/internal/objectMatchesWhereClause.test.js.map +1 -1
- package/build/browser/observable/internal/testUtils.js +222 -19
- package/build/browser/observable/internal/testUtils.js.map +1 -1
- package/build/browser/ontology/StandardOntologyProvider.test.js +17 -16
- package/build/browser/ontology/StandardOntologyProvider.test.js.map +1 -1
- package/build/browser/public/unstable-do-not-use.js.map +1 -1
- package/build/browser/queries/applyQuery.js +33 -1
- package/build/browser/queries/applyQuery.js.map +1 -1
- package/build/browser/queries/queries.test.js +36 -13
- package/build/browser/queries/queries.test.js.map +1 -1
- package/build/browser/tsserver.js.map +1 -1
- package/build/browser/util/UserAgent.js +1 -1
- package/build/browser/util/UserAgent.js.map +1 -1
- package/build/browser/util/toDataValue.js +10 -2
- package/build/browser/util/toDataValue.js.map +1 -1
- package/build/browser/util/toDataValue.test.js +37 -16
- package/build/browser/util/toDataValue.test.js.map +1 -1
- package/build/browser/util/toDataValueQueries.js +27 -2
- package/build/browser/util/toDataValueQueries.js.map +1 -1
- package/build/cjs/{Client-C8K3E1vH.d.cts → Client-DBTcM9gB.d.cts} +1 -1
- package/build/cjs/{chunk-FEUFIE6T.cjs → chunk-EY52J5Z4.cjs} +25 -15
- package/build/cjs/chunk-EY52J5Z4.cjs.map +1 -0
- package/build/cjs/{chunk-ACX536BS.cjs → chunk-MCQVHD2F.cjs} +40 -29
- package/build/cjs/chunk-MCQVHD2F.cjs.map +1 -0
- package/build/cjs/chunk-T4NIFYZS.cjs +14 -0
- package/build/cjs/chunk-T4NIFYZS.cjs.map +1 -0
- package/build/cjs/{graphql-JJX5MZPQ.cjs → graphql-RGM5SRWV.cjs} +43 -2
- package/build/cjs/graphql-RGM5SRWV.cjs.map +1 -0
- package/build/cjs/index.cjs +265 -94
- package/build/cjs/index.cjs.map +1 -1
- package/build/cjs/index.d.cts +6 -4
- package/build/cjs/public/internal.cjs +6 -6
- package/build/cjs/public/internal.d.cts +1 -1
- package/build/cjs/public/unstable-do-not-use.cjs +1087 -470
- package/build/cjs/public/unstable-do-not-use.cjs.map +1 -1
- package/build/cjs/public/unstable-do-not-use.d.cts +37 -27
- package/build/esm/Client.js +1 -1
- package/build/esm/Client.js.map +1 -1
- package/build/esm/MinimalClientContext.js.map +1 -1
- package/build/esm/actions/ActionValidationError.js +1 -1
- package/build/esm/actions/ActionValidationError.js.map +1 -1
- package/build/esm/actions/actions.test.js +164 -87
- package/build/esm/actions/actions.test.js.map +1 -1
- package/build/esm/actions/applyAction.js +21 -15
- package/build/esm/actions/applyAction.js.map +1 -1
- package/build/esm/createClient.js +19 -8
- package/build/esm/createClient.js.map +1 -1
- package/build/esm/createClient.test.js +14 -6
- package/build/esm/createClient.test.js.map +1 -1
- package/build/esm/createMinimalClient.js +2 -2
- package/build/esm/createMinimalClient.js.map +1 -1
- package/build/esm/createMinimalClientHelper.js +25 -0
- package/build/esm/createMinimalClientHelper.js.map +1 -0
- package/build/esm/derivedProperties/createWithPropertiesObjectSet.test.js +2 -2
- package/build/esm/derivedProperties/createWithPropertiesObjectSet.test.js.map +1 -1
- package/build/esm/fetchMetadata.test.js +11 -9
- package/build/esm/fetchMetadata.test.js.map +1 -1
- package/build/esm/index.js +1 -0
- package/build/esm/index.js.map +1 -1
- package/build/esm/intellisense.test.js +5 -1
- package/build/esm/intellisense.test.js.map +1 -1
- package/build/esm/internal/conversions/modernToLegacyGroupByClause.js +7 -0
- package/build/esm/internal/conversions/modernToLegacyGroupByClause.js.map +1 -1
- package/build/esm/internal/conversions/modernToLegacyWhereClause.js +1 -1
- package/build/esm/internal/conversions/modernToLegacyWhereClause.js.map +1 -1
- package/build/esm/logger/BaseLogger.js +53 -0
- package/build/esm/logger/BaseLogger.js.map +1 -0
- package/build/{browser → esm/logger}/Logger.js.map +1 -1
- package/build/esm/logger/MinimalLogger.js +41 -0
- package/build/esm/logger/MinimalLogger.js.map +1 -0
- package/build/esm/object/AttachmentUpload.js +3 -0
- package/build/esm/object/AttachmentUpload.js.map +1 -1
- package/build/esm/object/SimpleOsdkProperties.js +2 -0
- package/build/esm/object/SimpleOsdkProperties.js.map +1 -0
- package/build/esm/object/aggregate.test.js +12 -2
- package/build/esm/object/aggregate.test.js.map +1 -1
- package/build/esm/object/attachment.test.js +20 -7
- package/build/esm/object/attachment.test.js.map +1 -1
- package/build/esm/object/convertWireToOsdkObjects/BaseHolder.js +2 -0
- package/build/esm/object/convertWireToOsdkObjects/BaseHolder.js.map +1 -0
- package/build/esm/object/convertWireToOsdkObjects/InterfaceHolder.js.map +1 -1
- package/build/esm/object/convertWireToOsdkObjects/ObjectHolder.js.map +1 -1
- package/build/esm/object/convertWireToOsdkObjects/createOsdkInterface.js +25 -0
- package/build/esm/object/convertWireToOsdkObjects/createOsdkInterface.js.map +1 -1
- package/build/esm/object/convertWireToOsdkObjects/createOsdkObject.js +10 -3
- package/build/esm/object/convertWireToOsdkObjects/createOsdkObject.js.map +1 -1
- package/build/esm/object/convertWireToOsdkObjects/getDollarAs.js.map +1 -1
- package/build/esm/object/convertWireToOsdkObjects/getDollarLink.js.map +1 -1
- package/build/esm/object/convertWireToOsdkObjects.js +13 -4
- package/build/esm/object/convertWireToOsdkObjects.js.map +1 -1
- package/build/esm/object/convertWireToOsdkObjects.test.js +17 -11
- package/build/esm/object/convertWireToOsdkObjects.test.js.map +1 -1
- package/build/{browser/observable/internal/ChangedObjects.js → esm/object/createObjectSpecifierFromPrimaryKey.js} +3 -7
- package/build/esm/object/createObjectSpecifierFromPrimaryKey.js.map +1 -0
- package/build/esm/object/fetchPage.js +13 -1
- package/build/esm/object/fetchPage.js.map +1 -1
- package/build/esm/object/fetchPage.test.js +56 -2
- package/build/esm/object/fetchPage.test.js.map +1 -1
- package/build/esm/object/geotimeseriesreference.test.js +56 -134
- package/build/esm/object/geotimeseriesreference.test.js.map +1 -1
- package/build/esm/object/media.test.js +19 -14
- package/build/esm/object/media.test.js.map +1 -1
- package/build/esm/object/object.test.js +166 -66
- package/build/esm/object/object.test.js.map +1 -1
- package/build/esm/object/timeseries.test.js +119 -85
- package/build/esm/object/timeseries.test.js.map +1 -1
- package/build/esm/objectSet/InterfaceObjectSet.test.js +37 -17
- package/build/esm/objectSet/InterfaceObjectSet.test.js.map +1 -1
- package/build/esm/objectSet/ObjectSet.test.js +117 -109
- package/build/esm/objectSet/ObjectSet.test.js.map +1 -1
- package/build/esm/objectSet/ObjectSetListenerWebsocket.js +18 -14
- package/build/esm/objectSet/ObjectSetListenerWebsocket.js.map +1 -1
- package/build/esm/objectSet/ObjectSetListenerWebsocket.test.js +16 -9
- package/build/esm/objectSet/ObjectSetListenerWebsocket.test.js.map +1 -1
- package/build/esm/objectSet/createObjectSet.js.map +1 -1
- package/build/esm/observable/ListPayload.js.map +1 -1
- package/build/esm/observable/ObjectPayload.js.map +1 -1
- package/build/esm/observable/ObservableClient.js.map +1 -1
- package/build/esm/observable/OptimisticBuilder.js.map +1 -1
- package/build/esm/observable/internal/ActionApplication.js +102 -0
- package/build/esm/observable/internal/ActionApplication.js.map +1 -0
- package/build/esm/observable/internal/BulkObjectLoader.js +93 -0
- package/build/esm/observable/internal/BulkObjectLoader.js.map +1 -0
- package/build/esm/observable/internal/BulkObjectLoader.test.js +112 -0
- package/build/esm/observable/internal/BulkObjectLoader.test.js.map +1 -0
- package/build/esm/observable/internal/CacheKey.js +38 -1
- package/build/esm/observable/internal/CacheKey.js.map +1 -1
- package/build/esm/observable/internal/CacheKeys.js +4 -4
- package/build/esm/observable/internal/CacheKeys.js.map +1 -1
- package/build/esm/observable/internal/Changes.js +58 -0
- package/build/esm/observable/internal/Changes.js.map +1 -0
- package/build/esm/observable/internal/Layer.js +6 -3
- package/build/esm/observable/internal/Layer.js.map +1 -1
- package/build/esm/observable/internal/ListQuery.js +495 -129
- package/build/esm/observable/internal/ListQuery.js.map +1 -1
- package/build/esm/observable/internal/ObjectQuery.js +40 -14
- package/build/esm/observable/internal/ObjectQuery.js.map +1 -1
- package/build/esm/observable/internal/ObservableClientImpl.js +4 -12
- package/build/esm/observable/internal/ObservableClientImpl.js.map +1 -1
- package/build/esm/observable/internal/OptimisticJob.js +30 -29
- package/build/esm/observable/internal/OptimisticJob.js.map +1 -1
- package/build/esm/observable/internal/OrderByCanonicalizer.js +73 -0
- package/build/esm/observable/internal/OrderByCanonicalizer.js.map +1 -0
- package/build/esm/observable/internal/OrderByCanonicalizer.test.js +78 -0
- package/build/esm/observable/internal/OrderByCanonicalizer.test.js.map +1 -0
- package/build/esm/observable/internal/Query.js +79 -6
- package/build/esm/observable/internal/Query.js.map +1 -1
- package/build/esm/observable/internal/RefCounts.js +7 -2
- package/build/esm/observable/internal/RefCounts.js.map +1 -1
- package/build/esm/observable/internal/SimpleWhereClause.js +2 -0
- package/build/esm/observable/internal/SimpleWhereClause.js.map +1 -0
- package/build/esm/observable/internal/Store.js +138 -188
- package/build/esm/observable/internal/Store.js.map +1 -1
- package/build/esm/observable/internal/Store.test.js +664 -255
- package/build/esm/observable/internal/Store.test.js.map +1 -1
- package/build/esm/observable/internal/WhereClauseCanonicalizer.js +11 -3
- package/build/esm/observable/internal/WhereClauseCanonicalizer.js.map +1 -1
- package/build/esm/observable/internal/objectMatchesWhereClause.js +0 -4
- package/build/esm/observable/internal/objectMatchesWhereClause.js.map +1 -1
- package/build/esm/observable/internal/objectMatchesWhereClause.test.js.map +1 -1
- package/build/esm/observable/internal/testUtils.js +222 -19
- package/build/esm/observable/internal/testUtils.js.map +1 -1
- package/build/esm/ontology/StandardOntologyProvider.test.js +17 -16
- package/build/esm/ontology/StandardOntologyProvider.test.js.map +1 -1
- package/build/esm/public/unstable-do-not-use.js.map +1 -1
- package/build/esm/queries/applyQuery.js +33 -1
- package/build/esm/queries/applyQuery.js.map +1 -1
- package/build/esm/queries/queries.test.js +36 -13
- package/build/esm/queries/queries.test.js.map +1 -1
- package/build/esm/tsserver.js.map +1 -1
- package/build/esm/util/UserAgent.js +1 -1
- package/build/esm/util/UserAgent.js.map +1 -1
- package/build/esm/util/toDataValue.js +10 -2
- package/build/esm/util/toDataValue.js.map +1 -1
- package/build/esm/util/toDataValue.test.js +37 -16
- package/build/esm/util/toDataValue.test.js.map +1 -1
- package/build/esm/util/toDataValueQueries.js +27 -2
- package/build/esm/util/toDataValueQueries.js.map +1 -1
- package/build/types/Client.d.ts +2 -2
- package/build/types/Client.d.ts.map +1 -1
- package/build/types/MinimalClientContext.d.ts +1 -1
- package/build/types/MinimalClientContext.d.ts.map +1 -1
- package/build/types/actions/applyAction.d.ts.map +1 -1
- package/build/types/createClient.d.ts +1 -1
- package/build/types/createClient.d.ts.map +1 -1
- package/build/types/createClient.test.d.ts +2 -1
- package/build/types/createClient.test.d.ts.map +1 -1
- package/build/types/createMinimalClientHelper.d.ts +1 -0
- package/build/types/createMinimalClientHelper.d.ts.map +1 -0
- package/build/types/index.d.ts +3 -2
- package/build/types/index.d.ts.map +1 -1
- package/build/types/logger/BaseLogger.d.ts +31 -0
- package/build/types/logger/BaseLogger.d.ts.map +1 -0
- package/build/types/{Logger.d.ts → logger/Logger.d.ts} +1 -2
- package/build/types/logger/Logger.d.ts.map +1 -0
- package/build/types/logger/MinimalLogger.d.ts +8 -0
- package/build/types/logger/MinimalLogger.d.ts.map +1 -0
- package/build/types/object/AttachmentUpload.d.ts +3 -0
- package/build/types/object/AttachmentUpload.d.ts.map +1 -1
- package/build/types/object/SimpleOsdkProperties.d.ts +1 -0
- package/build/types/object/SimpleOsdkProperties.d.ts.map +1 -0
- package/build/types/object/convertWireToOsdkObjects/BaseHolder.d.ts +1 -0
- package/build/types/object/convertWireToOsdkObjects/BaseHolder.d.ts.map +1 -0
- package/build/types/object/convertWireToOsdkObjects.d.ts +8 -1
- package/build/types/object/convertWireToOsdkObjects.d.ts.map +1 -1
- package/build/types/object/createObjectSpecifierFromPrimaryKey.d.ts +2 -0
- package/build/types/object/createObjectSpecifierFromPrimaryKey.d.ts.map +1 -0
- package/build/types/object/object.test.d.ts.map +1 -1
- package/build/types/objectSet/ObjectSet.test.d.ts.map +1 -1
- package/build/types/observable/ListPayload.d.ts +5 -9
- package/build/types/observable/ListPayload.d.ts.map +1 -1
- package/build/types/observable/ObjectPayload.d.ts +4 -7
- package/build/types/observable/ObjectPayload.d.ts.map +1 -1
- package/build/types/observable/ObservableClient.d.ts +33 -10
- package/build/types/observable/ObservableClient.d.ts.map +1 -1
- package/build/types/observable/OptimisticBuilder.d.ts +1 -1
- package/build/types/observable/OptimisticBuilder.d.ts.map +1 -1
- package/build/types/observable/internal/ActionApplication.d.ts +9 -0
- package/build/types/observable/internal/ActionApplication.d.ts.map +1 -0
- package/build/types/observable/internal/BulkObjectLoader.d.ts +8 -0
- package/build/types/observable/internal/BulkObjectLoader.d.ts.map +1 -0
- package/build/types/observable/internal/BulkObjectLoader.test.d.ts +1 -0
- package/build/types/observable/internal/BulkObjectLoader.test.d.ts.map +1 -0
- package/build/types/observable/internal/CacheKeys.d.ts +2 -1
- package/build/types/observable/internal/CacheKeys.d.ts.map +1 -1
- package/build/types/observable/internal/Changes.d.ts +15 -0
- package/build/types/observable/internal/Changes.d.ts.map +1 -0
- package/build/types/observable/internal/Layer.d.ts +2 -1
- package/build/types/observable/internal/Layer.d.ts.map +1 -1
- package/build/types/observable/internal/ListQuery.d.ts +69 -23
- package/build/types/observable/internal/ListQuery.d.ts.map +1 -1
- package/build/types/observable/internal/ObjectQuery.d.ts +8 -9
- package/build/types/observable/internal/ObjectQuery.d.ts.map +1 -1
- package/build/types/observable/internal/OptimisticJob.d.ts +2 -2
- package/build/types/observable/internal/OptimisticJob.d.ts.map +1 -1
- package/build/types/observable/internal/OrderByCanonicalizer.d.ts +12 -0
- package/build/types/observable/internal/OrderByCanonicalizer.d.ts.map +1 -0
- package/build/types/observable/internal/OrderByCanonicalizer.test.d.ts +1 -0
- package/build/types/observable/internal/OrderByCanonicalizer.test.d.ts.map +1 -0
- package/build/types/observable/internal/Query.d.ts +45 -9
- package/build/types/observable/internal/Query.d.ts.map +1 -1
- package/build/types/observable/internal/RefCounts.d.ts.map +1 -1
- package/build/types/observable/internal/SimpleWhereClause.d.ts +2 -0
- package/build/types/observable/internal/SimpleWhereClause.d.ts.map +1 -0
- package/build/types/observable/internal/Store.d.ts +33 -29
- package/build/types/observable/internal/Store.d.ts.map +1 -1
- package/build/types/observable/internal/WhereClauseCanonicalizer.d.ts +2 -1
- package/build/types/observable/internal/WhereClauseCanonicalizer.d.ts.map +1 -1
- package/build/types/observable/internal/objectMatchesWhereClause.d.ts +4 -2
- package/build/types/observable/internal/objectMatchesWhereClause.d.ts.map +1 -1
- package/build/types/observable/internal/testUtils.d.ts +49 -9
- package/build/types/observable/internal/testUtils.d.ts.map +1 -1
- package/build/types/public/unstable-do-not-use.d.ts +1 -4
- package/build/types/public/unstable-do-not-use.d.ts.map +1 -1
- package/build/types/queries/applyQuery.d.ts.map +1 -1
- package/build/types/tsserver.d.ts +1 -1
- package/build/types/tsserver.d.ts.map +1 -1
- package/package.json +17 -13
- package/build/browser/observable/internal/ChangedObjects.js.map +0 -1
- package/build/cjs/chunk-ACX536BS.cjs.map +0 -1
- package/build/cjs/chunk-FEUFIE6T.cjs.map +0 -1
- package/build/cjs/graphql-JJX5MZPQ.cjs.map +0 -1
- package/build/esm/observable/internal/ChangedObjects.js.map +0 -1
- package/build/types/Logger.d.ts.map +0 -1
- package/build/types/observable/internal/ChangedObjects.d.ts +0 -7
- package/build/types/observable/internal/ChangedObjects.d.ts.map +0 -1
- /package/build/browser/{Logger.js → logger/Logger.js} +0 -0
- /package/build/esm/{Logger.js → logger/Logger.js} +0 -0
|
@@ -14,14 +14,21 @@
|
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
17
|
+
import { createOffice, Employee, FooInterface, Todo } from "@osdk/client.test.ontology";
|
|
18
|
+
import { wireObjectTypeFullMetadataToSdkObjectMetadata } from "@osdk/generator-converters";
|
|
19
|
+
import { LegacyFauxFoundry, startNodeApiServer, stubData } from "@osdk/shared.test";
|
|
20
|
+
import chalk from "chalk";
|
|
19
21
|
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi, vitest } from "vitest";
|
|
20
22
|
import { createClient } from "../../createClient.js";
|
|
23
|
+
import { createMinimalClient } from "../../createMinimalClient.js";
|
|
24
|
+
import { createObjectSet } from "../../objectSet/createObjectSet.js";
|
|
25
|
+
import { InterfaceDefinitions } from "../../ontology/OntologyProvider.js";
|
|
21
26
|
import { createOptimisticId } from "./OptimisticId.js";
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
27
|
+
import { runOptimisticJob } from "./OptimisticJob.js";
|
|
28
|
+
import { invalidateList, Store } from "./Store.js";
|
|
29
|
+
import { applyCustomMatchers, createClientMockHelper, createDefer, createTestLogger, expectNoMoreCalls, expectSingleListCallAndClear, expectSingleObjectCallAndClear, getObject, mockListSubCallback, mockSingleSubCallback, objectPayloadContaining, updateList, updateObject, waitForCall } from "./testUtils.js";
|
|
24
30
|
const defer = createDefer();
|
|
31
|
+
const logger = createTestLogger({});
|
|
25
32
|
beforeAll(() => {
|
|
26
33
|
vi.setConfig({
|
|
27
34
|
fakeTimers: {
|
|
@@ -38,6 +45,19 @@ const ANY_INIT_ENTRY = {
|
|
|
38
45
|
lastUpdated: 0,
|
|
39
46
|
status: "init"
|
|
40
47
|
};
|
|
48
|
+
|
|
49
|
+
// eslint-disable-next-line @typescript-eslint/no-deprecated
|
|
50
|
+
function fullTaskName(task) {
|
|
51
|
+
return task ? `${fullTaskName(task.suite)} > ${task.name}` : "";
|
|
52
|
+
}
|
|
53
|
+
beforeEach(x => {
|
|
54
|
+
console.log(chalk.bgRed(chalk.white(fullTaskName(x.task))));
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// helper method to make debugging tests easier
|
|
58
|
+
function testStage(s) {
|
|
59
|
+
console.log(chalk.bgYellow(`Test Stage: ${s}`));
|
|
60
|
+
}
|
|
41
61
|
applyCustomMatchers();
|
|
42
62
|
describe(Store, () => {
|
|
43
63
|
describe("with mock server", () => {
|
|
@@ -46,44 +66,49 @@ describe(Store, () => {
|
|
|
46
66
|
let employeesAsServerReturns;
|
|
47
67
|
let mutatedEmployees;
|
|
48
68
|
beforeAll(async () => {
|
|
49
|
-
|
|
50
|
-
|
|
69
|
+
const testSetup = startNodeApiServer(new LegacyFauxFoundry(), createClient, {
|
|
70
|
+
logger
|
|
71
|
+
});
|
|
72
|
+
({
|
|
73
|
+
client
|
|
74
|
+
} = testSetup);
|
|
51
75
|
employeesAsServerReturns = (await client(Employee).fetchPage()).data;
|
|
52
76
|
mutatedEmployees = [employeesAsServerReturns[0], employeesAsServerReturns[1].$clone({
|
|
53
77
|
fullName: "foo"
|
|
54
78
|
}), ...employeesAsServerReturns.slice(2)];
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
79
|
+
return () => {
|
|
80
|
+
testSetup.apiServer.close();
|
|
81
|
+
};
|
|
58
82
|
});
|
|
59
83
|
beforeEach(() => {
|
|
60
84
|
cache = new Store(client);
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
85
|
+
return () => {
|
|
86
|
+
cache = undefined;
|
|
87
|
+
};
|
|
64
88
|
});
|
|
65
89
|
it("basic single object works", async () => {
|
|
66
90
|
const emp = employeesAsServerReturns[0];
|
|
91
|
+
const cacheKey = cache.getCacheKey("object", "Employee", emp.$primaryKey);
|
|
67
92
|
|
|
68
93
|
// starts empty
|
|
69
|
-
expect(cache.
|
|
70
|
-
const result =
|
|
94
|
+
expect(cache.getValue(cacheKey)?.value).toBeUndefined();
|
|
95
|
+
const result = updateObject(cache, emp);
|
|
71
96
|
expect(emp).toBe(result);
|
|
72
97
|
|
|
73
98
|
// getting the object now matches the result
|
|
74
|
-
expect(cache.
|
|
75
|
-
const updatedEmpFromCache =
|
|
99
|
+
expect(cache.getValue(cacheKey)?.value).toEqual(result);
|
|
100
|
+
const updatedEmpFromCache = updateObject(cache, emp.$clone({
|
|
76
101
|
fullName: "new name"
|
|
77
102
|
}));
|
|
78
103
|
expect(updatedEmpFromCache).not.toBe(emp);
|
|
79
104
|
|
|
80
105
|
// getting it again is the updated object
|
|
81
|
-
expect(cache.
|
|
106
|
+
expect(cache.getValue(cacheKey)?.value).toEqual(updatedEmpFromCache);
|
|
82
107
|
});
|
|
83
108
|
describe("optimistic updates", () => {
|
|
84
109
|
it("rolls back objects", async () => {
|
|
85
110
|
const emp = employeesAsServerReturns[0];
|
|
86
|
-
|
|
111
|
+
updateObject(cache, emp); // pre-seed the cache with the "real" value
|
|
87
112
|
|
|
88
113
|
const subFn = mockSingleSubCallback();
|
|
89
114
|
defer(cache.observeObject(Employee, emp.$primaryKey, {
|
|
@@ -92,7 +117,7 @@ describe(Store, () => {
|
|
|
92
117
|
expectSingleObjectCallAndClear(subFn, emp, "loaded");
|
|
93
118
|
const optimisticId = createOptimisticId();
|
|
94
119
|
// update with an optimistic write
|
|
95
|
-
|
|
120
|
+
updateObject(cache, emp.$clone({
|
|
96
121
|
fullName: "new name"
|
|
97
122
|
}), {
|
|
98
123
|
optimisticId
|
|
@@ -106,10 +131,12 @@ describe(Store, () => {
|
|
|
106
131
|
expectSingleObjectCallAndClear(subFn, emp, "loaded");
|
|
107
132
|
});
|
|
108
133
|
it("rolls back to an updated real value", async () => {
|
|
109
|
-
vi.useFakeTimers();
|
|
110
|
-
|
|
111
134
|
// pre-seed the cache with the "real" value
|
|
112
|
-
|
|
135
|
+
updateList(cache, {
|
|
136
|
+
type: Employee,
|
|
137
|
+
where: {},
|
|
138
|
+
orderBy: {}
|
|
139
|
+
}, employeesAsServerReturns);
|
|
113
140
|
const emp = employeesAsServerReturns[0];
|
|
114
141
|
const empSubFn = mockSingleSubCallback();
|
|
115
142
|
defer(cache.observeObject(Employee, emp.$primaryKey, {
|
|
@@ -117,88 +144,90 @@ describe(Store, () => {
|
|
|
117
144
|
}, empSubFn));
|
|
118
145
|
expectSingleObjectCallAndClear(empSubFn, emp, "loaded");
|
|
119
146
|
const listSubFn = mockListSubCallback();
|
|
120
|
-
defer(cache.observeList(
|
|
147
|
+
defer(cache.observeList({
|
|
148
|
+
type: Employee,
|
|
121
149
|
mode: "offline"
|
|
122
150
|
}, listSubFn));
|
|
151
|
+
await waitForCall(listSubFn, 1);
|
|
123
152
|
expectSingleListCallAndClear(listSubFn, employeesAsServerReturns);
|
|
124
153
|
const optimisticEmployee = emp.$clone({
|
|
125
154
|
fullName: "new name"
|
|
126
155
|
});
|
|
127
156
|
const optimisticId = createOptimisticId();
|
|
157
|
+
testStage("optimistic update");
|
|
158
|
+
expect(listSubFn.next).not.toHaveBeenCalled();
|
|
128
159
|
|
|
129
160
|
// update with an optimistic write
|
|
130
|
-
|
|
161
|
+
updateObject(cache, optimisticEmployee, {
|
|
131
162
|
optimisticId
|
|
132
163
|
});
|
|
164
|
+
testStage("after optimistic update");
|
|
133
165
|
|
|
134
166
|
// expect optimistic write
|
|
135
167
|
expectSingleObjectCallAndClear(empSubFn, optimisticEmployee);
|
|
136
168
|
|
|
137
169
|
// expect optimistic write to the list
|
|
138
|
-
|
|
170
|
+
await waitForCall(listSubFn, 1);
|
|
171
|
+
expectSingleListCallAndClear(listSubFn, [optimisticEmployee, ...employeesAsServerReturns.slice(1)], {
|
|
172
|
+
isOptimistic: true,
|
|
173
|
+
status: "loading"
|
|
174
|
+
});
|
|
139
175
|
|
|
140
176
|
// write the real update, via the earlier list definition
|
|
141
177
|
const truthUpdatedEmployee = emp.$clone({
|
|
142
178
|
fullName: "real update"
|
|
143
179
|
});
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
// for the object
|
|
151
|
-
expectSingleListCallAndClear(listSubFn, [optimisticEmployee]);
|
|
180
|
+
testStage("write real update");
|
|
181
|
+
updateList(cache, {
|
|
182
|
+
type: Employee,
|
|
183
|
+
where: {},
|
|
184
|
+
orderBy: {}
|
|
185
|
+
}, [truthUpdatedEmployee]);
|
|
152
186
|
|
|
153
187
|
// remove the optimistic write
|
|
154
188
|
cache.removeLayer(optimisticId);
|
|
155
189
|
|
|
156
190
|
// see the object observation get updated
|
|
157
|
-
expectSingleObjectCallAndClear(empSubFn, truthUpdatedEmployee);
|
|
191
|
+
expectSingleObjectCallAndClear(empSubFn, truthUpdatedEmployee, "loaded");
|
|
158
192
|
|
|
159
193
|
// see the list get updated
|
|
160
|
-
|
|
161
|
-
|
|
194
|
+
await waitForCall(listSubFn, 1);
|
|
195
|
+
expectSingleListCallAndClear(listSubFn, [truthUpdatedEmployee], {
|
|
196
|
+
status: "loaded",
|
|
197
|
+
isOptimistic: false
|
|
198
|
+
});
|
|
162
199
|
});
|
|
163
200
|
it("rolls back to an updated real value via list", async () => {
|
|
164
201
|
const emp = employeesAsServerReturns[0];
|
|
165
|
-
|
|
202
|
+
updateObject(cache, emp); // pre-seed the cache with the "real" value
|
|
166
203
|
|
|
167
204
|
const subFn = mockSingleSubCallback();
|
|
168
205
|
defer(cache.observeObject(Employee, emp.$primaryKey, {
|
|
169
206
|
mode: "offline"
|
|
170
207
|
}, subFn));
|
|
171
|
-
|
|
172
|
-
object: emp,
|
|
173
|
-
status: "loaded"
|
|
174
|
-
}));
|
|
175
|
-
subFn.mockClear();
|
|
208
|
+
expectSingleObjectCallAndClear(subFn, emp, "loaded");
|
|
176
209
|
const optimisticEmployee = emp.$clone({
|
|
177
210
|
fullName: "new name"
|
|
178
211
|
});
|
|
179
212
|
|
|
180
213
|
// update with an optimistic write
|
|
181
214
|
const optimisticId = createOptimisticId();
|
|
182
|
-
|
|
215
|
+
updateObject(cache, optimisticEmployee, {
|
|
183
216
|
optimisticId
|
|
184
217
|
});
|
|
185
|
-
|
|
186
|
-
object: optimisticEmployee
|
|
187
|
-
}));
|
|
188
|
-
subFn.mockClear();
|
|
218
|
+
expectSingleObjectCallAndClear(subFn, optimisticEmployee);
|
|
189
219
|
const truthUpdatedEmployee = emp.$clone({
|
|
190
220
|
fullName: "real update"
|
|
191
221
|
});
|
|
192
|
-
|
|
222
|
+
updateObject(cache, truthUpdatedEmployee);
|
|
193
223
|
|
|
194
224
|
// we shouldn't expect an update because the top layer has a value
|
|
195
|
-
expect(subFn).not.toHaveBeenCalled();
|
|
225
|
+
expect(subFn.next).not.toHaveBeenCalled();
|
|
196
226
|
|
|
197
227
|
// remove the optimistic write
|
|
198
228
|
cache.removeLayer(optimisticId);
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
}));
|
|
229
|
+
expectSingleObjectCallAndClear(subFn, truthUpdatedEmployee);
|
|
230
|
+
expectNoMoreCalls(subFn);
|
|
202
231
|
});
|
|
203
232
|
});
|
|
204
233
|
describe(".invalidateObject", () => {
|
|
@@ -207,29 +236,20 @@ describe(Store, () => {
|
|
|
207
236
|
const staleEmp = emp.$clone({
|
|
208
237
|
fullName: "stale"
|
|
209
238
|
});
|
|
210
|
-
|
|
239
|
+
updateObject(cache, staleEmp);
|
|
211
240
|
const subFn = mockSingleSubCallback();
|
|
212
241
|
defer(cache.observeObject(Employee, emp.$primaryKey, {
|
|
213
242
|
mode: "offline"
|
|
214
243
|
}, subFn));
|
|
215
|
-
|
|
216
|
-
object: staleEmp,
|
|
217
|
-
status: "loaded"
|
|
218
|
-
}));
|
|
219
|
-
subFn.mockClear();
|
|
244
|
+
expectSingleObjectCallAndClear(subFn, staleEmp, "loaded");
|
|
220
245
|
|
|
221
246
|
// invalidate
|
|
222
247
|
void cache.invalidateObject(Employee, staleEmp.$primaryKey);
|
|
223
|
-
await
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
subFn.mockClear();
|
|
229
|
-
await vi.waitFor(() => expect(subFn).toHaveBeenCalled());
|
|
230
|
-
expect(subFn).toHaveBeenCalledExactlyOnceWith(objectPayloadContaining({
|
|
231
|
-
object: emp
|
|
232
|
-
}));
|
|
248
|
+
await waitForCall(subFn);
|
|
249
|
+
expectSingleObjectCallAndClear(subFn, staleEmp, "loading");
|
|
250
|
+
await waitForCall(subFn);
|
|
251
|
+
expectSingleObjectCallAndClear(subFn, emp, "loaded");
|
|
252
|
+
expectNoMoreCalls(subFn);
|
|
233
253
|
});
|
|
234
254
|
});
|
|
235
255
|
describe(".invalidateList", () => {
|
|
@@ -244,39 +264,43 @@ describe(Store, () => {
|
|
|
244
264
|
const staleEmp = emp.$clone({
|
|
245
265
|
fullName: "stale"
|
|
246
266
|
});
|
|
247
|
-
|
|
267
|
+
updateList(cache, {
|
|
268
|
+
type: Employee,
|
|
269
|
+
where: {},
|
|
270
|
+
orderBy: {}
|
|
271
|
+
}, [staleEmp]);
|
|
248
272
|
const subFn = mockSingleSubCallback();
|
|
249
273
|
defer(cache.observeObject(Employee, emp.$primaryKey, {
|
|
250
274
|
mode: "offline"
|
|
251
275
|
}, subFn));
|
|
252
276
|
expectSingleObjectCallAndClear(subFn, staleEmp);
|
|
253
277
|
const subListFn = mockListSubCallback();
|
|
254
|
-
defer(cache.observeList(
|
|
278
|
+
defer(cache.observeList({
|
|
279
|
+
type: Employee,
|
|
255
280
|
mode: "offline"
|
|
256
281
|
}, subListFn));
|
|
257
|
-
await
|
|
258
|
-
|
|
259
|
-
resolvedList: [staleEmp],
|
|
282
|
+
await waitForCall(subListFn, 1);
|
|
283
|
+
expectSingleListCallAndClear(subListFn, [staleEmp], {
|
|
260
284
|
status: "loaded"
|
|
261
|
-
})
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
285
|
+
});
|
|
286
|
+
testStage("invalidate");
|
|
287
|
+
const invalidateListPromise = invalidateList(cache, {
|
|
288
|
+
type: Employee
|
|
289
|
+
});
|
|
290
|
+
testStage("check invalidate");
|
|
291
|
+
await waitForCall(subListFn, 1);
|
|
292
|
+
expectSingleListCallAndClear(subListFn, [staleEmp], {
|
|
267
293
|
status: "loading"
|
|
268
|
-
})
|
|
269
|
-
subListFn
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
object: emp
|
|
279
|
-
}));
|
|
294
|
+
});
|
|
295
|
+
await waitForCall(subListFn, 1);
|
|
296
|
+
expectSingleListCallAndClear(subListFn, employeesAsServerReturns, {
|
|
297
|
+
status: "loaded"
|
|
298
|
+
});
|
|
299
|
+
await waitForCall(subFn, 1);
|
|
300
|
+
expectSingleObjectCallAndClear(subFn, emp, "loaded");
|
|
301
|
+
|
|
302
|
+
// don't leave promises dangling
|
|
303
|
+
await invalidateListPromise;
|
|
280
304
|
});
|
|
281
305
|
});
|
|
282
306
|
describe(".invalidateObjectType", () => {
|
|
@@ -291,47 +315,53 @@ describe(Store, () => {
|
|
|
291
315
|
const staleEmp = emp.$clone({
|
|
292
316
|
fullName: "stale"
|
|
293
317
|
});
|
|
294
|
-
|
|
318
|
+
updateList(cache, {
|
|
319
|
+
type: Employee,
|
|
320
|
+
where: {},
|
|
321
|
+
orderBy: {}
|
|
322
|
+
}, [staleEmp]);
|
|
295
323
|
const subFn = mockSingleSubCallback();
|
|
296
324
|
defer(cache.observeObject(Employee, emp.$primaryKey, {
|
|
297
325
|
mode: "offline"
|
|
298
326
|
}, subFn));
|
|
299
327
|
expectSingleObjectCallAndClear(subFn, staleEmp);
|
|
300
328
|
const subListFn = mockListSubCallback();
|
|
301
|
-
defer(cache.observeList(
|
|
329
|
+
defer(cache.observeList({
|
|
330
|
+
type: Employee,
|
|
331
|
+
where: {},
|
|
332
|
+
orderBy: {},
|
|
302
333
|
mode: "offline"
|
|
303
334
|
}, subListFn));
|
|
304
|
-
await
|
|
305
|
-
|
|
306
|
-
resolvedList: [staleEmp],
|
|
335
|
+
await waitForCall(subListFn, 1);
|
|
336
|
+
expectSingleListCallAndClear(subListFn, [staleEmp], {
|
|
307
337
|
status: "loaded"
|
|
308
|
-
})
|
|
309
|
-
|
|
310
|
-
cache.invalidateObjectType(Employee);
|
|
311
|
-
await
|
|
312
|
-
|
|
313
|
-
resolvedList: [staleEmp],
|
|
338
|
+
});
|
|
339
|
+
testStage("invalidate");
|
|
340
|
+
const pInvalidateComplete = cache.invalidateObjectType(Employee, undefined);
|
|
341
|
+
await waitForCall(subListFn, 1);
|
|
342
|
+
expectSingleListCallAndClear(subListFn, [staleEmp], {
|
|
314
343
|
status: "loading"
|
|
315
|
-
})
|
|
316
|
-
subListFn
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
status: "loaded",
|
|
325
|
-
object: emp
|
|
326
|
-
}));
|
|
344
|
+
});
|
|
345
|
+
await waitForCall(subListFn, 1);
|
|
346
|
+
expectSingleListCallAndClear(subListFn, employeesAsServerReturns);
|
|
347
|
+
await waitForCall(subFn, 1);
|
|
348
|
+
expectSingleObjectCallAndClear(subFn, emp, "loaded");
|
|
349
|
+
|
|
350
|
+
// we don't need this value to control the test but we want to make sure we don't have
|
|
351
|
+
// any unhandled exceptions upon test completion
|
|
352
|
+
await pInvalidateComplete;
|
|
327
353
|
});
|
|
328
354
|
});
|
|
329
355
|
describe(".observeObject (force)", () => {
|
|
330
356
|
const subFn1 = mockSingleSubCallback();
|
|
331
357
|
const subFn2 = mockSingleSubCallback();
|
|
332
358
|
beforeEach(async () => {
|
|
333
|
-
subFn1.mockClear();
|
|
334
|
-
|
|
359
|
+
subFn1.complete.mockClear();
|
|
360
|
+
subFn1.next.mockClear();
|
|
361
|
+
subFn1.error.mockClear();
|
|
362
|
+
subFn2.complete.mockClear();
|
|
363
|
+
subFn2.next.mockClear();
|
|
364
|
+
subFn2.error.mockClear();
|
|
335
365
|
});
|
|
336
366
|
const likeEmployee50030 = expect.objectContaining({
|
|
337
367
|
$primaryKey: 50030,
|
|
@@ -341,42 +371,36 @@ describe(Store, () => {
|
|
|
341
371
|
defer(cache.observeObject(Employee, 50030, {
|
|
342
372
|
mode: "force"
|
|
343
373
|
}, subFn1));
|
|
344
|
-
expect(subFn1).toHaveBeenCalledExactlyOnceWith(objectPayloadContaining({
|
|
374
|
+
expect(subFn1.next).toHaveBeenCalledExactlyOnceWith(objectPayloadContaining({
|
|
345
375
|
status: "loading",
|
|
346
376
|
object: undefined,
|
|
347
377
|
isOptimistic: false
|
|
348
378
|
}));
|
|
349
|
-
subFn1.mockClear();
|
|
350
|
-
await
|
|
351
|
-
expect(subFn1).toHaveBeenCalledExactlyOnceWith(objectPayloadContaining({
|
|
379
|
+
subFn1.next.mockClear();
|
|
380
|
+
await waitForCall(subFn1);
|
|
381
|
+
expect(subFn1.next).toHaveBeenCalledExactlyOnceWith(objectPayloadContaining({
|
|
352
382
|
object: likeEmployee50030,
|
|
353
383
|
isOptimistic: false
|
|
354
384
|
}));
|
|
355
|
-
const firstLoad = subFn1.mock.lastCall?.[0];
|
|
356
|
-
subFn1.mockClear();
|
|
385
|
+
const firstLoad = subFn1.next.mock.lastCall?.[0];
|
|
386
|
+
subFn1.next.mockClear();
|
|
357
387
|
defer(cache.observeObject(Employee, 50030, {
|
|
358
388
|
mode: "force"
|
|
359
389
|
}, subFn2));
|
|
360
|
-
|
|
361
|
-
status: "loading"
|
|
362
|
-
}));
|
|
363
|
-
subFn1.mockClear();
|
|
390
|
+
expectSingleObjectCallAndClear(subFn1, likeEmployee50030, "loading");
|
|
364
391
|
|
|
365
392
|
// should be the earlier results
|
|
366
|
-
|
|
367
|
-
status: "loading"
|
|
368
|
-
}));
|
|
369
|
-
subFn2.mockClear();
|
|
393
|
+
expectSingleObjectCallAndClear(subFn2, likeEmployee50030, "loading");
|
|
370
394
|
|
|
371
395
|
// both will be updated
|
|
372
396
|
for (const s of [subFn1, subFn2]) {
|
|
373
397
|
// wait for the result to come in
|
|
374
|
-
await
|
|
375
|
-
expect(s).toHaveBeenCalledExactlyOnceWith(objectPayloadContaining({
|
|
398
|
+
await waitForCall(s, 1);
|
|
399
|
+
expect(s.next).toHaveBeenCalledExactlyOnceWith(objectPayloadContaining({
|
|
376
400
|
...firstLoad,
|
|
377
401
|
lastUpdated: expect.toBeGreaterThan(firstLoad.lastUpdated)
|
|
378
402
|
}));
|
|
379
|
-
s.mockClear();
|
|
403
|
+
s.next.mockClear();
|
|
380
404
|
}
|
|
381
405
|
});
|
|
382
406
|
});
|
|
@@ -384,152 +408,185 @@ describe(Store, () => {
|
|
|
384
408
|
const subFn = mockSingleSubCallback();
|
|
385
409
|
let sub;
|
|
386
410
|
beforeEach(() => {
|
|
387
|
-
subFn.mockClear();
|
|
411
|
+
subFn.complete.mockClear();
|
|
412
|
+
subFn.next.mockClear();
|
|
413
|
+
subFn.error.mockClear();
|
|
388
414
|
sub = defer(cache.observeObject(Employee, 50030, {
|
|
389
415
|
mode: "offline"
|
|
390
416
|
}, subFn));
|
|
391
|
-
|
|
392
|
-
status: "init",
|
|
393
|
-
object: undefined
|
|
394
|
-
}));
|
|
395
|
-
subFn.mockClear();
|
|
417
|
+
expectSingleObjectCallAndClear(subFn, undefined, "init");
|
|
396
418
|
});
|
|
397
419
|
it("does basic observation and unsubscribe", async () => {
|
|
398
420
|
const emp = employeesAsServerReturns[0];
|
|
399
421
|
|
|
400
422
|
// force an update
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
object: emp
|
|
404
|
-
}));
|
|
405
|
-
subFn.mockClear();
|
|
423
|
+
updateObject(cache, emp);
|
|
424
|
+
expectSingleObjectCallAndClear(subFn, emp);
|
|
406
425
|
|
|
407
426
|
// force again
|
|
408
|
-
|
|
427
|
+
updateObject(cache, emp.$clone({
|
|
409
428
|
fullName: "new name"
|
|
410
429
|
}));
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
fullName: "new name"
|
|
414
|
-
})
|
|
430
|
+
expectSingleObjectCallAndClear(subFn, emp.$clone({
|
|
431
|
+
fullName: "new name"
|
|
415
432
|
}));
|
|
416
|
-
subFn.mockClear();
|
|
417
433
|
sub.unsubscribe();
|
|
418
434
|
|
|
419
435
|
// force again but no subscription update
|
|
420
|
-
|
|
436
|
+
updateObject(cache, emp.$clone({
|
|
421
437
|
fullName: "new name 2"
|
|
422
438
|
}));
|
|
423
|
-
expect(subFn).not.toHaveBeenCalled();
|
|
439
|
+
expect(subFn.next).not.toHaveBeenCalled();
|
|
424
440
|
});
|
|
425
441
|
it("observes with list update", async () => {
|
|
426
442
|
const emp = employeesAsServerReturns[0];
|
|
427
443
|
|
|
428
444
|
// force an update
|
|
429
|
-
|
|
445
|
+
updateObject(cache, emp.$clone({
|
|
430
446
|
fullName: "not the name"
|
|
431
447
|
}));
|
|
432
|
-
expect(subFn).toHaveBeenCalledTimes(1);
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
448
|
+
expect(subFn.next).toHaveBeenCalledTimes(1);
|
|
449
|
+
updateList(cache, {
|
|
450
|
+
type: Employee,
|
|
451
|
+
where: {},
|
|
452
|
+
orderBy: {}
|
|
453
|
+
}, employeesAsServerReturns);
|
|
454
|
+
expect(subFn.next).toHaveBeenCalledTimes(2);
|
|
455
|
+
expect(subFn.next.mock.calls[1][0]).toEqual(objectPayloadContaining({
|
|
436
456
|
object: emp
|
|
437
457
|
}));
|
|
438
458
|
});
|
|
439
459
|
});
|
|
440
460
|
describe(".observeList", () => {
|
|
441
461
|
const listSub1 = mockListSubCallback();
|
|
462
|
+
const ifaceSub = mockListSubCallback();
|
|
442
463
|
beforeEach(() => {
|
|
443
464
|
vi.useFakeTimers({});
|
|
444
|
-
listSub1.mockReset();
|
|
465
|
+
vi.mocked(listSub1.next).mockReset();
|
|
466
|
+
vi.mocked(listSub1.error).mockReset();
|
|
467
|
+
vi.mocked(listSub1.complete).mockReset();
|
|
468
|
+
vi.mocked(ifaceSub.next).mockReset();
|
|
469
|
+
vi.mocked(ifaceSub.error).mockReset();
|
|
470
|
+
vi.mocked(ifaceSub.complete).mockReset();
|
|
445
471
|
});
|
|
446
472
|
afterEach(() => {
|
|
447
473
|
vi.useRealTimers();
|
|
448
474
|
});
|
|
449
475
|
describe("mode=force", () => {
|
|
450
476
|
it("initial load", async () => {
|
|
451
|
-
defer(cache.observeList(
|
|
477
|
+
defer(cache.observeList({
|
|
478
|
+
type: Employee,
|
|
479
|
+
orderBy: {},
|
|
452
480
|
mode: "force"
|
|
453
481
|
}, listSub1));
|
|
482
|
+
defer(cache.observeList({
|
|
483
|
+
type: FooInterface,
|
|
484
|
+
orderBy: {},
|
|
485
|
+
mode: "force"
|
|
486
|
+
}, ifaceSub));
|
|
454
487
|
vitest.runOnlyPendingTimers();
|
|
455
|
-
await
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
})
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
488
|
+
await waitForCall(listSub1);
|
|
489
|
+
await waitForCall(ifaceSub);
|
|
490
|
+
expectSingleListCallAndClear(listSub1, [], {
|
|
491
|
+
status: "loading"
|
|
492
|
+
});
|
|
493
|
+
expectSingleListCallAndClear(ifaceSub, [], {
|
|
494
|
+
status: "loading"
|
|
495
|
+
});
|
|
496
|
+
await waitForCall(listSub1);
|
|
497
|
+
expectSingleListCallAndClear(listSub1, employeesAsServerReturns, {
|
|
464
498
|
status: "loaded"
|
|
465
|
-
})
|
|
499
|
+
});
|
|
500
|
+
await waitForCall(ifaceSub);
|
|
501
|
+
expectSingleListCallAndClear(ifaceSub, employeesAsServerReturns, {
|
|
502
|
+
status: "loaded"
|
|
503
|
+
});
|
|
504
|
+
expectNoMoreCalls(listSub1);
|
|
505
|
+
expectNoMoreCalls(ifaceSub);
|
|
506
|
+
expect(listSub1.next).not.toHaveBeenCalled();
|
|
507
|
+
expect(listSub1.error).not.toHaveBeenCalled();
|
|
508
|
+
expect(ifaceSub.next).not.toHaveBeenCalled();
|
|
509
|
+
expect(ifaceSub.error).not.toHaveBeenCalled();
|
|
466
510
|
});
|
|
467
511
|
it("subsequent load", async () => {
|
|
468
512
|
// Pre-seed with data the server doesn't return
|
|
469
|
-
|
|
470
|
-
|
|
513
|
+
updateList(cache, {
|
|
514
|
+
type: Employee,
|
|
515
|
+
where: {},
|
|
516
|
+
orderBy: {}
|
|
517
|
+
}, mutatedEmployees);
|
|
518
|
+
defer(cache.observeList({
|
|
519
|
+
type: Employee,
|
|
471
520
|
mode: "force"
|
|
472
521
|
}, listSub1));
|
|
473
|
-
await
|
|
474
|
-
|
|
475
|
-
|
|
522
|
+
await waitForCall(listSub1, 1);
|
|
523
|
+
const firstLoad = listSub1.next.mock.calls[0][0];
|
|
524
|
+
expectSingleListCallAndClear(listSub1, mutatedEmployees, {
|
|
476
525
|
status: "loading"
|
|
477
|
-
})
|
|
478
|
-
|
|
479
|
-
listSub1
|
|
480
|
-
await vi.waitFor(() => expect(listSub1).toHaveBeenCalled());
|
|
481
|
-
expect(listSub1).toHaveBeenCalledExactlyOnceWith(listPayloadContaining({
|
|
482
|
-
resolvedList: employeesAsServerReturns,
|
|
526
|
+
});
|
|
527
|
+
await waitForCall(listSub1, 1);
|
|
528
|
+
expectSingleListCallAndClear(listSub1, employeesAsServerReturns, {
|
|
483
529
|
status: "loaded",
|
|
484
530
|
lastUpdated: expect.toBeGreaterThan(firstLoad.lastUpdated)
|
|
485
|
-
})
|
|
486
|
-
listSub1.mockClear();
|
|
531
|
+
});
|
|
487
532
|
});
|
|
488
533
|
});
|
|
489
534
|
describe("mode = offline", () => {
|
|
490
535
|
it("updates with list updates", async () => {
|
|
491
|
-
defer(cache.observeList(
|
|
536
|
+
defer(cache.observeList({
|
|
537
|
+
type: Employee,
|
|
538
|
+
where: {},
|
|
539
|
+
orderBy: {},
|
|
492
540
|
mode: "offline"
|
|
493
541
|
}, listSub1));
|
|
494
|
-
expect(listSub1).toHaveBeenCalledTimes(0);
|
|
495
|
-
|
|
542
|
+
expect(listSub1.next).toHaveBeenCalledTimes(0);
|
|
543
|
+
updateList(cache, {
|
|
544
|
+
type: Employee,
|
|
545
|
+
where: {},
|
|
546
|
+
orderBy: {}
|
|
547
|
+
}, employeesAsServerReturns);
|
|
496
548
|
vitest.runOnlyPendingTimers();
|
|
497
|
-
|
|
498
|
-
resolvedList: employeesAsServerReturns
|
|
499
|
-
}));
|
|
500
|
-
listSub1.mockClear();
|
|
549
|
+
expectSingleListCallAndClear(listSub1, employeesAsServerReturns);
|
|
501
550
|
|
|
502
551
|
// list is just now one object
|
|
503
|
-
|
|
552
|
+
updateList(cache, {
|
|
553
|
+
type: Employee,
|
|
554
|
+
where: {},
|
|
555
|
+
orderBy: {}
|
|
556
|
+
}, [employeesAsServerReturns[0]]);
|
|
504
557
|
vitest.runOnlyPendingTimers();
|
|
505
|
-
|
|
506
|
-
resolvedList: [employeesAsServerReturns[0]]
|
|
507
|
-
}));
|
|
558
|
+
expectSingleListCallAndClear(listSub1, [employeesAsServerReturns[0]]);
|
|
508
559
|
});
|
|
509
560
|
it("updates with different list updates", async () => {
|
|
510
|
-
defer(cache.observeList(
|
|
561
|
+
defer(cache.observeList({
|
|
562
|
+
type: Employee,
|
|
563
|
+
where: {},
|
|
564
|
+
orderBy: {},
|
|
511
565
|
mode: "offline"
|
|
512
566
|
}, listSub1));
|
|
513
|
-
expect(listSub1).toHaveBeenCalledTimes(0);
|
|
514
|
-
|
|
567
|
+
expect(listSub1.next).toHaveBeenCalledTimes(0);
|
|
568
|
+
updateList(cache, {
|
|
569
|
+
type: Employee,
|
|
570
|
+
where: {},
|
|
571
|
+
orderBy: {}
|
|
572
|
+
}, employeesAsServerReturns);
|
|
515
573
|
vitest.runOnlyPendingTimers();
|
|
516
|
-
|
|
517
|
-
resolvedList: employeesAsServerReturns
|
|
518
|
-
}));
|
|
519
|
-
listSub1.mockClear();
|
|
574
|
+
expectSingleListCallAndClear(listSub1, employeesAsServerReturns);
|
|
520
575
|
|
|
521
576
|
// new where === different list
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
577
|
+
updateList(cache, {
|
|
578
|
+
type: Employee,
|
|
579
|
+
where: {
|
|
580
|
+
employeeId: {
|
|
581
|
+
$gt: 0
|
|
582
|
+
}
|
|
583
|
+
},
|
|
584
|
+
orderBy: {}
|
|
526
585
|
}, mutatedEmployees);
|
|
527
586
|
vitest.runOnlyPendingTimers();
|
|
528
587
|
|
|
529
588
|
// original list updates still
|
|
530
|
-
|
|
531
|
-
resolvedList: mutatedEmployees
|
|
532
|
-
}));
|
|
589
|
+
expectSingleListCallAndClear(listSub1, mutatedEmployees);
|
|
533
590
|
});
|
|
534
591
|
});
|
|
535
592
|
});
|
|
@@ -542,57 +599,125 @@ describe(Store, () => {
|
|
|
542
599
|
});
|
|
543
600
|
it("works in the solo case", async () => {
|
|
544
601
|
const listSub = mockListSubCallback();
|
|
545
|
-
defer(cache.observeList(
|
|
602
|
+
defer(cache.observeList({
|
|
603
|
+
type: Employee,
|
|
604
|
+
where: {},
|
|
605
|
+
orderBy: {},
|
|
546
606
|
mode: "force",
|
|
547
607
|
pageSize: 1
|
|
548
608
|
}, listSub));
|
|
549
|
-
expect(listSub).not.toHaveBeenCalled();
|
|
550
|
-
await
|
|
551
|
-
|
|
609
|
+
expect(listSub.next).not.toHaveBeenCalled();
|
|
610
|
+
await waitForCall(listSub, 1);
|
|
611
|
+
expectSingleListCallAndClear(listSub, [], {
|
|
552
612
|
status: "loading"
|
|
553
|
-
})
|
|
554
|
-
listSub
|
|
555
|
-
await vi.waitFor(() => expect(listSub).toHaveBeenCalled());
|
|
556
|
-
expect(listSub).toHaveBeenCalledExactlyOnceWith(listPayloadContaining({
|
|
557
|
-
resolvedList: employeesAsServerReturns.slice(0, 1),
|
|
558
|
-
status: "loaded"
|
|
559
|
-
}));
|
|
613
|
+
});
|
|
614
|
+
await waitForCall(listSub, 1);
|
|
560
615
|
const {
|
|
561
616
|
fetchMore
|
|
562
|
-
} = listSub.mock.calls[0][0];
|
|
563
|
-
listSub.
|
|
617
|
+
} = listSub.next.mock.calls[0][0];
|
|
618
|
+
expectSingleListCallAndClear(listSub, employeesAsServerReturns.slice(0, 1), {
|
|
619
|
+
status: "loaded"
|
|
620
|
+
});
|
|
564
621
|
void fetchMore();
|
|
565
|
-
await
|
|
566
|
-
|
|
567
|
-
resolvedList: employeesAsServerReturns.slice(0, 1),
|
|
622
|
+
await waitForCall(listSub, 1);
|
|
623
|
+
expectSingleListCallAndClear(listSub, employeesAsServerReturns.slice(0, 1), {
|
|
568
624
|
status: "loading"
|
|
569
|
-
})
|
|
570
|
-
listSub
|
|
571
|
-
|
|
572
|
-
expect(listSub).toHaveBeenCalledWith(listPayloadContaining({
|
|
573
|
-
resolvedList: employeesAsServerReturns.slice(0, 2),
|
|
625
|
+
});
|
|
626
|
+
await waitForCall(listSub, 1);
|
|
627
|
+
expectSingleListCallAndClear(listSub, employeesAsServerReturns.slice(0, 2), {
|
|
574
628
|
status: "loaded"
|
|
575
|
-
})
|
|
629
|
+
});
|
|
576
630
|
});
|
|
577
631
|
});
|
|
578
632
|
});
|
|
579
633
|
describe("with mock client", () => {
|
|
580
634
|
let client;
|
|
581
635
|
let mockClient;
|
|
582
|
-
let
|
|
636
|
+
let store;
|
|
583
637
|
beforeEach(async () => {
|
|
584
638
|
mockClient = createClientMockHelper();
|
|
585
639
|
client = mockClient.client;
|
|
586
|
-
|
|
640
|
+
store = new Store(client);
|
|
641
|
+
});
|
|
642
|
+
it("properly fires error handler for a list", async () => {
|
|
643
|
+
const error = new Error("A faux error");
|
|
644
|
+
mockClient.mockFetchPageOnce().reject(error);
|
|
645
|
+
const sub = mockListSubCallback();
|
|
646
|
+
store.observeList({
|
|
647
|
+
type: Employee,
|
|
648
|
+
where: {},
|
|
649
|
+
orderBy: {}
|
|
650
|
+
}, sub);
|
|
651
|
+
await waitForCall(sub.error, 1);
|
|
652
|
+
expect(sub.error).toHaveBeenCalled();
|
|
653
|
+
expect(sub.next).not.toHaveBeenCalled();
|
|
654
|
+
});
|
|
655
|
+
describe("batching", () => {
|
|
656
|
+
it("groups requests for single objects", async () => {
|
|
657
|
+
mockClient.mockFetchPageOnce().resolve({
|
|
658
|
+
data: [{
|
|
659
|
+
$apiName: "Employee",
|
|
660
|
+
$objectType: "Employee",
|
|
661
|
+
$primaryKey: 0
|
|
662
|
+
}, {
|
|
663
|
+
$apiName: "Employee",
|
|
664
|
+
$objectType: "Employee",
|
|
665
|
+
$primaryKey: 1
|
|
666
|
+
}],
|
|
667
|
+
nextPageToken: undefined,
|
|
668
|
+
totalCount: "2"
|
|
669
|
+
});
|
|
670
|
+
vi.mocked(client.fetchMetadata).mockReturnValue(Promise.resolve({
|
|
671
|
+
primaryKeyApiName: "id"
|
|
672
|
+
}));
|
|
673
|
+
const a = mockSingleSubCallback();
|
|
674
|
+
const b = mockSingleSubCallback();
|
|
675
|
+
defer(store.observeObject(Employee, 0, {}, a));
|
|
676
|
+
defer(store.observeObject(Employee, 1, {}, b));
|
|
677
|
+
await a.expectLoadingAndLoaded({
|
|
678
|
+
loading: objectPayloadContaining({
|
|
679
|
+
status: "loading",
|
|
680
|
+
object: undefined
|
|
681
|
+
}),
|
|
682
|
+
loaded: objectPayloadContaining({
|
|
683
|
+
object: expect.objectContaining({
|
|
684
|
+
$primaryKey: 0
|
|
685
|
+
})
|
|
686
|
+
})
|
|
687
|
+
});
|
|
688
|
+
await b.expectLoadingAndLoaded({
|
|
689
|
+
loading: objectPayloadContaining({
|
|
690
|
+
status: "loading",
|
|
691
|
+
object: undefined
|
|
692
|
+
}),
|
|
693
|
+
loaded: objectPayloadContaining({
|
|
694
|
+
object: expect.objectContaining({
|
|
695
|
+
$primaryKey: 1
|
|
696
|
+
})
|
|
697
|
+
})
|
|
698
|
+
});
|
|
699
|
+
console.log(client.mock.calls);
|
|
700
|
+
});
|
|
587
701
|
});
|
|
588
702
|
describe("actions", () => {
|
|
703
|
+
beforeEach(() => {
|
|
704
|
+
vi.mocked(client.fetchMetadata).mockReturnValue(Promise.resolve({
|
|
705
|
+
primaryKeyApiName: "id"
|
|
706
|
+
}));
|
|
707
|
+
});
|
|
589
708
|
it("properly invalidates objects", async () => {
|
|
590
709
|
// after the below `observeObject`, the cache will need to load from the server
|
|
591
|
-
|
|
592
|
-
|
|
710
|
+
// (also the batch loader uses object set to load not fetchOne)
|
|
711
|
+
mockClient.mockFetchPageOnce().resolve({
|
|
712
|
+
data: [{
|
|
713
|
+
$apiName: "Todo",
|
|
714
|
+
$primaryKey: 0
|
|
715
|
+
}],
|
|
716
|
+
nextPageToken: undefined,
|
|
717
|
+
totalCount: "1"
|
|
593
718
|
});
|
|
594
719
|
const todoSubFn = mockSingleSubCallback();
|
|
595
|
-
defer(
|
|
720
|
+
defer(store.observeObject(Todo, 0, {}, todoSubFn));
|
|
596
721
|
await todoSubFn.expectLoadingAndLoaded({
|
|
597
722
|
loading: objectPayloadContaining({
|
|
598
723
|
status: "loading",
|
|
@@ -614,15 +739,18 @@ describe(Store, () => {
|
|
|
614
739
|
});
|
|
615
740
|
|
|
616
741
|
// after we apply the action, the object is invalidated and gets re-requested
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
742
|
+
mockClient.mockFetchPageOnce().resolve({
|
|
743
|
+
data: [{
|
|
744
|
+
$primaryKey: 0,
|
|
745
|
+
$apiName: "Todo",
|
|
746
|
+
text: "hello there kind sir"
|
|
747
|
+
}],
|
|
748
|
+
nextPageToken: undefined,
|
|
749
|
+
totalCount: "1"
|
|
621
750
|
});
|
|
622
|
-
|
|
751
|
+
await store.applyAction(createOffice, {
|
|
623
752
|
officeId: "whatever"
|
|
624
753
|
});
|
|
625
|
-
await actionPromise;
|
|
626
754
|
await todoSubFn.expectLoadingAndLoaded({
|
|
627
755
|
loading: objectPayloadContaining({
|
|
628
756
|
status: "loading"
|
|
@@ -643,9 +771,13 @@ describe(Store, () => {
|
|
|
643
771
|
};
|
|
644
772
|
|
|
645
773
|
// after the below `observeObject`, the cache will need to load from the server
|
|
646
|
-
mockClient.
|
|
774
|
+
mockClient.mockFetchPageOnce().resolve({
|
|
775
|
+
data: [fauxObject],
|
|
776
|
+
nextPageToken: undefined,
|
|
777
|
+
totalCount: "1"
|
|
778
|
+
});
|
|
647
779
|
const todoSubFn = mockSingleSubCallback();
|
|
648
|
-
defer(
|
|
780
|
+
defer(store.observeObject(Todo, 0, {}, todoSubFn));
|
|
649
781
|
await todoSubFn.expectLoadingAndLoaded({
|
|
650
782
|
loading: objectPayloadContaining({
|
|
651
783
|
status: "loading",
|
|
@@ -661,26 +793,26 @@ describe(Store, () => {
|
|
|
661
793
|
|
|
662
794
|
// at this point we have an observation properly set up
|
|
663
795
|
const applyActionResult = mockClient.mockApplyActionOnce();
|
|
664
|
-
const actionPromise =
|
|
796
|
+
const actionPromise = store.applyAction(createOffice, {
|
|
665
797
|
officeId: "whatever"
|
|
666
798
|
}, {
|
|
667
799
|
optimisticUpdate: ctx => {
|
|
668
800
|
ctx.updateObject({
|
|
669
801
|
...fauxObject,
|
|
670
|
-
|
|
802
|
+
text: "optimistic"
|
|
671
803
|
});
|
|
672
804
|
}
|
|
673
805
|
});
|
|
674
806
|
await waitForCall(todoSubFn, 1);
|
|
675
|
-
expect(todoSubFn).toHaveBeenCalledExactlyOnceWith(objectPayloadContaining({
|
|
807
|
+
expect(todoSubFn.next).toHaveBeenCalledExactlyOnceWith(objectPayloadContaining({
|
|
676
808
|
object: {
|
|
677
809
|
...fauxObject,
|
|
678
|
-
|
|
810
|
+
text: "optimistic"
|
|
679
811
|
},
|
|
680
812
|
status: "loading",
|
|
681
813
|
isOptimistic: true
|
|
682
814
|
}));
|
|
683
|
-
todoSubFn.mockClear();
|
|
815
|
+
todoSubFn.next.mockClear();
|
|
684
816
|
|
|
685
817
|
// let the action error out
|
|
686
818
|
applyActionResult.reject("an error thrown");
|
|
@@ -688,17 +820,294 @@ describe(Store, () => {
|
|
|
688
820
|
|
|
689
821
|
// back to the original object
|
|
690
822
|
await waitForCall(todoSubFn, 1);
|
|
691
|
-
expect(todoSubFn).toHaveBeenCalledExactlyOnceWith(objectPayloadContaining({
|
|
823
|
+
expect(todoSubFn.next).toHaveBeenCalledExactlyOnceWith(objectPayloadContaining({
|
|
692
824
|
object: fauxObject,
|
|
693
825
|
status: "loaded",
|
|
694
826
|
isOptimistic: false
|
|
695
827
|
}));
|
|
696
828
|
});
|
|
697
829
|
});
|
|
830
|
+
describe("orderBy", async () => {
|
|
831
|
+
const ontologyProvider = {
|
|
832
|
+
getObjectDefinition: async () => {
|
|
833
|
+
return {
|
|
834
|
+
...wireObjectTypeFullMetadataToSdkObjectMetadata(stubData.todoWithLinkTypes, true),
|
|
835
|
+
[InterfaceDefinitions]: {}
|
|
836
|
+
};
|
|
837
|
+
},
|
|
838
|
+
getActionDefinition() {
|
|
839
|
+
throw new Error("not implemented");
|
|
840
|
+
},
|
|
841
|
+
getInterfaceDefinition() {
|
|
842
|
+
throw new Error("not implemented");
|
|
843
|
+
},
|
|
844
|
+
getQueryDefinition() {
|
|
845
|
+
throw new Error("not implemented");
|
|
846
|
+
}
|
|
847
|
+
};
|
|
848
|
+
const minimalClient = createMinimalClient({
|
|
849
|
+
ontologyRid: "ri.whatever"
|
|
850
|
+
}, "https://localhost:8080", () => Promise.resolve("token"), {
|
|
851
|
+
logger
|
|
852
|
+
}, fetch, createObjectSet, () => () => ontologyProvider);
|
|
853
|
+
async function createObject(type, x) {
|
|
854
|
+
return (await minimalClient.objectFactory2(minimalClient, [{
|
|
855
|
+
...x,
|
|
856
|
+
$apiName: type.apiName,
|
|
857
|
+
$objectType: type.apiName,
|
|
858
|
+
$objectSpecifier: `${type.apiName}:${x.$primaryKey}`
|
|
859
|
+
}], undefined))[0];
|
|
860
|
+
}
|
|
861
|
+
let nextPk = 0;
|
|
862
|
+
const fauxObjectA = await createObject(Todo, {
|
|
863
|
+
$primaryKey: nextPk,
|
|
864
|
+
$title: "a",
|
|
865
|
+
id: nextPk,
|
|
866
|
+
text: "a"
|
|
867
|
+
});
|
|
868
|
+
nextPk++;
|
|
869
|
+
const fauxObjectB = await createObject(Todo, {
|
|
870
|
+
$primaryKey: nextPk,
|
|
871
|
+
$title: "b",
|
|
872
|
+
id: nextPk,
|
|
873
|
+
text: "b"
|
|
874
|
+
});
|
|
875
|
+
nextPk++;
|
|
876
|
+
const fauxObjectC = await createObject(Todo, {
|
|
877
|
+
$primaryKey: nextPk,
|
|
878
|
+
$title: "c",
|
|
879
|
+
id: nextPk,
|
|
880
|
+
text: "c"
|
|
881
|
+
});
|
|
882
|
+
const noWhereNoOrderBy = {
|
|
883
|
+
type: Todo,
|
|
884
|
+
where: {},
|
|
885
|
+
orderBy: {}
|
|
886
|
+
};
|
|
887
|
+
const noWhereOrderByText = {
|
|
888
|
+
type: Todo,
|
|
889
|
+
where: {},
|
|
890
|
+
orderBy: {
|
|
891
|
+
text: "asc"
|
|
892
|
+
}
|
|
893
|
+
};
|
|
894
|
+
const subListUnordered = mockListSubCallback();
|
|
895
|
+
const subListOrdered = mockListSubCallback();
|
|
896
|
+
beforeEach(() => {
|
|
897
|
+
vi.mocked(client.fetchMetadata).mockReturnValue(Promise.resolve({
|
|
898
|
+
primaryKeyApiName: "id"
|
|
899
|
+
}));
|
|
900
|
+
});
|
|
901
|
+
beforeEach(() => {
|
|
902
|
+
defer(store.observeList({
|
|
903
|
+
...noWhereNoOrderBy,
|
|
904
|
+
mode: "offline"
|
|
905
|
+
}, subListUnordered));
|
|
906
|
+
expect(subListUnordered.next).toHaveBeenCalledTimes(0);
|
|
907
|
+
defer(store.observeList({
|
|
908
|
+
...noWhereOrderByText,
|
|
909
|
+
mode: "offline"
|
|
910
|
+
}, subListOrdered));
|
|
911
|
+
expect(subListOrdered.next).toHaveBeenCalledTimes(0);
|
|
912
|
+
});
|
|
913
|
+
it("invalidates the correct lists", async () => {
|
|
914
|
+
// for whatever reason, the first list is loaded as [B, A]
|
|
915
|
+
updateList(store, noWhereNoOrderBy, [fauxObjectB, fauxObjectA]);
|
|
916
|
+
await waitForCall(subListUnordered, 1);
|
|
917
|
+
expectSingleListCallAndClear(subListUnordered, [fauxObjectB, fauxObjectA]);
|
|
918
|
+
|
|
919
|
+
// The other list definitely matches on the where clause and we can insert
|
|
920
|
+
// orderBy properly. So this is [A, B]
|
|
921
|
+
await waitForCall(subListOrdered, 1);
|
|
922
|
+
expectSingleListCallAndClear(subListOrdered, [fauxObjectA, fauxObjectB]);
|
|
923
|
+
|
|
924
|
+
// For whatever reason, object B is no longer in the first set (use your imagination)
|
|
925
|
+
// but we have added a C before A. So the first list is [C, A]
|
|
926
|
+
updateList(store, {
|
|
927
|
+
type: Todo,
|
|
928
|
+
where: {},
|
|
929
|
+
orderBy: {}
|
|
930
|
+
}, [fauxObjectC, fauxObjectA]);
|
|
931
|
+
await waitForCall(subListUnordered, 1);
|
|
932
|
+
expectSingleListCallAndClear(subListUnordered, [fauxObjectC, fauxObjectA]);
|
|
933
|
+
|
|
934
|
+
// Nothing told the system that B was deleted so we can presume it still exists
|
|
935
|
+
// and therefore the second list is now [A, B, C]
|
|
936
|
+
await waitForCall(subListOrdered, 1);
|
|
937
|
+
expectSingleListCallAndClear(subListOrdered, [fauxObjectA, fauxObjectB, fauxObjectC]);
|
|
938
|
+
});
|
|
939
|
+
it("produces proper results with optimistic updates and successful action", async () => {
|
|
940
|
+
const optimisticallyMutatedA = await createObject(Todo, {
|
|
941
|
+
...fauxObjectA,
|
|
942
|
+
text: "optimistic"
|
|
943
|
+
});
|
|
944
|
+
const pkForOptimistic = nextPk++;
|
|
945
|
+
const optimisticallyCreatedObjectD = await createObject(Todo, {
|
|
946
|
+
"$primaryKey": pkForOptimistic,
|
|
947
|
+
"$title": "d",
|
|
948
|
+
"text": "d",
|
|
949
|
+
id: pkForOptimistic
|
|
950
|
+
});
|
|
951
|
+
|
|
952
|
+
// for whatever reason, the first list is loaded as [B, A]
|
|
953
|
+
updateList(store, noWhereNoOrderBy, [fauxObjectB, fauxObjectA]);
|
|
954
|
+
await waitForCall(subListUnordered, 1);
|
|
955
|
+
expectSingleListCallAndClear(subListUnordered, [fauxObjectB, fauxObjectA]);
|
|
956
|
+
|
|
957
|
+
// The other list definitely matches on the where clause and we can insert
|
|
958
|
+
// orderBy properly. So this is [A, B]
|
|
959
|
+
await waitForCall(subListOrdered, 1);
|
|
960
|
+
expectSingleListCallAndClear(subListOrdered, [fauxObjectA, fauxObjectB]);
|
|
961
|
+
testStage("Start");
|
|
962
|
+
|
|
963
|
+
// the optimistic job will call createObject which triggers the `objectFactory2` of the
|
|
964
|
+
// cache context.
|
|
965
|
+
mockClient.mockObjectFactory2Once().resolve([optimisticallyCreatedObjectD]);
|
|
966
|
+
|
|
967
|
+
// Perform something optimistic.
|
|
968
|
+
const removeOptimisticResult = runOptimisticJob(store, b => {
|
|
969
|
+
b.createObject(Todo, pkForOptimistic, {
|
|
970
|
+
id: pkForOptimistic,
|
|
971
|
+
text: "d"
|
|
972
|
+
});
|
|
973
|
+
b.updateObject(optimisticallyMutatedA);
|
|
974
|
+
});
|
|
975
|
+
|
|
976
|
+
// The first list is now [B, A, optimistic]
|
|
977
|
+
await waitForCall(subListUnordered, 1);
|
|
978
|
+
expectSingleListCallAndClear(subListUnordered, [fauxObjectB, optimisticallyMutatedA,
|
|
979
|
+
// same position, new values
|
|
980
|
+
optimisticallyCreatedObjectD], {
|
|
981
|
+
isOptimistic: true
|
|
982
|
+
});
|
|
983
|
+
|
|
984
|
+
// the second list is now [A, B, optimistic]
|
|
985
|
+
await waitForCall(subListOrdered, 1);
|
|
986
|
+
expectSingleListCallAndClear(subListOrdered, [fauxObjectB, optimisticallyCreatedObjectD, optimisticallyMutatedA], {
|
|
987
|
+
isOptimistic: true
|
|
988
|
+
});
|
|
989
|
+
|
|
990
|
+
// Roll back the optimistic update
|
|
991
|
+
await removeOptimisticResult();
|
|
992
|
+
|
|
993
|
+
// The first list is now [B, A]
|
|
994
|
+
await waitForCall(subListUnordered, 1);
|
|
995
|
+
expectSingleListCallAndClear(subListUnordered, [fauxObjectB, fauxObjectA], {
|
|
996
|
+
isOptimistic: false
|
|
997
|
+
});
|
|
998
|
+
|
|
999
|
+
// the second list is now [A, B]
|
|
1000
|
+
await waitForCall(subListOrdered, 1);
|
|
1001
|
+
expectSingleListCallAndClear(subListOrdered, [fauxObjectA, fauxObjectB], {
|
|
1002
|
+
isOptimistic: false
|
|
1003
|
+
});
|
|
1004
|
+
});
|
|
1005
|
+
// I think these are named backwards
|
|
1006
|
+
it("produces proper results with optimistic updates and rollback", async () => {
|
|
1007
|
+
const pkForOptimistic = nextPk++;
|
|
1008
|
+
const optimisticallyCreatedObjectD = await createObject(Todo, {
|
|
1009
|
+
"$primaryKey": pkForOptimistic,
|
|
1010
|
+
"$title": "d",
|
|
1011
|
+
"text": "d",
|
|
1012
|
+
id: pkForOptimistic
|
|
1013
|
+
});
|
|
1014
|
+
const optimisticallyMutatedA = await createObject(Todo, {
|
|
1015
|
+
...fauxObjectA,
|
|
1016
|
+
text: "optimistic"
|
|
1017
|
+
});
|
|
1018
|
+
testStage("Initial Setup");
|
|
1019
|
+
|
|
1020
|
+
// later we will "create" this object
|
|
1021
|
+
const createdObjectD = await createObject(Todo, {
|
|
1022
|
+
"$primaryKey": 9000,
|
|
1023
|
+
"$title": "d prime",
|
|
1024
|
+
"text": "d prime",
|
|
1025
|
+
id: 9000
|
|
1026
|
+
});
|
|
1027
|
+
|
|
1028
|
+
// for whatever reason, the first list is loaded as [B, A]
|
|
1029
|
+
updateList(store, noWhereNoOrderBy, [fauxObjectB, fauxObjectA]);
|
|
1030
|
+
await waitForCall(subListUnordered, 1);
|
|
1031
|
+
expectSingleListCallAndClear(subListUnordered, [fauxObjectB, fauxObjectA]);
|
|
1032
|
+
|
|
1033
|
+
// The other list definitely matches on the where clause and we can insert
|
|
1034
|
+
// orderBy properly. So this is [A, B]
|
|
1035
|
+
expectSingleListCallAndClear(subListOrdered, [fauxObjectA, fauxObjectB]);
|
|
1036
|
+
testStage("Optimistic Creation");
|
|
1037
|
+
|
|
1038
|
+
// the optimistic job will call createObject which triggers the `objectFactory2` of the
|
|
1039
|
+
// cache context.
|
|
1040
|
+
|
|
1041
|
+
mockClient.mockObjectFactory2Once().resolve([optimisticallyCreatedObjectD]);
|
|
1042
|
+
const mockedApplyAction = mockClient.mockApplyActionOnce();
|
|
1043
|
+
testStage("Apply Action");
|
|
1044
|
+
const actionPromise = store.applyAction(createOffice, {
|
|
1045
|
+
officeId: "5"
|
|
1046
|
+
}, {
|
|
1047
|
+
optimisticUpdate: b => {
|
|
1048
|
+
b.createObject(Todo, optimisticallyCreatedObjectD.$primaryKey, {
|
|
1049
|
+
id: optimisticallyCreatedObjectD.$primaryKey,
|
|
1050
|
+
text: "d"
|
|
1051
|
+
});
|
|
1052
|
+
b.updateObject(optimisticallyMutatedA);
|
|
1053
|
+
}
|
|
1054
|
+
});
|
|
1055
|
+
testStage("Optimistic Updates");
|
|
1056
|
+
|
|
1057
|
+
// The first list is now [B, A, optimistic]
|
|
1058
|
+
await waitForCall(subListUnordered, 1);
|
|
1059
|
+
expectSingleListCallAndClear(subListUnordered, [fauxObjectB, optimisticallyMutatedA,
|
|
1060
|
+
// same position, new values
|
|
1061
|
+
optimisticallyCreatedObjectD], {
|
|
1062
|
+
isOptimistic: true
|
|
1063
|
+
});
|
|
1064
|
+
|
|
1065
|
+
// the second list is now [B, optimistic, optimistic a]
|
|
1066
|
+
await waitForCall(subListOrdered, 1);
|
|
1067
|
+
expectSingleListCallAndClear(subListOrdered, [fauxObjectB, optimisticallyCreatedObjectD, optimisticallyMutatedA], {
|
|
1068
|
+
isOptimistic: true
|
|
1069
|
+
});
|
|
1070
|
+
testStage("Resolve Action");
|
|
1071
|
+
const modifiedObjectA = await createObject(Todo, {
|
|
1072
|
+
...fauxObjectA,
|
|
1073
|
+
text: "a prime"
|
|
1074
|
+
});
|
|
1075
|
+
|
|
1076
|
+
// The action will complete and then revalidate in order...
|
|
1077
|
+
mockClient.mockFetchPageOnce().resolve({
|
|
1078
|
+
data: [modifiedObjectA, createdObjectD],
|
|
1079
|
+
nextPageToken: undefined,
|
|
1080
|
+
totalCount: "1"
|
|
1081
|
+
});
|
|
1082
|
+
mockedApplyAction.resolve({
|
|
1083
|
+
addedObjects: [{
|
|
1084
|
+
objectType: "Todo",
|
|
1085
|
+
primaryKey: createdObjectD.id
|
|
1086
|
+
}],
|
|
1087
|
+
modifiedObjects: [{
|
|
1088
|
+
objectType: "Todo",
|
|
1089
|
+
primaryKey: fauxObjectA.$primaryKey
|
|
1090
|
+
}]
|
|
1091
|
+
});
|
|
1092
|
+
await actionPromise;
|
|
1093
|
+
await waitForCall(subListUnordered, 1);
|
|
1094
|
+
console.log("=====", subListUnordered.next.mock.calls[0][0]);
|
|
1095
|
+
expectSingleListCallAndClear(subListUnordered, [fauxObjectB,
|
|
1096
|
+
// fauxObjectC,
|
|
1097
|
+
modifiedObjectA, createdObjectD], {
|
|
1098
|
+
isOptimistic: false
|
|
1099
|
+
});
|
|
1100
|
+
await waitForCall(subListOrdered, 1);
|
|
1101
|
+
expectSingleListCallAndClear(subListOrdered, [modifiedObjectA, fauxObjectB, createdObjectD], {
|
|
1102
|
+
isOptimistic: false
|
|
1103
|
+
});
|
|
1104
|
+
});
|
|
1105
|
+
});
|
|
698
1106
|
});
|
|
699
1107
|
describe("layers", () => {
|
|
700
1108
|
it("properly remove", () => {
|
|
701
|
-
const
|
|
1109
|
+
const clientHelper = createClientMockHelper();
|
|
1110
|
+
const store = new Store(clientHelper.client);
|
|
702
1111
|
const baseObjects = [1, 2].map(i => ({
|
|
703
1112
|
$primaryKey: i,
|
|
704
1113
|
$objectType: "Employee",
|
|
@@ -709,12 +1118,12 @@ describe(Store, () => {
|
|
|
709
1118
|
|
|
710
1119
|
// set the truth
|
|
711
1120
|
for (const obj of baseObjects) {
|
|
712
|
-
|
|
1121
|
+
updateObject(store, obj);
|
|
713
1122
|
}
|
|
714
1123
|
|
|
715
1124
|
// expect the truth
|
|
716
1125
|
for (const obj of baseObjects) {
|
|
717
|
-
expect(
|
|
1126
|
+
expect(getObject(store, "Employee", obj.$primaryKey)).toEqual(expect.objectContaining({
|
|
718
1127
|
$title: `truth ${obj.$primaryKey}`
|
|
719
1128
|
}));
|
|
720
1129
|
}
|
|
@@ -734,7 +1143,7 @@ describe(Store, () => {
|
|
|
734
1143
|
|
|
735
1144
|
// expect the optimistic values
|
|
736
1145
|
for (let i = 0; i < 2; i++) {
|
|
737
|
-
expect(
|
|
1146
|
+
expect(getObject(store, "Employee", baseObjects[i].$primaryKey)).toEqual(expect.objectContaining({
|
|
738
1147
|
$title: `optimistic ${baseObjects[i].$primaryKey}`
|
|
739
1148
|
}));
|
|
740
1149
|
}
|
|
@@ -743,10 +1152,10 @@ describe(Store, () => {
|
|
|
743
1152
|
store.removeLayer(layerIds[0]);
|
|
744
1153
|
|
|
745
1154
|
// should have truth object 1 and optimistic object 2
|
|
746
|
-
expect(
|
|
1155
|
+
expect(getObject(store, "Employee", 1)).toEqual(expect.objectContaining({
|
|
747
1156
|
$title: "truth 1"
|
|
748
1157
|
}));
|
|
749
|
-
expect(
|
|
1158
|
+
expect(getObject(store, "Employee", 2)).toEqual(expect.objectContaining({
|
|
750
1159
|
$title: "optimistic 2"
|
|
751
1160
|
}));
|
|
752
1161
|
|
|
@@ -755,7 +1164,7 @@ describe(Store, () => {
|
|
|
755
1164
|
|
|
756
1165
|
// should have truth objects
|
|
757
1166
|
for (const obj of baseObjects) {
|
|
758
|
-
expect(
|
|
1167
|
+
expect(getObject(store, "Employee", obj.$primaryKey)).toEqual(expect.objectContaining({
|
|
759
1168
|
$title: `truth ${obj.$primaryKey}`
|
|
760
1169
|
}));
|
|
761
1170
|
}
|