@powersync/web 1.15.1 → 1.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@powersync/web",
3
- "version": "1.15.1",
3
+ "version": "1.17.0",
4
4
  "description": "PowerSync web SDK. Sync Postgres, MongoDB or MySQL with SQLite in your web app",
5
5
  "main": "lib/src/index.js",
6
6
  "types": "lib/src/index.d.ts",
@@ -61,7 +61,7 @@
61
61
  "license": "Apache-2.0",
62
62
  "peerDependencies": {
63
63
  "@journeyapps/wa-sqlite": "^1.2.2",
64
- "@powersync/common": "workspace:^1.25.0"
64
+ "@powersync/common": "workspace:^1.26.0"
65
65
  },
66
66
  "dependencies": {
67
67
  "@powersync/common": "workspace:*",
@@ -19,6 +19,7 @@ export interface AsyncDatabaseConnection<Config extends ResolvedWebSQLOpenOption
19
19
  init(): Promise<void>;
20
20
  close(): Promise<void>;
21
21
  execute(sql: string, params?: any[]): Promise<ProxiedQueryResult>;
22
+ executeRaw(sql: string, params?: any[]): Promise<any[][]>;
22
23
  executeBatch(sql: string, params?: any[]): Promise<ProxiedQueryResult>;
23
24
  registerOnTableChange(callback: OnTableChangeCallback): Promise<() => void>;
24
25
  getConfig(): Promise<Config>;
@@ -51,6 +51,7 @@ export declare class LockedAsyncDatabaseAdapter extends BaseObserver<LockedAsync
51
51
  */
52
52
  refreshSchema(): Promise<void>;
53
53
  execute(query: string, params?: any[] | undefined): Promise<QueryResult>;
54
+ executeRaw(query: string, params?: any[] | undefined): Promise<any[][]>;
54
55
  executeBatch(query: string, params?: any[][]): Promise<QueryResult>;
55
56
  /**
56
57
  * Attempts to close the connection.
@@ -75,6 +76,10 @@ export declare class LockedAsyncDatabaseAdapter extends BaseObserver<LockedAsync
75
76
  * Wraps the worker execute function, awaiting for it to be available
76
77
  */
77
78
  private _execute;
79
+ /**
80
+ * Wraps the worker executeRaw function, awaiting for it to be available
81
+ */
82
+ private _executeRaw;
78
83
  /**
79
84
  * Wraps the worker executeBatch function, awaiting for it to be available
80
85
  */
@@ -40,7 +40,8 @@ export class LockedAsyncDatabaseAdapter extends BaseObserver {
40
40
  };
41
41
  }
42
42
  this.dbGetHelpers = this.generateDBHelpers({
43
- execute: (query, params) => this.acquireLock(() => this._execute(query, params))
43
+ execute: (query, params) => this.acquireLock(() => this._execute(query, params)),
44
+ executeRaw: (query, params) => this.acquireLock(() => this._executeRaw(query, params))
44
45
  });
45
46
  this.initPromise = this._init();
46
47
  }
@@ -98,6 +99,9 @@ export class LockedAsyncDatabaseAdapter extends BaseObserver {
98
99
  async execute(query, params) {
99
100
  return this.writeLock((ctx) => ctx.execute(query, params));
100
101
  }
102
+ async executeRaw(query, params) {
103
+ return this.writeLock((ctx) => ctx.executeRaw(query, params));
104
+ }
101
105
  async executeBatch(query, params) {
102
106
  return this.writeLock((ctx) => this._executeBatch(query, params));
103
107
  }
@@ -124,11 +128,11 @@ export class LockedAsyncDatabaseAdapter extends BaseObserver {
124
128
  }
125
129
  async readLock(fn, options) {
126
130
  await this.waitForInitialized();
127
- return this.acquireLock(async () => fn(this.generateDBHelpers({ execute: this._execute })));
131
+ return this.acquireLock(async () => fn(this.generateDBHelpers({ execute: this._execute, executeRaw: this._executeRaw })));
128
132
  }
129
133
  async writeLock(fn, options) {
130
134
  await this.waitForInitialized();
131
- return this.acquireLock(async () => fn(this.generateDBHelpers({ execute: this._execute })));
135
+ return this.acquireLock(async () => fn(this.generateDBHelpers({ execute: this._execute, executeRaw: this._executeRaw })));
132
136
  }
133
137
  acquireLock(callback) {
134
138
  return getNavigatorLocks().request(`db-lock-${this._dbIdentifier}`, callback);
@@ -225,6 +229,13 @@ export class LockedAsyncDatabaseAdapter extends BaseObserver {
225
229
  }
226
230
  };
227
231
  };
