private C4Document *ForceInsert(C4Database *db, string docID, string[] history, string body, C4RevisionFlags flags, C4Error *error = null)
        {
            LiteCoreBridge.Check(err => Native.c4db_beginTransaction(db, err));
            var c4History = new C4String[history.Length];
            var success   = false;

            try {
                var i            = 0;
                var sliceHistory = new FLSlice[history.Length];
                foreach (var entry in history)
                {
                    var c4Str = new C4String(entry);
                    c4History[i]      = c4Str;
                    sliceHistory[i++] = c4Str.AsFLSlice();
                }

                using (var docID_ = new C4String(docID))
                    using (var body_ = new C4String(body))
                    {
                        fixed(FLSlice *sliceHistory_ = sliceHistory)
                        {
                            var rq = new C4DocPutRequest
                            {
                                docID            = docID_.AsFLSlice(),
                                existingRevision = true,
                                allowConflict    = true,
                                history          = sliceHistory_,
                                historyCount     = (ulong)history.Length,
                                body             = body_.AsFLSlice(),
                                revFlags         = flags,
                                remoteDBID       = _remoteDocID,
                                save             = true
                            };

                            C4Document *doc;

                            if (error != null)
                            {
                                var local = rq;
                                doc = Native.c4doc_put(db, &local, null, error);
                            }
                            else
                            {
                                doc = (C4Document *)LiteCoreBridge.Check(err =>
                                {
                                    var local = rq;
                                    return(Native.c4doc_put(db, &local, null, err));
                                });
                            }

                            success = true;
                            return(doc);
                        }
                    }
            } finally {
                foreach (var entry in c4History)
                {
                    entry.Dispose();
                }

                LiteCoreBridge.Check(err => Native.c4db_endTransaction(db, success, err));
            }
        }
示例#2
0
        public void TestUpdate()
        {
            RunTestVariants(() =>
            {
                WriteLine("Begin test");
                C4Document *doc = null;
                LiteCoreBridge.Check(err => Native.c4db_beginTransaction(Db, err));
                try {
                    WriteLine("Begin create");
                    doc = (C4Document *)LiteCoreBridge.Check(err => NativeRaw.c4doc_create(Db, DocID, FleeceBody, 0, err));
                } finally {
                    LiteCoreBridge.Check(err => Native.c4db_endTransaction(Db, true, err));
                }

                WriteLine("After save");
                var expectedRevID = IsRevTrees()
                    ? FLSlice.Constant("1-042ca1d3a1d16fd5ab2f87efc7ebbf50b7498032")
                    : FLSlice.Constant("1@*");

                doc->revID.Equals(expectedRevID).Should().BeTrue();
                doc->flags.Should().Be(C4DocumentFlags.DocExists, "because the document was saved");
                doc->selectedRev.revID.Equals(expectedRevID).Should().BeTrue();
                doc->docID.Equals(DocID).Should().BeTrue("because that is the document ID that it was saved with");

                // Read the doc into another C4Document
                var doc2 = (C4Document *)LiteCoreBridge.Check(err => NativeRaw.c4doc_get(Db, DocID, false, err));
                doc->revID.Equals(expectedRevID).Should()
                .BeTrue("because the other reference should have the same rev ID");

                for (int i = 2; i <= 5; i++)
                {
                    LiteCoreBridge.Check(err => Native.c4db_beginTransaction(Db, err));
                    try
                    {
                        WriteLine($"Begin save #{i}");
                        var body       = JSON2Fleece("{\"ok\":\"go\"}");
                        var oldRevID   = doc->revID;
                        var updatedDoc =
                            (C4Document *)LiteCoreBridge.Check(
                                err => NativeRaw.c4doc_update(doc, (FLSlice)body, 0, err));
                        doc->selectedRev.revID.Equals(oldRevID).Should().BeTrue();
                        doc->revID.Equals(oldRevID).Should().BeTrue();
                        Native.c4doc_release(doc);
                        doc = updatedDoc;
                        Native.FLSliceResult_Release(body);
                    }
                    finally
                    {
                        LiteCoreBridge.Check(err => Native.c4db_endTransaction(Db, true, err));
                    }
                }

                WriteLine("After multiple updates");
                var expectedRev2ID = IsRevTrees()
                    ? FLSlice.Constant("5-a452899fa8e69b06d936a5034018f6fff0a8f906")
                    : FLSlice.Constant("5@*");
                doc->revID.Equals(expectedRev2ID).Should().BeTrue();
                doc->selectedRev.revID.Equals(expectedRev2ID).Should().BeTrue();

                LiteCoreBridge.Check(err => Native.c4db_beginTransaction(Db, err));
                try {
                    WriteLine("Begin conflicting save");
                    C4Error error;
                    var body = JSON2Fleece("{\"ok\":\"no way\"}");
                    ((long)NativeRaw.c4doc_update(doc2, (FLSlice)body, 0, &error)).Should().Be(0, "because this is a conflict");
                    error.code.Should().Be((int)C4ErrorCode.Conflict);
                    error.domain.Should().Be(C4ErrorDomain.LiteCoreDomain);
                    Native.FLSliceResult_Release(body);
                }
                finally {
                    LiteCoreBridge.Check(err => Native.c4db_endTransaction(Db, true, err));
                }

                LiteCoreBridge.Check(err => Native.c4db_beginTransaction(Db, err));
                try {
                    WriteLine("Begin conflicting create");
                    C4Error error;
                    var body = JSON2Fleece("{\"ok\":\"no way\"}");
                    ((long)NativeRaw.c4doc_create(Db, DocID, (FLSlice)body, 0, &error)).Should().Be(0, "because this is a conflict");
                    error.code.Should().Be((int)C4ErrorCode.Conflict);
                    error.domain.Should().Be(C4ErrorDomain.LiteCoreDomain);
                    Native.FLSliceResult_Release(body);
                }
                finally {
                    LiteCoreBridge.Check(err => Native.c4db_endTransaction(Db, true, err));
                }

                Native.c4doc_release(doc);
                Native.c4doc_release(doc2);
            });
        }
