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 emptyObject property for sending modified keys to server #243

Merged
merged 8 commits into from
Sep 27, 2021

Conversation

cbaker6
Copy link
Contributor

@cbaker6 cbaker6 commented Sep 23, 2021

New Pull Request Checklist

Issue Description

When fetching a saved object and then calling .save, all keys are marked as dirty and saved to the backend, causing unnecessary traffic and database ops.

Related issue: #242

Approach

Developers were able to accomplish this before this PR by creating a new instance of their ParseObject, setting the objectId and createdAt to the object they want to modify, and then only modifying the needed keys. They could also do any of the following mentioned in #242 (comment).

This PR makes the process easier with less work on the developer by adding a computed property called emptyObject to all ParseObjects that provides a copy of the respective ParseObject that only contains the current objectId and createdAt. If developers wants to only modify a subset of the keys, they can modify a mutable version of the empty object. When the mutations of the empty object are saved, only those keys are sent to the server as opposed to sending keys that were not modified before the save. Example's on how to use are in the playgrounds as well as below:

//: Define initial GameScores.
let score = GameScore(score: 10)

/*: Save asynchronously (preferred way) - Performs work on background
    queue and returns to specified callbackQueue.
    If no callbackQueue is specified it returns to main queue.
*/
score.save { result in
    switch result {
    case .success(let savedScore):

        /*: To modify, need to make it a var as the value type
            was initialized as immutable. Using `emptyObject`
            allows you to only send the updated keys to the
            parse server as opposed to the whole object.
        */
        var changedScore = savedScore.emptyObject
        changedScore.score = 200
        changedScore.save { result in
            switch result {
            case .success:
                /*: Only the modified keys were sent to produce a successful save.
                */

            case .failure(let error):
                assertionFailure("Error saving: \(error)")
            }
        }
    case .failure(let error):
        assertionFailure("Error saving: \(error)")
    }
}

A "possible breaking change" is introduced depending on how developers have created initializers for their ParseObjects. If a developer had a ParseObject with inits that looked like:

//: Create your own value typed `ParseObject`.
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

    init(score: Int) {
        self.score = score
    }

    init(objectId: String?) {
        self.objectId = objectId
    }
}

it is recommended to leverage extensions to preserve the convenience initializer by converting to the following:

//: Create your own value typed `ParseObject`.
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
}

//: It's recommended to place custom initializers in an extension
//: to preserve the convenience initializer.
extension GameScore {

    init(score: Int) {
        self.score = score
    }

    init(objectId: String?) {
        self.objectId = objectId
    }
}

If developers already implemented the empty initializer, init() or already use extensions for inits, then no breaks to your code should occur. If the developer has required fields (non-optional fields) in their ParseObject's they have should already been specifying values or marking them as optional anyways as this prevents decoding the respective objects as parse Pointer's(see #157 (comment) for more info).

TODOs before merging

  • Add tests
  • Add entry to changelog
  • Add changes to documentation (guides, repository pages, in-code descriptions)

@parse-github-assistant
Copy link

parse-github-assistant bot commented Sep 23, 2021

Thanks for opening this pull request!

  • 🎉 We are excited about your hands-on contribution!

@cbaker6 cbaker6 linked an issue Sep 23, 2021 that may be closed by this pull request
4 tasks
@codecov
Copy link

codecov bot commented Sep 23, 2021

Codecov Report

Merging #243 (547c9b6) into main (087227e) will increase coverage by 0.03%.
The diff coverage is 100.00%.

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #243      +/-   ##
==========================================
+ Coverage   83.74%   83.78%   +0.03%     
==========================================
  Files          78       78              
  Lines        7365     7370       +5     
==========================================
+ Hits         6168     6175       +7     
+ Misses       1197     1195       -2     
Impacted Files Coverage Δ
Sources/ParseSwift/Objects/ParseObject.swift 78.53% <100.00%> (+0.01%) ⬆️
Sources/ParseSwift/Objects/ParseUser.swift 83.11% <0.00%> (+0.14%) ⬆️
Sources/ParseSwift/Types/Query.swift 95.15% <0.00%> (+0.15%) ⬆️
Sources/ParseSwift/Coding/AnyEncodable.swift 61.84% <0.00%> (+0.65%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 087227e...547c9b6. Read the comment docs.

@cbaker6 cbaker6 changed the title Add emptyObject method that for sending modified keys to server feat: Add emptyObject method that for sending modified keys to server Sep 23, 2021
@cbaker6
Copy link
Contributor Author

cbaker6 commented Sep 23, 2021

@dblythy let me know what you think about the property name, emptyObject. If you think of a more applicable name, feel free to suggest.

@cbaker6 cbaker6 changed the title feat: Add emptyObject method that for sending modified keys to server feat: Add emptyObject property that for sending modified keys to server Sep 23, 2021
@cbaker6 cbaker6 changed the title feat: Add emptyObject property that for sending modified keys to server feat: Add emptyObject property for sending modified keys to server Sep 23, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Partially updating an object sends the full object to the server
1 participant