/
MappedResolver.ts
100 lines (74 loc) · 2.85 KB
/
MappedResolver.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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import * as yup from "yup";
import {
DbMapper,
ObjectWithId,
ObjectWithIdAndTenant,
ZeroArgumentsConstructor,
} from "../../shared/db";
import GraphQLModelMapper from "../mappers/GraphQLModelMapper";
import shallowUpdate from "./shallowUpdate";
export default class MappedResolver<
TGraphQL extends TGraphQLCreateInput,
TGraphQLCreateInput extends object,
TGraphQLUpdateInput extends ObjectWithId,
TModel extends ObjectWithIdAndTenant,
TModelConstructor extends ZeroArgumentsConstructor<TModel>,
TMapper extends GraphQLModelMapper<TGraphQL, TGraphQLCreateInput, TModel>
> {
private readonly _modelConstructor: TModelConstructor;
private readonly _mapper: TMapper;
private readonly _schema?: yup.ObjectSchema;
public constructor(
modelConstructor: TModelConstructor,
mapper: TMapper,
schema?: yup.ObjectSchema
) {
this._modelConstructor = modelConstructor;
this._mapper = mapper;
this._schema = schema;
}
public async getAll(tenant: string): Promise<TGraphQL[]> {
const items: TGraphQL[] = [];
for await (const modelItem of DbMapper.query(this._modelConstructor, { tenant })) {
items.push(this._mapper.graphqlFromModel(modelItem));
}
return items;
}
public async getOne<TArgs extends ObjectWithId>(tenant: string, args: TArgs): Promise<TGraphQL> {
const itemCondition: Pick<TModel, "tenant" | "id"> = { tenant, id: args.id };
const item = await DbMapper.get(Object.assign(new this._modelConstructor(), itemCondition));
return this._mapper.graphqlFromModel(item);
}
public async create(tenant: string, input: TGraphQLCreateInput): Promise<TGraphQL> {
// Verify provided values
if (!this._schema) {
throw new Error("Schema required to create.");
}
await this._schema.validate(input);
// Build new object with provided values
const item = this._mapper.modelFromGraphql(tenant, input);
// Persist changes
await DbMapper.put(item);
return this._mapper.graphqlFromModel(item);
}
public async update(tenant: string, input: TGraphQLUpdateInput): Promise<TGraphQL> {
// Retrieve existing item
const initialModelCondition: Pick<TModel, "tenant" | "id"> = { tenant, id: input.id };
const initialModel = await DbMapper.get(
Object.assign(new this._modelConstructor(), initialModelCondition)
);
// Build GraphQL representation
const initialGraphql = this._mapper.graphqlFromModel(initialModel);
// Merge in mutated values
const updatedGraphql = shallowUpdate(initialGraphql, input);
// Verify combined values
if (!this._schema) {
throw new Error("Schema required to update.");
}
await this._schema.validate(updatedGraphql);
// Persist changes
const updatedModel = this._mapper.modelFromGraphql(tenant, updatedGraphql);
await DbMapper.put(updatedModel);
return updatedGraphql;
}
}