realm-swift icon indicating copy to clipboard operation
realm-swift copied to clipboard

Flexible Sync V2 (Proposed 1)

Open dianaafanador3 opened this issue 2 years ago • 1 comments

This PR contains a complete new API for Flexible Sync, intended to make flexible sync less confusing to the developer.

let app = App(id: "my-app-id")
let user = try await app.login(credentials: .anonymous)
let realm = try user.realm(configuration: .defaultConfiguration)

// You can subscribe and get `QueryResults` from 1-12 queries at the same time, this subscriptions will be done within a batch write
let (persons, dogs, birds) = try await realm.subscriptions.subscribe(to: 
QuerySubscription<Person> { $0.age >= 18}, 
QuerySubscription<Dog>(), //Intended to query all elements for this object 
QuerySubscription<Bird> { $0.species == .magpie })

print(persons.count) //20

let newPerson = Person()
newPerson.age = 18
try realm.write {
    realm.add(newPerson)
}

// QueryResults will be updated if the values are within the subscription query 
print(persons.count) //21 

// Unsubscribe will remove the values from the `QueryResult` and remove the subscription from the subscription set.
try await persons.unsubscribe()

// Reusing a `QueryResults` is as easy as calling again subscribe for the same query
let persons: QueryResults<Person>= try await realm.subscriptions.subscribe(to: { $0.age >= 18 })
// Or search in your subscription set
let foundedSubscription = realm.subscriptions.first(ofType: SwiftPerson.self, where: { { $0.age >= 18 })

// You can use unsubscribeAll to remove all subscriptions from the subscription set
try await realm.subscriptions.unsubscribeAll()

// Or you can remove them by type
try await realm.subscriptions.unsubscribeAll(ofType: Person.self)

SwiftUI You can use @ObservedResults to add a subscription and retrieve data from it We are adding a new property to @ObservedResultswhich includes a state value, this state will publish any subscription state changes to view.

public enum SubscriptionState {
    case pending //Subscription has been added and waiting for data to bootstrap.
    case error(Error) // An error has occurred while adding the subscription (client or server side)
    case completed // Data has been bootstrapped and query results updated.
}
@available(macOS 12.0, *)
struct ObservedQueryResultsStateView: View {
    @ObservedResults(Person.self, where: { $0.age > 18 && $0.firstName == ProcessInfo.processInfo.environment["firstName"]! })
    var persons

    var body: some View {
        VStack {
            switch $persons.state {
            case .pending:
                ProgressView()
            case .completed:
                List {
                    ForEach(persons) { person in
                        Text("\(person.firstName)")
                    }
                }
            case .error(let error):
                ErrorView(error: error)
                    .background(Color.red)
                    .transition(AnyTransition.move(edge: .trailing)).animation(.default)
            }
        }
    }
}

@available(macOS 12.0, *)
struct ObservedQueryResultsView: View {
    @ObservedResults(Person.self,  where: { $0.age >= 15 && $0.firstName == ProcessInfo.processInfo.environment["firstName"]! })
    var persons
    @State var searchFilter: String = ""

    var body: some View {
        VStack {
            if persons.isEmpty {
                ProgressView()
            } else {
                List {
                    ForEach(persons) { person in
                        HStack {
                            Text("\(person.firstName)")
                            Spacer()
                            Text("\(person.age)")
                        }
                    }
                }
            }
        }
        .onDisappear {
            Task {
                do {
                    try await $persons.unsubscribe()
                }
            }
        }
    }
}

Notes

  • AnyQueryResults??, didn't add the implementation for using this as a collection, which can be added if needed but I don’t consider this to be a priority, which brings me to the issue if the user is really going to use this instead of doing a search for the query or subscribe again to the query which will retrieve the results without adding another subscription.

dianaafanador3 avatar Apr 21 '22 20:04 dianaafanador3