Skip to content

Commit 51e16d0

Browse files
authored
fix: allow ParseRole to save when using custom objectId's (#338)
* fix: allow ParseRole to save when using custom objectId's * codecov
1 parent aa02ed9 commit 51e16d0

File tree

6 files changed

+326
-8
lines changed

6 files changed

+326
-8
lines changed

.codecov.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ coverage:
66
status:
77
patch:
88
default:
9-
target: 78
9+
target: auto
1010
changes: false
1111
project:
1212
default:

CHANGELOG.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,15 @@
22

33
### main
44

5-
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/4.0.0...main)
5+
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/4.0.1...main)
66
* _Contributing to this repo? Add info about your change here to be included in the next release_
77

8+
### 4.0.1
9+
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/4.0.0...4.0.1)
10+
11+
__Fixes__
12+
- Allow ParseRole's to be updated when the SDK is allowing custom objectId's ([#338](https://github.com/parse-community/Parse-Swift/pull/338)), thanks to [Corey Baker](https://github.com/cbaker6).
13+
814
### 4.0.0
915
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/3.1.2...4.0.0)
1016

Sources/ParseSwift/ParseConstants.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import Foundation
1010

1111
enum ParseConstants {
1212
static let sdk = "swift"
13-
static let version = "4.0.0"
13+
static let version = "4.0.1"
1414
static let fileManagementDirectory = "parse/"
1515
static let fileManagementPrivateDocumentsDirectory = "Private Documents/"
1616
static let fileManagementLibraryDirectory = "Library/"

Sources/ParseSwift/Types/ParseOperation.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -386,7 +386,7 @@ extension ParseOperation {
386386
- returns: Returns saved `ParseObject`.
387387
*/
388388
public func save(options: API.Options = []) throws -> T {
389-
if !target.isSaved {
389+
guard target.objectId != nil else {
390390
throw ParseError(code: .missingObjectId, message: "ParseObject isn't saved.")
391391
}
392392
return try saveCommand()
@@ -406,7 +406,7 @@ extension ParseOperation {
406406
callbackQueue: DispatchQueue = .main,
407407
completion: @escaping (Result<T, ParseError>) -> Void
408408
) {
409-
if !target.isSaved {
409+
guard target.objectId != nil else {
410410
callbackQueue.async {
411411
let error = ParseError(code: .missingObjectId, message: "ParseObject isn't saved.")
412412
completion(.failure(error))

Tests/ParseSwiftTests/ParseRelationTests.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ class ParseRelationTests: XCTestCase {
215215
XCTAssertThrowsError(try relation.add("level", objects: [level]))
216216
}
217217

218-
func testAddOperations() throws {
218+
func testAddOperation() throws {
219219
var score = GameScore(points: 10)
220220
let objectId = "hello"
221221
score.objectId = objectId
@@ -252,7 +252,7 @@ class ParseRelationTests: XCTestCase {
252252
XCTAssertThrowsError(try relation.add("yolo", objects: [level]))
253253
}
254254

255-
func testAddOperationsNoKey() throws {
255+
func testAddOperationNoKey() throws {
256256
var score = GameScore(points: 10)
257257
let objectId = "hello"
258258
score.objectId = objectId
@@ -274,7 +274,7 @@ class ParseRelationTests: XCTestCase {
274274
XCTAssertEqual(decoded, expected)
275275
}
276276

277-
func testAddOperationsKeyCheck() throws {
277+
func testAddOperationKeyCheck() throws {
278278
var score = GameScore(points: 10)
279279
let objectId = "hello"
280280
score.objectId = objectId

Tests/ParseSwiftTests/ParseRoleTests.swift

Lines changed: 312 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,318 @@ class ParseRoleTests: XCTestCase {
377377
XCTAssertEqual(decoded2, expected2)
378378
}
379379

380+
func testRoleAddOperationSaveSynchronous() throws {
381+
var acl = ParseACL()
382+
acl.publicWrite = false
383+
acl.publicRead = true
384+
385+
var role = try Role<User>(name: "Administrator", acl: acl)
386+
role.createdAt = Date()
387+
role.updatedAt = Date()
388+
XCTAssertNil(role.roles) // Shouldn't produce a relation without an objectId.
389+
role.objectId = "yolo"
390+
guard let roles = role.roles else {
391+
XCTFail("Should have unwrapped")
392+
return
393+
}
394+
395+
var newRole = try Role<User>(name: "Moderator", acl: acl)
396+
newRole.objectId = "heel"
397+
let operation = try roles.add([newRole])
398+
399+
var serverResponse = role
400+
serverResponse.createdAt = nil
401+
serverResponse.updatedAt = Date()
402+
403+
let encoded: Data!
404+
do {
405+
encoded = try ParseCoding.jsonEncoder().encode(serverResponse)
406+
//Get dates in correct format from ParseDecoding strategy
407+
serverResponse = try serverResponse.getDecoder().decode(Role<User>.self, from: encoded)
408+
} catch {
409+
XCTFail("Should encode/decode. Error \(error)")
410+
return
411+
}
412+
413+
MockURLProtocol.mockRequests { _ in
414+
return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)
415+
}
416+
417+
let updatedRole = try operation.save()
418+
XCTAssertEqual(updatedRole.updatedAt, serverResponse.updatedAt)
419+
XCTAssertTrue(updatedRole.hasSameObjectId(as: serverResponse))
420+
}
421+
422+
func testRoleAddOperationSaveSynchronousError() throws {
423+
var acl = ParseACL()
424+
acl.publicWrite = false
425+
acl.publicRead = true
426+
427+
var role = try Role<User>(name: "Administrator", acl: acl)
428+
role.createdAt = Date()
429+
role.updatedAt = Date()
430+
XCTAssertNil(role.roles) // Shouldn't produce a relation without an objectId.
431+
role.objectId = "yolo"
432+
guard let roles = role.roles else {
433+
XCTFail("Should have unwrapped")
434+
return
435+
}
436+
437+
var newRole = try Role<User>(name: "Moderator", acl: acl)
438+
newRole.objectId = "heel"
439+
var operation = try roles.add([newRole])
440+
operation.target.objectId = nil
441+
442+
do {
443+
_ = try operation.save()
444+
XCTFail("Should have failed")
445+
} catch {
446+
XCTAssertTrue(error.containedIn([.missingObjectId]))
447+
}
448+
}
449+
450+
func testRoleAddOperationSaveSynchronousCustomObjectId() throws {
451+
var acl = ParseACL()
452+
acl.publicWrite = false
453+
acl.publicRead = true
454+
455+
ParseSwift.configuration.isAllowingCustomObjectIds = true
456+
var role = try Role<User>(name: "Administrator", acl: acl)
457+
role.createdAt = Date()
458+
role.updatedAt = Date()
459+
XCTAssertNil(role.roles) // Shouldn't produce a relation without an objectId.
460+
role.objectId = "yolo"
461+
guard let roles = role.roles else {
462+
XCTFail("Should have unwrapped")
463+
return
464+
}
465+
466+
var newRole = try Role<User>(name: "Moderator", acl: acl)
467+
newRole.objectId = "heel"
468+
let operation = try roles.add([newRole])
469+
470+
var serverResponse = role
471+
serverResponse.createdAt = nil
472+
serverResponse.updatedAt = Date()
473+
474+
let encoded: Data!
475+
do {
476+
encoded = try ParseCoding.jsonEncoder().encode(serverResponse)
477+
//Get dates in correct format from ParseDecoding strategy
478+
serverResponse = try serverResponse.getDecoder().decode(Role<User>.self, from: encoded)
479+
} catch {
480+
XCTFail("Should encode/decode. Error \(error)")
481+
return
482+
}
483+
484+
MockURLProtocol.mockRequests { _ in
485+
return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)
486+
}
487+
488+
let updatedRole = try operation.save()
489+
XCTAssertEqual(updatedRole.updatedAt, serverResponse.updatedAt)
490+
XCTAssertTrue(updatedRole.hasSameObjectId(as: serverResponse))
491+
}
492+
493+
func testRoleAddOperationSaveSynchronousCustomObjectIdError() throws {
494+
var acl = ParseACL()
495+
acl.publicWrite = false
496+
acl.publicRead = true
497+
498+
ParseSwift.configuration.isAllowingCustomObjectIds = true
499+
var role = try Role<User>(name: "Administrator", acl: acl)
500+
role.createdAt = Date()
501+
role.updatedAt = Date()
502+
XCTAssertNil(role.roles) // Shouldn't produce a relation without an objectId.
503+
role.objectId = "yolo"
504+
guard let roles = role.roles else {
505+
XCTFail("Should have unwrapped")
506+
return
507+
}
508+
509+
var newRole = try Role<User>(name: "Moderator", acl: acl)
510+
newRole.objectId = "heel"
511+
var operation = try roles.add([newRole])
512+
operation.target.objectId = nil
513+
514+
do {
515+
_ = try operation.save()
516+
XCTFail("Should have failed")
517+
} catch {
518+
XCTAssertTrue(error.containedIn([.missingObjectId]))
519+
}
520+
}
521+
522+
func testRoleAddOperationSaveAsynchronous() throws {
523+
var acl = ParseACL()
524+
acl.publicWrite = false
525+
acl.publicRead = true
526+
527+
var role = try Role<User>(name: "Administrator", acl: acl)
528+
role.createdAt = Date()
529+
role.updatedAt = Date()
530+
XCTAssertNil(role.roles) // Shouldn't produce a relation without an objectId.
531+
role.objectId = "yolo"
532+
guard let roles = role.roles else {
533+
XCTFail("Should have unwrapped")
534+
return
535+
}
536+
537+
var newRole = try Role<User>(name: "Moderator", acl: acl)
538+
newRole.objectId = "heel"
539+
let operation = try roles.add([newRole])
540+
541+
var serverResponse = role
542+
serverResponse.createdAt = nil
543+
serverResponse.updatedAt = Date()
544+
545+
let encoded: Data!
546+
do {
547+
encoded = try ParseCoding.jsonEncoder().encode(serverResponse)
548+
//Get dates in correct format from ParseDecoding strategy
549+
serverResponse = try serverResponse.getDecoder().decode(Role<User>.self, from: encoded)
550+
} catch {
551+
XCTFail("Should encode/decode. Error \(error)")
552+
return
553+
}
554+
555+
MockURLProtocol.mockRequests { _ in
556+
return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)
557+
}
558+
559+
let expectation1 = XCTestExpectation(description: "Save object1")
560+
operation.save { result in
561+
switch result {
562+
case .success(let updatedRole):
563+
XCTAssertEqual(updatedRole.updatedAt, serverResponse.updatedAt)
564+
XCTAssertTrue(updatedRole.hasSameObjectId(as: serverResponse))
565+
case .failure(let error):
566+
XCTFail(error.localizedDescription)
567+
}
568+
expectation1.fulfill()
569+
}
570+
wait(for: [expectation1], timeout: 20.0)
571+
}
572+
573+
func testRoleAddOperationSaveAsynchronousError() throws {
574+
var acl = ParseACL()
575+
acl.publicWrite = false
576+
acl.publicRead = true
577+
578+
ParseSwift.configuration.isAllowingCustomObjectIds = true
579+
var role = try Role<User>(name: "Administrator", acl: acl)
580+
role.createdAt = Date()
581+
role.updatedAt = Date()
582+
XCTAssertNil(role.roles) // Shouldn't produce a relation without an objectId.
583+
role.objectId = "yolo"
584+
guard let roles = role.roles else {
585+
XCTFail("Should have unwrapped")
586+
return
587+
}
588+
589+
var newRole = try Role<User>(name: "Moderator", acl: acl)
590+
newRole.objectId = "heel"
591+
var operation = try roles.add([newRole])
592+
operation.target.objectId = nil
593+
594+
let expectation1 = XCTestExpectation(description: "Save object1")
595+
operation.save { result in
596+
switch result {
597+
case .success:
598+
XCTFail("Should have failed")
599+
case .failure(let error):
600+
XCTAssertEqual(error.code, .missingObjectId)
601+
}
602+
expectation1.fulfill()
603+
}
604+
wait(for: [expectation1], timeout: 20.0)
605+
}
606+
607+
func testRoleAddOperationSaveAsynchronousCustomObjectId() throws {
608+
var acl = ParseACL()
609+
acl.publicWrite = false
610+
acl.publicRead = true
611+
612+
ParseSwift.configuration.isAllowingCustomObjectIds = true
613+
var role = try Role<User>(name: "Administrator", acl: acl)
614+
role.createdAt = Date()
615+
role.updatedAt = Date()
616+
XCTAssertNil(role.roles) // Shouldn't produce a relation without an objectId.
617+
role.objectId = "yolo"
618+
guard let roles = role.roles else {
619+
XCTFail("Should have unwrapped")
620+
return
621+
}
622+
623+
var newRole = try Role<User>(name: "Moderator", acl: acl)
624+
newRole.objectId = "heel"
625+
let operation = try roles.add([newRole])
626+
627+
var serverResponse = role
628+
serverResponse.createdAt = nil
629+
serverResponse.updatedAt = Date()
630+
631+
let encoded: Data!
632+
do {
633+
encoded = try ParseCoding.jsonEncoder().encode(serverResponse)
634+
//Get dates in correct format from ParseDecoding strategy
635+
serverResponse = try serverResponse.getDecoder().decode(Role<User>.self, from: encoded)
636+
} catch {
637+
XCTFail("Should encode/decode. Error \(error)")
638+
return
639+
}
640+
641+
MockURLProtocol.mockRequests { _ in
642+
return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)
643+
}
644+
645+
let expectation1 = XCTestExpectation(description: "Save object1")
646+
operation.save { result in
647+
switch result {
648+
case .success(let updatedRole):
649+
XCTAssertEqual(updatedRole.updatedAt, serverResponse.updatedAt)
650+
XCTAssertTrue(updatedRole.hasSameObjectId(as: serverResponse))
651+
case .failure(let error):
652+
XCTFail(error.localizedDescription)
653+
}
654+
expectation1.fulfill()
655+
}
656+
wait(for: [expectation1], timeout: 20.0)
657+
}
658+
659+
func testRoleAddOperationSaveAsynchronousCustomObjectIdError() throws {
660+
var acl = ParseACL()
661+
acl.publicWrite = false
662+
acl.publicRead = true
663+
664+
var role = try Role<User>(name: "Administrator", acl: acl)
665+
role.createdAt = Date()
666+
role.updatedAt = Date()
667+
XCTAssertNil(role.roles) // Shouldn't produce a relation without an objectId.
668+
role.objectId = "yolo"
669+
guard let roles = role.roles else {
670+
XCTFail("Should have unwrapped")
671+
return
672+
}
673+
674+
var newRole = try Role<User>(name: "Moderator", acl: acl)
675+
newRole.objectId = "heel"
676+
var operation = try roles.add([newRole])
677+
operation.target.objectId = nil
678+
679+
let expectation1 = XCTestExpectation(description: "Save object1")
680+
operation.save { result in
681+
switch result {
682+
case .success:
683+
XCTFail("Should have failed")
684+
case .failure(let error):
685+
XCTAssertEqual(error.code, .missingObjectId)
686+
}
687+
expectation1.fulfill()
688+
}
689+
wait(for: [expectation1], timeout: 20.0)
690+
}
691+
380692
func testRoleAddOperationNoKey() throws {
381693
var acl = ParseACL()
382694
acl.publicWrite = false

0 commit comments

Comments
 (0)