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

feat: add ability to merge updated objects with original #315

Merged
merged 29 commits into from
Jan 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
3c09b20
feat: allow for developer to specify updated keys
cbaker6 Jan 10, 2022
347bdfc
add tests and Playgrounds
cbaker6 Jan 10, 2022
4fb838e
nit
cbaker6 Jan 10, 2022
df836f0
add ACL to default implementation
cbaker6 Jan 11, 2022
68d5a93
test Patch merge
cbaker6 Jan 11, 2022
b3bca74
update documentation
cbaker6 Jan 11, 2022
e125b54
merge ParseObjects automatically
cbaker6 Jan 14, 2022
29a96f1
fix build on Swift 5.2
cbaker6 Jan 14, 2022
aa9c6da
Make sure originalData never saves to Keychain
cbaker6 Jan 14, 2022
8c5f2ed
move test to correct file
cbaker6 Jan 15, 2022
8ffb95d
Merge remote-tracking branch 'upstream/main' into updateKeys
cbaker6 Jan 15, 2022
034b652
Update Playgrounds and move ParseObjectMutable into ParseObject
cbaker6 Jan 15, 2022
d180c63
doc updates
cbaker6 Jan 15, 2022
0f64ca7
coverage
cbaker6 Jan 15, 2022
f1e4a0a
update Playgrounds
cbaker6 Jan 15, 2022
3e6dcdc
Merge branch 'main' into updateKeys
cbaker6 Jan 16, 2022
4d0d802
tested and nit playgrounds
cbaker6 Jan 16, 2022
854acd0
merge
cbaker6 Jan 17, 2022
509c19f
fix merge conflicts
cbaker6 Jan 17, 2022
3889682
mutable -> mergeable
cbaker6 Jan 17, 2022
3486699
fix sortByText
cbaker6 Jan 17, 2022
3a15233
add info about POP in README
cbaker6 Jan 17, 2022
e12b88f
Move the where for Swift 5.2
cbaker6 Jan 17, 2022
19d1fd9
Update README.md
cbaker6 Jan 18, 2022
d0ff845
try windows action
cbaker6 Jan 18, 2022
78ea506
Update ci.yml
cbaker6 Jan 18, 2022
5dcfdbb
Update ci.yml
cbaker6 Jan 18, 2022
b1baebb
don't build async on windows
cbaker6 Jan 18, 2022
7fa72f2
revert async back to Swift 5.5.2
cbaker6 Jan 18, 2022
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
17 changes: 15 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,22 @@

### main

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

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

