/// <exception cref="Couchbase.Lite.CouchbaseLiteException"></exception>
        internal SavedRevision PutProperties(IDictionary <String, Object> properties, String prevID, Boolean allowConflict)
        {
            string newId = null;

            if (properties != null && properties.ContainsKey("_id"))
            {
                newId = (string)properties.Get("_id");
            }
            if (newId != null && !newId.Equals(Id, StringComparison.InvariantCultureIgnoreCase))
            {
                Log.W(Database.Tag, String.Format("Trying to put wrong _id to this: {0} properties: {1}", this, properties)); // TODO: Make sure all string formats use .NET codes, and not Java.
            }

            // Process _attachments dict, converting CBLAttachments to dicts:
            IDictionary <string, object> attachments = null;

            if (properties != null && properties.ContainsKey("_attachments"))
            {
                attachments = (IDictionary <string, object>)properties.Get("_attachments");
            }
            if (attachments != null && attachments.Count > 0)
            {
                var updatedAttachments = Attachment.InstallAttachmentBodies(attachments, Database);
                properties["_attachments"] = updatedAttachments;
            }

            var hasTrueDeletedProperty = false;

            if (properties != null)
            {
                hasTrueDeletedProperty = properties.Get("_deleted") != null && ((bool)properties.Get("_deleted"));
            }

            var deleted = (properties == null) || hasTrueDeletedProperty;
            var rev     = new RevisionInternal(Id, null, deleted, Database);

            if (deleted)
            {
                rev.SetJson(Encoding.UTF8.GetBytes("{}"));
            }
            if (properties != null)
            {
                rev.SetProperties(properties);
            }

            var newRev = Database.PutRevision(rev, prevID, allowConflict);

            if (newRev == null)
            {
                return(null);
            }
            return(new SavedRevision(this, newRev));
        }
