Skip to content

Commit d3f0ab4

Browse files
authored
Implement BundleCache for IDB and memory. (#3170)
1 parent 2f179bc commit d3f0ab4

15 files changed

+730
-20
lines changed

packages/firestore/src/core/bundle.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/**
2+
* @license
3+
* Copyright 2020 Google LLC
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
import { Query } from './query';
19+
import { SnapshotVersion } from './snapshot_version';
20+
21+
/**
22+
* Represents a Firestore bundle saved by the SDK in its local storage.
23+
*/
24+
export interface Bundle {
25+
readonly id: string;
26+
readonly version: number;
27+
/**
28+
* Set to the snapshot version of the bundle if created by the Server SDKs.
29+
* Otherwise set to SnapshotVersion.MIN.
30+
*/
31+
readonly createTime: SnapshotVersion;
32+
}
33+
34+
/**
35+
* Represents a Query saved by the SDK in its local storage.
36+
*/
37+
export interface NamedQuery {
38+
readonly name: string;
39+
readonly query: Query;
40+
/** The time at which the results for this query were read. */
41+
readonly readTime: SnapshotVersion;
42+
}

packages/firestore/src/core/component_provider.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,8 @@ export class MemoryComponentProvider implements ComponentProvider {
137137
!cfg.persistenceSettings.durable,
138138
'Can only start memory persistence'
139139
);
140-
return new MemoryPersistence(MemoryEagerDelegate.factory);
140+
const serializer = cfg.platform.newSerializer(cfg.databaseInfo.databaseId);
141+
return new MemoryPersistence(MemoryEagerDelegate.factory, serializer);
141142
}
142143

