@powersync/web 0.0.0-dev-20240723112746 → 0.0.0-dev-20240726145618
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/README.md +25 -1
- package/lib/src/db/PowerSyncDatabase.d.ts +2 -2
- package/lib/src/db/PowerSyncDatabase.js +28 -32
- package/lib/src/db/adapters/AbstractWebPowerSyncDatabaseOpenFactory.js +1 -7
- package/lib/src/db/adapters/AbstractWebSQLOpenFactory.js +0 -2
- package/lib/src/db/adapters/SSRDBAdapter.js +48 -28
- package/lib/src/db/adapters/wa-sqlite/WASQLiteDBAdapter.d.ts +1 -0
- package/lib/src/db/adapters/wa-sqlite/WASQLiteDBAdapter.js +136 -100
- package/lib/src/db/adapters/wa-sqlite/WASQLiteOpenFactory.js +1 -4
- package/lib/src/db/adapters/web-sql-flags.js +3 -6
- package/lib/src/db/sync/SSRWebStreamingSyncImplementation.js +0 -2
- package/lib/src/db/sync/SharedWebStreamingSyncImplementation.js +95 -66
- package/lib/src/db/sync/WebRemote.d.ts +1 -5
- package/lib/src/db/sync/WebRemote.js +21 -29
- package/lib/src/shared/open-db.js +184 -153
- package/lib/src/worker/db/SharedWASQLiteDB.worker.js +23 -15
- package/lib/src/worker/db/WASQLiteDB.worker.js +10 -1
- package/lib/src/worker/sync/BroadcastLogger.js +19 -16
- package/lib/src/worker/sync/SharedSyncImplementation.js +115 -96
- package/lib/src/worker/sync/SharedSyncImplementation.worker.js +5 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +7 -13
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
# PowerSync SDK for Web
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
*[PowerSync](https://www.powersync.com) is a Postgres-SQLite sync layer, which helps developers to create local-first real-time reactive apps that work seamlessly both online and offline.*
|
|
8
8
|
|
|
9
9
|
This package (`packages/web`) is the PowerSync SDK for JavaScript Web clients. It is an extension of `packages/common`.
|
|
10
10
|
|
|
@@ -28,6 +28,30 @@ Install it in your app with:
|
|
|
28
28
|
npm install @journeyapps/wa-sqlite
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
+
## Polyfills
|
|
32
|
+
|
|
33
|
+
### WebSocket Connections: Buffer
|
|
34
|
+
|
|
35
|
+
Note: Beta Release - WebSockets are currently in a beta release. It should be safe to use in production if sufficient testing is done on the client side.
|
|
36
|
+
|
|
37
|
+
This SDK connects to a PowerSync instance via HTTP streams (enabled by default) or WebSockets. The WebSocket connection method requires `Buffer` to be available in the global scope. When multiple tabs are used the shared web worker will apply a polyfill in its own scope, but the `Buffer` class should be polyfills in the application for cases where multiple tabs are not supported.
|
|
38
|
+
|
|
39
|
+
Install a suitable Buffer implementation
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
npm install buffer
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Apply it in your application if not yet provided
|
|
46
|
+
|
|
47
|
+
```Javascript
|
|
48
|
+
import { Buffer } from 'buffer';
|
|
49
|
+
|
|
50
|
+
if (typeof self.Buffer == 'undefined') {
|
|
51
|
+
self.Buffer = Buffer;
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
31
55
|
## Webpack
|
|
32
56
|
|
|
33
57
|
See the [example Webpack config](https://github.com/powersync-ja/powersync-js/blob/main/demos/example-webpack/webpack.config.js) for details on polyfills and requirements.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type AbstractStreamingSyncImplementation, type
|
|
1
|
+
import { type AbstractStreamingSyncImplementation, type BucketStorageAdapter, type PowerSyncBackendConnector, type PowerSyncCloseOptions, type PowerSyncConnectionOptions, AbstractPowerSyncDatabase, DBAdapter, PowerSyncDatabaseOptions, PowerSyncDatabaseOptionsWithDBAdapter, PowerSyncDatabaseOptionsWithOpenFactory, PowerSyncDatabaseOptionsWithSettings } from '@powersync/common';
|
|
2
2
|
import { Mutex } from 'async-mutex';
|
|
3
3
|
import { WebSQLFlags } from './adapters/web-sql-flags';
|
|
4
4
|
export interface WebPowerSyncFlags extends WebSQLFlags {
|
|
@@ -42,7 +42,7 @@ export declare class PowerSyncDatabase extends AbstractPowerSyncDatabase {
|
|
|
42
42
|
constructor(options: WebPowerSyncDatabaseOptionsWithSettings);
|
|
43
43
|
constructor(options: WebPowerSyncDatabaseOptions);
|
|
44
44
|
_initialize(): Promise<void>;
|
|
45
|
-
protected openDBAdapter(options:
|
|
45
|
+
protected openDBAdapter(options: WebPowerSyncDatabaseOptionsWithSettings): DBAdapter;
|
|
46
46
|
/**
|
|
47
47
|
* Closes the database connection.
|
|
48
48
|
* By default the sync stream client is only disconnected if
|
|
@@ -1,21 +1,23 @@
|
|
|
1
|
-
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import { AbstractPowerSyncDatabase, DEFAULT_POWERSYNC_CLOSE_OPTIONS, SqliteBucketStorage } from '@powersync/common';
|
|
2
11
|
import { Mutex } from 'async-mutex';
|
|
3
|
-
import {
|
|
12
|
+
import { WASQLiteOpenFactory } from './adapters/wa-sqlite/WASQLiteOpenFactory';
|
|
13
|
+
import { DEFAULT_WEB_SQL_FLAGS, resolveWebSQLFlags } from './adapters/web-sql-flags';
|
|
4
14
|
import { SharedWebStreamingSyncImplementation } from './sync/SharedWebStreamingSyncImplementation';
|
|
5
15
|
import { SSRStreamingSyncImplementation } from './sync/SSRWebStreamingSyncImplementation';
|
|
16
|
+
import { WebRemote } from './sync/WebRemote';
|
|
6
17
|
import { WebStreamingSyncImplementation } from './sync/WebStreamingSyncImplementation';
|
|
7
|
-
|
|
8
|
-
import { DEFAULT_WEB_SQL_FLAGS, resolveWebSQLFlags } from './adapters/web-sql-flags';
|
|
9
|
-
export const DEFAULT_POWERSYNC_FLAGS = {
|
|
10
|
-
...DEFAULT_WEB_SQL_FLAGS,
|
|
11
|
-
externallyUnload: false
|
|
12
|
-
};
|
|
18
|
+
export const DEFAULT_POWERSYNC_FLAGS = Object.assign(Object.assign({}, DEFAULT_WEB_SQL_FLAGS), { externallyUnload: false });
|
|
13
19
|
export const resolveWebPowerSyncFlags = (flags) => {
|
|
14
|
-
return {
|
|
15
|
-
...DEFAULT_POWERSYNC_FLAGS,
|
|
16
|
-
...flags,
|
|
17
|
-
...resolveWebSQLFlags(flags)
|
|
18
|
-
};
|
|
20
|
+
return Object.assign(Object.assign(Object.assign({}, DEFAULT_POWERSYNC_FLAGS), flags), resolveWebSQLFlags(flags));
|
|
19
21
|
};
|
|
20
22
|
/**
|
|
21
23
|
* A PowerSync database which provides SQLite functionality
|
|
@@ -32,10 +34,6 @@ export const resolveWebPowerSyncFlags = (flags) => {
|
|
|
32
34
|
* ```
|
|
33
35
|
*/
|
|
34
36
|
export class PowerSyncDatabase extends AbstractPowerSyncDatabase {
|
|
35
|
-
options;
|
|
36
|
-
static SHARED_MUTEX = new Mutex();
|
|
37
|
-
unloadListener;
|
|
38
|
-
resolvedFlags;
|
|
39
37
|
constructor(options) {
|
|
40
38
|
super(options);
|
|
41
39
|
this.options = options;
|
|
@@ -45,9 +43,11 @@ export class PowerSyncDatabase extends AbstractPowerSyncDatabase {
|
|
|
45
43
|
window.addEventListener('unload', this.unloadListener);
|
|
46
44
|
}
|
|
47
45
|
}
|
|
48
|
-
|
|
46
|
+
_initialize() {
|
|
47
|
+
return __awaiter(this, void 0, void 0, function* () { });
|
|
48
|
+
}
|
|
49
49
|
openDBAdapter(options) {
|
|
50
|
-
const defaultFactory = new WASQLiteOpenFactory({
|
|
50
|
+
const defaultFactory = new WASQLiteOpenFactory(Object.assign(Object.assign({}, options.database), { flags: resolveWebPowerSyncFlags(options.flags) }));
|
|
51
51
|
return defaultFactory.openDB();
|
|
52
52
|
}
|
|
53
53
|
/**
|
|
@@ -56,12 +56,13 @@ export class PowerSyncDatabase extends AbstractPowerSyncDatabase {
|
|
|
56
56
|
* multiple tabs are not enabled.
|
|
57
57
|
*/
|
|
58
58
|
close(options = DEFAULT_POWERSYNC_CLOSE_OPTIONS) {
|
|
59
|
+
var _a;
|
|
59
60
|
if (this.unloadListener) {
|
|
60
61
|
window.removeEventListener('unload', this.unloadListener);
|
|
61
62
|
}
|
|
62
63
|
return super.close({
|
|
63
64
|
// Don't disconnect by default if multiple tabs are enabled
|
|
64
|
-
disconnect: options.disconnect
|
|
65
|
+
disconnect: (_a = options.disconnect) !== null && _a !== void 0 ? _a : !this.resolvedFlags.enableMultiTabs
|
|
65
66
|
});
|
|
66
67
|
}
|
|
67
68
|
connect(connector, options) {
|
|
@@ -71,7 +72,8 @@ export class PowerSyncDatabase extends AbstractPowerSyncDatabase {
|
|
|
71
72
|
* connection attempts.
|
|
72
73
|
*/
|
|
73
74
|
return this.runExclusive(() => {
|
|
74
|
-
|
|
75
|
+
var _a;
|
|
76
|
+
(_a = this.options.logger) === null || _a === void 0 ? void 0 : _a.debug('Attempting to connect to PowerSync instance');
|
|
75
77
|
return super.connect(connector, options);
|
|
76
78
|
});
|
|
77
79
|
}
|
|
@@ -86,17 +88,10 @@ export class PowerSyncDatabase extends AbstractPowerSyncDatabase {
|
|
|
86
88
|
}
|
|
87
89
|
generateSyncStreamImplementation(connector) {
|
|
88
90
|
const remote = new WebRemote(connector);
|
|
89
|
-
const syncOptions = {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
remote,
|
|
94
|
-
uploadCrud: async () => {
|
|
95
|
-
await this.waitForReady();
|
|
96
|
-
await connector.uploadData(this);
|
|
97
|
-
},
|
|
98
|
-
identifier: this.database.name
|
|
99
|
-
};
|
|
91
|
+
const syncOptions = Object.assign(Object.assign({}, this.options), { flags: this.resolvedFlags, adapter: this.bucketStorageAdapter, remote, uploadCrud: () => __awaiter(this, void 0, void 0, function* () {
|
|
92
|
+
yield this.waitForReady();
|
|
93
|
+
yield connector.uploadData(this);
|
|
94
|
+
}), identifier: this.database.name });
|
|
100
95
|
switch (true) {
|
|
101
96
|
case this.resolvedFlags.ssrMode:
|
|
102
97
|
return new SSRStreamingSyncImplementation(syncOptions);
|
|
@@ -115,3 +110,4 @@ export class PowerSyncDatabase extends AbstractPowerSyncDatabase {
|
|
|
115
110
|
}
|
|
116
111
|
}
|
|
117
112
|
}
|
|
113
|
+
PowerSyncDatabase.SHARED_MUTEX = new Mutex();
|
|
@@ -7,18 +7,12 @@ import { PowerSyncDatabase, resolveWebPowerSyncFlags } from '../../db/PowerSyncD
|
|
|
7
7
|
* empty query results in SSR which will allow for generating server partial views.
|
|
8
8
|
*/
|
|
9
9
|
export class AbstractWebPowerSyncDatabaseOpenFactory extends AbstractPowerSyncDatabaseOpenFactory {
|
|
10
|
-
options;
|
|
11
10
|
constructor(options) {
|
|
12
11
|
super(options);
|
|
13
12
|
this.options = options;
|
|
14
13
|
}
|
|
15
14
|
generateOptions() {
|
|
16
|
-
return {
|
|
17
|
-
...this.options,
|
|
18
|
-
database: this.openDB(),
|
|
19
|
-
schema: this.schema,
|
|
20
|
-
flags: resolveWebPowerSyncFlags(this.options.flags)
|
|
21
|
-
};
|
|
15
|
+
return Object.assign(Object.assign({}, this.options), { database: this.openDB(), schema: this.schema, flags: resolveWebPowerSyncFlags(this.options.flags) });
|
|
22
16
|
}
|
|
23
17
|
generateInstance(options) {
|
|
24
18
|
return new PowerSyncDatabase(options);
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { SSRDBAdapter } from './SSRDBAdapter';
|
|
2
2
|
import { isServerSide, resolveWebSQLFlags } from './web-sql-flags';
|
|
3
3
|
export class AbstractWebSQLOpenFactory {
|
|
4
|
-
options;
|
|
5
|
-
resolvedFlags;
|
|
6
4
|
constructor(options) {
|
|
7
5
|
this.options = options;
|
|
8
6
|
this.resolvedFlags = resolveWebSQLFlags(options.flags);
|
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
1
10
|
import { BaseObserver } from '@powersync/common';
|
|
2
11
|
import { Mutex } from 'async-mutex';
|
|
3
12
|
const MOCK_QUERY_RESPONSE = {
|
|
@@ -9,9 +18,6 @@ const MOCK_QUERY_RESPONSE = {
|
|
|
9
18
|
* server rendered views to initially generate scaffolding components
|
|
10
19
|
*/
|
|
11
20
|
export class SSRDBAdapter extends BaseObserver {
|
|
12
|
-
name;
|
|
13
|
-
readMutex;
|
|
14
|
-
writeMutex;
|
|
15
21
|
constructor() {
|
|
16
22
|
super();
|
|
17
23
|
this.name = 'SSR DB';
|
|
@@ -19,32 +25,50 @@ export class SSRDBAdapter extends BaseObserver {
|
|
|
19
25
|
this.writeMutex = new Mutex();
|
|
20
26
|
}
|
|
21
27
|
close() { }
|
|
22
|
-
|
|
23
|
-
return this
|
|
28
|
+
readLock(fn, options) {
|
|
29
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
30
|
+
return this.readMutex.runExclusive(() => fn(this));
|
|
31
|
+
});
|
|
24
32
|
}
|
|
25
|
-
|
|
26
|
-
return this
|
|
33
|
+
readTransaction(fn, options) {
|
|
34
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
35
|
+
return this.readLock(() => fn(this.generateMockTransactionContext()));
|
|
36
|
+
});
|
|
27
37
|
}
|
|
28
|
-
|
|
29
|
-
return this
|
|
38
|
+
writeLock(fn, options) {
|
|
39
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
40
|
+
return this.writeMutex.runExclusive(() => fn(this));
|
|
41
|
+
});
|
|
30
42
|
}
|
|
31
|
-
|
|
32
|
-
return this
|
|
43
|
+
writeTransaction(fn, options) {
|
|
44
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
45
|
+
return this.writeLock(() => fn(this.generateMockTransactionContext()));
|
|
46
|
+
});
|
|
33
47
|
}
|
|
34
|
-
|
|
35
|
-
return this
|
|
48
|
+
execute(query, params) {
|
|
49
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
50
|
+
return this.writeMutex.runExclusive(() => __awaiter(this, void 0, void 0, function* () { return MOCK_QUERY_RESPONSE; }));
|
|
51
|
+
});
|
|
36
52
|
}
|
|
37
|
-
|
|
38
|
-
return this
|
|
53
|
+
executeBatch(query, params) {
|
|
54
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
55
|
+
return this.writeMutex.runExclusive(() => __awaiter(this, void 0, void 0, function* () { return MOCK_QUERY_RESPONSE; }));
|
|
56
|
+
});
|
|
39
57
|
}
|
|
40
|
-
|
|
41
|
-
return
|
|
58
|
+
getAll(sql, parameters) {
|
|
59
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
60
|
+
return [];
|
|
61
|
+
});
|
|
42
62
|
}
|
|
43
|
-
|
|
44
|
-
return
|
|
63
|
+
getOptional(sql, parameters) {
|
|
64
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
65
|
+
return null;
|
|
66
|
+
});
|
|
45
67
|
}
|
|
46
|
-
|
|
47
|
-
|
|
68
|
+
get(sql, parameters) {
|
|
69
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
70
|
+
throw new Error(`No values are returned in SSR mode`);
|
|
71
|
+
});
|
|
48
72
|
}
|
|
49
73
|
/**
|
|
50
74
|
* Generates a mock context for use in read/write transactions.
|
|
@@ -52,14 +76,10 @@ export class SSRDBAdapter extends BaseObserver {
|
|
|
52
76
|
* are added here
|
|
53
77
|
*/
|
|
54
78
|
generateMockTransactionContext() {
|
|
55
|
-
return {
|
|
56
|
-
...this,
|
|
57
|
-
commit: async () => {
|
|
79
|
+
return Object.assign(Object.assign({}, this), { commit: () => __awaiter(this, void 0, void 0, function* () {
|
|
58
80
|
return MOCK_QUERY_RESPONSE;
|
|
59
|
-
},
|
|
60
|
-
rollback: async () => {
|
|
81
|
+
}), rollback: () => __awaiter(this, void 0, void 0, function* () {
|
|
61
82
|
return MOCK_QUERY_RESPONSE;
|
|
62
|
-
}
|
|
63
|
-
};
|
|
83
|
+
}) });
|
|
64
84
|
}
|
|
65
85
|
}
|
|
@@ -22,6 +22,7 @@ export declare class WASQLiteDBAdapter extends BaseObserver<DBAdapterListener> i
|
|
|
22
22
|
private logger;
|
|
23
23
|
private dbGetHelpers;
|
|
24
24
|
private methods;
|
|
25
|
+
private debugMode;
|
|
25
26
|
constructor(options: WASQLiteDBAdapterOptions);
|
|
26
27
|
get name(): string;
|
|
27
28
|
protected get flags(): WASQLiteFlags;
|
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
1
10
|
import { BaseObserver } from '@powersync/common';
|
|
2
11
|
import * as Comlink from 'comlink';
|
|
3
12
|
import Logger from 'js-logger';
|
|
@@ -7,17 +16,45 @@ import { getWorkerDatabaseOpener } from '../../../worker/db/open-worker-database
|
|
|
7
16
|
* Adapter for WA-SQLite SQLite connections.
|
|
8
17
|
*/
|
|
9
18
|
export class WASQLiteDBAdapter extends BaseObserver {
|
|
10
|
-
options;
|
|
11
|
-
initialized;
|
|
12
|
-
logger;
|
|
13
|
-
dbGetHelpers;
|
|
14
|
-
methods;
|
|
15
19
|
constructor(options) {
|
|
20
|
+
var _a;
|
|
16
21
|
super();
|
|
17
22
|
this.options = options;
|
|
23
|
+
/**
|
|
24
|
+
* Wraps the worker execute function, awaiting for it to be available
|
|
25
|
+
*/
|
|
26
|
+
this._execute = (sql, bindings) => __awaiter(this, void 0, void 0, function* () {
|
|
27
|
+
yield this.initialized;
|
|
28
|
+
const result = yield this.methods.execute(sql, bindings);
|
|
29
|
+
return Object.assign(Object.assign({}, result), { rows: Object.assign(Object.assign({}, result.rows), { item: (idx) => result.rows._array[idx] }) });
|
|
30
|
+
});
|
|
31
|
+
/**
|
|
32
|
+
* Wraps the worker executeBatch function, awaiting for it to be available
|
|
33
|
+
*/
|
|
34
|
+
this._executeBatch = (query, params) => __awaiter(this, void 0, void 0, function* () {
|
|
35
|
+
yield this.initialized;
|
|
36
|
+
const result = yield this.methods.executeBatch(query, params);
|
|
37
|
+
return Object.assign(Object.assign({}, result), { rows: undefined });
|
|
38
|
+
});
|
|
18
39
|
this.logger = Logger.get('WASQLite');
|
|
19
40
|
this.dbGetHelpers = null;
|
|
20
41
|
this.methods = null;
|
|
42
|
+
this.debugMode = (_a = options.debugMode) !== null && _a !== void 0 ? _a : false;
|
|
43
|
+
if (this.debugMode) {
|
|
44
|
+
const originalExecute = this._execute.bind(this);
|
|
45
|
+
this._execute = (sql, bindings) => __awaiter(this, void 0, void 0, function* () {
|
|
46
|
+
const start = performance.now();
|
|
47
|
+
try {
|
|
48
|
+
const r = yield originalExecute(sql, bindings);
|
|
49
|
+
performance.measure(`[SQL] ${sql}`, { start });
|
|
50
|
+
return r;
|
|
51
|
+
}
|
|
52
|
+
catch (e) {
|
|
53
|
+
performance.measure(`[SQL] [ERROR: ${e.message}] ${sql}`, { start });
|
|
54
|
+
throw e;
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
}
|
|
21
58
|
this.initialized = this.init();
|
|
22
59
|
this.dbGetHelpers = this.generateDBHelpers({
|
|
23
60
|
execute: (query, params) => this.acquireLock(() => this._execute(query, params))
|
|
@@ -27,93 +64,88 @@ export class WASQLiteDBAdapter extends BaseObserver {
|
|
|
27
64
|
return this.options.dbFilename;
|
|
28
65
|
}
|
|
29
66
|
get flags() {
|
|
30
|
-
|
|
67
|
+
var _a;
|
|
68
|
+
return (_a = this.options.flags) !== null && _a !== void 0 ? _a : {};
|
|
31
69
|
}
|
|
32
70
|
getWorker() { }
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
this.
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
this.
|
|
71
|
+
init() {
|
|
72
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
73
|
+
const { enableMultiTabs, useWebWorker } = this.flags;
|
|
74
|
+
if (!enableMultiTabs) {
|
|
75
|
+
this.logger.warn('Multiple tabs are not enabled in this browser');
|
|
76
|
+
}
|
|
77
|
+
if (useWebWorker) {
|
|
78
|
+
const dbOpener = this.options.workerPort
|
|
79
|
+
? Comlink.wrap(this.options.workerPort)
|
|
80
|
+
: getWorkerDatabaseOpener(this.options.dbFilename, enableMultiTabs);
|
|
81
|
+
this.methods = yield dbOpener(this.options.dbFilename);
|
|
82
|
+
this.methods.registerOnTableChange(Comlink.proxy((opType, tableName, rowId) => {
|
|
83
|
+
this.iterateListeners((cb) => { var _a; return (_a = cb.tablesUpdated) === null || _a === void 0 ? void 0 : _a.call(cb, { opType, table: tableName, rowId }); });
|
|
84
|
+
}));
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
this.methods = yield _openDB(this.options.dbFilename, { useWebWorker: false });
|
|
88
|
+
this.methods.registerOnTableChange((opType, tableName, rowId) => {
|
|
89
|
+
this.iterateListeners((cb) => { var _a; return (_a = cb.tablesUpdated) === null || _a === void 0 ? void 0 : _a.call(cb, { opType, table: tableName, rowId }); });
|
|
90
|
+
});
|
|
51
91
|
});
|
|
52
92
|
}
|
|
53
|
-
|
|
54
|
-
return this
|
|
93
|
+
execute(query, params) {
|
|
94
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
95
|
+
return this.writeLock((ctx) => ctx.execute(query, params));
|
|
96
|
+
});
|
|
55
97
|
}
|
|
56
|
-
|
|
57
|
-
return this
|
|
98
|
+
executeBatch(query, params) {
|
|
99
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
100
|
+
return this.writeLock((ctx) => this._executeBatch(query, params));
|
|
101
|
+
});
|
|
58
102
|
}
|
|
59
|
-
/**
|
|
60
|
-
* Wraps the worker execute function, awaiting for it to be available
|
|
61
|
-
*/
|
|
62
|
-
_execute = async (sql, bindings) => {
|
|
63
|
-
await this.initialized;
|
|
64
|
-
const result = await this.methods.execute(sql, bindings);
|
|
65
|
-
return {
|
|
66
|
-
...result,
|
|
67
|
-
rows: {
|
|
68
|
-
...result.rows,
|
|
69
|
-
item: (idx) => result.rows._array[idx]
|
|
70
|
-
}
|
|
71
|
-
};
|
|
72
|
-
};
|
|
73
|
-
/**
|
|
74
|
-
* Wraps the worker executeBatch function, awaiting for it to be available
|
|
75
|
-
*/
|
|
76
|
-
_executeBatch = async (query, params) => {
|
|
77
|
-
await this.initialized;
|
|
78
|
-
const result = await this.methods.executeBatch(query, params);
|
|
79
|
-
return {
|
|
80
|
-
...result,
|
|
81
|
-
rows: undefined
|
|
82
|
-
};
|
|
83
|
-
};
|
|
84
103
|
/**
|
|
85
104
|
* Attempts to close the connection.
|
|
86
105
|
* Shared workers might not actually close the connection if other
|
|
87
106
|
* tabs are still using it.
|
|
88
107
|
*/
|
|
89
108
|
close() {
|
|
90
|
-
|
|
109
|
+
var _a, _b;
|
|
110
|
+
(_b = (_a = this.methods) === null || _a === void 0 ? void 0 : _a.close) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
91
111
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
112
|
+
getAll(sql, parameters) {
|
|
113
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
114
|
+
yield this.initialized;
|
|
115
|
+
return this.dbGetHelpers.getAll(sql, parameters);
|
|
116
|
+
});
|
|
95
117
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
118
|
+
getOptional(sql, parameters) {
|
|
119
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
120
|
+
yield this.initialized;
|
|
121
|
+
return this.dbGetHelpers.getOptional(sql, parameters);
|
|
122
|
+
});
|
|
99
123
|
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
124
|
+
get(sql, parameters) {
|
|
125
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
126
|
+
yield this.initialized;
|
|
127
|
+
return this.dbGetHelpers.get(sql, parameters);
|
|
128
|
+
});
|
|
103
129
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
130
|
+
readLock(fn, options) {
|
|
131
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
132
|
+
yield this.initialized;
|
|
133
|
+
return this.acquireLock(() => __awaiter(this, void 0, void 0, function* () { return fn(this.generateDBHelpers({ execute: this._execute })); }));
|
|
134
|
+
});
|
|
107
135
|
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
136
|
+
writeLock(fn, options) {
|
|
137
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
138
|
+
yield this.initialized;
|
|
139
|
+
return this.acquireLock(() => __awaiter(this, void 0, void 0, function* () { return fn(this.generateDBHelpers({ execute: this._execute })); }));
|
|
140
|
+
});
|
|
111
141
|
}
|
|
112
142
|
acquireLock(callback) {
|
|
113
143
|
return navigator.locks.request(`db-lock-${this.options.dbFilename}`, callback);
|
|
114
144
|
}
|
|
115
|
-
|
|
116
|
-
return
|
|
145
|
+
readTransaction(fn, options) {
|
|
146
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
147
|
+
return this.readLock(this.wrapTransaction(fn));
|
|
148
|
+
});
|
|
117
149
|
}
|
|
118
150
|
writeTransaction(fn, options) {
|
|
119
151
|
return this.writeLock(this.wrapTransaction(fn));
|
|
@@ -122,35 +154,32 @@ export class WASQLiteDBAdapter extends BaseObserver {
|
|
|
122
154
|
* Wraps a lock context into a transaction context
|
|
123
155
|
*/
|
|
124
156
|
wrapTransaction(cb) {
|
|
125
|
-
return
|
|
126
|
-
|
|
157
|
+
return (tx) => __awaiter(this, void 0, void 0, function* () {
|
|
158
|
+
yield this._execute('BEGIN TRANSACTION');
|
|
127
159
|
let finalized = false;
|
|
128
|
-
const commit =
|
|
160
|
+
const commit = () => __awaiter(this, void 0, void 0, function* () {
|
|
129
161
|
if (finalized) {
|
|
130
162
|
return { rowsAffected: 0 };
|
|
131
163
|
}
|
|
132
164
|
finalized = true;
|
|
133
165
|
return this._execute('COMMIT');
|
|
134
|
-
};
|
|
166
|
+
});
|
|
135
167
|
const rollback = () => {
|
|
136
168
|
finalized = true;
|
|
137
169
|
return this._execute('ROLLBACK');
|
|
138
170
|
};
|
|
139
171
|
try {
|
|
140
|
-
const result =
|
|
141
|
-
|
|
142
|
-
commit,
|
|
143
|
-
rollback
|
|
144
|
-
});
|
|
172
|
+
const result = yield cb(Object.assign(Object.assign({}, tx), { commit,
|
|
173
|
+
rollback }));
|
|
145
174
|
if (!finalized) {
|
|
146
|
-
|
|
175
|
+
yield commit();
|
|
147
176
|
}
|
|
148
177
|
return result;
|
|
149
178
|
}
|
|
150
179
|
catch (ex) {
|
|
151
180
|
this.logger.debug('Caught ex in transaction', ex);
|
|
152
181
|
try {
|
|
153
|
-
|
|
182
|
+
yield rollback();
|
|
154
183
|
}
|
|
155
184
|
catch (ex2) {
|
|
156
185
|
// In rare cases, a rollback may fail.
|
|
@@ -158,36 +187,43 @@ export class WASQLiteDBAdapter extends BaseObserver {
|
|
|
158
187
|
}
|
|
159
188
|
throw ex;
|
|
160
189
|
}
|
|
161
|
-
};
|
|
190
|
+
});
|
|
162
191
|
}
|
|
163
192
|
generateDBHelpers(tx) {
|
|
164
|
-
return {
|
|
165
|
-
...tx,
|
|
193
|
+
return Object.assign(Object.assign({}, tx), {
|
|
166
194
|
/**
|
|
167
195
|
* Execute a read-only query and return results
|
|
168
196
|
*/
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
197
|
+
getAll(sql, parameters) {
|
|
198
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
199
|
+
var _a, _b;
|
|
200
|
+
const res = yield tx.execute(sql, parameters);
|
|
201
|
+
return (_b = (_a = res.rows) === null || _a === void 0 ? void 0 : _a._array) !== null && _b !== void 0 ? _b : [];
|
|
202
|
+
});
|
|
172
203
|
},
|
|
173
204
|
/**
|
|
174
205
|
* Execute a read-only query and return the first result, or null if the ResultSet is empty.
|
|
175
206
|
*/
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
207
|
+
getOptional(sql, parameters) {
|
|
208
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
209
|
+
var _a, _b;
|
|
210
|
+
const res = yield tx.execute(sql, parameters);
|
|
211
|
+
return (_b = (_a = res.rows) === null || _a === void 0 ? void 0 : _a.item(0)) !== null && _b !== void 0 ? _b : null;
|
|
212
|
+
});
|
|
179
213
|
},
|
|
180
214
|
/**
|
|
181
215
|
* Execute a read-only query and return the first result, error if the ResultSet is empty.
|
|
182
216
|
*/
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
217
|
+
get(sql, parameters) {
|
|
218
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
219
|
+
var _a;
|
|
220
|
+
const res = yield tx.execute(sql, parameters);
|
|
221
|
+
const first = (_a = res.rows) === null || _a === void 0 ? void 0 : _a.item(0);
|
|
222
|
+
if (!first) {
|
|
223
|
+
throw new Error('Result set is empty');
|
|
224
|
+
}
|
|
225
|
+
return first;
|
|
226
|
+
});
|
|
227
|
+
} });
|
|
192
228
|
}
|
|
193
229
|
}
|
|
@@ -5,9 +5,6 @@ import { AbstractWebSQLOpenFactory } from '../AbstractWebSQLOpenFactory';
|
|
|
5
5
|
*/
|
|
6
6
|
export class WASQLiteOpenFactory extends AbstractWebSQLOpenFactory {
|
|
7
7
|
openAdapter() {
|
|
8
|
-
return new WASQLiteDBAdapter({
|
|
9
|
-
...this.options,
|
|
10
|
-
flags: this.resolvedFlags
|
|
11
|
-
});
|
|
8
|
+
return new WASQLiteDBAdapter(Object.assign(Object.assign({}, this.options), { flags: this.resolvedFlags }));
|
|
12
9
|
}
|
|
13
10
|
}
|