Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(DataStore): DisableSubscriptions flag for watchOS #3368

Merged
merged 9 commits into from
Dec 5, 2023
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1430"
version = "1.7">
version = "1.3">
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will revert

<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ import Foundation
public struct ConflictResolutionDecorator: ModelBasedGraphQLDocumentDecorator {

private let version: Int?
private let lastSync: Int?
private let lastSync: Int64?
private let graphQLType: GraphQLOperationType
private var primaryKeysOnly: Bool

public init(version: Int? = nil,
lastSync: Int? = nil,
lastSync: Int64? = nil,
graphQLType: GraphQLOperationType,
primaryKeysOnly: Bool = true) {
self.version = version
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ protocol ModelSyncGraphQLRequestFactory {
where predicate: QueryPredicate?,
limit: Int?,
nextToken: String?,
lastSync: Int?,
lastSync: Int64?,
authType: AWSAuthorizationType?) -> GraphQLRequest<SyncQueryResult>

}
Expand Down Expand Up @@ -110,7 +110,7 @@ extension GraphQLRequest: ModelSyncGraphQLRequestFactory {
where predicate: QueryPredicate? = nil,
limit: Int? = nil,
nextToken: String? = nil,
lastSync: Int? = nil,
lastSync: Int64? = nil,
authType: AWSAuthorizationType? = nil) -> GraphQLRequest<SyncQueryResult> {
syncQuery(modelSchema: modelType.schema,
where: predicate,
Expand Down Expand Up @@ -215,7 +215,7 @@ extension GraphQLRequest: ModelSyncGraphQLRequestFactory {
where predicate: QueryPredicate? = nil,
limit: Int? = nil,
nextToken: String? = nil,
lastSync: Int? = nil,
lastSync: Int64? = nil,
authType: AWSAuthorizationType? = nil) -> GraphQLRequest<SyncQueryResult> {
var documentBuilder = ModelBasedGraphQLDocumentBuilder(modelSchema: modelSchema,
operationType: .query,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,16 @@ extension Int: GraphQLDocumentValueRepresentable {
}
}

extension Int64: GraphQLDocumentValueRepresentable {
public var graphQLDocumentValue: String {
return "\(self)"
}

public var graphQLInlineValue: String {
return "\(self)"
}
}

extension String: GraphQLDocumentValueRepresentable {
public var graphQLDocumentValue: String {
return self
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ public struct ModelSyncMetadata: Model {
public let id: String

/// The timestamp (in Unix seconds) at which the last sync was started, as reported by the service
public var lastSync: Int?
public var lastSync: Int64?

public init(id: String,
lastSync: Int?) {
lastSync: Int64?) {
self.id = id
self.lastSync = lastSync
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ public struct MutationSync<ModelType: Model>: Decodable {
self.syncMetadata = MutationSyncMetadata(modelId: modelIdentifier,
modelName: resolvedModelName,
deleted: deleted,
lastChangedAt: Int(lastChangedAt),
lastChangedAt: Int64(lastChangedAt),
version: Int(version))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public struct MutationSyncMetadata: Model {

public let id: MutationSyncIdentifier
public var deleted: Bool
public var lastChangedAt: Int
public var lastChangedAt: Int64
public var version: Int

static let deliminator = "|"
Expand All @@ -30,14 +30,14 @@ public struct MutationSyncMetadata: Model {
The format of the `id` has changed to support unique ids across mutiple model types.
Use init(modelId:modelName:deleted:lastChangedAt) to pass in the `modelName`.
""")
public init(id: MutationSyncIdentifier, deleted: Bool, lastChangedAt: Int, version: Int) {
public init(id: MutationSyncIdentifier, deleted: Bool, lastChangedAt: Int64, version: Int) {
self.id = id
self.deleted = deleted
self.lastChangedAt = lastChangedAt
self.version = version
}

public init(modelId: ModelId, modelName: String, deleted: Bool, lastChangedAt: Int, version: Int) {
public init(modelId: ModelId, modelName: String, deleted: Bool, lastChangedAt: Int64, version: Int) {
self.id = Self.identifier(modelName: modelName, modelId: modelId)
self.deleted = deleted
self.lastChangedAt = lastChangedAt
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,5 @@ import Foundation
public struct PaginatedList<ModelType: Model>: Decodable {
public let items: [MutationSync<ModelType>]
public let nextToken: String?
public let startedAt: Int?
public let startedAt: Int64?
}
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ class GraphQLSyncQueryTests: XCTestCase {
XCTAssertEqual(variables["nextToken"] as? String, "token")
XCTAssertNotNil(variables["filter"])
XCTAssertNotNil(variables["lastSync"])
XCTAssertEqual(variables["lastSync"] as? Int, 123)
XCTAssertEqual(variables["lastSync"] as? Int64, 123)
}

func testSyncGraphQLQueryForComment() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ class GraphQLRequestAnyModelWithSyncTests: XCTestCase {
let modelType = Post.self as Model.Type
let nextToken = "nextToken"
let limit = 100
let lastSync = 123
let lastSync: Int64 = 123
var documentBuilder = ModelBasedGraphQLDocumentBuilder(modelSchema: modelType.schema, operationType: .query)
documentBuilder.add(decorator: DirectiveNameDecorator(type: .sync))
documentBuilder.add(decorator: PaginationDecorator(limit: limit, nextToken: nextToken))
Expand Down Expand Up @@ -274,14 +274,14 @@ class GraphQLRequestAnyModelWithSyncTests: XCTestCase {
XCTAssertNotNil(variables["nextToken"])
XCTAssertEqual(variables["nextToken"] as? String, nextToken)
XCTAssertNotNil(variables["lastSync"])
XCTAssertEqual(variables["lastSync"] as? Int, lastSync)
XCTAssertEqual(variables["lastSync"] as? Int64, lastSync)
}

func testOptimizedSyncQueryGraphQLRequestWithFilter() {
let modelType = Post.self as Model.Type
let nextToken = "nextToken"
let limit = 100
let lastSync = 123
let lastSync: Int64 = 123
let postId = "123"
let predicate = Post.CodingKeys.id.eq(postId)
let request = GraphQLRequest<SyncQueryResult>.syncQuery(
Expand Down Expand Up @@ -310,7 +310,7 @@ class GraphQLRequestAnyModelWithSyncTests: XCTestCase {
let modelType = Post.self as Model.Type
let nextToken = "nextToken"
let limit = 100
let lastSync = 123
let lastSync: Int64 = 123
let postId = "123"
let altPostId = "456"
let predicate = Post.CodingKeys.id.eq(postId) || Post.CodingKeys.id.eq(altPostId)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ class GraphQLRequestAuthRuleTests: XCTestCase {
let modelType = Article.self as Model.Type
let nextToken = "nextToken"
let limit = 100
let lastSync = 123
let lastSync: Int64 = 123
var documentBuilder = ModelBasedGraphQLDocumentBuilder(modelSchema: modelType.schema, operationType: .query)
documentBuilder.add(decorator: DirectiveNameDecorator(type: .sync))
documentBuilder.add(decorator: PaginationDecorator(limit: limit, nextToken: nextToken))
Expand Down Expand Up @@ -347,6 +347,6 @@ class GraphQLRequestAuthRuleTests: XCTestCase {
XCTAssertNotNil(variables["nextToken"])
XCTAssertEqual(variables["nextToken"] as? String, nextToken)
XCTAssertNotNil(variables["lastSync"])
XCTAssertEqual(variables["lastSync"] as? Int, lastSync)
XCTAssertEqual(variables["lastSync"] as? Int64, lastSync)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ class GraphQLRequestSyncCustomPrimaryKeyWithMultipleFieldsTests: XCTestCase {
func testSyncQueryGraphQLRequestWithDateInPK() throws {
let nextToken = "nextToken"
let limit = 100
let lastSync = 123
let lastSync: Int64 = 123
var documentBuilder = ModelBasedGraphQLDocumentBuilder(modelName: CustomerWithMultipleFieldsinPK.modelName,
operationType: .query)
documentBuilder.add(decorator: DirectiveNameDecorator(type: .sync))
Expand Down Expand Up @@ -188,7 +188,7 @@ class GraphQLRequestSyncCustomPrimaryKeyWithMultipleFieldsTests: XCTestCase {
XCTAssertNotNil(variables["nextToken"])
XCTAssertEqual(variables["nextToken"] as? String, nextToken)
XCTAssertNotNil(variables["lastSync"])
XCTAssertEqual(variables["lastSync"] as? Int, lastSync)
XCTAssertEqual(variables["lastSync"] as? Int64, lastSync)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,13 @@ final public class AWSDataStorePlugin: DataStoreCategoryPlugin {
}
}

/// No-argument init that uses defaults for all providers
#if os(watchOS)
/// Initializer
/// - Parameters:
/// - modelRegistration: Register DataStore models.
/// - dataStoreConfiguration: Configuration object for DataStore
public init(modelRegistration: AmplifyModelRegistration,
configuration dataStoreConfiguration: DataStoreConfiguration = .default) {
configuration dataStoreConfiguration: DataStoreConfiguration) {
sebaland marked this conversation as resolved.
Show resolved Hide resolved
self.modelRegistration = modelRegistration
self.configuration = InternalDatastoreConfiguration(
isSyncEnabled: false,
Expand All @@ -77,10 +81,37 @@ final public class AWSDataStorePlugin: DataStoreCategoryPlugin {
self.dataStorePublisher = DataStorePublisher()
self.dispatchedModelSyncedEvents = [:]
}
#else
/// Initializer
/// - Parameters:
/// - modelRegistration: Register DataStore models.
/// - dataStoreConfiguration: Configuration object for DataStore
public init(modelRegistration: AmplifyModelRegistration,
configuration dataStoreConfiguration: DataStoreConfiguration = .default) {
self.modelRegistration = modelRegistration
self.configuration = InternalDatastoreConfiguration(
isSyncEnabled: false,
validAPIPluginKey: "awsAPIPlugin",
validAuthPluginKey: "awsCognitoAuthPlugin",
pluginConfiguration: dataStoreConfiguration)

self.storageEngineBehaviorFactory =
StorageEngine.init(
isSyncEnabled:
dataStoreConfiguration:
validAPIPluginKey:
validAuthPluginKey:
modelRegistryVersion:
userDefault:
)
self.dataStorePublisher = DataStorePublisher()
self.dispatchedModelSyncedEvents = [:]
}
#endif

/// Internal initializer for testing
init(modelRegistration: AmplifyModelRegistration,
configuration dataStoreConfiguration: DataStoreConfiguration = .default,
configuration dataStoreConfiguration: DataStoreConfiguration = .testDefault(),
storageEngineBehaviorFactory: StorageEngineBehaviorFactory? = nil,
dataStorePublisher: ModelSubcriptionBehavior,
operationQueue: OperationQueue = OperationQueue(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,42 @@ extension DataStoreConfiguration {
public static let defaultSyncMaxRecords: UInt = 10_000
public static let defaultSyncPageSize: UInt = 1_000

#if os(watchOS)
/// Creates a custom configuration. The only required property is `conflictHandler`.
///
/// - Parameters:
/// - errorHandler: a callback function called on unhandled errors
/// - conflictHandler: a callback called when a conflict could not be resolved by the service
/// - syncInterval: how often the sync engine will run (in seconds)
/// - syncMaxRecords: the number of records to sync per execution
/// - syncPageSize: the page size of each sync execution
/// - authModeStrategy: authorization strategy (.default | multiauth)
sebaland marked this conversation as resolved.
Show resolved Hide resolved
/// - disableSubscriptions: called before establishing subscriptions. Return true to disable subscriptions.
/// - Returns: an instance of `DataStoreConfiguration` with the passed parameters.
public static func custom(
errorHandler: @escaping DataStoreErrorHandler = { error in
Amplify.Logging.error(error: error)
},
conflictHandler: @escaping DataStoreConflictHandler = { _, resolve in
resolve(.applyRemote)
},
syncInterval: TimeInterval = DataStoreConfiguration.defaultSyncInterval,
syncMaxRecords: UInt = DataStoreConfiguration.defaultSyncMaxRecords,
syncPageSize: UInt = DataStoreConfiguration.defaultSyncPageSize,
syncExpressions: [DataStoreSyncExpression] = [],
authModeStrategy: AuthModeStrategyType = .default,
disableSubscriptions: @escaping () -> Bool
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This name is a bit confusing, as it's actually more of a "delegate" callback than a setter.

How about areSubscriptionsDisabled or something like that?
Alternatively we can make this an actual non-optional delegate, but it's probably an overkill at this point.

) -> DataStoreConfiguration {
return DataStoreConfiguration(errorHandler: errorHandler,
conflictHandler: conflictHandler,
syncInterval: syncInterval,
syncMaxRecords: syncMaxRecords,
syncPageSize: syncPageSize,
syncExpressions: syncExpressions,
authModeStrategy: authModeStrategy,
disableSubscriptions: disableSubscriptions)
}
#else
/// Creates a custom configuration. The only required property is `conflictHandler`.
///
/// - Parameters:
Expand Down Expand Up @@ -46,10 +82,32 @@ extension DataStoreConfiguration {
syncExpressions: syncExpressions,
authModeStrategy: authModeStrategy)
}

#endif

#if os(watchOS)
/// Default configuration with subscriptions disabled for watchOS. DataStore uses subscriptions via websockets,
/// which work on the watchOS simulator but not on the device. Running DataStore on watchOS with subscriptions
/// enabled is only possible during special circumstances such as actively streaming audio.
/// See https://github.com/aws-amplify/amplify-swift/pull/3368 for more details.
public static var subscriptionsDisabled: DataStoreConfiguration {
.custom(disableSubscriptions: { false })
}
sebaland marked this conversation as resolved.
Show resolved Hide resolved
#else
/// The default configuration.
public static var `default`: DataStoreConfiguration {
.custom()
}

#endif

#if os(watchOS)
/// Internal method for testing
static func testDefault(disableSubscriptions: @escaping () -> Bool = { false }) -> DataStoreConfiguration {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not a fan of the name, but I also can't think of anything other than internalDefault, which I equally dislike 😅

.custom(disableSubscriptions: disableSubscriptions)
}
#else
/// Internal method for testing
static func testDefault() -> DataStoreConfiguration {
.custom()
}
#endif
}
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,27 @@ public struct DataStoreConfiguration {
/// Authorization mode strategy
public var authModeStrategyType: AuthModeStrategyType

public let disableSubscriptions: () -> Bool

#if os(watchOS)
init(errorHandler: @escaping DataStoreErrorHandler,
conflictHandler: @escaping DataStoreConflictHandler,
syncInterval: TimeInterval,
syncMaxRecords: UInt,
syncPageSize: UInt,
syncExpressions: [DataStoreSyncExpression],
authModeStrategy: AuthModeStrategyType = .default,
disableSubscriptions: @escaping () -> Bool) {
self.errorHandler = errorHandler
self.conflictHandler = conflictHandler
self.syncInterval = syncInterval
self.syncMaxRecords = syncMaxRecords
self.syncPageSize = syncPageSize
self.syncExpressions = syncExpressions
self.authModeStrategyType = authModeStrategy
self.disableSubscriptions = disableSubscriptions
}
#else
init(errorHandler: @escaping DataStoreErrorHandler,
conflictHandler: @escaping DataStoreConflictHandler,
syncInterval: TimeInterval,
Expand All @@ -84,6 +105,7 @@ public struct DataStoreConfiguration {
self.syncPageSize = syncPageSize
self.syncExpressions = syncExpressions
self.authModeStrategyType = authModeStrategy
self.disableSubscriptions = { false }
}

#endif
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ extension MutationSyncMetadataMigration {
public struct MutationSyncMetadataCopy: Model {
public let id: String
public var deleted: Bool
public var lastChangedAt: Int
public var lastChangedAt: Int64
public var version: Int

// MARK: - CodingKeys
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,13 @@ public struct SQLiteModelValueConverter: ModelValueConverter {
case .string:
return value as? String
case .int:
return value as? Int
if let intValue = value as? Int {
return intValue
}
if let int64Value = value as? Int64 {
return int64Value
}
return nil
case .double:
return value as? Double
case .date, .dateTime, .time:
Expand Down
Loading