Skip to content

Commit f877b37

Browse files
authored
Fix saving ParseObjects with Pointers as properties (#169)
* WIP * Fixed bug, but broke other pointers * Fixed regression * Update playgrounds * revert encoder change * Add another test and don't run them on Linux
1 parent c8ae80e commit f877b37

File tree

9 files changed

+99
-18
lines changed

9 files changed

+99
-18
lines changed

CHANGELOG.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
11
# Parse-Swift Changelog
22

33
### main
4-
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.8.2...main)
4+
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.8.3...main)
55
* _Contributing to this repo? Add info about your change here to be included in the next release_
66

7+
### 1.8.3
8+
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.8.2...1.8.3)
9+
10+
__Fixes__
11+
- Fixed a bug that prevented saving ParseObjects that had Pointers as properties ([#169](https://github.com/parse-community/Parse-Swift/pull/169)), thanks to [Corey Baker](https://github.com/cbaker6).
12+
713
### 1.8.2
814
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.8.1...1.8.2)
915

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

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ struct Book: ParseObject {
2020
var createdAt: Date?
2121
var updatedAt: Date?
2222
var ACL: ParseACL?
23+
var relatedBook: Pointer<Book>?
2324

2425
//: Your own properties.
2526
var title: String?
@@ -78,7 +79,9 @@ author2.save { result in
7879
assert(savedAuthorAndBook.ACL == nil)
7980
assert(savedAuthorAndBook.otherBooks?.count == 2)
8081

82+
//: Notice the pointer objects haven't been updated on the client.
8183
print("Saved \(savedAuthorAndBook)")
84+
8285
case .failure(let error):
8386
assertionFailure("Error saving: \(error)")
8487
}
@@ -160,5 +163,40 @@ do {
160163
print("\(error)")
161164
}
162165

166+
//: Here's an example of saving Pointers as properties
167+
do {
168+
// First we query
169+
let query5 = try Author.query("book" == newBook)
170+
.include("book")
171+
172+
query5.first { results in
173+
switch results {
174+
case .success(let author):
175+
print("Found author and included all: \(author)")
176+
//: Setup related books.
177+
newBook.relatedBook = try? author.otherBooks?.first?.toPointer()
178+
179+
newBook.save { result in
180+
switch result {
181+
case .success(let updatedBook):
182+
assert(updatedBook.objectId != nil)
183+
assert(updatedBook.createdAt != nil)
184+
assert(updatedBook.updatedAt != nil)
185+
assert(updatedBook.ACL == nil)
186+
assert(updatedBook.relatedBook != nil)
187+
188+
print("Saved \(updatedBook)")
189+
case .failure(let error):
190+
assertionFailure("Error saving: \(error)")
191+
}
192+
}
193+
case .failure(let error):
194+
assertionFailure("Error querying: \(error)")
195+
}
196+
}
197+
} catch {
198+
print("\(error)")
199+
}
200+
163201
PlaygroundPage.current.finishExecution()
164202
//: [Next](@next)

ParseSwift.podspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Pod::Spec.new do |s|
22
s.name = "ParseSwift"
3-
s.version = "1.8.2"
3+
s.version = "1.8.3"
44
s.summary = "Parse Pure Swift SDK"
55
s.homepage = "https://github.com/parse-community/Parse-Swift"
66
s.authors = {

ParseSwift.xcodeproj/project.pbxproj

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2433,7 +2433,7 @@
24332433
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
24342434
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
24352435
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
2436-
MARKETING_VERSION = 1.8.2;
2436+
MARKETING_VERSION = 1.8.3;
24372437
PRODUCT_BUNDLE_IDENTIFIER = com.parse.ParseSwift;
24382438
PRODUCT_NAME = ParseSwift;
24392439
SKIP_INSTALL = YES;
@@ -2457,7 +2457,7 @@
24572457
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
24582458
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
24592459
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
2460-
MARKETING_VERSION = 1.8.2;
2460+
MARKETING_VERSION = 1.8.3;
24612461
PRODUCT_BUNDLE_IDENTIFIER = com.parse.ParseSwift;
24622462
PRODUCT_NAME = ParseSwift;
24632463
SKIP_INSTALL = YES;
@@ -2523,7 +2523,7 @@
25232523
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
25242524
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
25252525
MACOSX_DEPLOYMENT_TARGET = 10.13;
2526-
MARKETING_VERSION = 1.8.2;
2526+
MARKETING_VERSION = 1.8.3;
25272527
PRODUCT_BUNDLE_IDENTIFIER = com.parse.ParseSwift;
25282528
PRODUCT_NAME = ParseSwift;
25292529
SDKROOT = macosx;
@@ -2549,7 +2549,7 @@
25492549
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
25502550
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
25512551
MACOSX_DEPLOYMENT_TARGET = 10.13;
2552-
MARKETING_VERSION = 1.8.2;
2552+
MARKETING_VERSION = 1.8.3;
25532553
PRODUCT_BUNDLE_IDENTIFIER = com.parse.ParseSwift;
25542554
PRODUCT_NAME = ParseSwift;
25552555
SDKROOT = macosx;
@@ -2696,7 +2696,7 @@
26962696
INFOPLIST_FILE = "ParseSwift-watchOS/Info.plist";
26972697
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
26982698
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
2699-
MARKETING_VERSION = 1.8.2;
2699+
MARKETING_VERSION = 1.8.3;
27002700
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
27012701
MTL_FAST_MATH = YES;
27022702
PRODUCT_BUNDLE_IDENTIFIER = "com.parse.ParseSwift-watchOS";
@@ -2725,7 +2725,7 @@
27252725
INFOPLIST_FILE = "ParseSwift-watchOS/Info.plist";
27262726
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
27272727
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
2728-
MARKETING_VERSION = 1.8.2;
2728+
MARKETING_VERSION = 1.8.3;
27292729
MTL_FAST_MATH = YES;
27302730
PRODUCT_BUNDLE_IDENTIFIER = "com.parse.ParseSwift-watchOS";
27312731
PRODUCT_NAME = ParseSwift;
@@ -2752,7 +2752,7 @@
27522752
INFOPLIST_FILE = "ParseSwift-tvOS/Info.plist";
27532753
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
27542754
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
2755-
MARKETING_VERSION = 1.8.2;
2755+
MARKETING_VERSION = 1.8.3;
27562756
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
27572757
MTL_FAST_MATH = YES;
27582758
PRODUCT_BUNDLE_IDENTIFIER = "com.parse.ParseSwift-tvOS";
@@ -2780,7 +2780,7 @@
27802780
INFOPLIST_FILE = "ParseSwift-tvOS/Info.plist";
27812781
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
27822782
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
2783-
MARKETING_VERSION = 1.8.2;
2783+
MARKETING_VERSION = 1.8.3;
27842784
MTL_FAST_MATH = YES;
27852785
PRODUCT_BUNDLE_IDENTIFIER = "com.parse.ParseSwift-tvOS";
27862786
PRODUCT_NAME = ParseSwift;

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ import PackageDescription
4444
let package = Package(
4545
name: "YOUR_PROJECT_NAME",
4646
dependencies: [
47-
.package(url: "https://github.com/parse-community/Parse-Swift", from: "1.8.1"),
47+
.package(url: "https://github.com/parse-community/Parse-Swift", from: "1.8.3"),
4848
]
4949
)
5050
```

Scripts/jazzy.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ bundle exec jazzy \
55
--author_url http://parseplatform.org \
66
--github_url https://github.com/parse-community/Parse-Swift \
77
--root-url http://parseplatform.org/Parse-Swift/api/ \
8-
--module-version 1.8.2 \
8+
--module-version 1.8.3 \
99
--theme fullwidth \
1010
--skip-undocumented \
1111
--output ./docs/api \

Sources/ParseSwift/Coding/ParseEncoder.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -893,7 +893,7 @@ extension _ParseEncoder {
893893
//COREY: DON'T remove the force unwrap, it will crash the app
894894
// swiftlint:disable:next force_cast
895895
return try self.box(value as! [String : Encodable])
896-
} else if value is PointerType {
896+
} else if value is ParsePointer {
897897
ignoreSkipKeys = true
898898
}
899899

Sources/ParseSwift/Types/Pointer.swift

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import Foundation
33
import Combine
44
#endif
55

6+
protocol ParsePointer { }
7+
68
private func getObjectId<T: ParseObject>(target: T) throws -> String {
79
guard let objectId = target.objectId else {
810
throw ParseError(code: .missingObjectId, message: "Cannot set a pointer to an unsaved object")
@@ -18,7 +20,7 @@ private func getObjectId(target: Objectable) throws -> String {
1820
}
1921

2022
/// A Pointer referencing a ParseObject.
21-
public struct Pointer<T: ParseObject>: Fetchable, Encodable, Hashable {
23+
public struct Pointer<T: ParseObject>: ParsePointer, Fetchable, Encodable, Hashable {
2224

2325
private let __type: String = "Pointer" // swiftlint:disable:this identifier_name
2426

@@ -127,13 +129,13 @@ public extension Pointer {
127129
#endif
128130
}
129131

130-
internal struct PointerType: Encodable {
132+
internal struct PointerType: ParsePointer, Encodable {
131133

132134
var __type: String = "Pointer" // swiftlint:disable:this identifier_name
133-
public var objectId: String
134-
public var className: String
135+
var objectId: String
136+
var className: String
135137

136-
public init(_ target: Objectable) throws {
138+
init(_ target: Objectable) throws {
137139
self.objectId = try getObjectId(target: target)
138140
self.className = target.className
139141
}

Tests/ParseSwiftTests/ParsePointerTests.swift

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ class ParsePointerTests: XCTestCase {
2121

2222
//: Your own properties
2323
var score: Int
24+
var other: Pointer<GameScore>?
2425

2526
//: a custom initializer
2627
init(score: Int) {
@@ -199,6 +200,40 @@ class ParsePointerTests: XCTestCase {
199200
}
200201

201202
#if !os(Linux) && !os(Android)
203+
func testEncodeEmbeddedPointer() throws {
204+
var score = GameScore(score: 10)
205+
let objectId = "yarr"
206+
score.objectId = objectId
207+
208+
var score2 = GameScore(score: 50)
209+
score2.other = try score.toPointer()
210+
211+
let encoded = try score2.getEncoder().encode(score2,
212+
collectChildren: false,
213+
objectsSavedBeforeThisOne: nil,
214+
filesSavedBeforeThisOne: nil)
215+
216+
let decoded = String(data: encoded.encoded, encoding: .utf8)
217+
XCTAssertEqual(decoded,
218+
// swiftlint:disable:next line_length
219+
"{\"score\":50,\"other\":{\"__type\":\"Pointer\",\"className\":\"GameScore\",\"objectId\":\"yarr\"}}")
220+
XCTAssertEqual(encoded.unique.count, 0)
221+
XCTAssertEqual(encoded.unsavedChildren.count, 0)
222+
}
223+
224+
func testPointerTypeEncoding() throws {
225+
var score = GameScore(score: 10)
226+
let objectId = "yarr"
227+
score.objectId = objectId
228+
229+
let pointerType = try PointerType(score)
230+
231+
let encoded = try ParseCoding.parseEncoder().encode(pointerType)
232+
let decoded = String(data: encoded, encoding: .utf8)
233+
XCTAssertEqual(decoded,
234+
"{\"__type\":\"Pointer\",\"className\":\"GameScore\",\"objectId\":\"yarr\"}")
235+
}
236+
202237
func testThreadSafeFetchAsync() throws {
203238
var score = GameScore(score: 10)
204239
let objectId = "yarr"

0 commit comments

Comments
 (0)