@dhis2/app-service-data 3.7.0 → 3.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/cjs/__tests__/integration.test.js +16 -10
- package/build/cjs/__tests__/mutations.test.js +8 -5
- package/build/cjs/engine/DataEngine.js +14 -12
- package/build/cjs/engine/helpers/resolveDynamicQuery.js +14 -11
- package/build/cjs/engine/helpers/resolveDynamicQuery.test.js +23 -14
- package/build/cjs/engine/helpers/validate.js +6 -4
- package/build/cjs/engine/helpers/validate.test.js +74 -15
- package/build/cjs/engine/types/FetchError.js +6 -5
- package/build/cjs/engine/types/InvalidQueryError.js +1 -1
- package/build/cjs/index.js +10 -10
- package/build/cjs/links/CustomDataLink.js +8 -6
- package/build/cjs/links/CustomDataLink.test.js +2 -2
- package/build/cjs/links/RestAPILink/fetchData.js +3 -2
- package/build/cjs/links/RestAPILink/fetchData.test.js +1 -1
- package/build/cjs/links/RestAPILink/metadataResources.js +1 -1
- package/build/cjs/links/RestAPILink/path.js +5 -1
- package/build/cjs/links/RestAPILink/queryToRequestOptions/multipartFormDataMatchers.js +29 -16
- package/build/cjs/links/RestAPILink/queryToRequestOptions/requestContentType.js +9 -6
- package/build/cjs/links/RestAPILink/queryToRequestOptions/requestContentType.test.js +2 -2
- package/build/cjs/links/RestAPILink/queryToRequestOptions/textPlainMatchers.js +51 -33
- package/build/cjs/links/RestAPILink/queryToRequestOptions/xWwwFormUrlencodedMatchers.js +6 -3
- package/build/cjs/links/RestAPILink/queryToRequestOptions.js +1 -1
- package/build/cjs/links/RestAPILink/queryToRequestOptions.test.js +56 -6
- package/build/cjs/links/RestAPILink/queryToResourcePath.js +14 -6
- package/build/cjs/links/RestAPILink/queryToResourcePath.test.js +16 -16
- package/build/cjs/links/RestAPILink/validateQuery.test.js +12 -12
- package/build/cjs/links/RestAPILink.js +4 -3
- package/build/cjs/react/components/CustomDataProvider.js +7 -6
- package/build/cjs/react/components/DataMutation.js +8 -7
- package/build/cjs/react/components/DataProvider.js +1 -1
- package/build/cjs/react/components/DataQuery.js +9 -8
- package/build/cjs/react/context/defaultContext.test.js +10 -2
- package/build/cjs/react/hooks/stableVariablesHash.js +1 -2
- package/build/cjs/react/hooks/stableVariablesHash.test.js +6 -6
- package/build/cjs/react/hooks/useDataMutation.js +7 -6
- package/build/cjs/react/hooks/useDataMutation.test.js +70 -43
- package/build/cjs/react/hooks/useDataQuery.js +13 -9
- package/build/cjs/react/hooks/useDataQuery.test.js +259 -162
- package/build/cjs/react/hooks/useQueryExecutor.js +11 -9
- package/build/cjs/react/hooks/useQueryExecutor.test.js +16 -12
- package/build/cjs/react/hooks/useStaticInput.js +7 -6
- package/build/cjs/react/hooks/useStaticInput.test.js +44 -25
- package/build/cjs/react/index.js +6 -6
- package/build/es/__tests__/integration.test.js +16 -10
- package/build/es/__tests__/mutations.test.js +8 -5
- package/build/es/engine/DataEngine.js +14 -12
- package/build/es/engine/helpers/resolveDynamicQuery.js +14 -11
- package/build/es/engine/helpers/resolveDynamicQuery.test.js +23 -14
- package/build/es/engine/helpers/validate.js +6 -4
- package/build/es/engine/helpers/validate.test.js +74 -15
- package/build/es/engine/types/FetchError.js +6 -5
- package/build/es/engine/types/InvalidQueryError.js +1 -1
- package/build/es/links/CustomDataLink.js +8 -6
- package/build/es/links/CustomDataLink.test.js +2 -2
- package/build/es/links/RestAPILink/fetchData.js +3 -2
- package/build/es/links/RestAPILink/fetchData.test.js +1 -1
- package/build/es/links/RestAPILink/path.js +5 -1
- package/build/es/links/RestAPILink/queryToRequestOptions/multipartFormDataMatchers.js +28 -15
- package/build/es/links/RestAPILink/queryToRequestOptions/requestContentType.js +8 -5
- package/build/es/links/RestAPILink/queryToRequestOptions/requestContentType.test.js +2 -2
- package/build/es/links/RestAPILink/queryToRequestOptions/textPlainMatchers.js +50 -32
- package/build/es/links/RestAPILink/queryToRequestOptions/xWwwFormUrlencodedMatchers.js +6 -3
- package/build/es/links/RestAPILink/queryToRequestOptions.js +1 -1
- package/build/es/links/RestAPILink/queryToRequestOptions.test.js +56 -6
- package/build/es/links/RestAPILink/queryToResourcePath.js +14 -6
- package/build/es/links/RestAPILink/queryToResourcePath.test.js +16 -16
- package/build/es/links/RestAPILink/validateQuery.test.js +12 -12
- package/build/es/links/RestAPILink.js +4 -3
- package/build/es/react/components/CustomDataProvider.js +7 -6
- package/build/es/react/components/DataMutation.js +8 -7
- package/build/es/react/components/DataQuery.js +9 -8
- package/build/es/react/context/defaultContext.test.js +10 -2
- package/build/es/react/hooks/stableVariablesHash.js +1 -2
- package/build/es/react/hooks/stableVariablesHash.test.js +6 -6
- package/build/es/react/hooks/useDataMutation.js +7 -6
- package/build/es/react/hooks/useDataMutation.test.js +70 -43
- package/build/es/react/hooks/useDataQuery.js +13 -9
- package/build/es/react/hooks/useDataQuery.test.js +259 -162
- package/build/es/react/hooks/useQueryExecutor.js +11 -9
- package/build/es/react/hooks/useQueryExecutor.test.js +16 -12
- package/build/es/react/hooks/useStaticInput.js +7 -6
- package/build/es/react/hooks/useStaticInput.test.js +44 -25
- package/package.json +2 -2
|
@@ -26,7 +26,7 @@ export const parseStatus = async response => {
|
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
if (response.status < 200 || response.status >= 400) {
|
|
29
|
-
const message =
|
|
29
|
+
const message = `An unknown error occurred - ${response.statusText} (${response.status})`;
|
|
30
30
|
let details = {};
|
|
31
31
|
|
|
32
32
|
try {
|
|
@@ -43,7 +43,8 @@ export const parseStatus = async response => {
|
|
|
43
43
|
|
|
44
44
|
return response;
|
|
45
45
|
};
|
|
46
|
-
export function fetchData(url
|
|
46
|
+
export function fetchData(url) {
|
|
47
|
+
let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
47
48
|
return fetch(url, { ...options,
|
|
48
49
|
credentials: 'include',
|
|
49
50
|
headers: {
|
|
@@ -77,7 +77,7 @@ describe('networkFetch', () => {
|
|
|
77
77
|
};
|
|
78
78
|
expect(parseStatus(response)).rejects.toMatchObject({
|
|
79
79
|
type: 'unknown',
|
|
80
|
-
message:
|
|
80
|
+
message: `An unknown error occurred - Failed (500)`,
|
|
81
81
|
details: {
|
|
82
82
|
message: 'An error occurred'
|
|
83
83
|
}
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
export const joinPath = (
|
|
1
|
+
export const joinPath = function () {
|
|
2
|
+
for (var _len = arguments.length, parts = new Array(_len), _key = 0; _key < _len; _key++) {
|
|
3
|
+
parts[_key] = arguments[_key];
|
|
4
|
+
}
|
|
5
|
+
|
|
2
6
|
const realParts = parts.filter(part => !!part);
|
|
3
7
|
return realParts.map(part => part.replace(/^\/+|\/+$/g, '')).join('/');
|
|
4
8
|
};
|
|
@@ -5,25 +5,38 @@
|
|
|
5
5
|
*/
|
|
6
6
|
// Post to 'dataValues' (send/update a data value; endpoint doesn't support JSON)
|
|
7
7
|
// For file-uploads too
|
|
8
|
-
export const isDataValue = (type, {
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
export const isDataValue = (type, _ref) => {
|
|
9
|
+
let {
|
|
10
|
+
resource
|
|
11
|
+
} = _ref;
|
|
12
|
+
return type === 'create' && (resource === 'dataValues' || resource === 'dataValues/file');
|
|
13
|
+
}; // POST to 'fileResources' (upload a file resource)
|
|
11
14
|
|
|
12
|
-
export const isFileResourceUpload = (type, {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
+
export const isFileResourceUpload = (type, _ref2) => {
|
|
16
|
+
let {
|
|
17
|
+
resource
|
|
18
|
+
} = _ref2;
|
|
19
|
+
return type === 'create' && resource === 'fileResources';
|
|
20
|
+
}; // POST to 'messageConversations/attachments' (upload a message conversation attachment)
|
|
15
21
|
|
|
16
|
-
export const isMessageConversationAttachment = (type, {
|
|
17
|
-
|
|
18
|
-
|
|
22
|
+
export const isMessageConversationAttachment = (type, _ref3) => {
|
|
23
|
+
let {
|
|
24
|
+
resource
|
|
25
|
+
} = _ref3;
|
|
26
|
+
return type === 'create' && resource === 'messageConversations/attachments';
|
|
27
|
+
}; // POST to `staticContent/${key}` (upload staticContent: logo_banner | logo_front)
|
|
19
28
|
|
|
20
|
-
export const isStaticContentUpload = (type, {
|
|
21
|
-
|
|
22
|
-
|
|
29
|
+
export const isStaticContentUpload = (type, _ref4) => {
|
|
30
|
+
let {
|
|
31
|
+
resource
|
|
32
|
+
} = _ref4;
|
|
23
33
|
const pattern = /^staticContent\/(?:logo_banner|logo_front)$/;
|
|
24
34
|
return type === 'create' && pattern.test(resource);
|
|
25
35
|
}; // POST to 'apps' (install an app)
|
|
26
36
|
|
|
27
|
-
export const isAppInstall = (type, {
|
|
28
|
-
|
|
29
|
-
|
|
37
|
+
export const isAppInstall = (type, _ref5) => {
|
|
38
|
+
let {
|
|
39
|
+
resource
|
|
40
|
+
} = _ref5;
|
|
41
|
+
return type === 'create' && resource === 'apps';
|
|
42
|
+
};
|
|
@@ -12,10 +12,11 @@ const convertData = (data, initialValue) => {
|
|
|
12
12
|
const dataEntries = Object.entries(data);
|
|
13
13
|
|
|
14
14
|
if (dataEntries.length === 0) {
|
|
15
|
-
throw new Error(
|
|
15
|
+
throw new Error(`Could not convert data to ${initialValue.constructor.name}: object does not have own enumerable string-keyed properties`);
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
return dataEntries.reduce((convertedData,
|
|
18
|
+
return dataEntries.reduce((convertedData, _ref) => {
|
|
19
|
+
let [key, value] = _ref;
|
|
19
20
|
convertedData.append(key, value);
|
|
20
21
|
return convertedData;
|
|
21
22
|
}, initialValue);
|
|
@@ -60,9 +61,11 @@ export const requestHeadersForContentType = contentType => {
|
|
|
60
61
|
'Content-Type': contentType
|
|
61
62
|
};
|
|
62
63
|
};
|
|
63
|
-
export const requestBodyForContentType = (contentType, {
|
|
64
|
-
|
|
65
|
-
|
|
64
|
+
export const requestBodyForContentType = (contentType, _ref2) => {
|
|
65
|
+
let {
|
|
66
|
+
data
|
|
67
|
+
} = _ref2;
|
|
68
|
+
|
|
66
69
|
if (typeof data === 'undefined') {
|
|
67
70
|
return undefined;
|
|
68
71
|
}
|
|
@@ -85,7 +85,7 @@ describe('requestBodyForContentType', () => {
|
|
|
85
85
|
type: 'text/plain'
|
|
86
86
|
})
|
|
87
87
|
});
|
|
88
|
-
}).toThrowErrorMatchingInlineSnapshot("
|
|
88
|
+
}).toThrowErrorMatchingInlineSnapshot(`"Could not convert data to FormData: object does not have own enumerable string-keyed properties"`);
|
|
89
89
|
});
|
|
90
90
|
it('converts to URLSearchParams if contentType is "application/x-www-form-urlencoded"', () => {
|
|
91
91
|
const data = {
|
|
@@ -106,7 +106,7 @@ describe('requestBodyForContentType', () => {
|
|
|
106
106
|
type: 'text/plain'
|
|
107
107
|
})
|
|
108
108
|
});
|
|
109
|
-
}).toThrowErrorMatchingInlineSnapshot("
|
|
109
|
+
}).toThrowErrorMatchingInlineSnapshot(`"Could not convert data to URLSearchParams: object does not have own enumerable string-keyed properties"`);
|
|
110
110
|
});
|
|
111
111
|
it('returns the data as received if contentType is "text/plain"', () => {
|
|
112
112
|
const data = 'Something';
|
|
@@ -9,28 +9,35 @@
|
|
|
9
9
|
* "create" mutation-objects, we will have to include additional checks below.
|
|
10
10
|
*/
|
|
11
11
|
// POST to `messageConversations/${id}` (reply to a messagConversation)
|
|
12
|
-
export const isReplyToMessageConversation = (type, {
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
export const isReplyToMessageConversation = (type, _ref) => {
|
|
13
|
+
let {
|
|
14
|
+
resource
|
|
15
|
+
} = _ref;
|
|
15
16
|
const pattern = /^messageConversations\/[a-zA-Z0-9]{11}$/;
|
|
16
17
|
return type === 'create' && pattern.test(resource);
|
|
17
18
|
}; // POST to 'messageConversations/feedback' (create a feedback message)
|
|
18
19
|
|
|
19
|
-
export const isCreateFeedbackMessage = (type, {
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
export const isCreateFeedbackMessage = (type, _ref2) => {
|
|
21
|
+
let {
|
|
22
|
+
resource
|
|
23
|
+
} = _ref2;
|
|
24
|
+
return type === 'create' && resource === 'messageConversations/feedback';
|
|
25
|
+
}; // POST `interpretations/${objectType}/${id}` (add an interpretation to a visualization)
|
|
22
26
|
|
|
23
|
-
export const isCreateInterpretation = (type, {
|
|
24
|
-
|
|
25
|
-
|
|
27
|
+
export const isCreateInterpretation = (type, _ref3) => {
|
|
28
|
+
let {
|
|
29
|
+
resource
|
|
30
|
+
} = _ref3;
|
|
26
31
|
const pattern = /^interpretations\/(?:reportTable|chart|visualization|map|eventVisualization|eventReport|eventChart|dataSetReport)\/[a-zA-Z0-9]{11}$/;
|
|
27
32
|
return type === 'create' && pattern.test(resource);
|
|
28
33
|
}; // PUT to `interpretations/${id}` (update an interpretation)
|
|
29
34
|
|
|
30
|
-
export const isUpdateInterpretation = (type, {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
35
|
+
export const isUpdateInterpretation = (type, _ref4) => {
|
|
36
|
+
let {
|
|
37
|
+
resource,
|
|
38
|
+
id
|
|
39
|
+
} = _ref4;
|
|
40
|
+
|
|
34
41
|
if (type !== 'replace') {
|
|
35
42
|
return false;
|
|
36
43
|
}
|
|
@@ -47,18 +54,21 @@ export const isUpdateInterpretation = (type, {
|
|
|
47
54
|
return resourcePattern.test(resource);
|
|
48
55
|
}; // POST to `interpretations/${id}/comments` (comment on an interpretation)
|
|
49
56
|
|
|
50
|
-
export const isCommentOnInterpretation = (type, {
|
|
51
|
-
|
|
52
|
-
|
|
57
|
+
export const isCommentOnInterpretation = (type, _ref5) => {
|
|
58
|
+
let {
|
|
59
|
+
resource
|
|
60
|
+
} = _ref5;
|
|
53
61
|
const pattern = /^interpretations\/[a-zA-Z0-9]{11}\/comments$/;
|
|
54
62
|
return type === 'create' && pattern.test(resource);
|
|
55
63
|
}; // PUT to `interpretations/${interpretationId}/comments/${commentId}`
|
|
56
64
|
// (update an interpretation comment)
|
|
57
65
|
|
|
58
|
-
export const isInterpretationCommentUpdate = (type, {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
66
|
+
export const isInterpretationCommentUpdate = (type, _ref6) => {
|
|
67
|
+
let {
|
|
68
|
+
resource,
|
|
69
|
+
id
|
|
70
|
+
} = _ref6;
|
|
71
|
+
|
|
62
72
|
if (type !== 'replace') {
|
|
63
73
|
return false;
|
|
64
74
|
}
|
|
@@ -75,28 +85,36 @@ export const isInterpretationCommentUpdate = (type, {
|
|
|
75
85
|
}; // POST to `systemSettings/${settingKey}` or `userSettings/${settingKey}`
|
|
76
86
|
// (add or update a single system or user setting)
|
|
77
87
|
|
|
78
|
-
export const isAddOrUpdateSystemOrUserSetting = (type, {
|
|
79
|
-
|
|
80
|
-
|
|
88
|
+
export const isAddOrUpdateSystemOrUserSetting = (type, _ref7) => {
|
|
89
|
+
let {
|
|
90
|
+
resource
|
|
91
|
+
} = _ref7;
|
|
81
92
|
// At least 4 chars because the all start with 'key' (i.e. keyStyle)
|
|
82
93
|
const pattern = /^(?:systemSettings|userSettings)\/[a-zA-Z]{4,}$/;
|
|
83
94
|
return type === 'create' && pattern.test(resource);
|
|
84
95
|
}; // POST to `configuration/${configurationProperty}`
|
|
85
96
|
// (add or update a single configuration property)
|
|
86
97
|
|
|
87
|
-
export const addOrUpdateConfigurationProperty = (type, {
|
|
88
|
-
|
|
89
|
-
|
|
98
|
+
export const addOrUpdateConfigurationProperty = (type, _ref8) => {
|
|
99
|
+
let {
|
|
100
|
+
resource
|
|
101
|
+
} = _ref8;
|
|
90
102
|
// NOTE: The corsWhitelist property does expect "application/json"
|
|
91
103
|
const pattern = /^(configuration)\/([a-zA-Z]{1,50})$/;
|
|
92
104
|
const match = resource.match(pattern);
|
|
93
105
|
return type === 'create' && !!match && match[2] !== 'corsWhitelist';
|
|
94
106
|
}; // POST to 'synchronization/metadataPull' (install a metadata package)
|
|
95
107
|
|
|
96
|
-
export const isMetadataPackageInstallation = (type, {
|
|
97
|
-
|
|
98
|
-
|
|
108
|
+
export const isMetadataPackageInstallation = (type, _ref9) => {
|
|
109
|
+
let {
|
|
110
|
+
resource
|
|
111
|
+
} = _ref9;
|
|
112
|
+
return type === 'create' && resource === 'synchronization/metadataPull';
|
|
113
|
+
}; // POST to 'indicaators/expression/description' (validate an expression)
|
|
99
114
|
|
|
100
|
-
export const isExpressionDescriptionValidation = (type, {
|
|
101
|
-
|
|
102
|
-
|
|
115
|
+
export const isExpressionDescriptionValidation = (type, _ref10) => {
|
|
116
|
+
let {
|
|
117
|
+
resource
|
|
118
|
+
} = _ref10;
|
|
119
|
+
return type === 'create' && resource === 'indicators/expression/description';
|
|
120
|
+
};
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
// POST to convert an SVG file
|
|
2
|
-
export const isSvgConversion = (type, {
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
export const isSvgConversion = (type, _ref) => {
|
|
3
|
+
let {
|
|
4
|
+
resource
|
|
5
|
+
} = _ref;
|
|
6
|
+
return type === 'create' && (resource === 'svg.png' || resource === 'svg.pdf');
|
|
7
|
+
};
|
|
@@ -4,7 +4,14 @@ describe('queryToRequestOptions', () => {
|
|
|
4
4
|
const options = queryToRequestOptions('read', {
|
|
5
5
|
resource: 'test'
|
|
6
6
|
});
|
|
7
|
-
expect(options).toMatchInlineSnapshot(
|
|
7
|
+
expect(options).toMatchInlineSnapshot(`
|
|
8
|
+
Object {
|
|
9
|
+
"body": undefined,
|
|
10
|
+
"headers": undefined,
|
|
11
|
+
"method": "GET",
|
|
12
|
+
"signal": undefined,
|
|
13
|
+
}
|
|
14
|
+
`);
|
|
8
15
|
});
|
|
9
16
|
it('should return a valid Fetch option object for create request', () => {
|
|
10
17
|
const options = queryToRequestOptions('create', {
|
|
@@ -14,7 +21,16 @@ describe('queryToRequestOptions', () => {
|
|
|
14
21
|
foo: 'bar'
|
|
15
22
|
}
|
|
16
23
|
});
|
|
17
|
-
expect(options).toMatchInlineSnapshot(
|
|
24
|
+
expect(options).toMatchInlineSnapshot(`
|
|
25
|
+
Object {
|
|
26
|
+
"body": "{\\"answer\\":42,\\"foo\\":\\"bar\\"}",
|
|
27
|
+
"headers": Object {
|
|
28
|
+
"Content-Type": "application/json",
|
|
29
|
+
},
|
|
30
|
+
"method": "POST",
|
|
31
|
+
"signal": undefined,
|
|
32
|
+
}
|
|
33
|
+
`);
|
|
18
34
|
});
|
|
19
35
|
it('should return a valid Fetch option object for update request', () => {
|
|
20
36
|
const options = queryToRequestOptions('update', {
|
|
@@ -24,7 +40,16 @@ describe('queryToRequestOptions', () => {
|
|
|
24
40
|
foo: 'bar'
|
|
25
41
|
}
|
|
26
42
|
});
|
|
27
|
-
expect(options).toMatchInlineSnapshot(
|
|
43
|
+
expect(options).toMatchInlineSnapshot(`
|
|
44
|
+
Object {
|
|
45
|
+
"body": "{\\"answer\\":42,\\"foo\\":\\"bar\\"}",
|
|
46
|
+
"headers": Object {
|
|
47
|
+
"Content-Type": "application/json",
|
|
48
|
+
},
|
|
49
|
+
"method": "PATCH",
|
|
50
|
+
"signal": undefined,
|
|
51
|
+
}
|
|
52
|
+
`);
|
|
28
53
|
});
|
|
29
54
|
it('should return a valid Fetch option object for json-patch request', () => {
|
|
30
55
|
const options = queryToRequestOptions('json-patch', {
|
|
@@ -34,7 +59,16 @@ describe('queryToRequestOptions', () => {
|
|
|
34
59
|
foo: 'bar'
|
|
35
60
|
}
|
|
36
61
|
});
|
|
37
|
-
expect(options).toMatchInlineSnapshot(
|
|
62
|
+
expect(options).toMatchInlineSnapshot(`
|
|
63
|
+
Object {
|
|
64
|
+
"body": "{\\"answer\\":42,\\"foo\\":\\"bar\\"}",
|
|
65
|
+
"headers": Object {
|
|
66
|
+
"Content-Type": "application/json-patch+json",
|
|
67
|
+
},
|
|
68
|
+
"method": "PATCH",
|
|
69
|
+
"signal": undefined,
|
|
70
|
+
}
|
|
71
|
+
`);
|
|
38
72
|
});
|
|
39
73
|
it('should return a valid Fetch option object for replace request', () => {
|
|
40
74
|
const options = queryToRequestOptions('replace', {
|
|
@@ -44,12 +78,28 @@ describe('queryToRequestOptions', () => {
|
|
|
44
78
|
foo: 'bar'
|
|
45
79
|
}
|
|
46
80
|
});
|
|
47
|
-
expect(options).toMatchInlineSnapshot(
|
|
81
|
+
expect(options).toMatchInlineSnapshot(`
|
|
82
|
+
Object {
|
|
83
|
+
"body": "{\\"answer\\":42,\\"foo\\":\\"bar\\"}",
|
|
84
|
+
"headers": Object {
|
|
85
|
+
"Content-Type": "application/json",
|
|
86
|
+
},
|
|
87
|
+
"method": "PUT",
|
|
88
|
+
"signal": undefined,
|
|
89
|
+
}
|
|
90
|
+
`);
|
|
48
91
|
});
|
|
49
92
|
it('should return a valid Fetch option object for delete request', () => {
|
|
50
93
|
const options = queryToRequestOptions('delete', {
|
|
51
94
|
resource: 'test'
|
|
52
95
|
});
|
|
53
|
-
expect(options).toMatchInlineSnapshot(
|
|
96
|
+
expect(options).toMatchInlineSnapshot(`
|
|
97
|
+
Object {
|
|
98
|
+
"body": undefined,
|
|
99
|
+
"headers": undefined,
|
|
100
|
+
"method": "DELETE",
|
|
101
|
+
"signal": undefined,
|
|
102
|
+
}
|
|
103
|
+
`);
|
|
54
104
|
});
|
|
55
105
|
});
|
|
@@ -43,17 +43,20 @@ const queryParametersMapToArray = params => Object.keys(params).reduce((out, key
|
|
|
43
43
|
|
|
44
44
|
const queryParametersToQueryString = params => {
|
|
45
45
|
const expandedParams = queryParametersMapToArray(params);
|
|
46
|
-
return expandedParams.map(({
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
46
|
+
return expandedParams.map((_ref) => {
|
|
47
|
+
let {
|
|
48
|
+
key,
|
|
49
|
+
value
|
|
50
|
+
} = _ref;
|
|
51
|
+
return `${encodeURIComponent(key)}=${encodeQueryParameter(value)}`;
|
|
52
|
+
}).join('&');
|
|
50
53
|
};
|
|
51
54
|
|
|
52
55
|
const actionPrefix = 'action::';
|
|
53
56
|
|
|
54
57
|
const isAction = resource => resource.startsWith(actionPrefix);
|
|
55
58
|
|
|
56
|
-
const makeActionPath = resource => joinPath('dhis-web-commons',
|
|
59
|
+
const makeActionPath = resource => joinPath('dhis-web-commons', `${resource.substr(actionPrefix.length)}.action`);
|
|
57
60
|
|
|
58
61
|
const skipApiVersion = (resource, config) => {
|
|
59
62
|
if (resource === 'tracker' || resource.startsWith('tracker/')) {
|
|
@@ -62,6 +65,11 @@ const skipApiVersion = (resource, config) => {
|
|
|
62
65
|
if (!((_config$serverVersion = config.serverVersion) !== null && _config$serverVersion !== void 0 && _config$serverVersion.minor) || ((_config$serverVersion2 = config.serverVersion) === null || _config$serverVersion2 === void 0 ? void 0 : _config$serverVersion2.minor) < 38) {
|
|
63
66
|
return true;
|
|
64
67
|
}
|
|
68
|
+
} // The `/api/ping` endpoint is unversioned
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
if (resource === 'ping') {
|
|
72
|
+
return true;
|
|
65
73
|
}
|
|
66
74
|
|
|
67
75
|
return false;
|
|
@@ -78,7 +86,7 @@ export const queryToResourcePath = (link, query, type) => {
|
|
|
78
86
|
validateResourceQuery(query, type);
|
|
79
87
|
|
|
80
88
|
if (Object.keys(params).length) {
|
|
81
|
-
return
|
|
89
|
+
return `${base}?${queryParametersToQueryString(params)}`;
|
|
82
90
|
}
|
|
83
91
|
|
|
84
92
|
return base;
|
|
@@ -14,7 +14,7 @@ const defaultConfig = {
|
|
|
14
14
|
};
|
|
15
15
|
const link = createLink(defaultConfig);
|
|
16
16
|
const apiPath = link.versionedApiPath;
|
|
17
|
-
const actionPrefix =
|
|
17
|
+
const actionPrefix = `dhis-web-commons/`;
|
|
18
18
|
const actionPostfix = '.action';
|
|
19
19
|
describe('queryToResourcePath', () => {
|
|
20
20
|
describe('action', () => {
|
|
@@ -22,7 +22,7 @@ describe('queryToResourcePath', () => {
|
|
|
22
22
|
const query = {
|
|
23
23
|
resource: 'action::test'
|
|
24
24
|
};
|
|
25
|
-
expect(queryToResourcePath(link, query, 'read')).toBe(
|
|
25
|
+
expect(queryToResourcePath(link, query, 'read')).toBe(`${actionPrefix}test${actionPostfix}`);
|
|
26
26
|
});
|
|
27
27
|
it('should return action URL with a simple querystring if query parameters are passed', () => {
|
|
28
28
|
const query = {
|
|
@@ -31,7 +31,7 @@ describe('queryToResourcePath', () => {
|
|
|
31
31
|
key: 'value'
|
|
32
32
|
}
|
|
33
33
|
};
|
|
34
|
-
expect(queryToResourcePath(link, query, 'read')).toBe(
|
|
34
|
+
expect(queryToResourcePath(link, query, 'read')).toBe(`${actionPrefix}test${actionPostfix}?key=value`);
|
|
35
35
|
});
|
|
36
36
|
});
|
|
37
37
|
describe('resource with dot', () => {
|
|
@@ -39,14 +39,14 @@ describe('queryToResourcePath', () => {
|
|
|
39
39
|
const query = {
|
|
40
40
|
resource: 'svg.pdf'
|
|
41
41
|
};
|
|
42
|
-
expect(queryToResourcePath(link, query, 'read')).toBe(
|
|
42
|
+
expect(queryToResourcePath(link, query, 'read')).toBe(`${apiPath}/svg.pdf`);
|
|
43
43
|
});
|
|
44
44
|
});
|
|
45
45
|
it('should return resource url with no querystring if not query parameters are passed', () => {
|
|
46
46
|
const query = {
|
|
47
47
|
resource: 'test'
|
|
48
48
|
};
|
|
49
|
-
expect(queryToResourcePath(link, query, 'read')).toBe(
|
|
49
|
+
expect(queryToResourcePath(link, query, 'read')).toBe(`${apiPath}/test`);
|
|
50
50
|
});
|
|
51
51
|
it('should return resource url and singular parameter separated by ?', () => {
|
|
52
52
|
const query = {
|
|
@@ -55,7 +55,7 @@ describe('queryToResourcePath', () => {
|
|
|
55
55
|
key: 'value'
|
|
56
56
|
}
|
|
57
57
|
};
|
|
58
|
-
expect(queryToResourcePath(link, query, 'read')).toBe(
|
|
58
|
+
expect(queryToResourcePath(link, query, 'read')).toBe(`${apiPath}/test?key=value`);
|
|
59
59
|
});
|
|
60
60
|
it('should return resource url and multiple parameters separated by ? and &', () => {
|
|
61
61
|
const query = {
|
|
@@ -65,7 +65,7 @@ describe('queryToResourcePath', () => {
|
|
|
65
65
|
param: 'value2'
|
|
66
66
|
}
|
|
67
67
|
};
|
|
68
|
-
expect(queryToResourcePath(link, query, 'read')).toBe(
|
|
68
|
+
expect(queryToResourcePath(link, query, 'read')).toBe(`${apiPath}/test?key=value¶m=value2`);
|
|
69
69
|
});
|
|
70
70
|
it('should url encode special characters in query keys', () => {
|
|
71
71
|
const query = {
|
|
@@ -74,7 +74,7 @@ describe('queryToResourcePath', () => {
|
|
|
74
74
|
'key=42&val': 'value'
|
|
75
75
|
}
|
|
76
76
|
};
|
|
77
|
-
expect(queryToResourcePath(link, query, 'read')).toBe(
|
|
77
|
+
expect(queryToResourcePath(link, query, 'read')).toBe(`${apiPath}/test?key%3D42%26val=value`);
|
|
78
78
|
});
|
|
79
79
|
it('should url encode special characters in string parameters', () => {
|
|
80
80
|
const query = {
|
|
@@ -84,7 +84,7 @@ describe('queryToResourcePath', () => {
|
|
|
84
84
|
param: 'value2&& 53'
|
|
85
85
|
}
|
|
86
86
|
};
|
|
87
|
-
expect(queryToResourcePath(link, query, 'read')).toBe(
|
|
87
|
+
expect(queryToResourcePath(link, query, 'read')).toBe(`${apiPath}/test?key=value%3F%3D42¶m=value2%26%26%2053`);
|
|
88
88
|
});
|
|
89
89
|
it('should support numeric (integer and float) parameters', () => {
|
|
90
90
|
const query = {
|
|
@@ -94,7 +94,7 @@ describe('queryToResourcePath', () => {
|
|
|
94
94
|
param: 193.75
|
|
95
95
|
}
|
|
96
96
|
};
|
|
97
|
-
expect(queryToResourcePath(link, query, 'read')).toBe(
|
|
97
|
+
expect(queryToResourcePath(link, query, 'read')).toBe(`${apiPath}/test?key=42¶m=193.75`);
|
|
98
98
|
});
|
|
99
99
|
it('should support boolean parameters', () => {
|
|
100
100
|
const query = {
|
|
@@ -104,7 +104,7 @@ describe('queryToResourcePath', () => {
|
|
|
104
104
|
someflag: true
|
|
105
105
|
}
|
|
106
106
|
};
|
|
107
|
-
expect(queryToResourcePath(link, query, 'read')).toBe(
|
|
107
|
+
expect(queryToResourcePath(link, query, 'read')).toBe(`${apiPath}/test?key=42&someflag=true`);
|
|
108
108
|
});
|
|
109
109
|
it('should join array parameters with commas', () => {
|
|
110
110
|
const query = {
|
|
@@ -113,7 +113,7 @@ describe('queryToResourcePath', () => {
|
|
|
113
113
|
key: ['asdf', 123]
|
|
114
114
|
}
|
|
115
115
|
};
|
|
116
|
-
expect(queryToResourcePath(link, query, 'read')).toBe(
|
|
116
|
+
expect(queryToResourcePath(link, query, 'read')).toBe(`${apiPath}/test?key=asdf,123`);
|
|
117
117
|
});
|
|
118
118
|
it('should include multiple filter parameters when array of filters provided', () => {
|
|
119
119
|
const query = {
|
|
@@ -122,7 +122,7 @@ describe('queryToResourcePath', () => {
|
|
|
122
122
|
filter: ['asdf', 123]
|
|
123
123
|
}
|
|
124
124
|
};
|
|
125
|
-
expect(queryToResourcePath(link, query, 'read')).toBe(
|
|
125
|
+
expect(queryToResourcePath(link, query, 'read')).toBe(`${apiPath}/test?filter=asdf&filter=123`);
|
|
126
126
|
});
|
|
127
127
|
it('should NOT YET support name-aliased parameters', () => {
|
|
128
128
|
const query = {
|
|
@@ -148,13 +148,13 @@ describe('queryToResourcePath', () => {
|
|
|
148
148
|
const query = {
|
|
149
149
|
resource: 'tracker'
|
|
150
150
|
};
|
|
151
|
-
expect(queryToResourcePath(link, query, 'read')).toBe(
|
|
151
|
+
expect(queryToResourcePath(link, query, 'read')).toBe(`${link.unversionedApiPath}/tracker`);
|
|
152
152
|
});
|
|
153
153
|
it('should return an unversioned endpoint sub-resources of the new tracker importer (in version 2.37)', () => {
|
|
154
154
|
const query = {
|
|
155
155
|
resource: 'tracker/test'
|
|
156
156
|
};
|
|
157
|
-
expect(queryToResourcePath(link, query, 'read')).toBe(
|
|
157
|
+
expect(queryToResourcePath(link, query, 'read')).toBe(`${link.unversionedApiPath}/tracker/test`);
|
|
158
158
|
});
|
|
159
159
|
it('should return a VERSIONED endpoint for the new tracker importer (in version 2.38)', () => {
|
|
160
160
|
const query = {
|
|
@@ -167,6 +167,6 @@ describe('queryToResourcePath', () => {
|
|
|
167
167
|
patch: 0
|
|
168
168
|
}
|
|
169
169
|
};
|
|
170
|
-
expect(queryToResourcePath(createLink(v38config), query, 'read')).toBe(
|
|
170
|
+
expect(queryToResourcePath(createLink(v38config), query, 'read')).toBe(`${link.versionedApiPath}/tracker`);
|
|
171
171
|
});
|
|
172
172
|
});
|