From d793731eab14cca2a167c07143a947c95f52efe7 Mon Sep 17 00:00:00 2001 From: radex Date: Mon, 4 Nov 2019 09:17:50 +0100 Subject: [PATCH 1/6] Close connection to WatermelonIDBChecker after checking -- otherwise it might block concurrent access --- src/adapters/lokijs/worker/lokiExtensions.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/adapters/lokijs/worker/lokiExtensions.js b/src/adapters/lokijs/worker/lokiExtensions.js index 76fefa439..5580b88b4 100644 --- a/src/adapters/lokijs/worker/lokiExtensions.js +++ b/src/adapters/lokijs/worker/lokiExtensions.js @@ -12,8 +12,14 @@ const isIDBAvailable = () => { // in Firefox private mode, IDB will be available, but will fail to open const db = indexedDB.open('WatermelonIDBChecker') - db.onsuccess = () => resolve(true) - db.onerror = () => resolve(false) + db.onsuccess = () => { + db.close() + resolve(true) + } + db.onerror = () => { + db.close() + resolve(false) + } }) } From 23da8e62ec6a999bd7c313836457bdeb1dbfb6e8 Mon Sep 17 00:00:00 2001 From: radex Date: Mon, 4 Nov 2019 11:24:21 +0100 Subject: [PATCH 2/6] Bump LokiJS dependency --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7ea8a5dc2..f358d5cad 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ }, "dependencies": { "lodash.clonedeep": "^4.5.0", - "lokijs": "git+https://github.com/Nozbe/LokiJS.git#f9f6f73c4bfe1d6df27c99d7a5e18f730754e904", + "lokijs": "git+https://github.com/Nozbe/LokiJS.git#384b80f", "rambdax": "2.15.0", "rxjs": "^6.2.2", "rxjs-compat": "^6.3.2", From 1e2fde82abf8afb16132a09efeec1b3787715b89 Mon Sep 17 00:00:00 2001 From: radex Date: Mon, 4 Nov 2019 11:34:19 +0100 Subject: [PATCH 3/6] Pass through onversionchange from LokiJSAdapter to Loki's IncrementalIndexedDBAdapter --- docs-master/Installation.md | 28 ++++++++++++-------- src/adapters/lokijs/index.js | 4 +++ src/adapters/lokijs/worker/executor.js | 4 +++ src/adapters/lokijs/worker/lokiExtensions.js | 8 ++++-- 4 files changed, 31 insertions(+), 13 deletions(-) diff --git a/docs-master/Installation.md b/docs-master/Installation.md index a2a779458..6242e1f30 100644 --- a/docs-master/Installation.md +++ b/docs-master/Installation.md @@ -20,10 +20,10 @@ npm install @nozbe/with-observables yarn add --dev @babel/plugin-proposal-decorators ``` or - + ```bash npm install -D @babel/plugin-proposal-decorators - + 2. Add ES6 decorators support to your `.babelrc` file: ```json { @@ -38,9 +38,9 @@ npm install @nozbe/with-observables ### iOS (React Native) 1. **Set up Babel config in your project** - + See instructions above ⬆️ - + 2. **Add Swift support to your Xcode project**: - Open `ios/YourAppName.xcodeproj` in Xcode - Right-click on **Your App Name** in the Project Navigator on the left, and click **New File…** @@ -59,11 +59,11 @@ npm install @nozbe/with-observables 1. Open your project in Xcode, right click on **Libraries** in the Project Navigator on the left and click **Add Files to "Your Project Name"**. Look under `node_modules/@nozbe/watermelondb/native/ios` and select `WatermelonDB.xcodeproj` 2. Go to Project settings (top item in the Project navigator on the left), select your app name under **Targets** → **Build Phases** → **Link Binary With Libraries**, and add `libWatermelonDB.a` - + For more information about linking libraries manually, [see React Native documentation](https://facebook.github.io/react-native/docs/linking-libraries-ios). - + **Using CocoaPods** - + [Please contribute!](https://github.com/Nozbe/WatermelonDB/issues/279) Note that Xcode 9.4 and a deployment target of at least iOS 9.0 is required (although Xcode 10 and iOS 11.0 are recommended). @@ -71,9 +71,9 @@ Note that Xcode 9.4 and a deployment target of at least iOS 9.0 is required (alt ### Android (React Native) 1. **Set up Babel config in your project** - + See instructions above ⬆️ - + 1. In `android/settings.gradle`, add: ```gradle @@ -141,11 +141,11 @@ This guide assumes you use Webpack as your bundler. yarn add --dev worker-loader ``` or - + ```bash npm install -D worker-loader ``` - + 2. And add this to Webpack configuration: ```js // webpack.config.js @@ -241,6 +241,12 @@ import LokiJSAdapter from '@nozbe/watermelondb/adapters/lokijs' const adapter = new LokiJSAdapter({ schema, + // useWebWorker: false, + // experimentalUseIncrementalIndexedDB: true, + // onIndexedDBVersionChange: () => { + // // database was deleted in another browser tab + // services.forceLogOut() + // }, }) // The rest is the same! diff --git a/src/adapters/lokijs/index.js b/src/adapters/lokijs/index.js index f86cf5655..2e6a1f0c3 100644 --- a/src/adapters/lokijs/index.js +++ b/src/adapters/lokijs/index.js @@ -42,6 +42,10 @@ export type LokiAdapterOptions = $Exact<{ // may lead to lower memory consumption, lower latency, and easier debugging useWebWorker?: boolean, experimentalUseIncrementalIndexedDB?: boolean, + // Called when internal IDB version changed (most likely the database was deleted in another browser tab) + // Pass a callback to force log out in this copy of the app as well + // Note that this only works when using incrementalIDB and not using web workers + onIndexedDBVersionChange?: () => void, // -- internal -- _testLokiAdapter?: LokiMemoryAdapter, }> diff --git a/src/adapters/lokijs/worker/executor.js b/src/adapters/lokijs/worker/executor.js index 4f7194fe0..76bc042cd 100644 --- a/src/adapters/lokijs/worker/executor.js +++ b/src/adapters/lokijs/worker/executor.js @@ -35,6 +35,8 @@ export default class LokiExecutor { experimentalUseIncrementalIndexedDB: boolean + onIndexedDBVersionChange: ?(() => void) + _testLokiAdapter: ?LokiMemoryAdapter cachedRecords: Map, Set> = new Map() @@ -45,6 +47,7 @@ export default class LokiExecutor { this.schema = schema this.migrations = migrations this.experimentalUseIncrementalIndexedDB = options.experimentalUseIncrementalIndexedDB || false + this.onIndexedDBVersionChange = options.onIndexedDBVersionChange this._testLokiAdapter = _testLokiAdapter } @@ -236,6 +239,7 @@ export default class LokiExecutor { this.dbName, this._testLokiAdapter, this.experimentalUseIncrementalIndexedDB, + this.onIndexedDBVersionChange, ) logger.log('[DB][Worker] Database loaded') diff --git a/src/adapters/lokijs/worker/lokiExtensions.js b/src/adapters/lokijs/worker/lokiExtensions.js index 5580b88b4..7db53f864 100644 --- a/src/adapters/lokijs/worker/lokiExtensions.js +++ b/src/adapters/lokijs/worker/lokiExtensions.js @@ -27,13 +27,16 @@ async function getLokiAdapter( name: ?string, adapter: ?LokiMemoryAdapter, useIncrementalIDB: boolean, + onIndexedDBVersionChange: ?(() => void), ): mixed { if (adapter) { return adapter } else if (await isIDBAvailable()) { if (useIncrementalIDB) { const IncrementalIDBAdapter = require('lokijs/src/incremental-indexeddb-adapter') - return new IncrementalIDBAdapter() + return new IncrementalIDBAdapter({ + onversionchange: onIndexedDBVersionChange, + }) } const LokiIndexedAdapter = require('lokijs/src/loki-indexed-adapter') return new LokiIndexedAdapter(name) @@ -48,9 +51,10 @@ export async function newLoki( name: ?string, adapter: ?LokiMemoryAdapter, useIncrementalIDB: boolean, + onIndexedDBVersionChange: ?(() => void), ): Loki { const loki = new Loki(name, { - adapter: await getLokiAdapter(name, adapter, useIncrementalIDB), + adapter: await getLokiAdapter(name, adapter, useIncrementalIDB, onIndexedDBVersionChange), autosave: true, autosaveInterval: 250, verbose: true, From 9544eaaa9b8fad54e9772ce6add8c48fad84680c Mon Sep 17 00:00:00 2001 From: radex Date: Mon, 4 Nov 2019 11:42:22 +0100 Subject: [PATCH 4/6] Fix WatermelonIDBChecker --- src/adapters/lokijs/worker/lokiExtensions.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/adapters/lokijs/worker/lokiExtensions.js b/src/adapters/lokijs/worker/lokiExtensions.js index 7db53f864..b612dd5e0 100644 --- a/src/adapters/lokijs/worker/lokiExtensions.js +++ b/src/adapters/lokijs/worker/lokiExtensions.js @@ -11,15 +11,19 @@ const isIDBAvailable = () => { } // in Firefox private mode, IDB will be available, but will fail to open - const db = indexedDB.open('WatermelonIDBChecker') - db.onsuccess = () => { + const checkRequest: IDBOpenDBRequest = indexedDB.open('WatermelonIDBChecker') + checkRequest.onsuccess = e => { + const db: IDBDatabase = e.target.result db.close() resolve(true) } - db.onerror = () => { - db.close() + checkRequest.onerror = () => { resolve(false) } + checkRequest.onblocked = () => { + // eslint-disable-next-line no-console + console.error('WatermelonIDBChecker call is blocked') + } }) } From 840316fce839ac386c499cbd8a243a961e3f1543 Mon Sep 17 00:00:00 2001 From: radex Date: Mon, 4 Nov 2019 12:02:20 +0100 Subject: [PATCH 5/6] v0.15.0-10 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f358d5cad..2fbc375ff 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@nozbe/watermelondb", "description": "Build powerful React Native and React web apps that scale from hundreds to tens of thousands of records and remain fast", - "version": "0.15.0-7", + "version": "0.15.0-10", "scripts": { "build": "NODE_ENV=production node ./scripts/make.js", "dev": "NODE_ENV=development node ./scripts/make.js", From ad105135731fef52399df159bab92adfc4c353bc Mon Sep 17 00:00:00 2001 From: radex Date: Mon, 4 Nov 2019 12:09:33 +0100 Subject: [PATCH 6/6] update changelog --- CHANGELOG.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 759197948..362b197b9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,7 +42,10 @@ This is a **massive** new update to WatermelonDB! 🍉 - [LokiJS] Introduces new `new LokiJSAdapter({ ..., useWebWorker: false })` option. Before, web workers were always used with `LokiJSAdapter`. Although web workers may have some performance benefits, disabling them may lead to lower memory consumption, lower latency, and easier debugging. YMMV. - +- [LokiJS] Added `onIndexedDBVersionChange` option to `LokiJSAdapter`. This is a callback that's called + when internal IDB version changed (most likely the database was deleted in another browser tab). + Pass a callback to force log out in this copy of the app as well. Note that this only works when + using incrementalIDB and not using web workers - [Model] Add `Model._dangerouslySetRawWithoutMarkingColumnChange()` method. You probably shouldn't use it, but if you know what you're doing and want to live-update records from server without marking record as updated, this is useful