示例#3
0
        public void TestConflict()
        {
            RunTestVariants(() =>
            {
                if (!IsRevTrees())
                {
                    return;
                }

                var body2 = JSON2Fleece("{\"ok\":\"go\"}");
                var body3 = JSON2Fleece("{\"ubu\":\"roi\"}");
                CreateRev(DocID.CreateString(), RevID, FleeceBody);
                CreateRev(DocID.CreateString(), Rev2ID, (FLSlice)body2, C4RevisionFlags.KeepBody);
                CreateRev(DocID.CreateString(), FLSlice.Constant("3-aaaaaa"), (FLSlice)body3);

                LiteCoreBridge.Check(err => Native.c4db_beginTransaction(Db, err));
                try {
                    // "Pull" a conflicting revision:
                    var history = new FLSlice[] { FLSlice.Constant("4-dddd"), FLSlice.Constant("3-ababab"), Rev2ID };
                    fixed(FLSlice * history_ = history)
                    {
                        var rq = new C4DocPutRequest
                        {
                            existingRevision = true,
                            docID            = DocID,
                            history          = history_,
                            historyCount     = 3,
                            allowConflict    = true,
                            body             = (FLSlice)body3,
                            save             = true,
                            remoteDBID       = 1
                        };

                        C4Error error;
                        var doc = Native.c4doc_put(Db, &rq, null, &error);
                        ((IntPtr)doc).Should().NotBe(IntPtr.Zero);

                        Native.FLSliceResult_Release(body2);
                        Native.FLSliceResult_Release(body3);

                        Native.c4doc_selectCommonAncestorRevision(doc, "3-aaaaaa", "4-dddd").Should().BeTrue();
                        doc->selectedRev.revID.CreateString().Should().Be(Rev2ID.CreateString());
                        Native.c4doc_selectCommonAncestorRevision(doc, "4-dddd", "3-aaaaaa").Should().BeTrue();
                        doc->selectedRev.revID.CreateString().Should().Be(Rev2ID.CreateString());

                        Native.c4doc_selectCommonAncestorRevision(doc, "3-ababab", "3-aaaaaa").Should().BeTrue();
                        doc->selectedRev.revID.CreateString().Should().Be(Rev2ID.CreateString());
                        Native.c4doc_selectCommonAncestorRevision(doc, "3-aaaaaa", "3-ababab").Should().BeTrue();
                        doc->selectedRev.revID.CreateString().Should().Be(Rev2ID.CreateString());

                        Native.c4doc_selectCommonAncestorRevision(doc, Rev2ID.CreateString(), "3-aaaaaa").Should().BeTrue();
                        doc->selectedRev.revID.CreateString().Should().Be(Rev2ID.CreateString());
                        Native.c4doc_selectCommonAncestorRevision(doc, "3-aaaaaa", Rev2ID.CreateString()).Should().BeTrue();
                        doc->selectedRev.revID.CreateString().Should().Be(Rev2ID.CreateString());

                        NativeRaw.c4doc_selectCommonAncestorRevision(doc, Rev2ID, Rev2ID).Should().BeTrue();
                        doc->selectedRev.revID.CreateString().Should().Be(Rev2ID.CreateString());
                    }
                } finally {
                    LiteCoreBridge.Check(err => Native.c4db_endTransaction(Db, true, err));
                }

                var mergedBody = JSON2Fleece("{\"merged\":true}");
                LiteCoreBridge.Check(err => Native.c4db_beginTransaction(Db, err));
                try {
                    var doc = (C4Document *)LiteCoreBridge.Check(err => Native.c4doc_get(Db, DocID.CreateString(), true, err));
                    LiteCoreBridge.Check(err => NativeRaw.c4doc_resolveConflict(doc, FLSlice.Constant("4-dddd"), FLSlice.Constant("3-aaaaaa"), (FLSlice)mergedBody, 0, err));
                    Native.c4doc_selectCurrentRevision(doc);
                    doc->selectedRev.revID.CreateString().Should().Be("5-79b2ecd897d65887a18c46cc39db6f0a3f7b38c4");
                    doc->selectedRev.body.Equals(mergedBody).Should().BeTrue();
                    Native.c4doc_selectParentRevision(doc);
                    doc->selectedRev.revID.CreateString().Should().Be("4-dddd");
                } finally {
                    LiteCoreBridge.Check(err => Native.c4db_endTransaction(Db, false, err));
                }

                LiteCoreBridge.Check(err => Native.c4db_beginTransaction(Db, err));
                try {
                    var doc = (C4Document *)LiteCoreBridge.Check(err => Native.c4doc_get(Db, DocID.CreateString(), true, err));
                    LiteCoreBridge.Check(err => NativeRaw.c4doc_resolveConflict(doc, FLSlice.Constant("3-aaaaaa"), FLSlice.Constant("4-dddd"), (FLSlice)mergedBody, 0, err));
                    Native.c4doc_selectCurrentRevision(doc);
                    doc->selectedRev.revID.CreateString().Should().Be("4-1fa2dbcb66b5e0456f6d6fc4a90918d42f3dd302");
                    doc->selectedRev.body.Equals(mergedBody).Should().BeTrue();
                    Native.c4doc_selectParentRevision(doc);
                    doc->selectedRev.revID.CreateString().Should().Be("3-aaaaaa");
                } finally {
                    LiteCoreBridge.Check(err => Native.c4db_endTransaction(Db, false, err));
                }
            });
        }
