Skip to content

Commit

Permalink
refactor(datastore): Escape hatch for nonmodeltype subcsription (aws-…
Browse files Browse the repository at this point in the history
…amplify#876)

Adds support for the datastore plugin to subscribe to events based on the model name instead of Model.Type.

- Moved internal methods used by AWSDataStorePublisher to a protocol ModelSubcriptionBehavior
- Added a new property var publisher: AnyPublisher<MutationEvent, DataStoreError> to ModelSubcriptionBehavior
- Copied test for Local subscription to use json serialized model.
  • Loading branch information
royjit authored Nov 10, 2020
1 parent f0e004f commit 85a8870
Show file tree
Hide file tree
Showing 8 changed files with 380 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -177,9 +177,7 @@ extension AWSDataStorePlugin: DataStoreBaseBehavior {
storageEngine.clear { result in
self.storageEngine = nil
if #available(iOS 13.0, *) {
if let publisher = self.dataStorePublisher as? DataStorePublisher {
publisher.sendFinished()
}
self.dataStorePublisher?.sendFinished()
}
self.dataStorePublisher = nil
completion(result)
Expand Down Expand Up @@ -221,9 +219,7 @@ extension AWSDataStorePlugin: DataStoreBaseBehavior {
modelSchema: modelSchema,
mutationType: mutationType,
version: syncMetadata?.version)
if let publisher = self.dataStorePublisher as? DataStorePublisher {
publisher.send(input: mutationEvent)
}
self.dataStorePublisher?.send(input: mutationEvent)
} catch {
self.log.error(error: error)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,22 @@ import Amplify
import Combine

extension AWSDataStorePlugin: DataStoreSubscribeBehavior {

@available(iOS 13.0, *)
public var publisher: AnyPublisher<MutationEvent, DataStoreError> {
reinitStorageEngineIfNeeded()
// Force-unwrapping: The optional 'dataStorePublisher' is expected
// to exist for deployment targets >=iOS13.0
return dataStorePublisher!.publisher
}

@available(iOS 13.0, *)
public func publisher<M: Model>(for modelType: M.Type) -> AnyPublisher<MutationEvent, DataStoreError> {
return publisher(for: modelType.modelName)
}

@available(iOS 13.0, *)
public func publisher<M: Model>(for modelType: M.Type)
-> AnyPublisher<MutationEvent, DataStoreError> {
reinitStorageEngineIfNeeded()
// Force-unwrapping: The optional 'dataStorePublisher' is expected
// to exist for deployment targets >=iOS13.0
return dataStorePublisher!.publisher(for: modelType)
public func publisher(for modelName: ModelName) -> AnyPublisher<MutationEvent, DataStoreError> {
return publisher.filter { $0.modelName == modelName }.eraseToAnyPublisher()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ final public class AWSDataStorePlugin: DataStoreCategoryPlugin {
var isSyncEnabled: Bool

/// The Publisher that sends mutation events to subscribers
var dataStorePublisher: DataStoreSubscribeBehavior?
var dataStorePublisher: ModelSubcriptionBehavior?

let modelRegistration: AmplifyModelRegistration

Expand Down Expand Up @@ -64,7 +64,7 @@ final public class AWSDataStorePlugin: DataStoreCategoryPlugin {
init(modelRegistration: AmplifyModelRegistration,
configuration dataStoreConfiguration: DataStoreConfiguration = .default,
storageEngine: StorageEngineBehavior,
dataStorePublisher: DataStoreSubscribeBehavior,
dataStorePublisher: ModelSubcriptionBehavior,
validAPIPluginKey: String,
validAuthPluginKey: String) {
self.modelRegistration = modelRegistration
Expand Down Expand Up @@ -144,7 +144,7 @@ final public class AWSDataStorePlugin: DataStoreCategoryPlugin {

@available(iOS 13.0, *)
private func onReceiveCompletion(completed: Subscribers.Completion<DataStoreError>) {
guard let dataStorePublisher = self.dataStorePublisher as? DataStorePublisher else {
guard let dataStorePublisher = self.dataStorePublisher else {
log.error("Data store publisher not initalized")
return
}
Expand All @@ -158,7 +158,7 @@ final public class AWSDataStorePlugin: DataStoreCategoryPlugin {

@available(iOS 13.0, *)
private func onRecieveValue(receiveValue: StorageEngineEvent) {
guard let dataStorePublisher = self.dataStorePublisher as? DataStorePublisher else {
guard let dataStorePublisher = self.dataStorePublisher else {
log.error("Data store publisher not initalized")
return
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,13 @@
import Amplify
import Combine

// TODO: Should this be a multicast publisher?
@available(iOS 13.0, *)
struct DataStorePublisher: DataStoreSubscribeBehavior {
struct DataStorePublisher: ModelSubcriptionBehavior {

private let subject = PassthroughSubject<MutationEvent, DataStoreError>()

func publisher<M: Model>(for modelType: M.Type) -> AnyPublisher<MutationEvent, DataStoreError> {
return subject
.filter { $0.modelName == modelType.modelName }
.eraseToAnyPublisher()
var publisher: AnyPublisher<MutationEvent, DataStoreError> {
return subject.eraseToAnyPublisher()
}

func send(input: MutationEvent) {
Expand All @@ -32,3 +29,15 @@ struct DataStorePublisher: DataStoreSubscribeBehavior {
subject.send(completion: .finished)
}
}

protocol ModelSubcriptionBehavior {

@available(iOS 13.0, *)
var publisher: AnyPublisher<MutationEvent, DataStoreError> { get }

func send(input: MutationEvent)

func send(dataStoreError: DataStoreError)

func sendFinished()
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,23 @@ import Amplify
struct DynamicModel: Model, JSONValueHolder {

public let id: String
public let values: [String: JSONValue]
public var values: [String: JSONValue]

public init(id: String = UUID().uuidString, values: [String: JSONValue]) {
public init(id: String = UUID().uuidString,
values: [String: JSONValue]) {
self.id = id
self.values = values
var valueWIthId = values
valueWIthId["id"] = .string(id)
self.values = valueWIthId
}

public init(from decoder: Decoder) throws {

print("DEncode \(decoder)")
let container = try decoder.container(keyedBy: CodingKeys.self)
id = try container.decode(String.self, forKey: .id)
values = try decoder.singleValueContainer().decode([String: JSONValue].self)
}

public func encode(to encoder: Encoder) throws {
print("Encode")
var container = encoder.unkeyedContainer()
try container.encode(values)
}
Expand Down Expand Up @@ -58,6 +58,20 @@ struct DynamicModel: Model, JSONValueHolder {
if case .int = field?.type,
case .some(.number(let deserializedValue)) = values[key] {
return Int(deserializedValue)

} else if case .dateTime = field?.type,
case .some(.string(let deserializedValue)) = values[key] {

return try? Temporal.DateTime(iso8601String: deserializedValue)

} else if case .date = field?.type,
case .some(.string(let deserializedValue)) = values[key] {
return try? Temporal.Date(iso8601String: deserializedValue)

} else if case .time = field?.type,
case .some(.string(let deserializedValue)) = values[key] {
return try? Temporal.Time(iso8601String: deserializedValue)

}
return jsonValue(for: key)
}
Expand Down
Loading

0 comments on commit 85a8870

Please sign in to comment.