Skip to content

Commit da11b81

Browse files
authored
fix: saving nested ParseObjects and ParseFiles (#8)
* fix: saving nested ParseObjects and ParseFiles * nits
1 parent 8c58ad2 commit da11b81

File tree

14 files changed

+121
-44
lines changed

14 files changed

+121
-44
lines changed

CHANGELOG.md

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,26 @@
11
# Parse-Swift Changelog
22

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

7+
### 4.15.2
8+
[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)
9+
10+
__Fixes__
11+
- 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).
12+
713
### 4.15.1
814
[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)
915

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

1319
### 4.15.0
1420
[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)
1521

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

1925
### 4.14.2
2026
[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)

ParseSwift.playground/Pages/8 - Pointers.xcplaygroundpage/Contents.swift

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,10 @@ struct Book: ParseObject, ParseQueryScorable {
4545
}
4646
}
4747

48-
//: It's recommended to place custom initializers in an extension
49-
//: to preserve the memberwise initializer.
48+
/*:
49+
It's recommended to place custom initializers in an extension
50+
to preserve the memberwise initializer.
51+
*/
5052
extension Book {
5153

5254
init(title: String) {
@@ -89,8 +91,10 @@ struct Author: ParseObject {
8991
}
9092
}
9193

92-
//: It's recommended to place custom initializers in an extension
93-
//: to preserve the memberwise initializer.
94+
/*:
95+
It's recommended to place custom initializers in an extension
96+
to preserve the memberwise initializer.
97+
*/
9498
extension Author {
9599
init(name: String, book: Book) {
96100
self.name = name
@@ -152,15 +156,17 @@ query1.first { results in
152156
}
153157
}
154158

155-
/*: You will notice in the query above, the fields `book` and `otherBooks` only contain
159+
/*:
160+
You will notice in the query above, the fields `book` and `otherBooks` only contain
156161
arrays consisting of key/value pairs of `objectId`. These are called Pointers
157162
in `Parse`.
158163

159164
If you want to retrieve the complete object pointed to in `book`, you need to add
160165
the field names containing the objects specifically in `include` in your query.
161166
*/
162167

163-
/*: Here, we include `book`. If you wanted `book` and `otherBook`, you
168+
/*:
169+
Here, we include `book`. If you wanted `book` and `otherBook`, you
164170
could have used: `.include(["book", "otherBook"])`.
165171
*/
166172
let query2 = Author.query("name" == "Bruce")
@@ -181,7 +187,8 @@ query2.first { results in
181187
}
182188
}
183189

184-
/*: When you have many fields that are pointing to objects, it may become tedious
190+
/*:
191+
When you have many fields that are pointing to objects, it may become tedious
185192
to add all of them to the list. You can quickly retreive all pointer objects by
186193
using `includeAll`. You can also use `include("*")` to retrieve all pointer
187194
objects.

ParseSwift.playground/Pages/9 - Files.xcplaygroundpage/Contents.swift

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ struct GameScore: ParseObject {
2626
var points: Int? = 0
2727
var profilePicture: ParseFile?
2828
var myData: ParseFile?
29+
var otherPhoto: GamePhoto?
2930

3031
/*:
3132
Optional - implement your own version of merge
@@ -45,6 +46,10 @@ struct GameScore: ParseObject {
4546
original: object) {
4647
updated.myData = object.myData
4748
}
49+
if updated.shouldRestoreKey(\.otherPhoto,
50+
original: object) {
51+
updated.otherPhoto = object.otherPhoto
52+
}
4853
return updated
4954
}
5055
}
@@ -62,6 +67,18 @@ extension GameScore {
6267
}
6368
}
6469

70+
struct GamePhoto: ParseObject {
71+
//: These are required by ParseObject
72+
var objectId: String?
73+
var createdAt: Date?
74+
var updatedAt: Date?
75+
var ACL: ParseACL?
76+
var originalData: Data?
77+
78+
//: Your own properties.
79+
var image: ParseFile?
80+
}
81+
6582
//: Define initial GameScore.
6683
var score = GameScore(points: 52)
6784

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

94+
//: Set the picture in a nested ParseObject
95+
var photo = GamePhoto()
96+
photo.image = profilePic
97+
score.otherPhoto = photo
98+
7799
/*:
78100
Save asynchronously (preferred way) - Performs work on background
79101
queue and returns to specified callbackQueue.

ParseSwift.playground/Sources/Common.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ public func initializeParse(customObjectId: Bool = false) {
66
clientKey: "clientKey",
77
primaryKey: "primaryKey",
88
serverURL: URL(string: "http://localhost:1337/1")!,
9-
allowingCustomObjectIds: customObjectId,
9+
requiringCustomObjectIds: customObjectId,
1010
usingEqualQueryConstraint: false,
1111
usingDataProtectionKeychain: false)
1212
}

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ For more information about the Parse Platform and its features, see the public [
2323
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).
2424

2525
## Use Parse-Swift from NetReconLab
26-
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>
26+
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>
2727

2828
---
2929

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

7474
## Example Apps and Frameworks
7575
Below is a list of apps and frameworks that use Parse-Swift to help developers take advantage of the framework:
76-
- [ParseServerSwift](https://github.com/netreconlab/parse-server-swift) - Write Parse Cloud Code in Swift
76+
- [ParseServerSwift](https://github.com/netreconlab/parse-server-swift) - Write Parse Cloud Code in Swift using Parse-Swift
7777
- [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)
7878
- [ParseCareKit](https://github.com/netreconlab/ParseCareKit) - Synchronize CareKit 2.1+ data with a parse-server using Parse-Swift
7979
- [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
80-
- [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
80+
- [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
8181

8282
## Usage Guide
8383

Sources/ParseSwift/API/API+NonParseBodyCommand.swift

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,10 @@ internal extension API.NonParseBodyCommand {
152152
internal extension API.NonParseBodyCommand {
153153
// MARK: Batch - Child Objects
154154
static func batch(objects: [ParseEncodable],
155-
transaction: Bool) throws -> RESTBatchCommandTypeEncodablePointer<AnyCodable> {
155+
transaction: Bool,
156+
objectsSavedBeforeThisOne: [String: PointerType]?,
157+
// swiftlint:disable:next line_length
158+
filesSavedBeforeThisOne: [UUID: ParseFile]?) throws -> RESTBatchCommandTypeEncodablePointer<AnyCodable> {
156159
let batchCommands = try objects.compactMap { (object) -> API.BatchCommand<AnyCodable, PointerType>? in
157160
guard var objectable = object as? Objectable else {
158161
return nil
@@ -170,7 +173,10 @@ internal extension API.NonParseBodyCommand {
170173
}
171174

172175
let path = Parse.configuration.mountPath + objectable.endpoint.urlComponent
173-
let encoded = try ParseCoding.parseEncoder().encode(object, batching: true)
176+
let encoded = try ParseCoding.parseEncoder().encode(object,
177+
batching: true,
178+
objectsSavedBeforeThisOne: objectsSavedBeforeThisOne,
179+
filesSavedBeforeThisOne: filesSavedBeforeThisOne)
174180
let body = try ParseCoding.jsonDecoder().decode(AnyCodable.self, from: encoded)
175181
return API.BatchCommand<AnyCodable, PointerType>(method: method,
176182
path: .any(path),

Sources/ParseSwift/Coding/ParseEncoder.swift

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,10 @@ public struct ParseEncoder {
104104
self.outputFormatting = outputFormatting
105105
}
106106

107-
func encode(_ value: Encodable, batching: Bool = false) throws -> Data {
107+
func encode(_ value: Encodable,
108+
batching: Bool = false,
109+
objectsSavedBeforeThisOne: [String: PointerType]? = nil,
110+
filesSavedBeforeThisOne: [UUID: ParseFile]? = nil) throws -> Data {
108111
var keysToSkip = SkipKeys.none.keys()
109112
if batching {
110113
keysToSkip = SkipKeys.object.keys()
@@ -120,8 +123,8 @@ public struct ParseEncoder {
120123
batching: batching,
121124
collectChildren: false,
122125
uniquePointer: nil,
123-
objectsSavedBeforeThisOne: nil,
124-
filesSavedBeforeThisOne: nil).encoded
126+
objectsSavedBeforeThisOne: objectsSavedBeforeThisOne,
127+
filesSavedBeforeThisOne: filesSavedBeforeThisOne).encoded
125128
}
126129

127130
/**
@@ -147,6 +150,7 @@ public struct ParseEncoder {
147150

148151
// swiftlint:disable large_tuple
149152
internal func encode<T: ParseObject>(_ value: T,
153+
collectChildren: Bool,
150154
objectsSavedBeforeThisOne: [String: PointerType]?,
151155
filesSavedBeforeThisOne: [UUID: ParseFile]?) throws -> (encoded: Data,
152156
unique: PointerType?,
@@ -165,15 +169,15 @@ public struct ParseEncoder {
165169
encoder.outputFormatting = outputFormatting
166170
}
167171
return try encoder.encodeObject(value,
168-
collectChildren: true,
172+
collectChildren: collectChildren,
169173
uniquePointer: try? value.toPointer(),
170174
objectsSavedBeforeThisOne: objectsSavedBeforeThisOne,
171175
filesSavedBeforeThisOne: filesSavedBeforeThisOne)
172176
}
173177

174178
// swiftlint:disable large_tuple
175179
internal func encode(_ value: ParseEncodable,
176-
batching: Bool = false,
180+
batching: Bool,
177181
collectChildren: Bool,
178182
objectsSavedBeforeThisOne: [String: PointerType]?,
179183
filesSavedBeforeThisOne: [UUID: ParseFile]?) throws -> (encoded: Data, unique: PointerType?, unsavedChildren: [Encodable]) {
@@ -398,13 +402,13 @@ internal class _ParseEncoder: JSONEncoder, Encoder {
398402
if let updatedFile = self.filesSavedBeforeThisOne?[value.id] {
399403
valueToEncode = updatedFile
400404
} else {
401-
//New object needs to be saved before it can be stored
405+
// New object needs to be saved before it can be stored
402406
self.newObjects.append(value)
403407
}
404408
} else if let currentFile = self.filesSavedBeforeThisOne?[value.id] {
405409
valueToEncode = currentFile
406410
} else if dictionary.count > 0 {
407-
//Only top level objects can be saved without a pointer
411+
// Only top level objects can be saved without a pointer
408412
throw ParseError(code: .unknownError, message: "Error. Could not resolve unsaved file while encoding.")
409413
}
410414
}

0 commit comments

Comments
 (0)