__New features__
- (Breaking Change) Add the ability to merge updated ParseObject's with original objects when using the
.mergeable property. To do this, developers need to add an implementation of merge() to
respective ParseObject's. The compiler will recommend the new originalData property be added to
every ParseObject. If you used ParseObjectMutable in the past, you should remove it as it is now
part of ParseObject. In addition, all ParseObject properties should be optional and every object
needs to have a default initilizer of init(). See the Playgrounds for recommendations on how to
define a ParseObject. Look at the PR for
details on why this is important when using the SDK ([#315](https://github.com/parse-community/Parse-Swift/pull/315)), thanks to [Corey Baker](https://github.com/cbaker6).

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

Expand All @@ -31,7 +44,7 @@ __New features__
- Adds equalTo QueryConstraint along with ability to change the SDK default behavior of using $eq QueryConstraint parameter or not ([#310](https://github.com/parse-community/Parse-Swift/pull/310)), thanks to [Corey Baker](https://github.com/cbaker6).
- Adds isNull and isNotNull QueryConstraint along with the ability set/forceSet null using ParseOperation ([#308](https://github.com/parse-community/Parse-Swift/pull/308)), thanks to [Corey Baker](https://github.com/cbaker6).
- Adds auth support for GitHub, Google, and LinkedIn ([#307](https://github.com/parse-community/Parse-Swift/pull/307)), thanks to [Corey Baker](https://github.com/cbaker6).
- (Breaking Change) Adds options to matchesText QueryConstraint along with the ability to see matching score. The compiler should recommend the new score property to all ParseObjects ([#306](https://github.com/parse-community/Parse-Swift/pull/306)), thanks to [Corey Baker](https://github.com/cbaker6).
- (Breaking Change) Adds options to matchesText QueryConstraint along with the ability to see matching score. The compiler will recommend the new score property be added to all ParseObjects ([#306](https://github.com/parse-community/Parse-Swift/pull/306)), thanks to [Corey Baker](https://github.com/cbaker6).
cbaker6 marked this conversation as resolved.
Show resolved Hide resolved
- Adds withCount query ([#306](https://github.com/parse-community/Parse-Swift/pull/306)), thanks to [Corey Baker](https://github.com/cbaker6).

__Improvements__
Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ Currently, we are not making use of the commit _scope_, which would be written a

## Evolution

It's not intended as a port of the Parse Objective-c SDK and has many new philosophies. Please see [this thread](https://github.com/parse-community/Parse-Swift/issues/3) for a detailed discussion about the intended evolution of this SDK.
The ParseSwift SDK is not a port of the [Parse-SDK-iOS-OSX SDK](https://github.com/parse-community/Parse-SDK-iOS-OSX) and though some of it may feel familiar, it is not backwards compatible and is designed using [protocol oriented programming (POP) and value types](https://www.pluralsight.com/guides/protocol-oriented-programming-in-swift) instead of OOP and reference types. You can learn more about POP by watching [this](https://developer.apple.com/videos/play/wwdc2015/408/) or [that](https://developer.apple.com/videos/play/wwdc2016/419/) videos from previous WWDC's. Please see [this thread](https://github.com/parse-community/Parse-Swift/issues/3) for a detailed discussion about the intended evolution of this SDK.

## Code of Conduct

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,26 @@ do {
}

//: Create your own value typed `ParseObject`.
struct GameScore: ParseObject, ParseObjectMutable {
struct GameScore: ParseObject {
//: These are required by ParseObject
var objectId: String?
var createdAt: Date?
var updatedAt: Date?
var ACL: ParseACL?
var originalData: Data?

//: Your own properties.
var points: Int = 0
var points: Int?

//: Implement your own version of merge
func merge(_ object: Self) throws -> Self {
var updated = try mergeParse(object)
if updated.shouldRestoreKey(\.points,
original: object) {
updated.points = object.points
}
return updated
}
}

//: It's recommended to place custom initializers in an extension
Expand All @@ -60,12 +71,27 @@ struct GameData: ParseObject {
var createdAt: Date?
var updatedAt: Date?
var ACL: ParseACL?
var originalData: Data?

//: Your own properties.
var polygon: ParsePolygon?
//: `ParseBytes` needs to be a part of the original schema
//: or else you will need your masterKey to force an upgrade.
var bytes: ParseBytes?

//: Implement your own version of merge
func merge(_ object: Self) throws -> Self {
var updated = try mergeParse(object)
if shouldRestoreKey(\.polygon,
original: object) {
updated.polygon = object.polygon
}
if shouldRestoreKey(\.bytes,
original: object) {
updated.bytes = object.bytes
}
return updated
}
}

//: It's recommended to place custom initializers in an extension
Expand Down Expand Up @@ -99,19 +125,14 @@ score.save { result in
allows you to only send the updated keys to the
parse server as opposed to the whole object.
*/
var changedScore = savedScore.mutable
var changedScore = savedScore.mergeable
changedScore.points = 200
changedScore.save { result in
switch result {
case .success(var savedChangedScore):
case .success(let savedChangedScore):
assert(savedChangedScore.points == 200)
assert(savedScore.objectId == savedChangedScore.objectId)

/*: Note that savedChangedScore is mutable since it's
a var after success.
*/
savedChangedScore.points = 500

case .failure(let error):
assertionFailure("Error saving: \(error)")
}
Expand All @@ -132,7 +153,10 @@ var score2ForFetchedLater: GameScore?
otherResults.forEach { otherResult in
switch otherResult {
case .success(let savedScore):
print("Saved \"\(savedScore.className)\" with points \(savedScore.points) successfully")
print("""
Saved \"\(savedScore.className)\" with
points \(String(describing: savedScore.points)) successfully
""")
if index == 1 {
score2ForFetchedLater = savedScore
}
Expand Down Expand Up @@ -191,14 +215,15 @@ assert(savedScore?.points == 10)
allows you to only send the updated keys to the
parse server as opposed to the whole object.
*/
guard var changedScore = savedScore?.mutable else {
fatalError()
guard var changedScore = savedScore?.mergeable else {
fatalError("Should have produced mutable changedScore")
}
changedScore.points = 200

let savedChangedScore: GameScore?
do {
savedChangedScore = try changedScore.save()
print("Updated score: \(String(describing: savedChangedScore))")
} catch {
savedChangedScore = nil
fatalError("Error saving: \(error)")
Expand All @@ -220,7 +245,7 @@ assert(otherResults != nil)
otherResults!.forEach { result in
switch result {
case .success(let savedScore):
print("Saved \"\(savedScore.className)\" with points \(savedScore.points) successfully")
print("Saved \"\(savedScore.className)\" with points \(String(describing: savedScore.points)) successfully")
case .failure(let error):
assertionFailure("Error saving: \(error)")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,20 @@ struct GameScore: ParseObject {
var createdAt: Date?
var updatedAt: Date?
var ACL: ParseACL?
var originalData: Data?

//: Your own properties.
var points: Int = 0
var points: Int?

//: Implement your own version of merge
func merge(_ object: Self) throws -> Self {
var updated = try mergeParse(object)
if updated.shouldRestoreKey(\.points,
original: object) {
updated.points = object.points
}
return updated
}
}

//: It's recommended to place custom initializers in an extension
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,30 @@ struct GameScore: ParseObject {
var createdAt: Date?
var updatedAt: Date?
var ACL: ParseACL?
var originalData: Data?

//: Your own properties.
var points: Int = 0
var points: Int?
var location: ParseGeoPoint?
var name: String?

//: Implement your own version of merge
func merge(_ object: Self) throws -> Self {
var updated = try mergeParse(object)
if updated.shouldRestoreKey(\.points,
original: object) {
updated.points = object.points
}
if updated.shouldRestoreKey(\.location,
original: object) {
updated.location = object.location
}
if updated.shouldRestoreKey(\.name,
original: object) {
updated.name = object.name
}
return updated
}
}

//: It's recommended to place custom initializers in an extension
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ struct User: ParseUser {
var createdAt: Date?
var updatedAt: Date?
var ACL: ParseACL?
var originalData: Data?

//: These are required by `ParseUser`.
var username: String?
Expand All @@ -29,6 +30,16 @@ struct User: ParseUser {

//: Your custom keys.
var customKey: String?

//: Implement your own version of merge
func merge(_ object: Self) throws -> Self {
var updated = try mergeParse(object)
if updated.shouldRestoreKey(\.customKey,
original: object) {
updated.customKey = object.customKey
}
return updated
}
}

struct Role<RoleUser: ParseUser>: ParseRole {
Expand All @@ -38,25 +49,43 @@ struct Role<RoleUser: ParseUser>: ParseRole {
var createdAt: Date?
var updatedAt: Date?
var ACL: ParseACL?
var originalData: Data?

//: Provided by Role.
var name: String

init() {
self.name = ""
var name: String?

//: Implement your own version of merge
func merge(_ object: Self) throws -> Self {
var updated = try mergeParse(object)
if updated.shouldRestoreKey(\.name,
original: object) {
updated.name = object.name
}
return updated
}
}

//: Create your own value typed `ParseObject`.
struct GameScore: ParseObject, ParseObjectMutable {
struct GameScore: ParseObject {
//: These are required by ParseObject
var objectId: String?
var createdAt: Date?
var updatedAt: Date?
var ACL: ParseACL?
var originalData: Data?

//: Your own properties.
var points: Int = 0
var points: Int?

//: Implement your own version of merge
func merge(_ object: Self) throws -> Self {
var updated = try mergeParse(object)
if updated.shouldRestoreKey(\.points,
original: object) {
updated.points = object.points
}
return updated
}
}

//: It's recommended to place custom initializers in an extension
Expand Down Expand Up @@ -136,7 +165,10 @@ 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)")
print("""
The following users are part of the
\"\(String(describing: savedRole!.name)) role: \(relatedUsers)
""")

case .failure(let error):
print("Error saving role: \(error)")
Expand Down Expand Up @@ -220,7 +252,10 @@ do {
savedRole!.queryRoles?.find { result in
switch result {
case .success(let relatedRoles):
print("The following roles are part of the \"\(savedRole!.name) role: \(relatedRoles)")
print("""
The following roles are part of the
\"\(String(describing: savedRole!.name)) role: \(relatedRoles)
""")

case .failure(let error):
print("Error saving role: \(error)")
Expand Down Expand Up @@ -263,7 +298,7 @@ let score2 = GameScore(points: 57)
switch result {
case .success(let saved):
print("The relation saved successfully: \(saved)")
print("Check \"pointss\" field in your \"_User\" class in Parse Dashboard.")
print("Check \"points\" field in your \"_User\" class in Parse Dashboard.")

case .failure(let error):
print("Error saving role: \(error)")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,25 @@ struct GameScore: ParseObject {
var createdAt: Date?
var updatedAt: Date?
var ACL: ParseACL?
var originalData: Data?

//: Your own properties.
var points: Int? = 0
var points: Int?
var name: String?

//: Implement your own version of merge
func merge(_ object: Self) throws -> Self {
var updated = try mergeParse(object)
if updated.shouldRestoreKey(\.points,
original: object) {
updated.points = object.points
}
if updated.shouldRestoreKey(\.name,
original: object) {
updated.name = object.name
}
return updated
}
}

//: It's recommended to place custom initializers in an extension
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,26 @@ npm start -- --appId applicationId --clientKey clientKey --masterKey masterKey -
initializeParseCustomObjectId()

//: Create your own value typed `ParseObject`.
struct GameScore: ParseObject, ParseObjectMutable {
struct GameScore: ParseObject {
//: These are required by ParseObject
var objectId: String?
var createdAt: Date?
var updatedAt: Date?
var ACL: ParseACL?
var originalData: Data?

//: Your own properties.
var points: Int = 0
var points: Int?

//: Implement your own version of merge
func merge(_ object: Self) throws -> Self {
var updated = try mergeParse(object)
if updated.shouldRestoreKey(\.points,
original: object) {
updated.points = object.points
}
return updated
}
}

//: It's recommended to place custom initializers in an extension
Expand Down Expand Up @@ -67,11 +78,11 @@ score.save { result in
print("Saved score: \(savedScore)")

/*: To modify, need to make it a var as the value type
was initialized as immutable. Using `mutable`
was initialized as immutable. Using `.mergeable`
allows you to only send the updated keys to the
parse server as opposed to the whole object.
*/
var changedScore = savedScore.mutable
var changedScore = savedScore.mergeable
changedScore.points = 200
changedScore.save { result in
switch result {
Expand Down
Loading