-
-
Notifications
You must be signed in to change notification settings - Fork 69
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* WIP * Add role * Add Operation tests, some renaming * name change * Add all operation tests and playgrounds example * Add/Remove Relation operation * merge and update * Add Query "distinct" * Make query thread safe since it's a reference type. - Added aggregate to query. This needs to be tested on a real server. * remove old file * more compatibility for linux build * use new cache for jazzy * initial role * Clean up * Update naming conventions * Update ParseSwift initialization/ * Improved ParseACL * remove renamed files * Working Role and Relation * Make Query a value type instead of reference type * Remove ParseRelation.save, ParseOperations can handle all saves for Relations. * More ParseRelation tests * Add ParseRole tests * Added Relation query tests. Fixed some bugs in batch object test cases causing random failures. * More tests * Add complete ParseRole tutorial to Playgrounds. * Finished Playground examples. * Add missing query constraints with tests. * Apply suggestions from code review Co-authored-by: Tom Fox <[email protected]> * Apply suggestions from code review Co-authored-by: Tom Fox <[email protected]> Co-authored-by: Tom Fox <[email protected]>
- Loading branch information
Showing
56 changed files
with
3,387 additions
and
560 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
215 changes: 215 additions & 0 deletions
215
ParseSwift.playground/Pages/12 - Roles and Relations.xcplaygroundpage/Contents.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,215 @@ | ||
//: [Previous](@previous) | ||
|
||
import PlaygroundSupport | ||
import Foundation | ||
import ParseSwift | ||
|
||
PlaygroundPage.current.needsIndefiniteExecution = true | ||
initializeParse() | ||
|
||
struct User: ParseUser { | ||
//: These are required for ParseObject | ||
var objectId: String? | ||
var createdAt: Date? | ||
var updatedAt: Date? | ||
var ACL: ParseACL? | ||
|
||
//: These are required for ParseUser | ||
var username: String? | ||
var email: String? | ||
var password: String? | ||
var authData: [String: [String: String]?]? | ||
|
||
//: Your custom keys | ||
var customKey: String? | ||
} | ||
|
||
struct Role<RoleUser: ParseUser>: ParseRole { | ||
|
||
// required by ParseObject | ||
var objectId: String? | ||
var createdAt: Date? | ||
var updatedAt: Date? | ||
var ACL: ParseACL? | ||
|
||
// provided by Role | ||
var name: String | ||
|
||
init() { | ||
self.name = "" | ||
} | ||
} | ||
|
||
//: Roles can provide additional access/security to your apps. | ||
|
||
//: This variable will store the saved role | ||
var savedRole: Role<User>? | ||
|
||
//: Now we will create the Role. | ||
if let currentUser = User.current { | ||
|
||
//: Every Role requires an ACL that can't be changed after saving. | ||
var acl = ParseACL() | ||
acl.setReadAccess(user: currentUser, value: true) | ||
acl.setWriteAccess(user: currentUser, value: true) | ||
|
||
do { | ||
//: Create the actual Role with a name and ACL. | ||
var adminRole = try Role<User>(name: "Administrator", acl: acl) | ||
adminRole.save { result in | ||
switch result { | ||
case .success(let saved): | ||
print("The role saved successfully: \(saved)") | ||
print("Check your \"Role\" class in Parse Dashboard.") | ||
|
||
//: Store the saved role so we can use it later... | ||
savedRole = saved | ||
|
||
case .failure(let error): | ||
print("Error saving role: \(error)") | ||
} | ||
} | ||
} catch { | ||
print("Error: \(error)") | ||
} | ||
} | ||
|
||
//: Lets check to see if our Role has saved | ||
if savedRole != nil { | ||
print("We have a saved Role") | ||
} | ||
|
||
//: Users can be added to our previously saved Role. | ||
do { | ||
//: `ParseRoles` have `ParseRelations` that relate them either `ParseUser` and `ParseRole` objects. | ||
//: The `ParseUser` relations can be accessed using `users`. We can then add `ParseUser`'s to the relation. | ||
try savedRole!.users.add([User.current!]).save { result in | ||
switch result { | ||
case .success(let saved): | ||
print("The role saved successfully: \(saved)") | ||
print("Check \"users\" field in your \"Role\" class in Parse Dashboard.") | ||
|
||
case .failure(let error): | ||
print("Error saving role: \(error)") | ||
} | ||
} | ||
|
||
} catch { | ||
print("Error: \(error)") | ||
} | ||
|
||
//: 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)") | ||
|
||
case .failure(let error): | ||
print("Error saving role: \(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.") | ||
|
||
case .failure(let error): | ||
print("Error saving role: \(error)") | ||
} | ||
} | ||
|
||
//: Additional roles can be created and tied to already created roles. Lets create a "Member" role. | ||
|
||
//: This variable will store the saved role | ||
var savedRoleModerator: Role<User>? | ||
|
||
//: We need another ACL | ||
var acl = ParseACL() | ||
acl.setReadAccess(user: User.current!, value: true) | ||
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) | ||
memberRole.save { result in | ||
switch result { | ||
case .success(let saved): | ||
print("The role saved successfully: \(saved)") | ||
print("Check your \"Role\" class in Parse Dashboard.") | ||
|
||
//: Store the saved role so we can use it later... | ||
savedRoleModerator = saved | ||
|
||
case .failure(let error): | ||
print("Error saving role: \(error)") | ||
} | ||
} | ||
} catch { | ||
print("Error: \(error)") | ||
} | ||
|
||
//: Lets check to see if our Role has saved | ||
if savedRoleModerator != nil { | ||
print("We have a saved Role") | ||
} | ||
|
||
//: Roles can be added to our previously saved Role. | ||
do { | ||
//: `ParseRoles` have `ParseRelations` that relate them either `ParseUser` and `ParseRole` objects. | ||
//: The `ParseUser` relations can be accessed using `users`. We can then add `ParseUser`'s to the relation. | ||
try savedRole!.roles.add([savedRoleModerator!]).save { result in | ||
switch result { | ||
case .success(let saved): | ||
print("The role saved successfully: \(saved)") | ||
print("Check \"roles\" field in your \"Role\" class in Parse Dashboard.") | ||
|
||
case .failure(let error): | ||
print("Error saving role: \(error)") | ||
} | ||
} | ||
|
||
} catch { | ||
print("Error: \(error)") | ||
} | ||
|
||
//: To retrieve the users who are all Administrators, we need to query the relation. | ||
//: This time we will use a helper query from `ParseRole`. | ||
savedRole!.queryRoles?.find { result in | ||
switch result { | ||
case .success(let relatedRoles): | ||
print("The following roles are part of the \"\(savedRole!.name) role: \(relatedRoles)") | ||
|
||
case .failure(let error): | ||
print("Error saving role: \(error)") | ||
} | ||
} | ||
|
||
//: 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.") | ||
|
||
case .failure(let error): | ||
print("Error saving role: \(error)") | ||
} | ||
} | ||
|
||
//: All `ParseObjects` have a `ParseRelation` attribute that be used on instances. | ||
//: For example, the User has: | ||
let relation = User.current!.relation | ||
|
||
//: Example: relation.add(<#T##users: [ParseUser]##[ParseUser]#>) | ||
//: Example: relation.remove(<#T##key: String##String#>, objects: <#T##[ParseObject]#>) | ||
|
||
//: Using this relation, you can create many-to-many relationships with other `ParseObjecs`, | ||
//: similar to `users` and `roles`. | ||
|
||
PlaygroundPage.current.finishExecution() | ||
|
||
//: [Next](@next) |
70 changes: 70 additions & 0 deletions
70
ParseSwift.playground/Pages/13 - Operations.xcplaygroundpage/Contents.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
//: [Previous](@previous) | ||
|
||
import PlaygroundSupport | ||
import Foundation | ||
import ParseSwift | ||
|
||
PlaygroundPage.current.needsIndefiniteExecution = true | ||
initializeParse() | ||
|
||
//: Some ValueTypes ParseObject's we will use... | ||
struct GameScore: ParseObject { | ||
//: Those are required for Object | ||
var objectId: String? | ||
var createdAt: Date? | ||
var updatedAt: Date? | ||
var ACL: ParseACL? | ||
|
||
//: Your own properties | ||
var score: Int = 0 | ||
|
||
//custom initializer | ||
init(score: Int) { | ||
self.score = score | ||
} | ||
|
||
init(objectId: String?) { | ||
self.objectId = objectId | ||
} | ||
} | ||
|
||
//: You can have the server do operations on your ParseObjects for you. | ||
|
||
//: First lets create another GameScore | ||
let savedScore: GameScore! | ||
do { | ||
savedScore = try GameScore(score: 102).save() | ||
} catch { | ||
savedScore = nil | ||
fatalError("Error saving: \(error)") | ||
} | ||
|
||
//: Then we will increment the score. | ||
let incrementOperation = savedScore | ||
.operation.increment("score", by: 1) | ||
|
||
incrementOperation.save { result in | ||
switch result { | ||
case .success: | ||
print("Original score: \(savedScore). Check the new score on Parse Dashboard.") | ||
case .failure(let error): | ||
assertionFailure("Error saving: \(error)") | ||
} | ||
} | ||
|
||
//: You can increment the score again syncronously. | ||
do { | ||
_ = try incrementOperation.save() | ||
print("Original score: \(savedScore). Check the new score on Parse Dashboard.") | ||
} catch { | ||
print(error) | ||
} | ||
|
||
//: There are other operations: add/remove/delete objects from `ParseObjects`. | ||
//: In fact, the `users` and `roles` relations from `ParseRoles` used the add/remove operations. | ||
let operations = savedScore.operation | ||
|
||
//: Example: operations.add("hello", objects: ["test"]) | ||
|
||
PlaygroundPage.current.finishExecution() | ||
//: [Next](@next) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.