Add partial copy form async name validation
[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 { AxiosInstance, AxiosPromise } from "axios";
7 import { Resource } from "~/models/resource";
8
9 export interface ListArguments {
10     limit?: number;
11     offset?: number;
12     filters?: string;
13     order?: string;
14     select?: string[];
15     distinct?: boolean;
16     count?: string;
17 }
18
19 export interface ListResults<T> {
20     kind: string;
21     offset: number;
22     limit: number;
23     items: T[];
24     itemsAvailable: number;
25 }
26
27 export interface Errors {
28     errors: string[];
29     errorToken: string;
30 }
31
32 export enum CommonResourceServiceError {
33     UNIQUE_VIOLATION = 'UniqueViolation',
34     UNKNOWN = 'Unknown',
35     NONE = 'None'
36 }
37
38 export class CommonResourceService<T extends Resource> {
39
40     static mapResponseKeys = (response: any): Promise<any> =>
41         CommonResourceService.mapKeys(_.camelCase)(response.data)
42
43     static mapKeys = (mapFn: (key: string) => string) =>
44         (value: any): any => {
45             switch (true) {
46                 case _.isPlainObject(value):
47                     return Object
48                         .keys(value)
49                         .map(key => [key, mapFn(key)])
50                         .reduce((newValue, [key, newKey]) => ({
51                             ...newValue,
52                             [newKey]: CommonResourceService.mapKeys(mapFn)(value[key])
53                         }), {});
54                 case _.isArray(value):
55                     return value.map(CommonResourceService.mapKeys(mapFn));
56                 default:
57                     return value;
58             }
59         }
60
61     static defaultResponse<R>(promise: AxiosPromise<R>): Promise<R> {
62         return promise
63             .then(CommonResourceService.mapResponseKeys)
64             .catch(({ response }) => Promise.reject<Errors>(CommonResourceService.mapResponseKeys(response)));
65     }
66
67     protected serverApi: AxiosInstance;
68     protected resourceType: string;
69
70     constructor(serverApi: AxiosInstance, resourceType: string) {
71         this.serverApi = serverApi;
72         this.resourceType = '/' + resourceType + '/';
73     }
74
75     create(data?: Partial<T> | any) {
76         return CommonResourceService.defaultResponse(
77             this.serverApi
78                 .post<T>(this.resourceType, data && CommonResourceService.mapKeys(_.snakeCase)(data)));
79     }
80
81     delete(uuid: string): Promise<T> {
82         return CommonResourceService.defaultResponse(
83             this.serverApi
84                 .delete(this.resourceType + uuid));
85     }
86
87     get(uuid: string) {
88         return CommonResourceService.defaultResponse(
89             this.serverApi
90                 .get<T>(this.resourceType + uuid));
91     }
92
93     list(args: ListArguments = {}): Promise<ListResults<T>> {
94         const { filters, order, ...other } = args;
95         const params = {
96             ...other,
97             filters: filters ? `[${filters}]` : undefined,
98             order: order ? order : undefined
99         };
100         return CommonResourceService.defaultResponse(
101             this.serverApi
102                 .get(this.resourceType, {
103                     params: CommonResourceService.mapKeys(_.snakeCase)(params)
104                 }));
105     }
106
107     update(uuid: string, data: any) {
108         return CommonResourceService.defaultResponse(
109             this.serverApi
110                 .put<T>(this.resourceType + uuid, data));
111
112     }
113 }
114
115 export const getCommonResourceServiceError = (errorResponse: any) => {
116     if ('errors' in errorResponse && 'errorToken' in errorResponse) {
117         const error = errorResponse.errors.join('');
118         switch (true) {
119             case /UniqueViolation/.test(error):
120                 return CommonResourceServiceError.UNIQUE_VIOLATION;
121             default:
122                 return CommonResourceServiceError.UNKNOWN;
123         }
124     }
125     return CommonResourceServiceError.NONE;
126 };
127
128