Skip to content

Commit 875b19b

Browse files
author
nebarf
committed
Add configurable prefix and separator to http cache store
1 parent 7253b70 commit 875b19b

File tree

7 files changed

+130
-32
lines changed

7 files changed

+130
-32
lines changed

src/cache/http-cache-store.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,33 @@
11
import { HttpCacheEntry } from './types';
22

3-
export abstract class HttpCacheStore<Identifier = string> {
3+
export interface HttpCacheStore {
44
/**
55
* Gets the cached entry for the given identifier.
66
*/
7-
abstract get<T>(identifier: Identifier): HttpCacheEntry<T> | undefined;
7+
get<T>(identifier: string): HttpCacheEntry<T> | undefined;
88

99
/**
1010
* Stores the entry.
1111
*/
12-
abstract put<T>(entry: HttpCacheEntry<T>): () => void;
12+
put<T>(identifier: string, entry: HttpCacheEntry<T>): () => void;
1313

1414
/**
1515
* Determines if the entry is in the store.
1616
*/
17-
abstract has(idenitifier: Identifier): boolean;
17+
has(identifier: string): boolean;
1818

1919
/**
2020
* Deletes the cached entry for the given identifier.
2121
*/
22-
abstract delete(idenitifier: Identifier): void;
22+
delete(identifier: string): void;
2323

2424
/**
2525
* Gets all stored entries.
2626
*/
27-
abstract entries(): HttpCacheEntry<unknown>[];
27+
entries(): HttpCacheEntry<unknown>[];
2828

2929
/**
3030
* Flushes the store by deleting all entries.
3131
*/
32-
abstract flush(): void;
32+
flush(): void;
3333
}

src/cache/http-cache.ts

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
1-
import { HttpCacheStore } from './http-cache-store';
21
import { HttpRequest } from '../client';
32
import { HttpCacheEntry } from './types';
3+
import { HttpCacheStorePrefixDecorator } from './prefix-decorator';
44

55
export class HttpCacheService {
6-
constructor(private store: HttpCacheStore) {}
6+
private prefixedStore: HttpCacheStorePrefixDecorator;
7+
8+
constructor(store: HttpCacheStorePrefixDecorator) {
9+
this.prefixedStore = store;
10+
}
711

812
/**
913
* Gets the unique key used as idenitifier to store
@@ -29,22 +33,22 @@ export class HttpCacheService {
2933
*/
3034
private getEntry<T>(request: HttpRequest): HttpCacheEntry<T> | undefined {
3135
const reqIdentifier = this.getRequestIdentifier(request);
32-
return this.store.get(reqIdentifier) as HttpCacheEntry<T>;
36+
return this.prefixedStore.get(reqIdentifier) as HttpCacheEntry<T>;
3337
}
3438

3539
/**
3640
* Removes a cached entry.
3741
*/
3842
private removeEntry<T>(entry: HttpCacheEntry<T>): void {
39-
this.store.delete(entry.identifier);
43+
this.prefixedStore.delete(entry.identifier);
4044
}
4145

4246
/**
4347
* Determines if for the given request is available a cached response.
4448
*/
4549
has(request: HttpRequest): boolean {
4650
const key = this.getRequestIdentifier(request);
47-
return this.store.has(key);
51+
return this.prefixedStore.has(key);
4852
}
4953

5054
/**
@@ -89,7 +93,7 @@ export class HttpCacheService {
8993
};
9094

9195
// Update the store.
92-
this.store.put(entry);
96+
this.prefixedStore.put(entry.identifier, entry);
9397

9498
// Remove the entry from the cache once expired.
9599
const timerRef = setTimeout(() => {
@@ -102,7 +106,7 @@ export class HttpCacheService {
102106
* Founds all expired entry and deletes them from the cache.
103107
*/
104108
prune(): void {
105-
const entries = this.store.entries();
109+
const entries = this.prefixedStore.entries();
106110
entries.forEach((entry) => {
107111
const isEntryExpired = this.isEntryExpired(entry);
108112

@@ -116,6 +120,6 @@ export class HttpCacheService {
116120
* Flush the cache by removing all entries.
117121
*/
118122
flush(): void {
119-
this.store.flush();
123+
this.prefixedStore.flush();
120124
}
121125
}

src/cache/http-in-memory-cache-store.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { HttpCacheEntry } from './types';
22
import { HttpCacheStore } from './http-cache-store';
33

4-
export class HttpInMemoryCacheStore extends HttpCacheStore {
4+
export class HttpInMemoryCacheStore implements HttpCacheStore {
55
/**
66
* The local cache providing for a request identifier
77
* the corresponding cached entry.
@@ -18,9 +18,9 @@ export class HttpInMemoryCacheStore extends HttpCacheStore {
1818
/**
1919
* @inheritdoc
2020
*/
21-
put<T>(entry: HttpCacheEntry<T>): () => void {
22-
this.store.set(entry.identifier, entry);
23-
return () => this.delete(entry.identifier);
21+
put<T>(identifier: string, entry: HttpCacheEntry<T>): () => void {
22+
this.store.set(identifier, entry);
23+
return () => this.delete(identifier);
2424
}
2525

2626
/**

src/cache/prefix-decorator.ts

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import { HttpCacheStore } from './http-cache-store';
2+
import { HttpCacheEntry } from './types';
3+
4+
export class HttpCacheStorePrefixDecorator implements HttpCacheStore {
5+
/**
6+
* The label use to prefix any entry identifier.
7+
*/
8+
private prefix = 'rhf';
9+
10+
/**
11+
* The label used to separate the prefix and the entry identifier.
12+
*/
13+
private separator = '__';
14+
15+
/**
16+
* The http cache store to decorate.
17+
*/
18+
private store: HttpCacheStore;
19+
20+
constructor(store: HttpCacheStore, prefix?: string, separator?: string) {
21+
this.store = store;
22+
this.prefix = prefix || this.prefix;
23+
this.separator = separator || this.separator;
24+
}
25+
26+
/**
27+
* Computes the entry identifier by concatenating the store prefix with
28+
* the base identifier.
29+
*/
30+
private getPrefixedIdentifier(entryIdentifier: string): string {
31+
return `${this.prefix}${this.separator}${entryIdentifier}`;
32+
}
33+
34+
/**
35+
* @inheritdoc
36+
*/
37+
get<T>(entryIdentifier: string): HttpCacheEntry<T> | undefined {
38+
const prefixedIdentifier = this.getPrefixedIdentifier(entryIdentifier);
39+
return this.store.get(prefixedIdentifier);
40+
}
41+
42+
/**
43+
* @inheritdoc
44+
*/
45+
put<T>(entryIdentifier: string, entry: HttpCacheEntry<T>): () => void {
46+
const prefixedIdentifier = this.getPrefixedIdentifier(entryIdentifier);
47+
return this.store.put(prefixedIdentifier, entry);
48+
}
49+
50+
/**
51+
* @inheritdoc
52+
*/
53+
has(entryIdentifier: string): boolean {
54+
const prefixedIdentifier = this.getPrefixedIdentifier(entryIdentifier);
55+
return this.store.has(prefixedIdentifier);
56+
}
57+
58+
/**
59+
* @inheritdoc
60+
*/
61+
delete(entryIdentifier: string): void {
62+
const prefixedIdentifier = this.getPrefixedIdentifier(entryIdentifier);
63+
return this.store.delete(prefixedIdentifier);
64+
}
65+
66+
/**
67+
* @inheritdoc
68+
*/
69+
entries(): HttpCacheEntry<unknown>[] {
70+
return this.store.entries();
71+
}
72+
73+
/**
74+
* @inheritdoc
75+
*/
76+
flush(): void {
77+
return this.store.flush();
78+
}
79+
}

src/config/defaults.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ import { HttpClientContextProps, HttpClientConfig } from './types';
22
import { httpResponseParser } from './response-parser';
33
import { serializeRequestBody } from './request-body-serializer';
44
import { HttpCacheService, HttpInMemoryCacheStore } from '../cache';
5+
import { HttpCacheStorePrefixDecorator } from '../cache/prefix-decorator';
6+
7+
export const defaultCacheStore = new HttpInMemoryCacheStore();
58

69
export const defaultHttpReqConfig: HttpClientConfig = {
710
baseUrl: '',
@@ -12,7 +15,7 @@ export const defaultHttpReqConfig: HttpClientConfig = {
1215
'Content-Type': 'application/json',
1316
},
1417
},
15-
cache: new HttpCacheService(new HttpInMemoryCacheStore()),
18+
cache: new HttpCacheService(new HttpCacheStorePrefixDecorator(defaultCacheStore)),
1619
};
1720

1821
export const defaultClientProps: HttpClientContextProps = {

src/config/http-client-config-provider.tsx

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import React, { ReactElement, createContext, useContext, memo, useMemo } from 'react';
22
import { useCompareMemo } from '../shared';
3-
import { defaultClientProps, defaultHttpReqConfig } from './defaults';
3+
import { defaultClientProps, defaultHttpReqConfig, defaultCacheStore } from './defaults';
44
import { HttpClientContextProps, HttpClientProviderProps, HttpClientConfig } from './types';
55
import fastCompare from 'react-fast-compare';
66
import { HttpCacheService } from '..';
7+
import { HttpCacheStorePrefixDecorator } from '../cache/prefix-decorator';
78

89
/**
910
* The context to provide the default http client configuration.
@@ -18,16 +19,25 @@ const HttpClientConfigProvider = ({ config, children }: HttpClientProviderProps)
1819
* The merged http config.
1920
*/
2021
const mergedHttpConfig: HttpClientConfig = useCompareMemo(
21-
() => ({
22-
baseUrl: config.baseUrl || defaultHttpReqConfig.baseUrl,
23-
responseParser: config.responseParser || defaultHttpReqConfig.responseParser,
24-
reqOptions: config.reqOptions || defaultHttpReqConfig.reqOptions,
25-
requestBodySerializer:
26-
config.requestBodySerializer || defaultHttpReqConfig.requestBodySerializer,
27-
cache: config.cacheStore
28-
? new HttpCacheService(config.cacheStore)
29-
: defaultHttpReqConfig.cache,
30-
}),
22+
() => {
23+
const cacheStore = config.cacheStore || defaultCacheStore;
24+
const prefixedCacheStore = new HttpCacheStorePrefixDecorator(
25+
cacheStore,
26+
config.cacheStorePrefix,
27+
config.cacheStoreSeparator
28+
);
29+
30+
const cache = new HttpCacheService(prefixedCacheStore);
31+
32+
return {
33+
baseUrl: config.baseUrl || defaultHttpReqConfig.baseUrl,
34+
responseParser: config.responseParser || defaultHttpReqConfig.responseParser,
35+
reqOptions: config.reqOptions || defaultHttpReqConfig.reqOptions,
36+
requestBodySerializer:
37+
config.requestBodySerializer || defaultHttpReqConfig.requestBodySerializer,
38+
cache,
39+
};
40+
},
3141
[config],
3242
fastCompare
3343
);

src/config/types.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,11 @@ export interface HttpClientProviderConfig {
3131
responseParser: HttpResponseParser;
3232
requestBodySerializer: HttpRequestBodySerializer;
3333
cacheStore: HttpCacheStore;
34+
cacheStorePrefix: string;
35+
cacheStoreSeparator: string;
3436
}
3537

3638
export interface HttpClientProviderProps {
3739
children: ReactElement;
38-
config: HttpClientProviderConfig;
40+
config: Partial<HttpClientProviderConfig>;
3941
}

0 commit comments

Comments
 (0)