Skip to content

Commit 7472d5d

Browse files
committed
Completed first pass of caching
1 parent fcd22d5 commit 7472d5d

File tree

9 files changed

+32
-47
lines changed

9 files changed

+32
-47
lines changed

common/api-review/data-connect.api.md

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@ import { Provider } from '@firebase/component';
1515
export interface CacheSettings {
1616
// (undocumented)
1717
cacheProvider?: IndexedDBStub<StorageType>;
18-
// (undocumented)
19-
maxSizeBytes?: number;
2018
}
2119

2220
// @public
@@ -236,9 +234,9 @@ export const QUERY_STR = "query";
236234

237235
// @public
238236
export const QueryFetchPolicy: {
239-
PREFER_CACHE: string;
240-
CACHE_ONLY: string;
241-
SERVER_ONLY: string;
237+
readonly PREFER_CACHE: "PREFER_CACHE";
238+
readonly CACHE_ONLY: "CACHE_ONLY";
239+
readonly SERVER_ONLY: "SERVER_ONLY";
242240
};
243241

244242
// @public (undocumented)

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

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -386,15 +386,13 @@ export function terminate(dataConnect: DataConnect): Promise<void> {
386386
// TODO(mtewani): Stop pending tasks
387387
}
388388
export const StorageType = {
389-
// PERSISTENT: 'PERSISTENT',
390389
MEMORY: 'MEMORY'
391390
};
392391

393392
export type StorageType = (typeof StorageType)[keyof typeof StorageType];
394393

395394

