#6828 fix(@aws-amplify/datastore): use runExclusive when enqueuing

Open Alex Hinson amhinson
Coverage Reach
aws-amplify-react/src/Auth/Provider/withFacebook.tsx aws-amplify-react/src/Auth/Provider/withAuth0.tsx aws-amplify-react/src/Auth/Provider/withGoogle.tsx aws-amplify-react/src/Auth/Provider/withAmazon.tsx aws-amplify-react/src/Auth/Provider/withOAuth.tsx aws-amplify-react/src/Auth/Provider/index.tsx aws-amplify-react/src/Auth/Authenticator.tsx aws-amplify-react/src/Auth/SignUp.tsx aws-amplify-react/src/Auth/Greetings.tsx aws-amplify-react/src/Auth/AuthPiece.tsx aws-amplify-react/src/Auth/SignOut.tsx aws-amplify-react/src/Auth/FederatedSignIn.tsx aws-amplify-react/src/Auth/SignIn.tsx aws-amplify-react/src/Auth/VerifyContact.tsx aws-amplify-react/src/Auth/index.tsx aws-amplify-react/src/Auth/RequireNewPassword.tsx aws-amplify-react/src/Auth/ForgotPassword.tsx aws-amplify-react/src/Auth/ConfirmSignIn.tsx aws-amplify-react/src/Auth/ConfirmSignUp.tsx aws-amplify-react/src/Auth/TOTPSetup.tsx aws-amplify-react/src/Auth/PhoneField.tsx aws-amplify-react/src/Auth/Loading.tsx aws-amplify-react/src/Auth/common/types.ts aws-amplify-react/src/Auth/common/default-sign-up-fields.tsx aws-amplify-react/src/Auth/common/constants.tsx aws-amplify-react/src/Auth/common/country-dial-codes.tsx aws-amplify-react/src/Storage/S3Album.tsx aws-amplify-react/src/Storage/S3Image.tsx aws-amplify-react/src/Storage/S3Text.tsx aws-amplify-react/src/Storage/Common.tsx aws-amplify-react/src/Amplify-UI/Amplify-UI-Components-React.tsx aws-amplify-react/src/Amplify-UI/Amplify-UI-Theme.tsx aws-amplify-react/src/Amplify-UI/data-test-attributes.tsx aws-amplify-react/src/Widget/TOTPSetupComp.tsx aws-amplify-react/src/Widget/SelectMFAType.tsx aws-amplify-react/src/Widget/PhotoPicker.tsx aws-amplify-react/src/Widget/TextPicker.tsx aws-amplify-react/src/Widget/Picker.tsx aws-amplify-react/src/Widget/index.tsx aws-amplify-react/src/AmplifyUI.tsx aws-amplify-react/src/XR/SumerianScene.tsx aws-amplify-react/src/XR/IconButton.tsx aws-amplify-react/src/XR/Tooltip.tsx aws-amplify-react/src/XR/Loading.tsx aws-amplify-react/src/Analytics/trackLifecycle.tsx aws-amplify-react/src/AmplifyTheme.tsx aws-amplify-react/src/AmplifyMessageMap.tsx datastore/src/sync/processors/subscription.ts datastore/src/sync/processors/mutation.ts datastore/src/sync/processors/sync.ts datastore/src/sync/index.ts datastore/src/sync/utils.ts datastore/src/sync/outbox.ts datastore/src/sync/datastoreConnectivity.ts datastore/src/sync/merger.ts datastore/src/sync/datastoreReachability/index.ts datastore/src/storage/adapter/indexeddb.ts datastore/src/storage/adapter/asyncstorage.ts datastore/src/storage/adapter/AsyncStorageDatabase.ts datastore/src/storage/adapter/getDefaultAdapter/index.ts datastore/src/storage/storage.ts datastore/src/datastore/datastore.ts datastore/src/util.ts datastore/src/predicates/index.ts datastore/src/predicates/sort.ts datastore/src/types.ts datastore/src/index.ts datastore/__tests__/model.ts datastore/__tests__/schema.ts analytics/src/Providers/AWSPinpointProvider.ts analytics/src/Providers/AmazonPersonalizeProvider.ts analytics/src/Providers/AmazonPersonalizeHelper/MediaAutoTrack.ts analytics/src/Providers/AmazonPersonalizeHelper/SessionInfoManager.ts analytics/src/Providers/AmazonPersonalizeHelper/index.ts analytics/src/Providers/AWSKinesisProvider.ts analytics/src/Providers/EventBuffer.ts analytics/src/Providers/AWSKinesisFirehoseProvider.ts analytics/src/trackers/PageViewTracker.ts analytics/src/trackers/SessionTracker.ts analytics/src/trackers/SessionTracker-rn.ts analytics/src/trackers/EventTracker.ts analytics/src/trackers/index.ts analytics/src/Analytics.ts analytics/src/utils/MethodEmbed.ts analytics/src/utils/AppUtils.ts core/src/Credentials.ts core/src/Util/Retry.ts core/src/Util/Mutex.ts core/src/Util/Reachability.ts core/src/Util/Reachability.native.ts core/src/Util/DateUtils.ts core/src/Util/index.ts core/src/Signer.ts core/src/JS.ts core/src/OAuthHelper/GoogleOAuth.ts core/src/OAuthHelper/FacebookOAuth.ts core/src/OAuthHelper/index.ts core/src/I18n/I18n.ts core/src/I18n/index.ts core/src/Hub.ts core/src/ServiceWorker/ServiceWorker.ts core/src/ServiceWorker/index.ts core/src/ClientDevice/browser.ts core/src/ClientDevice/index.ts core/src/Amplify.ts core/src/Logger/ConsoleLogger.ts core/src/Logger/index.ts core/src/UniversalStorage/index.ts core/src/StorageHelper/index.ts core/src/index.ts core/src/Parser.ts core/src/Platform/index.ts core/src/Platform/version.ts core/src/RNComponents/index.ts core/src/constants.ts core/src/Errors.ts auth/src/Auth.ts auth/src/OAuth/OAuth.ts auth/src/OAuth/oauthStorage.ts auth/src/OAuth/urlOpener.ts auth/src/types/Auth.ts auth/src/types/index.ts auth/src/Errors.ts auth/src/common/AuthErrorStrings.ts auth/src/urlListener.ts predictions/src/Providers/AmazonAIConvertPredictionsProvider.ts predictions/src/Providers/AmazonAIIdentifyPredictionsProvider.ts predictions/src/Providers/AmazonAIInterpretPredictionsProvider.ts predictions/src/Providers/IdentifyTextUtils.ts predictions/src/Providers/AmazonAIPredictionsProvider.ts predictions/src/Providers/Utils.ts predictions/src/Providers/index.ts predictions/src/types/Providers/AbstractIdentifyPredictionsProvider.ts predictions/src/types/Providers/AbstractConvertPredictionsProvider.ts predictions/src/types/Providers/AbstractInterpretPredictionsProvider.ts predictions/src/types/Providers/AbstractPredictionsProvider.ts predictions/src/types/Providers/index.ts predictions/src/types/Predictions.ts predictions/src/types/index.ts predictions/src/Predictions.ts predictions/src/index.ts aws-amplify-vue/src/components/authenticator/SignUp.vue aws-amplify-vue/src/components/authenticator/SignIn.vue aws-amplify-vue/src/components/authenticator/SetMFA.vue aws-amplify-vue/src/components/authenticator/ForgotPassword.vue aws-amplify-vue/src/components/authenticator/Authenticator.vue aws-amplify-vue/src/components/authenticator/RequireNewPassword.vue aws-amplify-vue/src/components/authenticator/ConfirmSignUp.vue aws-amplify-vue/src/components/authenticator/UsernameField.vue aws-amplify-vue/src/components/authenticator/ConfirmSignIn.vue aws-amplify-vue/src/components/authenticator/SignOut.vue aws-amplify-vue/src/components/authenticator/PhoneField.vue aws-amplify-vue/src/components/authenticator/index.js aws-amplify-vue/src/components/authenticator/common.js aws-amplify-vue/src/components/interactions/Chatbot.vue aws-amplify-vue/src/components/interactions/index.js aws-amplify-vue/src/components/storage/PhotoPicker.vue aws-amplify-vue/src/components/storage/S3Album.vue aws-amplify-vue/src/components/storage/S3Image.vue aws-amplify-vue/src/components/storage/index.js aws-amplify-vue/src/components/api/graphql/Connect.vue aws-amplify-vue/src/components/api/index.js aws-amplify-vue/src/components/xr/SumerianScene.vue aws-amplify-vue/src/components/xr/index.js aws-amplify-vue/src/assets/data-test-attributes.js aws-amplify-vue/src/assets/default-sign-up-fields.js aws-amplify-vue/src/assets/countries.js aws-amplify-vue/src/plugins/AmplifyPlugin.js aws-amplify-vue/src/services/getUser.js aws-amplify-vue/src/Amplify.vue aws-amplify-vue/src/events/AmplifyEventBus.js aws-amplify-vue/test_setup/setup-jest.ts pubsub/src/Providers/AWSAppSyncRealTimeProvider.ts pubsub/src/Providers/MqttOverWSProvider.ts pubsub/src/Providers/AWSAppSyncProvider.ts pubsub/src/Providers/AWSIotProvider.ts pubsub/src/Providers/PubSubProvider.ts pubsub/src/Providers/index.ts pubsub/src/PubSub.ts pubsub/src/index.ts storage/src/providers/AWSS3Provider.ts storage/src/providers/AWSS3ProviderManagedUpload.ts storage/src/providers/axios-http-handler.ts storage/src/providers/index.ts storage/src/Storage.ts storage/src/index.ts cache/src/BrowserStorageCache.ts cache/src/InMemoryCache.ts cache/src/Utils/CacheList.ts cache/src/Utils/CacheUtils.ts cache/src/Utils/index.ts cache/src/StorageCache.ts api-rest/src/RestClient.ts api-rest/src/RestAPI.ts api-rest/src/index.ts xr/src/Providers/SumerianProvider.ts xr/src/Providers/XRProvider.ts xr/src/XR.ts xr/src/Errors.ts pushnotification/src/PushNotification.ts pushnotification/src/index.ts api-graphql/src/GraphQLAPI.ts api-graphql/src/index.ts api-graphql/src/types/index.ts interactions/src/Providers/AWSLexProvider.ts interactions/src/Providers/InteractionsProvider.ts interactions/src/Providers/AWSLexProviderHelper/convert.ts interactions/src/Providers/index.ts interactions/src/Interactions.ts aws-amplify/src/index.ts aws-amplify/src/withSSRContext.ts api/src/API.ts

