Local callback in Simperium triggered by a local update - simperium

I'm having problem with Simperium.
This little plnkr allows one user to create an account on my app, and authenticate with it.
Once you authenticate, you can modify the object_to_update object in the mydata_data bucket with a name: value pair (press the update button to do so!).
The problem is that I always get the bucket's local callback executed when updating the object_to_update object. I can't see why. The update is triggered locally (I don't have other remote stuff doing stuff on this page), but even triggering it locally always trigger the local callback.
The docs for local say:
This callback is triggered whenever the library needs to check what the current local state of an object is before it sends you a notify event. This is so any local changes can be incorporated into the updated object. In the example above, you may be syncing text input from a HTML element named "mytextfield". If there is an update available (this object was changed elsewhere), the library will expect to get the current state of the object so it can incorporate the local changes with the remote changes. When you get the notify event, then you can update "mytextfield" directly.
But the update was not triggered elsewhere, I'm triggering it locally!
The only way I see for the update to succeed as intended is to duplicate the update code:
bucket.update ("object_to_update", {on: va});
in the local callback, with the exactly same on and va values, but what's the point in duplicating it in the first place? There must be another explanation.

I believe the library is simply querying your app for the data it should send to the server. It's expected that calls to local will always return the most recent local data for an object (even if you've changed it elsewhere in your app).

Related

Graph calendar change notification sent for series master when instance is edited