232
+ /**
233
+ * Wraps the worker executeRaw function, awaiting for it to be available
234
+ */
235
+ _executeRaw = async (sql, bindings) => {
236
+ await this.waitForInitialized();
237
+ return await this.baseDB.executeRaw(sql, bindings);
238
+ };
228
239
  /**
229
240
  * Wraps the worker executeBatch function, awaiting for it to be available
230
241
  */
@@ -16,6 +16,7 @@ export declare class SSRDBAdapter extends BaseObserver<DBAdapterListener> implem
16
16
  writeLock<T>(fn: (tx: LockContext) => Promise<T>, options?: DBLockOptions): Promise<T>;
17
17
  writeTransaction<T>(fn: (tx: Transaction) => Promise<T>, options?: DBLockOptions): Promise<T>;
18
18
  execute(query: string, params?: any[]): Promise<QueryResult>;
19
+ executeRaw(query: string, params?: any[]): Promise<any[][]>;
19
20
  executeBatch(query: string, params?: any[][]): Promise<QueryResult>;
20
21
  getAll<T>(sql: string, parameters?: any[]): Promise<T[]>;
21
22
  getOptional<T>(sql: string, parameters?: any[] | undefined): Promise<T | null>;
@@ -34,6 +34,9 @@ export class SSRDBAdapter extends BaseObserver {
34
34
  async execute(query, params) {
35
35
  return this.writeMutex.runExclusive(async () => MOCK_QUERY_RESPONSE);
36
36
  }
37
+ async executeRaw(query, params) {
38
+ return this.writeMutex.runExclusive(async () => []);
39
+ }
37
40
  async executeBatch(query, params) {
38
41
  return this.writeMutex.runExclusive(async () => MOCK_QUERY_RESPONSE);
39
42
  }
@@ -35,6 +35,7 @@ export declare class WorkerWrappedAsyncDatabaseConnection<Config extends Resolve
35
35
  registerOnTableChange(callback: OnTableChangeCallback): Promise<() => void>;
36
36
  close(): Promise<void>;
37
37
  execute(sql: string, params?: any[]): Promise<ProxiedQueryResult>;
38
+ executeRaw(sql: string, params?: any[]): Promise<any[][]>;
38
39
  executeBatch(sql: string, params?: any[]): Promise<ProxiedQueryResult>;
39
40
  getConfig(): Promise<ResolvedWebSQLOpenOptions>;
40
41
  }
