Skip to content

Commit

Permalink
Merge pull request #148 from tursodatabase/offline-writes
Browse files Browse the repository at this point in the history
Offline writes
  • Loading branch information
penberg authored Nov 5, 2024
2 parents f941c5d + 2cd3ebb commit 1054c4e
Show file tree
Hide file tree
Showing 10 changed files with 796 additions and 65 deletions.
762 changes: 717 additions & 45 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ crate-type = ["cdylib"]

[dependencies]
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
libsql = { git = "https://github.com/tursodatabase/libsql/", rev = "20147731c4a9d6e942b159f183215e9399fda2c3", features = ["encryption"] }
libsql = { git = "https://github.com/tursodatabase/libsql/", rev = "18f444290d9f2542d6da14e559d2b3e31f8f157d", features = ["encryption"] }
tracing = "0.1"
once_cell = "1.18.0"
tokio = { version = "1.29.1", features = [ "rt-multi-thread" ] }
Expand Down
35 changes: 35 additions & 0 deletions examples/offline-writes/example.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import Database from "libsql";
import reader from "readline-sync";

const dbPath = process.env.LIBSQL_DB_PATH;
if (!dbPath) {
throw new Error("Environment variable LIBSQL_DB_PATH is not set.");
}
const syncUrl = process.env.LIBSQL_SYNC_URL;
if (!syncUrl) {
throw new Error("Environment variable LIBSQL_SYNC_URL is not set.");
}
const authToken = process.env.LIBSQL_AUTH_TOKEN;

const options = { syncUrl: syncUrl, authToken: authToken, offline: true };
const db = new Database(dbPath, options);

db.exec("CREATE TABLE IF NOT EXISTS guest_book_entries (text TEXT)");

const comment = reader.question("Enter your comment: ");

console.log(comment);

const stmt = db.prepare("INSERT INTO guest_book_entries (text) VALUES (?)");
stmt.run(comment);
console.log("max write replication index: " + db.maxWriteReplicationIndex());

const replicated = db.sync();
console.log("frames synced: " + replicated.frames_synced);
console.log("frame no: " + replicated.frame_no);

console.log("Guest book entries:");
const rows = db.prepare("SELECT * FROM guest_book_entries").all();
for (const row of rows) {
console.log(" - " + row.text);
}
17 changes: 17 additions & 0 deletions examples/offline-writes/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "libsql-example",
"version": "1.0.0",
"description": "",
"type": "module",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"libsql": "../..",
"readline-sync": "^1.4.10"
}
}
5 changes: 3 additions & 2 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ function requireNative() {

const {
databaseOpen,
databaseOpenWithRpcSync,
databaseOpenWithSync,
databaseInTransaction,
databaseClose,
databaseSyncSync,
Expand Down Expand Up @@ -76,7 +76,8 @@ class Database {
const encryptionKey = opts?.encryptionKey ?? "";
const syncPeriod = opts?.syncPeriod ?? 0.0;
const readYourWrites = opts?.readYourWrites ?? true;
this.db = databaseOpenWithRpcSync(path, opts.syncUrl, authToken, encryptionCipher, encryptionKey, syncPeriod, readYourWrites);
const offline = opts?.offline ?? false;
this.db = databaseOpenWithSync(path, opts.syncUrl, authToken, encryptionCipher, encryptionKey, syncPeriod, readYourWrites, offline);
} else {
const authToken = opts?.authToken ?? "";
const encryptionKey = opts?.encryptionKey ?? "";
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions promise.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ function requireNative() {

const {
databaseOpen,
databaseOpenWithRpcSync,
databaseOpenWithSync,
databaseInTransaction,
databaseClose,
databaseSyncAsync,
Expand Down Expand Up @@ -79,7 +79,8 @@ class Database {
}
const encryptionKey = opts?.encryptionKey ?? "";
const syncPeriod = opts?.syncPeriod ?? 0.0;
this.db = databaseOpenWithRpcSync(path, opts.syncUrl, authToken, encryptionCipher, encryptionKey, syncPeriod);
const offline = opts?.offline ?? false;
this.db = databaseOpenWithSync(path, opts.syncUrl, authToken, encryptionCipher, encryptionKey, syncPeriod, offline);
} else {
const authToken = opts?.authToken ?? "";
const encryptionKey = opts?.encryptionKey ?? "";
Expand Down
27 changes: 16 additions & 11 deletions src/database.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,14 +61,15 @@ impl Database {
Ok(cx.boxed(db))
}

pub fn js_open_with_rpc_sync(mut cx: FunctionContext) -> JsResult<JsBox<Database>> {
pub fn js_open_with_sync(mut cx: FunctionContext) -> JsResult<JsBox<Database>> {
let db_path = cx.argument::<JsString>(0)?.value(&mut cx);
let sync_url = cx.argument::<JsString>(1)?.value(&mut cx);
let sync_auth = cx.argument::<JsString>(2)?.value(&mut cx);
let encryption_cipher = cx.argument::<JsString>(3)?.value(&mut cx);
let encryption_key = cx.argument::<JsString>(4)?.value(&mut cx);
let sync_period = cx.argument::<JsNumber>(5)?.value(&mut cx);
let read_your_writes = cx.argument::<JsBoolean>(6)?.value(&mut cx);
let offline = cx.argument::<JsBoolean>(7)?.value(&mut cx);

let cipher = libsql::Cipher::from_str(&encryption_cipher).or_else(|err| {
throw_libsql_error(
Expand All @@ -95,16 +96,20 @@ impl Database {
sync_url
);
let rt = runtime(&mut cx)?;
let fut = libsql::Database::open_with_remote_sync_internal(
db_path,
sync_url,
sync_auth,
Some(version),
read_your_writes,
encryption_config,
sync_period,
);
let result = rt.block_on(fut);
let result = if offline {
rt.block_on(libsql::Builder::new_synced_database(db_path, sync_url, sync_auth).build())
} else {
rt.block_on(async {
let mut builder = libsql::Builder::new_remote_replica(db_path, sync_url, sync_auth);
if let Some(encryption_config) = encryption_config {
builder = builder.encryption_config(encryption_config);
}
if let Some(sync_period) = sync_period {
builder = builder.sync_interval(sync_period);
}
builder.build().await
})
};
let db = result.or_else(|err| cx.throw_error(err.to_string()))?;
let conn = db
.connect()
Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ fn main(mut cx: ModuleContext) -> NeonResult<()> {
)
.try_init();
cx.export_function("databaseOpen", Database::js_open)?;
cx.export_function("databaseOpenWithRpcSync", Database::js_open_with_rpc_sync)?;
cx.export_function("databaseOpenWithSync", Database::js_open_with_sync)?;
cx.export_function("databaseInTransaction", Database::js_in_transaction)?;
cx.export_function("databaseClose", Database::js_close)?;
cx.export_function("databaseSyncSync", Database::js_sync_sync)?;
Expand Down
2 changes: 1 addition & 1 deletion types/promise.d.ts.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 1054c4e

Please sign in to comment.