Skip to content

Commit

Permalink
fix: saving nested ParseObjects and ParseFiles (#8)
Browse files Browse the repository at this point in the history
* fix: saving nested ParseObjects and ParseFiles

* nits
  • Loading branch information
cbaker6 committed Oct 23, 2022
1 parent 8c58ad2 commit da11b81
Show file tree
Hide file tree
Showing 14 changed files with 121 additions and 44 deletions.
12 changes: 9 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,26 @@
# Parse-Swift Changelog

### main
[Full Changelog](https://github.com/netreconlab/Parse-Swift/compare/4.15.1...main), [Documentation](https://swiftpackageindex.com/netreconlab/Parse-Swift/main/documentation/parseswift)
[Full Changelog](https://github.com/netreconlab/Parse-Swift/compare/4.15.2...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_

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

__Fixes__
- Fixed an issue that prevented nested ParseObjects and ParsFiles from saving correctly in some cases ([#8](https://github.com/netrencolab/Parse-Swift/pull/8)), thanks to [Corey Baker](https://github.com/cbaker6).

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

__Fixes__
- Fixed ambigous SDK initializer ([#6](https://github.com/netrecolab/Parse-Swift/pull/6)), thanks to [Corey Baker](https://github.com/cbaker6).
- Fixed ambigous SDK initializer ([#6](https://github.com/netrencolab/Parse-Swift/pull/6)), thanks to [Corey Baker](https://github.com/cbaker6).

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

__New features__
- Refactored masterKey->primaryKey due to insensitive language ([#2](https://github.com/netrecolab/Parse-Swift/pull/2)), thanks to [Corey Baker](https://github.com/cbaker6).
- Refactored masterKey->primaryKey due to insensitive language ([#2](https://github.com/netrencolab/Parse-Swift/pull/2)), thanks to [Corey Baker](https://github.com/cbaker6).

### 4.14.2
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/4.14.1...4.14.2), [Documentation](https://swiftpackageindex.com/parse-community/Parse-Swift/4.14.2/documentation/parseswift)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,10 @@ struct Book: ParseObject, ParseQueryScorable {
}
}

//: It's recommended to place custom initializers in an extension
//: to preserve the memberwise initializer.
/*:
It's recommended to place custom initializers in an extension
to preserve the memberwise initializer.
*/
extension Book {

init(title: String) {
Expand Down Expand Up @@ -89,8 +91,10 @@ struct Author: ParseObject {
}
}

//: It's recommended to place custom initializers in an extension
//: to preserve the memberwise initializer.
/*:
It's recommended to place custom initializers in an extension
to preserve the memberwise initializer.
*/
extension Author {
init(name: String, book: Book) {
self.name = name
Expand Down Expand Up @@ -152,15 +156,17 @@ query1.first { results in
}
}

/*: You will notice in the query above, the fields `book` and `otherBooks` only contain
/*:
You will notice in the query above, the fields `book` and `otherBooks` only contain
arrays consisting of key/value pairs of `objectId`. These are called Pointers
in `Parse`.
If you want to retrieve the complete object pointed to in `book`, you need to add
the field names containing the objects specifically in `include` in your query.
*/

/*: Here, we include `book`. If you wanted `book` and `otherBook`, you
/*:
Here, we include `book`. If you wanted `book` and `otherBook`, you
could have used: `.include(["book", "otherBook"])`.
*/
let query2 = Author.query("name" == "Bruce")
Expand All @@ -181,7 +187,8 @@ query2.first { results in
}
}

/*: When you have many fields that are pointing to objects, it may become tedious
/*:
When you have many fields that are pointing to objects, it may become tedious
to add all of them to the list. You can quickly retreive all pointer objects by
using `includeAll`. You can also use `include("*")` to retrieve all pointer
objects.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ struct GameScore: ParseObject {
var points: Int? = 0
var profilePicture: ParseFile?
var myData: ParseFile?
var otherPhoto: GamePhoto?

/*:
Optional - implement your own version of merge
Expand All @@ -45,6 +46,10 @@ struct GameScore: ParseObject {
original: object) {
updated.myData = object.myData
}
if updated.shouldRestoreKey(\.otherPhoto,
original: object) {
updated.otherPhoto = object.otherPhoto
}
return updated
}
}
Expand All @@ -62,6 +67,18 @@ extension GameScore {
}
}

struct GamePhoto: ParseObject {
//: These are required by ParseObject
var objectId: String?
var createdAt: Date?
var updatedAt: Date?
var ACL: ParseACL?
var originalData: Data?

//: Your own properties.
var image: ParseFile?
}

//: Define initial GameScore.
var score = GameScore(points: 52)

Expand All @@ -74,6 +91,11 @@ let profilePic = ParseFile(name: "profile.svg", cloudURL: linkToFile)
//: Set the picture as part of your ParseObject
score.profilePicture = profilePic

//: Set the picture in a nested ParseObject
var photo = GamePhoto()
photo.image = profilePic
score.otherPhoto = photo

/*:
Save asynchronously (preferred way) - Performs work on background
queue and returns to specified callbackQueue.
Expand Down
2 changes: 1 addition & 1 deletion ParseSwift.playground/Sources/Common.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ public func initializeParse(customObjectId: Bool = false) {
clientKey: "clientKey",
primaryKey: "primaryKey",
serverURL: URL(string: "http://localhost:1337/1")!,
allowingCustomObjectIds: customObjectId,
requiringCustomObjectIds: customObjectId,
usingEqualQueryConstraint: false,
usingDataProtectionKeychain: false)
}
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ For more information about the Parse Platform and its features, see the public [
To learn how to use or experiment with ParseSwift, you can run and edit the [ParseSwift.playground](https://github.com/netreconlab/Parse-Swift/tree/main/ParseSwift.playground/Pages). You can use the parse-server in [this repo](https://github.com/netreconlab/parse-hipaa/tree/parse-swift) which has docker compose files (`docker-compose up` gives you a working server) configured to connect with the playground files, has [Parse Dashboard](https://github.com/parse-community/parse-dashboard), and can be used with MongoDB or PostgreSQL. You can also configure the Swift Playgrounds to work with your own Parse Server by editing the configuation in [Common.swift](https://github.com/netreconlab/Parse-Swift/blob/e9ba846c399257100b285d25d2bd055628b13b4b/ParseSwift.playground/Sources/Common.swift#L4-L19). To learn more, check out [CONTRIBUTING.md](https://github.com/netreconlab/Parse-Swift/blob/main/CONTRIBUTING.md#swift-playgrounds).

## Use Parse-Swift from NetReconLab
This repo is maintained by [Corey E. Baker](https://github.com/cbaker6), [1 of 2 of the original developers of Parse-Swift](https://github.com/parse-community/Parse-Swift/graphs/contributors). Corey was responsible for the direction and development of all releases from [1.0.0](https://github.com/parse-community/Parse-Swift/releases/tag/4.14.2) to [4.14.2](https://github.com/parse-community/Parse-Swift/releases/tag/4.14.2). This repo will remain aligned with the original core principals of a swifty framework that contains zero dependencies and takes advantage of all of the features the [parse-server](https://github.com/parse-community/parse-server) has to offer. The reason for the bifurcation from the parse-community version of Parse-Swift is due to interference and a number of disagreements with a member of [Project Management Committee (PMC)](https://github.com/parse-community/Governance/blob/main/TEAM.md#project-management-committee-pmc) about the future of ParseSwift along with the PMC member ignoring code reviews and comments, marking relevant comments as `off-topic`, merging commits directly to main branch, lack-of-understanding of Swift fundamentals, client-side development, and lack of knowledge about how the Parse-Swift framework is designed. It is important to emphasize that no member of the Parse PMC participated in the design, release, and direction of Parse-Swift from its [first commit](https://github.com/parse-community/Parse-Swift/tree/cf69b7f0638819a7070b82228bc51a97df5757e6) to version [4.14.2](https://github.com/parse-community/Parse-Swift/releases/tag/4.14.2). In addition, no funding or support from the [parse-community funds](https://opencollective.com/parse-server) was ever offered to Corey for any of his [contributions to Parse](https://github.com/search?q=user%3Aparse-community+author%3Acbaker6&type=issues), though a [number of payments have been offered and made to other contributors](https://opencollective.com/parse-server#category-BUDGET). If you benefit from Parse-Swift and would like to show monetary support, feel free to <a href="https://www.buymeacoffee.com/cbaker6" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/default-orange.png" alt="Buy Me A Coffee" height="41" width="174"></a>
This repo is maintained by [Corey E. Baker](https://github.com/cbaker6), [1 of 2 of the original developers of Parse-Swift](https://github.com/parse-community/Parse-Swift/graphs/contributors). Corey was responsible for the direction and development of all releases from [1.0.0](https://github.com/parse-community/Parse-Swift/releases/tag/4.14.2) to [4.14.2](https://github.com/parse-community/Parse-Swift/releases/tag/4.14.2). This repo will remain aligned with the original core principals of a swifty framework that contains zero dependencies and takes advantage of all of the features the [parse-server](https://github.com/parse-community/parse-server) has to offer. The reason for the bifurcation from the parse-community version of Parse-Swift is due to interference and a number of disagreements with a member of [Parse Project Management Committee (PMC)](https://github.com/parse-community/Governance/blob/main/TEAM.md#project-management-committee-pmc) about the future of ParseSwift along with the PMC member ignoring code reviews and comments, marking relevant comments as `off-topic`, merging commits directly to main branch, lack-of-understanding of Swift fundamentals, client-side development, and lack of knowledge about how the Parse-Swift framework is designed. It is important to emphasize that no member of the Parse PMC participated in the design, release, and direction of Parse-Swift from its [first commit](https://github.com/parse-community/Parse-Swift/tree/cf69b7f0638819a7070b82228bc51a97df5757e6) to version [4.14.2](https://github.com/parse-community/Parse-Swift/releases/tag/4.14.2). In addition, no funding or support from the [parse-community funds](https://opencollective.com/parse-server) was ever offered to Corey for any of his [contributions to Parse](https://github.com/search?q=user%3Aparse-community+author%3Acbaker6&type=issues), though a [number of payments have been offered and made to other contributors](https://opencollective.com/parse-server#category-BUDGET). If you benefit from Parse-Swift and would like to show monetary support, feel free to <a href="https://www.buymeacoffee.com/cbaker6" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/default-orange.png" alt="Buy Me A Coffee" height="41" width="174"></a>

---

Expand Down Expand Up @@ -73,11 +73,11 @@ Run `carthage update`, and you should now have the latest version of ParseSwift

## Example Apps and Frameworks
Below is a list of apps and frameworks that use Parse-Swift to help developers take advantage of the framework:
- [ParseServerSwift](https://github.com/netreconlab/parse-server-swift) - Write Parse Cloud Code in Swift
- [ParseServerSwift](https://github.com/netreconlab/parse-server-swift) - Write Parse Cloud Code in Swift using Parse-Swift
- [CarekitSampe-ParseCareKit](https://github.com/netreconlab/CareKitSample-ParseCareKit) - An example application of [CareKit](https://github.com/carekit-apple/CareKit)'s OCKSample synchronizing CareKit data to the Cloud via [ParseCareKit](https://github.com/netreconlab/ParseCareKit)
- [ParseCareKit](https://github.com/netreconlab/ParseCareKit) - Synchronize CareKit 2.1+ data with a parse-server using Parse-Swift
- [SnapCat](https://github.com/netreconlab/SnapCat) - SnapCat is a social media application for posting pictures, comments, and finding friends. SnapCat is designed using SwiftUI and the ParseSwift SDK
- [ParseMigrateKeychain](https://github.com/netreconlab/ParseMigrateKeychain) - A sample app that demonstrates how to migrate an app written with the Parse [Objective-C SDK](https://github.com/parse-community/Parse-SDK-iOS-OSX) to the Swift SDK
- [ParseMigrateKeychain](https://github.com/netreconlab/ParseMigrateKeychain) - A sample app that demonstrates how to migrate an app written with the Parse [Objective-C SDK](https://github.com/parse-community/Parse-SDK-iOS-OSX) to the Parse-Swift SDK

## Usage Guide

Expand Down
10 changes: 8 additions & 2 deletions Sources/ParseSwift/API/API+NonParseBodyCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,10 @@ internal extension API.NonParseBodyCommand {
internal extension API.NonParseBodyCommand {
// MARK: Batch - Child Objects
static func batch(objects: [ParseEncodable],
transaction: Bool) throws -> RESTBatchCommandTypeEncodablePointer<AnyCodable> {
transaction: Bool,
objectsSavedBeforeThisOne: [String: PointerType]?,
// swiftlint:disable:next line_length
filesSavedBeforeThisOne: [UUID: ParseFile]?) throws -> RESTBatchCommandTypeEncodablePointer<AnyCodable> {
let batchCommands = try objects.compactMap { (object) -> API.BatchCommand<AnyCodable, PointerType>? in
guard var objectable = object as? Objectable else {
return nil
Expand All @@ -170,7 +173,10 @@ internal extension API.NonParseBodyCommand {
}

let path = Parse.configuration.mountPath + objectable.endpoint.urlComponent
let encoded = try ParseCoding.parseEncoder().encode(object, batching: true)
let encoded = try ParseCoding.parseEncoder().encode(object,
batching: true,
objectsSavedBeforeThisOne: objectsSavedBeforeThisOne,
filesSavedBeforeThisOne: filesSavedBeforeThisOne)
let body = try ParseCoding.jsonDecoder().decode(AnyCodable.self, from: encoded)
return API.BatchCommand<AnyCodable, PointerType>(method: method,
path: .any(path),
Expand Down
18 changes: 11 additions & 7 deletions Sources/ParseSwift/Coding/ParseEncoder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,10 @@ public struct ParseEncoder {
self.outputFormatting = outputFormatting
}

func encode(_ value: Encodable, batching: Bool = false) throws -> Data {
func encode(_ value: Encodable,
batching: Bool = false,
objectsSavedBeforeThisOne: [String: PointerType]? = nil,
filesSavedBeforeThisOne: [UUID: ParseFile]? = nil) throws -> Data {
var keysToSkip = SkipKeys.none.keys()
if batching {
keysToSkip = SkipKeys.object.keys()
Expand All @@ -120,8 +123,8 @@ public struct ParseEncoder {
batching: batching,
collectChildren: false,
uniquePointer: nil,
objectsSavedBeforeThisOne: nil,
filesSavedBeforeThisOne: nil).encoded
objectsSavedBeforeThisOne: objectsSavedBeforeThisOne,
filesSavedBeforeThisOne: filesSavedBeforeThisOne).encoded
}

/**
Expand All @@ -147,6 +150,7 @@ public struct ParseEncoder {

// swiftlint:disable large_tuple
internal func encode<T: ParseObject>(_ value: T,
collectChildren: Bool,
objectsSavedBeforeThisOne: [String: PointerType]?,
filesSavedBeforeThisOne: [UUID: ParseFile]?) throws -> (encoded: Data,
unique: PointerType?,
Expand All @@ -165,15 +169,15 @@ public struct ParseEncoder {
encoder.outputFormatting = outputFormatting
}
return try encoder.encodeObject(value,
collectChildren: true,
collectChildren: collectChildren,
uniquePointer: try? value.toPointer(),
objectsSavedBeforeThisOne: objectsSavedBeforeThisOne,
filesSavedBeforeThisOne: filesSavedBeforeThisOne)
}

// swiftlint:disable large_tuple
internal func encode(_ value: ParseEncodable,
batching: Bool = false,
batching: Bool,
collectChildren: Bool,
objectsSavedBeforeThisOne: [String: PointerType]?,
filesSavedBeforeThisOne: [UUID: ParseFile]?) throws -> (encoded: Data, unique: PointerType?, unsavedChildren: [Encodable]) {
Expand Down Expand Up @@ -398,13 +402,13 @@ internal class _ParseEncoder: JSONEncoder, Encoder {
if let updatedFile = self.filesSavedBeforeThisOne?[value.id] {
valueToEncode = updatedFile
} else {
//New object needs to be saved before it can be stored
// New object needs to be saved before it can be stored
self.newObjects.append(value)
}
} else if let currentFile = self.filesSavedBeforeThisOne?[value.id] {
valueToEncode = currentFile
} else if dictionary.count > 0 {
//Only top level objects can be saved without a pointer
// Only top level objects can be saved without a pointer
throw ParseError(code: .unknownError, message: "Error. Could not resolve unsaved file while encoding.")
}
}
Expand Down
Loading

0 comments on commit da11b81

Please sign in to comment.