示例#4
0
        public void TestPurge()
        {
            RunTestVariants(() => {
                var body2 = JSON2Fleece("{\"ok\":\"go\"}");
                var body3 = JSON2Fleece("{\"ubu\":\"roi\"}");
                CreateRev(DocID.CreateString(), RevID, FleeceBody);
                CreateRev(DocID.CreateString(), Rev2ID, (FLSlice)body2);
                CreateRev(DocID.CreateString(), Rev3ID, (FLSlice)body3);

                var history = new[] { FLSlice.Constant("3-ababab"), Rev2ID };
                fixed(FLSlice * history_ = history)
                {
                    var rq = new C4DocPutRequest
                    {
                        existingRevision = true,
                        docID            = DocID,
                        history          = history_,
                        historyCount     = 2,
                        allowConflict    = true,
                        body             = (FLSlice)body3,
                        save             = true
                    };

                    C4Error error;
                    C4Document *doc = null;
                    LiteCoreBridge.Check(err => Native.c4db_beginTransaction(Db, err));
                    try {
                        doc = Native.c4doc_put(Db, &rq, null, &error);
                        ((IntPtr)doc).Should().NotBe(IntPtr.Zero);
                        Native.c4doc_release(doc);
                    } finally {
                        LiteCoreBridge.Check(err => Native.c4db_endTransaction(Db, true, err));
                    }

                    LiteCoreBridge.Check(err => Native.c4db_beginTransaction(Db, err));
                    try {
                        LiteCoreBridge.Check(err => NativeRaw.c4db_purgeDoc(Db, DocID, err));
                    } finally {
                        LiteCoreBridge.Check(err => Native.c4db_endTransaction(Db, true, err));
                    }

                    Native.c4db_getDocumentCount(Db).Should().Be(0UL);

                    CreateRev(DocID.CreateString(), RevID, FleeceBody);
                    CreateRev(DocID.CreateString(), Rev2ID, (FLSlice)body2);
                    CreateRev(DocID.CreateString(), Rev3ID, (FLSlice)body3);

                    LiteCoreBridge.Check(err => Native.c4db_beginTransaction(Db, err));
                    try {
                        doc = Native.c4doc_put(Db, &rq, null, &error);
                        ((IntPtr)doc).Should().NotBe(IntPtr.Zero);
                    } finally {
                        LiteCoreBridge.Check(err => Native.c4db_endTransaction(Db, true, err));
                    }

                    LiteCoreBridge.Check(err => Native.c4db_beginTransaction(Db, err));
                    try {
                        LiteCoreBridge.Check(err => Native.c4doc_purgeRevision(doc, null, err));
                        LiteCoreBridge.Check(err => Native.c4doc_save(doc, 0, err));
                    } finally {
                        Native.c4doc_release(doc);
                        LiteCoreBridge.Check(err => Native.c4db_endTransaction(Db, true, err));
                    }

                    Native.c4db_getDocumentCount(Db).Should().Be(0UL);
                    Native.FLSliceResult_Release(body2);
                    Native.FLSliceResult_Release(body3);
                }
            });
        }
