Skip to content

Commit 07e44e7

Browse files
Pseudocode for Schema Migration
1 parent eb44929 commit 07e44e7

File tree

4 files changed

+80
-49
lines changed

4 files changed

+80
-49
lines changed

packages/firestore/src/local/indexeddb_migrations.ts

Lines changed: 57 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -15,28 +15,20 @@
1515
*/
1616
import {
1717
DbDocumentMutation, DbInstance,
18-
DbMutationBatch, DbMutationQueue, DbOwner, DbRemoteDocument, DbTarget,
18+
DbMutationBatch, DbMutationQueue, DbOwner,
19+
DbRemoteDocument, DbTarget,
1920
DbTargetDocument, DbTargetGlobal
2021
} from './indexeddb_schema';
21-
import {fail} from '../util/assert';
22+
import {assert, fail} from '../util/assert';
2223

23-
export function createDb(db: IDBDatabase): void {
24-
db.createObjectStore(DbMutationQueue.store, {
25-
keyPath: DbMutationQueue.keyPath
26-
});
27-
28-
// TODO(mikelehen): Get rid of "as any" if/when TypeScript fixes their
29-
// types. https://github.com/Microsoft/TypeScript/issues/14322
30-
db.createObjectStore(
31-
DbMutationBatch.store,
32-
// tslint:disable-next-line:no-any
33-
{ keyPath: DbMutationBatch.keyPath as any }
34-
);
24+
// TODO(mikelehen): Get rid of "as any" if/when TypeScript fixes their types.
25+
// https://github.com/Microsoft/TypeScript/issues/14322
26+
type KeyPath = any; // tslint:disable-line:no-any
3527

28+
function createCache(db: IDBDatabase): void {
3629
const targetDocumentsStore = db.createObjectStore(
3730
DbTargetDocument.store,
38-
// tslint:disable-next-line:no-any
39-
{ keyPath: DbTargetDocument.keyPath as any }
31+
{ keyPath: DbTargetDocument.keyPath as KeyPath }
4032
);
4133
targetDocumentsStore.createIndex(
4234
DbTargetDocument.documentTargetsIndex,
@@ -47,45 +39,72 @@ export function createDb(db: IDBDatabase): void {
4739
const targetStore = db.createObjectStore(DbTarget.store, {
4840
keyPath: DbTarget.keyPath
4941
});
42+
5043
// NOTE: This is unique only because the TargetId is the suffix.
5144
targetStore.createIndex(
5245
DbTarget.queryTargetsIndexName,
5346
DbTarget.queryTargetsKeyPath,
5447
{ unique: true }
5548
);
49+
db.createObjectStore(DbRemoteDocument.store);
50+
db.createObjectStore(DbTargetGlobal.store);
51+
}
52+
53+
function dropCache(db: IDBDatabase): void {
54+
db.deleteObjectStore(DbTargetDocument.store);
55+
db.deleteObjectStore(DbTarget.keyPath);
56+
db.deleteObjectStore(DbRemoteDocument.store);
57+
db.deleteObjectStore(DbTargetGlobal.store);
58+
}
5659

57-
const instanceStore = db.createObjectStore(DbInstance.store, {
58-
keyPath: DbInstance.keyPath as any
60+
function createOwnerStore(db: IDBDatabase) : void {
61+
db.createObjectStore(DbOwner.store);
62+
}
63+
64+
function createInstanceStore(db: IDBDatabase) : void {
65+
db.createObjectStore(DbInstance.store, {
66+
keyPath: DbInstance.keyPath as KeyPath
5967
});
68+
}
69+
70+
function createMutationQueue(db: IDBDatabase) : void {
71+
db.createObjectStore(DbMutationQueue.store, {
72+
keyPath: DbMutationQueue.keyPath
73+
});
74+
75+
db.createObjectStore(
76+
DbMutationBatch.store,
77+
{ keyPath: DbMutationBatch.keyPath as KeyPath }
78+
);
6079

6180
// NOTE: keys for these stores are specified explicitly rather than using a
6281
// keyPath.
6382
db.createObjectStore(DbDocumentMutation.store);
64-
db.createObjectStore(DbRemoteDocument.store);
65-
db.createObjectStore(DbOwner.store);
66-
db.createObjectStore(DbTargetGlobal.store);
6783
}
6884

69-
export function upgradeDbFromV1(db: IDBDatabase): void {
85+
/**
86+
* Runs any migrations needed to bring the given database up to the current
87+
* schema version.
88+
*/
89+
export function createOrUpgradeDb(db: IDBDatabase, oldVersion: number, newVersion: number): void {
90+
assert(oldVersion >= 0 || oldVersion <= 1, 'Unexpected upgrade from version ' + oldVersion);
91+
assert(newVersion >= 1 || newVersion <= 2, 'Unexpected upgrade to version ' + newVersion);
7092

71-
}
93+
const createV1 = newVersion >= 1 && oldVersion <= 1;
94+
const dropV1 = oldVersion >= 1;
95+
const createV2 = newVersion >= 2 && oldVersion <= 2;
7296

73-
export class IndexedDbMigrations {
74-
/**
75-
* Runs any migrations needed to bring the given database up to the current
76-
* schema version.
77-
*/
78-
static runMigrations(db: IDBDatabase, oldVersion: number) {
79-
if (oldVersion == 0) {
80-
createDb(db, oldVersion);
81-
return;
82-
}
97+
if (dropV1) {
98+
dropCache(db);
99+
}
83100

84-
if (oldVersion == 1) {
85-
upgradeDbFromV1(db, oldVersion);
86-
return;
87-
}
101+
if (createV1) {
102+
createOwnerStore(db);
103+
createMutationQueue(db);
104+
createCache(db);
105+
}
88106

89-
fail('Unexpected upgrade from version ' + oldVersion);
107+
if (createV2) {
108+
createInstanceStore(db);
90109
}
91110
}

packages/firestore/src/local/indexeddb_persistence.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,15 @@ import { IndexedDbMutationQueue } from './indexeddb_mutation_queue';
2626
import { IndexedDbQueryCache } from './indexeddb_query_cache';
2727
import { IndexedDbRemoteDocumentCache } from './indexeddb_remote_document_cache';
2828
import { ALL_STORES, DbOwner, DbOwnerKey } from './indexeddb_schema';
29-
import { createOrUpgradeDb, SCHEMA_VERSION } from './indexeddb_schema';
29+
import { SCHEMA_VERSION } from './indexeddb_schema';
3030
import { LocalSerializer } from './local_serializer';
3131
import { MutationQueue } from './mutation_queue';
3232
import { Persistence } from './persistence';
3333
import { PersistencePromise } from './persistence_promise';
3434
import { QueryCache } from './query_cache';
3535
import { RemoteDocumentCache } from './remote_document_cache';
3636
import { SimpleDb, SimpleDbTransaction } from './simple_db';
37-
import {IndexedDbMigrations} from './indexeddb_migrations';
37+
import {createOrUpgradeDb} from './indexeddb_migrations';
3838

3939
const LOG_TAG = 'IndexedDbPersistence';
4040

@@ -128,7 +128,7 @@ export class IndexedDbPersistence implements Persistence {
128128
assert(!this.started, 'IndexedDbPersistence double-started!');
129129
this.started = true;
130130

131-
return SimpleDb.openOrCreate(this.dbName, SCHEMA_VERSION, IndexedDbMigrations.runMigrations)
131+
return SimpleDb.openOrCreate(this.dbName, SCHEMA_VERSION, createOrUpgradeDb)
132132
.then(db => {
133133
this.simpleDb = db;
134134
})

packages/firestore/src/local/indexeddb_schema.ts

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import { ResourcePath } from '../model/path';
2121
import { assert } from '../util/assert';
2222

2323
import { encode, EncodedResourcePath } from './encoded_resource_path';
24+
import {SnapshotVersion} from '../core/snapshot_version';
2425

2526
export const SCHEMA_VERSION = 1;
2627

@@ -86,7 +87,15 @@ export class DbMutationQueue {
8687
* After sending this token, earlier tokens may not be used anymore so
8788
* only a single stream token is retained.
8889
*/
89-
public lastStreamToken: string
90+
public lastStreamToken: string,
91+
92+
/**
93+
* An identifier for the highest numbered batch that has been acknowledged
94+
* by the server. All MutationBatches in this queue with batchIds less
95+
* than or equal to this value are considered to have been acknowledged by
96+
* the server.
97+
*/
98+
public highestPendingBatchId: number,
9099
) {}
91100
}
92101

@@ -345,8 +354,8 @@ export class DbTargetDocument {
345354
/** Name of the IndexedDb object store. */
346355
static store = 'targetDocuments';
347356

348-
/** Keys are automatically assigned via the targetId, path properties. */
349-
static keyPath = ['targetId', 'path'];
357+
/** Keys are automatically assigned via the targetId, snapshotVersion, and path properties. */
358+
static keyPath = ['targetId', 'snapshotVersion', 'path'];
350359

351360
/** The index name for the reverse index. */
352361
static documentTargetsIndex = 'documentTargetsIndex';
@@ -359,6 +368,8 @@ export class DbTargetDocument {
359368
* The targetId identifying a target.
360369
*/
361370
public targetId: TargetId,
371+
372+
public snapshotVersion: number,
362373
/**
363374
* The path to the document, as encoded in the key.
364375
*/
@@ -420,8 +431,7 @@ export class DbInstance {
420431
constructor(
421432
public userId: string,
422433
public instanceId: string,
423-
public updateTimeMs: number,
424-
public visibilityState: VisibilityState
434+
public updateTimeMs: number
425435
) {}
426436
}
427437

@@ -437,5 +447,6 @@ export const ALL_STORES = [
437447
DbTarget.store,
438448
DbOwner.store,
439449
DbTargetGlobal.store,
440-
DbTargetDocument.store
450+
DbTargetDocument.store,
451+
DbInstance.store
441452
];

packages/firestore/src/local/simple_db.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import { debug } from '../util/log';
1919
import { AnyDuringMigration } from '../util/misc';
2020

2121
import { PersistencePromise } from './persistence_promise';
22+
import {SCHEMA_VERSION} from './indexeddb_schema';
2223

2324
const LOG_TAG = 'SimpleDb';
2425

@@ -34,7 +35,7 @@ export class SimpleDb {
3435
static openOrCreate(
3536
name: string,
3637
version: number,
37-
runUpgrade: (db: IDBDatabase, oldVersion: number) => void
38+
runUpgrade: (db: IDBDatabase, oldVersion: number, newVersion: number) => void
3839
): Promise<SimpleDb> {
3940
assert(
4041
SimpleDb.isAvailable(),
@@ -70,7 +71,7 @@ export class SimpleDb {
7071
// cheating and just passing the raw IndexedDB in, since
7172
// createObjectStore(), etc. are synchronous.
7273
const db = (event.target as IDBOpenDBRequest).result;
73-
runUpgrade(db, event.oldVersion);
74+
runUpgrade(db, event.oldVersion, SCHEMA_VERSION);
7475
};
7576
}).toPromise();
7677
}

0 commit comments

Comments
 (0)