UNPKG

3.14 kBPlain TextView Raw
1import { Context } from "./Context";
2import { Strategy } from "./Strategy";
3import { GraphQLFieldConfig, GraphQLNamedType } from "graphql";
4import { Authority, AuthorityData, Credential, CredentialData } from "./model";
5
6export class StrategyCollection {
7 public map: { [name: string]: Strategy } = {};
8
9 public authorityMap: {
10 readonly [name: string]: {
11 new (data: AuthorityData<any> & { readonly recordId: string }): Authority<
12 any
13 >;
14 };
15 } = {};
16
17 public credentialMap: {
18 readonly [name: string]: {
19 new (
20 data: CredentialData<any> & { readonly recordId: string }
21 ): Credential<any>;
22 };
23 } = {};
24
25 public queryFields: {
26 readonly [field: string]: GraphQLFieldConfig<any, Context, any>;
27 } = {};
28
29 public mutationFields: {
30 readonly [field: string]: GraphQLFieldConfig<any, Context, any>;
31 } = {};
32
33 public types: GraphQLNamedType[] = [];
34
35 public constructor(strategies?: Iterable<Strategy>) {
36 if (strategies) {
37 for (const strategy of strategies) {
38 this.add(strategy);
39 }
40 }
41 }
42
43 public add(s: Strategy): StrategyCollection {
44 if (this.map[s.name])
45 throw new Error(
46 `INVARIANT: Multiple strategies cannot use the same identifier; "${s.name}" is used twice.`
47 );
48
49 const queryFields = { ...this.queryFields };
50 for (const f of Object.keys(s.queryFields)) {
51 if (queryFields[f]) {
52 throw new Error(
53 `INVARIANT: Multiple strategies cannot use the query field; "${f}" is used twice.`
54 );
55 }
56
57 queryFields[f] = s.queryFields[f];
58 }
59
60 const mutationFields = { ...this.mutationFields };
61 for (const f of Object.keys(s.mutationFields)) {
62 if (mutationFields[f]) {
63 throw new Error(
64 `INVARIANT: Multiple strategies cannot use the mutation field; "${f}" is used twice.`
65 );
66 }
67
68 mutationFields[f] = s.mutationFields[f];
69 }
70
71 this.map = { ...this.map, [s.name]: s };
72 this.authorityMap = { ...this.authorityMap, [s.name]: s.authorityModel };
73 this.credentialMap = { ...this.credentialMap, [s.name]: s.credentialModel };
74 this.queryFields = queryFields;
75 this.mutationFields = mutationFields;
76 this.types = [...this.types, ...s.types];
77
78 return this;
79 }
80
81 public delete(s: Strategy): boolean {
82 if (!this.map[s.name]) return false;
83
84 const map = { ...this.map };
85 delete map[s.name];
86
87 const authorityMap = { ...this.authorityMap };
88 delete authorityMap[s.name];
89
90 const credentialMap = { ...this.credentialMap };
91 delete credentialMap[s.name];
92
93 const queryFields = { ...this.queryFields };
94 for (const f of Object.keys(s.queryFields)) {
95 delete queryFields[f];
96 }
97
98 const mutationFields = { ...this.mutationFields };
99 for (const f of Object.keys(s.mutationFields)) {
100 delete mutationFields[f];
101 }
102
103 this.map = map;
104 this.authorityMap = authorityMap;
105 this.credentialMap = credentialMap;
106 this.queryFields = queryFields;
107 this.mutationFields = mutationFields;
108 this.types = this.types.filter(t => !s.types.includes(t));
109
110 return true;
111 }
112}