@powersync/common 1.57.1 → 2.0.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 (219) hide show
  1. package/lib/attachments/AttachmentContext.d.ts +5 -5
  2. package/lib/attachments/AttachmentContext.js +6 -2
  3. package/lib/attachments/AttachmentContext.js.map +1 -1
  4. package/lib/attachments/AttachmentQueue.d.ts +6 -6
  5. package/lib/attachments/AttachmentQueue.js +9 -8
  6. package/lib/attachments/AttachmentQueue.js.map +1 -1
  7. package/lib/attachments/AttachmentService.d.ts +3 -3
  8. package/lib/attachments/AttachmentService.js +4 -3
  9. package/lib/attachments/AttachmentService.js.map +1 -1
  10. package/lib/attachments/Schema.d.ts +2 -2
  11. package/lib/attachments/SyncingService.d.ts +2 -2
  12. package/lib/attachments/SyncingService.js +21 -6
  13. package/lib/attachments/SyncingService.js.map +1 -1
  14. package/lib/client/{AbstractPowerSyncDatabase.d.ts → CommonPowerSyncDatabase.d.ts} +56 -232
  15. package/lib/client/CommonPowerSyncDatabase.js +2 -0
  16. package/lib/client/CommonPowerSyncDatabase.js.map +1 -0
  17. package/lib/client/SQLOpenFactory.d.ts +35 -13
  18. package/lib/client/SQLOpenFactory.js +1 -25
  19. package/lib/client/SQLOpenFactory.js.map +1 -1
  20. package/lib/client/compilableQueryWatch.d.ts +2 -2
  21. package/lib/client/compilableQueryWatch.js +1 -2
  22. package/lib/client/compilableQueryWatch.js.map +1 -1
  23. package/lib/client/connection/PowerSyncBackendConnector.d.ts +3 -3
  24. package/lib/client/runOnSchemaChange.d.ts +2 -2
  25. package/lib/client/runOnSchemaChange.js.map +1 -1
  26. package/lib/client/sync/bucket/CrudEntry.d.ts +3 -34
  27. package/lib/client/sync/bucket/CrudEntry.js +0 -99
  28. package/lib/client/sync/bucket/CrudEntry.js.map +1 -1
  29. package/lib/client/sync/options.d.ts +65 -0
  30. package/lib/client/sync/options.js +25 -0
  31. package/lib/client/sync/options.js.map +1 -0
  32. package/lib/client/sync/sync-streams.d.ts +1 -1
  33. package/lib/client/triggers/TriggerManager.d.ts +9 -38
  34. package/lib/client/watched/GetAllQuery.d.ts +3 -3
  35. package/lib/client/watched/GetAllQuery.js +1 -1
  36. package/lib/client/watched/GetAllQuery.js.map +1 -1
  37. package/lib/client/watched/WatchedQuery.d.ts +2 -10
  38. package/lib/client/watched/WatchedQuery.js +0 -11
  39. package/lib/client/watched/WatchedQuery.js.map +1 -1
  40. package/lib/client/watched/processors/DifferentialQueryProcessor.d.ts +0 -50
  41. package/lib/client/watched/processors/DifferentialQueryProcessor.js +1 -176
  42. package/lib/client/watched/processors/DifferentialQueryProcessor.js.map +1 -1
  43. package/lib/client/watched/processors/OnChangeQueryProcessor.d.ts +0 -22
  44. package/lib/client/watched/processors/OnChangeQueryProcessor.js +1 -82
  45. package/lib/client/watched/processors/OnChangeQueryProcessor.js.map +1 -1
  46. package/lib/db/DBAdapter.d.ts +72 -154
  47. package/lib/db/DBAdapter.js +70 -108
  48. package/lib/db/DBAdapter.js.map +1 -1
  49. package/lib/db/QueryResult.d.ts +104 -0
  50. package/lib/db/QueryResult.js +96 -0
  51. package/lib/db/QueryResult.js.map +1 -0
  52. package/lib/db/crud/SyncProgress.d.ts +1 -13
  53. package/lib/db/crud/SyncProgress.js +1 -62
  54. package/lib/db/crud/SyncProgress.js.map +1 -1
  55. package/lib/db/crud/SyncStatus.d.ts +32 -66
  56. package/lib/db/crud/SyncStatus.js +1 -253
  57. package/lib/db/crud/SyncStatus.js.map +1 -1
  58. package/lib/db/schema/Column.d.ts +0 -7
  59. package/lib/db/schema/Column.js +0 -7
  60. package/lib/db/schema/Column.js.map +1 -1
  61. package/lib/db/schema/Index.d.ts +2 -6
  62. package/lib/db/schema/Index.js +1 -4
  63. package/lib/db/schema/Index.js.map +1 -1
  64. package/lib/db/schema/IndexedColumn.d.ts +2 -6
  65. package/lib/db/schema/IndexedColumn.js +1 -4
  66. package/lib/db/schema/IndexedColumn.js.map +1 -1
  67. package/lib/db/schema/Schema.d.ts +4 -28
  68. package/lib/db/schema/Schema.js.map +1 -1
  69. package/lib/db/schema/Table.d.ts +50 -96
  70. package/lib/db/schema/Table.js +83 -91
  71. package/lib/db/schema/Table.js.map +1 -1
  72. package/lib/index.d.ts +5 -21
  73. package/lib/index.js +5 -22
  74. package/lib/index.js.map +1 -1
  75. package/lib/utils/BaseObserver.d.ts +1 -1
  76. package/lib/utils/BaseObserver.js +1 -1
  77. package/lib/utils/Logger.d.ts +52 -23
  78. package/lib/utils/Logger.js +35 -33
  79. package/lib/utils/Logger.js.map +1 -1
  80. package/lib/utils/MetaBaseObserver.d.ts +11 -11
  81. package/lib/utils/MetaBaseObserver.js +1 -50
  82. package/lib/utils/MetaBaseObserver.js.map +1 -1
  83. package/lib/utils/mutex.d.ts +3 -53
  84. package/lib/utils/mutex.js +1 -156
  85. package/lib/utils/mutex.js.map +1 -1
  86. package/package.json +8 -45
  87. package/src/attachments/AttachmentContext.ts +11 -10
  88. package/src/attachments/AttachmentQueue.ts +15 -14
  89. package/src/attachments/AttachmentService.ts +7 -6
  90. package/src/attachments/Schema.ts +2 -2
  91. package/src/attachments/SyncingService.ts +23 -9
  92. package/src/client/CommonPowerSyncDatabase.ts +540 -0
  93. package/src/client/SQLOpenFactory.ts +38 -22
  94. package/src/client/compilableQueryWatch.ts +3 -4
  95. package/src/client/connection/PowerSyncBackendConnector.ts +3 -3
  96. package/src/client/runOnSchemaChange.ts +2 -2
  97. package/src/client/sync/bucket/CrudEntry.ts +4 -104
  98. package/src/client/sync/options.ts +77 -0
  99. package/src/client/sync/sync-streams.ts +1 -1
  100. package/src/client/triggers/TriggerManager.ts +10 -41
  101. package/src/client/watched/GetAllQuery.ts +3 -3
  102. package/src/client/watched/WatchedQuery.ts +2 -15
  103. package/src/client/watched/processors/DifferentialQueryProcessor.ts +0 -223
  104. package/src/client/watched/processors/OnChangeQueryProcessor.ts +0 -111
  105. package/src/db/DBAdapter.ts +141 -226
  106. package/src/db/QueryResult.ts +195 -0
  107. package/src/db/crud/SyncProgress.ts +2 -42
  108. package/src/db/crud/SyncStatus.ts +45 -220
  109. package/src/db/schema/Column.ts +0 -8
  110. package/src/db/schema/Index.ts +3 -6
  111. package/src/db/schema/IndexedColumn.ts +3 -6
  112. package/src/db/schema/Schema.ts +4 -4
  113. package/src/db/schema/Table.ts +111 -186
  114. package/src/index.ts +5 -21
  115. package/src/utils/BaseObserver.ts +1 -1
  116. package/src/utils/Logger.ts +80 -34
  117. package/src/utils/MetaBaseObserver.ts +14 -60
  118. package/src/utils/mutex.ts +4 -201
  119. package/dist/bundle.cjs +0 -14390
  120. package/dist/bundle.cjs.map +0 -1
  121. package/dist/bundle.mjs +0 -14309
  122. package/dist/bundle.mjs.map +0 -1
  123. package/dist/bundle.node.cjs +0 -12021
  124. package/dist/bundle.node.cjs.map +0 -1
  125. package/dist/bundle.node.mjs +0 -11940
  126. package/dist/bundle.node.mjs.map +0 -1
  127. package/dist/index.d.cts +0 -4651
  128. package/legacy/sync_protocol.d.ts +0 -103
  129. package/lib/client/AbstractPowerSyncDatabase.js +0 -990
  130. package/lib/client/AbstractPowerSyncDatabase.js.map +0 -1
  131. package/lib/client/AbstractPowerSyncOpenFactory.d.ts +0 -28
  132. package/lib/client/AbstractPowerSyncOpenFactory.js +0 -28
  133. package/lib/client/AbstractPowerSyncOpenFactory.js.map +0 -1
  134. package/lib/client/ConnectionManager.d.ts +0 -115
  135. package/lib/client/ConnectionManager.js +0 -294
  136. package/lib/client/ConnectionManager.js.map +0 -1
  137. package/lib/client/CustomQuery.d.ts +0 -22
  138. package/lib/client/CustomQuery.js +0 -43
  139. package/lib/client/CustomQuery.js.map +0 -1
  140. package/lib/client/constants.d.ts +0 -4
  141. package/lib/client/constants.js +0 -5
  142. package/lib/client/constants.js.map +0 -1
  143. package/lib/client/sync/bucket/BucketStorageAdapter.d.ts +0 -56
  144. package/lib/client/sync/bucket/BucketStorageAdapter.js +0 -29
  145. package/lib/client/sync/bucket/BucketStorageAdapter.js.map +0 -1
  146. package/lib/client/sync/bucket/SqliteBucketStorage.d.ts +0 -37
  147. package/lib/client/sync/bucket/SqliteBucketStorage.js +0 -165
  148. package/lib/client/sync/bucket/SqliteBucketStorage.js.map +0 -1
  149. package/lib/client/sync/stream/AbstractRemote.d.ts +0 -180
  150. package/lib/client/sync/stream/AbstractRemote.js +0 -505
  151. package/lib/client/sync/stream/AbstractRemote.js.map +0 -1
  152. package/lib/client/sync/stream/AbstractStreamingSyncImplementation.d.ts +0 -265
  153. package/lib/client/sync/stream/AbstractStreamingSyncImplementation.js +0 -705
  154. package/lib/client/sync/stream/AbstractStreamingSyncImplementation.js.map +0 -1
  155. package/lib/client/sync/stream/WebsocketClientTransport.d.ts +0 -15
  156. package/lib/client/sync/stream/WebsocketClientTransport.js +0 -62
  157. package/lib/client/sync/stream/WebsocketClientTransport.js.map +0 -1
  158. package/lib/client/sync/stream/core-instruction.d.ts +0 -77
  159. package/lib/client/sync/stream/core-instruction.js +0 -30
  160. package/lib/client/sync/stream/core-instruction.js.map +0 -1
  161. package/lib/client/triggers/MemoryTriggerClaimManager.d.ts +0 -6
  162. package/lib/client/triggers/MemoryTriggerClaimManager.js +0 -21
  163. package/lib/client/triggers/MemoryTriggerClaimManager.js.map +0 -1
  164. package/lib/client/triggers/TriggerManagerImpl.d.ts +0 -39
  165. package/lib/client/triggers/TriggerManagerImpl.js +0 -410
  166. package/lib/client/triggers/TriggerManagerImpl.js.map +0 -1
  167. package/lib/client/watched/processors/AbstractQueryProcessor.d.ts +0 -68
  168. package/lib/client/watched/processors/AbstractQueryProcessor.js +0 -151
  169. package/lib/client/watched/processors/AbstractQueryProcessor.js.map +0 -1
  170. package/lib/db/ConnectionClosedError.d.ts +0 -12
  171. package/lib/db/ConnectionClosedError.js +0 -23
  172. package/lib/db/ConnectionClosedError.js.map +0 -1
  173. package/lib/db/schema/TableV2.d.ts +0 -11
  174. package/lib/db/schema/TableV2.js +0 -11
  175. package/lib/db/schema/TableV2.js.map +0 -1
  176. package/lib/utils/AbortOperation.d.ts +0 -11
  177. package/lib/utils/AbortOperation.js +0 -21
  178. package/lib/utils/AbortOperation.js.map +0 -1
  179. package/lib/utils/ControlledExecutor.d.ts +0 -31
  180. package/lib/utils/ControlledExecutor.js +0 -54
  181. package/lib/utils/ControlledExecutor.js.map +0 -1
  182. package/lib/utils/async.d.ts +0 -46
  183. package/lib/utils/async.js +0 -147
  184. package/lib/utils/async.js.map +0 -1
  185. package/lib/utils/compatibility.d.ts +0 -8
  186. package/lib/utils/compatibility.js +0 -9
  187. package/lib/utils/compatibility.js.map +0 -1
  188. package/lib/utils/parseQuery.d.ts +0 -12
  189. package/lib/utils/parseQuery.js +0 -20
  190. package/lib/utils/parseQuery.js.map +0 -1
  191. package/lib/utils/queue.d.ts +0 -16
  192. package/lib/utils/queue.js +0 -42
  193. package/lib/utils/queue.js.map +0 -1
  194. package/lib/utils/stream_transform.d.ts +0 -41
  195. package/lib/utils/stream_transform.js +0 -211
  196. package/lib/utils/stream_transform.js.map +0 -1
  197. package/src/client/AbstractPowerSyncDatabase.ts +0 -1408
  198. package/src/client/AbstractPowerSyncOpenFactory.ts +0 -45
  199. package/src/client/ConnectionManager.ts +0 -405
  200. package/src/client/CustomQuery.ts +0 -56
  201. package/src/client/constants.ts +0 -4
  202. package/src/client/sync/bucket/BucketStorageAdapter.ts +0 -65
  203. package/src/client/sync/bucket/SqliteBucketStorage.ts +0 -202
  204. package/src/client/sync/stream/AbstractRemote.ts +0 -644
  205. package/src/client/sync/stream/AbstractStreamingSyncImplementation.ts +0 -970
  206. package/src/client/sync/stream/WebsocketClientTransport.ts +0 -82
  207. package/src/client/sync/stream/core-instruction.ts +0 -109
  208. package/src/client/triggers/MemoryTriggerClaimManager.ts +0 -25
  209. package/src/client/triggers/TriggerManagerImpl.ts +0 -501
  210. package/src/client/watched/processors/AbstractQueryProcessor.ts +0 -226
  211. package/src/db/ConnectionClosedError.ts +0 -25
  212. package/src/db/schema/TableV2.ts +0 -11
  213. package/src/utils/AbortOperation.ts +0 -19
  214. package/src/utils/ControlledExecutor.ts +0 -78
  215. package/src/utils/async.ts +0 -185
  216. package/src/utils/compatibility.ts +0 -9
  217. package/src/utils/parseQuery.ts +0 -31
  218. package/src/utils/queue.ts +0 -48
  219. package/src/utils/stream_transform.ts +0 -260