143144
createRemoteStore(cfg: ComponentConfiguration): RemoteStore {
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/**
2+
* @license
3+
* Copyright 2020 Google LLC
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
import { PersistenceTransaction } from './persistence';
19+
import { PersistencePromise } from './persistence_promise';
20+
import * as bundleProto from '../protos/firestore_bundle_proto';
21+
import { Bundle, NamedQuery } from '../core/bundle';
22+
23+
/**
24+
* Provides interfaces to save and read Firestore bundles.
25+
*/
26+
export interface BundleCache {
27+
/**
28+
* Gets a saved `Bundle` for a given `bundleId`, returns undefined if
29+
* no bundles are found under the given id.
30+
*/
31+
getBundle(
32+
transaction: PersistenceTransaction,
33+
bundleId: string
34+
): PersistencePromise<Bundle | undefined>;
35+
36+
/**
37+
* Saves a `BundleMetadata` from a bundle into local storage, using its id as
38+
* the persistent key.
39+
*/
40+
saveBundleMetadata(
41+
transaction: PersistenceTransaction,
42+
metadata: bundleProto.BundleMetadata
43+
): PersistencePromise<void>;
44+
45+
/**
46+
* Gets a saved `NamedQuery` for the given query name. Returns undefined if
47+
* no queries are found under the given name.
48+
*/
49+
getNamedQuery(
50+
transaction: PersistenceTransaction,
51+
queryName: string
52+
): PersistencePromise<NamedQuery | undefined>;
53+
54+
/**
55+
* Saves a `NamedQuery` from a bundle, using its name as the persistent key.
56+
*/
57+
saveNamedQuery(
58+
transaction: PersistenceTransaction,
59+
query: bundleProto.NamedQuery
60+
): PersistencePromise<void>;
61+
}
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
/**
2+
* @license
3+
* Copyright 2020 Google LLC
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
import { PersistenceTransaction } from './persistence';
19+
import { PersistencePromise } from './persistence_promise';
20+
import * as bundleProto from '../protos/firestore_bundle_proto';
21+
import { BundleCache } from './bundle_cache';
22+
import {
23+
DbBundle,
24+
DbBundlesKey,
25+
DbNamedQuery,
26+
DbNamedQueriesKey
27+
} from './indexeddb_schema';
28+
import { SimpleDbStore } from './simple_db';
29+
import { IndexedDbPersistence } from './indexeddb_persistence';
30+
import {
31+
fromDbBundle,
32+
fromDbNamedQuery,
33+
LocalSerializer,
34+
toDbBundle,
35+
toDbNamedQuery
36+
} from './local_serializer';
37+
import { Bundle, NamedQuery } from '../core/bundle';
38+
39+
export class IndexedDbBundleCache implements BundleCache {
40+
constructor(private serializer: LocalSerializer) {}
41+
42+
getBundle(
43+
transaction: PersistenceTransaction,
44+
bundleId: string
45+
): PersistencePromise<Bundle | undefined> {
46+
return bundlesStore(transaction)
47+
.get(bundleId)
48+
.next(bundle => {
49+
if (bundle) {
50+
return fromDbBundle(this.serializer, bundle);
51+
}
52+
return undefined;
53+
});
54+
}
55+
56+
saveBundleMetadata(
57+
transaction: PersistenceTransaction,
58+
bundleMetadata: bundleProto.BundleMetadata
59+
): PersistencePromise<void> {
60+
return bundlesStore(transaction).put(
61+
toDbBundle(this.serializer, bundleMetadata)
62+
);
63+
}
64+
65+
getNamedQuery(
66+
transaction: PersistenceTransaction,
67+
queryName: string
68+
): PersistencePromise<NamedQuery | undefined> {
69+
return namedQueriesStore(transaction)
70+
.get(queryName)
71+
.next(query => {
72+
if (query) {
73+
return fromDbNamedQuery(this.serializer, query);
74+
}
75+
return undefined;
76+
});
77+
}
78+
79+
saveNamedQuery(
80+
transaction: PersistenceTransaction,
81+
query: bundleProto.NamedQuery
82+
): PersistencePromise<void> {
83+
return namedQueriesStore(transaction).put(
84+
toDbNamedQuery(this.serializer, query)
85+
);
86+
}
87+
}
88+
89+
/**
90+
* Helper to get a typed SimpleDbStore for the bundles object store.
91+
*/
92+
function bundlesStore(
93+
txn: PersistenceTransaction
94+
): SimpleDbStore<DbBundlesKey, DbBundle> {
95+
return IndexedDbPersistence.getStore<DbBundlesKey, DbBundle>(
96+
txn,
97+
DbBundle.store
98+
);
99+
}
100+
101+
/**
102+
* Helper to get a typed SimpleDbStore for the namedQueries object store.
103+
*/
104+
function namedQueriesStore(
105+
txn: PersistenceTransaction
106+
): SimpleDbStore<DbNamedQueriesKey, DbNamedQuery> {
107+
return IndexedDbPersistence.getStore<DbNamedQueriesKey, DbNamedQuery>(
108+
txn,
109+
DbNamedQuery.store
110+
);
111+
}

packages/firestore/src/local/indexeddb_persistence.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import {
3232
EncodedResourcePath,
3333
encodeResourcePath
3434
} from './encoded_resource_path';
35+
import { IndexedDbBundleCache } from './indexeddb_bundle_cache';
3536
import { IndexedDbIndexManager } from './indexeddb_index_manager';
3637
import {
3738
IndexedDbMutationQueue,
@@ -226,6 +227,7 @@ export class IndexedDbPersistence implements Persistence {
226227
private readonly targetCache: IndexedDbTargetCache;
227228
private readonly indexManager: IndexedDbIndexManager;
228229
private readonly remoteDocumentCache: IndexedDbRemoteDocumentCache;
230+
private readonly bundleCache: IndexedDbBundleCache;
229231
private readonly webStorage: Storage;
230232
readonly referenceDelegate: IndexedDbLruDelegate;
231233

@@ -259,6 +261,7 @@ export class IndexedDbPersistence implements Persistence {
259261
this.serializer,
260262
this.indexManager
261263
);
264+
this.bundleCache = new IndexedDbBundleCache(this.serializer);
262265
if (platform.window && platform.window.localStorage) {
263266
this.window = platform.window;
264267
this.webStorage = this.window.localStorage;
@@ -763,6 +766,14 @@ export class IndexedDbPersistence implements Persistence {
763766
return this.indexManager;
764767
}
765768

769+
getBundleCache(): IndexedDbBundleCache {
770+
debugAssert(
771+
this.started,
772+
'Cannot initialize BundleCache before persistence is started.'
773+
);
774+
return this.bundleCache;
775+
}
776+
766777
runTransaction<T>(
767778
action: string,
768779
mode: PersistenceTransactionMode,

packages/firestore/src/local/indexeddb_schema.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1092,11 +1092,11 @@ export type DbBundlesKey = string;
10921092
/**
10931093
* A object representing a bundle loaded by the SDK.
10941094
*/
1095-
export class DbBundles {
1095+
export class DbBundle {
10961096
/** Name of the IndexedDb object store. */
10971097
static store = 'bundles';
10981098

1099-
static keyPath = ['bundleId'];
1099+
static keyPath = 'bundleId';
11001100

11011101
constructor(
11021102
/** The ID of the loaded bundle. */
@@ -1109,8 +1109,8 @@ export class DbBundles {
11091109
}
11101110

11111111
function createBundlesStore(db: IDBDatabase): void {
1112-
db.createObjectStore(DbBundles.store, {
1113-
keyPath: DbBundles.keyPath
1112+
db.createObjectStore(DbBundle.store, {
1113+
keyPath: DbBundle.keyPath
11141114
});
11151115
}
11161116

@@ -1119,11 +1119,11 @@ export type DbNamedQueriesKey = string;
11191119
/**
11201120
* A object representing a named query loaded by the SDK via a bundle.
11211121
*/
1122-
export class DbNamedQueries {
1122+
export class DbNamedQuery {
11231123
/** Name of the IndexedDb object store. */
11241124
static store = 'namedQueries';
11251125

1126-
static keyPath = ['name'];
1126+
static keyPath = 'name';
11271127

11281128
constructor(
11291129
/** The name of the query. */
@@ -1136,8 +1136,8 @@ export class DbNamedQueries {
11361136
}
11371137

11381138
function createNamedQueriesStore(db: IDBDatabase): void {
1139-
db.createObjectStore(DbNamedQueries.store, {
1140-
keyPath: DbNamedQueries.keyPath
1139+
db.createObjectStore(DbNamedQuery.store, {
1140+
keyPath: DbNamedQuery.keyPath
11411141
});
11421142
}
11431143

@@ -1174,7 +1174,7 @@ export const V8_STORES = [...V6_STORES, DbCollectionParent.store];
11741174

11751175
// V10 does not change the set of stores.
11761176

1177-
export const V11_STORES = [...V8_STORES, DbCollectionParent.store];
1177+
export const V11_STORES = [...V8_STORES, DbBundle.store, DbNamedQuery.store];
11781178

11791179
/**
11801180
* The list of all default IndexedDB stores used throughout the SDK. This is

0 commit comments

Comments
 (0)