No flags found

Use flags to group coverage reports by test type, project and/or folders.
Then setup custom commit statuses and notifications for each flag.

e.g., #unittest #integration

#production #enterprise

#frontend #backend

Learn more about Codecov Flags here.


@@ -27,54 +27,56 @@
Loading
27 27
		storage: Storage,
28 28
		mutationEvent: MutationEvent
29 29
	): Promise<void> {
30 -
		const mutationEventModelDefinition = this.schema.namespaces[SYNC].models[
31 -
			'MutationEvent'
32 -
		];
33 -
34 -
		const predicate = ModelPredicateCreator.createFromExisting<MutationEvent>(
35 -
			mutationEventModelDefinition,
36 -
			c =>
37 -
				c
38 -
					.modelId('eq', mutationEvent.modelId)
39 -
					.id('ne', this.inProgressMutationEventId)
40 -
		);
30 +
		storage.runExclusive(async s => {
31 +
			const mutationEventModelDefinition = this.schema.namespaces[SYNC].models[
32 +
				'MutationEvent'
33 +
			];
41 34
42 -
		const [first] = await storage.query(this.MutationEvent, predicate);
35 +
			const predicate = ModelPredicateCreator.createFromExisting<MutationEvent>(
36 +
				mutationEventModelDefinition,
37 +
				c =>
38 +
					c
39 +
						.modelId('eq', mutationEvent.modelId)
40 +
						.id('ne', this.inProgressMutationEventId)
41 +
			);
43 42
44 -
		if (first === undefined) {
45 -
			await storage.save(mutationEvent, undefined, this.ownSymbol);
46 -
			return;
47 -
		}
43 +
			const [first] = await s.query(this.MutationEvent, predicate);
48 44
49 -
		const { operation: incomingMutationType } = mutationEvent;
45 +
			if (first === undefined) {
46 +
				await s.save(mutationEvent, undefined, this.ownSymbol);
47 +
				return;
48 +
			}
50 49
51 -
		if (first.operation === TransformerMutationType.CREATE) {
52 -
			if (incomingMutationType === TransformerMutationType.DELETE) {
53 -
				// delete all for model
54 -
				await storage.delete(this.MutationEvent, predicate);
50 +
			const { operation: incomingMutationType } = mutationEvent;
51 +
52 +
			if (first.operation === TransformerMutationType.CREATE) {
53 +
				if (incomingMutationType === TransformerMutationType.DELETE) {
54 +
					// delete all for model
55 +
					await s.delete(this.MutationEvent, predicate);
56 +
				} else {
57 +
					// first gets updated with incoming's data, condition intentionally skiped
58 +
					await s.save(
59 +
						this.MutationEvent.copyOf(first, draft => {
60 +
							draft.data = mutationEvent.data;
61 +
						}),
62 +
						undefined,
63 +
						this.ownSymbol
64 +
					);
65 +
				}
55 66
			} else {
56 -
				// first gets updated with incoming's data, condition intentionally skiped
57 -
				await storage.save(
58 -
					this.MutationEvent.copyOf(first, draft => {
59 -
						draft.data = mutationEvent.data;
60 -
					}),
61 -
					undefined,
62 -
					this.ownSymbol
63 -
				);
64 -
			}
65 -
		} else {
66 -
			const { condition: incomingConditionJSON } = mutationEvent;
67 -
			const incomingCondition = JSON.parse(incomingConditionJSON);
68 -
69 -
			// If no condition
70 -
			if (Object.keys(incomingCondition).length === 0) {
71 -
				// delete all for model
72 -
				await storage.delete(this.MutationEvent, predicate);
73 -
			}
67 +
				const { condition: incomingConditionJSON } = mutationEvent;
68 +
				const incomingCondition = JSON.parse(incomingConditionJSON);
69 +
70 +
				// If no condition
71 +
				if (Object.keys(incomingCondition).length === 0) {
72 +
					// delete all for model
73 +
					await s.delete(this.MutationEvent, predicate);
74 +
				}
74 75
75 -
			// Enqueue new one
76 -
			await storage.save(mutationEvent, undefined, this.ownSymbol);
77 -
		}
76 +
				// Enqueue new one
77 +
				await s.save(mutationEvent, undefined, this.ownSymbol);
78 +
			}
79 +
		});
78 80
	}
79 81
80 82
	public async dequeue(storage: StorageFacade): Promise<MutationEvent> {

@@ -310,7 +310,7 @@
Loading
310 310
											: null,
311 311
									});
312 312
								} catch (err) {
313 -
									logger.warn("failed to execute errorHandler", err);
313 +
									logger.warn('failed to execute errorHandler', err);
314 314
								} finally {
315 315
									// Return empty tuple, dequeues the mutation
316 316
									return error.data

Everything is accounted for!

No changes detected that need to be reviewed.
What changes does Codecov check for?
Lines, not adjusted in diff, that have changed coverage data.
Files that introduced coverage data that had none before.
Files that have missing coverage data that once were tracked.
Files Coverage
packages -0.01% 73.35%
Project Totals (212 files) 73.35%
Loading