@powersync/common 1.47.0 → 1.49.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.
Files changed (40) hide show
  1. package/dist/bundle.cjs +189 -52
  2. package/dist/bundle.cjs.map +1 -1
  3. package/dist/bundle.mjs +188 -52
  4. package/dist/bundle.mjs.map +1 -1
  5. package/dist/bundle.node.cjs +189 -52
  6. package/dist/bundle.node.cjs.map +1 -1
  7. package/dist/bundle.node.mjs +188 -52
  8. package/dist/bundle.node.mjs.map +1 -1
  9. package/dist/index.d.cts +186 -89
  10. package/lib/client/triggers/TriggerManager.d.ts +13 -1
  11. package/lib/client/triggers/TriggerManagerImpl.d.ts +2 -2
  12. package/lib/client/triggers/TriggerManagerImpl.js +19 -7
  13. package/lib/client/triggers/TriggerManagerImpl.js.map +1 -1
  14. package/lib/db/DBAdapter.d.ts +48 -8
  15. package/lib/db/DBAdapter.js +126 -0
  16. package/lib/db/DBAdapter.js.map +1 -1
  17. package/lib/db/schema/RawTable.d.ts +61 -26
  18. package/lib/db/schema/RawTable.js +1 -32
  19. package/lib/db/schema/RawTable.js.map +1 -1
  20. package/lib/db/schema/Schema.d.ts +14 -7
  21. package/lib/db/schema/Schema.js +25 -3
  22. package/lib/db/schema/Schema.js.map +1 -1
  23. package/lib/db/schema/Table.d.ts +13 -8
  24. package/lib/db/schema/Table.js +3 -8
  25. package/lib/db/schema/Table.js.map +1 -1
  26. package/lib/db/schema/internal.d.ts +12 -0
  27. package/lib/db/schema/internal.js +15 -0
  28. package/lib/db/schema/internal.js.map +1 -0
  29. package/lib/index.d.ts +1 -1
  30. package/lib/index.js +0 -1
  31. package/lib/index.js.map +1 -1
  32. package/package.json +1 -1
  33. package/src/client/triggers/TriggerManager.ts +15 -2
  34. package/src/client/triggers/TriggerManagerImpl.ts +18 -6
  35. package/src/db/DBAdapter.ts +160 -8
  36. package/src/db/schema/RawTable.ts +66 -31
  37. package/src/db/schema/Schema.ts +27 -2
  38. package/src/db/schema/Table.ts +11 -11
  39. package/src/db/schema/internal.ts +17 -0
  40. package/src/index.ts +1 -1
package/dist/bundle.cjs CHANGED
@@ -103,6 +103,21 @@ class Index {
103
103
  }
104
104
  }
105
105
 
106
+ /**
107
+ * @internal Not exported from `index.ts`.
108
+ */
109
+ function encodeTableOptions(options) {
110
+ const trackPrevious = options.trackPrevious;
111
+ return {
112
+ local_only: options.localOnly,
113
+ insert_only: options.insertOnly,
114
+ include_old: trackPrevious && (trackPrevious.columns ?? true),
115
+ include_old_only_when_changed: typeof trackPrevious == 'object' && trackPrevious.onlyWhenChanged == true,
116
+ include_metadata: options.trackMetadata,
117
+ ignore_empty_update: options.ignoreEmptyUpdates
118
+ };
119
+ }
120
+
106
121
  const DEFAULT_TABLE_OPTIONS = {
107
122
  indexes: [],
108
123
  insertOnly: false,
@@ -292,18 +307,12 @@ class Table {
292
307
  }
293
308
  }
294
309
  toJSON() {
295
- const trackPrevious = this.trackPrevious;
296
310
  return {
297
311
  name: this.name,
298
312
  view_name: this.viewName,
299
- local_only: this.localOnly,
300
- insert_only: this.insertOnly,
301
- include_old: trackPrevious && (trackPrevious.columns ?? true),
302
- include_old_only_when_changed: typeof trackPrevious == 'object' && trackPrevious.onlyWhenChanged == true,
303
- include_metadata: this.trackMetadata,
304
- ignore_empty_update: this.ignoreEmptyUpdates,
305
313
  columns: this.columns.map((c) => c.toJSON()),
306
- indexes: this.indexes.map((e) => e.toJSON(this))
314
+ indexes: this.indexes.map((e) => e.toJSON(this)),
315
+ ...encodeTableOptions(this)
307
316
  };
308
317
  }
309
318
  }