@@ -29,7 +29,7 @@ export class WorkerWrappedAsyncDatabaseConnection {
29
29
  * The `shareConnection` method should not be called on multiple tabs concurrently.
30
30
  */
31
31
  await new Promise((resolve, reject) => navigator.locks
32
- .request(`shared-connection-${this.options.identifier}`, {
32
+ .request(`shared-connection-${this.options.identifier}-${Date.now()}-${Math.round(Math.random() * 10000)}`, {
33
33
  signal: this.lockAbortController.signal
34
34
  }, async () => {
35
35
  resolve();
@@ -73,6 +73,9 @@ export class WorkerWrappedAsyncDatabaseConnection {
73
73
  execute(sql, params) {
74
74
  return this.baseConnection.execute(sql, params);
75
75
  }
76
+ executeRaw(sql, params) {
77
+ return this.baseConnection.executeRaw(sql, params);
78
+ }
76
79
  executeBatch(sql, params) {
77
80
  return this.baseConnection.executeBatch(sql, params);
78
81
  }
@@ -113,6 +113,7 @@ export declare class WASqliteConnection extends BaseObserver<WASQLiteConnectionL
113
113
  * This executes single SQL statements inside a requested lock.
114
114
  */
115
115
  execute(sql: string | TemplateStringsArray, bindings?: any[]): Promise<ProxiedQueryResult>;
116
+ executeRaw(sql: string | TemplateStringsArray, bindings?: any[]): Promise<any[][]>;
116
117
  close(): Promise<void>;
117
118
  registerOnTableChange(callback: OnTableChangeCallback): Promise<() => void>;
118
119
  /**
@@ -124,4 +125,9 @@ export declare class WASqliteConnection extends BaseObserver<WASQLiteConnectionL
124
125
  * This executes a single statement using SQLite3.
125
126
  */
126
127
  protected executeSingleStatement(sql: string | TemplateStringsArray, bindings?: any[]): Promise<ProxiedQueryResult>;
128
+ /**
129
+ * This executes a single statement using SQLite3 and returns the results as an array of arrays.
130
+ */
131
+ protected executeSingleStatementRaw(sql: string | TemplateStringsArray, bindings?: any[]): Promise<any[][]>;
132
+ private _execute;
127
133
  }
@@ -184,8 +184,8 @@ export class WASqliteConnection extends BaseObserver {
184
184
  await this.openDB();
185
185
  this.registerBroadcastListeners();
186
186
  await this.executeSingleStatement(`PRAGMA temp_store = ${this.options.temporaryStorage};`);
187
- await this.executeSingleStatement(`PRAGMA cache_size = -${this.options.cacheSizeKb};`);
188
187
  await this.executeEncryptionPragma();
188
+ await this.executeSingleStatement(`PRAGMA cache_size = -${this.options.cacheSizeKb};`);
189
189
  this.sqliteAPI.update_hook(this.dbP, (updateType, dbName, tableName) => {
190
190
  if (!tableName) {
191
191
  return;
@@ -271,6 +271,11 @@ export class WASqliteConnection extends BaseObserver {
271
271
  return this.executeSingleStatement(sql, bindings);
272
272
  });
273
273
  }
274
+ async executeRaw(sql, bindings) {
275
+ return this.acquireExecuteLock(async () => {
276
+ return this.executeSingleStatementRaw(sql, bindings);
277
+ });
278
+ }
274
279
  async close() {
275
280
  this.broadcastChannel?.close();
276
281
  await this.sqliteAPI.close(this.dbP);
@@ -291,6 +296,35 @@ export class WASqliteConnection extends BaseObserver {
291
296
  * This executes a single statement using SQLite3.
292
297
  */
293
298
  async executeSingleStatement(sql, bindings) {
299
+ const results = await this._execute(sql, bindings);
300
+ const rows = [];
301
+ for (const resultSet of results) {
302
+ for (const row of resultSet.rows) {
303
+ const outRow = {};
304
+ resultSet.columns.forEach((key, index) => {
305
+ outRow[key] = row[index];
306
+ });
307
+ rows.push(outRow);
308
+ }
309
+ }
310
+ const result = {
311
+ insertId: this.sqliteAPI.last_insert_id(this.dbP),
312
+ rowsAffected: this.sqliteAPI.changes(this.dbP),
313
+ rows: {
314
+ _array: rows,
315
+ length: rows.length
316
+ }
317
+ };
318
+ return result;
319
+ }
320
+ /**
321
+ * This executes a single statement using SQLite3 and returns the results as an array of arrays.
322
+ */
323
+ async executeSingleStatementRaw(sql, bindings) {
324
+ const results = await this._execute(sql, bindings);
325
+ return results.flatMap((resultset) => resultset.rows.map((row) => resultset.columns.map((_, index) => row[index])));
326
+ }
327
+ async _execute(sql, bindings) {
294
328
  const results = [];
295
329
  for await (const stmt of this.sqliteAPI.statements(this.dbP, sql)) {
296
330
  let columns;
@@ -321,24 +355,6 @@ export class WASqliteConnection extends BaseObserver {
321
355
  break;
322
356
  }
323
357
  }
324
- const rows = [];
325
- for (const resultSet of results) {
326
- for (const row of resultSet.rows) {
327
- const outRow = {};
328
- resultSet.columns.forEach((key, index) => {
329
- outRow[key] = row[index];
330
- });
331
- rows.push(outRow);
332
- }
333
- }
334
- const result = {
335
- insertId: this.sqliteAPI.last_insert_id(this.dbP),
336
- rowsAffected: this.sqliteAPI.changes(this.dbP),
337
- rows: {
338
- _array: rows,
339
- length: rows.length
340
- }
341
- };
342
- return result;
358
+ return results;
343
359
  }
344
360
  }
@@ -15,6 +15,7 @@ const openWorkerConnection = async (options) => {
15
15
  getConfig: Comlink.proxy(() => connection.getConfig()),
16
16
  close: Comlink.proxy(() => connection.close()),
17
17
  execute: Comlink.proxy(async (sql, params) => connection.execute(sql, params)),
18
+ executeRaw: Comlink.proxy(async (sql, params) => connection.executeRaw(sql, params)),
18
19
  executeBatch: Comlink.proxy(async (sql, params) => connection.executeBatch(sql, params)),
19
20
  registerOnTableChange: Comlink.proxy(async (callback) => {
20
21
  // Proxy the callback remove function