示例#5
0
        public void TestPut()
        {
            RunTestVariants(() => {
                LiteCoreBridge.Check(err => Native.c4db_beginTransaction(Db, err));
                try {
                    // Creating doc given ID:
                    var rq = new C4DocPutRequest {
                        docID = DocID,
                        body  = FleeceBody,
                        save  = true
                    };

                    var doc = (C4Document *)LiteCoreBridge.Check(err => {
                        var localRq = rq;
                        return(Native.c4doc_put(Db, &localRq, null, err));
                    });

                    doc->docID.Equals(DocID).Should().BeTrue("because the doc should have the correct doc ID");
                    var expectedRevID = IsRevTrees() ? FLSlice.Constant("1-042ca1d3a1d16fd5ab2f87efc7ebbf50b7498032") :
                                        FLSlice.Constant("1@*");
                    doc->revID.Equals(expectedRevID).Should().BeTrue("because the doc should have the correct rev ID");
                    doc->flags.Should().Be(C4DocumentFlags.DocExists, "because the document exists");
                    doc->selectedRev.revID.Equals(expectedRevID).Should().BeTrue("because the selected rev should have the correct rev ID");
                    Native.c4doc_release(doc);

                    // Update doc:
                    var tmp                   = new[] { expectedRevID };
                    var body                  = JSON2Fleece("{\"ok\":\"go\"}");
                    rq.body                   = (FLSlice)body;
                    rq.historyCount           = 1;
                    ulong commonAncestorIndex = 0UL;
                    fixed(FLSlice * history   = tmp)
                    {
                        rq.history = history;
                        doc        = (C4Document *)LiteCoreBridge.Check(err => {
                            var localRq = rq;
                            ulong cai;
                            var retVal          = Native.c4doc_put(Db, &localRq, &cai, err);
                            commonAncestorIndex = cai;
                            return(retVal);
                        });
                    }

                    commonAncestorIndex.Should().Be(0UL, "because there are no common ancestors");
                    var expectedRev2ID = IsRevTrees() ? FLSlice.Constant("2-201796aeeaa6ddbb746d6cab141440f23412ac51") :
                                         FLSlice.Constant("2@*");
                    doc->revID.Equals(expectedRev2ID).Should().BeTrue("because the doc should have the updated rev ID");
                    doc->flags.Should().Be(C4DocumentFlags.DocExists, "because the document exists");
                    doc->selectedRev.revID.Equals(expectedRev2ID).Should().BeTrue("because the selected rev should have the correct rev ID");
                    Native.c4doc_release(doc);

                    // Insert existing rev that conflicts:
                    Native.FLSliceResult_Release(body);
                    body                = JSON2Fleece("{\"from\":\"elsewhere\"}");
                    rq.body             = (FLSlice)body;
                    rq.existingRevision = true;
                    rq.remoteDBID       = 1;
                    var conflictRevID   = IsRevTrees() ? FLSlice.Constant("2-deadbeef") : FLSlice.Constant("1@binky");
                    tmp                     = new[] { conflictRevID, expectedRevID };
                    rq.historyCount         = 2;
                    rq.allowConflict        = true;
                    fixed(FLSlice * history = tmp)
                    {
                        rq.history = history;
                        doc        = (C4Document *)LiteCoreBridge.Check(err => {
                            var localRq = rq;
                            ulong cai;
                            var retVal          = Native.c4doc_put(Db, &localRq, &cai, err);
                            commonAncestorIndex = cai;
                            return(retVal);
                        });
                    }

                    commonAncestorIndex.Should().Be(1UL, "because the common ancestor is at sequence 1");
                    doc->flags.Should().Be(C4DocumentFlags.DocExists | C4DocumentFlags.DocConflicted, "because the document exists");
                    doc->selectedRev.revID.Equals(conflictRevID).Should().BeTrue("because the selected rev should have the correct rev ID");
                    doc->revID.Equals(expectedRev2ID).Should().BeTrue("because the conflicting rev should never be the default");
                    Native.FLSliceResult_Release(body);
                    Native.c4doc_release(doc);
                } finally {
                    LiteCoreBridge.Check(err => Native.c4db_endTransaction(Db, true, err));
                }
            });
        }
