private Tuple <PendingWriteAction, T> CacheSave(T entity) { PendingWriteAction pendingAction = null; T savedEntity = default(T); var idToken = JObject.FromObject(entity)["_id"]; if (idToken != null && !String.IsNullOrEmpty(idToken.ToString())) { var networkRequest = Client.NetworkFactory.buildUpdateRequest(Collection, entity, idToken.ToString()); savedEntity = Cache.Update(entity); pendingAction = PendingWriteAction.buildFromRequest(networkRequest); } else { var networkRequest = Client.NetworkFactory.buildCreateRequest(Collection, entity); var tempIdLocal = PrepareCacheSave(ref entity); savedEntity = Cache.Save(entity); pendingAction = PendingWriteAction.buildFromRequest(networkRequest); pendingAction.entityId = tempIdLocal; } return(new Tuple <PendingWriteAction, T>(pendingAction, savedEntity)); }
/// <summary> /// Removes pending write action item. /// </summary> /// <param name="pending"> Pending write action item. </param> /// <returns>The count of removed pending write action items.</returns> public int Remove(PendingWriteAction pending) { lock (dbConnection) { return(dbConnection.Delete(pending)); } }
private async Task <Tuple <T, KinveyException, int> > HandlePushDELETE(PendingWriteAction pwa) { var offset = 0; KinveyException kinveyException = null; try { int result = 0; NetworkRequest <KinveyDeleteResponse> request = Client.NetworkFactory.buildDeleteRequest <KinveyDeleteResponse>(pwa.collection, pwa.entityId); KinveyDeleteResponse kdr = await request.ExecuteAsync().ConfigureAwait(false); if (kdr.count == 1) { result = SyncQueue.Remove(pwa); if (result == 0) { offset++; } } } catch (KinveyException ke) { kinveyException = ke; offset++; } return(new Tuple <T, KinveyException, int>(default(T), kinveyException, offset)); }
private async Task <Tuple <T, KinveyException, int> > HandlePushPUT(PendingWriteAction pwa) { T entity = default(T); var offset = 0; KinveyException kinveyException = null; try { int result = 0; var localEntity = Cache.FindByID(pwa.entityId); NetworkRequest <T> request = Client.NetworkFactory.buildUpdateRequest <T>(pwa.collection, localEntity, pwa.entityId); entity = await request.ExecuteAsync().ConfigureAwait(false); Cache.UpdateCacheSave(entity, pwa.entityId); result = SyncQueue.Remove(pwa); if (result == 0) { offset++; } } catch (KinveyException ke) { kinveyException = ke; offset++; } return(new Tuple <T, KinveyException, int>(entity, kinveyException, offset)); }
/// <summary> /// Fetches and deletes the first pending write action item. /// </summary> /// <returns> Received pending write action item from the cache. </returns> public PendingWriteAction Pop() { lock (dbConnection) { try { PendingWriteAction item = Peek(); dbConnection.Delete <PendingWriteAction>(item.key); return(item); } catch (Exception) { return(null); } } }
public static PendingWriteAction buildFromRequest <T> (NetworkRequest <T> request) { PendingWriteAction newAction = new PendingWriteAction(); newAction.action = request.RequestMethod; if (request.uriResourceParameters.ContainsKey("entityID")) { newAction.entityId = request.uriResourceParameters["entityID"]; } if (request.uriResourceParameters.ContainsKey("collectionName")) { newAction.collection = request.uriResourceParameters["collectionName"]; } newAction.state = JsonConvert.SerializeObject(request.customRequestHeaders); return(newAction); }
private async Task <Tuple <T, KinveyException, int> > HandlePushPOST(PendingWriteAction pwa) { T entity = default(T); var offset = 0; KinveyException kinveyException = null; try { int result = 0; string tempID = pwa.entityId; var localEntity = Cache.FindByID(pwa.entityId); JObject obj = JObject.FromObject(localEntity); obj["_id"] = null; localEntity = Newtonsoft.Json.JsonConvert.DeserializeObject <T>(obj.ToString()); NetworkRequest <T> request = Client.NetworkFactory.buildCreateRequest <T>(pwa.collection, localEntity); entity = await request.ExecuteAsync().ConfigureAwait(false); Cache.UpdateCacheSave(entity, tempID); result = SyncQueue.Remove(pwa); if (result == 0) { offset++; } } catch (KinveyException ke) { kinveyException = ke; offset++; } return(new Tuple <T, KinveyException, int>(entity, kinveyException, offset)); }
public override async Task <T> ExecuteAsync() { T savedEntity = default(T); NetworkRequest <T> request = null; string entityID = null;; JToken idToken = JObject.FromObject(entity) ["_id"]; if (idToken != null && !String.IsNullOrEmpty(idToken.ToString())) { entityID = idToken.ToString(); request = Client.NetworkFactory.buildUpdateRequest(Collection, entity, entityID); } else { request = Client.NetworkFactory.buildCreateRequest(Collection, entity); } switch (Policy) { case WritePolicy.FORCE_LOCAL: // sync PendingWriteAction pendingAction = PendingWriteAction.buildFromRequest(request); string saveModeLocal = request.RequestMethod; string tempIdLocal = null; if (String.Equals("POST", saveModeLocal)) { tempIdLocal = PrepareCacheSave(ref entity); savedEntity = Cache.Save(entity); pendingAction.entityId = tempIdLocal; } else { savedEntity = Cache.Update(entity); } SyncQueue.Enqueue(pendingAction); break; case WritePolicy.FORCE_NETWORK: // network savedEntity = await request.ExecuteAsync(); break; case WritePolicy.NETWORK_THEN_LOCAL: // cache string saveModeNetworkThenLocal = request.RequestMethod; string tempIdNetworkThenLocal = null; if (String.Equals("POST", saveModeNetworkThenLocal)) { tempIdNetworkThenLocal = PrepareCacheSave(ref entity); Cache.Save(entity); } else { Cache.Update(entity); } // network save savedEntity = await request.ExecuteAsync(); if (tempIdNetworkThenLocal != null) { Cache.UpdateCacheSave(savedEntity, tempIdNetworkThenLocal); } break; case WritePolicy.LOCAL_THEN_NETWORK: string saveModeLocalThenNetwork = request.RequestMethod; // cache if (String.Equals("POST", saveModeLocalThenNetwork)) { entityID = PrepareCacheSave(ref entity); savedEntity = Cache.Save(entity); } else { savedEntity = Cache.Update(entity); } KinveyException kinveyException = null; Exception exception = null; try { // network save savedEntity = await request.ExecuteAsync(); } catch (KinveyException kinveyEx) { kinveyException = kinveyEx; } catch (Exception ex) { exception = ex; } if (kinveyException != null || exception != null) { // if the network request fails, save data to sync queue var localPendingAction = PendingWriteAction.buildFromRequest(request); localPendingAction.entityId = entityID; SyncQueue.Enqueue(localPendingAction); if (kinveyException != null) { throw kinveyException; } } else { Cache.UpdateCacheSave(savedEntity, entityID); } break; default: throw new KinveyException(EnumErrorCategory.ERROR_GENERAL, EnumErrorCode.ERROR_GENERAL, "Invalid write policy"); } return(savedEntity); }
/// <summary> /// Enqueues a pending write action item. /// </summary> /// <returns>The count of enqueued pending write action items.</returns> /// <param name="pending">Pending write action item.</param> public int Enqueue(PendingWriteAction pending) { lock (dbConnection) { // Check if a sync queue entry for this entity already exists PendingWriteAction existingSyncItem = GetByID(pending.entityId); if (existingSyncItem != null) { if (existingSyncItem.action == Constants.STR_REST_METHOD_PUT && pending.action == Constants.STR_REST_METHOD_PUT) { // If both the existing and pending actions are PUT, this means either this is an already created // item, or the item has been created with a custom ID on the client. In either case, the existing // entry will capture the state of the entity. return(0); } else if (existingSyncItem.action == Constants.STR_REST_METHOD_POST && pending.action == Constants.STR_REST_METHOD_PUT) { // Do not enqueue in the case of an existing POST, since the POST // entry will already capture the current state of the entity. return(0); } else if (existingSyncItem.action == Constants.STR_REST_METHOD_PUT && pending.action == Constants.STR_REST_METHOD_POST) { // highly unlikely, but favor the POST this.Remove(existingSyncItem); } else if (existingSyncItem.action == Constants.STR_REST_METHOD_POST && pending.action == Constants.STR_REST_METHOD_POST) { // Should be imposssible to have this situation, favor the // existing POST by not enqueueing return(0); } else if (existingSyncItem.action == Constants.STR_REST_METHOD_DELETE && (pending.action == Constants.STR_REST_METHOD_PUT || pending.action == Constants.STR_REST_METHOD_POST)) { // odd case where an object has somehow been created/updated // after a delete call, but favor the create/update this.Remove(existingSyncItem); } else if (pending.action == Constants.STR_REST_METHOD_DELETE) { // no matter what, favor the current deletion this.Remove(existingSyncItem); // If the existing item that is being deleted is something that only existed locally, // do not insert the DELETE action into the queue, since it is local-only. // Note that this cannot be optimized for the case when a custom ID has been set on // the entity. if (existingSyncItem.entityId.StartsWith("temp_", StringComparison.OrdinalIgnoreCase)) { return(0); } } } return(dbConnection.Insert(pending)); } }
public override async Task <KinveyDeleteResponse> ExecuteAsync() { var kdr = default(KinveyDeleteResponse); switch (Policy) { case WritePolicy.FORCE_LOCAL: // sync if (_query == null) { // cache kdr = Cache.DeleteByID(entityID); var request = Client.NetworkFactory.buildDeleteRequest <KinveyDeleteResponse>(Collection, entityID); var pendingAction = PendingWriteAction.buildFromRequest(request); SyncQueue.Enqueue(pendingAction); } else { // cache kdr = Cache.DeleteByQuery(_query); foreach (var id in kdr.IDs) { var request = Client.NetworkFactory.buildDeleteRequest <KinveyDeleteResponse>(Collection, id); var pendingAction = PendingWriteAction.buildFromRequest(request); SyncQueue.Enqueue(pendingAction); } } break; case WritePolicy.FORCE_NETWORK: // network if (_query == null) { kdr = await Client.NetworkFactory.buildDeleteRequest <KinveyDeleteResponse>(Collection, entityID).ExecuteAsync(); } else { var mongoQuery = KinveyMongoQueryBuilder.GetQueryForRemoveOperation <T>(_query); kdr = await Client.NetworkFactory.buildDeleteRequestWithQuery <KinveyDeleteResponse>(Collection, mongoQuery).ExecuteAsync(); } break; case WritePolicy.NETWORK_THEN_LOCAL: if (_query == null) { // cache kdr = Cache.DeleteByID(entityID); // network kdr = await Client.NetworkFactory.buildDeleteRequest <KinveyDeleteResponse>(Collection, entityID).ExecuteAsync(); } else { // cache kdr = Cache.DeleteByQuery(_query); // network var mongoQuery = KinveyMongoQueryBuilder.GetQueryForRemoveOperation <T>(_query); kdr = await Client.NetworkFactory.buildDeleteRequestWithQuery <KinveyDeleteResponse>(Collection, mongoQuery).ExecuteAsync(); } break; case WritePolicy.LOCAL_THEN_NETWORK: if (_query == null) { // cache kdr = Cache.DeleteByID(entityID); var deleteRequest = Client.NetworkFactory.buildDeleteRequest <KinveyDeleteResponse>(Collection, entityID); KinveyException kinveyException = null; Exception exception = null; try { // network kdr = await deleteRequest.ExecuteAsync(); } catch (KinveyException kinveyEx) { kinveyException = kinveyEx; } catch (Exception ex) { exception = ex; } if (kinveyException != null || exception != null) { var pendingAction = PendingWriteAction.buildFromRequest(deleteRequest); SyncQueue.Enqueue(pendingAction); if (kinveyException != null) { throw kinveyException; } } } else { // cache kdr = Cache.DeleteByQuery(_query); // network KinveyException kinveyException = null; Exception exception = null; try { var mongoQuery = KinveyMongoQueryBuilder.GetQueryForRemoveOperation <T>(_query); kdr = await Client.NetworkFactory.buildDeleteRequestWithQuery <KinveyDeleteResponse>(Collection, mongoQuery).ExecuteAsync(); } catch (KinveyException kinveyEx) { kinveyException = kinveyEx; } catch (Exception ex) { exception = ex; } if (kinveyException != null || exception != null) { foreach (var id in kdr.IDs) { var request = Client.NetworkFactory.buildDeleteRequest <KinveyDeleteResponse>(Collection, id); var pendingAction = PendingWriteAction.buildFromRequest(request); SyncQueue.Enqueue(pendingAction); } if (kinveyException != null) { throw kinveyException; } } } break; default: throw new KinveyException(EnumErrorCategory.ERROR_GENERAL, EnumErrorCode.ERROR_GENERAL, "Invalid write policy"); } return(kdr); }