@powersync/common 1.48.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.
- package/dist/bundle.cjs +148 -8
- package/dist/bundle.cjs.map +1 -1
- package/dist/bundle.mjs +147 -9
- package/dist/bundle.mjs.map +1 -1
- package/dist/bundle.node.cjs +148 -8
- package/dist/bundle.node.cjs.map +1 -1
- package/dist/bundle.node.mjs +147 -9
- package/dist/bundle.node.mjs.map +1 -1
- package/dist/index.d.cts +64 -12
- package/lib/client/triggers/TriggerManager.d.ts +13 -1
- package/lib/client/triggers/TriggerManagerImpl.d.ts +2 -2
- package/lib/client/triggers/TriggerManagerImpl.js +19 -7
- package/lib/client/triggers/TriggerManagerImpl.js.map +1 -1
- package/lib/db/DBAdapter.d.ts +48 -8
- package/lib/db/DBAdapter.js +126 -0
- package/lib/db/DBAdapter.js.map +1 -1
- package/package.json +1 -1
- package/src/client/triggers/TriggerManager.ts +15 -2
- package/src/client/triggers/TriggerManagerImpl.ts +18 -6
- package/src/db/DBAdapter.ts +160 -8
package/src/db/DBAdapter.ts
CHANGED
|
@@ -41,7 +41,7 @@ export interface DBGetUtils {
|
|
|
41
41
|
get<T>(sql: string, parameters?: any[]): Promise<T>;
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
export interface
|
|
44
|
+
export interface SqlExecutor {
|
|
45
45
|
/** Execute a single write statement. */
|
|
46
46
|
execute: (query: string, params?: any[] | undefined) => Promise<QueryResult>;
|
|
47
47
|
/**
|
|
@@ -59,6 +59,61 @@ export interface LockContext extends DBGetUtils {
|
|
|
59
59
|
* ```[ { id: '33', name: 'list 1', content: 'Post content', list_id: '1' } ]```
|
|
60
60
|
*/
|
|
61
61
|
executeRaw: (query: string, params?: any[] | undefined) => Promise<any[][]>;
|
|
62
|
+
|
|
63
|
+
executeBatch: (query: string, params?: any[][]) => Promise<QueryResult>;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export interface LockContext extends SqlExecutor, DBGetUtils {}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Implements {@link DBGetUtils} on a {@link SqlRunner}.
|
|
70
|
+
*/
|
|
71
|
+
export function DBGetUtilsDefaultMixin<TBase extends new (...args: any[]) => Omit<SqlExecutor, 'executeBatch'>>(
|
|
72
|
+
Base: TBase
|
|
73
|
+
) {
|
|
74
|
+
return class extends Base implements DBGetUtils, SqlExecutor {
|
|
75
|
+
async getAll<T>(sql: string, parameters?: any[]): Promise<T[]> {
|
|
76
|
+
const res = await this.execute(sql, parameters);
|
|
77
|
+
return res.rows?._array ?? [];
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async getOptional<T>(sql: string, parameters?: any[]): Promise<T | null> {
|
|
81
|
+
const res = await this.execute(sql, parameters);
|
|
82
|
+
return res.rows?.item(0) ?? null;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
async get<T>(sql: string, parameters?: any[]): Promise<T> {
|
|
86
|
+
const res = await this.execute(sql, parameters);
|
|
87
|
+
const first = res.rows?.item(0);
|
|
88
|
+
if (!first) {
|
|
89
|
+
throw new Error('Result set is empty');
|
|
90
|
+
}
|
|
91
|
+
return first;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
async executeBatch(query: string, params: any[][] = []): Promise<QueryResult> {
|
|
95
|
+
// If this context can run batch statements natively, use that.
|
|
96
|
+
// @ts-ignore
|
|
97
|
+
if (super.executeBatch) {
|
|
98
|
+
// @ts-ignore
|
|
99
|
+
return super.executeBatch(query, params);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Emulate executeBatch by running statements individually.
|
|
103
|
+
let lastInsertId: number | undefined;
|
|
104
|
+
let rowsAffected = 0;
|
|
105
|
+
for (const set of params) {
|
|
106
|
+
const result = await this.execute(query, set);
|
|
107
|
+
lastInsertId = result.insertId;
|
|
108
|
+
rowsAffected += result.rowsAffected;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return {
|
|
112
|
+
rowsAffected,
|
|
113
|
+
insertId: lastInsertId
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
};
|
|
62
117
|
}
|
|
63
118
|
|
|
64
119
|
export interface Transaction extends LockContext {
|
|
@@ -107,22 +162,119 @@ export interface DBLockOptions {
|
|
|
107
162
|
timeoutMs?: number;
|
|
108
163
|
}
|
|
109
164
|
|
|
110
|
-
export interface
|
|
111
|
-
close: () => void | Promise<void>;
|
|
112
|
-
execute: (query: string, params?: any[]) => Promise<QueryResult>;
|
|
113
|
-
executeRaw: (query: string, params?: any[]) => Promise<any[][]>;
|
|
114
|
-
executeBatch: (query: string, params?: any[][]) => Promise<QueryResult>;
|
|
165
|
+
export interface ConnectionPool extends BaseObserverInterface<DBAdapterListener> {
|
|
115
166
|
name: string;
|
|
167
|
+
close: () => void | Promise<void>;
|
|
116
168
|
readLock: <T>(fn: (tx: LockContext) => Promise<T>, options?: DBLockOptions) => Promise<T>;
|
|
117
|
-
readTransaction: <T>(fn: (tx: Transaction) => Promise<T>, options?: DBLockOptions) => Promise<T>;
|
|
118
169
|
writeLock: <T>(fn: (tx: LockContext) => Promise<T>, options?: DBLockOptions) => Promise<T>;
|
|
119
|
-
|
|
170
|
+
|
|
120
171
|
/**
|
|
121
172
|
* This method refreshes the schema information across all connections. This is for advanced use cases, and should generally not be needed.
|
|
122
173
|
*/
|
|
123
174
|
refreshSchema: () => Promise<void>;
|
|
124
175
|
}
|
|
125
176
|
|
|
177
|
+
export interface DBAdapter extends ConnectionPool, SqlExecutor, DBGetUtils {
|
|
178
|
+
readTransaction: <T>(fn: (tx: Transaction) => Promise<T>, options?: DBLockOptions) => Promise<T>;
|
|
179
|
+
writeTransaction: <T>(fn: (tx: Transaction) => Promise<T>, options?: DBLockOptions) => Promise<T>;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* A mixin to implement {@link DBAdapter} by delegating to {@link ConnectionPool.readLock} and
|
|
184
|
+
* {@link ConnectionPool.writeLock}.
|
|
185
|
+
*/
|
|
186
|
+
export function DBAdapterDefaultMixin<TBase extends new (...args: any[]) => ConnectionPool>(Base: TBase) {
|
|
187
|
+
return class extends Base implements DBAdapter {
|
|
188
|
+
readTransaction<T>(fn: (tx: Transaction) => Promise<T>, options?: DBLockOptions): Promise<T> {
|
|
189
|
+
return this.readLock((ctx) => TransactionImplementation.runWith(ctx, fn), options);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
writeTransaction<T>(fn: (tx: Transaction) => Promise<T>, options?: DBLockOptions): Promise<T> {
|
|
193
|
+
return this.writeLock((ctx) => TransactionImplementation.runWith(ctx, fn), options);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
getAll<T>(sql: string, parameters?: any[]): Promise<T[]> {
|
|
197
|
+
return this.readLock((ctx) => ctx.getAll(sql, parameters));
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
getOptional<T>(sql: string, parameters?: any[]): Promise<T | null> {
|
|
201
|
+
return this.readLock((ctx) => ctx.getOptional(sql, parameters));
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
get<T>(sql: string, parameters?: any[]): Promise<T> {
|
|
205
|
+
return this.readLock((ctx) => ctx.get(sql, parameters));
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
execute(query: string, params?: any[]): Promise<QueryResult> {
|
|
209
|
+
return this.writeLock((ctx) => ctx.execute(query, params));
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
executeRaw(query: string, params?: any[]): Promise<any[][]> {
|
|
213
|
+
return this.writeLock((ctx) => ctx.executeRaw(query, params));
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
executeBatch(query: string, params?: any[][]): Promise<QueryResult> {
|
|
217
|
+
return this.writeTransaction((tx) => tx.executeBatch(query, params));
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
class BaseTransaction implements SqlExecutor {
|
|
223
|
+
private finalized = false;
|
|
224
|
+
|
|
225
|
+
constructor(private inner: SqlExecutor) {}
|
|
226
|
+
|
|
227
|
+
async commit(): Promise<QueryResult> {
|
|
228
|
+
if (this.finalized) {
|
|
229
|
+
return { rowsAffected: 0 };
|
|
230
|
+
}
|
|
231
|
+
this.finalized = true;
|
|
232
|
+
return this.inner.execute('COMMIT');
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
async rollback(): Promise<QueryResult> {
|
|
236
|
+
if (this.finalized) {
|
|
237
|
+
return { rowsAffected: 0 };
|
|
238
|
+
}
|
|
239
|
+
this.finalized = true;
|
|
240
|
+
return this.inner.execute('ROLLBACK');
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
execute(query: string, params?: any[] | undefined): Promise<QueryResult> {
|
|
244
|
+
return this.inner.execute(query, params);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
executeRaw(query: string, params?: any[] | undefined): Promise<any[][]> {
|
|
248
|
+
return this.inner.executeRaw(query, params);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
executeBatch(query: string, params?: any[][]): Promise<QueryResult> {
|
|
252
|
+
return this.inner.executeBatch(query, params);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
class TransactionImplementation extends DBGetUtilsDefaultMixin(BaseTransaction) {
|
|
257
|
+
static async runWith<T>(ctx: LockContext, fn: (tx: Transaction) => Promise<T>): Promise<T> {
|
|
258
|
+
let tx = new TransactionImplementation(ctx);
|
|
259
|
+
|
|
260
|
+
try {
|
|
261
|
+
await ctx.execute('BEGIN IMMEDIATE');
|
|
262
|
+
|
|
263
|
+
const result = await fn(tx);
|
|
264
|
+
await tx.commit();
|
|
265
|
+
return result;
|
|
266
|
+
} catch (ex) {
|
|
267
|
+
try {
|
|
268
|
+
await tx.rollback();
|
|
269
|
+
} catch (ex2) {
|
|
270
|
+
// In rare cases, a rollback may fail.
|
|
271
|
+
// Safe to ignore.
|
|
272
|
+
}
|
|
273
|
+
throw ex;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
126
278
|
export function isBatchedUpdateNotification(
|
|
127
279
|
update: BatchedUpdateNotification | UpdateNotification
|
|
128
280
|
): update is BatchedUpdateNotification {
|