public void TestLoadRevisionBody() { var document = database.CreateDocument(); var properties = new Dictionary <string, object>(); properties["foo"] = "foo"; properties["bar"] = false; properties["_id"] = document.Id; document.PutProperties(properties); properties["_rev"] = document.CurrentRevisionId; Assert.IsNotNull(document.CurrentRevision); var revisionInternal = new RevisionInternal( document.Id, document.CurrentRevisionId, false); database.LoadRevisionBody(revisionInternal); Assert.AreEqual(properties, revisionInternal.GetProperties()); revisionInternal.SetBody(null); // now lets purge the document, and then try to load the revision body again document.Purge(); var gotExpectedException = false; try { database.LoadRevisionBody(revisionInternal); } catch (CouchbaseLiteException e) { gotExpectedException |= e.CBLStatus.Code == StatusCode.NotFound; } Assert.IsTrue(gotExpectedException); }
public void LoadRevisionBody(RevisionInternal rev) { WithC4Document(rev.GetDocId(), rev.GetRevId(), true, false, doc => { if (doc == null) { throw new CouchbaseLiteException(StatusCode.NotFound); } rev.SetBody(new Body(doc->selectedRev.body)); }); }
public RevisionInternal GetParentRevision(RevisionInternal rev) { var retVal = default(RevisionInternal); WithC4Document(rev.GetDocId(), rev.GetRevId(), false, false, doc => { if (!Native.c4doc_selectParentRevision(doc)) { return; } ForestDBBridge.Check(err => Native.c4doc_loadRevisionBody(doc, err)); retVal = new RevisionInternal((string)doc->docID, (string)doc->selectedRev.revID, doc->selectedRev.IsDeleted); retVal.SetSequence((long)doc->selectedRev.sequence); retVal.SetBody(new Body(doc->selectedRev.body)); }); return(retVal); }
/// <summary> /// Attempt to update a document based on the information in the HTTP request /// </summary> /// <returns>The resulting status of the operation</returns> /// <param name="context">The request context</param> /// <param name="db">The database in which the document exists</param> /// <param name="docId">The ID of the document being updated</param> /// <param name="body">The new document body</param> /// <param name="deleting">Whether or not the document is being deleted</param> /// <param name="allowConflict">Whether or not to allow a conflict to be inserted</param> /// <param name="outRev">The resulting revision of the document</param> public static StatusCode UpdateDocument(ICouchbaseListenerContext context, Database db, string docId, Body body, bool deleting, bool allowConflict, out RevisionInternal outRev) { outRev = null; if (body != null && !body.IsValidJSON()) { return(StatusCode.BadJson); } string prevRevId; if (!deleting) { var properties = body.GetProperties(); deleting = properties.GetCast <bool>("_deleted"); if (docId == null) { // POST's doc ID may come from the _id field of the JSON body. docId = properties.CblID(); if (docId == null && deleting) { return(StatusCode.BadId); } } // PUT's revision ID comes from the JSON body. prevRevId = properties.GetCast <string>("_rev"); } else { // DELETE's revision ID comes from the ?rev= query param prevRevId = context.GetQueryParam("rev"); } // A backup source of revision ID is an If-Match header: if (prevRevId == null) { prevRevId = context.IfMatch(); } if (docId == null && deleting) { return(StatusCode.BadId); } RevisionInternal rev = new RevisionInternal(docId, null, deleting); rev.SetBody(body); // Check for doc expiration var expirationTime = default(DateTime?); var tmp = default(object); var props = rev.GetProperties(); var hasValue = false; if (props != null && props.TryGetValue("_exp", out tmp)) { hasValue = true; if (tmp != null) { if (tmp is DateTime || tmp is DateTimeOffset) { expirationTime = (DateTime)tmp; } else { try { expirationTime = Convert.ToDateTime(tmp); } catch (Exception) { try { var num = Convert.ToInt64(tmp); expirationTime = Misc.OffsetFromEpoch(TimeSpan.FromSeconds(num)); } catch (Exception) { Log.To.Router.E(TAG, "Invalid value for _exp: {0}", tmp); return(StatusCode.BadRequest); } } } } props.Remove("_exp"); rev.SetProperties(props); } var castContext = context as ICouchbaseListenerContext2; var source = castContext != null && !castContext.IsLoopbackRequest ? castContext.Sender : null; StatusCode status = deleting ? StatusCode.Ok : StatusCode.Created; try { if (docId != null && docId.StartsWith("_local")) { if (expirationTime.HasValue) { return(StatusCode.BadRequest); } Log.To.Router.I(TAG, "Attempting to insert local {0} on top of {1} from PUT request", rev, prevRevId != null ? prevRevId.ToString() : "<root>"); outRev = db.Storage.PutLocalRevision(rev, prevRevId.AsRevID(), true); //TODO: Doesn't match iOS } else { Log.To.Router.I(TAG, "Attempting to insert {0} on top of {1} from PUT request", rev, prevRevId != null ? prevRevId.ToString() : "<root>"); outRev = db.PutRevision(rev, prevRevId.AsRevID(), allowConflict, source); if (hasValue) { db.Storage?.SetDocumentExpiration(rev.DocID, expirationTime); } } } catch (CouchbaseLiteException e) { status = e.Code; } return(status); }
/// <summary> /// Attempt to update a document based on the information in the HTTP request /// </summary> /// <returns>The resulting status of the operation</returns> /// <param name="context">The request context</param> /// <param name="db">The database in which the document exists</param> /// <param name="docId">The ID of the document being updated</param> /// <param name="body">The new document body</param> /// <param name="deleting">Whether or not the document is being deleted</param> /// <param name="allowConflict">Whether or not to allow a conflict to be inserted</param> /// <param name="outRev">The resulting revision of the document</param> public static StatusCode UpdateDocument(ICouchbaseListenerContext context, Database db, string docId, Body body, bool deleting, bool allowConflict, out RevisionInternal outRev) { outRev = null; if (body != null && !body.IsValidJSON()) { return(StatusCode.BadJson); } string prevRevId; if (!deleting) { var properties = body.GetProperties(); deleting = properties.GetCast <bool>("_deleted"); if (docId == null) { // POST's doc ID may come from the _id field of the JSON body. docId = properties.GetCast <string>("_id"); if (docId == null && deleting) { return(StatusCode.BadId); } } // PUT's revision ID comes from the JSON body. prevRevId = properties.GetCast <string>("_rev"); } else { // DELETE's revision ID comes from the ?rev= query param prevRevId = context.GetQueryParam("rev"); } // A backup source of revision ID is an If-Match header: if (prevRevId == null) { prevRevId = context.IfMatch(); } if (docId == null && deleting) { return(StatusCode.BadId); } RevisionInternal rev = new RevisionInternal(docId, null, deleting); rev.SetBody(body); StatusCode status = StatusCode.Created; try { if (docId.StartsWith("_local")) { outRev = db.PutLocalRevision(rev, prevRevId); //TODO: Doesn't match iOS } else { Status retStatus = new Status(); outRev = db.PutRevision(rev, prevRevId, allowConflict, retStatus); status = retStatus.GetCode(); } } catch (CouchbaseLiteException e) { status = e.Code; } return(status); }