示例#6
0
 private void Log(C4LogLevel level, FLSlice s)
 {
     WriteLine($"[{level}] {s.CreateString()}");
 }
示例#7
0
        protected uint ImportJSONFile(string path, string idPrefix, TimeSpan timeout, bool verbose)
        {
            WriteLine($"Reading {path} ...");
            var st = Stopwatch.StartNew();

#if WINDOWS_UWP
            var url  = $"ms-appx:///Assets/{path}";
            var file = Windows.Storage.StorageFile.GetFileFromApplicationUriAsync(new Uri(url))
                       .AsTask()
                       .ConfigureAwait(false)
                       .GetAwaiter()
                       .GetResult();

            var buffer = Windows.Storage.FileIO.ReadBufferAsync(file).AsTask().ConfigureAwait(false).GetAwaiter()
                         .GetResult();
            var jsonData = System.Runtime.InteropServices.WindowsRuntime.WindowsRuntimeBufferExtensions.ToArray(buffer);
#elif __ANDROID__
            var    ctx = global::Couchbase.Lite.Tests.Android.MainActivity.ActivityContext;
            byte[] jsonData;
            using (var stream = ctx.Assets.Open(path))
                using (var ms = new MemoryStream()) {
                    stream.CopyTo(ms);
                    jsonData = ms.ToArray();
                }
#elif __IOS__
            var    bundlePath = ios::Foundation.NSBundle.MainBundle.PathForResource(Path.GetFileNameWithoutExtension(path), Path.GetExtension(path));
            byte[] jsonData;
            using (var stream = File.Open(bundlePath, FileMode.Open, FileAccess.Read))
                using (var ms = new MemoryStream()) {
                    stream.CopyTo(ms);
                    jsonData = ms.ToArray();
                }
#else
            var jsonData = File.ReadAllBytes(path);
#endif

            FLError       error;
            FLSliceResult fleeceData;
            fixed(byte *jsonData_ = jsonData)
            {
                fleeceData = NativeRaw.FLData_ConvertJSON(new FLSlice(jsonData_, (ulong)jsonData.Length), &error);
            }

            ((long)fleeceData.buf).Should().NotBe(0, "because otherwise the conversion failed");
            var root = Native.FLValue_AsArray(NativeRaw.FLValue_FromData((FLSlice)fleeceData, FLTrust.Trusted));
            ((long)root).Should().NotBe(0, "because otherwise the value is not of the expected type");

            LiteCoreBridge.Check(err => Native.c4db_beginTransaction(Db, err));
            try {
                FLArrayIterator iter;
                FLValue *       item;
                uint            numDocs = 0;
                for (Native.FLArrayIterator_Begin(root, &iter);
                     null != (item = Native.FLArrayIterator_GetValue(&iter));
                     Native.FLArrayIterator_Next(&iter))
                {
                    var docID = idPrefix != null ? $"{idPrefix}{numDocs + 1:D7}" : $"doc{numDocs + 1:D7}";
                    var enc   = Native.c4db_getSharedFleeceEncoder(Db);
                    Native.FLEncoder_WriteValue(enc, item);
                    var body = NativeRaw.FLEncoder_Finish(enc, &error);

                    var rq = new C4DocPutRequest {
                        docID = FLSlice.Allocate(docID),
                        body  = (FLSlice)body,
                        save  = true
                    };

                    var doc = (C4Document *)LiteCoreBridge.Check(err =>
                    {
                        var localPut = rq;
                        return(Native.c4doc_put(Db, &localPut, null, err));
                    });

                    Native.c4doc_free(doc);
                    Native.FLSliceResult_Release(body);
                    FLSlice.Free(rq.docID);
                    ++numDocs;
                    if ((numDocs % 1000) == 0 && st.Elapsed > timeout)
                    {
                        WriteLine($"WARNING: Stopping JSON import after {st.Elapsed}");
                        return(numDocs);
                    }
                    if (verbose && (numDocs % 100000) == 0)
                    {
                        WriteLine($"{numDocs}  ");
                    }
                }

                if (verbose)
                {
                    st.PrintReport("Importing", numDocs, "doc", _output);
                }

                return(numDocs);
            }
            finally {
                Native.FLSliceResult_Release(fleeceData);
                LiteCoreBridge.Check(err => Native.c4db_endTransaction(Db, true, err));
            }
        }
