Skip to content

Commit

Permalink
Trigger reactive queries only on transactions
Browse files Browse the repository at this point in the history
  • Loading branch information
ospfranco committed Oct 15, 2024
1 parent 5599f0f commit 3ca43ac
Show file tree
Hide file tree
Showing 7 changed files with 159 additions and 92 deletions.
176 changes: 111 additions & 65 deletions cpp/DBHostObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,37 @@ namespace jsi = facebook::jsi;
namespace react = facebook::react;

#ifndef OP_SQLITE_USE_LIBSQL
void DBHostObject::flush_pending_reactive_queries() {
for (const auto &query_ptr : pending_reactive_queries) {
auto query = query_ptr.get();

std::vector<DumbHostObject> results;
std::shared_ptr<std::vector<SmartHostObject>> metadata =
std::make_shared<std::vector<SmartHostObject>>();

auto status = opsqlite_execute_prepared_statement(db_name, query->stmt,
&results, metadata);

if (status.type == SQLiteError) {
invoker->invokeAsync(
[this, callback = query->callback, status = std::move(status)] {
auto errorCtr = rt.global().getPropertyAsFunction(rt, "Error");
auto error = errorCtr.callAsConstructor(
rt, jsi::String::createFromUtf8(rt, status.message));
callback->asObject(rt).asFunction(rt).call(rt, error);
});
} else {
invoker->invokeAsync(
[this,
results = std::make_shared<std::vector<DumbHostObject>>(results),
callback = query->callback, metadata, status = std::move(status)] {
auto jsiResult = createResult(rt, status, results.get(), metadata);
callback->asObject(rt).asFunction(rt).call(rt, jsiResult);
});
}
}
}

