Skip to content

Commit

Permalink
feat: Add fetchAll method for Parse pointers (#141)
Browse files Browse the repository at this point in the history
* feat: Add fetchAll method for Parse pointers

* add fetchAll methods

* Update project

* add test cases

* nit

* nits
  • Loading branch information
cbaker6 authored Jan 9, 2024
1 parent 7b3e48b commit 0cc07eb
Show file tree
Hide file tree
Showing 12 changed files with 467 additions and 93 deletions.
8 changes: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,15 @@
# Parse-Swift Changelog

### main
[Full Changelog](https://github.com/netreconlab/Parse-Swift/compare/5.8.2...main), [Documentation](https://swiftpackageindex.com/netreconlab/Parse-Swift/main/documentation/parseswift)
[Full Changelog](https://github.com/netreconlab/Parse-Swift/compare/5.9.0...main), [Documentation](https://swiftpackageindex.com/netreconlab/Parse-Swift/main/documentation/parseswift)
* _Contributing to this repo? Add info about your change here to be included in the next release_

### 5.9.0
[Full Changelog](https://github.com/netreconlab/Parse-Swift/compare/5.8.2...5.9.0), [Documentation](https://swiftpackageindex.com/netreconlab/Parse-Swift/5.9.0/documentation/parseswift)

__New features__
* Add fetchAll method to array of Parse Pointer Object's ([#141](https://github.com/netreconlab/Parse-Swift/pull/141)), thanks to [Corey Baker](https://github.com/cbaker6).

### 5.8.2
[Full Changelog](https://github.com/netreconlab/Parse-Swift/compare/5.8.1...5.8.2), [Documentation](https://swiftpackageindex.com/netreconlab/Parse-Swift/5.8.2/documentation/parseswift)

Expand Down
16 changes: 15 additions & 1 deletion ParseSwift.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
7003972A25A3B0140052CB31 /* ParseURLSessionDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7003972925A3B0130052CB31 /* ParseURLSessionDelegate.swift */; };
7004C22025B63C7A005E0AD9 /* ParseRelation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7004C21F25B63C7A005E0AD9 /* ParseRelation.swift */; };
7004C24D25B69207005E0AD9 /* ParseRoleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7004C22D25B69077005E0AD9 /* ParseRoleTests.swift */; };
700A8A662B4CC1E40087ADBE /* ParsePointerable+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 700A8A652B4CC1E40087ADBE /* ParsePointerable+async.swift */; };
700A8A682B4CC2700087ADBE /* ParsePointerable+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 700A8A672B4CC2700087ADBE /* ParsePointerable+combine.swift */; };
700AFE03289C3508006C1CD9 /* ParseQueryCacheTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 700AFE02289C3508006C1CD9 /* ParseQueryCacheTests.swift */; };
70110D52250680140091CC1D /* ParseConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70110D51250680140091CC1D /* ParseConstants.swift */; };
70110D572506CE890091CC1D /* BaseParseInstallation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70110D562506CE890091CC1D /* BaseParseInstallation.swift */; };
Expand Down Expand Up @@ -278,6 +280,7 @@
918CED592684C74000CFDC83 /* ParseLiveQuery+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 918CED582684C74000CFDC83 /* ParseLiveQuery+combine.swift */; };
918CED5E268618C600CFDC83 /* ParseLiveQueryCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 918CED5D268618C600CFDC83 /* ParseLiveQueryCombineTests.swift */; };
9194657824F16E330070296B /* ParseACLTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9194657724F16E330070296B /* ParseACLTests.swift */; };
919823652B3A134000E9591A /* ParsePointerable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 919823642B3A134000E9591A /* ParsePointerable.swift */; };
91B40651267A66ED00B129CD /* ParseErrorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91B40650267A66ED00B129CD /* ParseErrorTests.swift */; };
91B79AC326EE3A4E00073F2C /* API+NonParseBodyCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91B79AC226EE3A4E00073F2C /* API+NonParseBodyCommand.swift */; };
91B79AC826EE3C5D00073F2C /* API+BatchCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91B79AC726EE3C5D00073F2C /* API+BatchCommand.swift */; };
Expand Down Expand Up @@ -364,6 +367,8 @@
7003972925A3B0130052CB31 /* ParseURLSessionDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseURLSessionDelegate.swift; sourceTree = "<group>"; };
7004C21F25B63C7A005E0AD9 /* ParseRelation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseRelation.swift; sourceTree = "<group>"; };
7004C22D25B69077005E0AD9 /* ParseRoleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseRoleTests.swift; sourceTree = "<group>"; };
700A8A652B4CC1E40087ADBE /* ParsePointerable+async.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ParsePointerable+async.swift"; sourceTree = "<group>"; };
700A8A672B4CC2700087ADBE /* ParsePointerable+combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ParsePointerable+combine.swift"; sourceTree = "<group>"; };
700AFE02289C3508006C1CD9 /* ParseQueryCacheTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseQueryCacheTests.swift; sourceTree = "<group>"; };
70110D51250680140091CC1D /* ParseConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseConstants.swift; sourceTree = "<group>"; };
70110D562506CE890091CC1D /* BaseParseInstallation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseParseInstallation.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -625,6 +630,7 @@
918CED582684C74000CFDC83 /* ParseLiveQuery+combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ParseLiveQuery+combine.swift"; sourceTree = "<group>"; };
918CED5D268618C600CFDC83 /* ParseLiveQueryCombineTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseLiveQueryCombineTests.swift; sourceTree = "<group>"; };
9194657724F16E330070296B /* ParseACLTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseACLTests.swift; sourceTree = "<group>"; };
919823642B3A134000E9591A /* ParsePointerable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParsePointerable.swift; sourceTree = "<group>"; };
91B40650267A66ED00B129CD /* ParseErrorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseErrorTests.swift; sourceTree = "<group>"; };
91B79AC226EE3A4E00073F2C /* API+NonParseBodyCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "API+NonParseBodyCommand.swift"; sourceTree = "<group>"; };
91B79AC726EE3C5D00073F2C /* API+BatchCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "API+BatchCommand.swift"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -942,6 +948,9 @@
705025EF2851542D008D6624 /* ParsePushFirebasePayloadable.swift */,
705025CB284CE4C2008D6624 /* ParsePushPayloadable.swift */,
70A98D812794AB3C009B58F2 /* ParseQueryScorable.swift */,
919823642B3A134000E9591A /* ParsePointerable.swift */,
700A8A652B4CC1E40087ADBE /* ParsePointerable+async.swift */,
700A8A672B4CC2700087ADBE /* ParsePointerable+combine.swift */,
916E206F29D8C83100C21EC6 /* ParseRelationOperationable.swift */,
70CE0ABB285F8FF900DAEA86 /* ParseTypeable.swift */,
F97B45C824D9C6F200F4A88B /* Queryable.swift */,
Expand Down Expand Up @@ -1410,7 +1419,7 @@
attributes = {
BuildIndependentTargetsInParallel = YES;
LastSwiftUpdateCheck = 1430;
LastUpgradeCheck = 1500;
LastUpgradeCheck = 1520;
ORGANIZATIONNAME = "Network Reconnaissance Lab";
TargetAttributes = {
4AB8B4F31F254AE10070F682 = {
Expand Down Expand Up @@ -1557,6 +1566,7 @@
703B094E26BF47E3005A112F /* ParseTwitter+combine.swift in Sources */,
70386A3825D998D90048EC1B /* ParseLDAP.swift in Sources */,
709A14A02839CABD00BF85E5 /* ParseCLP.swift in Sources */,
700A8A662B4CC1E40087ADBE /* ParsePointerable+async.swift in Sources */,
700395F225A171320052CB31 /* LiveQueryable.swift in Sources */,
70F03A252780BDF700E5AFB4 /* ParseGoogle+async.swift in Sources */,
F97B45F224D9C6F200F4A88B /* Pointer.swift in Sources */,
Expand Down Expand Up @@ -1603,6 +1613,7 @@
7045769326BD8F8100F86F71 /* ParseInstallation+async.swift in Sources */,
7C55F9E72860CD6B002A352D /* ParseSpotify.swift in Sources */,
7034B9FF2A46391200395CBC /* ParseHookFunction.swift in Sources */,
700A8A682B4CC2700087ADBE /* ParsePointerable+combine.swift in Sources */,
7003960925A184EF0052CB31 /* ParseLiveQuery.swift in Sources */,
7044C17525C4ECFF0011F6E7 /* ParseCloudable+combine.swift in Sources */,
705025B32845C302008D6624 /* ParsePushStatus.swift in Sources */,
Expand Down Expand Up @@ -1654,6 +1665,7 @@
F97B45F624D9C6F200F4A88B /* ParseError.swift in Sources */,
7045769D26BD934000F86F71 /* ParseFile+async.swift in Sources */,
F97B463324D9C74400F4A88B /* URLSession.swift in Sources */,
919823652B3A134000E9591A /* ParsePointerable.swift in Sources */,
F97B464E24D9C78B00F4A88B /* ParseOperationAdd.swift in Sources */,
70D41D8028B520E200613510 /* ParseKeychainAccessGroup.swift in Sources */,
70385E762858E1000084D306 /* ParseHookFunctionable.swift in Sources */,
Expand Down Expand Up @@ -1848,6 +1860,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
Expand Down Expand Up @@ -1917,6 +1930,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1500"
LastUpgradeVersion = "1520"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1500"
LastUpgradeVersion = "1520"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
Expand Down
2 changes: 1 addition & 1 deletion Sources/ParseSwift/ParseConstants.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import Foundation

enum ParseConstants {
static let sdk = "swift"
static let version = "5.8.2"
static let version = "5.9.0"
static let fileManagementDirectory = "parse/"
static let fileManagementPrivateDocumentsDirectory = "Private Documents/"
static let fileManagementLibraryDirectory = "Library/"
Expand Down
38 changes: 38 additions & 0 deletions Sources/ParseSwift/Protocols/ParsePointerable+async.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//
// ParsePointerable+async.swift
// ParseSwift
//
// Created by Corey Baker on 1/8/24.
// Copyright © 2024 Network Reconnaissance Lab. All rights reserved.
//

import Foundation

// MARK: Batch Support
public extension Sequence where Element: ParsePointerObject {

/**
Fetches a collection of objects *aynchronously* with the current data from the server and sets
an error if one occurs.
- parameter includeKeys: The name(s) of the key(s) to include that are
`ParseObject`s. Use `["*"]` to include all keys one level deep. This is similar to `include` and
`includeAll` for `Query`.
- parameter options: A set of header options sent to the server. Defaults to an empty set.
- returns: Returns an array of Result enums with the object if a fetch was successful or a
`ParseError` if it failed.
- throws: An error of type `ParseError`.
*/
@discardableResult func fetchAll(
includeKeys: [String]? = nil,
options: API.Options = []
) async throws -> [(Result<Self.Element.Object, ParseError>)] {
try await withCheckedThrowingContinuation { continuation in
self.fetchAll(
includeKeys: includeKeys,
options: options,
completion: continuation.resume
)
}
}

}
41 changes: 41 additions & 0 deletions Sources/ParseSwift/Protocols/ParsePointerable+combine.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//
// ParsePointerable+combine.swift
// ParseSwift
//
// Created by Corey Baker on 1/8/24.
// Copyright © 2024 Network Reconnaissance Lab. All rights reserved.
//

#if canImport(Combine)

import Foundation
import Combine

// MARK: Batch Support
public extension Sequence where Element: ParsePointerObject {

/**
Fetches a collection of objects *aynchronously* with the current data from the server and sets
an error if one occurs. Publishes when complete.
- parameter includeKeys: The name(s) of the key(s) to include that are
`ParseObject`s. Use `["*"]` to include all keys one level deep. This is similar to `include` and
`includeAll` for `Query`.
- parameter options: A set of header options sent to the server. Defaults to an empty set.
- returns: A publisher that eventually produces an an array of Result enums with the object if a fetch was
successful or a `ParseError` if it failed.
*/
func fetchAllPublisher(
includeKeys: [String]? = nil,
options: API.Options = []) -> Future<[(Result<Self.Element.Object, ParseError>)], ParseError> {
Future { promise in
self.fetchAll(
includeKeys: includeKeys,
options: options,
completion: promise
)
}
}

}

#endif
134 changes: 134 additions & 0 deletions Sources/ParseSwift/Protocols/ParsePointerable.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
//
// ParsePointerable.swift
// ParseSwift
//
// Created by Corey Baker on 12/25/23.
// Copyright © 2023 Network Reconnaissance Lab. All rights reserved.
//

import Foundation

public protocol ParsePointer: Encodable {

var __type: String { get } // swiftlint:disable:this identifier_name

var className: String { get }

var objectId: String { get set }
}

extension ParsePointer {
/**
Determines if two objects have the same objectId.
- parameter as: Object to compare.
- returns: Returns a **true** if the other object has the same `objectId` or **false** if unsuccessful.
*/
func hasSameObjectId(as other: any ParsePointer) -> Bool {
return other.className == className && other.objectId == objectId
}
}

public protocol ParsePointerObject: ParsePointer, ParseTypeable, Fetchable, Hashable {
associatedtype Object: ParseObject
}

extension ParsePointerObject {

/**
Convert a Pointer to its respective `ParseObject`.
- returns: A `ParseObject` created from this Pointer.
*/
func toObject() -> Object {
var object = Object()
object.objectId = self.objectId
return object
}

/**
Determines if a `ParseObject` and `Pointer`have the same `objectId`.
- parameter as: `ParseObject` to compare.
- returns: Returns a **true** if the other object has the same `objectId` or **false** if unsuccessful.
*/
func hasSameObjectId(as other: Object) -> Bool {
return other.className == className && other.objectId == objectId
}

/**
Determines if two `Pointer`'s have the same `objectId`.
- parameter as: `Pointer` to compare.
- returns: Returns a **true** if the other object has the same `objectId` or **false** if unsuccessful.
*/
func hasSameObjectId(as other: Self) -> Bool {
return other.className == className && other.objectId == objectId
}

/**
Fetches the `ParseObject` *asynchronously* and executes the given callback block.
- parameter includeKeys: The name(s) of the key(s) to include. Use `["*"]` to include
all keys.
- 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 when completed.
It should have the following argument signature: `(Result<T, ParseError>)`.
- note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer
desires a different policy, it should be inserted in `options`.
*/
func fetch(includeKeys: [String]? = nil,
options: API.Options = [],
callbackQueue: DispatchQueue = .main,
completion: @escaping (Result<Object, ParseError>) -> Void) {
Task {
var options = options
options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))

let method = API.Method.GET
let path = API.Endpoint.object(className: className, objectId: objectId)
let params: [String: String]? = {
guard let includeKeys = includeKeys else {
return nil
}
return ["include": "\(Set(includeKeys))"]
}()
let mapper = { (data) -> Object in
try ParseCoding.jsonDecoder().decode(Object.self, from: data)
}
await API.NonParseBodyCommand<NoBody, Object>(method: method, path: path, params: params, mapper: mapper)
.execute(options: options,
callbackQueue: callbackQueue,
completion: completion)
}
}
}

// MARK: Batch Support
public extension Sequence where Element: ParsePointerObject {

/**
Fetches a collection of objects all at once *asynchronously* and executes the completion block when done.
- parameter includeKeys: The name(s) of the key(s) to include that are
`ParseObject`s. Use `["*"]` to include all keys one level deep. This is similar to `include` and
`includeAll` for `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.
- parameter completion: The block to execute.
It should have the following argument signature: `(Result<[(Result<Element.Object, ParseError>)], ParseError>)`.
- warning: The order in which objects are returned are not guarenteed. You should not expect results in
any particular order.
*/
func fetchAll(
includeKeys: [String]? = nil,
options: API.Options = [],
callbackQueue: DispatchQueue = .main,
completion: @escaping (Result<[(Result<Element.Object, ParseError>)], ParseError>) -> Void
) {
let objects = Set(compactMap { $0.toObject() })
objects.fetchAll(
includeKeys: includeKeys,
options: options,
callbackQueue: callbackQueue,
completion: completion
)
}

}
Loading

0 comments on commit 0cc07eb

Please sign in to comment.