@@ -1674,6 +1683,49 @@ var Logger = /*@__PURE__*/getDefaultExportFromCjs(loggerExports);
1674
1683
  * Set of generic interfaces to allow PowerSync compatibility with
1675
1684
  * different SQLite DB implementations.
1676
1685
  */
1686
+ /**
1687
+ * Implements {@link DBGetUtils} on a {@link SqlRunner}.
1688
+ */
1689
+ function DBGetUtilsDefaultMixin(Base) {
1690
+ return class extends Base {
1691
+ async getAll(sql, parameters) {
1692
+ const res = await this.execute(sql, parameters);
1693
+ return res.rows?._array ?? [];
1694
+ }
1695
+ async getOptional(sql, parameters) {
1696
+ const res = await this.execute(sql, parameters);
1697
+ return res.rows?.item(0) ?? null;
1698
+ }
1699
+ async get(sql, parameters) {
1700
+ const res = await this.execute(sql, parameters);
1701
+ const first = res.rows?.item(0);
1702
+ if (!first) {
1703
+ throw new Error('Result set is empty');
1704
+ }
1705
+ return first;
1706
+ }
1707
+ async executeBatch(query, params = []) {
1708
+ // If this context can run batch statements natively, use that.
1709
+ // @ts-ignore
1710
+ if (super.executeBatch) {
1711
+ // @ts-ignore
1712
+ return super.executeBatch(query, params);
1713
+ }
1714
+ // Emulate executeBatch by running statements individually.
1715
+ let lastInsertId;
1716
+ let rowsAffected = 0;
1717
+ for (const set of params) {
1718
+ const result = await this.execute(query, set);
1719
+ lastInsertId = result.insertId;
1720
+ rowsAffected += result.rowsAffected;
1721
+ }
1722
+ return {
1723
+ rowsAffected,
1724
+ insertId: lastInsertId
1725
+ };
1726
+ }
1727
+ };
1728
+ }
1677
1729
  /**
1678
1730
  * Update table operation numbers from SQLite
1679
1731
  */
@@ -1683,6 +1735,89 @@ exports.RowUpdateType = void 0;
1683
1735
  RowUpdateType[RowUpdateType["SQLITE_DELETE"] = 9] = "SQLITE_DELETE";
1684
1736
  RowUpdateType[RowUpdateType["SQLITE_UPDATE"] = 23] = "SQLITE_UPDATE";
1685
1737
  })(exports.RowUpdateType || (exports.RowUpdateType = {}));
1738
+ /**
1739
+ * A mixin to implement {@link DBAdapter} by delegating to {@link ConnectionPool.readLock} and
1740
+ * {@link ConnectionPool.writeLock}.
1741
+ */
1742
+ function DBAdapterDefaultMixin(Base) {
1743
+ return class extends Base {
1744
+ readTransaction(fn, options) {
1745
+ return this.readLock((ctx) => TransactionImplementation.runWith(ctx, fn), options);
1746
+ }
1747
+ writeTransaction(fn, options) {
1748
+ return this.writeLock((ctx) => TransactionImplementation.runWith(ctx, fn), options);
1749
+ }
1750
+ getAll(sql, parameters) {
1751
+ return this.readLock((ctx) => ctx.getAll(sql, parameters));
1752
+ }
1753
+ getOptional(sql, parameters) {
1754
+ return this.readLock((ctx) => ctx.getOptional(sql, parameters));
1755
+ }
1756
+ get(sql, parameters) {
1757
+ return this.readLock((ctx) => ctx.get(sql, parameters));
1758
+ }
1759
+ execute(query, params) {
1760
+ return this.writeLock((ctx) => ctx.execute(query, params));
1761
+ }
1762
+ executeRaw(query, params) {
1763
+ return this.writeLock((ctx) => ctx.executeRaw(query, params));
1764
+ }
1765
+ executeBatch(query, params) {
1766
+ return this.writeTransaction((tx) => tx.executeBatch(query, params));
1767
+ }
1768
+ };
1769
+ }
1770
+ class BaseTransaction {
1771
+ inner;
1772
+ finalized = false;
1773
+ constructor(inner) {
1774
+ this.inner = inner;
1775
+ }
1776
+ async commit() {
1777
+ if (this.finalized) {
1778
+ return { rowsAffected: 0 };
1779
+ }
1780
+ this.finalized = true;
1781
+ return this.inner.execute('COMMIT');
1782
+ }
1783
+ async rollback() {
1784
+ if (this.finalized) {
1785
+ return { rowsAffected: 0 };
1786
+ }
1787
+ this.finalized = true;
1788
+ return this.inner.execute('ROLLBACK');
1789
+ }
1790
+ execute(query, params) {
1791
+ return this.inner.execute(query, params);
1792
+ }
1793
+ executeRaw(query, params) {
1794
+ return this.inner.executeRaw(query, params);
1795
+ }
1796
+ executeBatch(query, params) {
1797
+ return this.inner.executeBatch(query, params);
1798
+ }
1799
+ }
1800
+ class TransactionImplementation extends DBGetUtilsDefaultMixin(BaseTransaction) {
1801
+ static async runWith(ctx, fn) {
1802
+ let tx = new TransactionImplementation(ctx);
1803
+ try {
1804
+ await ctx.execute('BEGIN IMMEDIATE');
1805
+ const result = await fn(tx);
1806
+ await tx.commit();
1807
+ return result;
1808
+ }
1809
+ catch (ex) {
1810
+ try {
1811
+ await tx.rollback();
1812
+ }
1813
+ catch (ex2) {
1814
+ // In rare cases, a rollback may fail.
1815
+ // Safe to ignore.
1816
+ }
1817
+ throw ex;
1818
+ }
1819
+ }
1820
+ }
1686
1821
  function isBatchedUpdateNotification(update) {
1687
1822
  return 'tables' in update;
1688
1823
  }