void DBHostObject::auto_register_update_hook() {
if (update_hook_callback == nullptr && reactive_queries.empty() &&
is_update_hook_registered) {
Expand All @@ -31,19 +62,17 @@ void DBHostObject::auto_register_update_hook() {
auto hook = [this](std::string name, std::string table_name,
std::string operation, int rowid) {
if (update_hook_callback != nullptr) {
invoker->invokeAsync(
[this,
callback = update_hook_callback, table_name,
operation = std::move(operation), rowid] {
auto res = jsi::Object(rt);
res.setProperty(rt, "table",
jsi::String::createFromUtf8(rt, table_name));
res.setProperty(rt, "operation",
jsi::String::createFromUtf8(rt, operation));
res.setProperty(rt, "rowId", jsi::Value(rowid));

callback->asObject(rt).asFunction(rt).call(rt, res);
});
invoker->invokeAsync([this, callback = update_hook_callback, table_name,
operation = std::move(operation), rowid] {
auto res = jsi::Object(rt);
res.setProperty(rt, "table",
jsi::String::createFromUtf8(rt, table_name));
res.setProperty(rt, "operation",
jsi::String::createFromUtf8(rt, operation));
res.setProperty(rt, "rowId", jsi::Value(rowid));

callback->asObject(rt).asFunction(rt).call(rt, res);
});
}

for (const auto &query_ptr : reactive_queries) {
Expand All @@ -55,56 +84,64 @@ void DBHostObject::auto_register_update_hook() {
bool shouldFire = false;

for (const auto &discriminator : query->discriminators) {
// Tables don't match then skip
if (discriminator.table != table_name) {
continue;
}
// Table has matched

// If no ids are specified, then we should fire
if (discriminator.ids.size() == 0) {
shouldFire = true;
break;
} else { // If ids are specified, then we should check if the rowId
// matches
for (const auto &discrimator_id : discriminator.ids) {
if (rowid == discrimator_id) {
shouldFire = true;
break;
}
}

// If ids are specified, then we should check if the rowId matches
for (const auto &discrimator_id : discriminator.ids) {
if (rowid == discrimator_id) {
shouldFire = true;
break;
}
}
}


// if (!shouldFire) {
// continue;
// }
//
// std::vector<DumbHostObject> results;
// std::shared_ptr<std::vector<SmartHostObject>> metadata =
// std::make_shared<std::vector<SmartHostObject>>();
//
// auto status = opsqlite_execute_prepared_statement(db_name, query->stmt,
// &results, metadata);
//
// if (status.type == SQLiteError) {
// invoker->invokeAsync(
// [this, callback = query->callback, status = std::move(status)] {
// auto errorCtr = rt.global().getPropertyAsFunction(rt, "Error");
// auto error = errorCtr.callAsConstructor(
// rt, jsi::String::createFromUtf8(rt, status.message));
// callback->asObject(rt).asFunction(rt).call(rt, error);
// });
// } else {
// invoker->invokeAsync(
// [this,
// results = std::make_shared<std::vector<DumbHostObject>>(results),
// callback = query->callback, metadata, status = std::move(status)] {
// auto jsiResult =
// createResult(rt, status, results.get(), metadata);
// callback->asObject(rt).asFunction(rt).call(rt, jsiResult);
// });
// }

if (shouldFire) {
pending_reactive_queries.insert(query_ptr);
}

// if (!shouldFire) {
// continue;
// }
//
// std::vector<DumbHostObject> results;
// std::shared_ptr<std::vector<SmartHostObject>> metadata =
// std::make_shared<std::vector<SmartHostObject>>();
//
// auto status = opsqlite_execute_prepared_statement(db_name,
// query->stmt,
// &results,
// metadata);
//
// if (status.type == SQLiteError) {
// invoker->invokeAsync(
// [this, callback = query->callback, status =
// std::move(status)] {
// auto errorCtr = rt.global().getPropertyAsFunction(rt,
// "Error"); auto error = errorCtr.callAsConstructor(
// rt, jsi::String::createFromUtf8(rt, status.message));
// callback->asObject(rt).asFunction(rt).call(rt, error);
// });
// } else {
// invoker->invokeAsync(
// [this,
// results =
// std::make_shared<std::vector<DumbHostObject>>(results),
// callback = query->callback, metadata, status =
// std::move(status)] {
// auto jsiResult =
// createResult(rt, status, results.get(), metadata);
// callback->asObject(rt).asFunction(rt).call(rt, jsiResult);
// });
// }
}
};

Expand All @@ -118,8 +155,7 @@ DBHostObject::DBHostObject(jsi::Runtime &rt, std::string &url,
std::string &auth_token,
std::shared_ptr<react::CallInvoker> invoker,
std::shared_ptr<ThreadPool> thread_pool)
: db_name(url), invoker(js_call_invoker), thread_pool(thread_pool),
rt(rt) {
: db_name(url), invoker(js_call_invoker), thread_pool(thread_pool), rt(rt) {

Check failure on line 158 in cpp/DBHostObject.cpp

View workflow job for this annotation

GitHub Actions / test-ios-libsql

use of undeclared identifier 'js_call_invoker'
BridgeResult result = opsqlite_libsql_open_remote(url, auth_token);

if (result.type == SQLiteError) {
Expand All @@ -135,8 +171,7 @@ DBHostObject::DBHostObject(jsi::Runtime &rt,
std::string &db_name, std::string &path,
std::string &url, std::string &auth_token,
int sync_interval)
: db_name(db_name), invoker(invoker), thread_pool(thread_pool),
rt(rt) {
: db_name(db_name), invoker(invoker), thread_pool(thread_pool), rt(rt) {
BridgeResult result =
opsqlite_libsql_open_sync(db_name, path, url, auth_token, sync_interval);

Expand All @@ -156,8 +191,8 @@ DBHostObject::DBHostObject(jsi::Runtime &rt, std::string &base_path,
std::string &crsqlite_path,
std::string &sqlite_vec_path,
std::string &encryption_key)
: base_path(base_path), invoker(invoker),
thread_pool(thread_pool), db_name(db_name), rt(rt) {
: base_path(base_path), invoker(invoker), thread_pool(thread_pool),
db_name(db_name), rt(rt) {

#ifdef OP_SQLITE_USE_SQLCIPHER
BridgeResult result = opsqlite_open(db_name, path, crsqlite_path,
Expand Down Expand Up @@ -527,7 +562,7 @@ void DBHostObject::create_jsi_functions() {
}

invoker->invokeAsync([&rt, batchResult = std::move(batchResult),
resolve, reject] {
resolve, reject] {
if (batchResult.type == SQLiteOk) {
auto res = jsi::Object(rt);
res.setProperty(rt, "rowsAffected",
Expand Down Expand Up @@ -587,7 +622,7 @@ void DBHostObject::create_jsi_functions() {
const auto result = importSQLFile(db_name, sqlFileName);

invoker->invokeAsync([&rt, result = std::move(result), resolve,
reject] {
reject] {
if (result.type == SQLiteOk) {
auto res = jsi::Object(rt);
res.setProperty(rt, "rowsAffected",
Expand Down Expand Up @@ -773,8 +808,8 @@ void DBHostObject::create_jsi_functions() {
sqlite3_stmt *statement = opsqlite_prepare_statement(db_name, query);
#endif
auto preparedStatementHostObject =
std::make_shared<PreparedStatementHostObject>(
db_name, statement, invoker, thread_pool);
std::make_shared<PreparedStatementHostObject>(db_name, statement,
invoker, thread_pool);

return jsi::Object::createFromHostObject(rt, preparedStatementHostObject);
});
Expand Down Expand Up @@ -802,6 +837,12 @@ void DBHostObject::create_jsi_functions() {
return jsi::String::createFromUtf8(rt, result);
});

auto flush_pending_reactive_queries_js =
HOSTFN("flushPendingReactiveQueries") {
flush_pending_reactive_queries();
return {};
});

function_map["attach"] = std::move(attach);
function_map["detach"] = std::move(detach);
function_map["close"] = std::move(close);
Expand All @@ -821,6 +862,8 @@ void DBHostObject::create_jsi_functions() {
function_map["rollbackHook"] = std::move(rollback_hook);
function_map["loadExtension"] = std::move(load_extension);
function_map["reactiveExecute"] = std::move(reactive_execute);
function_map["flushPendingReactiveQueries"] =
std::move(flush_pending_reactive_queries_js);
#endif
}

Expand All @@ -834,6 +877,12 @@ jsi::Value DBHostObject::get(jsi::Runtime &rt,
const jsi::PropNameID &propNameID) {

auto name = propNameID.utf8(rt);
if (name == "execute") {
return jsi::Value(rt, function_map["execute"]);
}
if (name == "flushPendingReactiveQueries") {
return jsi::Value(rt, function_map["flushPendingReactiveQueries"]);
}
if (name == "attach") {
return jsi::Value(rt, function_map["attach"]);
}
Expand All @@ -846,9 +895,6 @@ jsi::Value DBHostObject::get(jsi::Runtime &rt,
if (name == "executeRaw") {
return jsi::Value(rt, function_map["executeRaw"]);
}
if (name == "execute") {
return jsi::Value(rt, function_map["execute"]);
}
if (name == "executeWithHostObjects") {
return jsi::Value(rt, function_map["executeWithHostObjects"]);
}
Expand Down
4 changes: 3 additions & 1 deletion cpp/DBHostObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
#include "sqlite3.h"
#include "types.h"
#include <ReactCommon/CallInvoker.h>
#include <any>
#include <jsi/jsi.h>
#include <unordered_map>
#include <vector>
#include <set>

namespace opsqlite {

Expand Down Expand Up @@ -61,8 +61,10 @@ class JSI_EXPORT DBHostObject : public jsi::HostObject {
~DBHostObject();

private:
std::set<std::shared_ptr<ReactiveQuery>> pending_reactive_queries;
void auto_register_update_hook();
void create_jsi_functions();
void flush_pending_reactive_queries();

std::unordered_map<std::string, jsi::Value> function_map;
std::string base_path;
Expand Down
6 changes: 3 additions & 3 deletions example/src/tests/dbsetup.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ import {Platform} from 'react-native';
let expect = chai.expect;

const expectedVersion = isLibsql()
? '3.45.1'
? '3.46.1'
: isSQLCipher()
? '3.44.2'
: '3.45.1';
? '3.46.1'
: '3.46.1';

// const expectedSqliteVecVersion = 'v0.1.2-alpha.7';

Expand Down
4 changes: 2 additions & 2 deletions example/src/tests/hooks.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import Chance from 'chance';

import {type DB, open, isLibsql} from '@op-engineering/op-sqlite';
import chai from 'chai';
import {describe, it, beforeEach, afterAll, itOnly} from './MochaRNAdapter';
import {describe, it, beforeEach, afterAll} from './MochaRNAdapter';
import {sleep} from './utils';

const expect = chai.expect;
Expand Down Expand Up @@ -47,7 +47,7 @@ export function registerHooksTests() {
return;
}

itOnly('update hook', async () => {
it('update hook', async () => {
let promiseResolve: any;
let promise = new Promise<{
rowId: number;
Expand Down
2 changes: 1 addition & 1 deletion example/src/tests/queries.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,7 @@ export function queriesTests() {
expect(res.insertId).to.equal(1);
// expect(res.metadata).to.eql([]);
expect(res.rows).to.eql([]);
expect(res.rows?.length).to.equal(0);
expect(res.rows.length).to.equal(0);

await tx.commit();

Expand Down
Loading

0 comments on commit 3ca43ac

Please sign in to comment.