Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Idempotency #62

Merged
merged 4 commits into from
Jan 24, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .swiftlint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ disabled_rules:
- function_body_length
- type_body_length
- inclusive_language
- comment_spacing
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.0.2...main)
* _Contributing to this repo? Add info about your change here to be included in next release_

__New features__
- Idempotency support ([#62](https://github.com/parse-community/Parse-Swift/pull/62)), thanks to [Corey Baker](https://github.com/cbaker6).

### 1.0.2
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.0.0...1.0.2)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ if let currentUser = User.current {

do {
//: Create the actual Role with a name and ACL.
var adminRole = try Role<User>(name: "Administrator", acl: acl)
let adminRole = try Role<User>(name: "Administrator", acl: acl)
adminRole.save { result in
switch result {
case .success(let saved):
Expand Down Expand Up @@ -100,26 +100,34 @@ do {

//: To retrieve the users who are all Administrators, we need to query the relation.
let templateUser = User()
savedRole!.users.query(templateUser).find { result in
switch result {
case .success(let relatedUsers):
print("The following users are part of the \"\(savedRole!.name) role: \(relatedUsers)")
do {
try savedRole!.users.query(templateUser).find { result in
switch result {
case .success(let relatedUsers):
print("The following users are part of the \"\(savedRole!.name) role: \(relatedUsers)")

case .failure(let error):
print("Error saving role: \(error)")
case .failure(let error):
print("Error saving role: \(error)")
}
}
} catch {
print(error)
}

//: Of course, you can remove users from the roles as well.
try savedRole!.users.remove([User.current!]).save { result in
switch result {
case .success(let saved):
print("The role removed successfully: \(saved)")
print("Check \"users\" field in your \"Role\" class in Parse Dashboard.")
do {
try savedRole!.users.remove([User.current!]).save { result in
switch result {
case .success(let saved):
print("The role removed successfully: \(saved)")
print("Check \"users\" field in your \"Role\" class in Parse Dashboard.")

case .failure(let error):
print("Error saving role: \(error)")
case .failure(let error):
print("Error saving role: \(error)")
}
}
} catch {
print(error)
}

//: Additional roles can be created and tied to already created roles. Lets create a "Member" role.
Expand All @@ -134,7 +142,7 @@ acl.setWriteAccess(user: User.current!, value: false)

do {
//: Create the actual Role with a name and ACL.
var memberRole = try Role<User>(name: "Member", acl: acl)
let memberRole = try Role<User>(name: "Member", acl: acl)
memberRole.save { result in
switch result {
case .success(let saved):
Expand Down Expand Up @@ -171,7 +179,6 @@ do {
print("Error saving role: \(error)")
}
}

} catch {
print("Error: \(error)")
}
Expand All @@ -189,15 +196,19 @@ savedRole!.queryRoles?.find { result in
}

//: Of course, you can remove users from the roles as well.
try savedRole!.roles.remove([savedRoleModerator!]).save { result in
switch result {
case .success(let saved):
print("The role removed successfully: \(saved)")
print("Check the \"roles\" field in your \"Role\" class in Parse Dashboard.")
do {
try savedRole!.roles.remove([savedRoleModerator!]).save { result in
switch result {
case .success(let saved):
print("The role removed successfully: \(saved)")
print("Check the \"roles\" field in your \"Role\" class in Parse Dashboard.")

case .failure(let error):
print("Error saving role: \(error)")
case .failure(let error):
print("Error saving role: \(error)")
}
}
} catch {
print(error)
}

//: All `ParseObjects` have a `ParseRelation` attribute that be used on instances.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ let incrementOperation = savedScore
incrementOperation.save { result in
switch result {
case .success:
print("Original score: \(savedScore). Check the new score on Parse Dashboard.")
print("Original score: \(String(describing: savedScore)). Check the new score on Parse Dashboard.")
case .failure(let error):
assertionFailure("Error saving: \(error)")
}
Expand All @@ -54,7 +54,7 @@ incrementOperation.save { result in
//: You can increment the score again syncronously.
do {
_ = try incrementOperation.save()
print("Original score: \(savedScore). Check the new score on Parse Dashboard.")
print("Original score: \(String(describing: savedScore)). Check the new score on Parse Dashboard.")
} catch {
print(error)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ config.fetch { result in
}

//: Anytime you fetch or update your Config successfully, it's automatically saved to your Keychain.
print(Config.current)
print(Config.current ?? "No config")

PlaygroundPage.current.finishExecution()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ query.first { results in
switch results {
case .success(let score):

guard let objectId = score.objectId,
guard score.objectId != nil,
let createdAt = score.createdAt else { fatalError() }
assert(createdAt.timeIntervalSince1970 > afterDate.timeIntervalSince1970, "date should be ok")
print("Found score: \(score)")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ do {
User.anonymous.login { result in
switch result {
case .success:
print("Successfully logged in \(User.current)")
print("Successfully logged in \(String(describing: User.current))")
case .failure(let error):
print("Error logging in: \(error)")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ score.save { result in
picture.fetch { result in
switch result {
case .success(let fetchedFile):
print("The file is now saved on your device at: \(fetchedFile.localURL)")
print("The file is now saved on your device at: \(String(describing: fetchedFile.localURL))")
print("The full details of your profilePicture ParseFile are: \(fetchedFile)")
case .failure(let error):
assertionFailure("Error fetching: \(error)")
Expand Down Expand Up @@ -107,7 +107,7 @@ do {

//: To get the contents updated `ParseFile`, you need to fetch your GameScore.
let fetchedScore = try savedScore.fetch()
if var myData = fetchedScore.myData {
if let myData = fetchedScore.myData {

guard let url = myData.url else {
fatalError("Error: file should have url.")
Expand Down
7 changes: 4 additions & 3 deletions ParseSwift.playground/contents.xcplayground
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@
<page name='8 - Pointers'/>
<page name='9 - Files'/>
<page name='10 - Cloud Code'/>
<page name='11 - LiveQuery'/>
<page name='12 - Roles and Relations'/>
<page name='13 - Operations'/>
<page name='10 - Cloud Code'/>
<page name='11 - LiveQuery'/>
<page name='12 - Roles and Relations'/>
<page name='13 - Operations'/>
<page name='14 - Config'/>
</pages>
</playground>
2 changes: 2 additions & 0 deletions Sources/ParseSwift/API/API.swift
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,8 @@ public struct API {
headers["X-Parse-Installation-Id"] = installationId
}

headers["X-Parse-Request-Id"] = UUID().uuidString.lowercased()

options.forEach { (option) in
switch option {
case .useMasterKey:
Expand Down
4 changes: 4 additions & 0 deletions Tests/ParseSwiftTests/APICommandTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -151,4 +151,8 @@ class APICommandTests: XCTestCase {
}
}

func testIdempodency() {
let headers = API.getHeaders(options: [])
XCTAssertNotNil(headers["X-Parse-Request-Id"])
}
}