Skip to content

Commit a787029

Browse files
authored
feat: PR #369 with reverting back to AmplifyModelRegistration (#394)
* add DataStore configuration API * add documentation, fix formatting and add TimeInterval utilities
1 parent 8a7d847 commit a787029

File tree

15 files changed

+225
-39
lines changed

15 files changed

+225
-39
lines changed

Amplify.xcodeproj/project.pbxproj

+5-1
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,7 @@
211211
B98E9D142372236300934B51 /* QueryPredicate+Equatable.swift in Sources */ = {isa = PBXBuildFile; fileRef = B98E9D0C2372236200934B51 /* QueryPredicate+Equatable.swift */; };
212212
B996FC4423FF2FA8006D0F68 /* Encodable+AnyEncodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = B996FC4323FF2FA8006D0F68 /* Encodable+AnyEncodable.swift */; };
213213
B996FC4D24059918006D0F68 /* Model+Enum.swift in Sources */ = {isa = PBXBuildFile; fileRef = B996FC4C24059918006D0F68 /* Model+Enum.swift */; };
214+
B9A329CC243559BF00C5B80C /* TimeInterval+Helper.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9A329CB243559BF00C5B80C /* TimeInterval+Helper.swift */; };
214215
B9B64A9F23FCBF7E00730B68 /* ModelValueConverter.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9B64A9E23FCBF7E00730B68 /* ModelValueConverter.swift */; };
215216
B9DCA263240F217C00075E22 /* AnyEncodableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9DCA262240F217C00075E22 /* AnyEncodableTests.swift */; };
216217
B9FAA10B23878122009414B4 /* ModelField+Association.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9FAA10A23878122009414B4 /* ModelField+Association.swift */; };
@@ -846,6 +847,7 @@
846847
B99209E22411E49D00F80010 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
847848
B996FC4323FF2FA8006D0F68 /* Encodable+AnyEncodable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Encodable+AnyEncodable.swift"; sourceTree = "<group>"; };
848849
B996FC4C24059918006D0F68 /* Model+Enum.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Model+Enum.swift"; sourceTree = "<group>"; };
850+
B9A329CB243559BF00C5B80C /* TimeInterval+Helper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TimeInterval+Helper.swift"; sourceTree = "<group>"; };
849851
B9B64A9E23FCBF7E00730B68 /* ModelValueConverter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModelValueConverter.swift; sourceTree = "<group>"; };
850852
B9DCA262240F217C00075E22 /* AnyEncodableTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnyEncodableTests.swift; sourceTree = "<group>"; };
851853
B9FAA10A23878122009414B4 /* ModelField+Association.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ModelField+Association.swift"; sourceTree = "<group>"; };
@@ -1740,7 +1742,6 @@
17401742
B92E03A62367CE7A006CEB8D /* Model */ = {
17411743
isa = PBXGroup;
17421744
children = (
1743-
2129BE502395A66F006363A1 /* AmplifyModelRegistration.swift */,
17441745
B92E03A72367CE7A006CEB8D /* Model.swift */,
17451746
B9FAA17F238FBB5D009414B4 /* Model+Array.swift */,
17461747
B92E03AC2367CE7A006CEB8D /* Model+Codable.swift */,
@@ -1750,6 +1751,7 @@
17501751
FA8EE77C238627350097E4F1 /* Model+Subscript.swift */,
17511752
B92E03A92367CE7A006CEB8D /* ModelRegistry.swift */,
17521753
FA5D4CF2238AFD7B00D2F54A /* ModelRegistry+Syncable.swift */,
1754+
2129BE502395A66F006363A1 /* AmplifyModelRegistration.swift */,
17531755
FA8EE780238628490097E4F1 /* Persistable.swift */,
17541756
FA8EE775238626C70097E4F1 /* AnyModel */,
17551757
B9FAA1232388BE2B009414B4 /* Collection */,
@@ -2090,6 +2092,7 @@
20902092
FAE4145E23999BC900CE94C2 /* Result+Void.swift */,
20912093
FA56F72422B14B6A0039754A /* Resumable.swift */,
20922094
B9FAA174238EFC59009414B4 /* String+Extensions.swift */,
2095+
B9A329CB243559BF00C5B80C /* TimeInterval+Helper.swift */,
20932096
219A88EC23F3309800BBC5F2 /* Tree.swift */,
20942097
);
20952098
path = Support;
@@ -3777,6 +3780,7 @@
37773780
FAC2351C227A053D00424678 /* APICategoryPlugin.swift in Sources */,
37783781
FA176ED52385012000C5C5F9 /* DataStoreCategory+HubPayloadEventName.swift in Sources */,
37793782
210DBC162332B3CB009B9E51 /* StorageDownloadDataOperation.swift in Sources */,
3783+
B9A329CC243559BF00C5B80C /* TimeInterval+Helper.swift in Sources */,
37803784
950A26DC23D15D7E00D92B19 /* PredictionsTextToSpeechOperation.swift in Sources */,
37813785
FAC235A3227A5ED000424678 /* HubChannel.swift in Sources */,
37823786
FAA2E8CE23A02A8100E420EA /* PredictionsCategory+Resettable.swift in Sources */,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
//
2+
// Copyright 2018-2020 Amazon.com,
3+
// Inc. or its affiliates. All Rights Reserved.
4+
//
5+
// SPDX-License-Identifier: Apache-2.0
6+
//
7+
8+
import Foundation
9+
10+
extension TimeInterval {
11+
12+
public static func seconds(_ value: Double) -> TimeInterval {
13+
return value
14+
}
15+
16+
public static func minutes(_ value: Double) -> TimeInterval {
17+
return value * 60
18+
}
19+
20+
public static func hours(_ value: Double) -> TimeInterval {
21+
return value * 60 * 60
22+
}
23+
24+
public static func days(_ value: Double) -> TimeInterval {
25+
return value * 60 * 60 * 24
26+
}
27+
28+
}

AmplifyPlugins/DataStore/AWSDataStoreCategoryPlugin/AWSDataStorePlugin.swift

+7-1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ final public class AWSDataStorePlugin: DataStoreCategoryPlugin {
2020

2121
let modelRegistration: AmplifyModelRegistration
2222

23+
/// The DataStore configuration
24+
let configuration: DataStoreConfiguration
25+
2326
/// The local storage provider. Resolved during configuration phase
2427
var storageEngine: StorageEngineBehavior!
2528

@@ -38,8 +41,9 @@ final public class AWSDataStorePlugin: DataStoreCategoryPlugin {
3841
}
3942

4043
/// No-argument init that uses defaults for all providers
41-
public init(modelRegistration: AmplifyModelRegistration) {
44+
public init(modelRegistration: AmplifyModelRegistration, configuration: DataStoreConfiguration = .default) {
4245
self.modelRegistration = modelRegistration
46+
self.configuration = configuration
4347
self.isSyncEnabled = false
4448
if #available(iOS 13.0, *) {
4549
self.dataStorePublisher = DataStorePublisher()
@@ -50,9 +54,11 @@ final public class AWSDataStorePlugin: DataStoreCategoryPlugin {
5054

5155
/// Internal initializer for testing
5256
init(modelRegistration: AmplifyModelRegistration,
57+
configuration: DataStoreConfiguration = .default,
5358
storageEngine: StorageEngineBehavior,
5459
dataStorePublisher: DataStoreSubscribeBehavior) {
5560
self.modelRegistration = modelRegistration
61+
self.configuration = configuration
5662
self.isSyncEnabled = false
5763
self.storageEngine = storageEngine
5864
self.dataStorePublisher = dataStorePublisher
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
//
2+
// Copyright 2018-2020 Amazon.com,
3+
// Inc. or its affiliates. All Rights Reserved.
4+
//
5+
// SPDX-License-Identifier: Apache-2.0
6+
//
7+
8+
import Amplify
9+
import Foundation
10+
11+
/// Error Handler function typealias
12+
public typealias DataStoreErrorHandler = (AmplifyError) -> Void
13+
14+
/// Holds a reference to both the local `Model` and the remote one during a conflict
15+
/// resolution. Implementations of the `DataStoreConflictHandler` use this to decide
16+
/// what the outcome of a conflict should be.
17+
public struct DataStoreConclictData {
18+
public let local: Model
19+
public let remote: Model
20+
}
21+
22+
/// Conflict Handler function typealias. The function is used during a conflict that
23+
/// could not be resolved and requires a decision from the consumer.
24+
public typealias DataStoreConflictHandler = (DataStoreConclictData, DataStoreConflictHandlerResolver) -> Void
25+
26+
/// Callback for the `DataStoreConflictHandler`.
27+
public typealias DataStoreConflictHandlerResolver = (DataStoreConflictHandlerResult) -> Void
28+
29+
/// The conflict resolution result enum.
30+
public enum DataStoreConflictHandlerResult {
31+
32+
/// Discard the local changes in favor of the remote ones.
33+
case discard
34+
35+
/// Keep the local changes (semantic shortcut to `retry(local)`).
36+
case keep
37+
38+
/// Return a new `Model` instance that should used instead of the local and remote changes.
39+
case retry(Model)
40+
}
41+
42+
/// The `DataStore` plugin configuration object.
43+
public struct DataStoreConfiguration {
44+
45+
/// A callback function called on unhandled errors
46+
public let errorHandler: DataStoreErrorHandler
47+
48+
/// A callback called when a conflict could not be resolved by the service
49+
public let conflictHandler: DataStoreConflictHandler
50+
51+
/// How often the sync engine will run (in seconds)
52+
public let syncInterval: TimeInterval
53+
54+
/// The number of records to sync per execution
55+
public let syncMaxRecords: UInt
56+
57+
/// The page size of each sync execution
58+
public let syncPageSize: UInt
59+
60+
init(errorHandler: @escaping DataStoreErrorHandler,
61+
conflictHandler: @escaping DataStoreConflictHandler,
62+
syncInterval: TimeInterval,
63+
syncMaxRecords: UInt,
64+
syncPageSize: UInt) {
65+
self.errorHandler = errorHandler
66+
self.conflictHandler = conflictHandler
67+
self.syncInterval = syncInterval
68+
self.syncMaxRecords = syncMaxRecords
69+
self.syncPageSize = syncPageSize
70+
}
71+
72+
}
73+
74+
extension DataStoreConfiguration {
75+
76+
public static let defaultSyncInterval: TimeInterval = .hours(24)
77+
public static let defaultSyncMaxRecords: UInt = 10_000
78+
public static let defaultSyncPageSize: UInt = 1_000
79+
80+
/// Creates a custom configuration. The only required property is `conflictHandler`.
81+
///
82+
/// - Parameters:
83+
/// - errorHandler: a callback function called on unhandled errors
84+
/// - conflictHandler: a callback called when a conflict could not be resolved by the service
85+
/// - syncInterval: how often the sync engine will run (in seconds)
86+
/// - syncMaxRecords: the number of records to sync per execution
87+
/// - syncPageSize: the page size of each sync execution
88+
/// - Returns: an instance of `DataStoreConfiguration` with the passed parameters.
89+
public static func custom(
90+
errorHandler: @escaping DataStoreErrorHandler = { error in
91+
Amplify.Logging.error(error: error)
92+
},
93+
conflictHandler: @escaping DataStoreConflictHandler = { _, resolve in
94+
resolve(.discard)
95+
},
96+
syncInterval: TimeInterval = DataStoreConfiguration.defaultSyncInterval,
97+
syncMaxRecords: UInt = DataStoreConfiguration.defaultSyncMaxRecords,
98+
syncPageSize: UInt = DataStoreConfiguration.defaultSyncPageSize
99+
) -> DataStoreConfiguration {
100+
return DataStoreConfiguration(errorHandler: errorHandler,
101+
conflictHandler: conflictHandler,
102+
syncInterval: syncInterval,
103+
syncMaxRecords: syncMaxRecords,
104+
syncPageSize: syncPageSize)
105+
}
106+
107+
/// The default configuration.
108+
public static var `default`: DataStoreConfiguration {
109+
.custom()
110+
}
111+
112+
}

AmplifyPlugins/DataStore/AWSDataStoreCategoryPluginTests/Sync/APICategoryDependencyTests.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,8 @@ extension APICategoryDependencyTests {
7373

7474
let dataStorePublisher = DataStorePublisher()
7575
let dataStorePlugin = AWSDataStorePlugin(modelRegistration: TestModelRegistration(),
76-
storageEngine: storageEngine,
77-
dataStorePublisher: dataStorePublisher)
76+
storageEngine: storageEngine,
77+
dataStorePublisher: dataStorePublisher)
7878
try Amplify.add(plugin: dataStorePlugin)
7979

8080
let dataStoreConfig = DataStoreCategoryConfiguration(plugins: [

AmplifyPlugins/DataStore/AWSDataStoreCategoryPluginTests/Sync/LocalSubscriptionTests.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,8 @@ class LocalSubscriptionTests: XCTestCase {
5454

5555
let dataStorePublisher = DataStorePublisher()
5656
let dataStorePlugin = AWSDataStorePlugin(modelRegistration: TestModelRegistration(),
57-
storageEngine: storageEngine,
58-
dataStorePublisher: dataStorePublisher)
57+
storageEngine: storageEngine,
58+
dataStorePublisher: dataStorePublisher)
5959

6060
let dataStoreConfig = DataStoreCategoryConfiguration(plugins: [
6161
"awsDataStorePlugin": true

AmplifyPlugins/DataStore/AWSDataStoreCategoryPluginTests/Sync/MutationQueue/AWSMutationEventIngesterTests.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@ class AWSMutationEventIngesterTests: XCTestCase {
4444

4545
let publisher = DataStorePublisher()
4646
let dataStorePlugin = AWSDataStorePlugin(modelRegistration: TestModelRegistration(),
47-
storageEngine: storageEngine,
48-
dataStorePublisher: publisher)
47+
storageEngine: storageEngine,
48+
dataStorePublisher: publisher)
4949

5050
try Amplify.add(plugin: apiPlugin)
5151
try Amplify.add(plugin: dataStorePlugin)

AmplifyPlugins/DataStore/AWSDataStoreCategoryPluginTests/Sync/RemoteSync/RemoteSyncAPIInvocationTests.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,8 @@ class RemoteSyncAPIInvocationTests: XCTestCase {
5050

5151
let dataStorePublisher = DataStorePublisher()
5252
let dataStorePlugin = AWSDataStorePlugin(modelRegistration: TestModelRegistration(),
53-
storageEngine: storageEngine,
54-
dataStorePublisher: dataStorePublisher)
53+
storageEngine: storageEngine,
54+
dataStorePublisher: dataStorePublisher)
5555

5656
let apiConfig = APICategoryConfiguration(plugins: [apiPlugin.key: true])
5757
let dataStoreConfig = DataStoreCategoryConfiguration(plugins: [dataStorePlugin.key: true])

AmplifyPlugins/DataStore/AWSDataStoreCategoryPluginTests/Sync/SubscriptionSync/ModelReconciliationDeleteTests.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ class ModelReconciliationDeleteTests: SyncEngineTestBase {
153153
let syncReceivedNotification = expectation(description: "Received 'syncReceived' update from Hub")
154154
let syncReceivedToken = Amplify.Hub.listen(to: .dataStore,
155155
eventName: HubPayload.EventName.DataStore.syncReceived) { _ in
156-
syncReceivedNotification.fulfill()
156+
syncReceivedNotification.fulfill()
157157
}
158158
guard try HubListenerTestUtilities.waitForListener(with: syncReceivedToken, timeout: 5.0) else {
159159
XCTFail("Sync listener never registered")

AmplifyPlugins/DataStore/DataStoreCategoryPlugin.xcodeproj/project.pbxproj

+9-5
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@
7474
9BDB42C47E6D7F9A113AE558 /* Pods_HostApp.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9C6448DF009E54C11ACE4515 /* Pods_HostApp.framework */; };
7575
B912D1B824296F1E0028F05C /* QueryPaginationInput+SQLite.swift in Sources */ = {isa = PBXBuildFile; fileRef = B912D1B724296F1E0028F05C /* QueryPaginationInput+SQLite.swift */; };
7676
B912D1BA242984D10028F05C /* QueryPaginationInputTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B912D1B9242984D10028F05C /* QueryPaginationInputTests.swift */; };
77+
B9334BA22433AF3E00C9F407 /* DataStoreConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9334BA12433AF3E00C9F407 /* DataStoreConfiguration.swift */; };
7778
B996FC4723FF3C7C006D0F68 /* ExampleWithEveryType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B996FC4623FF3C7C006D0F68 /* ExampleWithEveryType.swift */; };
7879
B996FC4923FF3E92006D0F68 /* ExampleWithEveryType+Schema.swift in Sources */ = {isa = PBXBuildFile; fileRef = B996FC4823FF3E92006D0F68 /* ExampleWithEveryType+Schema.swift */; };
7980
B996FC4B23FF418C006D0F68 /* SQLModelValueConverterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B996FC4A23FF418C006D0F68 /* SQLModelValueConverterTests.swift */; };
@@ -256,6 +257,7 @@
256257
AA98AF8502498A6DD04B5B9D /* Pods-HostApp.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-HostApp.release.xcconfig"; path = "Target Support Files/Pods-HostApp/Pods-HostApp.release.xcconfig"; sourceTree = "<group>"; };
257258
B912D1B724296F1E0028F05C /* QueryPaginationInput+SQLite.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "QueryPaginationInput+SQLite.swift"; sourceTree = "<group>"; };
258259
B912D1B9242984D10028F05C /* QueryPaginationInputTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QueryPaginationInputTests.swift; sourceTree = "<group>"; };
260+
B9334BA12433AF3E00C9F407 /* DataStoreConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataStoreConfiguration.swift; sourceTree = "<group>"; };
259261
B996FC4623FF3C7C006D0F68 /* ExampleWithEveryType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExampleWithEveryType.swift; sourceTree = "<group>"; };
260262
B996FC4823FF3E92006D0F68 /* ExampleWithEveryType+Schema.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ExampleWithEveryType+Schema.swift"; sourceTree = "<group>"; };
261263
B996FC4A23FF418C006D0F68 /* SQLModelValueConverterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SQLModelValueConverterTests.swift; sourceTree = "<group>"; };
@@ -402,11 +404,12 @@
402404
2149E5A62388684F00873955 /* AWSDataStoreCategoryPlugin */ = {
403405
isa = PBXGroup;
404406
children = (
405-
2149E5C32388684F00873955 /* Info.plist */,
406407
2149E5C42388684F00873955 /* AWSDataStorePlugin.swift */,
407408
FACBB2AD238AFAE800C29602 /* AWSDataStorePlugin+DataStoreBaseBehavior.swift */,
408409
FA5D4CEE238AFCBC00D2F54A /* AWSDataStorePlugin+DataStoreSubscribeBehavior.swift */,
409410
FA5D4CEC238AFC4D00D2F54A /* AWSDataStorePlugin+DefaultLogger.swift */,
411+
B9334BA12433AF3E00C9F407 /* DataStoreConfiguration.swift */,
412+
2149E5C32388684F00873955 /* Info.plist */,
410413
2149E5A72388684F00873955 /* Storage */,
411414
2149E5B82388684F00873955 /* Subscribe */,
412415
2149E5BA2388684F00873955 /* Sync */,
@@ -779,14 +782,14 @@
779782
isa = PBXGroup;
780783
children = (
781784
B9E010E3239167E000DCE8C8 /* TestModelRegistration.swift */,
785+
6B64027823E3584300001FD7 /* MockAWSIncomingEventReconciliationQueue.swift */,
786+
6BDC224123E27324007C8410 /* MockAWSInitialSyncOrchestrator.swift */,
787+
6B64027A23E38B9900001FD7 /* MockOutgoingMutationQueue.swift */,
782788
FAF5287A2399814F0053A717 /* MockReconciliationQueue.swift */,
789+
6BC4FDA923A899680027D20C /* MockRequestRetryablePolicy.swift */,
783790
6B4E3DF52397327E00AD962B /* MockStateMachine.swift */,
784791
FA8D932E239EA5C4001ED336 /* NoOpInitialSyncOrchestrator.swift */,
785792
FA23345B23955CEF009BEFE9 /* NoOpMutationQueue.swift */,
786-
6BC4FDA923A899680027D20C /* MockRequestRetryablePolicy.swift */,
787-
6BDC224123E27324007C8410 /* MockAWSInitialSyncOrchestrator.swift */,
788-
6B64027823E3584300001FD7 /* MockAWSIncomingEventReconciliationQueue.swift */,
789-
6B64027A23E38B9900001FD7 /* MockOutgoingMutationQueue.swift */,
790793
);
791794
path = Mocks;
792795
sourceTree = "<group>";
@@ -1271,6 +1274,7 @@
12711274
2149E5C72388684F00873955 /* StorageEngine.swift in Sources */,
12721275
FA3B3F05238F22F5002EFDB3 /* OutgoingMutationQueue+Action.swift in Sources */,
12731276
FAED573E238B4C2F008EBED8 /* StorageEngineAdapter+UntypedModel.swift in Sources */,
1277+
B9334BA22433AF3E00C9F407 /* DataStoreConfiguration.swift in Sources */,
12741278
FA4A9559239ACC1B008E876E /* IncomingSubscriptionEventPublisher.swift in Sources */,
12751279
FA8F4D222395B11700861D91 /* MutationEvent+Query.swift in Sources */,
12761280
FAF7CECB238C72830095547B /* OutgoingMutationQueue.swift in Sources */,

0 commit comments

Comments
 (0)