Skip to content

Commit 21a2406

Browse files
committed
OengusAPI reports fetching states
Related to Issue #47
1 parent 081e74d commit 21a2406

File tree

1 file changed

+36
-28
lines changed

1 file changed

+36
-28
lines changed

plugins/oengus.ts

+36-28
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@ import { ActionContext } from 'vuex';
22
import { NuxtHTTPInstance } from '@nuxt/http';
33
import { Context } from '@nuxt/types';
44

5-
export interface OengusStateCacheable {
6-
_expires: number;
5+
export interface OengusStateCacheable<V> {
6+
_cachedAt: number;
7+
_fetching: boolean;
8+
_promise: Promise<V&OengusStateCacheable<V>>;
79
}
8-
export type OengusStateValue<V> = V&OengusStateCacheable|OengusStateCacheable|undefined;
10+
export type OengusStateValue<V> = V&OengusStateCacheable<V>|OengusStateCacheable<V>|undefined;
911
export interface OengusStateValuesById<V> {
1012
[ id: string ]: OengusStateValue<V>;
1113
}
@@ -39,7 +41,7 @@ export interface GetterArgs<U, V = U> {
3941
* Used to alter the raw API response to whatever is stored in the state
4042
* This can be strip, change, or add new values or even change into a full class
4143
*/
42-
transform?(value: U, id?: number|string): V&OengusStateCacheable;
44+
transform?(value: U, id?: number|string): V;
4345
/**
4446
* How long should responses be cached for
4547
* Can be ignored with forceFetch
@@ -84,44 +86,50 @@ export class OengusAPI<T extends OengusState> {
8486
}
8587

8688
// Cache check
87-
let response: OengusStateValue<U|V> = id ? state[key][id] : state[key];
88-
const cachedTime = response?._expires ?? 0;
89-
if (cachedTime + cacheDuration > Date.now() && !forceFetch) {
90-
return response as V;
89+
const cachedResponse: OengusStateValue<V> = id ? state[key][id] : state[key];
90+
const cachedTime = cachedResponse?._cachedAt ?? 0;
91+
const fetching = cachedResponse?._fetching ?? false;
92+
if (fetching || (!forceFetch && cachedTime + cacheDuration > Date.now())) {
93+
return cachedResponse as V;
9194
}
9295

96+
// Setup the fetching promise
97+
let fetchingResolve: (value: OengusStateValue<V>) => void;
98+
let fetchingReject: (reason: { reason?: any, oldValue: OengusStateValue<V> }) => void;
99+
const fetchingPromise = new Promise<OengusStateValue<V>>((resolve, reject) => {
100+
fetchingResolve = resolve;
101+
fetchingReject = reject;
102+
});
103+
104+
// Mark the entry as updating by changing _fetching property
93105
if (cachedTime) {
94-
// Mark the entry as updating by changing the cache expired marker
95106
// This allows existing stuff to continue to use the cached value,
96-
commit(mutation, { id, value: { ...response, _expires: Date.now() } });
107+
commit(mutation, { id, value: { ...cachedResponse, _fetching: true, _promise: fetchingPromise } });
97108
} else {
98-
// Mark the entry as "being fetched" by giving it a promise
99-
// Anything that wants to read the value is welcome to await it or use Vuex's observers
100-
commit(mutation, { id, value: { _expires: Date.now() } });
109+
commit(mutation, { id, value: { _cachedAt: Date.now(), _fetching: true, _promise: fetchingPromise } });
101110
}
102111

103112
// Fetch and store into cache
104113
const route = `${this.basePath}${id ? `/${id}` : ''}${path ? `/${path}` : ''}`;
105-
let apiResponse: U&OengusStateCacheable;
114+
let apiResponse: U;
106115
try {
107116
apiResponse = await OengusAPI.http.$get(route);
108-
} catch {
109-
// This isn't intrinsically bad, just catch the error, mark as not fetching, and return nothing
110-
if (cachedTime) {
111-
// Reset the old cache timer, maybe the API is just down (should we worry about loops?)
112-
commit(mutation, { id, value: response });
113-
} else {
114-
commit(mutation, { id, value: undefined });
115-
}
117+
} catch (error) {
118+
// This isn't intrinsically bad, just catch the error, mark as not fetching, and return the old value
119+
// Put the old value back in full, maybe the API is just down (should we worry about loops?)
120+
fetchingReject!({ reason: error, oldValue: cachedResponse });
121+
commit(mutation, { id, value: cachedResponse });
116122
return;
117123
}
118-
response = apiResponse;
119124

120-
if (transform) {
121-
response = transform(response as U, id);
122-
}
123-
response._expires = Date.now();
124-
commit(mutation, { id, value: response as OengusStateValue<V> });
125+
const response = {
126+
...(transform ? transform(apiResponse as U, id) : apiResponse),
127+
_fetching: false,
128+
_cachedAt: Date.now(),
129+
_promise: fetchingPromise,
130+
} as OengusStateValue<V>;
131+
fetchingResolve!(response);
132+
commit(mutation, { id, value: response });
125133
return response as V;
126134
};
127135
}

0 commit comments

Comments
 (0)