Merge branch '13797-refatoring-part2'
[arvados-workbench2.git] / src / common / api / common-resource-service.ts
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 import * as _ from "lodash";
6 import { FilterBuilder } from "./filter-builder";
7 import { OrderBuilder } from "./order-builder";
8 import { AxiosInstance } from "axios";
9 import { Resource } from "../../models/resource";
10
11 export interface ListArguments {
12     limit?: number;
13     offset?: number;
14     filters?: FilterBuilder;
15     order?: OrderBuilder;
16     select?: string[];
17     distinct?: boolean;
18     count?: string;
19 }
20
21 export interface ListResults<T> {
22     kind: string;
23     offset: number;
24     limit: number;
25     items: T[];
26     itemsAvailable: number;
27 }
28
29 export class CommonResourceService<T extends Resource> {
30
31     static mapResponseKeys = (response: any): Promise<any> =>
32         CommonResourceService.mapKeys(_.camelCase)(response.data)
33
34     static mapKeys = (mapFn: (key: string) => string) =>
35         (value: any): any => {
36             switch (true) {
37                 case _.isPlainObject(value):
38                     return Object
39                         .keys(value)
40                         .map(key => [key, mapFn(key)])
41                         .reduce((newValue, [key, newKey]) => ({
42                             ...newValue,
43                             [newKey]: CommonResourceService.mapKeys(mapFn)(value[key])
44                         }), {});
45                 case _.isArray(value):
46                     return value.map(CommonResourceService.mapKeys(mapFn));
47                 default:
48                     return value;
49             }
50         }
51
52     protected serverApi: AxiosInstance;
53     protected resourceType: string;
54
55     constructor(serverApi: AxiosInstance, resourceType: string) {
56         this.serverApi = serverApi;
57         this.resourceType = '/' + resourceType + '/';
58     }
59
60     create(data: Partial<T>) {
61         return this.serverApi
62             .post<T>(this.resourceType, CommonResourceService.mapKeys(_.snakeCase)(data))
63             .then(CommonResourceService.mapResponseKeys);
64     }
65
66     delete(uuid: string): Promise<T> {
67         return this.serverApi
68             .delete(this.resourceType + uuid)
69             .then(CommonResourceService.mapResponseKeys);
70     }
71
72     get(uuid: string) {
73         return this.serverApi
74             .get<T>(this.resourceType + uuid)
75             .then(CommonResourceService.mapResponseKeys);
76     }
77
78     list(args: ListArguments = {}): Promise<ListResults<T>> {
79         const { filters, order, ...other } = args;
80         const params = {
81             ...other,
82             filters: filters ? filters.serialize() : undefined,
83             order: order ? order.getOrder() : undefined
84         };
85         return this.serverApi
86             .get(this.resourceType, {
87                 params: CommonResourceService.mapKeys(_.snakeCase)(params)
88             })
89             .then(CommonResourceService.mapResponseKeys);
90     }
91
92     update(uuid: string) {
93         throw new Error("Not implemented");
94     }
95 }
96