@powersync/capacitor 0.5.0 → 0.5.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@powersync/capacitor",
3
- "version": "0.5.0",
3
+ "version": "0.5.2",
4
4
  "description": "Adds PowerSync Capacitor support for iOS/Android",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org/",
@@ -67,7 +67,7 @@
67
67
  },
68
68
  "peerDependencies": {
69
69
  "@capacitor-community/sqlite": "^7.0.2",
70
- "@powersync/web": "^1.35.0"
70
+ "@powersync/web": "^1.37.0"
71
71
  },
72
72
  "swiftlint": "@ionic/swiftlint-config",
73
73
  "capacitor": {
@@ -80,9 +80,6 @@
80
80
  "src": "android"
81
81
  }
82
82
  },
83
- "dependencies": {
84
- "async-mutex": "^0.5.0"
85
- },
86
83
  "scripts": {
87
84
  "verify": "pnpm verify:ios && pnpm verify:android && pnpm verify:web",
88
85
  "verify:ios": "cd example-app && npm install && cd ios/App && pod install && xcodebuild -workspace App.xcworkspace -scheme App -destination 'platform=iOS Simulator,name=iPhone 16,OS=latest'",
@@ -4,15 +4,17 @@ import { Capacitor } from '@capacitor/core';
4
4
  import {
5
5
  BaseObserver,
6
6
  BatchedUpdateNotification,
7
+ ConnectionPool,
7
8
  DBAdapter,
9
+ DBAdapterDefaultMixin,
8
10
  DBAdapterListener,
9
11
  DBLockOptions,
10
12
  LockContext,
11
- mutexRunExclusive,
13
+ Mutex,
12
14
  QueryResult,
15
+ timeoutSignal,
13
16
  Transaction
14
17
  } from '@powersync/web';
15
- import { Mutex } from 'async-mutex';
16
18
  import { PowerSyncCore } from '../plugin/PowerSyncCore.js';
17
19
  import { messageForErrorCode } from '../plugin/PowerSyncPlugin.js';
18
20
  import { CapacitorSQLiteOpenFactoryOptions, DEFAULT_SQLITE_OPTIONS } from './CapacitorSQLiteOpenFactory.js';
@@ -30,13 +32,8 @@ async function monitorQuery(sql: string, executor: () => Promise<QueryResult>):
30
32
  throw e;
31
33
  }
32
34
  }