@@ -1,11 +1,4 @@
1
1
  import { WatchCompatibleQuery, WatchedQuery, WatchedQueryOptions } from '../WatchedQuery.js';
2
- import {
3
- AbstractQueryProcessor,
4
- AbstractQueryProcessorOptions,
5
- LinkQueryOptions,
6
- MutableWatchedQueryState
7
- } from './AbstractQueryProcessor.js';
8
- import { WatchedQueryComparator } from './comparators.js';
9
2
 
10
3
  /**
11
4
  * Settings for {@link WatchedQuery} instances created via {@link Query#watch}.
@@ -22,107 +15,3 @@ export interface WatchedQuerySettings<DataType> extends WatchedQueryOptions {
22
15
  * @public
23
16
  */
24
17
  export type StandardWatchedQuery<DataType> = WatchedQuery<DataType, WatchedQuerySettings<DataType>>;
25
-
26
- /**
27
- * @internal
28
- */
29
- export interface OnChangeQueryProcessorOptions<Data> extends AbstractQueryProcessorOptions<
30
- Data,
31
- WatchedQuerySettings<Data>
32
- > {
33
- comparator?: WatchedQueryComparator<Data>;
34
- }
35
-
36
- /**
37
- * Uses the PowerSync onChange event to trigger watched queries.
38
- * Results are emitted on every change of the relevant tables.
39
- * @internal
40
- */
41
- export class OnChangeQueryProcessor<Data> extends AbstractQueryProcessor<Data, WatchedQuerySettings<Data>> {
42
- constructor(protected options: OnChangeQueryProcessorOptions<Data>) {
43
- super(options);
44
- }
45
-
46
- /**
47
- * @returns If the sets are equal
48
- */
49
- protected checkEquality(current: Data, previous: Data): boolean {
50
- // Use the provided comparator if available. Assume values are unique if not available.
51
- return this.options.comparator?.checkEquality?.(current, previous) ?? false;
52
- }
53
-
54
- protected async linkQuery(options: LinkQueryOptions<Data>): Promise<void> {
55
- const { db, watchOptions } = this.options;
56
- const { abortSignal } = options;
57
-
58
- const compiledQuery = watchOptions.query.compile();
59
- const tables = await db.resolveTables(compiledQuery.sql, compiledQuery.parameters as any[], {
60
- tables: options.settings.triggerOnTables
61
- });
62
-
63
- db.onChangeWithCallback(
64
- {
65
- onChange: async () => {
66
- if (this.closed || abortSignal.aborted) {
67
- return;
68
- }
69
- // This fires for each change of the relevant tables
70
- try {
71
- if (this.reportFetching && !this.state.isFetching) {
72
- await this.updateState({ isFetching: true });
73
- }
74
-
75
- const partialStateUpdate: Partial<MutableWatchedQueryState<Data>> & { data?: Data } = {};
76
-
77
- // Always run the query if an underlying table has changed
78
- const result = await watchOptions.query.execute({
79
- sql: compiledQuery.sql,
80
- // Allows casting from ReadOnlyArray[unknown] to Array<unknown>
81
- // This allows simpler compatibility with PowerSync queries
82
- parameters: [...compiledQuery.parameters],
83
- db: this.options.db
84
- });
85
-
86
- if (abortSignal.aborted) {
87
- return;
88
- }
89
-
90
- if (this.reportFetching) {
91
- partialStateUpdate.isFetching = false;
92
- }
93
-
94
- if (this.state.isLoading) {
95
- partialStateUpdate.isLoading = false;
96
- }
97
-
98
- // Check if the result has changed
99
- if (!this.checkEquality(result, this.state.data)) {
100
- Object.assign(partialStateUpdate, {
101
- data: result
102
- });
103
- }
104
-
105
- if (this.state.error) {
106
- partialStateUpdate.error = null;
107
- }
108
-
109
- if (Object.keys(partialStateUpdate).length > 0) {
110
- await this.updateState(partialStateUpdate);
111
- }
112
- } catch (error: any) {
113
- await this.updateState({ error });
114
- }
115
- },
116
- onError: async (error) => {
117
- await this.updateState({ error });
118
- }
119
- },
120
- {
121
- signal: abortSignal,
122
- tables,
123
- throttleMs: watchOptions.throttleMs,
124
- triggerImmediate: true // used to emit the initial state
125
- }
126
- );
127
- }
128
- }
@@ -3,52 +3,43 @@
3
3
  * different SQLite DB implementations.
