y-cap-sqlite
Version:
y-cap-sqlite is a persistence provider for [Yjs](https://github.com/yjs/yjs) that uses [@capacitor-community/sqlite](https://github.com/capacitor-community/sqlite) to store document changes in a SQLite database. This is useful for Capacitor projects that
85 lines (84 loc) • 2.79 kB
JavaScript
// src/index.ts
import * as Y from "yjs";
import * as promise from "lib0/promise";
import { ObservableV2 } from "lib0/observable";
import { Buffer } from "buffer";
var DB_PREFIX = "cap-sqlite-persistence-";
var CapSQLitePersistence = class _CapSQLitePersistence extends ObservableV2 {
doc;
config;
whenSynced;
name;
db;
con;
synced = false;
_dbref = 0;
_dbsize = 0;
_destroyed = false;
constructor(config, doc, name, sqlite) {
super();
this.doc = doc;
this.config = config;
this.name = name;
this.con = sqlite;
this.whenSynced = promise.create(
(resolve) => this.on("synced", () => resolve(this))
);
this.destroy = this.destroy.bind(this);
this._storeUpdate.bind(this);
doc.on("update", this._storeUpdate.bind(this));
doc.on("destroy", this.destroy.bind(this));
}
async initDb() {
try {
const dbName = DB_PREFIX + this.name;
console.log((await this.con.isConnection(dbName, this.config.readonly ?? false)).result);
if ((await this.con.isConnection(dbName, this.config.readonly ?? false)).result) {
this.db = await this.con.retrieveConnection(dbName, this.config.readonly ?? false);
} else {
this.db = await this.con.createConnection(dbName, this.config.encrypted ?? false, this.config.mode ?? "", this.config.version ?? 1, this.config.readonly ?? false);
}
await this.db.open();
await this.db.execute("CREATE TABLE IF NOT EXISTS updates (id INTEGER PRIMARY KEY, content BLOB)");
const s = Y.encodeStateAsUpdate(this.doc);
if (s.length > 0) {
this._storeUpdate(s, null);
}
const { values } = await this.db.query("SELECT content FROM updates");
if (values != void 0) {
for (const row of values) {
Y.applyUpdate(this.doc, new Uint8Array(row.content));
}
}
this.synced = true;
this.emit("synced", [this]);
console.log("initialisation finished");
} catch (e) {
console.log("error loading update", e);
throw e;
}
}
static async create(config, doc, name, sqlite) {
const c = new _CapSQLitePersistence(config, doc, name, sqlite);
await c.initDb();
return c;
}
_storeUpdate(update, origin) {
if (!this.db || origin == this) {
!this.db && console.error("trying to store update without db");
return;
}
return this.db.run(`INSERT INTO updates (content) VALUES (?)`, [Buffer.from(update)]).catch((e) => console.error("error storing update", e));
}
destroy() {
this.doc.off("update", this._storeUpdate);
this.doc.off("destroy", this.destroy);
this._destroyed = true;
return this.db?.close().catch((e) => {
console.log("can't close", e);
});
}
};
export {
CapSQLitePersistence
};