33
- /**
34
- * An implementation of {@link DBAdapter} using the Capacitor Community SQLite [plugin](https://github.com/capacitor-community/sqlite).
35
- *
36
- * @experimental
37
- * @alpha This is currently experimental and may change without a major version bump.
38
- */
39
- export class CapacitorSQLiteAdapter extends BaseObserver<DBAdapterListener> implements DBAdapter {
35
+
36
+ class CapacitorConnectionPool extends BaseObserver<DBAdapterListener> implements ConnectionPool {
40
37
  protected _writeConnection: SQLiteDBConnection | null;
41
38
  protected _readConnection: SQLiteDBConnection | null;
42
39
  protected initializedPromise: Promise<void>;
@@ -206,26 +203,8 @@ export class CapacitorSQLiteAdapter extends BaseObserver<DBAdapterListener> impl
206
203
  return results.rows?._array.map((row) => Object.values(row)) ?? [];
207
204
  };
208
205
 
209
- return {
210
- getAll,
211
- getOptional,
212
- get,
213
- executeRaw,
214
- execute
215
- };
216
- }
217
-
218
- execute(query: string, params?: any[]): Promise<QueryResult> {
219
- return this.writeLock((tx) => tx.execute(query, params));
220
- }
221
-
222
- executeRaw(query: string, params?: any[]): Promise<any[][]> {
223
- return this.writeLock((tx) => tx.executeRaw(query, params));
224
- }
225
-
226
- async executeBatch(query: string, params: any[][] = []): Promise<QueryResult> {
227
- return this.writeLock(async (tx) => {
228
- let result = await this.writeConnection.executeSet(
206
+ const executeBatch = async (query: string, params: any[][] = []): Promise<QueryResult> => {
207
+ let result = await db.executeSet(
229
208
  params.map((param) => ({
230
209
  statement: query,
231
210
  values: param
@@ -236,55 +215,44 @@ export class CapacitorSQLiteAdapter extends BaseObserver<DBAdapterListener> impl
236
215
  rowsAffected: result.changes?.changes ?? 0,
237
216
  insertId: result.changes?.lastId
238
217
  };
239
- });
240
- }
218
+ };
241
219
 
242
- readLock<T>(fn: (tx: LockContext) => Promise<T>, options?: DBLockOptions): Promise<T> {
243
- return mutexRunExclusive(
244
- this.readMutex,
245
- async () => {
246
- await this.initializedPromise;
247
- return await fn(this.generateLockContext(this.readConnection));
248
- },
249
- options
250
- );
220
+ return {
221
+ getAll,
222
+ getOptional,
223
+ get,
224
+ executeRaw,
225
+ execute,
226
+ executeBatch
227
+ };
251
228
  }
252
229
 
253
- readTransaction<T>(fn: (tx: Transaction) => Promise<T>, options?: DBLockOptions): Promise<T> {
254
- return this.readLock(async (ctx) => {
255
- return this.internalTransaction(ctx, fn);
256
- });
230
+ readLock<T>(fn: (tx: LockContext) => Promise<T>, options?: DBLockOptions): Promise<T> {
231
+ return this.readMutex.runExclusive(async () => {
232
+ await this.initializedPromise;
233
+ return fn(this.generateLockContext(this.readConnection));
234
+ }, timeoutSignal(options?.timeoutMs));
257
235
  }
258
236
 
259
237
  writeLock<T>(fn: (tx: LockContext) => Promise<T>, options?: DBLockOptions): Promise<T> {
260
- return mutexRunExclusive(
261
- this.writeMutex,
262
- async () => {
263
- await this.initializedPromise;
264
- const result = await fn(this.generateLockContext(this.writeConnection));
265
-
266
- // Fetch table updates
267
- const updates = await this.writeConnection.query("SELECT powersync_update_hooks('get') AS table_name");
268
- const jsonUpdates = updates.values?.[0];
269
- if (!jsonUpdates || !jsonUpdates.table_name) {
270
- throw new Error('Could not fetch table updates');
271
- }
272
- const notification: BatchedUpdateNotification = {
273
- rawUpdates: [],
274
- tables: JSON.parse(jsonUpdates.table_name),
275
- groupedUpdates: {}
276
- };
277
- this.iterateListeners((l) => l.tablesUpdated?.(notification));
278
- return result;
279
- },
280
- options
281
- );
282
- }
283
-
284
- writeTransaction<T>(fn: (tx: Transaction) => Promise<T>, options?: DBLockOptions): Promise<T> {
285
- return this.writeLock(async (ctx) => {
286
- return this.internalTransaction(ctx, fn);
287
- });
238
+ return this.writeMutex.runExclusive(async () => {
239
+ await this.initializedPromise;
240
+ const result = await fn(this.generateLockContext(this.writeConnection));
241
+
242
+ // Fetch table updates
243
+ const updates = await this.writeConnection.query("SELECT powersync_update_hooks('get') AS table_name");
244
+ const jsonUpdates = updates.values?.[0];
245
+ if (!jsonUpdates || !jsonUpdates.table_name) {
246
+ throw new Error('Could not fetch table updates');
247
+ }
248
+ const notification: BatchedUpdateNotification = {
249
+ rawUpdates: [],
250
+ tables: JSON.parse(jsonUpdates.table_name),
251
+ groupedUpdates: {}
252
+ };
253
+ this.iterateListeners((l) => l.tablesUpdated?.(notification));
254
+ return result;
255
+ }, timeoutSignal(options?.timeoutMs));
288
256
  }
289
257
 
290
258
  refreshSchema(): Promise<void> {
@@ -296,52 +264,12 @@ export class CapacitorSQLiteAdapter extends BaseObserver<DBAdapterListener> impl
296
264
  });
297
265
  });
298
266
  }
299
-
300
- getAll<T>(sql: string, parameters?: any[]): Promise<T[]> {
301
- return this.readLock((tx) => tx.getAll<T>(sql, parameters));
302
- }
303
-
304
- getOptional<T>(sql: string, parameters?: any[]): Promise<T | null> {
305
- return this.readLock((tx) => tx.getOptional<T>(sql, parameters));
306
- }
307
-
308
- get<T>(sql: string, parameters?: any[]): Promise<T> {
309
- return this.readLock((tx) => tx.get<T>(sql, parameters));
310
- }
311
-
312
- protected async internalTransaction<T>(ctx: LockContext, fn: (tx: Transaction) => Promise<T>): Promise<T> {
313
- let finalized = false;
314
- const commit = async (): Promise<QueryResult> => {
315
- if (finalized) {
316
- return { rowsAffected: 0 };
317
- }
318
- finalized = true;
319
- return ctx.execute('COMMIT');
320
- };
321
- const rollback = async (): Promise<QueryResult> => {
322
- if (finalized) {
323
- return { rowsAffected: 0 };
324
- }
325
- finalized = true;
326
- return ctx.execute('ROLLBACK');
327
- };
328
- try {
329
- await ctx.execute('BEGIN');
330
- const result = await fn({
331
- ...ctx,
332
- commit,
333
- rollback
334
- });
335
- await commit();
336
- return result;
337
- } catch (ex) {
338
- try {
339
- await rollback();
340
- } catch (ex2) {
341
- // In rare cases, a rollback may fail.
342
- // Safe to ignore.
343
- }
344
- throw ex;
345
- }
346
- }
347
267
  }
268
+
269
+ /**
270
+ * An implementation of {@link DBAdapter} using the Capacitor Community SQLite [plugin](https://github.com/capacitor-community/sqlite).
271
+ *
272
+ * @experimental
273
+ * @alpha This is currently experimental and may change without a major version bump.
274
+ */
275
+ export class CapacitorSQLiteAdapter extends DBAdapterDefaultMixin(CapacitorConnectionPool) {}
@@ -1,5 +1,4 @@
1
- import { AbstractStreamingSyncImplementation, LockOptions, LockType, mutexRunExclusive } from '@powersync/web';
2
- import { Mutex } from 'async-mutex';
1
+ import { AbstractStreamingSyncImplementation, LockOptions, LockType, Mutex } from '@powersync/web';
3
2
 
4
3
  type MutexMap = {
5
4
  /**
@@ -56,11 +55,8 @@ export class CapacitorStreamingSyncImplementation extends AbstractStreamingSyncI
56
55
  mutexRecord.tracking.add(this.instanceId);
57
56
  const mutex = mutexRecord.locks[lockOptions.type];
58
57
 
59
- return mutexRunExclusive(mutex, async () => {
60
- if (lockOptions.signal?.aborted) {
61
- throw new Error('Aborted');
62
- }
58
+ return mutex.runExclusive(async () => {
63
59
  return await lockOptions.callback();
64
- });
60
+ }, lockOptions.signal);
65
61
  }
66
62
  }