@@ -10448,7 +10583,7 @@ function requireDist () {
10448
10583
 
10449
10584
  var distExports = requireDist();
10450
10585
 
10451
- var version = "1.47.0";
10586
+ var version = "1.49.0";
10452
10587
  var PACKAGE = {
10453
10588
  version: version};
10454
10589
 
@@ -12481,7 +12616,7 @@ class TriggerManagerImpl {
12481
12616
  }
12482
12617
  async createDiffTrigger(options) {
12483
12618
  await this.db.waitForReady();
12484
- const { source, destination, columns, when, hooks,
12619
+ const { source, destination, columns, when, hooks, setupContext,
12485
12620
  // Fall back to the provided default if not given on this level
12486
12621
  useStorage = this.defaultConfig.useStorageByDefault } = options;
12487
12622
  const operations = Object.keys(when);
@@ -12536,13 +12671,20 @@ class TriggerManagerImpl {
12536
12671
  * we need to ensure we can cleanup the created resources.
12537
12672
  * We unfortunately cannot rely on transaction rollback.
12538
12673
  */
12539
- const cleanup = async () => {
12674
+ const cleanup = async (options) => {
12675
+ const { context } = options ?? {};
12540
12676
  disposeWarningListener();
12541
- return this.db.writeLock(async (tx) => {
12677
+ const doCleanup = async (tx) => {
12542
12678
  await this.removeTriggers(tx, triggerIds);
12543
- await tx.execute(/* sql */ `DROP TABLE IF EXISTS ${destination};`);
12679
+ await tx.execute(`DROP TABLE IF EXISTS ${destination};`);
12544
12680
  await releaseStorageClaim?.();
12545
- });
12681
+ };
12682
+ if (context) {
12683
+ await doCleanup(context);
12684
+ }
12685
+ else {
12686
+ await this.db.writeLock(doCleanup);
12687
+ }
12546
12688
  };
12547
12689
  const setup = async (tx) => {
12548
12690
  // Allow user code to execute in this lock context before the trigger is created.
@@ -12616,12 +12758,17 @@ class TriggerManagerImpl {
12616
12758
  }
12617
12759
  };
12618
12760
  try {
12619
- await this.db.writeLock(setup);
12761
+ if (setupContext) {
12762
+ await setup(setupContext);
12763
+ }
12764
+ else {
12765
+ await this.db.writeLock(setup);
12766
+ }
12620
12767
  return cleanup;
12621
12768
  }
12622
12769
  catch (error) {
12623
12770
  try {
12624
- await cleanup();
12771
+ await cleanup(setupContext ? { context: setupContext } : undefined);
12625
12772
  }
12626
12773
  catch (cleanupError) {
12627
12774
  throw new AggregateError([error, cleanupError], 'Error during operation and cleanup');
@@ -14129,39 +14276,6 @@ class ConnectionClosedError extends Error {
14129
14276
  }
14130
14277
  }
14131
14278
 
14132
- /**
14133
- * Instructs PowerSync to sync data into a "raw" table.
14134
- *
14135
- * Since raw tables are not backed by JSON, running complex queries on them may be more efficient. Further, they allow
14136
- * using client-side table and column constraints.
14137
- *
14138
- * To collect local writes to raw tables with PowerSync, custom triggers are required. See
14139
- * {@link https://docs.powersync.com/usage/use-case-examples/raw-tables the documentation} for details and an example on
14140
- * using raw tables.
14141
- *
14142
- * Note that raw tables are only supported when using the new `SyncClientImplementation.rust` sync client.
14143
- *
14144
- * @experimental Please note that this feature is experimental at the moment, and not covered by PowerSync semver or
14145
- * stability guarantees.
14146
- */
14147
- class RawTable {
14148
- /**
14149
- * The name of the table.
14150
- *
14151
- * This does not have to match the actual table name in the schema - {@link put} and {@link delete} are free to use
14152
- * another table. Instead, this name is used by the sync client to recognize that operations on this table (as it
14153
- * appears in the source / backend database) are to be handled specially.
14154
- */
14155
- name;
14156
- put;
14157
- delete;
14158
- constructor(name, type) {
14159
- this.name = name;
14160
- this.put = type.put;
14161
- this.delete = type.delete;
14162
- }
14163
- }
14164
-
14165
14279
  /**
14166
14280
  * A schema is a collection of tables. It is used to define the structure of a database.
14167
14281
  */
@@ -14206,7 +14320,7 @@ class Schema {
14206
14320
  */
14207
14321
  withRawTables(tables) {
14208
14322
  for (const [name, rawTableDefinition] of Object.entries(tables)) {
14209
- this.rawTables.push(new RawTable(name, rawTableDefinition));
14323
+ this.rawTables.push({ name, ...rawTableDefinition });
14210
14324
  }
14211
14325
  }
14212
14326
  validate() {
@@ -14217,9 +14331,31 @@ class Schema {
14217
14331
  toJSON() {
14218
14332
  return {
14219
14333
  tables: this.tables.map((t) => t.toJSON()),
14220
- raw_tables: this.rawTables
14334
+ raw_tables: this.rawTables.map(Schema.rawTableToJson)
14221
14335
  };
14222
14336
  }
14337
+ /**
14338
+ * Returns a representation of the raw table that is understood by the PowerSync SQLite core extension.
14339
+ *
14340
+ * The output of this can be passed through `JSON.serialize` and then used in `powersync_create_raw_table_crud_trigger`
14341
+ * to define triggers for this table.
14342
+ */
14343
+ static rawTableToJson(table) {
14344
+ const serialized = {
14345
+ name: table.name,
14346
+ put: table.put,
14347
+ delete: table.delete,
14348
+ clear: table.clear
14349
+ };
14350
+ if ('schema' in table) {
14351
+ // We have schema options, those are flattened into the outer JSON object for the core extension.
14352
+ const schema = table.schema;
14353
+ serialized.table_name = schema.tableName ?? table.name;
14354
+ serialized.synced_columns = schema.syncedColumns;
14355
+ Object.assign(serialized, encodeTableOptions(table.schema));
14356
+ }
14357
+ return serialized;
14358
+ }
14223
14359
  }
14224
14360
 
14225
14361
  /**
@@ -14397,6 +14533,8 @@ exports.ControlledExecutor = ControlledExecutor;
14397
14533
  exports.CrudBatch = CrudBatch;
14398
14534
  exports.CrudEntry = CrudEntry;
14399
14535
  exports.CrudTransaction = CrudTransaction;
14536
+ exports.DBAdapterDefaultMixin = DBAdapterDefaultMixin;
14537
+ exports.DBGetUtilsDefaultMixin = DBGetUtilsDefaultMixin;
14400
14538
  exports.DEFAULT_CRUD_BATCH_LIMIT = DEFAULT_CRUD_BATCH_LIMIT;
14401
14539
  exports.DEFAULT_CRUD_UPLOAD_THROTTLE_MS = DEFAULT_CRUD_UPLOAD_THROTTLE_MS;
14402
14540
  exports.DEFAULT_INDEX_COLUMN_OPTIONS = DEFAULT_INDEX_COLUMN_OPTIONS;
@@ -14431,7 +14569,6 @@ exports.MEMORY_TRIGGER_CLAIM_MANAGER = MEMORY_TRIGGER_CLAIM_MANAGER;
14431
14569
  exports.OnChangeQueryProcessor = OnChangeQueryProcessor;
14432
14570
  exports.OpType = OpType;
14433
14571
  exports.OplogEntry = OplogEntry;
14434
- exports.RawTable = RawTable;
14435
14572
  exports.Schema = Schema;
14436
14573
  exports.SqliteBucketStorage = SqliteBucketStorage;
14437
14574
  exports.SyncDataBatch = SyncDataBatch;