Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
271 changes: 186 additions & 85 deletions c_playground/main.c
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <cbl/CBLCollection.h>
#include <cbl/CBLDatabase.h>
#include <cbl/CBLDocument.h>
#include <cbl/CBLLog.h>
#include <cbl/CBLQuery.h>
#include <cbl/CBLReplicator.h>

const char* DOMAINS[] = { "Database", "Query", "Replicator", "Network" };
const char* LEVEL_PREFIX[] = { "((", "_", "", "WARNING: ", "***ERROR: " };
Expand All @@ -22,125 +25,223 @@ void log_callback(CBLLogDomain domain, CBLLogLevel level, FLString message) {
);
}

int main(void) {
CBLConsoleLogSink log_sink = {};
log_sink.level = kCBLLogDebug;
log_sink.domains = kCBLLogDomainMaskAll;

CBLLogSinks_SetConsole(log_sink);

// Open database
void startReplication(CBLDatabase *db, bool writer, bool deleter) {
CBLError error;
CBLDatabaseConfiguration config = {FLSTR("/tmp")};
CBLDatabase* db = CBLDatabase_Open(FLSTR("my_db"), &config, &error);
assert(db);

CBLCollection* default_collection = CBLDatabase_DefaultCollection(db, &error);
assert(default_collection);

// Create a document
CBLDocument* doc = CBLDocument_Create();
CBLEndpoint* endpoint = CBLEndpoint_CreateWithURL(FLSTR("wss://sync-gateway-staging.doctolib.com:443/billeo-db"), &error);
assert(endpoint);

char* token = writer ? "0febaaafc5368d7e2f8663e0ee08b024a47278c1"
: (deleter ? "61b8b461214c7d6c6c7365dbc4e824111bc4167a"
: "49230c1a31db39e1d5e96e5fbdf1bf93099b53b5"
);
char cookie[64];
snprintf(cookie, sizeof cookie, "SyncGatewaySession=%s", token);

FLMutableDict headers = FLMutableDict_New();
FLMutableDict_SetString(headers, FLSTR("Cookie"), FLStr(cookie));

FLMutableArray emptyArray = FLMutableArray_New();
FLArray array = FLMutableArray_GetSource(emptyArray);

CBLReplicatorConfiguration config = {
.database = db,
.endpoint = endpoint,
.replicatorType = kCBLReplicatorTypePushAndPull,
.continuous = true,
.disableAutoPurge = true,
.maxAttempts = 1,
.maxAttemptWaitTime = 0,
.heartbeat = 55,
.authenticator = NULL,
.proxy = NULL,
.headers = headers,
.pinnedServerCertificate = FLStr(NULL),
.trustedRootCertificates = FLStr(NULL),
.channels = array,
.documentIDs = array,
.pushFilter = NULL,
.pullFilter = NULL,
.conflictResolver = NULL,
.context = NULL,
.collections = NULL,
.collectionCount = 0,
.acceptParentDomainCookies = false,
};

CBLReplicator* replicator = CBLReplicator_Create(&config, &error);
assert(replicator);

CBLReplicator_Start(replicator, false);
}

FILE* fp = fopen("doc.json", "r");
void createDocuments(CBLDatabase *db) {
CBLError error;

char json_format[4096];
int len = fread(json_format, 1, 4096, fp);
FILE* fp = fopen("replication_issue.json", "r");
if (!fp) {
printf("Failed to open replication_issue.json\n");
return;
}

fseek(fp, 0, SEEK_END);
long file_size = ftell(fp);
fseek(fp, 0, SEEK_SET);

char* json_format = malloc(file_size + 1);
if (!json_format) {
printf("Failed to allocate memory for JSON\n");
fclose(fp);
return;
}

size_t len = fread(json_format, 1, file_size, fp);
json_format[len] = '\0';

fclose(fp);

FLString json = {};
json.buf = &json_format;
json.buf = json_format;
json.size = len;
bool set_doc_content = CBLDocument_SetJSON(doc, json, &error);

// Save the document
bool saved = CBLDatabase_SaveDocument(db, doc, &error);
assert(saved);

CBLDocument_Release(doc);

// Simple array index
CBLArrayIndexConfiguration array_index_config = {};
array_index_config.expressionLanguage = kCBLN1QLLanguage;
array_index_config.path = FLSTR("likes");
array_index_config.expressions = FLSTR("");
const int idOffset = 100;
for (int i = 0; i < 100; ++i) {
char id[64];
snprintf(id, sizeof id, "replication_issue_%d", idOffset + i);

CBLDocument* doc = CBLDocument_CreateWithID(FLStr(id));
bool set_doc_content = CBLDocument_SetJSON(doc, json, &error);
assert(set_doc_content);

FLMutableDict properties = CBLDocument_MutableProperties(doc);
FLMutableDict_SetString(properties, FLSTR("owner"), FLSTR("00102204"));

bool saved = CBLDatabase_SaveDocument(db, doc, &error);
assert(saved);

CBLDocument_Release(doc);
}

free(json_format);
}

bool array_index_created = CBLCollection_CreateArrayIndex(
default_collection,
FLSTR("one_level"),
array_index_config,
void getRemainingDocuments(CBLDatabase *db, FLString* result, int* count) {
CBLError error;
int errorPos = 0;
CBLQuery* query = CBLDatabase_CreateQuery(
db,
kCBLN1QLLanguage,
FLSTR("SELECT meta().id FROM _ WHERE _.type='ReplicationIssue' LIMIT 10"),
&errorPos,
&error
);
assert(array_index_created);
assert(query);

CBLResultSet* queryResult = CBLQuery_Execute(query, &error);
assert(queryResult);

int i = 0;
while (CBLResultSet_Next(queryResult) && i < 10) {
FLValue id = CBLResultSet_ValueAtIndex(queryResult, 0);
result[i++] = FLSliceResult_AsSlice(FLSlice_Copy(FLValue_AsString(id)));
}
*count = i;

CBLResultSet_Release(queryResult);
CBLQuery_Release(query);
}

int error_pos = 0;
int getDocumentCount(CBLDatabase *db) {
CBLError error;
int errorPos = 0;
CBLQuery* query = CBLDatabase_CreateQuery(
db,
kCBLN1QLLanguage,
FLSTR("SELECT _.name, _like FROM _ UNNEST _.likes as _like WHERE _like = 'travel'"),
&error_pos,
FLSTR("SELECT COUNT(*) FROM _ WHERE _.type='ReplicationIssue'"),
&errorPos,
&error
);
assert(query);

FLSliceResult explain_result = CBLQuery_Explain(query);
assert(strstr(explain_result.buf, "USING INDEX one_level"));
CBLResultSet* queryResult = CBLQuery_Execute(query, &error);
assert(queryResult);

CBLResultSet* query_result = CBLQuery_Execute(query, &error);
assert(query_result);
assert(CBLResultSet_Next(queryResult));
FLValue count = CBLResultSet_ValueAtIndex(queryResult, 0);

assert(CBLResultSet_Next(query_result));
int result = FLValue_AsInt(count);

FLArray row = CBLResultSet_ResultArray(query_result);
FLValue name = FLArray_Get(row, 0);
assert(strcmp(FLValue_AsString(name).buf, "Sam") == 0);
CBLResultSet_Release(queryResult);
CBLQuery_Release(query);

assert(!CBLResultSet_Next(query_result));
return result;
}

CBLResultSet_Release(query_result);
CBLQuery_Release(query);
void deleteDocuments(CBLDatabase *db) {
bool remaining = true;
CBLError error;

// Complex array index
array_index_config.expressionLanguage = kCBLN1QLLanguage;
array_index_config.path = FLSTR("contacts[].phones");
array_index_config.expressions = FLSTR("type");
while (remaining) {
sleep(1);

array_index_created = CBLCollection_CreateArrayIndex(
default_collection,
FLSTR("two_level"),
array_index_config,
&error
);
assert(array_index_created);
FLString documents[10];
int count = 0;
getRemainingDocuments(db, documents, &count);

query = CBLDatabase_CreateQuery(
db,
kCBLN1QLLanguage,
FLSTR("SELECT _.name, contact.type, phone.number FROM _ UNNEST _.contacts as contact UNNEST contact.phones as phone WHERE phone.type = 'mobile'"),
&error_pos,
&error
);
assert(query);
remaining = (count > 0);

explain_result = CBLQuery_Explain(query);
assert(strstr(explain_result.buf, "USING INDEX two_level"));
for (int i = 0; i < count; i++) {
const CBLDocument* doc = CBLDatabase_GetDocument(db, documents[i], &error);
if (doc) {
bool deleted = CBLDatabase_DeleteDocument(db, doc, &error);
assert(deleted);
CBLDocument_Release(doc);
}
}
}
}

query_result = CBLQuery_Execute(query, &error);
assert(query_result);
int main(void) {
CBLConsoleLogSink log_sink = {};
log_sink.level = kCBLLogDebug;
log_sink.domains = kCBLLogDomainMaskAll;

assert(CBLResultSet_Next(query_result));
CBLLogSinks_SetConsole(log_sink);

row = CBLResultSet_ResultArray(query_result);
name = FLArray_Get(row, 0);
assert(strcmp(FLValue_AsString(name).buf, "Sam") == 0);
// Step configuration
bool writer = false;
bool deleter = false;

assert(CBLResultSet_Next(query_result));
assert(!CBLResultSet_Next(query_result));
FLSlice databaseName = writer || deleter ? FLSTR("writer") : FLSTR("observer");

CBLResultSet_Release(query_result);
CBLQuery_Release(query);
// Open database
CBLError error;
CBLDatabaseConfiguration config = {FLSTR("/Users/antoinemenciere/Documents")};
CBLDatabase* db = CBLDatabase_Open(databaseName, &config, &error);
assert(db);

// Cleanup
bool closed = CBLDatabase_Delete(db, &error);
assert(closed);
// Start a replication
startReplication(db, writer, deleter);

// Create 100 documents if the 'writer' variable is on
if (writer) {
printf("\nStart creating documents\n\n");
createDocuments(db);
printf("\nFinish creating documents\n\n");
}

// Delete all documents if the 'deleter' variable is on
if (deleter) {
printf("\nStart deleting documents\n\n");
deleteDocuments(db);
printf("\nFinish deleting documents\n\n");
}

// Always end by an infinite loop, to let the replication run as long as needed
while (true) {
sleep(1);

int count = getDocumentCount(db);
printf("\nThere is %d document(s) in database\n\n", count);
}
}
Loading