396395
export interface CacheSettings {
397-
maxSizeBytes?: number;
398396
cacheProvider?: CacheProvider<StorageType>;
399397
}
400398
export interface CacheProvider<T extends StorageType> {

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,9 +133,12 @@ export class DataConnectCache {
133133
const { data, stubDataObject } = await processor.dehydrateResults(
134134
serverValues,
135135
cacheProvider,
136-
acc
136+
acc,
137+
queryId
137138
);
138139
const now = new Date();
140+
// TODO: Check if ttl actually gets passed.
141+
// TODO: Check API Proposal fields.
139142
await cacheProvider.setResultTree(
140143
queryId,
141144
new ResultTree(data, stubDataObject, serverValues.ttl, now, now)

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

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -64,19 +64,10 @@ export class EntityDataObject {
6464
private map: {[key:string]: FDCScalarValue} = {};
6565
private queriesReferenced = new Set<string>();
6666
constructor(public readonly globalID: string) {}
67-
updateServerValue(key: string, value: FDCScalarValue): string[] {
67+
updateServerValue(key: string, value: FDCScalarValue, requestedFrom: string): string[] {
6868
this.map[key] = value;
69+
this.queriesReferenced.add(requestedFrom);
6970
return Array.from(this.queriesReferenced);
7071
}
7172
// TODO(mtewani): Add a way to track what fields are associated with each query during runtime.
72-
// private queryToFields = new Map<string, string[]>();
73-
track(queryId: string): void {
74-
this.queriesReferenced.add(queryId);
75-
// if(!this.queryToFields.has(queryId)) {
76-
// this.queryToFields.set(queryId, []);
77-
// }
78-
// if(!this.queryToFields.get(queryId).includes(key)) {
79-
// this.queryToFields.get(queryId).push(key);
80-
// }
81-
}
8273
}

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

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ export class EntityNode {
4242
}
4343

4444
async loadData(
45+
queryId: string,
4546
values?: FDCScalarValue,
4647
cacheProvider?: InternalCacheProvider,
4748
): Promise<void> {
@@ -61,11 +62,13 @@ export class EntityNode {
6162
return;
6263
}
6364

65+
6466
if (
6567
values.hasOwnProperty(GLOBAL_ID_KEY) &&
6668
typeof values[GLOBAL_ID_KEY] === 'string'
6769
) {
6870
this.globalId = values[GLOBAL_ID_KEY];
71+
// TODO: Add current query id to BDO
6972
this.entityData = await cacheProvider.getBdo(this.globalId);
7073
}
7174
for (const key in values) {
@@ -82,8 +85,8 @@ export class EntityNode {
8285
if (Array.isArray(value)) {
8386
// Note: we don't support sparse arrays.
8487
} else {
85-
const entityNode = new EntityNode( this.acc);
86-
await entityNode.loadData(value, cacheProvider);
88+
const entityNode = new EntityNode(this.acc);
89+
await entityNode.loadData(queryId, value, cacheProvider);
8790
objArray.push(entityNode);
8891
}
8992
} else {
@@ -100,7 +103,8 @@ export class EntityNode {
100103
if (this.entityData) {
101104
const impactedRefs = this.entityData.updateServerValue(
102105
key,
103-
scalarArray
106+
scalarArray,
107+
queryId
104108
);
105109
this.acc.add(impactedRefs);
106110
} else {
@@ -119,15 +123,16 @@ export class EntityNode {
119123
const stubDataObject = new EntityNode(
120124
this.acc
121125
);
122-
await stubDataObject.loadData(values[key], cacheProvider);
126+
await stubDataObject.loadData(queryId, values[key], cacheProvider);
123127
this.references[key] = stubDataObject;
124128
}
125129
} else {
126130
if (this.entityData) {
127131
// TODO: Track only the fields we need for the BDO
128132
const impactedRefs = this.entityData.updateServerValue(
129133
key,
130-
values[key]
134+
values[key],
135+
queryId
131136
);
132137
this.acc.add(impactedRefs);
133138
} else {

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ export class ResultTree {
3131
constructor(
3232
public readonly data: string,
3333
private rootStub: EntityNode,
34-
private ttlInMs: number = 300_000,
35-
private readonly cachedAt: Date,
34+
private ttlInMs: number = 30000,
35+
public readonly cachedAt: Date,
3636
private _lastAccessed: Date
3737
) {}
3838
isStale(): boolean {

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,11 @@ export class ResultTreeProcessor {
3131
async dehydrateResults(
3232
json: object,
3333
cacheProvider: InternalCacheProvider,
34-
acc: ImpactedQueryRefsAccumulator
34+
acc: ImpactedQueryRefsAccumulator,
35+
queryId: string
3536
): Promise< DehydratedResults> {
3637
const stubDataObject = new EntityNode(acc);
37-
await stubDataObject.loadData(json, cacheProvider);
38+
await stubDataObject.loadData(queryId, json, cacheProvider);
3839
return {
3940
stubDataObject,
4041
data: JSON.stringify(stubDataObject.toStorableJson())

packages/data-connect/src/core/query/QueryManager.ts

Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ function getRefSerializer<Data, Variables>(
5252
...queryRef.dataConnect.getSettings()
5353
}
5454
},
55-
fetchTime: Date.now().toLocaleString(),
55+
fetchTime: Date.now().toLocaleString(), // TODO: Fix the fetch time here.
5656
source
5757
};
5858
};
@@ -109,17 +109,13 @@ export class QueryManager {
109109
refType: QUERY_STR
110110
});
111111
const unsubscribe = (): void => {
112-
if (!this.callbacks.has(key)) {
112+
if (this.callbacks.has(key)) {
113113
const callbackList = this.callbacks.get(key)!;
114-
callbackList.forEach(subscription => {
115-
subscription.unsubscribe();
116-
});
117-
this.callbacks.set(key, []);
114+
this.callbacks.set(key, callbackList.filter(callback => callback.userCallback !== onResultCallback));
118115
}
119116
};
120117

121118
if (initialCache) {
122-
// TODO: The type might be wrong here
123119
this.updateSSR(initialCache as QueryResult<Data, Variables>);
124120
}
125121

@@ -161,21 +157,19 @@ export class QueryManager {
161157
variables: queryRef.variables,
162158
refType: QUERY_STR
163159
});
164-
// TODO: It seems like the cache isn't loading the data correctly.
165-
// TODO: It seems like cache loading is async. That needs to be fixed.
166160
if (
167161
options?.fetchPolicy !== QueryFetchPolicy.SERVER_ONLY &&
168162
(await this.cache.containsResultTree(key)) &&
169163
!(await this.cache.getResultTree(key)).isStale()
170164
) {
171165
const cacheResult: Data = JSON.parse(await this.cache.getResultJSON(key));
166+
const resultTree = await this.cache.getResultTree(key);
172167
const result: QueryResult<Data, Variables> = {
173-
...cacheResult,
174168
source: SOURCE_CACHE,
175169
ref: queryRef,
176170
data: cacheResult,
177171
toJSON: getRefSerializer(queryRef, cacheResult, SOURCE_CACHE),
178-
fetchTime: new Date().toISOString()
172+
fetchTime: resultTree.cachedAt.toString(),
179173
};
180174
(await this.cache.getResultTree(key)).updateAccessed();
181175
logDebug(
@@ -207,18 +201,13 @@ export class QueryManager {
207201
);
208202
const fetchTime = new Date().toString();
209203
const result: QueryResult<Data, Variables> = {
210-
...res,
204+
data: res.data,
211205
source: SOURCE_SERVER,
212206
ref: queryRef,
213207
toJSON: getRefSerializer(queryRef, res.data, SOURCE_SERVER),
214208
fetchTime
215209
};
216-
const subscribers = this.callbacks.get(key);
217-
if (subscribers !== undefined) {
218-
subscribers.forEach(subscription => {
219-
subscription.userCallback(result);
220-
});
221-
}
210+
222211
if (await this.cache.containsResultTree(key)) {
223212
(await this.cache.getResultTree(key)).updateAccessed();
224213
}

packages/data-connect/src/core/query/queryOptions.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export const QueryFetchPolicy = {
1919
PREFER_CACHE: 'PREFER_CACHE',
2020
CACHE_ONLY: 'CACHE_ONLY',
2121
SERVER_ONLY: 'SERVER_ONLY'
22-
};
22+
} as const;
2323

2424
/*
2525
* Represents policy for how executeQuery fetches data

0 commit comments

Comments
 (0)