Skip to content

Commit bcd9ebe

Browse files
committed
Done with first pass
1 parent 0229168 commit bcd9ebe

File tree

10 files changed

+103
-96
lines changed

10 files changed

+103
-96
lines changed

packages/data-connect/.eslintrc.js

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -51,14 +51,6 @@ module.exports = {
5151
],
5252
'no-restricted-globals': [
5353
'error',
54-
{
55-
'name': 'window',
56-
'message': 'Use `PlatformSupport.getPlatform().window` instead.'
57-
},
58-
{
59-
'name': 'document',
60-
'message': 'Use `PlatformSupport.getPlatform().document` instead.'
61-
}
6254
]
6355
},
6456
overrides: [

packages/data-connect/src/api/DataConnect.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import {
3030
updateEmulatorBanner
3131
} from '@firebase/util';
3232

33+
import { Cache as DataConnectCache } from '../cache/Cache';
3334
import { AppCheckTokenProvider } from '../core/AppCheckTokenProvider';
3435
import { Code, DataConnectError } from '../core/error';
3536
import {
@@ -47,7 +48,6 @@ import {
4748
import { RESTTransport } from '../network/transport/rest';
4849

4950
import { MutationManager } from './Mutation';
50-
import { Cache as DataConnectCache } from '../cache/Cache';
5151

5252
/**
5353
* Connector Config for calling Data Connect backend.

packages/data-connect/src/cache/BackingDataObject.ts

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,36 @@
11
export type FDCScalarValue = string | number | boolean | undefined | null | object | FDCScalarValue[];
22

3+
export interface BackingDataObjectJson {
4+
map: Map<string, FDCScalarValue>;
5+
queriesReferenced: Set<string>;
6+
globalID: string;
7+
}
8+
39
export class BackingDataObject {
4-
toStorableJson(): any {
10+
toStorableJson(): BackingDataObjectJson {
511
// TODO: This might not be ok.
6-
return this;
12+
return {
13+
globalID: this.globalID,
14+
map: this.map,
15+
queriesReferenced: this.queriesReferenced
16+
};
717
}
8-
static fromStorableJson(json: any): BackingDataObject {
18+
static fromStorableJson(json: BackingDataObjectJson): BackingDataObject {
919
const bdo = new BackingDataObject(json.globalID);
10-
// TODO: check whether the map can be stored in the database as-is
1120
bdo.map = new Map<string, FDCScalarValue>(json.map);
12-
// TODO: check whether the map can be stored in the database as-is
1321
bdo.queriesReferenced = json.queriesReferenced;
1422
return bdo;
1523
}
1624
private map = new Map<string, FDCScalarValue>();
1725
private queriesReferenced = new Set<string>();
18-
// private queryToFields = new Map<string, string[]>();
1926
constructor(public readonly globalID: string) {}
2027
updateServerValue(key: string, value: FDCScalarValue): string[] {
2128
this.map.set(key, value);
2229
return Array.from(this.queriesReferenced);
23-
// TODO: Collect queries that need to be updated.
2430
}
25-
track(queryId: string) {
31+
// TODO(mtewani): Add a way to track what fields are associated with each query during runtime.
32+
// private queryToFields = new Map<string, string[]>();
33+
track(queryId: string): void {
2634
this.queriesReferenced.add(queryId);
2735
// if(!this.queryToFields.has(queryId)) {
2836
// this.queryToFields.set(queryId, []);

packages/data-connect/src/cache/Cache.ts

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,19 @@
11
import { isIndexedDBAvailable } from '@firebase/util';
2+
23
import { DataConnectError } from '../core/error';
4+
35
import { BackingDataObject } from './BackingDataObject';
46
import { CacheProvider } from './CacheProvider';
5-
import { ResultTree } from './ResultTree';
6-
import { ResultTreeProcessor } from './ResultTreeProcessor';
77
import { ImpactedQueryRefsAccumulator } from './ImpactedQueryRefsAccumulator';
88
import { IndexedDBCacheProvider } from './IndexedDBCacheProvider';
9+
import { ResultTree } from './ResultTree';
10+
import { ResultTreeProcessor } from './ResultTreeProcessor';
911

10-
export interface ServerValues extends Object {
12+
export interface ServerValues {
1113
ttl: number;
1214
}
1315

14-
export const BDO_OBJECT_STORE_NAME = 'data-connect-bdos';
15-
export const SRT_OBJECT_STORE_NAME = 'data-connect-srts';
16+
1617

1718
export class Cache {
1819
private cacheProvider: CacheProvider;
@@ -30,7 +31,7 @@ export class Cache {
3031
const resultTree = this.cacheProvider.getResultTree(queryId);
3132
return resultTree !== undefined;
3233
}
33-
getResultTree(queryId: string) {
34+
getResultTree(queryId: string): ResultTree {
3435
return this.cacheProvider.getResultTree(queryId);
3536
}
3637
getResultJSON(queryId: string): string {
@@ -66,7 +67,7 @@ class EphemeralCacheProvider implements CacheProvider {
6667
private bdos = new Map<string, BackingDataObject>();
6768
private resultTrees = new Map<string, ResultTree>();
6869

69-
setResultTree(queryId: string, rt: ResultTree) {
70+
setResultTree(queryId: string, rt: ResultTree): void {
7071
this.resultTrees.set(queryId, rt);
7172
}
7273
// TODO: Should this be in the cache provider? This seems common along all CacheProviders.

packages/data-connect/src/cache/ImpactedQueryRefsAccumulator.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
export class ImpactedQueryRefsAccumulator {
22
impacted = new Set<string>();
3-
add(impacted: string[]) {
3+
add(impacted: string[]): void {
44
impacted.forEach(ref => this.impacted.add(ref));
55
}
6-
consumeEvents() {
6+
consumeEvents(): string[] {
77
const events = Array.from(this.impacted);
88
this.impacted.clear();
99
return events;

packages/data-connect/src/cache/IndexedDBCacheProvider.ts

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
import { BackingDataObject } from './BackingDataObject';
2-
import { BDO_OBJECT_STORE_NAME, SRT_OBJECT_STORE_NAME } from './Cache';
32
import { CacheProvider } from './CacheProvider';
43
import { ResultTree } from './ResultTree';
5-
4+
export const BDO_OBJECT_STORE_NAME = 'data-connect-bdos';
5+
export const SRT_OBJECT_STORE_NAME = 'data-connect-srts';
66
export class IndexedDBCacheProvider implements CacheProvider {
77
private bdos = new Map<string, BackingDataObject>();
88
private resultTrees = new Map<string, ResultTree>();
99
private dbPromise: Promise<IDBDatabase>;
10-
isIdbAvailable() {
11-
console.log('indexedDB' in window);
10+
isIdbAvailable(): boolean {
1211
return typeof window !== 'undefined' && 'indexedDB' in window;
1312
}
1413

@@ -23,7 +22,6 @@ export class IndexedDBCacheProvider implements CacheProvider {
2322
const db = (event.target as IDBOpenDBRequest).result;
2423
db.createObjectStore(BDO_OBJECT_STORE_NAME);
2524
db.createObjectStore(SRT_OBJECT_STORE_NAME);
26-
console.log('upgrade!');
2725
dbResolve(db);
2826
};
2927
request.onsuccess = async (event) => {
@@ -41,10 +39,9 @@ export class IndexedDBCacheProvider implements CacheProvider {
4139
const cursor = (event.target as IDBRequest)
4240
.result as IDBCursorWithValue;
4341
if (cursor) {
44-
console.log('updating result tree');
4542
this.resultTrees.set(cursor.key as string, cursor.value);
43+
cursor.continue();
4644
} else {
47-
console.log('resolving bdo cursor');
4845
// No more entries
4946
resolve(null);
5047
}
@@ -64,8 +61,8 @@ export class IndexedDBCacheProvider implements CacheProvider {
6461
cursor.key as string,
6562
ResultTree.parse(cursor.value)
6663
);
64+
cursor.continue();
6765
} else {
68-
console.log('resolving srt cursor');
6966
// No more entries
7067
resolve(null);
7168
}
@@ -87,7 +84,7 @@ export class IndexedDBCacheProvider implements CacheProvider {
8784
};
8885
});
8986
}
90-
async commitBdoChanges(backingData: BackingDataObject) {
87+
async commitBdoChanges(backingData: BackingDataObject): Promise<void> {
9188
if (!this.isIdbAvailable()) {
9289
return;
9390
}
@@ -96,7 +93,7 @@ export class IndexedDBCacheProvider implements CacheProvider {
9693
.objectStore(BDO_OBJECT_STORE_NAME)
9794
.put(backingData, backingData.globalID);
9895
}
99-
async commitResultTreeChanges(queryId: string, rt: ResultTree) {
96+
async commitResultTreeChanges(queryId: string, rt: ResultTree): Promise<void> {
10097
if (!this.isIdbAvailable()) {
10198
return;
10299
}
@@ -131,6 +128,6 @@ export class IndexedDBCacheProvider implements CacheProvider {
131128
}
132129
updateBackingData(backingData: BackingDataObject): void {
133130
this.bdos.set(backingData.globalID, backingData);
134-
this.commitBdoChanges(backingData);
131+
void this.commitBdoChanges(backingData);
135132
}
136133
}
Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
1-
import { StubDataObject } from './StubDataObject';
1+
import { StubDataObject, StubDataObjectJson } from './StubDataObject';
22

33
export class ResultTree {
4-
static parse(value: any): ResultTree {
5-
console.log('RESULT TREE', value);
6-
// TODO: need to parse stubdataobject as well.
7-
// const rootStub = new StubDataObject()
4+
static parse(value: ResultTreeJson): ResultTree {
85
const rt = new ResultTree(
9-
JSON.parse(value.data),
6+
value.data,
107
StubDataObject.fromStorableJson(value.rootStub),
118
value.ttlInMs,
129
value.cachedAt,
@@ -17,22 +14,28 @@ export class ResultTree {
1714
constructor(
1815
public readonly data: string,
1916
private rootStub: StubDataObject,
20-
private ttlInMs: number = 30_000,
17+
private ttlInMs: number = 300_000,
2118
private readonly cachedAt: Date,
2219
private lastAccessed: Date
2320
) {}
2421
isStale(): boolean {
25-
const stale = Date.now() - this.cachedAt.getTime() > this.ttlInMs;
26-
console.log('isStale: ' + stale)
27-
return stale;
22+
return (Date.now() - new Date(this.cachedAt.getTime()).getTime()) > this.ttlInMs;
2823
}
29-
updateTtl(ttlInMs: number) {
24+
updateTtl(ttlInMs: number): void {
3025
this.ttlInMs = ttlInMs;
3126
}
32-
updateAccessed() {
27+
updateAccessed(): void {
3328
this.lastAccessed = new Date();
3429
}
35-
getRootStub() {
30+
getRootStub(): StubDataObject {
3631
return this.rootStub;
3732
}
3833
}
34+
35+
interface ResultTreeJson {
36+
rootStub: StubDataObjectJson;
37+
ttlInMs: number;
38+
cachedAt: Date;
39+
lastAccessed: Date;
40+
data: string;
41+
}

packages/data-connect/src/cache/ResultTreeProcessor.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,13 @@ interface DehydratedResults {
99

1010
export class ResultTreeProcessor {
1111
hydrateResults(rootStubObject: StubDataObject): string {
12-
// TODO: convert SDO into JSON
1312
return JSON.stringify(rootStubObject.toJson());
1413
}
1514
dehydrateResults(json: object, cacheProvider: CacheProvider, acc: ImpactedQueryRefsAccumulator): DehydratedResults {
1615
const stubDataObject = new StubDataObject(json, cacheProvider, acc);
1716
return {
1817
stubDataObject,
19-
data: JSON.stringify(stubDataObject.toJson())
18+
data: JSON.stringify(stubDataObject.toStorableJson())
2019
};
2120
}
2221
}

packages/data-connect/src/cache/StubDataObject.ts

Lines changed: 39 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
import { DataConnectError } from '../core/error';
2-
import { BackingDataObject, FDCScalarValue } from './BackingDataObject';
1+
import { DataConnectError } from '../api';
2+
3+
import { BackingDataObject, BackingDataObjectJson, FDCScalarValue } from './BackingDataObject';
34
import { CacheProvider } from './CacheProvider';
45
import { ImpactedQueryRefsAccumulator } from './ImpactedQueryRefsAccumulator';
56

@@ -20,7 +21,6 @@ export class StubDataObject {
2021
if(typeof values === 'undefined' && typeof cacheProvider === 'undefined' && typeof acc === 'undefined') {
2122
return;
2223
}
23-
// TODO: validate that all other fields have been passed in
2424
// TODO: validate that all other fields have been passed in.
2525
if (typeof values !== 'object' || Array.isArray(values)) {
2626
throw new DataConnectError(
@@ -46,11 +46,8 @@ export class StubDataObject {
4646
}
4747
if (typeof values[key] === 'object') {
4848
if (Array.isArray(values[key])) {
49-
if (!this.objectLists[key]) {
50-
this.objectLists[key] = [];
51-
}
5249
const objArray: StubDataObject[] = [];
53-
const scalarArray: NonNullable<FDCScalarValue>[] = [];
50+
const scalarArray: Array<NonNullable<FDCScalarValue>> = [];
5451
for (const value of values[key]) {
5552
if (typeof value === 'object') {
5653
if (Array.isArray(value)) {
@@ -117,6 +114,7 @@ export class StubDataObject {
117114
resultObject[key] = this.backingData[key];
118115
}
119116
}
117+
// Scalars should never have stubdataobjects
120118
for (const key in this.scalars) {
121119
if (this.scalars.hasOwnProperty(key)) {
122120
resultObject[key] = this.scalars[key];
@@ -129,37 +127,41 @@ export class StubDataObject {
129127
}
130128
for (const key in this.objectLists) {
131129
if (this.objectLists.hasOwnProperty(key)) {
132-
resultObject[key] = this.objectLists[key].map(obj => obj.toJson());
130+
resultObject[key] = this.objectLists[key].map(obj => {
131+
return obj.toJson();
132+
});
133133
}
134134
}
135135
return resultObject;
136136
}
137-
static parseMap(map: {[key: string]: any}): typeof map {
137+
static parseMap(map: {[key: string]: StubDataObject | StubDataObject[] | FDCScalarValue}, isSdo = false): typeof map {
138138
const newMap: typeof map = {};
139139
for (const key in map) {
140140
if(map.hasOwnProperty(key)) {
141141
if(Array.isArray(map[key])) {
142-
newMap[key] = map[key].map(value => StubDataObject.fromStorableJson(value));
142+
newMap[key] = map[key].map(value => isSdo ? StubDataObject.fromStorableJson(value) : value);
143143
} else {
144-
newMap[key] = StubDataObject.fromStorableJson(map[key]);
144+
newMap[key] = isSdo ? StubDataObject.fromStorableJson(map[key] as StubDataObjectJson) : map[key];
145145
}
146146
}
147147
}
148148
return newMap;
149149
}
150-
static fromStorableJson(obj: any): StubDataObject {
150+
static fromStorableJson(obj: StubDataObjectJson): StubDataObject {
151151
const sdo = new StubDataObject();
152-
// TODO: implement this.
153-
sdo.backingData = BackingDataObject.fromStorableJson(obj.backingData);
152+
if(obj.backingData) {
153+
sdo.backingData = BackingDataObject.fromStorableJson(obj.backingData);
154+
}
154155
sdo.acc = new ImpactedQueryRefsAccumulator();
155156
sdo.globalId = obj.globalID;
156157
sdo.impactedQueryRefs = new Set<string>();
157158
sdo.scalars = this.parseMap(obj.scalars);
158-
sdo.references = this.parseMap(obj.references);
159+
sdo.references = this.parseMap(obj.references) as typeof sdo.references;
160+
sdo.objectLists = this.parseMap(obj.objectLists, true) as typeof sdo.objectLists;
159161
return sdo;
160162
}
161-
getStorableMap(map: {[key: string]: any}) {
162-
const newMap: typeof map = {};
163+
getStorableMap(map: {[key: string]: StubDataObject | StubDataObject[]}): {[key: string]: StubDataObjectJson | StubDataObjectJson[]} {
164+
const newMap: {[key: string]: StubDataObjectJson | StubDataObjectJson[]} = {};
163165
for (const key in map) {
164166
if(map.hasOwnProperty(key)) {
165167
if(Array.isArray(map[key])) {
@@ -171,14 +173,26 @@ export class StubDataObject {
171173
}
172174
return newMap;
173175
}
174-
toStorableJson(): object {
175-
// TODO: replace all `any` types.
176-
const obj: any = {};
177-
obj.backingData = this.backingData.toStorableJson();
178-
obj.globalID = this.globalId;
179-
obj.scalars = this.scalars;
180-
obj.references = this.getStorableMap(this.references);
181-
obj.objectLists = this.getStorableMap(this.objectLists);
176+
toStorableJson(): StubDataObjectJson {
177+
const obj: StubDataObjectJson = {
178+
globalID: this.globalId,
179+
scalars: this.scalars,
180+
references: this.getStorableMap(this.references) as StubDataObjectJson['references'],
181+
objectLists: this.getStorableMap(this.objectLists) as StubDataObjectJson['objectLists']
182+
};
183+
if(this.backingData) {
184+
obj.backingData = this.backingData.toStorableJson();
185+
}
182186
return obj;
183187
}
184188
}
189+
190+
export interface StubDataObjectJson {
191+
backingData?: BackingDataObjectJson;
192+
globalID: string;
193+
scalars: { [key: string]: FDCScalarValue };
194+
references: { [key: string]: StubDataObjectJson };
195+
objectLists: {
196+
[key: string]: StubDataObjectJson[];
197+
};
198+
}

0 commit comments

Comments
 (0)