示例#8
0
        public void TestCreateRawDoc()
        {
            RunTestVariants(() => {
                var key  = FLSlice.Constant("key");
                var meta = FLSlice.Constant("meta");
                LiteCoreBridge.Check(err => Native.c4db_beginTransaction(Db, err));
                LiteCoreBridge.Check(err => NativeRaw.c4raw_put(Db, FLSlice.Constant("test"), key, meta,
                                                                FleeceBody, err));
                LiteCoreBridge.Check(err => Native.c4db_endTransaction(Db, true, err));

                var doc = (C4RawDocument *)LiteCoreBridge.Check(err => NativeRaw.c4raw_get(Db,
                                                                                           FLSlice.Constant("test"), key, err));
                doc->key.Equals(key).Should().BeTrue("because the key should not change");
                doc->meta.Equals(meta).Should().BeTrue("because the meta should not change");
                doc->body.Equals(FleeceBody).Should().BeTrue("because the body should not change");
                Native.c4raw_free(doc);

                // Nonexistent:
                C4Error error;
                ((long)Native.c4raw_get(Db, "test", "bogus", &error)).Should().Be(0,
                                                                                  "because the document does not exist");
                error.domain.Should().Be(C4ErrorDomain.LiteCoreDomain, "because that is the correct domain");
                error.code.Should().Be((int)C4ErrorCode.NotFound, "because that is the correct error code");
            });
        }
示例#9
0
 internal void CreateRev(string docID, FLSlice revID, FLSlice body, C4RevisionFlags flags = (C4RevisionFlags)0)
 {
     CreateRev(Db, docID, revID, body, flags);
 }
