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);
        }
Exemple #2
0
        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));
            });
        }
Exemple #3
0
        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);
        }
Exemple #5
0
        /// <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);
        }