Merge branch 'master' into 13765-information-inside-details-panel
[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
10 export interface Resource {
11     uuid: string;
12     ownerUuid: string;
13     createdAt: string;
14     modifiedByClientUuid: string;
15     modifiedByUserUuid: string;
16     modifiedAt: string;
17     href: string;
18     kind: string;
19     etag: string;
20 }
21
22 export interface ListArguments {
23     limit?: number;
24     offset?: number;
25     filters?: FilterBuilder;
26     order?: OrderBuilder;
27     select?: string[];
28     distinct?: boolean;
29     count?: string;
30 }
31
32 export interface ListResults<T> {
33     kind: string;
34     offset: number;
35     limit: number;
36     items: T[];
37     itemsAvailable: number;
38 }
39
40 export default class CommonResourceService<T extends Resource> {
41
42     static mapResponseKeys = (response: any): Promise<any> =>
43         CommonResourceService.mapKeys(_.camelCase)(response.data)
44
45     static mapKeys = (mapFn: (key: string) => string) =>
46         (value: any): any => {
47             switch (true) {
48                 case _.isPlainObject(value):
49                     return Object
50                         .keys(value)
51                         .map(key => [key, mapFn(key)])
52                         .reduce((newValue, [key, newKey]) => ({
53                             ...newValue,
54                             [newKey]: CommonResourceService.mapKeys(mapFn)(value[key])
55                         }), {});
56                 case _.isArray(value):
57                     return value.map(CommonResourceService.mapKeys(mapFn));
58                 default:
59                     return value;
60             }
61         }
62
63     protected serverApi: AxiosInstance;
64     protected resourceType: string;
65
66     constructor(serverApi: AxiosInstance, resourceType: string) {
67         this.serverApi = serverApi;
68         this.resourceType = '/' + resourceType + '/';
69     }
70
71     create(data: Partial<T>) {
72         return this.serverApi
73             .post<T>(this.resourceType, CommonResourceService.mapKeys(_.snakeCase)(data))
74             .then(CommonResourceService.mapResponseKeys);
75     }
76
77     delete(uuid: string): Promise<T> {
78         return this.serverApi
79             .delete(this.resourceType + uuid)
80             .then(CommonResourceService.mapResponseKeys);
81     }
82
83     get(uuid: string) {
84         return this.serverApi
85             .get<T>(this.resourceType + uuid)
86             .then(CommonResourceService.mapResponseKeys);
87     }
88
89     list(args: ListArguments = {}): Promise<ListResults<T>> {
90         const { filters, order, ...other } = args;
91         const params = {
92             ...other,
93             filters: filters ? filters.serialize() : undefined,
94             order: order ? order.getOrder() : undefined
95         };
96         return this.serverApi
97             .get(this.resourceType, {
98                 params: CommonResourceService.mapKeys(_.snakeCase)(params)
99             })
100             .then(CommonResourceService.mapResponseKeys);
101     }
102
103     update(uuid: string) {
104         throw new Error("Not implemented");
105     }
106
107 }
108