internal RevisionInternal CopyWithoutBody() { if (_body == null) { return(this); } var rev = new RevisionInternal(_docId, _revId, _deleted); rev.SetSequence(_sequence); rev.SetMissing(_missing); return(rev); }
internal RevisionInternal GetDocumentWithIDAndRev(String id, String rev, DocumentContentOptions contentOptions) { RevisionInternal result = null; string sql; Cursor cursor = null; try { cursor = null; var cols = "revid, deleted, sequence, no_attachments"; if (!contentOptions.HasFlag(DocumentContentOptions.NoBody)) { cols += ", json"; } if (rev != null) { sql = "SELECT " + cols + " FROM revs, docs WHERE docs.docid=? AND revs.doc_id=docs.doc_id AND revid=? LIMIT 1"; //TODO: mismatch w iOS: {sql = "SELECT " + cols + " FROM revs WHERE revs.doc_id=? AND revid=? AND json notnull LIMIT 1";} var args = new[] { id, rev }; cursor = StorageEngine.RawQuery(sql, args); } else { sql = "SELECT " + cols + " FROM revs, docs WHERE docs.docid=? AND revs.doc_id=docs.doc_id and current=1 and deleted=0 ORDER BY revid DESC LIMIT 1"; //TODO: mismatch w iOS: {sql = "SELECT " + cols + " FROM revs WHERE revs.doc_id=? and current=1 and deleted=0 ORDER BY revid DESC LIMIT 1";} var args = new[] { id }; cursor = StorageEngine.RawQuery(sql, CommandBehavior.SequentialAccess, args); } if (cursor.MoveToNext()) { if (rev == null) { rev = cursor.GetString(0); } var deleted = cursor.GetInt(1) > 0; result = new RevisionInternal(id, rev, deleted, this); result.SetSequence(cursor.GetLong(2)); if (contentOptions != DocumentContentOptions.NoBody) { byte[] json = null; if (!contentOptions.HasFlag(DocumentContentOptions.NoBody)) { json = cursor.GetBlob(4); } if (cursor.GetInt(3) > 0) { // no_attachments == true contentOptions |= DocumentContentOptions.NoAttachments; } ExpandStoredJSONIntoRevisionWithAttachments(json, result, contentOptions); } } } catch (Exception e) { Log.E(Tag, "Error getting document with id and rev", e); } finally { if (cursor != null) { cursor.Close(); } } return result; }
internal RevisionInternal GetParentRevision(RevisionInternal rev) { // First get the parent's sequence: var seq = rev.GetSequence(); if (seq > 0) { seq = LongForQuery("SELECT parent FROM revs WHERE sequence=?", new [] { Convert.ToString(seq) }); } else { var docNumericID = GetDocNumericID(rev.GetDocId()); if (docNumericID <= 0) { return null; } var args = new [] { Convert.ToString(docNumericID), rev.GetRevId() }; seq = LongForQuery("SELECT parent FROM revs WHERE doc_id=? and revid=?", args); } if (seq == 0) { return null; } // Now get its revID and deletion status: RevisionInternal result = null; var queryArgs = new [] { Convert.ToString(seq) }; var queryString = "SELECT revid, deleted FROM revs WHERE sequence=?"; Cursor cursor = null; try { cursor = StorageEngine.RawQuery(queryString, queryArgs); if (cursor.MoveToNext()) { string revId = cursor.GetString(0); bool deleted = (cursor.GetInt(1) > 0); result = new RevisionInternal(rev.GetDocId(), revId, deleted, this); result.SetSequence(seq); } } finally { cursor.Close(); } return result; }
internal IDictionary<String, Object> DocumentPropertiesFromJSON(IEnumerable<Byte> json, String docId, String revId, Boolean deleted, Int64 sequence, DocumentContentOptions contentOptions) { var rev = new RevisionInternal(docId, revId, deleted, this); rev.SetSequence(sequence); IDictionary<String, Object> extra = ExtraPropertiesForRevision(rev, contentOptions); if (json == null) { return extra; } IDictionary<String, Object> docProperties = null; try { docProperties = Manager.GetObjectMapper().ReadValue<IDictionary<string, object>>(json); docProperties.PutAll(extra); } catch (Exception e) { Log.E(Tag, "Error serializing properties to JSON", e); } return docProperties; }
internal RevisionList ChangesSince(long lastSeq, ChangesOptions options, FilterDelegate filter) { // http://wiki.apache.org/couchdb/HTTP_database_API#Changes if (options == null) { options = new ChangesOptions(); } var includeDocs = options.IsIncludeDocs() || (filter != null); var additionalSelectColumns = string.Empty; if (includeDocs) { additionalSelectColumns = ", json"; } var sql = "SELECT sequence, revs.doc_id, docid, revid, deleted" + additionalSelectColumns + " FROM revs, docs " + "WHERE sequence > ? AND current=1 " + "AND revs.doc_id = docs.doc_id " + "ORDER BY revs.doc_id, revid DESC"; var args = lastSeq; Cursor cursor = null; RevisionList changes = null; try { cursor = StorageEngine.RawQuery(sql, CommandBehavior.SequentialAccess, args); cursor.MoveToNext(); changes = new RevisionList(); long lastDocId = 0; while (!cursor.IsAfterLast()) { if (!options.IsIncludeConflicts()) { // Only count the first rev for a given doc (the rest will be losing conflicts): var docNumericId = cursor.GetLong(1); if (docNumericId == lastDocId) { cursor.MoveToNext(); continue; } lastDocId = docNumericId; } var sequence = cursor.GetLong(0); var rev = new RevisionInternal(cursor.GetString(2), cursor.GetString(3), (cursor.GetInt(4) > 0), this); rev.SetSequence(sequence); if (includeDocs) { ExpandStoredJSONIntoRevisionWithAttachments(cursor.GetBlob(5), rev, options.GetContentOptions()); } IDictionary<string, object> paramsFixMe = null; // TODO: these should not be null if (RunFilter(filter, paramsFixMe, rev)) { changes.AddItem(rev); } cursor.MoveToNext(); } } catch (SQLException e) { Log.E(Tag, "Error looking for changes", e); } finally { if (cursor != null) { cursor.Close(); } } if (options.IsSortBySequence()) { changes.SortBySequence(); } changes.Limit(options.GetLimit()); return changes; }
public RevisionInternal PutRevision(string inDocId, string inPrevRevId, IDictionary<string, object> properties, bool deleting, bool allowConflict, StoreValidation validationBlock) { if(_config.HasFlag(C4DatabaseFlags.ReadOnly)) { throw new CouchbaseLiteException("Attempting to write to a readonly database", StatusCode.Forbidden); } var json = default(string); if (properties != null) { json = Manager.GetObjectMapper().WriteValueAsString(Database.StripDocumentJSON(properties), true); } else { json = "{}"; } if (inDocId == null) { inDocId = Misc.CreateGUID(); } var putRev = default(RevisionInternal); var change = default(DocumentChange); var success = RunInTransaction(() => { var docId = inDocId; var prevRevId = inPrevRevId; var transactionSuccess = false; WithC4Document(docId, null, false, true, doc => { if(prevRevId != null) { // Updating an existing revision; make sure it exists and is a leaf: ForestDBBridge.Check(err => Native.c4doc_selectRevision(doc, prevRevId, false, err)); if(!allowConflict && !doc->selectedRev.IsLeaf) { throw new CouchbaseLiteException(StatusCode.Conflict); } } else { // No parent revision given: if(deleting) { // Didn't specify a revision to delete: NotFound or a Conflict, depending throw new CouchbaseLiteException(doc->Exists ? StatusCode.Conflict : StatusCode.NotFound); } // If doc exists, current rev must be in a deleted state or there will be a conflict: if(Native.c4doc_selectCurrentRevision(doc)) { if(doc->selectedRev.IsDeleted) { // New rev will be child of the tombstone: prevRevId = (string)doc->revID; } else { throw new CouchbaseLiteException(StatusCode.Conflict); } } } // Compute the new revID. (Can't be done earlier because prevRevID may have changed.) var newRevID = Delegate != null ? Delegate.GenerateRevID(Encoding.UTF8.GetBytes(json), deleting, prevRevId) : null; if(newRevID == null) { throw new CouchbaseLiteException(StatusCode.BadId); } putRev = new RevisionInternal(docId, newRevID, deleting); if(properties != null) { properties["_id"] = docId; properties["_rev"] = newRevID; putRev.SetProperties(properties); } // Run any validation blocks: if(validationBlock != null) { var prevRev = default(RevisionInternal); if(prevRevId != null) { prevRev = new RevisionInternal(docId, prevRevId, doc->selectedRev.IsDeleted); } var status = validationBlock(putRev, prevRev, prevRevId); if(status.IsError) { throw new CouchbaseLiteException(String.Format("{0} failed validation", putRev), status.Code); } } // Add the revision to the database: ForestDBBridge.Check(err => Native.c4doc_insertRevision(doc, newRevID, json, deleting, putRev.GetAttachments() != null, allowConflict, err)); var isWinner = SaveDocument(doc, newRevID, properties); putRev.SetSequence((long)doc->sequence); change = ChangeWithNewRevision(putRev, isWinner, doc, null); transactionSuccess = true; }); return transactionSuccess; }); if (!success) { return null; } if (Delegate != null && change != null) { Delegate.DatabaseStorageChanged(change); } return putRev; }
public IDictionary<string, object> DocumentPropertiesFromJSON(byte[] json, string docId, string revId, bool deleted, long sequence, EnumSet<Database.TDContentOptions > contentOptions) { RevisionInternal rev = new RevisionInternal(docId, revId, deleted, this); rev.SetSequence(sequence); IDictionary<string, object> extra = ExtraPropertiesForRevision(rev, contentOptions ); if (json == null) { return extra; } IDictionary<string, object> docProperties = null; try { docProperties = Manager.GetObjectMapper().ReadValue<IDictionary>(json); docProperties.PutAll(extra); return docProperties; } catch (Exception e) { Log.E(Database.Tag, "Error serializing properties to JSON", e); } return docProperties; }
/// <exception cref="Couchbase.Lite.CouchbaseLiteException"></exception> internal RevisionInternal LoadRevisionBody(RevisionInternal rev, DocumentContentOptions contentOptions) { if (rev.GetBody() != null && contentOptions == DocumentContentOptions.None && rev.GetSequence() != 0) { return rev; } if ((rev.GetDocId() == null) || (rev.GetRevId() == null)) { Log.E(Database.Tag, "Error loading revision body"); throw new CouchbaseLiteException(StatusCode.PreconditionFailed); } Cursor cursor = null; var result = new Status(StatusCode.NotFound); try { // TODO: on ios this query is: // TODO: "SELECT sequence, json FROM revs WHERE doc_id=@ AND revid=@ LIMIT 1" var sql = "SELECT sequence, json FROM revs, docs WHERE revid=? AND docs.docid=? AND revs.doc_id=docs.doc_id LIMIT 1"; var args = new [] { rev.GetRevId(), rev.GetDocId() }; cursor = StorageEngine.RawQuery(sql, CommandBehavior.SequentialAccess, args); if (cursor.MoveToNext()) { result.SetCode(StatusCode.Ok); rev.SetSequence(cursor.GetLong(0)); ExpandStoredJSONIntoRevisionWithAttachments(cursor.GetBlob(1), rev, contentOptions); } } catch (SQLException e) { Log.E(Tag, "Error loading revision body", e); throw new CouchbaseLiteException(StatusCode.InternalServerError); } finally { if (cursor != null) { cursor.Close(); } } if (result.GetCode() == StatusCode.NotFound) { throw new CouchbaseLiteException(result.GetCode()); } return rev; }
public IList<RevisionInternal> GetRevisionHistory(RevisionInternal rev) { string docId = rev.GetDocId(); string revId = rev.GetRevId(); System.Diagnostics.Debug.Assert(((docId != null) && (revId != null))); long docNumericId = GetDocNumericID(docId); if (docNumericId < 0) { return null; } else { if (docNumericId == 0) { return new AList<RevisionInternal>(); } } string sql = "SELECT sequence, parent, revid, deleted, json isnull FROM revs " + "WHERE doc_id=? ORDER BY sequence DESC"; string[] args = new string[] { System.Convert.ToString(docNumericId) }; Cursor cursor = null; IList<RevisionInternal> result; try { cursor = database.RawQuery(sql, args); cursor.MoveToNext(); long lastSequence = 0; result = new AList<RevisionInternal>(); while (!cursor.IsAfterLast()) { long sequence = cursor.GetLong(0); bool matches = false; if (lastSequence == 0) { matches = revId.Equals(cursor.GetString(2)); } else { matches = (sequence == lastSequence); } if (matches) { revId = cursor.GetString(2); bool deleted = (cursor.GetInt(3) > 0); bool missing = (cursor.GetInt(4) > 0); RevisionInternal aRev = new RevisionInternal(docId, revId, deleted, this); aRev.SetMissing(missing); aRev.SetSequence(cursor.GetLong(0)); result.AddItem(aRev); lastSequence = cursor.GetLong(1); if (lastSequence == 0) { break; } } cursor.MoveToNext(); } } catch (SQLException e) { Log.E(Database.Tag, "Error getting revision history", e); return null; } finally { if (cursor != null) { cursor.Close(); } } return result; }
public long InsertRevision(RevisionInternal rev, long docNumericID, long parentSequence , bool current, byte[] data) { long rowId = 0; try { ContentValues args = new ContentValues(); args.Put("doc_id", docNumericID); args.Put("revid", rev.GetRevId()); if (parentSequence != 0) { args.Put("parent", parentSequence); } args.Put("current", current); args.Put("deleted", rev.IsDeleted()); args.Put("json", data); rowId = database.Insert("revs", null, args); rev.SetSequence(rowId); } catch (Exception e) { Log.E(Database.Tag, "Error inserting revision", e); } return rowId; }
public RevisionList GetAllRevisionsOfDocumentID(string docId, long docNumericID, bool onlyCurrent) { string sql = null; if (onlyCurrent) { sql = "SELECT sequence, revid, deleted FROM revs " + "WHERE doc_id=? AND current ORDER BY sequence DESC"; } else { sql = "SELECT sequence, revid, deleted FROM revs " + "WHERE doc_id=? ORDER BY sequence DESC"; } string[] args = new string[] { System.Convert.ToString(docNumericID) }; Cursor cursor = null; cursor = database.RawQuery(sql, args); RevisionList result; try { cursor.MoveToNext(); result = new RevisionList(); while (!cursor.IsAfterLast()) { RevisionInternal rev = new RevisionInternal(docId, cursor.GetString(1), (cursor.GetInt (2) > 0), this); rev.SetSequence(cursor.GetLong(0)); result.AddItem(rev); cursor.MoveToNext(); } } catch (SQLException e) { Log.E(Database.Tag, "Error getting all revisions of document", e); return null; } finally { if (cursor != null) { cursor.Close(); } } return result; }
public RevisionInternal LoadRevisionBody(RevisionInternal rev, EnumSet<Database.TDContentOptions > contentOptions) { if (rev.GetBody() != null && contentOptions == EnumSet.NoneOf<Database.TDContentOptions >() && rev.GetSequence() != 0) { return rev; } System.Diagnostics.Debug.Assert(((rev.GetDocId() != null) && (rev.GetRevId() != null ))); Cursor cursor = null; Status result = new Status(Status.NotFound); try { // TODO: on ios this query is: // TODO: "SELECT sequence, json FROM revs WHERE doc_id=? AND revid=? LIMIT 1" string sql = "SELECT sequence, json FROM revs, docs WHERE revid=? AND docs.docid=? AND revs.doc_id=docs.doc_id LIMIT 1"; string[] args = new string[] { rev.GetRevId(), rev.GetDocId() }; cursor = database.RawQuery(sql, args); if (cursor.MoveToNext()) { result.SetCode(Status.Ok); rev.SetSequence(cursor.GetLong(0)); ExpandStoredJSONIntoRevisionWithAttachments(cursor.GetBlob(1), rev, contentOptions ); } } catch (SQLException e) { Log.E(Database.Tag, "Error loading revision body", e); throw new CouchbaseLiteException(Status.InternalServerError); } finally { if (cursor != null) { cursor.Close(); } } if (result.GetCode() == Status.NotFound) { throw new CouchbaseLiteException(result); } return rev; }
public RevisionInternal GetDocumentWithIDAndRev(string id, string rev, EnumSet<Database.TDContentOptions > contentOptions) { RevisionInternal result = null; string sql; Cursor cursor = null; try { cursor = null; string cols = "revid, deleted, sequence"; if (!contentOptions.Contains(Database.TDContentOptions.TDNoBody)) { cols += ", json"; } if (rev != null) { sql = "SELECT " + cols + " FROM revs, docs WHERE docs.docid=? AND revs.doc_id=docs.doc_id AND revid=? LIMIT 1"; string[] args = new string[] { id, rev }; cursor = database.RawQuery(sql, args); } else { sql = "SELECT " + cols + " FROM revs, docs WHERE docs.docid=? AND revs.doc_id=docs.doc_id and current=1 and deleted=0 ORDER BY revid DESC LIMIT 1"; string[] args = new string[] { id }; cursor = database.RawQuery(sql, args); } if (cursor.MoveToNext()) { if (rev == null) { rev = cursor.GetString(0); } bool deleted = (cursor.GetInt(1) > 0); result = new RevisionInternal(id, rev, deleted, this); result.SetSequence(cursor.GetLong(2)); if (!contentOptions.Equals(EnumSet.Of(Database.TDContentOptions.TDNoBody))) { byte[] json = null; if (!contentOptions.Contains(Database.TDContentOptions.TDNoBody)) { json = cursor.GetBlob(3); } ExpandStoredJSONIntoRevisionWithAttachments(json, result, contentOptions); } } } catch (SQLException e) { Log.E(Database.Tag, "Error getting document with id and rev", e); } finally { if (cursor != null) { cursor.Close(); } } return result; }
/// <summary>Returns an array of TDRevs in reverse chronological order, starting with the given revision. /// </summary> /// <remarks>Returns an array of TDRevs in reverse chronological order, starting with the given revision. /// </remarks> internal IList<RevisionInternal> GetRevisionHistory(RevisionInternal rev) { string docId = rev.GetDocId(); string revId = rev.GetRevId(); Debug.Assert(((docId != null) && (revId != null))); long docNumericId = GetDocNumericID(docId); if (docNumericId < 0) { return null; } else { if (docNumericId == 0) { return new AList<RevisionInternal>(); } } Cursor cursor = null; IList<RevisionInternal> result; var args = new [] { Convert.ToString(docNumericId) }; var sql = "SELECT sequence, parent, revid, deleted, json isnull FROM revs WHERE doc_id=? ORDER BY sequence DESC"; try { cursor = StorageEngine.RawQuery(sql, args); cursor.MoveToNext(); long lastSequence = 0; result = new AList<RevisionInternal>(); while (!cursor.IsAfterLast()) { var sequence = cursor.GetLong(0); var parent = cursor.GetLong(1); bool matches = false; if (lastSequence == 0) { matches = revId.Equals(cursor.GetString(2)); } else { matches = (sequence == lastSequence); } if (matches) { revId = cursor.GetString(2); var deleted = (cursor.GetInt(3) > 0); var missing = (cursor.GetInt(4) > 0); var aRev = new RevisionInternal(docId, revId, deleted, this); aRev.SetSequence(sequence); aRev.SetMissing(missing); result.AddItem(aRev); if (parent > -1) lastSequence = parent; if (lastSequence == 0) { break; } } cursor.MoveToNext(); } } catch (SQLException e) { Log.E(Tag, "Error getting revision history", e); return null; } finally { if (cursor != null) { cursor.Close(); } } return result; }
public void ForceInsert(RevisionInternal inRev, IList<string> revHistory, StoreValidation validationBlock, Uri source) { if (_config.HasFlag(C4DatabaseFlags.ReadOnly)) { throw new CouchbaseLiteException("Attempting to write to a readonly database", StatusCode.Forbidden); } var json = Manager.GetObjectMapper().WriteValueAsString(inRev.GetProperties(), true); var change = default(DocumentChange); RunInTransaction(() => { // First get the CBForest doc: WithC4Document(inRev.GetDocId(), null, false, true, doc => { ForestDBBridge.Check(err => Native.c4doc_insertRevisionWithHistory(doc, json, inRev.IsDeleted(), inRev.GetAttachments() != null, revHistory.ToArray(), err)); // Save updated doc back to the database: var isWinner = SaveDocument(doc, revHistory[0], inRev.GetProperties()); inRev.SetSequence((long)doc->sequence); change = ChangeWithNewRevision(inRev, isWinner, doc, source); }); return true; }); if (change != null && Delegate != null) { Delegate.DatabaseStorageChanged(change); } }
internal Int64 InsertRevision(RevisionInternal rev, long docNumericID, long parentSequence, bool current, bool hasAttachments, IEnumerable<byte> data) { var rowId = 0L; try { var args = new ContentValues(); args["doc_id"] = docNumericID; args.Put("revid", rev.GetRevId()); if (parentSequence != 0) { args["parent"] = parentSequence; } args["current"] = current; args["deleted"] = rev.IsDeleted(); args["no_attachments"] = !hasAttachments; if (data != null) { args["json"] = data.ToArray(); } rowId = StorageEngine.Insert("revs", null, args); rev.SetSequence(rowId); } catch (Exception e) { Log.E(Tag, "Error inserting revision", e); } return rowId; }
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; }
private RevisionList GetAllRevisionsOfDocumentID(string docId, long docNumericID, bool onlyCurrent) { var sql = onlyCurrent ? "SELECT sequence, revid, deleted FROM revs " + "WHERE doc_id=? AND current ORDER BY sequence DESC" : "SELECT sequence, revid, deleted FROM revs " + "WHERE doc_id=? ORDER BY sequence DESC"; var args = new [] { Convert.ToString (docNumericID) }; var cursor = StorageEngine.RawQuery(sql, args); RevisionList result; try { cursor.MoveToNext(); result = new RevisionList(); while (!cursor.IsAfterLast()) { var rev = new RevisionInternal(docId, cursor.GetString(1), (cursor.GetInt(2) > 0), this); rev.SetSequence(cursor.GetLong(0)); result.AddItem(rev); cursor.MoveToNext(); } } catch (SQLException e) { Log.E(Tag, "Error getting all revisions of document", e); return null; } finally { if (cursor != null) { cursor.Close(); } } return result; }
internal RevisionInternal CopyWithoutBody() { if (_body == null) { return this; } var rev = new RevisionInternal(_docId, _revId, _deleted); rev.SetSequence(_sequence); rev.SetMissing(_missing); return rev; }