From eb44929efc57836f9e960eb798acb07ea25295a5 Mon Sep 17 00:00:00 2001 From: Sebastian Schmidt Date: Fri, 2 Feb 2018 11:44:46 -0800 Subject: [PATCH 01/22] Adding Schema Migration --- .../src/local/indexeddb_migrations.ts | 91 +++++++++++++++++++ .../src/local/indexeddb_persistence.ts | 3 +- .../firestore/src/local/indexeddb_schema.ts | 60 +++--------- 3 files changed, 108 insertions(+), 46 deletions(-) create mode 100644 packages/firestore/src/local/indexeddb_migrations.ts diff --git a/packages/firestore/src/local/indexeddb_migrations.ts b/packages/firestore/src/local/indexeddb_migrations.ts new file mode 100644 index 00000000000..b543fadc8eb --- /dev/null +++ b/packages/firestore/src/local/indexeddb_migrations.ts @@ -0,0 +1,91 @@ +/** + * Copyright 2018 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { + DbDocumentMutation, DbInstance, + DbMutationBatch, DbMutationQueue, DbOwner, DbRemoteDocument, DbTarget, + DbTargetDocument, DbTargetGlobal +} from './indexeddb_schema'; +import {fail} from '../util/assert'; + +export function createDb(db: IDBDatabase): void { + db.createObjectStore(DbMutationQueue.store, { + keyPath: DbMutationQueue.keyPath + }); + + // TODO(mikelehen): Get rid of "as any" if/when TypeScript fixes their + // types. https://github.com/Microsoft/TypeScript/issues/14322 + db.createObjectStore( + DbMutationBatch.store, + // tslint:disable-next-line:no-any + { keyPath: DbMutationBatch.keyPath as any } + ); + + const targetDocumentsStore = db.createObjectStore( + DbTargetDocument.store, + // tslint:disable-next-line:no-any + { keyPath: DbTargetDocument.keyPath as any } + ); + targetDocumentsStore.createIndex( + DbTargetDocument.documentTargetsIndex, + DbTargetDocument.documentTargetsKeyPath, + { unique: true } + ); + + const targetStore = db.createObjectStore(DbTarget.store, { + keyPath: DbTarget.keyPath + }); + // NOTE: This is unique only because the TargetId is the suffix. + targetStore.createIndex( + DbTarget.queryTargetsIndexName, + DbTarget.queryTargetsKeyPath, + { unique: true } + ); + + const instanceStore = db.createObjectStore(DbInstance.store, { + keyPath: DbInstance.keyPath as any + }); + + // NOTE: keys for these stores are specified explicitly rather than using a + // keyPath. + db.createObjectStore(DbDocumentMutation.store); + db.createObjectStore(DbRemoteDocument.store); + db.createObjectStore(DbOwner.store); + db.createObjectStore(DbTargetGlobal.store); +} + +export function upgradeDbFromV1(db: IDBDatabase): void { + +} + +export class IndexedDbMigrations { + /** + * Runs any migrations needed to bring the given database up to the current + * schema version. + */ + static runMigrations(db: IDBDatabase, oldVersion: number) { + if (oldVersion == 0) { + createDb(db, oldVersion); + return; + } + + if (oldVersion == 1) { + upgradeDbFromV1(db, oldVersion); + return; + } + + fail('Unexpected upgrade from version ' + oldVersion); + } +} \ No newline at end of file diff --git a/packages/firestore/src/local/indexeddb_persistence.ts b/packages/firestore/src/local/indexeddb_persistence.ts index c4bcd5c8634..298ef5c6879 100644 --- a/packages/firestore/src/local/indexeddb_persistence.ts +++ b/packages/firestore/src/local/indexeddb_persistence.ts @@ -34,6 +34,7 @@ import { PersistencePromise } from './persistence_promise'; import { QueryCache } from './query_cache'; import { RemoteDocumentCache } from './remote_document_cache'; import { SimpleDb, SimpleDbTransaction } from './simple_db'; +import {IndexedDbMigrations} from './indexeddb_migrations'; const LOG_TAG = 'IndexedDbPersistence'; @@ -127,7 +128,7 @@ export class IndexedDbPersistence implements Persistence { assert(!this.started, 'IndexedDbPersistence double-started!'); this.started = true; - return SimpleDb.openOrCreate(this.dbName, SCHEMA_VERSION, createOrUpgradeDb) + return SimpleDb.openOrCreate(this.dbName, SCHEMA_VERSION, IndexedDbMigrations.runMigrations) .then(db => { this.simpleDb = db; }) diff --git a/packages/firestore/src/local/indexeddb_schema.ts b/packages/firestore/src/local/indexeddb_schema.ts index 88bfb484371..a7808dbfbc7 100644 --- a/packages/firestore/src/local/indexeddb_schema.ts +++ b/packages/firestore/src/local/indexeddb_schema.ts @@ -24,51 +24,6 @@ import { encode, EncodedResourcePath } from './encoded_resource_path'; export const SCHEMA_VERSION = 1; -/** Performs database creation and (in the future) upgrades between versions. */ -export function createOrUpgradeDb(db: IDBDatabase, oldVersion: number): void { - assert(oldVersion === 0, 'Unexpected upgrade from version ' + oldVersion); - - db.createObjectStore(DbMutationQueue.store, { - keyPath: DbMutationQueue.keyPath - }); - - // TODO(mikelehen): Get rid of "as any" if/when TypeScript fixes their - // types. https://github.com/Microsoft/TypeScript/issues/14322 - db.createObjectStore( - DbMutationBatch.store, - // tslint:disable-next-line:no-any - { keyPath: DbMutationBatch.keyPath as any } - ); - - const targetDocumentsStore = db.createObjectStore( - DbTargetDocument.store, - // tslint:disable-next-line:no-any - { keyPath: DbTargetDocument.keyPath as any } - ); - targetDocumentsStore.createIndex( - DbTargetDocument.documentTargetsIndex, - DbTargetDocument.documentTargetsKeyPath, - { unique: true } - ); - - const targetStore = db.createObjectStore(DbTarget.store, { - keyPath: DbTarget.keyPath - }); - // NOTE: This is unique only because the TargetId is the suffix. - targetStore.createIndex( - DbTarget.queryTargetsIndexName, - DbTarget.queryTargetsKeyPath, - { unique: true } - ); - - // NOTE: keys for these stores are specified explicitly rather than using a - // keyPath. - db.createObjectStore(DbDocumentMutation.store); - db.createObjectStore(DbRemoteDocument.store); - db.createObjectStore(DbOwner.store); - db.createObjectStore(DbTargetGlobal.store); -} - /** * Wrapper class to store timestamps (seconds and nanos) in IndexedDb objects. */ @@ -455,6 +410,21 @@ export class DbTargetGlobal { ) {} } +export type DbInstanceKey = [string, string]; + +export class DbInstance { + static store = 'instances'; + + static keyPath = ['userId', 'instanceId']; + + constructor( + public userId: string, + public instanceId: string, + public updateTimeMs: number, + public visibilityState: VisibilityState + ) {} +} + /** * The list of all IndexedDB stored used by the SDK. This is used when creating * transactions so that access across all stores is done atomically. From 07e44e7e80167c0d25a40e9c8cc03290c222141f Mon Sep 17 00:00:00 2001 From: Sebastian Schmidt Date: Fri, 2 Feb 2018 13:54:02 -0800 Subject: [PATCH 02/22] Pseudocode for Schema Migration --- .../src/local/indexeddb_migrations.ts | 95 +++++++++++-------- .../src/local/indexeddb_persistence.ts | 6 +- .../firestore/src/local/indexeddb_schema.ts | 23 +++-- packages/firestore/src/local/simple_db.ts | 5 +- 4 files changed, 80 insertions(+), 49 deletions(-) diff --git a/packages/firestore/src/local/indexeddb_migrations.ts b/packages/firestore/src/local/indexeddb_migrations.ts index b543fadc8eb..98c3fba0a65 100644 --- a/packages/firestore/src/local/indexeddb_migrations.ts +++ b/packages/firestore/src/local/indexeddb_migrations.ts @@ -15,28 +15,20 @@ */ import { DbDocumentMutation, DbInstance, - DbMutationBatch, DbMutationQueue, DbOwner, DbRemoteDocument, DbTarget, + DbMutationBatch, DbMutationQueue, DbOwner, + DbRemoteDocument, DbTarget, DbTargetDocument, DbTargetGlobal } from './indexeddb_schema'; -import {fail} from '../util/assert'; +import {assert, fail} from '../util/assert'; -export function createDb(db: IDBDatabase): void { - db.createObjectStore(DbMutationQueue.store, { - keyPath: DbMutationQueue.keyPath - }); - - // TODO(mikelehen): Get rid of "as any" if/when TypeScript fixes their - // types. https://github.com/Microsoft/TypeScript/issues/14322 - db.createObjectStore( - DbMutationBatch.store, - // tslint:disable-next-line:no-any - { keyPath: DbMutationBatch.keyPath as any } - ); +// TODO(mikelehen): Get rid of "as any" if/when TypeScript fixes their types. +// https://github.com/Microsoft/TypeScript/issues/14322 +type KeyPath = any; // tslint:disable-line:no-any +function createCache(db: IDBDatabase): void { const targetDocumentsStore = db.createObjectStore( DbTargetDocument.store, - // tslint:disable-next-line:no-any - { keyPath: DbTargetDocument.keyPath as any } + { keyPath: DbTargetDocument.keyPath as KeyPath } ); targetDocumentsStore.createIndex( DbTargetDocument.documentTargetsIndex, @@ -47,45 +39,72 @@ export function createDb(db: IDBDatabase): void { const targetStore = db.createObjectStore(DbTarget.store, { keyPath: DbTarget.keyPath }); + // NOTE: This is unique only because the TargetId is the suffix. targetStore.createIndex( DbTarget.queryTargetsIndexName, DbTarget.queryTargetsKeyPath, { unique: true } ); + db.createObjectStore(DbRemoteDocument.store); + db.createObjectStore(DbTargetGlobal.store); +} + +function dropCache(db: IDBDatabase): void { + db.deleteObjectStore(DbTargetDocument.store); + db.deleteObjectStore(DbTarget.keyPath); + db.deleteObjectStore(DbRemoteDocument.store); + db.deleteObjectStore(DbTargetGlobal.store); +} - const instanceStore = db.createObjectStore(DbInstance.store, { - keyPath: DbInstance.keyPath as any +function createOwnerStore(db: IDBDatabase) : void { + db.createObjectStore(DbOwner.store); +} + +function createInstanceStore(db: IDBDatabase) : void { + db.createObjectStore(DbInstance.store, { + keyPath: DbInstance.keyPath as KeyPath }); +} + +function createMutationQueue(db: IDBDatabase) : void { + db.createObjectStore(DbMutationQueue.store, { + keyPath: DbMutationQueue.keyPath + }); + + db.createObjectStore( + DbMutationBatch.store, + { keyPath: DbMutationBatch.keyPath as KeyPath } + ); // NOTE: keys for these stores are specified explicitly rather than using a // keyPath. db.createObjectStore(DbDocumentMutation.store); - db.createObjectStore(DbRemoteDocument.store); - db.createObjectStore(DbOwner.store); - db.createObjectStore(DbTargetGlobal.store); } -export function upgradeDbFromV1(db: IDBDatabase): void { +/** + * Runs any migrations needed to bring the given database up to the current + * schema version. + */ +export function createOrUpgradeDb(db: IDBDatabase, oldVersion: number, newVersion: number): void { + assert(oldVersion >= 0 || oldVersion <= 1, 'Unexpected upgrade from version ' + oldVersion); + assert(newVersion >= 1 || newVersion <= 2, 'Unexpected upgrade to version ' + newVersion); -} + const createV1 = newVersion >= 1 && oldVersion <= 1; + const dropV1 = oldVersion >= 1; + const createV2 = newVersion >= 2 && oldVersion <= 2; -export class IndexedDbMigrations { - /** - * Runs any migrations needed to bring the given database up to the current - * schema version. - */ - static runMigrations(db: IDBDatabase, oldVersion: number) { - if (oldVersion == 0) { - createDb(db, oldVersion); - return; - } + if (dropV1) { + dropCache(db); + } - if (oldVersion == 1) { - upgradeDbFromV1(db, oldVersion); - return; - } + if (createV1) { + createOwnerStore(db); + createMutationQueue(db); + createCache(db); + } - fail('Unexpected upgrade from version ' + oldVersion); + if (createV2) { + createInstanceStore(db); } } \ No newline at end of file diff --git a/packages/firestore/src/local/indexeddb_persistence.ts b/packages/firestore/src/local/indexeddb_persistence.ts index 298ef5c6879..54abbdb40ae 100644 --- a/packages/firestore/src/local/indexeddb_persistence.ts +++ b/packages/firestore/src/local/indexeddb_persistence.ts @@ -26,7 +26,7 @@ import { IndexedDbMutationQueue } from './indexeddb_mutation_queue'; import { IndexedDbQueryCache } from './indexeddb_query_cache'; import { IndexedDbRemoteDocumentCache } from './indexeddb_remote_document_cache'; import { ALL_STORES, DbOwner, DbOwnerKey } from './indexeddb_schema'; -import { createOrUpgradeDb, SCHEMA_VERSION } from './indexeddb_schema'; +import { SCHEMA_VERSION } from './indexeddb_schema'; import { LocalSerializer } from './local_serializer'; import { MutationQueue } from './mutation_queue'; import { Persistence } from './persistence'; @@ -34,7 +34,7 @@ import { PersistencePromise } from './persistence_promise'; import { QueryCache } from './query_cache'; import { RemoteDocumentCache } from './remote_document_cache'; import { SimpleDb, SimpleDbTransaction } from './simple_db'; -import {IndexedDbMigrations} from './indexeddb_migrations'; +import {createOrUpgradeDb} from './indexeddb_migrations'; const LOG_TAG = 'IndexedDbPersistence'; @@ -128,7 +128,7 @@ export class IndexedDbPersistence implements Persistence { assert(!this.started, 'IndexedDbPersistence double-started!'); this.started = true; - return SimpleDb.openOrCreate(this.dbName, SCHEMA_VERSION, IndexedDbMigrations.runMigrations) + return SimpleDb.openOrCreate(this.dbName, SCHEMA_VERSION, createOrUpgradeDb) .then(db => { this.simpleDb = db; }) diff --git a/packages/firestore/src/local/indexeddb_schema.ts b/packages/firestore/src/local/indexeddb_schema.ts index a7808dbfbc7..4e147bbea22 100644 --- a/packages/firestore/src/local/indexeddb_schema.ts +++ b/packages/firestore/src/local/indexeddb_schema.ts @@ -21,6 +21,7 @@ import { ResourcePath } from '../model/path'; import { assert } from '../util/assert'; import { encode, EncodedResourcePath } from './encoded_resource_path'; +import {SnapshotVersion} from '../core/snapshot_version'; export const SCHEMA_VERSION = 1; @@ -86,7 +87,15 @@ export class DbMutationQueue { * After sending this token, earlier tokens may not be used anymore so * only a single stream token is retained. */ - public lastStreamToken: string + public lastStreamToken: string, + + /** + * An identifier for the highest numbered batch that has been acknowledged + * by the server. All MutationBatches in this queue with batchIds less + * than or equal to this value are considered to have been acknowledged by + * the server. + */ + public highestPendingBatchId: number, ) {} } @@ -345,8 +354,8 @@ export class DbTargetDocument { /** Name of the IndexedDb object store. */ static store = 'targetDocuments'; - /** Keys are automatically assigned via the targetId, path properties. */ - static keyPath = ['targetId', 'path']; + /** Keys are automatically assigned via the targetId, snapshotVersion, and path properties. */ + static keyPath = ['targetId', 'snapshotVersion', 'path']; /** The index name for the reverse index. */ static documentTargetsIndex = 'documentTargetsIndex'; @@ -359,6 +368,8 @@ export class DbTargetDocument { * The targetId identifying a target. */ public targetId: TargetId, + + public snapshotVersion: number, /** * The path to the document, as encoded in the key. */ @@ -420,8 +431,7 @@ export class DbInstance { constructor( public userId: string, public instanceId: string, - public updateTimeMs: number, - public visibilityState: VisibilityState + public updateTimeMs: number ) {} } @@ -437,5 +447,6 @@ export const ALL_STORES = [ DbTarget.store, DbOwner.store, DbTargetGlobal.store, - DbTargetDocument.store + DbTargetDocument.store, + DbInstance.store ]; diff --git a/packages/firestore/src/local/simple_db.ts b/packages/firestore/src/local/simple_db.ts index cfaa6bb9767..2a925ead624 100644 --- a/packages/firestore/src/local/simple_db.ts +++ b/packages/firestore/src/local/simple_db.ts @@ -19,6 +19,7 @@ import { debug } from '../util/log'; import { AnyDuringMigration } from '../util/misc'; import { PersistencePromise } from './persistence_promise'; +import {SCHEMA_VERSION} from './indexeddb_schema'; const LOG_TAG = 'SimpleDb'; @@ -34,7 +35,7 @@ export class SimpleDb { static openOrCreate( name: string, version: number, - runUpgrade: (db: IDBDatabase, oldVersion: number) => void + runUpgrade: (db: IDBDatabase, oldVersion: number, newVersion: number) => void ): Promise { assert( SimpleDb.isAvailable(), @@ -70,7 +71,7 @@ export class SimpleDb { // cheating and just passing the raw IndexedDB in, since // createObjectStore(), etc. are synchronous. const db = (event.target as IDBOpenDBRequest).result; - runUpgrade(db, event.oldVersion); + runUpgrade(db, event.oldVersion, SCHEMA_VERSION); }; }).toPromise(); } From 3e1053f5e683c5e5b95f6bf42ef64c5982f7c51a Mon Sep 17 00:00:00 2001 From: Sebastian Schmidt Date: Fri, 2 Feb 2018 13:54:29 -0800 Subject: [PATCH 03/22] [AUTOMATED]: Prettier Code Styling --- .../src/local/indexeddb_migrations.ts | 65 +++++++++++-------- .../src/local/indexeddb_persistence.ts | 2 +- .../firestore/src/local/indexeddb_schema.ts | 12 ++-- packages/firestore/src/local/simple_db.ts | 8 ++- 4 files changed, 51 insertions(+), 36 deletions(-) diff --git a/packages/firestore/src/local/indexeddb_migrations.ts b/packages/firestore/src/local/indexeddb_migrations.ts index 98c3fba0a65..faac5951c44 100644 --- a/packages/firestore/src/local/indexeddb_migrations.ts +++ b/packages/firestore/src/local/indexeddb_migrations.ts @@ -14,26 +14,30 @@ * limitations under the License. */ import { - DbDocumentMutation, DbInstance, - DbMutationBatch, DbMutationQueue, DbOwner, - DbRemoteDocument, DbTarget, - DbTargetDocument, DbTargetGlobal + DbDocumentMutation, + DbInstance, + DbMutationBatch, + DbMutationQueue, + DbOwner, + DbRemoteDocument, + DbTarget, + DbTargetDocument, + DbTargetGlobal } from './indexeddb_schema'; -import {assert, fail} from '../util/assert'; +import { assert, fail } from '../util/assert'; // TODO(mikelehen): Get rid of "as any" if/when TypeScript fixes their types. // https://github.com/Microsoft/TypeScript/issues/14322 type KeyPath = any; // tslint:disable-line:no-any function createCache(db: IDBDatabase): void { - const targetDocumentsStore = db.createObjectStore( - DbTargetDocument.store, - { keyPath: DbTargetDocument.keyPath as KeyPath } - ); + const targetDocumentsStore = db.createObjectStore(DbTargetDocument.store, { + keyPath: DbTargetDocument.keyPath as KeyPath + }); targetDocumentsStore.createIndex( - DbTargetDocument.documentTargetsIndex, - DbTargetDocument.documentTargetsKeyPath, - { unique: true } + DbTargetDocument.documentTargetsIndex, + DbTargetDocument.documentTargetsKeyPath, + { unique: true } ); const targetStore = db.createObjectStore(DbTarget.store, { @@ -42,9 +46,9 @@ function createCache(db: IDBDatabase): void { // NOTE: This is unique only because the TargetId is the suffix. targetStore.createIndex( - DbTarget.queryTargetsIndexName, - DbTarget.queryTargetsKeyPath, - { unique: true } + DbTarget.queryTargetsIndexName, + DbTarget.queryTargetsKeyPath, + { unique: true } ); db.createObjectStore(DbRemoteDocument.store); db.createObjectStore(DbTargetGlobal.store); @@ -57,25 +61,24 @@ function dropCache(db: IDBDatabase): void { db.deleteObjectStore(DbTargetGlobal.store); } -function createOwnerStore(db: IDBDatabase) : void { +function createOwnerStore(db: IDBDatabase): void { db.createObjectStore(DbOwner.store); } -function createInstanceStore(db: IDBDatabase) : void { +function createInstanceStore(db: IDBDatabase): void { db.createObjectStore(DbInstance.store, { keyPath: DbInstance.keyPath as KeyPath }); } -function createMutationQueue(db: IDBDatabase) : void { +function createMutationQueue(db: IDBDatabase): void { db.createObjectStore(DbMutationQueue.store, { keyPath: DbMutationQueue.keyPath }); - db.createObjectStore( - DbMutationBatch.store, - { keyPath: DbMutationBatch.keyPath as KeyPath } - ); + db.createObjectStore(DbMutationBatch.store, { + keyPath: DbMutationBatch.keyPath as KeyPath + }); // NOTE: keys for these stores are specified explicitly rather than using a // keyPath. @@ -86,9 +89,19 @@ function createMutationQueue(db: IDBDatabase) : void { * Runs any migrations needed to bring the given database up to the current * schema version. */ -export function createOrUpgradeDb(db: IDBDatabase, oldVersion: number, newVersion: number): void { - assert(oldVersion >= 0 || oldVersion <= 1, 'Unexpected upgrade from version ' + oldVersion); - assert(newVersion >= 1 || newVersion <= 2, 'Unexpected upgrade to version ' + newVersion); +export function createOrUpgradeDb( + db: IDBDatabase, + oldVersion: number, + newVersion: number +): void { + assert( + oldVersion >= 0 || oldVersion <= 1, + 'Unexpected upgrade from version ' + oldVersion + ); + assert( + newVersion >= 1 || newVersion <= 2, + 'Unexpected upgrade to version ' + newVersion + ); const createV1 = newVersion >= 1 && oldVersion <= 1; const dropV1 = oldVersion >= 1; @@ -107,4 +120,4 @@ export function createOrUpgradeDb(db: IDBDatabase, oldVersion: number, newVersio if (createV2) { createInstanceStore(db); } -} \ No newline at end of file +} diff --git a/packages/firestore/src/local/indexeddb_persistence.ts b/packages/firestore/src/local/indexeddb_persistence.ts index 54abbdb40ae..6b7f5b26c7e 100644 --- a/packages/firestore/src/local/indexeddb_persistence.ts +++ b/packages/firestore/src/local/indexeddb_persistence.ts @@ -34,7 +34,7 @@ import { PersistencePromise } from './persistence_promise'; import { QueryCache } from './query_cache'; import { RemoteDocumentCache } from './remote_document_cache'; import { SimpleDb, SimpleDbTransaction } from './simple_db'; -import {createOrUpgradeDb} from './indexeddb_migrations'; +import { createOrUpgradeDb } from './indexeddb_migrations'; const LOG_TAG = 'IndexedDbPersistence'; diff --git a/packages/firestore/src/local/indexeddb_schema.ts b/packages/firestore/src/local/indexeddb_schema.ts index 4e147bbea22..619b175a6b8 100644 --- a/packages/firestore/src/local/indexeddb_schema.ts +++ b/packages/firestore/src/local/indexeddb_schema.ts @@ -21,7 +21,7 @@ import { ResourcePath } from '../model/path'; import { assert } from '../util/assert'; import { encode, EncodedResourcePath } from './encoded_resource_path'; -import {SnapshotVersion} from '../core/snapshot_version'; +import { SnapshotVersion } from '../core/snapshot_version'; export const SCHEMA_VERSION = 1; @@ -88,14 +88,13 @@ export class DbMutationQueue { * only a single stream token is retained. */ public lastStreamToken: string, - /** * An identifier for the highest numbered batch that has been acknowledged * by the server. All MutationBatches in this queue with batchIds less * than or equal to this value are considered to have been acknowledged by * the server. */ - public highestPendingBatchId: number, + public highestPendingBatchId: number ) {} } @@ -368,7 +367,6 @@ export class DbTargetDocument { * The targetId identifying a target. */ public targetId: TargetId, - public snapshotVersion: number, /** * The path to the document, as encoded in the key. @@ -429,9 +427,9 @@ export class DbInstance { static keyPath = ['userId', 'instanceId']; constructor( - public userId: string, - public instanceId: string, - public updateTimeMs: number + public userId: string, + public instanceId: string, + public updateTimeMs: number ) {} } diff --git a/packages/firestore/src/local/simple_db.ts b/packages/firestore/src/local/simple_db.ts index 2a925ead624..c7f7ff87d98 100644 --- a/packages/firestore/src/local/simple_db.ts +++ b/packages/firestore/src/local/simple_db.ts @@ -19,7 +19,7 @@ import { debug } from '../util/log'; import { AnyDuringMigration } from '../util/misc'; import { PersistencePromise } from './persistence_promise'; -import {SCHEMA_VERSION} from './indexeddb_schema'; +import { SCHEMA_VERSION } from './indexeddb_schema'; const LOG_TAG = 'SimpleDb'; @@ -35,7 +35,11 @@ export class SimpleDb { static openOrCreate( name: string, version: number, - runUpgrade: (db: IDBDatabase, oldVersion: number, newVersion: number) => void + runUpgrade: ( + db: IDBDatabase, + oldVersion: number, + newVersion: number + ) => void ): Promise { assert( SimpleDb.isAvailable(), From 5e8478245bf434f96d3e81deca7d13ffc9e2bbc1 Mon Sep 17 00:00:00 2001 From: Sebastian Schmidt Date: Sun, 4 Feb 2018 20:15:54 -0800 Subject: [PATCH 04/22] IndexedDb Schema Migration --- .../src/local/indexeddb_migrations.ts | 123 -------- .../src/local/indexeddb_persistence.ts | 10 +- .../firestore/src/local/indexeddb_schema.ts | 264 ++++++++++++++---- packages/firestore/src/local/simple_db.ts | 4 +- .../test/unit/local/schema_migration.test.ts | 107 +++++++ 5 files changed, 320 insertions(+), 188 deletions(-) delete mode 100644 packages/firestore/src/local/indexeddb_migrations.ts create mode 100644 packages/firestore/test/unit/local/schema_migration.test.ts diff --git a/packages/firestore/src/local/indexeddb_migrations.ts b/packages/firestore/src/local/indexeddb_migrations.ts deleted file mode 100644 index faac5951c44..00000000000 --- a/packages/firestore/src/local/indexeddb_migrations.ts +++ /dev/null @@ -1,123 +0,0 @@ -/** - * Copyright 2018 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -import { - DbDocumentMutation, - DbInstance, - DbMutationBatch, - DbMutationQueue, - DbOwner, - DbRemoteDocument, - DbTarget, - DbTargetDocument, - DbTargetGlobal -} from './indexeddb_schema'; -import { assert, fail } from '../util/assert'; - -// TODO(mikelehen): Get rid of "as any" if/when TypeScript fixes their types. -// https://github.com/Microsoft/TypeScript/issues/14322 -type KeyPath = any; // tslint:disable-line:no-any - -function createCache(db: IDBDatabase): void { - const targetDocumentsStore = db.createObjectStore(DbTargetDocument.store, { - keyPath: DbTargetDocument.keyPath as KeyPath - }); - targetDocumentsStore.createIndex( - DbTargetDocument.documentTargetsIndex, - DbTargetDocument.documentTargetsKeyPath, - { unique: true } - ); - - const targetStore = db.createObjectStore(DbTarget.store, { - keyPath: DbTarget.keyPath - }); - - // NOTE: This is unique only because the TargetId is the suffix. - targetStore.createIndex( - DbTarget.queryTargetsIndexName, - DbTarget.queryTargetsKeyPath, - { unique: true } - ); - db.createObjectStore(DbRemoteDocument.store); - db.createObjectStore(DbTargetGlobal.store); -} - -function dropCache(db: IDBDatabase): void { - db.deleteObjectStore(DbTargetDocument.store); - db.deleteObjectStore(DbTarget.keyPath); - db.deleteObjectStore(DbRemoteDocument.store); - db.deleteObjectStore(DbTargetGlobal.store); -} - -function createOwnerStore(db: IDBDatabase): void { - db.createObjectStore(DbOwner.store); -} - -function createInstanceStore(db: IDBDatabase): void { - db.createObjectStore(DbInstance.store, { - keyPath: DbInstance.keyPath as KeyPath - }); -} - -function createMutationQueue(db: IDBDatabase): void { - db.createObjectStore(DbMutationQueue.store, { - keyPath: DbMutationQueue.keyPath - }); - - db.createObjectStore(DbMutationBatch.store, { - keyPath: DbMutationBatch.keyPath as KeyPath - }); - - // NOTE: keys for these stores are specified explicitly rather than using a - // keyPath. - db.createObjectStore(DbDocumentMutation.store); -} - -/** - * Runs any migrations needed to bring the given database up to the current - * schema version. - */ -export function createOrUpgradeDb( - db: IDBDatabase, - oldVersion: number, - newVersion: number -): void { - assert( - oldVersion >= 0 || oldVersion <= 1, - 'Unexpected upgrade from version ' + oldVersion - ); - assert( - newVersion >= 1 || newVersion <= 2, - 'Unexpected upgrade to version ' + newVersion - ); - - const createV1 = newVersion >= 1 && oldVersion <= 1; - const dropV1 = oldVersion >= 1; - const createV2 = newVersion >= 2 && oldVersion <= 2; - - if (dropV1) { - dropCache(db); - } - - if (createV1) { - createOwnerStore(db); - createMutationQueue(db); - createCache(db); - } - - if (createV2) { - createInstanceStore(db); - } -} diff --git a/packages/firestore/src/local/indexeddb_persistence.ts b/packages/firestore/src/local/indexeddb_persistence.ts index 6b7f5b26c7e..b09548e5e2b 100644 --- a/packages/firestore/src/local/indexeddb_persistence.ts +++ b/packages/firestore/src/local/indexeddb_persistence.ts @@ -25,8 +25,13 @@ import { AutoId } from '../util/misc'; import { IndexedDbMutationQueue } from './indexeddb_mutation_queue'; import { IndexedDbQueryCache } from './indexeddb_query_cache'; import { IndexedDbRemoteDocumentCache } from './indexeddb_remote_document_cache'; -import { ALL_STORES, DbOwner, DbOwnerKey } from './indexeddb_schema'; -import { SCHEMA_VERSION } from './indexeddb_schema'; +import { + ALL_STORES, + createOrUpgradeDb, + DbOwner, + DbOwnerKey, + SCHEMA_VERSION +} from './indexeddb_schema'; import { LocalSerializer } from './local_serializer'; import { MutationQueue } from './mutation_queue'; import { Persistence } from './persistence'; @@ -34,7 +39,6 @@ import { PersistencePromise } from './persistence_promise'; import { QueryCache } from './query_cache'; import { RemoteDocumentCache } from './remote_document_cache'; import { SimpleDb, SimpleDbTransaction } from './simple_db'; -import { createOrUpgradeDb } from './indexeddb_migrations'; const LOG_TAG = 'IndexedDbPersistence'; diff --git a/packages/firestore/src/local/indexeddb_schema.ts b/packages/firestore/src/local/indexeddb_schema.ts index 619b175a6b8..89a0fb4f817 100644 --- a/packages/firestore/src/local/indexeddb_schema.ts +++ b/packages/firestore/src/local/indexeddb_schema.ts @@ -21,9 +21,38 @@ import { ResourcePath } from '../model/path'; import { assert } from '../util/assert'; import { encode, EncodedResourcePath } from './encoded_resource_path'; -import { SnapshotVersion } from '../core/snapshot_version'; -export const SCHEMA_VERSION = 1; +export const SCHEMA_VERSION = 2; + +/** + * Performs database creation and schema migrations up to schema version 2. + */ +export function createOrUpgradeDb( + db: IDBDatabase, + fromVersion: number, + toVersion: number +): void { + assert( + fromVersion < toVersion && fromVersion >= 0 && toVersion <= 2, + 'Unexpected schema upgrade from v${fromVersion} to v{toVersion}.' + ); + + if (toVersion === 2) { + createInstanceMetadataStore(db); + createTargetChangeStore(db); + } + + if (fromVersion == 0 && toVersion >= 1) { + createOwnerStore(db); + createMutationQueue(db); + createQueryCache(db); + createRemoteDocumentCache(db); + } +} + +// TODO(mikelehen): Get rid of "as any" if/when TypeScript fixes their types. +// https://github.com/Microsoft/TypeScript/issues/14322 +type KeyPath = any; // tslint:disable-line:no-any /** * Wrapper class to store timestamps (seconds and nanos) in IndexedDb objects. @@ -50,6 +79,10 @@ export class DbOwner { constructor(public ownerId: string, public leaseTimestampMs: number) {} } +function createOwnerStore(db: IDBDatabase): void { + db.createObjectStore(DbOwner.store); +} + /** Object keys in the 'mutationQueues' store are userId strings. */ export type DbMutationQueueKey = string; @@ -68,18 +101,19 @@ export class DbMutationQueue { constructor( /** - * The normalized user ID to which this queue belongs. + * @param userId - The normalized user ID to which this queue belongs. */ public userId: string, /** - * An identifier for the highest numbered batch that has been acknowledged - * by the server. All MutationBatches in this queue with batchIds less - * than or equal to this value are considered to have been acknowledged by - * the server. + * @param lastAcknowledgedBatchId - An identifier for the highest numbered + * batch that has been acknowledged by the server. All MutationBatches in + * this queue with batchIds less than or equal to this value are considered + * to have been acknowledged by the server. */ public lastAcknowledgedBatchId: number, /** - * A stream token that was previously sent by the server. + * @param lastStreamToken - A stream token that was previously sent by the + * server. * * See StreamingWriteRequest in datastore.proto for more details about * usage. @@ -89,10 +123,11 @@ export class DbMutationQueue { */ public lastStreamToken: string, /** - * An identifier for the highest numbered batch that has been acknowledged - * by the server. All MutationBatches in this queue with batchIds less - * than or equal to this value are considered to have been acknowledged by - * the server. + * @param highestPendingBatchId - An identifier for the highest numbered + * batch in the mutation queue. This allows for efficient insert of new + * batches without relying on in-memory state. + * + * PORTING NOTE: iOS and Android clients keep this value in-memory. */ public highestPendingBatchId: number ) {} @@ -117,21 +152,22 @@ export class DbMutationBatch { constructor( /** - * The normalized user ID to which this batch belongs. + * @userId userId - The normalized user ID to which this batch belongs. */ public userId: string, /** - * An identifier for this batch, allocated by the mutation queue in a - * monotonically increasing manner. + * @batchId batchId - An identifier for this batch, allocated by the + * mutation queue in a monotonically increasing manner. */ public batchId: BatchId, /** - * The local write time of the batch, stored as milliseconds since the - * epoch. + * @param localWriteTimeMs - The local write time of the batch, stored as + * milliseconds since the epoch. */ public localWriteTimeMs: number, /** - * A list of mutations to apply. All mutations will be applied atomically. + * @param mutations - A list of mutations to apply. All mutations will be + * applied atomically. * * Mutations are serialized via JsonProtoSerializer.toMutation(). */ @@ -146,6 +182,20 @@ export class DbMutationBatch { */ export type DbDocumentMutationKey = [string, EncodedResourcePath, BatchId]; +function createMutationQueue(db: IDBDatabase): void { + db.createObjectStore(DbMutationQueue.store, { + keyPath: DbMutationQueue.keyPath + }); + + db.createObjectStore(DbMutationBatch.store, { + keyPath: DbMutationBatch.keyPath as KeyPath + }); + + // NOTE: keys for these stores are specified explicitly rather than using a + // keyPath. + db.createObjectStore(DbDocumentMutation.store); +} + /** * An object to be stored in the 'documentMutations' store in IndexedDb. * @@ -204,6 +254,10 @@ export class DbDocumentMutation { */ export type DbRemoteDocumentKey = string[]; +function createRemoteDocumentCache(db: IDBDatabase): void { + db.createObjectStore(DbRemoteDocument.store); +} + /** * Represents the known absence of a document at a particular version. * Stored in IndexedDb as part of a DbRemoteDocument object. @@ -225,13 +279,13 @@ export class DbRemoteDocument { constructor( /** - * Set to an instance of a DbNoDocument if it is known that no document - * exists. + * @param noDocument - Set to an instance of a DbNoDocument if it is known + * that no document exists. */ public noDocument: DbNoDocument | null, /** - * Set to an instance of a Document if there's a cached version of the - * document. + * @param document - Set to an instance of a Document if there's a cached + * version of the document. */ public document: api.Document | null ) {} @@ -276,7 +330,8 @@ export class DbTarget { constructor( /** - * An auto-generated sequential numeric identifier for the query. + * @param targetId - An auto-generated sequential numeric identifier for the + * query. * * Queries are stored using their canonicalId as the key, but these * canonicalIds can be quite long so we additionally assign a unique @@ -285,20 +340,23 @@ export class DbTarget { */ public targetId: TargetId, /** - * The canonical string representing this query. This is not unique. + * @param canonicalId - The canonical string representing this query. This + * is not unique. */ public canonicalId: string, /** - * The last readTime received from the Watch Service for this query. + * @param readTime - The last readTime received from the Watch Service for + * this query. * * This is the same value as TargetChange.read_time in the protos. */ public readTime: DbTimestamp, /** - * An opaque, server-assigned token that allows watching a query to be - * resumed after disconnecting without retransmitting all the data - * that matches the query. The resume token essentially identifies a - * point in time from which the server should resume sending results. + * @param resumeToken - An opaque, server-assigned token that allows + * watching a query to be resumed after disconnecting without retransmitting + * all the data that matches the query. The resume token essentially + * identifies a point in time from which the server should resume sending + * results. * * This is related to the snapshotVersion in that the resumeToken * effectively also encodes that value, but the resumeToken is opaque @@ -313,8 +371,9 @@ export class DbTarget { */ public resumeToken: string, /** - * A sequence number representing the last time this query was - * listened to, used for garbage collection purposes. + * @param lastListenSequenceNumber - A sequence number representing the + * last time this query was listened to, used for garbage collection + * purposes. * * Conventionally this would be a timestamp value, but device-local * clocks are unreliable and they must be able to create new listens @@ -328,7 +387,7 @@ export class DbTarget { */ public lastListenSequenceNumber: number, /** - * The query for this target. + * @param query - The query for this target. * * Because canonical ids are not unique we must store the actual query. We * use the proto to have an object we can persist without having to @@ -353,8 +412,8 @@ export class DbTargetDocument { /** Name of the IndexedDb object store. */ static store = 'targetDocuments'; - /** Keys are automatically assigned via the targetId, snapshotVersion, and path properties. */ - static keyPath = ['targetId', 'snapshotVersion', 'path']; + /** Keys are automatically assigned via the targetId, path properties. */ + static keyPath = ['targetId', 'path']; /** The index name for the reverse index. */ static documentTargetsIndex = 'documentTargetsIndex'; @@ -364,12 +423,11 @@ export class DbTargetDocument { constructor( /** - * The targetId identifying a target. + * @param targetId - The targetId identifying a target. */ public targetId: TargetId, - public snapshotVersion: number, /** - * The path to the document, as encoded in the key. + * @param path - The path to the document, as encoded in the key. */ public path: EncodedResourcePath ) {} @@ -396,55 +454,141 @@ export class DbTargetGlobal { constructor( /** - * The highest numbered target id across all targets. + * @param highestTargetId - The highest numbered target id across all + * targets. * * See DbTarget.targetId. */ public highestTargetId: TargetId, /** - * The highest numbered lastListenSequenceNumber across all targets. + * @param highestListenSequenceNumber - The highest numbered + * lastListenSequenceNumber across all targets. * * See DbTarget.lastListenSequenceNumber. */ public highestListenSequenceNumber: number, /** - * A global snapshot version representing the last consistent snapshot we - * received from the backend. This is monotonically increasing and any - * snapshots received from the backend prior to this version (e.g. for - * targets resumed with a resumeToken) should be suppressed (buffered) - * until the backend has caught up to this snapshot version again. This - * prevents our cache from ever going backwards in time. + * @param lastRemoteSnapshotVersion - A global snapshot version representing + * the last consistent snapshot we received from the backend. This is + * monotonically increasing and any snapshots received from the backend + * prior to this version (e.g. for targets resumed with a resumeToken) + * should be suppressed (buffered) until the backend has caught up to this + * snapshot version again. This prevents our cache from ever going backwards + * in time. */ public lastRemoteSnapshotVersion: DbTimestamp ) {} } -export type DbInstanceKey = [string, string]; +function createQueryCache(db: IDBDatabase): void { + const targetDocumentsStore = db.createObjectStore(DbTargetDocument.store, { + keyPath: DbTargetDocument.keyPath as KeyPath + }); + targetDocumentsStore.createIndex( + DbTargetDocument.documentTargetsIndex, + DbTargetDocument.documentTargetsKeyPath, + { unique: true } + ); + + const targetStore = db.createObjectStore(DbTarget.store, { + keyPath: DbTarget.keyPath + }); + + // NOTE: This is unique only because the TargetId is the suffix. + targetStore.createIndex( + DbTarget.queryTargetsIndexName, + DbTarget.queryTargetsKeyPath, + { unique: true } + ); + db.createObjectStore(DbTargetGlobal.store); +} -export class DbInstance { - static store = 'instances'; +/** + * An object representing the changes at a particular snapshot version for the + * given target. This is used to facilitate storing query changelogs in the + * targetChanges object store. + * + * PORTING NOTE: This is used for change propagation during multi-tab syncing + * and not needed on iOS and Android. + */ +export class DbTargetChange { + /** Name of the IndexedDb object store. */ + static store = 'targetChanges'; - static keyPath = ['userId', 'instanceId']; + /** Keys are automatically assigned via the targetId and snapshotVersion. */ + static keyPath = ['targetId', 'snapshotVersion']; constructor( - public userId: string, - public instanceId: string, - public updateTimeMs: number + /** + * @param targetId - The targetId identifying a target. + */ + public targetId: TargetId, + /** + * @param snapshotVersion - The snapshot version for this change. + */ + public snapshotVersion: DbTimestamp, + /** + * @param changes - The keys of the changed documents in this snapshot. + */ + public changes: { + added?: EncodedResourcePath[]; + modified?: EncodedResourcePath[]; + removed?: EncodedResourcePath[]; + } ) {} } +function createTargetChangeStore(db: IDBDatabase): void { + db.createObjectStore(DbTargetChange.store, { + keyPath: DbTargetChange.keyPath as KeyPath + }); +} + /** - * The list of all IndexedDB stored used by the SDK. This is used when creating - * transactions so that access across all stores is done atomically. + * A record of the metadata state of each instance. + * + * PORTING NOTE: This is used for primary-tab selection to support multi-tab + * persistence and does not need to be ported to iOS or Android. */ -export const ALL_STORES = [ +export class DbInstanceMetadata { + /** Name of the IndexedDb object store. */ + static store = 'instanceMetadata'; + + /** Keys are automatically assigned via the userId and instanceKey properties. */ + static keyPath = ['userId', 'instanceKey']; + + constructor( + /** userId - The normalized user ID to which this batch belongs.*/ + public userId: string, + /** instanceKey - The auto-generated instance key assigned at client startup. */ + public instanceKey: string, + /** updateTimeMs - The last time this state was updated. */ + public updateTimeMs: DbTimestamp + ) {} +} + +function createInstanceMetadataStore(db: IDBDatabase): void { + db.createObjectStore(DbInstanceMetadata.store, { + keyPath: DbInstanceMetadata.keyPath as KeyPath + }); +} + +// Exported for testing. +export const V1_STORES = [ + DbDocumentMutation.store, DbMutationQueue.store, DbMutationBatch.store, - DbDocumentMutation.store, - DbRemoteDocument.store, - DbTarget.store, DbOwner.store, - DbTargetGlobal.store, + DbRemoteDocument.store, DbTargetDocument.store, - DbInstance.store + DbTargetGlobal.store, + DbTarget.store ]; + +const SCHEMA_V2_STORES = [DbInstanceMetadata.store, DbTargetChange.store]; + +/** + * The list of all IndexedDB stored used by the SDK. This is used when creating + * transactions so that access across all stores is done atomically. + */ +export const ALL_STORES = [...V1_STORES, ...SCHEMA_V2_STORES]; diff --git a/packages/firestore/src/local/simple_db.ts b/packages/firestore/src/local/simple_db.ts index c7f7ff87d98..8adbcad37d5 100644 --- a/packages/firestore/src/local/simple_db.ts +++ b/packages/firestore/src/local/simple_db.ts @@ -37,8 +37,8 @@ export class SimpleDb { version: number, runUpgrade: ( db: IDBDatabase, - oldVersion: number, - newVersion: number + fromVersion: number, + toVersion: number ) => void ): Promise { assert( diff --git a/packages/firestore/test/unit/local/schema_migration.test.ts b/packages/firestore/test/unit/local/schema_migration.test.ts new file mode 100644 index 00000000000..8b5d1671a0b --- /dev/null +++ b/packages/firestore/test/unit/local/schema_migration.test.ts @@ -0,0 +1,107 @@ +/** + * Copyright 2018 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { expect } from 'chai'; +import { IndexedDbMutationQueue } from '../../../src/local/indexeddb_mutation_queue'; +import { IndexedDbPersistence } from '../../../src/local/indexeddb_persistence'; +import { + ALL_STORES, + createOrUpgradeDb, + V1_STORES +} from '../../../src/local/indexeddb_schema'; +import { Deferred } from '../../../src/util/promise'; + +const INDEXEDDB_TEST_DATABASE = 'schemaTest'; + +function deleteDb() { + const deferred = new Deferred(); + + const request = window.indexedDB.deleteDatabase(INDEXEDDB_TEST_DATABASE); + request.onsuccess = (event: Event) => { + deferred.resolve(); + }; + request.onerror = (event: ErrorEvent) => { + deferred.reject((event.target as IDBOpenDBRequest).error); + }; + + return deferred; +} + +function initDb(targetVersion) { + const deferred = new Deferred(); + + const request = window.indexedDB.open(INDEXEDDB_TEST_DATABASE, targetVersion); + request.onsuccess = (event: Event) => { + const db = (event.target as IDBOpenDBRequest).result; + deferred.resolve(db); + }; + request.onerror = (event: ErrorEvent) => { + deferred.reject((event.target as IDBOpenDBRequest).error); + }; + request.onupgradeneeded = (event: IDBVersionChangeEvent) => { + const db = (event.target as IDBOpenDBRequest).result; + createOrUpgradeDb(db, event.oldVersion, targetVersion); + }; + + return deferred.promise; +} + +function getAllObjectStores(db: IDBDatabase): String[] { + const objectStores: String[] = []; + for (let i = 0; i < db.objectStoreNames.length; ++i) { + objectStores.push(db.objectStoreNames.item(i)); + } + objectStores.sort(); + return objectStores; +} + +// Sorting these arrays directly should not affect the functionality of the SDK. +V1_STORES.sort(); +ALL_STORES.sort(); + +describe('SchemaMigration', () => { + if (!IndexedDbPersistence.isAvailable()) { + console.warn('No IndexedDB. Skipping IndexedDbMutationQueue tests.'); + return; + } + + beforeEach(() => { + return deleteDb(); + }); + + it('can install schema version 1', () => { + return initDb(1).then(db => { + expect(db.version).to.be.equal(1); + expect(getAllObjectStores(db)).to.deep.equal(V1_STORES); + }); + }); + + it('can install schema version 2', () => { + return initDb(2).then(db => { + expect(db.version).to.be.equal(2); + expect(getAllObjectStores(db)).to.deep.equal(ALL_STORES); + }); + }); + + it('can upgrade from schema version 1 to 2', () => { + return initDb(1) + .then(() => initDb(2)) + .then(db => { + expect(db.version).to.be.equal(2); + expect(getAllObjectStores(db)).to.deep.equal(ALL_STORES); + }); + }); +}); From fd5030170f404b65eb228cd7f822186ff6964c99 Mon Sep 17 00:00:00 2001 From: Sebastian Schmidt Date: Tue, 6 Feb 2018 10:46:40 -0800 Subject: [PATCH 05/22] Lint cleanup --- packages/firestore/src/local/indexeddb_schema.ts | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/packages/firestore/src/local/indexeddb_schema.ts b/packages/firestore/src/local/indexeddb_schema.ts index 89a0fb4f817..2b64538e9ed 100644 --- a/packages/firestore/src/local/indexeddb_schema.ts +++ b/packages/firestore/src/local/indexeddb_schema.ts @@ -42,7 +42,7 @@ export function createOrUpgradeDb( createTargetChangeStore(db); } - if (fromVersion == 0 && toVersion >= 1) { + if (fromVersion === 0 && toVersion >= 1) { createOwnerStore(db); createMutationQueue(db); createQueryCache(db); @@ -129,7 +129,7 @@ export class DbMutationQueue { * * PORTING NOTE: iOS and Android clients keep this value in-memory. */ - public highestPendingBatchId: number + public highestPendingBatchId?: number ) {} } @@ -558,11 +558,14 @@ export class DbInstanceMetadata { static keyPath = ['userId', 'instanceKey']; constructor( - /** userId - The normalized user ID to which this batch belongs.*/ + /** @param userId - The normalized user ID to which this batch belongs. */ public userId: string, - /** instanceKey - The auto-generated instance key assigned at client startup. */ + /** + * @param instanceKey - The auto-generated instance key assigned at client + * startup. + */ public instanceKey: string, - /** updateTimeMs - The last time this state was updated. */ + /** @param updateTimeMs - The last time this state was updated. */ public updateTimeMs: DbTimestamp ) {} } From be3b46358d087e309feb6c03e5cfbc5e90f71785 Mon Sep 17 00:00:00 2001 From: Sebastian Schmidt Date: Tue, 6 Feb 2018 13:08:47 -0800 Subject: [PATCH 06/22] Removing unused import --- packages/firestore/test/unit/local/schema_migration.test.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/firestore/test/unit/local/schema_migration.test.ts b/packages/firestore/test/unit/local/schema_migration.test.ts index 8b5d1671a0b..099ce80c2bc 100644 --- a/packages/firestore/test/unit/local/schema_migration.test.ts +++ b/packages/firestore/test/unit/local/schema_migration.test.ts @@ -15,7 +15,6 @@ */ import { expect } from 'chai'; -import { IndexedDbMutationQueue } from '../../../src/local/indexeddb_mutation_queue'; import { IndexedDbPersistence } from '../../../src/local/indexeddb_persistence'; import { ALL_STORES, From de237c5fd601bed1dc2bcd11910340a320cf3a32 Mon Sep 17 00:00:00 2001 From: Sebastian Schmidt Date: Tue, 6 Feb 2018 14:20:25 -0800 Subject: [PATCH 07/22] Removing user ID from instance row --- packages/firestore/src/local/indexeddb_schema.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/firestore/src/local/indexeddb_schema.ts b/packages/firestore/src/local/indexeddb_schema.ts index 2b64538e9ed..61507b56965 100644 --- a/packages/firestore/src/local/indexeddb_schema.ts +++ b/packages/firestore/src/local/indexeddb_schema.ts @@ -558,15 +558,18 @@ export class DbInstanceMetadata { static keyPath = ['userId', 'instanceKey']; constructor( - /** @param userId - The normalized user ID to which this batch belongs. */ - public userId: string, /** * @param instanceKey - The auto-generated instance key assigned at client * startup. */ public instanceKey: string, /** @param updateTimeMs - The last time this state was updated. */ - public updateTimeMs: DbTimestamp + public updateTimeMs: DbTimestamp, + /** + * @param isInForeground - Whether the instance is known to run in a + * foreground tab. + */ + public isInForeground: boolean, ) {} } From 53e56b5c08e87f5f345720230cd47433d59c78b9 Mon Sep 17 00:00:00 2001 From: Sebastian Schmidt Date: Tue, 6 Feb 2018 14:21:22 -0800 Subject: [PATCH 08/22] [AUTOMATED]: Prettier Code Styling --- packages/firestore/src/local/indexeddb_schema.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/firestore/src/local/indexeddb_schema.ts b/packages/firestore/src/local/indexeddb_schema.ts index 61507b56965..fe82b832b3b 100644 --- a/packages/firestore/src/local/indexeddb_schema.ts +++ b/packages/firestore/src/local/indexeddb_schema.ts @@ -569,7 +569,7 @@ export class DbInstanceMetadata { * @param isInForeground - Whether the instance is known to run in a * foreground tab. */ - public isInForeground: boolean, + public isInForeground: boolean ) {} } From 7b3bedb35ad7bea42a994d2d5367cc051857ddba Mon Sep 17 00:00:00 2001 From: Sebastian Schmidt Date: Wed, 7 Feb 2018 11:28:50 -0800 Subject: [PATCH 09/22] Review comments --- .../src/local/indexeddb_persistence.ts | 4 +- .../firestore/src/local/indexeddb_schema.ts | 168 ++++++++---------- packages/firestore/src/local/simple_db.ts | 4 +- .../test/unit/local/schema_migration.test.ts | 33 +--- 4 files changed, 89 insertions(+), 120 deletions(-) diff --git a/packages/firestore/src/local/indexeddb_persistence.ts b/packages/firestore/src/local/indexeddb_persistence.ts index b09548e5e2b..451bac4585e 100644 --- a/packages/firestore/src/local/indexeddb_persistence.ts +++ b/packages/firestore/src/local/indexeddb_persistence.ts @@ -30,7 +30,7 @@ import { createOrUpgradeDb, DbOwner, DbOwnerKey, - SCHEMA_VERSION + DEFAULT_SCHEMA_VERSION } from './indexeddb_schema'; import { LocalSerializer } from './local_serializer'; import { MutationQueue } from './mutation_queue'; @@ -132,7 +132,7 @@ export class IndexedDbPersistence implements Persistence { assert(!this.started, 'IndexedDbPersistence double-started!'); this.started = true; - return SimpleDb.openOrCreate(this.dbName, SCHEMA_VERSION, createOrUpgradeDb) + return SimpleDb.openOrCreate(this.dbName, DEFAULT_SCHEMA_VERSION, createOrUpgradeDb) .then(db => { this.simpleDb = db; }) diff --git a/packages/firestore/src/local/indexeddb_schema.ts b/packages/firestore/src/local/indexeddb_schema.ts index fe82b832b3b..655c90febda 100644 --- a/packages/firestore/src/local/indexeddb_schema.ts +++ b/packages/firestore/src/local/indexeddb_schema.ts @@ -21,33 +21,45 @@ import { ResourcePath } from '../model/path'; import { assert } from '../util/assert'; import { encode, EncodedResourcePath } from './encoded_resource_path'; +import {IndexedDbMutationQueue} from './indexeddb_mutation_queue'; +import {SimpleDb} from './simple_db'; -export const SCHEMA_VERSION = 2; +/** + * Schema version containing the Mutation Queue, the Query and the Remote + * Document Cache. + */ +export const DEFAULT_SCHEMA_VERSION = 1; /** - * Performs database creation and schema migrations up to schema version 2. + * Performs database creation and schema upgrades. + * + * Note that in production, this method is only ever used to upgrade the schema + * to DEFAULT_SCHEMA_VERSION. Different versions are only used for testing and + * local feature development. */ export function createOrUpgradeDb( db: IDBDatabase, fromVersion: number, toVersion: number ): void { + // This function currently supports migrating to schema version 1 (Mutation + // Queue, Query and Remote Document Cache) and schema version 2 (Multi-Tab). assert( fromVersion < toVersion && fromVersion >= 0 && toVersion <= 2, 'Unexpected schema upgrade from v${fromVersion} to v{toVersion}.' ); - if (toVersion === 2) { - createInstanceMetadataStore(db); - createTargetChangeStore(db); - } - - if (fromVersion === 0 && toVersion >= 1) { + if (fromVersion < 1 && toVersion >= 1) { createOwnerStore(db); createMutationQueue(db); createQueryCache(db); createRemoteDocumentCache(db); } + + if (fromVersion < 2 && toVersion >= 2) { + createClientMetadataStore(db); + createTargetChangeStore(db); + } } // TODO(mikelehen): Get rid of "as any" if/when TypeScript fixes their types. @@ -101,19 +113,18 @@ export class DbMutationQueue { constructor( /** - * @param userId - The normalized user ID to which this queue belongs. + * The normalized user ID to which this queue belongs. */ public userId: string, /** - * @param lastAcknowledgedBatchId - An identifier for the highest numbered - * batch that has been acknowledged by the server. All MutationBatches in - * this queue with batchIds less than or equal to this value are considered - * to have been acknowledged by the server. + * An identifier for the highest numbered batch that has been acknowledged + * by the server. All MutationBatches in this queue with batchIds less + * than or equal to this value are considered to have been acknowledged by + * the server. */ public lastAcknowledgedBatchId: number, /** - * @param lastStreamToken - A stream token that was previously sent by the - * server. + * A stream token that was previously sent by the server. * * See StreamingWriteRequest in datastore.proto for more details about * usage. @@ -122,14 +133,6 @@ export class DbMutationQueue { * only a single stream token is retained. */ public lastStreamToken: string, - /** - * @param highestPendingBatchId - An identifier for the highest numbered - * batch in the mutation queue. This allows for efficient insert of new - * batches without relying on in-memory state. - * - * PORTING NOTE: iOS and Android clients keep this value in-memory. - */ - public highestPendingBatchId?: number ) {} } @@ -152,22 +155,21 @@ export class DbMutationBatch { constructor( /** - * @userId userId - The normalized user ID to which this batch belongs. + * The normalized user ID to which this batch belongs. */ public userId: string, /** - * @batchId batchId - An identifier for this batch, allocated by the - * mutation queue in a monotonically increasing manner. + * An identifier for this batch, allocated by the mutation queue in a + * monotonically increasing manner. */ public batchId: BatchId, /** - * @param localWriteTimeMs - The local write time of the batch, stored as - * milliseconds since the epoch. + * The local write time of the batch, stored as milliseconds since the + * epoch. */ public localWriteTimeMs: number, /** - * @param mutations - A list of mutations to apply. All mutations will be - * applied atomically. + * A list of mutations to apply. All mutations will be applied atomically. * * Mutations are serialized via JsonProtoSerializer.toMutation(). */ @@ -191,8 +193,6 @@ function createMutationQueue(db: IDBDatabase): void { keyPath: DbMutationBatch.keyPath as KeyPath }); - // NOTE: keys for these stores are specified explicitly rather than using a - // keyPath. db.createObjectStore(DbDocumentMutation.store); } @@ -279,13 +279,13 @@ export class DbRemoteDocument { constructor( /** - * @param noDocument - Set to an instance of a DbNoDocument if it is known - * that no document exists. + * Set to an instance of a DbNoDocument if it is known that no document + * exists. */ public noDocument: DbNoDocument | null, /** - * @param document - Set to an instance of a Document if there's a cached - * version of the document. + * Set to an instance of a Document if there's a cached version of the + * document. */ public document: api.Document | null ) {} @@ -330,8 +330,7 @@ export class DbTarget { constructor( /** - * @param targetId - An auto-generated sequential numeric identifier for the - * query. + * An auto-generated sequential numeric identifier for the query. * * Queries are stored using their canonicalId as the key, but these * canonicalIds can be quite long so we additionally assign a unique @@ -340,23 +339,20 @@ export class DbTarget { */ public targetId: TargetId, /** - * @param canonicalId - The canonical string representing this query. This - * is not unique. + * The canonical string representing this query. This is not unique. */ public canonicalId: string, /** - * @param readTime - The last readTime received from the Watch Service for - * this query. + * The last readTime received from the Watch Service for this query. * * This is the same value as TargetChange.read_time in the protos. */ public readTime: DbTimestamp, /** - * @param resumeToken - An opaque, server-assigned token that allows - * watching a query to be resumed after disconnecting without retransmitting - * all the data that matches the query. The resume token essentially - * identifies a point in time from which the server should resume sending - * results. + * An opaque, server-assigned token that allows watching a query to be + * resumed after disconnecting without retransmitting all the data + * that matches the query. The resume token essentially identifies a + * point in time from which the server should resume sending results. * * This is related to the snapshotVersion in that the resumeToken * effectively also encodes that value, but the resumeToken is opaque @@ -371,9 +367,8 @@ export class DbTarget { */ public resumeToken: string, /** - * @param lastListenSequenceNumber - A sequence number representing the - * last time this query was listened to, used for garbage collection - * purposes. + * A sequence number representing the last time this query was + * listened to, used for garbage collection purposes. * * Conventionally this would be a timestamp value, but device-local * clocks are unreliable and they must be able to create new listens @@ -387,7 +382,7 @@ export class DbTarget { */ public lastListenSequenceNumber: number, /** - * @param query - The query for this target. + * The query for this target. * * Because canonical ids are not unique we must store the actual query. We * use the proto to have an object we can persist without having to @@ -423,11 +418,11 @@ export class DbTargetDocument { constructor( /** - * @param targetId - The targetId identifying a target. + * The targetId identifying a target. */ public targetId: TargetId, /** - * @param path - The path to the document, as encoded in the key. + * The path to the document, as encoded in the key. */ public path: EncodedResourcePath ) {} @@ -454,27 +449,24 @@ export class DbTargetGlobal { constructor( /** - * @param highestTargetId - The highest numbered target id across all - * targets. + * The highest numbered target id across all targets. * * See DbTarget.targetId. */ public highestTargetId: TargetId, /** - * @param highestListenSequenceNumber - The highest numbered - * lastListenSequenceNumber across all targets. + * The highest numbered lastListenSequenceNumber across all targets. * * See DbTarget.lastListenSequenceNumber. */ public highestListenSequenceNumber: number, /** - * @param lastRemoteSnapshotVersion - A global snapshot version representing - * the last consistent snapshot we received from the backend. This is - * monotonically increasing and any snapshots received from the backend - * prior to this version (e.g. for targets resumed with a resumeToken) - * should be suppressed (buffered) until the backend has caught up to this - * snapshot version again. This prevents our cache from ever going backwards - * in time. + * A global snapshot version representing the last consistent snapshot we + * received from the backend. This is monotonically increasing and any + * snapshots received from the backend prior to this version (e.g. for + * targets resumed with a resumeToken) should be suppressed (buffered) + * until the backend has caught up to this snapshot version again. This + * prevents our cache from ever going backwards in time. */ public lastRemoteSnapshotVersion: DbTimestamp ) {} @@ -520,15 +512,15 @@ export class DbTargetChange { constructor( /** - * @param targetId - The targetId identifying a target. + * The targetId identifying a target. */ public targetId: TargetId, /** - * @param snapshotVersion - The snapshot version for this change. + * The snapshot version for this change. */ public snapshotVersion: DbTimestamp, /** - * @param changes - The keys of the changed documents in this snapshot. + * The keys of the changed documents in this snapshot. */ public changes: { added?: EncodedResourcePath[]; @@ -545,37 +537,31 @@ function createTargetChangeStore(db: IDBDatabase): void { } /** - * A record of the metadata state of each instance. + * A record of the metadata state of each client. * - * PORTING NOTE: This is used for primary-tab selection to support multi-tab - * persistence and does not need to be ported to iOS or Android. + * PORTING NOTE: This is used to synchronize multi-tab state and does not need + * to be ported to iOS or Android. */ -export class DbInstanceMetadata { +export class DbClientMetadata { /** Name of the IndexedDb object store. */ - static store = 'instanceMetadata'; + static store = 'clientMetadata'; - /** Keys are automatically assigned via the userId and instanceKey properties. */ - static keyPath = ['userId', 'instanceKey']; + /** Keys are automatically assigned via the clientKey properties. */ + static keyPath = ['clientKey']; constructor( - /** - * @param instanceKey - The auto-generated instance key assigned at client - * startup. - */ - public instanceKey: string, - /** @param updateTimeMs - The last time this state was updated. */ + /** The auto-generated client key assigned at client startup. */ + public clientKey: string, + /** The last time this state was updated. */ public updateTimeMs: DbTimestamp, - /** - * @param isInForeground - Whether the instance is known to run in a - * foreground tab. - */ - public isInForeground: boolean + /** Whether this client is running in a foreground tab. */ + public inForeground: boolean ) {} } -function createInstanceMetadataStore(db: IDBDatabase): void { - db.createObjectStore(DbInstanceMetadata.store, { - keyPath: DbInstanceMetadata.keyPath as KeyPath +function createClientMetadataStore(db: IDBDatabase): void { + db.createObjectStore(DbClientMetadata.store, { + keyPath: DbClientMetadata.keyPath as KeyPath }); } @@ -591,10 +577,10 @@ export const V1_STORES = [ DbTarget.store ]; -const SCHEMA_V2_STORES = [DbInstanceMetadata.store, DbTargetChange.store]; +const V2_STORES = [DbClientMetadata.store, DbTargetChange.store]; /** - * The list of all IndexedDB stored used by the SDK. This is used when creating + * The list of all IndexedDB stores used by the SDK. This is used when creating * transactions so that access across all stores is done atomically. */ -export const ALL_STORES = [...V1_STORES, ...SCHEMA_V2_STORES]; +export const ALL_STORES = [...V1_STORES, ...V2_STORES]; diff --git a/packages/firestore/src/local/simple_db.ts b/packages/firestore/src/local/simple_db.ts index 8adbcad37d5..d6f7e432681 100644 --- a/packages/firestore/src/local/simple_db.ts +++ b/packages/firestore/src/local/simple_db.ts @@ -19,7 +19,7 @@ import { debug } from '../util/log'; import { AnyDuringMigration } from '../util/misc'; import { PersistencePromise } from './persistence_promise'; -import { SCHEMA_VERSION } from './indexeddb_schema'; +import { DEFAULT_SCHEMA_VERSION } from './indexeddb_schema'; const LOG_TAG = 'SimpleDb'; @@ -75,7 +75,7 @@ export class SimpleDb { // cheating and just passing the raw IndexedDB in, since // createObjectStore(), etc. are synchronous. const db = (event.target as IDBOpenDBRequest).result; - runUpgrade(db, event.oldVersion, SCHEMA_VERSION); + runUpgrade(db, event.oldVersion, DEFAULT_SCHEMA_VERSION); }; }).toPromise(); } diff --git a/packages/firestore/test/unit/local/schema_migration.test.ts b/packages/firestore/test/unit/local/schema_migration.test.ts index 099ce80c2bc..3af4f5d4a82 100644 --- a/packages/firestore/test/unit/local/schema_migration.test.ts +++ b/packages/firestore/test/unit/local/schema_migration.test.ts @@ -22,24 +22,11 @@ import { V1_STORES } from '../../../src/local/indexeddb_schema'; import { Deferred } from '../../../src/util/promise'; +import {SimpleDb} from '../../../src/local/simple_db'; const INDEXEDDB_TEST_DATABASE = 'schemaTest'; -function deleteDb() { - const deferred = new Deferred(); - - const request = window.indexedDB.deleteDatabase(INDEXEDDB_TEST_DATABASE); - request.onsuccess = (event: Event) => { - deferred.resolve(); - }; - request.onerror = (event: ErrorEvent) => { - deferred.reject((event.target as IDBOpenDBRequest).error); - }; - - return deferred; -} - -function initDb(targetVersion) { +function initDb(targetVersion) : Promise { const deferred = new Deferred(); const request = window.indexedDB.open(INDEXEDDB_TEST_DATABASE, targetVersion); @@ -67,31 +54,27 @@ function getAllObjectStores(db: IDBDatabase): String[] { return objectStores; } -// Sorting these arrays directly should not affect the functionality of the SDK. -V1_STORES.sort(); -ALL_STORES.sort(); - -describe('SchemaMigration', () => { +describe('IndexedDbSchema: createOrUpgradeDb', () => { if (!IndexedDbPersistence.isAvailable()) { - console.warn('No IndexedDB. Skipping IndexedDbMutationQueue tests.'); + console.warn('No IndexedDB. Skipping createOrUpgradeDb() tests.'); return; } beforeEach(() => { - return deleteDb(); + return SimpleDb.delete(INDEXEDDB_TEST_DATABASE); }); it('can install schema version 1', () => { return initDb(1).then(db => { expect(db.version).to.be.equal(1); - expect(getAllObjectStores(db)).to.deep.equal(V1_STORES); + expect(getAllObjectStores(db)).to.have.members(V1_STORES); }); }); it('can install schema version 2', () => { return initDb(2).then(db => { expect(db.version).to.be.equal(2); - expect(getAllObjectStores(db)).to.deep.equal(ALL_STORES); + expect(getAllObjectStores(db)).to.have.members(ALL_STORES); }); }); @@ -100,7 +83,7 @@ describe('SchemaMigration', () => { .then(() => initDb(2)) .then(db => { expect(db.version).to.be.equal(2); - expect(getAllObjectStores(db)).to.deep.equal(ALL_STORES); + expect(getAllObjectStores(db)).to.have.members(ALL_STORES); }); }); }); From c176eff2aa7d17ac94c5d98c144de8695f56cd4b Mon Sep 17 00:00:00 2001 From: Sebastian Schmidt Date: Wed, 7 Feb 2018 11:29:40 -0800 Subject: [PATCH 10/22] Lint fixes --- packages/firestore/src/local/indexeddb_schema.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/firestore/src/local/indexeddb_schema.ts b/packages/firestore/src/local/indexeddb_schema.ts index 655c90febda..5536c008e60 100644 --- a/packages/firestore/src/local/indexeddb_schema.ts +++ b/packages/firestore/src/local/indexeddb_schema.ts @@ -21,8 +21,6 @@ import { ResourcePath } from '../model/path'; import { assert } from '../util/assert'; import { encode, EncodedResourcePath } from './encoded_resource_path'; -import {IndexedDbMutationQueue} from './indexeddb_mutation_queue'; -import {SimpleDb} from './simple_db'; /** * Schema version containing the Mutation Queue, the Query and the Remote From 9154aad4d605ef99680702c0e06b11e4bc19f702 Mon Sep 17 00:00:00 2001 From: Sebastian Schmidt Date: Wed, 7 Feb 2018 11:32:51 -0800 Subject: [PATCH 11/22] Review --- packages/firestore/src/local/indexeddb_schema.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/firestore/src/local/indexeddb_schema.ts b/packages/firestore/src/local/indexeddb_schema.ts index 5536c008e60..93ed7fa7d7f 100644 --- a/packages/firestore/src/local/indexeddb_schema.ts +++ b/packages/firestore/src/local/indexeddb_schema.ts @@ -23,8 +23,8 @@ import { assert } from '../util/assert'; import { encode, EncodedResourcePath } from './encoded_resource_path'; /** - * Schema version containing the Mutation Queue, the Query and the Remote - * Document Cache. + * Default Schema Version for the Web client (containing the Mutation Queue, the + * Query and the Remote Document Cache). */ export const DEFAULT_SCHEMA_VERSION = 1; @@ -130,7 +130,7 @@ export class DbMutationQueue { * After sending this token, earlier tokens may not be used anymore so * only a single stream token is retained. */ - public lastStreamToken: string, + public lastStreamToken: string ) {} } @@ -565,14 +565,14 @@ function createClientMetadataStore(db: IDBDatabase): void { // Exported for testing. export const V1_STORES = [ - DbDocumentMutation.store, DbMutationQueue.store, DbMutationBatch.store, - DbOwner.store, + DbDocumentMutation.store, DbRemoteDocument.store, - DbTargetDocument.store, + DbTarget.store, + DbOwner.store, DbTargetGlobal.store, - DbTarget.store + DbTargetDocument.store ]; const V2_STORES = [DbClientMetadata.store, DbTargetChange.store]; From 6b072ff3381b0cd315971c0aa7ebfb7dea0c37a0 Mon Sep 17 00:00:00 2001 From: Sebastian Schmidt Date: Wed, 7 Feb 2018 11:33:15 -0800 Subject: [PATCH 12/22] [AUTOMATED]: Prettier Code Styling --- packages/firestore/src/local/indexeddb_persistence.ts | 6 +++++- packages/firestore/test/unit/local/schema_migration.test.ts | 4 ++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/firestore/src/local/indexeddb_persistence.ts b/packages/firestore/src/local/indexeddb_persistence.ts index 451bac4585e..a56eaba98e4 100644 --- a/packages/firestore/src/local/indexeddb_persistence.ts +++ b/packages/firestore/src/local/indexeddb_persistence.ts @@ -132,7 +132,11 @@ export class IndexedDbPersistence implements Persistence { assert(!this.started, 'IndexedDbPersistence double-started!'); this.started = true; - return SimpleDb.openOrCreate(this.dbName, DEFAULT_SCHEMA_VERSION, createOrUpgradeDb) + return SimpleDb.openOrCreate( + this.dbName, + DEFAULT_SCHEMA_VERSION, + createOrUpgradeDb + ) .then(db => { this.simpleDb = db; }) diff --git a/packages/firestore/test/unit/local/schema_migration.test.ts b/packages/firestore/test/unit/local/schema_migration.test.ts index 3af4f5d4a82..c0cc75373b9 100644 --- a/packages/firestore/test/unit/local/schema_migration.test.ts +++ b/packages/firestore/test/unit/local/schema_migration.test.ts @@ -22,11 +22,11 @@ import { V1_STORES } from '../../../src/local/indexeddb_schema'; import { Deferred } from '../../../src/util/promise'; -import {SimpleDb} from '../../../src/local/simple_db'; +import { SimpleDb } from '../../../src/local/simple_db'; const INDEXEDDB_TEST_DATABASE = 'schemaTest'; -function initDb(targetVersion) : Promise { +function initDb(targetVersion): Promise { const deferred = new Deferred(); const request = window.indexedDB.open(INDEXEDDB_TEST_DATABASE, targetVersion); From 662365ff8c3b61a6cf74398270518406a584123f Mon Sep 17 00:00:00 2001 From: Sebastian Schmidt Date: Wed, 7 Feb 2018 11:53:09 -0800 Subject: [PATCH 13/22] Fixing the tests --- .../firestore/src/local/indexeddb_persistence.ts | 4 ++-- packages/firestore/src/local/indexeddb_schema.ts | 14 ++++++++++---- .../test/unit/local/schema_migration.test.ts | 6 +++--- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/packages/firestore/src/local/indexeddb_persistence.ts b/packages/firestore/src/local/indexeddb_persistence.ts index a56eaba98e4..d6e17708a93 100644 --- a/packages/firestore/src/local/indexeddb_persistence.ts +++ b/packages/firestore/src/local/indexeddb_persistence.ts @@ -26,7 +26,7 @@ import { IndexedDbMutationQueue } from './indexeddb_mutation_queue'; import { IndexedDbQueryCache } from './indexeddb_query_cache'; import { IndexedDbRemoteDocumentCache } from './indexeddb_remote_document_cache'; import { - ALL_STORES, + DEFAULT_STORES, createOrUpgradeDb, DbOwner, DbOwnerKey, @@ -181,7 +181,7 @@ export class IndexedDbPersistence implements Persistence { // Do all transactions as readwrite against all object stores, since we // are the only reader/writer. - return this.simpleDb.runTransaction('readwrite', ALL_STORES, txn => { + return this.simpleDb.runTransaction('readwrite', DEFAULT_STORES, txn => { // Verify that we still have the owner lease as part of every transaction. return this.ensureOwnerLease(txn).next(() => operation(txn)); }); diff --git a/packages/firestore/src/local/indexeddb_schema.ts b/packages/firestore/src/local/indexeddb_schema.ts index 93ed7fa7d7f..1cbafb87c22 100644 --- a/packages/firestore/src/local/indexeddb_schema.ts +++ b/packages/firestore/src/local/indexeddb_schema.ts @@ -563,8 +563,7 @@ function createClientMetadataStore(db: IDBDatabase): void { }); } -// Exported for testing. -export const V1_STORES = [ +const V1_STORES = [ DbMutationQueue.store, DbMutationBatch.store, DbDocumentMutation.store, @@ -578,7 +577,14 @@ export const V1_STORES = [ const V2_STORES = [DbClientMetadata.store, DbTargetChange.store]; /** - * The list of all IndexedDB stores used by the SDK. This is used when creating - * transactions so that access across all stores is done atomically. + * The list of all default IndexedDB stores used throughout the SDK. This is + * used when creating transactions so that access across all stores is done + * atomically. + */ +export const DEFAULT_STORES = V1_STORES; + +/** + * The list of all IndexedDb stores. This is only available in multi-tab enabled + * clients with the schema version 2. */ export const ALL_STORES = [...V1_STORES, ...V2_STORES]; diff --git a/packages/firestore/test/unit/local/schema_migration.test.ts b/packages/firestore/test/unit/local/schema_migration.test.ts index c0cc75373b9..f3f0f461759 100644 --- a/packages/firestore/test/unit/local/schema_migration.test.ts +++ b/packages/firestore/test/unit/local/schema_migration.test.ts @@ -17,9 +17,9 @@ import { expect } from 'chai'; import { IndexedDbPersistence } from '../../../src/local/indexeddb_persistence'; import { - ALL_STORES, + DEFAULT_STORES, createOrUpgradeDb, - V1_STORES + ALL_STORES } from '../../../src/local/indexeddb_schema'; import { Deferred } from '../../../src/util/promise'; import { SimpleDb } from '../../../src/local/simple_db'; @@ -67,7 +67,7 @@ describe('IndexedDbSchema: createOrUpgradeDb', () => { it('can install schema version 1', () => { return initDb(1).then(db => { expect(db.version).to.be.equal(1); - expect(getAllObjectStores(db)).to.have.members(V1_STORES); + expect(getAllObjectStores(db)).to.have.members(DEFAULT_STORES); }); }); From dd213769e1f3834a48db6fbeca53be1003ac7194 Mon Sep 17 00:00:00 2001 From: Sebastian Schmidt Date: Wed, 7 Feb 2018 17:51:11 -0800 Subject: [PATCH 14/22] Closing the Database in the Schema tests --- .../test/unit/local/schema_migration.test.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/firestore/test/unit/local/schema_migration.test.ts b/packages/firestore/test/unit/local/schema_migration.test.ts index f3f0f461759..9c6f9a0abb6 100644 --- a/packages/firestore/test/unit/local/schema_migration.test.ts +++ b/packages/firestore/test/unit/local/schema_migration.test.ts @@ -60,14 +60,13 @@ describe('IndexedDbSchema: createOrUpgradeDb', () => { return; } - beforeEach(() => { - return SimpleDb.delete(INDEXEDDB_TEST_DATABASE); - }); + beforeEach(() => SimpleDb.delete(INDEXEDDB_TEST_DATABASE)); it('can install schema version 1', () => { return initDb(1).then(db => { expect(db.version).to.be.equal(1); expect(getAllObjectStores(db)).to.have.members(DEFAULT_STORES); + db.close(); }); }); @@ -75,15 +74,20 @@ describe('IndexedDbSchema: createOrUpgradeDb', () => { return initDb(2).then(db => { expect(db.version).to.be.equal(2); expect(getAllObjectStores(db)).to.have.members(ALL_STORES); + db.close(); }); }); it('can upgrade from schema version 1 to 2', () => { return initDb(1) - .then(() => initDb(2)) + .then(db => { + db.close(); + return initDb(2) + }) .then(db => { expect(db.version).to.be.equal(2); expect(getAllObjectStores(db)).to.have.members(ALL_STORES); + db.close(); }); }); }); From 5e54b3a7ca2e71cdfbb8bf581fa3303c95cea51d Mon Sep 17 00:00:00 2001 From: Sebastian Schmidt Date: Wed, 7 Feb 2018 17:51:35 -0800 Subject: [PATCH 15/22] [AUTOMATED]: Prettier Code Styling --- packages/firestore/test/unit/local/schema_migration.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/firestore/test/unit/local/schema_migration.test.ts b/packages/firestore/test/unit/local/schema_migration.test.ts index 9c6f9a0abb6..56393f2634a 100644 --- a/packages/firestore/test/unit/local/schema_migration.test.ts +++ b/packages/firestore/test/unit/local/schema_migration.test.ts @@ -82,7 +82,7 @@ describe('IndexedDbSchema: createOrUpgradeDb', () => { return initDb(1) .then(db => { db.close(); - return initDb(2) + return initDb(2); }) .then(db => { expect(db.version).to.be.equal(2); From cb81df80da2f4dc3b03f52b55e5f92f2214a7243 Mon Sep 17 00:00:00 2001 From: Sebastian Schmidt Date: Wed, 7 Feb 2018 22:42:31 -0800 Subject: [PATCH 16/22] Changing test helper to close the DB --- .../test/unit/local/schema_migration.test.ts | 50 ++++++++----------- 1 file changed, 21 insertions(+), 29 deletions(-) diff --git a/packages/firestore/test/unit/local/schema_migration.test.ts b/packages/firestore/test/unit/local/schema_migration.test.ts index 56393f2634a..014d63fdf64 100644 --- a/packages/firestore/test/unit/local/schema_migration.test.ts +++ b/packages/firestore/test/unit/local/schema_migration.test.ts @@ -26,23 +26,23 @@ import { SimpleDb } from '../../../src/local/simple_db'; const INDEXEDDB_TEST_DATABASE = 'schemaTest'; -function initDb(targetVersion): Promise { - const deferred = new Deferred(); - - const request = window.indexedDB.open(INDEXEDDB_TEST_DATABASE, targetVersion); - request.onsuccess = (event: Event) => { - const db = (event.target as IDBOpenDBRequest).result; - deferred.resolve(db); - }; - request.onerror = (event: ErrorEvent) => { - deferred.reject((event.target as IDBOpenDBRequest).error); - }; - request.onupgradeneeded = (event: IDBVersionChangeEvent) => { - const db = (event.target as IDBOpenDBRequest).result; - createOrUpgradeDb(db, event.oldVersion, targetVersion); - }; - - return deferred.promise; +function withDb(schemaVersion, fn: (db: IDBDatabase) => void): Promise { + return new Promise((resolve, reject) => { + const request = window.indexedDB.open(INDEXEDDB_TEST_DATABASE, schemaVersion); + request.onupgradeneeded = (event: IDBVersionChangeEvent) => { + const db = (event.target as IDBOpenDBRequest).result; + createOrUpgradeDb(db, event.oldVersion, schemaVersion); + }; + request.onsuccess = (event: Event) => { + resolve((event.target as IDBOpenDBRequest).result); + }; + request.onerror = (event: ErrorEvent) => { + reject((event.target as IDBOpenDBRequest).error); + }; + }).then(db => { + fn(db); + return db; + }).then(db => { db.close()}); } function getAllObjectStores(db: IDBDatabase): String[] { @@ -63,31 +63,23 @@ describe('IndexedDbSchema: createOrUpgradeDb', () => { beforeEach(() => SimpleDb.delete(INDEXEDDB_TEST_DATABASE)); it('can install schema version 1', () => { - return initDb(1).then(db => { + return withDb(1, db => { expect(db.version).to.be.equal(1); expect(getAllObjectStores(db)).to.have.members(DEFAULT_STORES); - db.close(); }); }); it('can install schema version 2', () => { - return initDb(2).then(db => { + return withDb(2,db => { expect(db.version).to.be.equal(2); expect(getAllObjectStores(db)).to.have.members(ALL_STORES); - db.close(); }); }); it('can upgrade from schema version 1 to 2', () => { - return initDb(1) - .then(db => { - db.close(); - return initDb(2); - }) - .then(db => { + return withDb(1,() => {}).then(() => withDb(2, (db) => { expect(db.version).to.be.equal(2); expect(getAllObjectStores(db)).to.have.members(ALL_STORES); - db.close(); - }); + })); }); }); From 79919709b6cecffcdde7806675bf4231fd1a56cb Mon Sep 17 00:00:00 2001 From: Sebastian Schmidt Date: Wed, 7 Feb 2018 22:42:53 -0800 Subject: [PATCH 17/22] [AUTOMATED]: Prettier Code Styling --- .../test/unit/local/schema_migration.test.ts | 25 +++++++++++++------ 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/packages/firestore/test/unit/local/schema_migration.test.ts b/packages/firestore/test/unit/local/schema_migration.test.ts index 014d63fdf64..eebf315f474 100644 --- a/packages/firestore/test/unit/local/schema_migration.test.ts +++ b/packages/firestore/test/unit/local/schema_migration.test.ts @@ -28,7 +28,10 @@ const INDEXEDDB_TEST_DATABASE = 'schemaTest'; function withDb(schemaVersion, fn: (db: IDBDatabase) => void): Promise { return new Promise((resolve, reject) => { - const request = window.indexedDB.open(INDEXEDDB_TEST_DATABASE, schemaVersion); + const request = window.indexedDB.open( + INDEXEDDB_TEST_DATABASE, + schemaVersion + ); request.onupgradeneeded = (event: IDBVersionChangeEvent) => { const db = (event.target as IDBOpenDBRequest).result; createOrUpgradeDb(db, event.oldVersion, schemaVersion); @@ -39,10 +42,14 @@ function withDb(schemaVersion, fn: (db: IDBDatabase) => void): Promise { request.onerror = (event: ErrorEvent) => { reject((event.target as IDBOpenDBRequest).error); }; - }).then(db => { - fn(db); - return db; - }).then(db => { db.close()}); + }) + .then(db => { + fn(db); + return db; + }) + .then(db => { + db.close(); + }); } function getAllObjectStores(db: IDBDatabase): String[] { @@ -70,16 +77,18 @@ describe('IndexedDbSchema: createOrUpgradeDb', () => { }); it('can install schema version 2', () => { - return withDb(2,db => { + return withDb(2, db => { expect(db.version).to.be.equal(2); expect(getAllObjectStores(db)).to.have.members(ALL_STORES); }); }); it('can upgrade from schema version 1 to 2', () => { - return withDb(1,() => {}).then(() => withDb(2, (db) => { + return withDb(1, () => {}).then(() => + withDb(2, db => { expect(db.version).to.be.equal(2); expect(getAllObjectStores(db)).to.have.members(ALL_STORES); - })); + }) + ); }); }); From 2c6d6e16f32259a3694fad532d7f16211dfa3608 Mon Sep 17 00:00:00 2001 From: Sebastian Schmidt Date: Thu, 8 Feb 2018 18:19:26 -0800 Subject: [PATCH 18/22] Making v2 the default version --- .../firestore/src/local/indexeddb_persistence.ts | 4 ++-- packages/firestore/src/local/indexeddb_schema.ts | 16 +++++----------- packages/firestore/src/local/simple_db.ts | 4 ++-- 3 files changed, 9 insertions(+), 15 deletions(-) diff --git a/packages/firestore/src/local/indexeddb_persistence.ts b/packages/firestore/src/local/indexeddb_persistence.ts index d6e17708a93..0ede8f4159f 100644 --- a/packages/firestore/src/local/indexeddb_persistence.ts +++ b/packages/firestore/src/local/indexeddb_persistence.ts @@ -30,7 +30,7 @@ import { createOrUpgradeDb, DbOwner, DbOwnerKey, - DEFAULT_SCHEMA_VERSION + SCHEMA_VERSION } from './indexeddb_schema'; import { LocalSerializer } from './local_serializer'; import { MutationQueue } from './mutation_queue'; @@ -134,7 +134,7 @@ export class IndexedDbPersistence implements Persistence { return SimpleDb.openOrCreate( this.dbName, - DEFAULT_SCHEMA_VERSION, + SCHEMA_VERSION, createOrUpgradeDb ) .then(db => { diff --git a/packages/firestore/src/local/indexeddb_schema.ts b/packages/firestore/src/local/indexeddb_schema.ts index 1cbafb87c22..eabc16a7a31 100644 --- a/packages/firestore/src/local/indexeddb_schema.ts +++ b/packages/firestore/src/local/indexeddb_schema.ts @@ -23,16 +23,16 @@ import { assert } from '../util/assert'; import { encode, EncodedResourcePath } from './encoded_resource_path'; /** - * Default Schema Version for the Web client (containing the Mutation Queue, the - * Query and the Remote Document Cache). + * Schema Version for the Web client (containing the Mutation Queue, the Query + * and the Remote Document Cache) and Multi-Tab Support. */ -export const DEFAULT_SCHEMA_VERSION = 1; +export const SCHEMA_VERSION = 2; /** * Performs database creation and schema upgrades. * * Note that in production, this method is only ever used to upgrade the schema - * to DEFAULT_SCHEMA_VERSION. Different versions are only used for testing and + * to SCHEMA_VERSION. Different versions are only used for testing and * local feature development. */ export function createOrUpgradeDb( @@ -581,10 +581,4 @@ const V2_STORES = [DbClientMetadata.store, DbTargetChange.store]; * used when creating transactions so that access across all stores is done * atomically. */ -export const DEFAULT_STORES = V1_STORES; - -/** - * The list of all IndexedDb stores. This is only available in multi-tab enabled - * clients with the schema version 2. - */ -export const ALL_STORES = [...V1_STORES, ...V2_STORES]; +export const DEFAULT_STORES = [...V1_STORES, ...V2_STORES]; diff --git a/packages/firestore/src/local/simple_db.ts b/packages/firestore/src/local/simple_db.ts index d6f7e432681..8adbcad37d5 100644 --- a/packages/firestore/src/local/simple_db.ts +++ b/packages/firestore/src/local/simple_db.ts @@ -19,7 +19,7 @@ import { debug } from '../util/log'; import { AnyDuringMigration } from '../util/misc'; import { PersistencePromise } from './persistence_promise'; -import { DEFAULT_SCHEMA_VERSION } from './indexeddb_schema'; +import { SCHEMA_VERSION } from './indexeddb_schema'; const LOG_TAG = 'SimpleDb'; @@ -75,7 +75,7 @@ export class SimpleDb { // cheating and just passing the raw IndexedDB in, since // createObjectStore(), etc. are synchronous. const db = (event.target as IDBOpenDBRequest).result; - runUpgrade(db, event.oldVersion, DEFAULT_SCHEMA_VERSION); + runUpgrade(db, event.oldVersion, SCHEMA_VERSION); }; }).toPromise(); } From f16bb4fc5729da1f1104c9d2271eef2248920d4a Mon Sep 17 00:00:00 2001 From: Sebastian Schmidt Date: Thu, 8 Feb 2018 18:19:48 -0800 Subject: [PATCH 19/22] [AUTOMATED]: Prettier Code Styling --- packages/firestore/src/local/indexeddb_persistence.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/packages/firestore/src/local/indexeddb_persistence.ts b/packages/firestore/src/local/indexeddb_persistence.ts index 0ede8f4159f..3dc3e287495 100644 --- a/packages/firestore/src/local/indexeddb_persistence.ts +++ b/packages/firestore/src/local/indexeddb_persistence.ts @@ -132,11 +132,7 @@ export class IndexedDbPersistence implements Persistence { assert(!this.started, 'IndexedDbPersistence double-started!'); this.started = true; - return SimpleDb.openOrCreate( - this.dbName, - SCHEMA_VERSION, - createOrUpgradeDb - ) + return SimpleDb.openOrCreate(this.dbName, SCHEMA_VERSION, createOrUpgradeDb) .then(db => { this.simpleDb = db; }) From 038c1599816821710679f26c7cdfebeefc3120f7 Mon Sep 17 00:00:00 2001 From: Sebastian Schmidt Date: Thu, 8 Feb 2018 18:24:23 -0800 Subject: [PATCH 20/22] Addressing comment --- packages/firestore/src/local/indexeddb_schema.ts | 3 ++- .../test/unit/local/schema_migration.test.ts | 12 ++++-------- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/packages/firestore/src/local/indexeddb_schema.ts b/packages/firestore/src/local/indexeddb_schema.ts index eabc16a7a31..d479971e884 100644 --- a/packages/firestore/src/local/indexeddb_schema.ts +++ b/packages/firestore/src/local/indexeddb_schema.ts @@ -563,7 +563,8 @@ function createClientMetadataStore(db: IDBDatabase): void { }); } -const V1_STORES = [ +// Visible for testing +export const V1_STORES = [ DbMutationQueue.store, DbMutationBatch.store, DbDocumentMutation.store, diff --git a/packages/firestore/test/unit/local/schema_migration.test.ts b/packages/firestore/test/unit/local/schema_migration.test.ts index eebf315f474..4197d5435d8 100644 --- a/packages/firestore/test/unit/local/schema_migration.test.ts +++ b/packages/firestore/test/unit/local/schema_migration.test.ts @@ -18,8 +18,7 @@ import { expect } from 'chai'; import { IndexedDbPersistence } from '../../../src/local/indexeddb_persistence'; import { DEFAULT_STORES, - createOrUpgradeDb, - ALL_STORES + createOrUpgradeDb, V1_STORES, } from '../../../src/local/indexeddb_schema'; import { Deferred } from '../../../src/util/promise'; import { SimpleDb } from '../../../src/local/simple_db'; @@ -45,9 +44,6 @@ function withDb(schemaVersion, fn: (db: IDBDatabase) => void): Promise { }) .then(db => { fn(db); - return db; - }) - .then(db => { db.close(); }); } @@ -72,14 +68,14 @@ describe('IndexedDbSchema: createOrUpgradeDb', () => { it('can install schema version 1', () => { return withDb(1, db => { expect(db.version).to.be.equal(1); - expect(getAllObjectStores(db)).to.have.members(DEFAULT_STORES); + expect(getAllObjectStores(db)).to.have.members(V1_STORES); }); }); it('can install schema version 2', () => { return withDb(2, db => { expect(db.version).to.be.equal(2); - expect(getAllObjectStores(db)).to.have.members(ALL_STORES); + expect(getAllObjectStores(db)).to.have.members(DEFAULT_STORES); }); }); @@ -87,7 +83,7 @@ describe('IndexedDbSchema: createOrUpgradeDb', () => { return withDb(1, () => {}).then(() => withDb(2, db => { expect(db.version).to.be.equal(2); - expect(getAllObjectStores(db)).to.have.members(ALL_STORES); + expect(getAllObjectStores(db)).to.have.members(DEFAULT_STORES); }) ); }); From b70303cb7ad896e7c96106f145f960662b9219a6 Mon Sep 17 00:00:00 2001 From: Sebastian Schmidt Date: Thu, 8 Feb 2018 18:24:55 -0800 Subject: [PATCH 21/22] [AUTOMATED]: Prettier Code Styling --- .../test/unit/local/schema_migration.test.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/firestore/test/unit/local/schema_migration.test.ts b/packages/firestore/test/unit/local/schema_migration.test.ts index 4197d5435d8..c98bf579bae 100644 --- a/packages/firestore/test/unit/local/schema_migration.test.ts +++ b/packages/firestore/test/unit/local/schema_migration.test.ts @@ -18,7 +18,8 @@ import { expect } from 'chai'; import { IndexedDbPersistence } from '../../../src/local/indexeddb_persistence'; import { DEFAULT_STORES, - createOrUpgradeDb, V1_STORES, + createOrUpgradeDb, + V1_STORES } from '../../../src/local/indexeddb_schema'; import { Deferred } from '../../../src/util/promise'; import { SimpleDb } from '../../../src/local/simple_db'; @@ -41,11 +42,10 @@ function withDb(schemaVersion, fn: (db: IDBDatabase) => void): Promise { request.onerror = (event: ErrorEvent) => { reject((event.target as IDBOpenDBRequest).error); }; - }) - .then(db => { - fn(db); - db.close(); - }); + }).then(db => { + fn(db); + db.close(); + }); } function getAllObjectStores(db: IDBDatabase): String[] { From 34ab25aae677f0151fffc4f269190811cd52e3e7 Mon Sep 17 00:00:00 2001 From: Sebastian Schmidt Date: Fri, 9 Feb 2018 10:03:15 -0800 Subject: [PATCH 22/22] Renamed to ALL_STORES --- packages/firestore/src/local/indexeddb_persistence.ts | 4 ++-- packages/firestore/src/local/indexeddb_schema.ts | 2 +- packages/firestore/test/unit/local/schema_migration.test.ts | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/firestore/src/local/indexeddb_persistence.ts b/packages/firestore/src/local/indexeddb_persistence.ts index 3dc3e287495..b09548e5e2b 100644 --- a/packages/firestore/src/local/indexeddb_persistence.ts +++ b/packages/firestore/src/local/indexeddb_persistence.ts @@ -26,7 +26,7 @@ import { IndexedDbMutationQueue } from './indexeddb_mutation_queue'; import { IndexedDbQueryCache } from './indexeddb_query_cache'; import { IndexedDbRemoteDocumentCache } from './indexeddb_remote_document_cache'; import { - DEFAULT_STORES, + ALL_STORES, createOrUpgradeDb, DbOwner, DbOwnerKey, @@ -177,7 +177,7 @@ export class IndexedDbPersistence implements Persistence { // Do all transactions as readwrite against all object stores, since we // are the only reader/writer. - return this.simpleDb.runTransaction('readwrite', DEFAULT_STORES, txn => { + return this.simpleDb.runTransaction('readwrite', ALL_STORES, txn => { // Verify that we still have the owner lease as part of every transaction. return this.ensureOwnerLease(txn).next(() => operation(txn)); }); diff --git a/packages/firestore/src/local/indexeddb_schema.ts b/packages/firestore/src/local/indexeddb_schema.ts index d479971e884..d3689ff94f1 100644 --- a/packages/firestore/src/local/indexeddb_schema.ts +++ b/packages/firestore/src/local/indexeddb_schema.ts @@ -582,4 +582,4 @@ const V2_STORES = [DbClientMetadata.store, DbTargetChange.store]; * used when creating transactions so that access across all stores is done * atomically. */ -export const DEFAULT_STORES = [...V1_STORES, ...V2_STORES]; +export const ALL_STORES = [...V1_STORES, ...V2_STORES]; diff --git a/packages/firestore/test/unit/local/schema_migration.test.ts b/packages/firestore/test/unit/local/schema_migration.test.ts index c98bf579bae..3faad875333 100644 --- a/packages/firestore/test/unit/local/schema_migration.test.ts +++ b/packages/firestore/test/unit/local/schema_migration.test.ts @@ -17,7 +17,7 @@ import { expect } from 'chai'; import { IndexedDbPersistence } from '../../../src/local/indexeddb_persistence'; import { - DEFAULT_STORES, + ALL_STORES, createOrUpgradeDb, V1_STORES } from '../../../src/local/indexeddb_schema'; @@ -75,7 +75,7 @@ describe('IndexedDbSchema: createOrUpgradeDb', () => { it('can install schema version 2', () => { return withDb(2, db => { expect(db.version).to.be.equal(2); - expect(getAllObjectStores(db)).to.have.members(DEFAULT_STORES); + expect(getAllObjectStores(db)).to.have.members(ALL_STORES); }); }); @@ -83,7 +83,7 @@ describe('IndexedDbSchema: createOrUpgradeDb', () => { return withDb(1, () => {}).then(() => withDb(2, db => { expect(db.version).to.be.equal(2); - expect(getAllObjectStores(db)).to.have.members(DEFAULT_STORES); + expect(getAllObjectStores(db)).to.have.members(ALL_STORES); }) ); });