-
Notifications
You must be signed in to change notification settings - Fork 121
/
ConvertingRouterRule.ts
62 lines (57 loc) · 2.4 KB
/
ConvertingRouterRule.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
import type { Representation } from '../../http/representation/Representation';
import type { ResourceIdentifier } from '../../http/representation/ResourceIdentifier';
import type { ResourceStore } from '../ResourceStore';
import type { PreferenceSupport } from './PreferenceSupport';
import { RouterRule } from './RouterRule';
export interface ConvertingStoreEntry {
store: ResourceStore;
supportChecker: PreferenceSupport;
}
/**
* Rule that directs requests based on how the data would need to be converted.
* In case the given converter can convert the data to the requested type,
* it will be directed to the `convertStore`.
* Otherwise the `defaultStore` will be chosen.
*
* In case there is no data and only an identifier the `defaultStore` will be checked
* if it contains the given identifier.
* If not, the `convertStore` will be returned.
*/
export class ConvertingRouterRule extends RouterRule {
private readonly typedStores: ConvertingStoreEntry[];
private readonly defaultStore: ResourceStore;
public constructor(typedStore: ConvertingStoreEntry, defaultStore: ResourceStore) {
super();
this.typedStores = [ typedStore ];
this.defaultStore = defaultStore;
}
public async handle(input: { identifier: ResourceIdentifier; representation?: Representation }):
Promise<ResourceStore> {
const { identifier, representation } = input;
let store: ResourceStore;
if (representation) {
// TS type checking is not smart enough to let us reuse the input object
store = await this.findStore(async(entry): Promise<boolean> =>
entry.supportChecker.supports({ identifier, representation }));
} else {
// No content-type given so we can only check if one of the stores has data for the identifier
store = await this.findStore(async(entry): Promise<boolean> => entry.store.hasResource(identifier));
}
return store;
}
/**
* Helper function that runs the given callback function for all the stores
* and returns the first one that does not throw an error.
*
* Returns the default store if no match was found.
*/
private async findStore(supports: (entry: ConvertingStoreEntry) => Promise<boolean>): Promise<ResourceStore> {
// Try all the stores, return default if there is no match
for (const entry of this.typedStores) {
if (await supports(entry)) {
return entry.store;
}
}
return this.defaultStore;
}
}