Beispiel #2
0
            private void ImportDoc(string docID, long docNumericID)
            {
                // CREATE TABLE revs (
                //  sequence INTEGER PRIMARY KEY AUTOINCREMENT,
                //  doc_id INTEGER NOT NULL REFERENCES docs(doc_id) ON DELETE CASCADE,
                //  revid TEXT NOT NULL COLLATE REVID,
                //  parent INTEGER REFERENCES revs(sequence) ON DELETE SET NULL,
                //  current BOOLEAN,
                //  deleted BOOLEAN DEFAULT 0,
                //  json BLOB,
                //  no_attachments BOOLEAN,
                //  UNIQUE (doc_id, revid) );
                sqlite3_stmt revQuery = null;

                _inner.PrepareSQL(ref revQuery, "SELECT sequence, revid, parent, current, deleted, json, no_attachments" +
                                  " FROM revs WHERE doc_id=? ORDER BY sequence");

                raw.sqlite3_bind_int64(revQuery, 1, docNumericID);

                var tree = new Dictionary <long, IList <object> >();

                int err;

                while (raw.SQLITE_ROW == (err = raw.sqlite3_step(revQuery)))
                {
                    long   sequence  = raw.sqlite3_column_int64(revQuery, 0);
                    string revID     = raw.sqlite3_column_text(revQuery, 1);
                    long   parentSeq = raw.sqlite3_column_int64(revQuery, 2);
                    bool   current   = raw.sqlite3_column_int(revQuery, 3) != 0;
                    bool   noAtts    = raw.sqlite3_column_int(revQuery, 6) != 0;

                    if (current)
                    {
                        // Add a leaf revision:
                        bool deleted            = raw.sqlite3_column_int(revQuery, 4) != 0;
                        IEnumerable <byte> json = raw.sqlite3_column_blob(revQuery, 5);
                        if (json == null)
                        {
                            json = Encoding.UTF8.GetBytes("{}");
                        }

                        var nuJson = json.ToList();
                        if (!noAtts)
                        {
                            try {
                                UpdateAttachmentFollows(nuJson);
                            } catch (CouchbaseLiteException) {
                                Log.To.Upgrade.E(TAG, "Failed to process attachments, rethrowing...");
                                throw;
                            } catch (Exception e) {
                                throw Misc.CreateExceptionAndLog(Log.To.Upgrade, e, TAG, "Error processing attachments");
                            }
                        }

                        json = nuJson;
                        RevisionInternal rev = new RevisionInternal(docID, revID, deleted);
                        rev.SetJson(json);

                        var history = new List <string>();
                        history.Add(revID);
                        while (parentSeq > 0)
                        {
                            var ancestor = tree.Get(parentSeq);
                            Debug.Assert(ancestor != null, String.Format("Couldn't find parent sequence of {0} (doc {1})", parentSeq, docID));
                            history.Add((string)ancestor[0]);
                            parentSeq = (long)ancestor[1];
                        }

                        Log.To.Upgrade.V(TAG, "Upgrading doc {0} history {1}", rev, Manager.GetObjectMapper().WriteValueAsString(history));
                        try {
                            _db.ForceInsert(rev, history, null);
                        } catch (CouchbaseLiteException) {
                            Log.To.Upgrade.E(TAG, "Failed to insert revision {0} into target database, rethrowing...", rev);
                            raw.sqlite3_finalize(revQuery);
                            throw;
                        } catch (Exception e) {
                            raw.sqlite3_finalize(revQuery);
                            throw Misc.CreateExceptionAndLog(Log.To.Upgrade, e, TAG,
                                                             "Error inserting revision {0} into target database", rev);
                        }

                        NumRevs++;
                    }
                    else
                    {
                        tree[sequence] = new List <object> {
                            revID, parentSeq
                        };
                    }
                }

                raw.sqlite3_finalize(revQuery);
                ++NumDocs;
                if (err != raw.SQLITE_OK)
                {
                    var s = SqliteErrToStatus(err);
                    if (s.IsError)
                    {
                        throw Misc.CreateExceptionAndLog(Log.To.Upgrade, s.Code, TAG, "SQLite error during upgrade ({0})",
                                                         err);
                    }
                }
            }
            private Status ImportDoc(string docID, long docNumericID)
            {
                // CREATE TABLE revs (
                //  sequence INTEGER PRIMARY KEY AUTOINCREMENT,
                //  doc_id INTEGER NOT NULL REFERENCES docs(doc_id) ON DELETE CASCADE,
                //  revid TEXT NOT NULL COLLATE REVID,
                //  parent INTEGER REFERENCES revs(sequence) ON DELETE SET NULL,
                //  current BOOLEAN,
                //  deleted BOOLEAN DEFAULT 0,
                //  json BLOB,
                //  no_attachments BOOLEAN,
                //  UNIQUE (doc_id, revid) );
                sqlite3_stmt revQuery = null;
                Status       status   = PrepareSQL(ref revQuery, "SELECT sequence, revid, parent, current, deleted, json" +
                                                   " FROM revs WHERE doc_id=? ORDER BY sequence");

                if (status.IsError)
                {
                    return(status);
                }

                raw.sqlite3_bind_int64(revQuery, 1, docNumericID);

                var tree = new Dictionary <long, IList <object> >();

                int err;

                while (raw.SQLITE_ROW == (err = raw.sqlite3_step(revQuery)))
                {
                    long   sequence  = raw.sqlite3_column_int64(revQuery, 0);
                    string revID     = raw.sqlite3_column_text(revQuery, 1);
                    long   parentSeq = raw.sqlite3_column_int64(revQuery, 2);
                    bool   current   = raw.sqlite3_column_int(revQuery, 3) != 0;

                    if (current)
                    {
                        // Add a leaf revision:
                        bool deleted            = raw.sqlite3_column_int(revQuery, 4) != 0;
                        IEnumerable <byte> json = raw.sqlite3_column_blob(revQuery, 5);
                        if (json == null)
                        {
                            json = Encoding.UTF8.GetBytes("{}");
                        }

                        var nuJson = new List <byte>(json);
                        status = AddAttachmentsToSequence(sequence, nuJson);
                        if (status.IsError)
                        {
                            raw.sqlite3_finalize(revQuery);
                            return(status);
                        }

                        json = nuJson;
                        RevisionInternal rev = new RevisionInternal(docID, revID, deleted);
                        rev.SetJson(json);

                        var history = new List <string>();
                        history.Add(revID);
                        while (parentSeq > 0)
                        {
                            var ancestor = tree.Get(parentSeq);
                            Debug.Assert(ancestor != null, String.Format("Couldn't find parent sequence of {0} (doc {1})", parentSeq, docID));
                            history.Add((string)ancestor[0]);
                            parentSeq = (long)ancestor[1];
                        }

                        Log.D(TAG, "Upgrading doc {0} history {1}", rev, Manager.GetObjectMapper().WriteValueAsString(history));
                        try {
                            _db.ForceInsert(rev, history, null);
                        } catch (CouchbaseLiteException e) {
                            status = e.CBLStatus;
                        }

                        if (status.IsError)
                        {
                            raw.sqlite3_finalize(revQuery);
                            return(status);
                        }

                        NumRevs++;
                    }
                    else
                    {
                        tree[sequence] = new List <object> {
                            revID, parentSeq
                        };
                    }
                }

                raw.sqlite3_finalize(revQuery);
                ++NumDocs;
                return(SqliteErrToStatus(err));
            }