示例#10
0
        private uint InsertDocs(FLArray *docs)
        {
            var typeKey    = NativeRaw.FLDictKey_Init(FLSlice.Constant("Track Type"), true);
            var idKey      = NativeRaw.FLDictKey_Init(FLSlice.Constant("Persistent ID"), true);
            var nameKey    = NativeRaw.FLDictKey_Init(FLSlice.Constant("Name"), true);
            var albumKey   = NativeRaw.FLDictKey_Init(FLSlice.Constant("Album"), true);
            var artistKey  = NativeRaw.FLDictKey_Init(FLSlice.Constant("Artist"), true);
            var timeKey    = NativeRaw.FLDictKey_Init(FLSlice.Constant("Total Time"), true);
            var genreKey   = NativeRaw.FLDictKey_Init(FLSlice.Constant("Genre"), true);
            var yearKey    = NativeRaw.FLDictKey_Init(FLSlice.Constant("Year"), true);
            var trackNoKey = NativeRaw.FLDictKey_Init(FLSlice.Constant("Track Number"), true);
            var compKey    = NativeRaw.FLDictKey_Init(FLSlice.Constant("Compilation"), true);

            LiteCoreBridge.Check(err => Native.c4db_beginTransaction(Db, err));
            try {
                var             enc = Native.FLEncoder_New();
                FLArrayIterator iter;
                Native.FLArrayIterator_Begin(docs, &iter);
                uint numDocs = 0;
                while (Native.FLArrayIterator_Next(&iter))
                {
                    // Check that track is correct type:
                    var track     = Native.FLValue_AsDict(Native.FLArrayIterator_GetValue(&iter));
                    var trackType = NativeRaw.FLValue_AsString(Native.FLDict_GetWithKey(track, &typeKey));
                    if (!trackType.Equals(FLSlice.Constant("File")) && !trackType.Equals(FLSlice.Constant("Remote")))
                    {
                        continue;
                    }

                    var trackID = NativeRaw.FLValue_AsString(Native.FLDict_GetWithKey(track, &idKey));
                    ((long)trackID.buf).Should().NotBe(0, "because otherwise the data was not read correctly");

                    // Encode doc body:
                    Native.FLEncoder_BeginDict(enc, 0);
                    CopyValue(track, &nameKey, enc).Should().BeTrue("because otherwise the copy failed");
                    CopyValue(track, &albumKey, enc);
                    CopyValue(track, &artistKey, enc);
                    CopyValue(track, &timeKey, enc);
                    CopyValue(track, &genreKey, enc);
                    CopyValue(track, &yearKey, enc);
                    CopyValue(track, &trackNoKey, enc);
                    CopyValue(track, &compKey, enc);
                    Native.FLEncoder_EndDict(enc);
                    FLError err;
                    var     body = NativeRaw.FLEncoder_Finish(enc, &err);
                    body.Should().NotBeNull("because otherwise the encoding process failed");
                    Native.FLEncoder_Reset(enc);

                    // Save Document:
                    var rq = new C4DocPutRequest {
                        docID = (C4Slice)trackID,
                        body  = (C4Slice)body,
                        save  = true
                    };
                    var doc = (C4Document *)LiteCoreBridge.Check(c4err => {
                        var localRq = rq;
                        return(Native.c4doc_put(Db, &localRq, null, c4err));
                    });

                    Native.c4doc_free(doc);
                    ++numDocs;
                }

                Native.FLEncoder_Free(enc);
                return(numDocs);
            } finally {
                LiteCoreBridge.Check(err => Native.c4db_endTransaction(Db, true, err));
            }
        }
示例#11
0
        private static void DocObserverCallback(C4DocumentObserver *obs, FLSlice docId, ulong sequence, void *context)
        {
            var obj = GCHandle.FromIntPtr((IntPtr)context).Target as ObserverTest;

            obj.DocObserverCalled(obs, docId.CreateString(), sequence);
        }
 private C4Document *PutDoc(string docID, string revID, FLSlice body, C4RevisionFlags flags = 0)
 {
     return(PutDoc(Db, docID, revID, body, flags));
 }
        private void ForceInsert(string docID, string[] history, FLSlice body, C4RevisionFlags flags = 0)
        {
            var doc = ForceInsert(Db, docID, history, body, flags);

            Native.c4doc_free(doc);
        }
 private void PutDocMustFail(string docID, string revID, FLSlice body, C4RevisionFlags flags, C4Error expected)
 {
     PutDocMustFail(Db, docID, revID, body, flags, expected);
 }
