@powersync/react-native
Version:
PowerSync React Native SDK. Sync Postgres, MongoDB or MySQL with SQLite in your React Native app
123 lines (122 loc) • 4.45 kB
JavaScript
import { BaseObserver } from '@powersync/common';
/**
* Adapter for React Native Quick SQLite
*/
export class RNQSDBAdapter extends BaseObserver {
baseDB;
name;
getAll;
getOptional;
get;
constructor(baseDB, name) {
super();
this.baseDB = baseDB;
this.name = name;
// link table update commands
baseDB.registerTablesChangedHook((update) => {
this.iterateListeners((cb) => cb.tablesUpdated?.(update));
});
const topLevelUtils = this.generateDBHelpers({
// Arrow function binds `this` for use in readOnlyExecute
execute: (sql, params) => this.readOnlyExecute(sql, params)
});
// Only assigning get helpers
this.getAll = topLevelUtils.getAll;
this.getOptional = topLevelUtils.getOptional;
this.get = topLevelUtils.get;
}
close() {
return this.baseDB.close();
}
readLock(fn, options) {
return this.baseDB.readLock((dbTx) => fn(this.generateDBHelpers(this.generateContext(dbTx))), options);
}
readTransaction(fn, options) {
return this.baseDB.readTransaction((dbTx) => fn(this.generateDBHelpers(this.generateContext(dbTx))), options);
}
writeLock(fn, options) {
return this.baseDB.writeLock((dbTx) => fn(this.generateDBHelpers(this.generateContext(dbTx))), options);
}
writeTransaction(fn, options) {
return this.baseDB.writeTransaction((dbTx) => fn(this.generateDBHelpers(this.generateContext(dbTx))), options);
}
execute(query, params) {
return this.baseDB.execute(query, params);
}
/**
* 'executeRaw' is not implemented in RNQS, this falls back to 'execute'.
*/
async executeRaw(query, params) {
const result = await this.baseDB.execute(query, params);
const rows = result.rows?._array ?? [];
return rows.map((row) => Object.values(row));
}
async executeBatch(query, params = []) {
const commands = [];
for (let i = 0; i < params.length; i++) {
commands.push([query, params[i]]);
}
const result = await this.baseDB.executeBatch(commands);
return {
rowsAffected: result.rowsAffected ? result.rowsAffected : 0
};
}
generateContext(ctx) {
return {
...ctx,
// 'executeRaw' is not implemented in RNQS, this falls back to 'execute'.
executeRaw: async (sql, params) => {
const result = await ctx.execute(sql, params);
const rows = result.rows?._array ?? [];
return rows.map((row) => Object.values(row));
}
};
}
/**
* This provides a top-level read only execute method which is executed inside a read-lock.
* This is necessary since the high level `execute` method uses a write-lock under
* the hood. Helper methods such as `get`, `getAll` and `getOptional` are read only,
* and should use this method.
*/
readOnlyExecute(sql, params) {
return this.baseDB.readLock((ctx) => ctx.execute(sql, params));
}
/**
* Adds DB get utils to lock contexts and transaction contexts
* @param tx
* @returns
*/
generateDBHelpers(tx) {
return {
...tx,
/**
* Execute a read-only query and return results
*/
getAll: async (sql, parameters) => {
const res = await tx.execute(sql, parameters);
return res.rows?._array ?? [];
},
/**
* Execute a read-only query and return the first result, or null if the ResultSet is empty.
*/
getOptional: async (sql, parameters) => {
const res = await tx.execute(sql, parameters);
return res.rows?.item(0) ?? null;
},
/**
* Execute a read-only query and return the first result, error if the ResultSet is empty.
*/
get: async (sql, parameters) => {
const res = await tx.execute(sql, parameters);
const first = res.rows?.item(0);
if (!first) {
throw new Error('Result set is empty');
}
return first;
}
};
}
async refreshSchema() {
await this.baseDB.refreshSchema();
}
}