Skip to content

Commit 4cec423

Browse files
Add Index Schema (#5954)
1 parent 0a04a1c commit 4cec423

File tree

3 files changed

+146
-11
lines changed

3 files changed

+146
-11
lines changed

packages/firestore/src/local/indexeddb_schema.ts

Lines changed: 112 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
*/
1717

1818
import { BatchId, ListenSequenceNumber, TargetId } from '../core/types';
19+
import { IndexKind } from '../model/field_index';
1920
import { ResourcePath } from '../model/path';
2021
import { BundledQuery } from '../protos/firestore_bundle_proto';
2122
import {
@@ -31,6 +32,11 @@ import {
3132
encodeResourcePath
3233
} from './encoded_resource_path';
3334

35+
// TODO(indexing): Remove this constant
36+
const INDEXING_ENABLED = false;
37+
38+
export const INDEXING_SCHEMA_VERSION = 12;
39+
3440
/**
3541
* Schema Version for the Web client:
3642
* 1. Initial version including Mutation Queue, Query Cache, and Remote
@@ -49,8 +55,9 @@ import {
4955
* an auto-incrementing ID. This is required for Index-Free queries.
5056
* 10. Rewrite the canonical IDs to the explicit Protobuf-based format.
5157
* 11. Add bundles and named_queries for bundle support.
58+
* 12. Add indexing support.
5259
*/
53-
export const SCHEMA_VERSION = 11;
60+
export const SCHEMA_VERSION = INDEXING_ENABLED ? INDEXING_SCHEMA_VERSION : 11;
5461

5562
/**
5663
* Wrapper class to store timestamps (seconds and nanos) in IndexedDb objects.
@@ -655,9 +662,7 @@ export type DbClientMetadataKey = string;
655662

656663
export type DbBundlesKey = string;
657664

658-
/**
659-
* A object representing a bundle loaded by the SDK.
660-
*/
665+
/** An object representing a bundle loaded by the SDK. */
661666
export class DbBundle {
662667
/** Name of the IndexedDb object store. */
663668
static store = 'bundles';
@@ -676,9 +681,7 @@ export class DbBundle {
676681

677682
export type DbNamedQueriesKey = string;
678683

679-
/**
680-
* A object representing a named query loaded by the SDK via a bundle.
681-
*/
684+
/** An object representing a named query loaded by the SDK via a bundle. */
682685
export class DbNamedQuery {
683686
/** Name of the IndexedDb object store. */
684687
static store = 'namedQueries';
@@ -695,6 +698,101 @@ export class DbNamedQuery {
695698
) {}
696699
}
697700

701+
/** The key for each index consisting of just the index id. */
702+
export type DbIndexConfigurationKey = number;
703+
704+
/** An object representing the global configuration for a field index. */
705+
export class DbIndexConfiguration {
706+
/** Name of the IndexedDb object store. */
707+
static store = 'indexConfiguration';
708+
709+
static keyPath = 'indexId';
710+
711+
constructor(
712+
/** The index id for this entry. */
713+
public indexId: number,
714+
/** The collection group this index belongs to. */
715+
public collectionGroup: string,
716+
/** The fields to index for this index. */
717+
public fields: [[name: string, kind: IndexKind]]
718+
) {}
719+
}
720+
721+
/** The key for each index state consisting of the index id and its user id. */
722+
export type DbIndexStateKey = [number, string];
723+
724+
/**
725+
* An object describing how up-to-date the index backfill is for each user and
726+
* index.
727+
*/
728+
export class DbIndexState {
729+
/** Name of the IndexedDb object store. */
730+
static store = 'indexState';
731+
732+
static keyPath = ['indexId', 'uid'];
733+
734+
constructor(
735+
/** The index id for this entry. */
736+
public indexId: number,
737+
/** The user id for this entry. */
738+
public uid: string,
739+
/**
740+
* A number that indicates when the index was last updated (relative to
741+
* other indexes).
742+
*/
743+
public sequenceNumber: number,
744+
/**
745+
* The latest read time that has been indexed by Firestore for this field
746+
* index. Set to `{seconds: 0, nanos: 0}` if no documents have been indexed.
747+
*/
748+
public readTime: DbTimestamp,
749+
/**
750+
* The last document that has been indexed for this field index. Empty if
751+
* no documents have been indexed.
752+
*/
753+
public documentKey: EncodedResourcePath,
754+
/**
755+
* The largest mutation batch id that has been processed for this index. -1
756+
* if no mutations have been indexed.
757+
*/
758+
public largestBatchId: number
759+
) {}
760+
}
761+
762+
/**
763+
* The key for each index entry consists of the index id and its user id,
764+
* the encoded array and directional value for the indexed fields as well as
765+
* the encoded document path for the indexed document.
766+
*/
767+
export type DbIndexEntryKey = [number, string, Uint8Array, Uint8Array, string];
768+
769+
/** An object that stores the encoded entries for all documents and fields. */
770+
export class DbIndexEntries {
771+
/** Name of the IndexedDb object store. */
772+
static store = 'indexEntries';
773+
774+
static keyPath = [
775+
'indexId',
776+
'uid',
777+
'arrayValue',
778+
'directionalValue',
779+
'documentKey'
780+
];
781+
782+
constructor(
783+
/** The index id for this entry. */
784+
public indexId: number,
785+
/** The user id for this entry. */
786+
public uid: string,
787+
/** The encoded array index value for this entry. */
788+
public arrayValue: Uint8Array,
789+
/** The encoded directional value for equality and inequality filters. */
790+
public directionalValue: Uint8Array,
791+
/** The document key this entry points to. */
792+
public documentKey: EncodedResourcePath
793+
) {}
794+
}
795+
698796
// Visible for testing
699797
export const V1_STORES = [
700798
DbMutationQueue.store,
@@ -712,7 +810,6 @@ export const V1_STORES = [
712810
// Visible for testing
713811
export const V3_STORES = V1_STORES;
714812

715-
// Visible for testing
716813
// Note: DbRemoteDocumentChanges is no longer used and dropped with v9.
717814
export const V4_STORES = [...V3_STORES, DbClientMetadata.store];
718815

@@ -730,6 +827,13 @@ export const V8_STORES = [...V6_STORES, DbCollectionParent.store];
730827

731828
export const V11_STORES = [...V8_STORES, DbBundle.store, DbNamedQuery.store];
732829

830+
export const V12_STORES = [
831+
...V11_STORES,
832+
DbIndexConfiguration.store,
833+
DbIndexState.store,
834+
DbIndexEntries.store
835+
];
836+
733837
/**
734838
* The list of all default IndexedDB stores used throughout the SDK. This is
735839
* used when creating transactions so that access across all stores is done

packages/firestore/src/local/indexeddb_schema_converter.ts

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ import {
3535
DbCollectionParentKey,
3636
DbDocumentMutation,
3737
DbDocumentMutationKey,
38+
DbIndexConfiguration,
39+
DbIndexEntries,
40+
DbIndexState,
3841
DbMutationBatch,
3942
DbMutationBatchKey,
4043
DbMutationQueue,
@@ -51,7 +54,7 @@ import {
5154
DbTargetGlobal,
5255
DbTargetGlobalKey,
5356
DbTargetKey,
54-
SCHEMA_VERSION
57+
INDEXING_SCHEMA_VERSION
5558
} from './indexeddb_schema';
5659
import {
5760
fromDbMutationBatch,
@@ -80,10 +83,10 @@ export class SchemaConverter implements SimpleDbSchemaConverter {
8083
fromVersion: number,
8184
toVersion: number
8285
): PersistencePromise<void> {
83-
hardAssert(
86+
debugAssert(
8487
fromVersion < toVersion &&
8588
fromVersion >= 0 &&
86-
toVersion <= SCHEMA_VERSION,
89+
toVersion <= INDEXING_SCHEMA_VERSION,
8790
`Unexpected schema upgrade from v${fromVersion} to v${toVersion}.`
8891
);
8992

@@ -169,6 +172,13 @@ export class SchemaConverter implements SimpleDbSchemaConverter {
169172
createNamedQueriesStore(db);
170173
});
171174
}
175+
176+
if (fromVersion < 12 && toVersion >= 12) {
177+
p = p.next(() => {
178+
createFieldIndex(db);
179+
});
180+
}
181+
172182
return p;
173183
}
174184

@@ -504,3 +514,15 @@ function createNamedQueriesStore(db: IDBDatabase): void {
504514
keyPath: DbNamedQuery.keyPath
505515
});
506516
}
517+
518+
function createFieldIndex(db: IDBDatabase): void {
519+
db.createObjectStore(DbIndexConfiguration.store, {
520+
keyPath: DbIndexConfiguration.keyPath
521+
});
522+
db.createObjectStore(DbIndexState.store, {
523+
keyPath: DbIndexState.keyPath
524+
});
525+
db.createObjectStore(DbIndexEntries.store, {
526+
keyPath: DbIndexEntries.keyPath
527+
});
528+
}

packages/firestore/test/unit/local/indexeddb_persistence.test.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ import {
5050
DbTargetKey,
5151
DbTimestamp,
5252
SCHEMA_VERSION,
53+
V12_STORES,
5354
V1_STORES,
5455
V3_STORES,
5556
V4_STORES,
@@ -1024,6 +1025,14 @@ describe('IndexedDbSchema: createOrUpgradeDb', () => {
10241025
});
10251026
});
10261027

1028+
it('can upgrade from version 11 to 12', async () => {
1029+
await withDb(11, async () => {});
1030+
await withDb(12, async (db, version, objectStores) => {
1031+
expect(version).to.have.equal(12);
1032+
expect(objectStores).to.have.members(V12_STORES);
1033+
});
1034+
});
1035+
10271036
it('downgrading throws a custom error', async function (this: Context) {
10281037
// Upgrade to latest version
10291038
await withDb(SCHEMA_VERSION, async (db, version) => {

0 commit comments

Comments
 (0)