4
4
  */
5
5
 
6
- import { BaseListener, BaseObserverInterface } from '../utils/BaseObserver.js';
6
+ import { BaseListener, BaseObserver } from '../utils/BaseObserver.js';
7
+ import {
8
+ QueryResult,
9
+ queryResultFromRaw,
10
+ queryResultWithoutRows,
11
+ RawQueryResult,
12
+ SqliteRecord
13
+ } from './QueryResult.js';
7
14
 
8
15
  /**
9
- * TODO most of these types could be exported to a common `types` package
10
- * which is used by the DB adapter libraries as well.
11
- */
12
-
13
- /**
14
- * Object returned by SQL Query executions.
15
- *
16
16
  * @public
17
17
  */
18
- export type QueryResult = {
19
- /** Represents the auto-generated row id if applicable. */
20
- insertId?: number;
18
+ export interface DBGetUtils {
21
19
  /**
22
- * Number of affected rows reported by SQLite for a write query.
20
+ * Execute a read-only query and return results.
23
21
  *
24
- * When using the default client-side [JSON-based view system](https://docs.powersync.com/architecture/client-architecture#client-side-schema-and-sqlite-database-structure),
25
- * `rowsAffected` may be `0` for successful `UPDATE` and `DELETE` statements.
26
- * Use a `RETURNING` clause and inspect `rows` when you need to confirm which rows changed.
22
+ * @param sql - The SQL query to execute
23
+ * @param parameters - Optional array of parameters to bind to the query
24
+ * @returns An array of results
27
25
  */
28
- rowsAffected: number;
29
- /** if status is undefined or 0 this object will contain the query results */
30
- rows?: {
31
- /** Raw array with all dataset */
32
- _array: any[];
33
- /** The length of the dataset */
34
- length: number;
35
- /** A convenience function to acess the index based the row object
36
- * @param idx - the row index
37
- * @returns the row structure identified by column names
38
- */
39
- item: (idx: number) => any;
40
- };
41
- };
42
-
43
- /**
44
- * @public
45
- */
46
- export interface DBGetUtils {
47
- /** Execute a read-only query and return results. */
48
26
  getAll<T>(sql: string, parameters?: any[]): Promise<T[]>;
49
- /** Execute a read-only query and return the first result, or null if the ResultSet is empty. */
27
+ /**
28
+ * Execute a read-only query and return the first result, or null if the ResultSet is empty.
29
+ *
30
+ * @param sql - The SQL query to execute
31
+ * @param parameters - Optional array of parameters to bind to the query
32
+ * @returns The first result if found, or null if no results are returned
33
+ */
50
34
  getOptional<T>(sql: string, parameters?: any[]): Promise<T | null>;
51
- /** Execute a read-only query and return the first result, error if the ResultSet is empty. */
35
+ /**
36
+ * Execute a read-only query and return the first result, error if the ResultSet is empty.
37
+ *
38
+ * @param sql - The SQL query to execute
39
+ * @param parameters - Optional array of parameters to bind to the query
40
+ * @returns The first result matching the query
41
+ * @throws Error if no rows are returned
42
+ */
52
43
  get<T>(sql: string, parameters?: any[]): Promise<T>;
53
44
  }
54
45
 
@@ -56,97 +47,91 @@ export interface DBGetUtils {
56
47
  * @public
57
48
  */
58
49
  export interface SqlExecutor {
59
- /** Execute a single write statement. */
60
- execute: (query: string, params?: any[] | undefined) => Promise<QueryResult>;
61
50
  /**
62
- * Execute a single write statement and return raw results.
63
- * Unlike `execute`, which returns an object with structured key-value pairs,
64
- * `executeRaw` returns a nested array of raw values, where each row is
65
- * represented as an array of column values without field names.
66
- *
67
- * Example result:
68
- *
69
- * ```JavaScript
70
- * [ [ '1', 'list 1', '33', 'Post content', '1' ] ]
71
- * ```
51
+ * Execute a SQL write (INSERT/UPDATE/DELETE) query
52
+ * and optionally return results.
72
53
  *
73
- * Where as `execute`'s `rows._array` would have been:
54
+ * When using the default client-side [JSON-based view system](https://docs.powersync.com/architecture/client-architecture#client-side-schema-and-sqlite-database-structure),
55
+ * the returned result's `rowsAffected` may be `0` for successful `UPDATE` and `DELETE` statements.
56
+ * Use a `RETURNING` clause and inspect `result.rows` when you need to confirm which rows changed.
74
57
  *
75
- * ```JavaScript
76
- * [ { id: '33', name: 'list 1', content: 'Post content', list_id: '1' } ]
77
- * ```
58
+ * @param sql - The SQL query to execute
59
+ * @param parameters - Optional array of parameters to bind to the query
60
+ * @returns The query result as an object with structured key-value pairs
78
61
  */
79
- executeRaw: (query: string, params?: any[] | undefined) => Promise<any[][]>;
62
+ execute: <T = SqliteRecord>(query: string, params?: any[] | undefined) => Promise<QueryResult<T>>;
80
63
 
81
- executeBatch: (query: string, params?: any[][]) => Promise<QueryResult>;
82
- }
64
+ /**
65
+ * Execute a SQL write (INSERT/UPDATE/DELETE) query directly on the database without any PowerSync processing.
66
+ * This bypasses certain PowerSync abstractions and is useful for accessing the raw database results.
67
+ *
68
+ * @param sql - The SQL query to execute
69
+ * @param parameters - Optional array of parameters to bind to the query
70
+ * @returns The {@link RawQueryResult} representing each row as an array.
71
+ */
72
+ executeRaw: (query: string, params?: any[] | undefined) => Promise<RawQueryResult>;
83
73
 
84
- /**
85
- * @public
86
- */
87
- export interface LockContext extends SqlExecutor, DBGetUtils {
88
74
  /**
89
- * How the connection has been opened.
75
+ * Execute a write query (INSERT/UPDATE/DELETE) multiple times with each parameter set
76
+ * and optionally return results.
77
+ * This is faster than executing separately with each parameter set.
90
78
  *
91
- * `writer` indicates that the lock context is capable of writing to the database.
92
- * `queryOnly` indicates that the lock context has been opened in a readwrite mode, but a `PRAGMA query_only = TRUE`
93
- * disabled writes.
94
- * `readOnly` indicates that the lock context has been opened by passing `SQLITE_OPEN_READONLY` to `sqlite3_open_v2`.
79
+ * @param sql - The SQL query to execute
80
+ * @param parameters - Optional 2D array of parameter sets, where each inner array is a set of parameters for one execution
81
+ * @returns The query result
95
82
  */
96
- connectionType?: 'writer' | 'queryOnly' | 'readOnly';
83
+ executeBatch: (query: string, params?: any[][]) => Promise<QueryResult<never>>;
97
84
  }
98
85
 
99
86
  /**
100
- * Implements {@link DBGetUtils} on a {@link SqlExecutor}.
101
- *
102
- * @internal
87
+ * @public
103
88
  */
104
- export function DBGetUtilsDefaultMixin<TBase extends new (...args: any[]) => Omit<SqlExecutor, 'executeBatch'>>(
105
- Base: TBase
106
- ) {
107
- return class extends Base implements DBGetUtils, SqlExecutor {
108
- async getAll<T>(sql: string, parameters?: any[]): Promise<T[]> {
109
- const res = await this.execute(sql, parameters);
110
- return res.rows?._array ?? [];
111
- }
89
+ export abstract class LockContext implements SqlExecutor, DBGetUtils {
90
+ abstract executeRaw<T>(query: string, params?: any[] | undefined): Promise<RawQueryResult>;
112
91
 
113
- async getOptional<T>(sql: string, parameters?: any[]): Promise<T | null> {
114
- const res = await this.execute(sql, parameters);
115
- return res.rows?.item(0) ?? null;
92
+ async getAll<T>(sql: string, parameters?: any[]): Promise<T[]> {
93
+ const rs = await this.execute<T>(sql, parameters);
94
+ return Array.from(rs);
95
+ }
96
+
97
+ async getOptional<T>(sql: string, parameters?: any[]): Promise<T | null> {
98
+ const { array } = await this.execute<T>(sql, parameters);
99
+ if (array.length > 0) {
100
+ return array[0];
116
101
  }
117
102
 
118
- async get<T>(sql: string, parameters?: any[]): Promise<T> {
119
- const res = await this.execute(sql, parameters);
120
- const first = res.rows?.item(0);
121
- if (!first) {
122
- throw new Error('Result set is empty');
123
- }
124
- return first;
103
+ return null;
104
+ }
105
+
106
+ async get<T>(sql: string, parameters?: any[]): Promise<T> {
107
+ const row = await this.getOptional<T>(sql, parameters);
108
+ if (row == null) {
109
+ throw new Error('Result set is empty');
125
110
  }
126
111
 
127
- async executeBatch(query: string, params: any[][] = []): Promise<QueryResult> {
128
- // If this context can run batch statements natively, use that.
129
- // @ts-ignore
130
- if (super.executeBatch) {
131
- // @ts-ignore
132
- return super.executeBatch(query, params);
133
- }
112
+ return row;
113
+ }
134
114
 
135
- // Emulate executeBatch by running statements individually.
136
- let lastInsertId: number | undefined;
137
- let rowsAffected = 0;
138
- for (const set of params) {
139
- const result = await this.execute(query, set);
140
- lastInsertId = result.insertId;
141
- rowsAffected += result.rowsAffected;
142
- }
115
+ async execute<T = SqliteRecord>(query: string, params?: any[] | undefined): Promise<QueryResult<T>> {
116
+ const raw = await this.executeRaw(query, params);
117
+ return queryResultFromRaw(raw);
118
+ }
143
119
 
144
- return {
145
- rowsAffected,
146
- insertId: lastInsertId
147
- };
120
+ async executeBatch(query: string, params: any[][] = []): Promise<QueryResult<never>> {
121
+ // Emulate executeBatch by running statements individually.
122
+ let lastInsertId: number | undefined;
123
+ let rowsAffected = 0;
124
+ for (const set of params) {
125
+ const result = await this.execute(query, set);
126
+ lastInsertId = result.insertId;
127
+ rowsAffected += result.rowsAffected ?? 0;
148
128
  }
149
- };
129
+
130
+ return queryResultWithoutRows({
131
+ rowsAffected,
132
+ insertId: lastInsertId
133
+ });
134
+ }
150
135
  }
151
136
 
152
137
  /**
@@ -154,46 +139,16 @@ export function DBGetUtilsDefaultMixin<TBase extends new (...args: any[]) => Omi
154
139
  */
155
140
  export interface Transaction extends LockContext {
156
141
  /** Commit multiple changes to the local DB using the Transaction context. */
157
- commit: () => Promise<QueryResult>;
142
+ commit: () => Promise<void>;
158
143
  /** Roll back multiple attempted changes using the Transaction context. */
159
- rollback: () => Promise<QueryResult>;
160
- }
161
-
162
- /**
163
- * Update table operation numbers from SQLite
164
- *
165
- * @public
166
- */
167
- export enum RowUpdateType {
168
- SQLITE_INSERT = 18,
169
- SQLITE_DELETE = 9,
170
- SQLITE_UPDATE = 23
171
- }
172
-
173
- /**
174
- * @public
175
- */
176
- export interface TableUpdateOperation {
177
- opType: RowUpdateType;
178
- rowId: number;
179
- }
180
- /**
181
- * Notification of an update to one or more tables, for the purpose of realtime change notifications.
182
- *
183
- * @public
184
- */
185
- export interface UpdateNotification extends TableUpdateOperation {
186
- table: string;
144
+ rollback: () => Promise<void>;
187
145
  }
188
146
 
189
147
  /**
190
148
  * @public
191
149
  */
192
150
  export interface BatchedUpdateNotification {
193
- // TODO (breaking change): Normalize to only including tables
194
- rawUpdates: UpdateNotification[];
195
151
  tables: string[];
196
- groupedUpdates: Record<string, TableUpdateOperation[]>;
197
152
  }
198
153
 
199
154
  /**
@@ -206,7 +161,7 @@ export interface DBAdapterListener extends BaseListener {
206
161
  * without the need for a major version bump
207
162
  * The DB adapter can also batch update notifications if supported.
208
163
  */
209
- tablesUpdated: (updateNotification: BatchedUpdateNotification | UpdateNotification) => void;
164
+ tablesUpdated: (updateNotification: BatchedUpdateNotification) => void;
210
165
  }
211
166
 
212
167
  /**
@@ -219,116 +174,92 @@ export interface DBLockOptions {
219
174
  /**
220
175
  * @public
221
176
  */
222
- export interface ConnectionPool extends BaseObserverInterface<DBAdapterListener> {
223
- name: string;
224
- close: () => void | Promise<void>;
225
- readLock: <T>(fn: (tx: LockContext) => Promise<T>, options?: DBLockOptions) => Promise<T>;
226
- writeLock: <T>(fn: (tx: LockContext) => Promise<T>, options?: DBLockOptions) => Promise<T>;
177
+ export abstract class DBAdapter extends BaseObserver<DBAdapterListener> implements SqlExecutor, DBGetUtils {
178
+ abstract get name(): string;
179
+
180
+ abstract close(): void | Promise<void>;
181
+
182
+ abstract readLock<T>(fn: (tx: LockContext) => Promise<T>, options?: DBLockOptions): Promise<T>;
183
+ abstract writeLock<T>(fn: (tx: LockContext) => Promise<T>, options?: DBLockOptions): Promise<T>;
227
184
 
228
185
  /**
229
186
  * This method refreshes the schema information across all connections. This is for advanced use cases, and should generally not be needed.
230
187
  */
231
- refreshSchema: () => Promise<void>;
232
- }
188
+ abstract refreshSchema(): Promise<void>;
233
189
 
234
- /**
235
- * @public
236
- */
237
- export interface DBAdapter extends ConnectionPool, SqlExecutor, DBGetUtils {
238
- readTransaction: <T>(fn: (tx: Transaction) => Promise<T>, options?: DBLockOptions) => Promise<T>;
239
- writeTransaction: <T>(fn: (tx: Transaction) => Promise<T>, options?: DBLockOptions) => Promise<T>;
240
- }
241
-
242
- /**
243
- * A mixin to implement {@link DBAdapter} by delegating to {@link ConnectionPool#readLock} and
244
- * {@link ConnectionPool#writeLock}.
245
- *
246
- * @internal
247
- */
248
- export function DBAdapterDefaultMixin<TBase extends new (...args: any[]) => ConnectionPool>(Base: TBase) {
249
- return class extends Base implements DBAdapter {
250
- readTransaction<T>(fn: (tx: Transaction) => Promise<T>, options?: DBLockOptions): Promise<T> {
251
- return this.readLock((ctx) => TransactionImplementation.runWith(ctx, fn), options);
252
- }
190
+ readTransaction<T>(fn: (tx: Transaction) => Promise<T>, options?: DBLockOptions): Promise<T> {
191
+ return this.readLock((ctx) => TransactionImplementation.runWith(ctx, fn), options);
192
+ }
253
193
 
254
- writeTransaction<T>(fn: (tx: Transaction) => Promise<T>, options?: DBLockOptions): Promise<T> {
255
- return this.writeLock((ctx) => TransactionImplementation.runWith(ctx, fn), options);
256
- }
194
+ writeTransaction<T>(fn: (tx: Transaction) => Promise<T>, options?: DBLockOptions): Promise<T> {
195
+ return this.writeLock((ctx) => TransactionImplementation.runWith(ctx, fn), options);
196
+ }
257
197
 
258
- getAll<T>(sql: string, parameters?: any[]): Promise<T[]> {
259
- return this.readLock((ctx) => ctx.getAll(sql, parameters));
260
- }
198
+ getAll<T>(sql: string, parameters?: any[]): Promise<T[]> {
199
+ return this.readLock((ctx) => ctx.getAll(sql, parameters));
200
+ }
261
201
 
262
- getOptional<T>(sql: string, parameters?: any[]): Promise<T | null> {
263
- return this.readLock((ctx) => ctx.getOptional(sql, parameters));
264
- }
202
+ getOptional<T>(sql: string, parameters?: any[]): Promise<T | null> {
203
+ return this.readLock((ctx) => ctx.getOptional(sql, parameters));
204
+ }
265
205
 
266
- get<T>(sql: string, parameters?: any[]): Promise<T> {
267
- return this.readLock((ctx) => ctx.get(sql, parameters));
268
- }
206
+ get<T>(sql: string, parameters?: any[]): Promise<T> {
207
+ return this.readLock((ctx) => ctx.get(sql, parameters));
208
+ }
269
209
 
270
- execute(query: string, params?: any[]): Promise<QueryResult> {
271
- return this.writeLock((ctx) => ctx.execute(query, params));
272
- }
210
+ execute<T>(query: string, params?: any[]): Promise<QueryResult<T>> {
211
+ return this.writeLock((ctx) => ctx.execute(query, params));
212
+ }
273
213
 
274
- executeRaw(query: string, params?: any[]): Promise<any[][]> {
275
- return this.writeLock((ctx) => ctx.executeRaw(query, params));
276
- }
214
+ executeRaw(query: string, params?: any[]): Promise<RawQueryResult> {
215
+ return this.writeLock((ctx) => ctx.executeRaw(query, params));
216
+ }
277
217
 
278
- executeBatch(query: string, params?: any[][]): Promise<QueryResult> {
279
- return this.writeTransaction((tx) => tx.executeBatch(query, params));
280
- }
281
- };
218
+ executeBatch(query: string, params?: any[][]): Promise<QueryResult<never>> {
219
+ return this.writeTransaction((tx) => tx.executeBatch(query, params));
220
+ }
282
221
  }
283
222
 
284
- class BaseTransaction implements SqlExecutor {
223
+ class TransactionImplementation extends LockContext {
285
224
  private finalized = false;
286
225
 
287
- constructor(private inner: SqlExecutor) {}
226
+ constructor(private inner: LockContext) {
227
+ super();
228
+ }
288
229
 
289
- async commit(): Promise<QueryResult> {
230
+ async commit(): Promise<void> {
290
231
  if (this.finalized) {
291
- return { rowsAffected: 0 };
232
+ return;
292
233
  }
293
234
  this.finalized = true;
294
- return this.inner.execute('COMMIT');
235
+ await this.inner.execute('COMMIT');
295
236
  }
296
237
 
297
- async rollback(): Promise<QueryResult> {
238
+ async rollback(): Promise<void> {
298
239
  if (this.finalized) {
299
- return { rowsAffected: 0 };
240
+ return;
300
241
  }
301
242
  this.finalized = true;
302
- return this.inner.execute('ROLLBACK');
243
+ await this.inner.execute('ROLLBACK');
303
244
  }
304
245
 
305
- execute(query: string, params?: any[] | undefined): Promise<QueryResult> {
246
+ execute<T>(query: string, params?: any[] | undefined): Promise<QueryResult<T>> {
306
247
  return this.inner.execute(query, params);
307
248
  }
308
249
 
309
- executeRaw(query: string, params?: any[] | undefined): Promise<any[][]> {
250
+ executeRaw(query: string, params?: any[] | undefined): Promise<RawQueryResult> {
310
251
  return this.inner.executeRaw(query, params);
311
252
  }
312
253
 
313
- executeBatch(query: string, params?: any[][]): Promise<QueryResult> {
254
+ executeBatch(query: string, params?: any[][]): Promise<QueryResult<never>> {
314
255
  return this.inner.executeBatch(query, params);
315
256
  }
316
- }
317
257
 
318
- class TransactionImplementation extends DBGetUtilsDefaultMixin(BaseTransaction) {
319
258
  static async runWith<T>(ctx: LockContext, fn: (tx: Transaction) => Promise<T>): Promise<T> {
320
259
  let tx = new TransactionImplementation(ctx);
321
260
 
322
- // For write transactions, use BEGIN IMMEDIATE to immediately obtain a write lock on the database (instead of doing
323
- // that on the first statement). If we have a genuine read-only connection, we also use BEGIN IMMEDIATE there: In
324
- // WAL mode, that ensures we pin the current state of the database (instead of the state at the first statement in
325
- // the transaction). But if we have a "fake" read-only connection implemented through `pragma query_only = true`, we
326
- // can't use this trick because it would attempt to lock the connection. So there, we use a regular `BEGIN`
327
- // statement.
328
- const useBeginImmediate = ctx.connectionType != 'queryOnly';
329
-
330
261
  try {
331
- await ctx.execute(useBeginImmediate ? 'BEGIN IMMEDIATE' : 'BEGIN');
262
+ await ctx.execute('BEGIN IMMEDIATE');
332
263
 
333
264
  const result = await fn(tx);
334
265
  await tx.commit();
@@ -344,19 +275,3 @@ class TransactionImplementation extends DBGetUtilsDefaultMixin(BaseTransaction)
344
275
  }
345
276
  }
346
277
  }
347
-
348
- /**
349
- * @internal
350
- */
351
- export function isBatchedUpdateNotification(
352
- update: BatchedUpdateNotification | UpdateNotification
353
- ): update is BatchedUpdateNotification {
354
- return 'tables' in update;
355
- }
356
-
357
- /**
358
- * @internal
359
- */
360
- export function extractTableUpdates(update: BatchedUpdateNotification | UpdateNotification) {
361
- return isBatchedUpdateNotification(update) ? update.tables : [update.table];
362
- }