realm-swift
realm-swift copied to clipboard
Flexible Sync V2 QBS (Proposed 2)
This PR contains a complete new QBS API for Flexible Sync, intended to make flexible sync less confusing to the developer, this proposal use a query based subscription API, which makes use of async await
to be able to add a subscription and bootstrap data from it.
let app = App(id: "my-app-id")
let user = try await app.login(credentials: .anonymous)
let realm = try await Realm(configuration: user.flexibleSyncConfiguration())
// You can subscribe and get a Result, using the async `function objects<>` API
let persons = try await realm.objects(SwiftPerson.self) // All documents for this object type
let dogs = try await realm.objects(SwiftDog.self, where: { $0.breed != "labradoodle" })
let birds = try await realm.objects(Bird.self, where: { $0.species.in(BirdSpecies.allCases) })
print(persons.count) //20
let newPerson = Person()
newPerson.age = 18
try realm.write {
realm.add(newPerson)
}
// Updating a subscription is as easy as sub querying over the results
let newPerson = try await persons.where { $0.age > 18 }
// Unsubscribe will remove the values from the Realm and the Results collection and remove the subscription from the subscription set.
try await persons.unsubscribe()
// Reusing a Subscription is as easy as getting a `Results` for the same query.
let persons = try await realm.objects(SwiftPerson.self, where: { $0.age > 12 })
// 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, ObservedResults will subscribe to the query provided on the initialiser if this is a flexible sync realm app.
We are adding a new property to @ObservedResults
which 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()
}
}
}
}
}
@jsflax I already made all the changes to this Proposal, this will need a review before MDBW.