示例#15
0
        private C4Error SetupC4Replicator()
        {
            Config.Database.CheckOpenLocked();
            C4Error err = new C4Error();

            if (_repl != null)
            {
                Native.c4repl_setOptions(_repl, ((FLSlice)Config.Options.FLEncode()).ToArrayFast());
                return(err);
            }

            _desc = ToString(); // Cache this; it may be called a lot when logging

            // Target:
            var      addr      = new C4Address();
            Database otherDB   = null;
            var      remoteUrl = Config.RemoteUrl;
            string   dbNameStr = remoteUrl?.Segments?.Last().TrimEnd('/');

            using (var dbNameStr_ = new C4String(dbNameStr))
                using (var remoteUrlStr_ = new C4String(remoteUrl?.AbsoluteUri)) {
                    FLSlice   dn = dbNameStr_.AsFLSlice();
                    C4Address localAddr;
                    var       addrFromUrl = NativeRaw.c4address_fromURL(remoteUrlStr_.AsFLSlice(), &localAddr, &dn);
                    addr = localAddr;

                    if (addrFromUrl)
                    {
                        //get cookies from url and add to replicator options
                        var cookiestring = Config.Database.GetCookies(remoteUrl);
                        if (!String.IsNullOrEmpty(cookiestring))
                        {
                            var split = cookiestring.Split(';') ?? Enumerable.Empty <string>();
                            foreach (var entry in split)
                            {
                                var pieces = entry?.Split('=');
                                if (pieces?.Length != 2)
                                {
                                    WriteLog.To.Sync.W(Tag, "Garbage cookie value, ignoring");
                                    continue;
                                }

                                Config.Options.Cookies.Add(new Cookie(pieces[0]?.Trim(), pieces[1]?.Trim()));
                            }
                        }
                    }
                    else
                    {
                        Config.OtherDB?.CheckOpenLocked();
                        otherDB = Config.OtherDB;
                    }

                    var options = Config.Options;

                    Config.Authenticator?.Authenticate(options);

                    options.Build();
                    var push       = Config.ReplicatorType.HasFlag(ReplicatorType.Push);
                    var pull       = Config.ReplicatorType.HasFlag(ReplicatorType.Pull);
                    var continuous = Config.Continuous;

                    var socketFactory = Config.SocketFactory;
                    socketFactory.context = GCHandle.ToIntPtr(GCHandle.Alloc(this)).ToPointer();
                    _nativeParams         = new ReplicatorParameters(options)
                    {
                        Push            = Mkmode(push, continuous),
                        Pull            = Mkmode(pull, continuous),
                        Context         = this,
                        OnDocumentEnded = OnDocEnded,
                        OnStatusChanged = StatusChangedCallback,
                        SocketFactory   = &socketFactory
                    };

                    // Clear the reset flag, it is a one-time thing
                    options.Reset = false;

                    if (Config.PushFilter != null)
                    {
                        _nativeParams.PushFilter = PushFilterCallback;
                    }
                    if (Config.PullFilter != null)
                    {
                        _nativeParams.PullFilter = PullValidateCallback;
                    }

                    DispatchQueue.DispatchSync(() =>
                    {
                        C4Error localErr = new C4Error();
                    #if COUCHBASE_ENTERPRISE
                        if (otherDB != null)
                        {
                            _repl = Native.c4repl_newLocal(Config.Database.c4db, otherDB.c4db, _nativeParams.C4Params,
                                                           &localErr);
                        }
                        else
                    #endif
                        _repl = Native.c4repl_new(Config.Database.c4db, addr, dbNameStr, _nativeParams.C4Params, &localErr);

                        if (_documentEndedUpdate.Counter > 0)
                        {
                            SetProgressLevel(C4ReplicatorProgressLevel.ReplProgressPerDocument);
                        }

                        err = localErr;
                    });
                }

            return(err);
        }
示例#16
0
        private static bool PushFilterCallback(FLSlice collectionName, FLSlice docID, FLSlice revID, C4RevisionFlags revisionFlags, FLDict *dict, void *context)
        {
            var replicator = GCHandle.FromIntPtr((IntPtr)context).Target as Replicator;

            if (replicator == null)
            {
                WriteLog.To.Database.E(Tag, "Push filter context pointing to invalid object {0}, aborting and returning true...",
                                       replicator);
                return(true);
            }

            var docIDStr = docID.CreateString();

            if (docIDStr == null)
            {
                WriteLog.To.Database.E(Tag, "Null document ID received in push filter, rejecting...");
                return(false);
            }

            var flags = revisionFlags.ToDocumentFlags();

            return(replicator.PushFilterCallback(docIDStr, revID.CreateString(), dict, flags));
        }