Skip to content

Add pull responses to Subscription for publishable VM #71

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

Merged
merged 4 commits into from
Jan 27, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,9 @@ jobs:
uses: actions/cache@v2
with:
path: vendor/bundle
key: ${{ runner.os }}-gem-v1-${{ hashFiles('**/Gemfile.lock') }}
key: ${{ runner.os }}-gem-v2-${{ hashFiles('**/Gemfile.lock') }}
restore-keys: |
${{ runner.os }}-gem-v1
${{ runner.os }}-gem-v2
- name: Install Bundle
run: |
bundle config path vendor/bundle
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ jobs:
uses: actions/cache@v2
with:
path: vendor/bundle
key: ${{ runner.os }}-gem-v1-${{ hashFiles('**/Gemfile.lock') }}
key: ${{ runner.os }}-gem-v2-${{ hashFiles('**/Gemfile.lock') }}
restore-keys: |
${{ runner.os }}-gem-v1
${{ runner.os }}-gem-v2
- name: Install Bundle
run: |
bundle config path vendor/bundle
Expand Down
202 changes: 201 additions & 1 deletion Sources/ParseSwift/LiveQuery/Subscription.swift
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ private func == <T>(lhs: Event<T>, rhs: Event<T>) -> Bool {
/**
A default implementation of the `ParseSubscription` protocol. Suitable for `ObjectObserved`
as the subscription can be used as a SwiftUI publisher. Meaning it can serve
indepedently as a ViewModel in MVVM.
indepedently as a ViewModel in MVVM. Also provides a publisher for pull responses of query such as:
`find`, `first`, `count`, and `aggregate`.
*/
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
open class Subscription<T: ParseObject>: ParseSubscription, ObservableObject {
Expand Down Expand Up @@ -102,6 +103,57 @@ open class Subscription<T: ParseObject>: ParseSubscription, ObservableObject {
}
}

/// The objects found in a `find`, `first`, or `aggregate`
/// query.
/// - note: this will only countain one item for `first`.
public internal(set) var results: [T]? {
willSet {
if newValue != nil {
resultsCodable = nil
count = nil
error = nil
objectWillChange.send()
}
}
}

/// The number of items found in a `count` query.
public internal(set) var count: Int? {
willSet {
if newValue != nil {
results = nil
resultsCodable = nil
error = nil
objectWillChange.send()
}
}
}

/// Results of a `explain` or `hint` query.
public internal(set) var resultsCodable: AnyCodable? {
willSet {
if newValue != nil {
results = nil
count = nil
error = nil
objectWillChange.send()
}
}
}

/// If an error occured during a `find`, `first`, `count`, or `aggregate`
/// query.
public internal(set) var error: ParseError? {
willSet {
if newValue != nil {
count = nil
results = nil
resultsCodable = nil
objectWillChange.send()
}
}
}

/**
Creates a new subscription that can be used to handle updates.
*/
Expand All @@ -128,6 +180,154 @@ open class Subscription<T: ParseObject>: ParseSubscription, ObservableObject {
open func didUnsubscribe() {
self.unsubscribed = query
}

/**
Finds objects and publishes them as `results` afterwards.

- parameter options: A set of header options sent to the server. Defaults to an empty set.
- parameter callbackQueue: The queue to return to after completion. Default value of `.main`.
*/
open func find(options: API.Options = [], callbackQueue: DispatchQueue = .main) {
query.find(options: options, callbackQueue: callbackQueue) { result in
switch result {

case .success(let results):
self.results = results
case .failure(let error):
self.error = error
}
}
}

/**
Finds objects and publishes them as `resultsCodable` afterwards.

- parameter explain: Used to toggle the information on the query plan.
- parameter hint: String or Object of index that should be used when executing query.
- parameter options: A set of header options sent to the server. Defaults to an empty set.
- parameter callbackQueue: The queue to return to after completion. Default value of `.main`.
*/
open func find(explain: Bool,
hint: String? = nil,
options: API.Options = [],
callbackQueue: DispatchQueue = .main) {
query.find(explain: explain, hint: hint, options: options, callbackQueue: callbackQueue) { result in
switch result {

case .success(let results):
self.resultsCodable = results
case .failure(let error):
self.error = error
}
}
}

/**
Gets an object and publishes them as `results` afterwards.

- warning: This method mutates the query. It will reset the limit to `1`.
- parameter options: A set of header options sent to the server. Defaults to an empty set.
- parameter callbackQueue: The queue to return to after completion. Default value of `.main`.
*/
open func first(options: API.Options = [], callbackQueue: DispatchQueue = .main) {
query.first(options: options, callbackQueue: callbackQueue) { result in
switch result {

case .success(let results):
self.results = [results]
case .failure(let error):
self.error = error
}
}
}

/**
Gets an object and publishes them as `resultsCodable` afterwards.

- warning: This method mutates the query. It will reset the limit to `1`.
- parameter explain: Used to toggle the information on the query plan.
- parameter hint: String or Object of index that should be used when executing query.
- parameter options: A set of header options sent to the server. Defaults to an empty set.
- parameter callbackQueue: The queue to return to after completion. Default value of `.main`.
*/
open func first(explain: Bool,
hint: String? = nil,
options: API.Options = [],
callbackQueue: DispatchQueue = .main) {
query.first(explain: explain, hint: hint, options: options, callbackQueue: callbackQueue) { result in
switch result {

case .success(let results):
self.resultsCodable = results
case .failure(let error):
self.error = error
}
}
}

/**
Counts objects and publishes them as `count` afterwards.

- parameter options: A set of header options sent to the server. Defaults to an empty set.
- parameter callbackQueue: The queue to return to after completion. Default value of `.main`.
*/
open func count(options: API.Options = [], callbackQueue: DispatchQueue = .main) {
query.count(options: options, callbackQueue: callbackQueue) { result in
switch result {

case .success(let results):
self.count = results
case .failure(let error):
self.error = error
}
}
}

/**
Counts objects and publishes them as `resultsCodable` afterwards.

- parameter explain: Used to toggle the information on the query plan.
- parameter hint: String or Object of index that should be used when executing query.
- parameter options: A set of header options sent to the server. Defaults to an empty set.
- parameter callbackQueue: The queue to return to after completion. Default value of `.main`.
*/
open func count(explain: Bool,
hint: String? = nil,
options: API.Options = [],
callbackQueue: DispatchQueue = .main) {
query.count(explain: explain, hint: hint, options: options) { result in
switch result {

case .success(let results):
self.resultsCodable = results
case .failure(let error):
self.error = error
}
}
}

/**
Executes an aggregate query and publishes the results as `results` afterwards.

- requires: `.useMasterKey` has to be available and passed as one of the set of `options`.
- parameter pipeline: A pipeline of stages to process query.
- parameter options: A set of header options sent to the server. Defaults to an empty set.
- parameter callbackQueue: The queue to return to after completion. Default value of `.main`.
- warning: This hasn't been tested thoroughly.
*/
open func aggregate(_ pipeline: Query<T>.AggregateType,
options: API.Options = [],
callbackQueue: DispatchQueue = .main) {
query.aggregate(pipeline, options: options, callbackQueue: callbackQueue) { result in
switch result {

case .success(let results):
self.results = results
case .failure(let error):
self.error = error
}
}
}
}
#endif

Expand Down
8 changes: 4 additions & 4 deletions Sources/ParseSwift/Types/Query.swift
Original file line number Diff line number Diff line change
Expand Up @@ -853,7 +853,7 @@ extension Query: Queryable {
- parameter options: A set of header options sent to the server. Defaults to an empty set.
- parameter callbackQueue: The queue to return to after completion. Default value of `.main`.
- parameter completion: The block to execute.
It should have the following argument signature: `(Result<[ResultType], ParseError>)`
It should have the following argument signature: `(Result<[ResultType], ParseError>)`.
*/
public func find(options: API.Options = [], callbackQueue: DispatchQueue = .main,
completion: @escaping (Result<[ResultType], ParseError>) -> Void) {
Expand All @@ -872,7 +872,7 @@ extension Query: Queryable {
- parameter options: A set of header options sent to the server. Defaults to an empty set.
- parameter callbackQueue: The queue to return to after completion. Default value of .main.
- parameter completion: The block to execute.
It should have the following argument signature: `(Result<[AnyResultType], ParseError>)`
It should have the following argument signature: `(Result<[AnyResultType], ParseError>)`.
*/
public func find(explain: Bool, hint: String? = nil, options: API.Options = [],
callbackQueue: DispatchQueue = .main,
Expand Down Expand Up @@ -1012,7 +1012,7 @@ extension Query: Queryable {
- parameter options: A set of header options sent to the server. Defaults to an empty set.
- parameter callbackQueue: The queue to return to after completion. Default value of `.main`.
- parameter completion: The block to execute.
It should have the following argument signature: `(Result<Int, ParseError>)`
It should have the following argument signature: `(Result<Int, ParseError>)`.
*/
public func count(explain: Bool, hint: String? = nil, options: API.Options = [],
callbackQueue: DispatchQueue = .main,
Expand Down Expand Up @@ -1059,7 +1059,7 @@ extension Query: Queryable {
- parameter options: A set of header options sent to the server. Defaults to an empty set.
- parameter callbackQueue: The queue to return to after completion. Default value of `.main`.
- parameter completion: The block to execute.
It should have the following argument signature: `(Result<Int, ParseError>)`
It should have the following argument signature: `(Result<[ResultType], ParseError>)`.
- warning: This hasn't been tested thoroughly.
*/
public func aggregate(_ pipeline: AggregateType,
Expand Down
Loading