I have created a subscription to my Outlook calendar. When a specific instance of a recurring event is edited in Outlook, the notification that is sent to my notification url is for the series master event (not the particular instance that was updated).
I am trying to determine if the change was to the series or to a specific instance.
Is there any way to find out from the notification (or the series master) what caused the notification?
When you get the instances for an event (using the Graph API), the exceptions come back first (before the occurrences).
Therefore, if the series master did not change, I check to see if there are any instances where Type == "Exception". If there are, I delete them from outlook so they don't come back the next time I query for the event instances.
NOTE- I am still trying to find a solution to retrieve cancelledOccurrences, those instances of a recurring event that are deleted (or declined) from Outlook and therefore are not returned when querying the Graph API for event instances (https://learn.microsoft.com/en-us/graph/api/event-list-instances?view=graph-rest-1.0&tabs=http).

How to update Relay store without pushing to server

I have a form in my React/Relay app that I am using to modify some fields. I don't want to send a server update every time a new letter is typed into an input. How can I use Relay to support the application state without always pushing to the server? Having read through most of the Relay docs it seems to me that I have to basically copy the Relay state either to the local state of my form or to some other Flux store, deal with changing it in there, and then commit it into Relay. That seems like a lot of extra work though just to keep a local state.
Relay current version is a glue between graphQL and React, it only handles the data from server.
...it seems to me that I have to basically copy the Relay state either
to the local state of my form...
I fail to see the problem. The way React works, requires you to store state for the whole form or for each input separately anyway.
If you add edit functionality (render form and fetch data to populate inputs for user to change them), all the Relay data is available as this.props.RelayFragmentName on form level anyway.
You pass it down to inputs where you assign it to state and circle is complete. You could also feed inputs directly from props (without assigning data to input state) and change form state from inputs via methods.
Now when user makes the changes and confirms it, you'll just collect all the state again to make a mutation.
I see it as a complete circle that is basically unbreakable if all the defaults are set.
Relay has imperative API to get, add or update cache directly but it's relatively dirty and rarely used (especially for local state). It's used for features like WebSockets where you want to push updates from server to client and update cache manually.
Current Relay is meant to work with server data only. Relay 2 has a local cache but it's not out yet.
If we're talking about different things or you could use some code samples, let me know.
In relay modern you can use commitLocalUpdate to do that.
For example
onEmailChange = (email) => {
commitLocalUpdate(environment, (proxy) => {
const userProxy = proxy.get(this.props.user.__id);
userProxy.setValue(email, 'email');
});
}

Cloudkit CKRecordZoneNotification how to know whether Add or modify happened

I am trying to implement Cloudkit sync with local cache (CoreData).
So far I managed to get the recordZone defined and get the relevant notifications. In the next step I check with CKFetchRecordChangesOperation what happened.
recordChangedBlock (i.e. according to Apple: ...for each record in the zone that changed since the previous fetch request....)
I do get the relevant record, but how do I know, whether this record was added or modified (without checking against my local cache)?
recordWithIDWasDeletedBlock I get the recordId, but how do I know which record it is in my local cache ? I could think of storing the recordId in the local cache in order to have a reference for such cases, but I can't believe that this is what I'm supposed to do...
Any suggestion is more than appreciated
There is no info in the recordChangedBlock that tells you whether it was added or changed. Keep in mind, even if it did, you still have to check whether the record exists or not in the local store. A record can be added into CloudKit and then changed several times all while your app isn't running. When your app finally runs, it will get only the last change notification. But the record doesn't exist in your local cache yet. So you must always see if you have the record locally or not and add/update accordingly.
With deletion, all you get is the CloudKit record id. Nothing else. What I do is ensure the CloudKit record id is based on the local key. This way I can easily find and remove the local record when the data is removed from Cloudkit. It also means that the local copy of the CloudKit data on all of the user's devices ends up with the same keys.

iOS: Auto-Sync in background with core data

I am developing a auto-sync application with offline functionality. User will be creating folder and documents and can sync with the server. There is a functionality of auto-sync in which sync with the server will happen in background every hour. During the sync process, user can also create, delete folders/document. All the changes are saved in core data. For changes to be send to server, i am maintaining a bool. If bool is NO then send those items to server and once response received set the bool to YES.
Now my problem is how can i make sure that changes done while sync is in process to be sent to server. Since sync is in process and during this if i make any changes to item which has been sent to server, even though sync bool is set to NO changes from server is update to YES again and these changes will not be send to server.
Note: I doesn't want to make any restrict to user while sync is in process.
How can i achieve this?
I'll tell you how we specifically solved this. In our syncing code, any attribute on any given object which a user can change also has an associated 'dirty flag', simply an additional boolean which is set whenever the user changes a property on an object in the main thread context (name has nameDirty, etc.). This boolean is automatically set based on a context pre-save notification observer, which checks the change dictionary of the context and marks attributes dirty as appropriate.
Sounds similar to your sync flag so far, though yours is per-object rather than per-attribute.
Any changes from the server will NOT be parsed into any attribute which has the dirty flag set to YES. Similarly, whenever a change is synced to the server, that flag is reset to NO so it will accept changes from the server again.
What happens when the user makes a change on the main context and the server parses in a change on the sync context (on a background thread) at the same time? That's where using the correct NSMergePolicy comes in. The main context has a merge policy telling its in-memory changes to trump anything in the database. Similarly, the sync context has a merge policy telling it to let any values in the database trump any in-memory changes in the sync context. (The same pre-save hook also pokes the sync context and tells it to sync any new changes to the server in the background.) This ensures the syncing process can never step on any changes the user just made on the main thread, even in a SQLite-level merge conflict.
The key here is the context separation between the context which takes user changes and the context which parses in server changes, as that allows us to very cleanly prioritize things and ensure bad merges can never happen. Both contexts are tied directly to the persistent store coordinator.
I'm working on a blog post about how our syncing framework works, but it's not quite done, so I don't have a link yet.
I know there are various third-party syncing libraries out there, and due to our unique requirements we chose to write our own, but I would definitely suggest seeing if any fit your needs out of the box.

iPhone Data Best Practices - caching vs remote

I'm developing an iPhone app that uses a user account and a web API to get results (json) from a website. The results are a list of user's events.
Just looking for some advice or strategies - when to cache and when to make an api call... and if the iPhone SDK has anything built in to handle these scenarios.
When I get the results from the server, they populate an array in a controller. In the UI, you can go from a table listing view, to a view of an individual event result - so two controllers share a reference to the same event object.
What gets tricky is that a user can change the details of an event. In this case I make a copy of the local Event object for the user's changes, in case they make an error. If the api call successfully goes through and updates that event on the server, I take these local changes from the Event copy and set the original Event object to match with setters.
I have the original controller observing if any change is made to the local Event object so that it can reflect it in the UI.
Is this the right way of doing things? I don't want to make too many API calls to reload data from the server, But after a user makes an update should I be pulling down the list again with the API call?
...I want to be careful that my local objects don't become out of sync with the remote.
Any advice is appreciated.
I took a similar approach with an app I built. I simply made a duplicate version of the remote data model with Core Data, and I use etags on the backend to prevent sync issues (in my case, it's okay to create duplicate records).
It sounds like you're taking a good approach to this.
Some time back, I developed an iOS app where in, I had almost same requirement to store data on server as well as locally to avoid several network call and also user can see their information without any delay.
In that app, user can store photos, nodes, checkIns and social media post and with all this data, app can form a beautiful timeline. So what we did was, we had everything locally and whenever user phone come in some WIFI zone, we start uploading that data to server and sync both (local and remote) databases.
Note this method works well when only one user can access this data.

Resources