@forge/storage 1.5.15 → 1.6.0-next.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/README.md +2 -1
- package/out/__test__/global-storage.test.js +169 -40
- package/out/entity-storage/query-api.js +56 -19
- package/out/entity-storage/storage-builder.js +2 -0
- package/out/errors.js +1 -1
- package/out/global-storage.d.ts +6 -1
- package/out/global-storage.d.ts.map +1 -1
- package/out/global-storage.js +49 -14
- package/out/gql-queries.js +86 -82
- package/out/query-api.js +19 -5
- package/package.json +5 -3
package/README.md
CHANGED
|
@@ -7,6 +7,7 @@ import fetch, { RequestInit } from 'node-fetch';
|
|
|
7
7
|
|
|
8
8
|
import { GlobalStorage } from './global-storage';
|
|
9
9
|
import { APIResponse, getStorageInstanceWithQuery } from './index';
|
|
10
|
+
import { getMetrics } from './runtime/fetch-and-storage';
|
|
10
11
|
|
|
11
12
|
const API_BASE = 'https://api.atlassian.com';
|
|
12
13
|
|
|
@@ -37,7 +38,7 @@ async function apiClient(path: string, init: RequestInit): Promise<APIResponse>
|
|
|
37
38
|
return fetch(url, init);
|
|
38
39
|
}
|
|
39
40
|
|
|
40
|
-
const adapter = new GlobalStorage(() => appContextAri, apiClient);
|
|
41
|
+
const adapter = new GlobalStorage(() => appContextAri, apiClient, getMetrics);
|
|
41
42
|
const storage = getStorageInstanceWithQuery(adapter);
|
|
42
43
|
|
|
43
44
|
async function demo() {
|
|
@@ -3,8 +3,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
const errors_1 = require("../errors");
|
|
4
4
|
const global_storage_1 = require("../global-storage");
|
|
5
5
|
const gql_queries_1 = require("../gql-queries");
|
|
6
|
+
const mocks_1 = require("@atlassian/metrics-interface/dist/mocks");
|
|
6
7
|
const contextAri = 'app-ari';
|
|
7
|
-
const getStorage = (apiClientMock) => new global_storage_1.GlobalStorage(() => contextAri, apiClientMock);
|
|
8
|
+
const getStorage = (apiClientMock, metrics) => new global_storage_1.GlobalStorage(() => contextAri, apiClientMock, () => metrics);
|
|
8
9
|
const getApiClientMock = (response, statusCode = 200) => {
|
|
9
10
|
return jest.fn().mockReturnValue({
|
|
10
11
|
ok: statusCode === 200,
|
|
@@ -12,6 +13,36 @@ const getApiClientMock = (response, statusCode = 200) => {
|
|
|
12
13
|
text: jest.fn().mockResolvedValue(JSON.stringify(response))
|
|
13
14
|
});
|
|
14
15
|
};
|
|
16
|
+
const getMetricMock = () => {
|
|
17
|
+
const mockMetrics = new mocks_1.MockMetrics();
|
|
18
|
+
const mockCounter = new mocks_1.MockCounter('');
|
|
19
|
+
const mockTiming = new mocks_1.MockTiming('');
|
|
20
|
+
const mockStopTiming = jest.fn();
|
|
21
|
+
const mockMeasure = {
|
|
22
|
+
stop: mockStopTiming
|
|
23
|
+
};
|
|
24
|
+
mockMetrics.counter.mockReturnValue(mockCounter);
|
|
25
|
+
mockMetrics.timing.mockReturnValue(mockTiming);
|
|
26
|
+
mockTiming.measure.mockReturnValue(mockMeasure);
|
|
27
|
+
return {
|
|
28
|
+
mockMetrics,
|
|
29
|
+
mockCounter,
|
|
30
|
+
mockStopTiming
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
const checkMetricsFired = ({ mockMetrics, mockCounter, mockStopTiming }, { encrypted, ...restTags }, success) => {
|
|
34
|
+
expect(mockMetrics.counter).toHaveBeenCalledWith('forge.runtime.storage.operation', {
|
|
35
|
+
...restTags,
|
|
36
|
+
encrypted: String(encrypted),
|
|
37
|
+
success: String(success)
|
|
38
|
+
});
|
|
39
|
+
expect(mockCounter.incr).toHaveBeenCalled();
|
|
40
|
+
expect(mockMetrics.timing).toHaveBeenCalledWith('forge.runtime.storage.operation.latency', {
|
|
41
|
+
...restTags,
|
|
42
|
+
encrypted: String(encrypted)
|
|
43
|
+
});
|
|
44
|
+
expect(mockStopTiming).toHaveBeenCalledWith({ success: String(success) });
|
|
45
|
+
};
|
|
15
46
|
const getApiClientMockInvalidJson = (response, statusCode = 200) => {
|
|
16
47
|
return jest.fn().mockReturnValue({
|
|
17
48
|
ok: statusCode === 200,
|
|
@@ -52,7 +83,8 @@ describe('GlobalStorage', () => {
|
|
|
52
83
|
}
|
|
53
84
|
}
|
|
54
85
|
});
|
|
55
|
-
const
|
|
86
|
+
const metricMocks = getMetricMock();
|
|
87
|
+
const globalStorage = getStorage(apiClientMock, metricMocks.mockMetrics);
|
|
56
88
|
const returnedValue = await globalStorage.get('testKey');
|
|
57
89
|
verifyApiClientCalledWith(apiClientMock, {
|
|
58
90
|
contextAri,
|
|
@@ -60,6 +92,7 @@ describe('GlobalStorage', () => {
|
|
|
60
92
|
encrypted: false
|
|
61
93
|
});
|
|
62
94
|
expect(returnedValue).toEqual('testValue');
|
|
95
|
+
checkMetricsFired(metricMocks, { store: 'untyped', operation: 'get', encrypted: false }, true);
|
|
63
96
|
});
|
|
64
97
|
it('should call the storage API, passing the provided key and returning undefined if the key doesnt exist', async () => {
|
|
65
98
|
const apiClientMock = getApiClientMock({
|
|
@@ -69,7 +102,8 @@ describe('GlobalStorage', () => {
|
|
|
69
102
|
}
|
|
70
103
|
}
|
|
71
104
|
});
|
|
72
|
-
const
|
|
105
|
+
const metricMocks = getMetricMock();
|
|
106
|
+
const globalStorage = getStorage(apiClientMock, metricMocks.mockMetrics);
|
|
73
107
|
const returnedValue = await globalStorage.get('testKey');
|
|
74
108
|
verifyApiClientCalledWith(apiClientMock, {
|
|
75
109
|
contextAri,
|
|
@@ -77,6 +111,7 @@ describe('GlobalStorage', () => {
|
|
|
77
111
|
encrypted: false
|
|
78
112
|
});
|
|
79
113
|
expect(returnedValue).toEqual(undefined);
|
|
114
|
+
checkMetricsFired(metricMocks, { store: 'untyped', operation: 'get', encrypted: false }, true);
|
|
80
115
|
});
|
|
81
116
|
it('should call the storage API, passing the provided key and returning the stored falsey value 0', async () => {
|
|
82
117
|
const apiClientMock = getApiClientMock({
|
|
@@ -86,7 +121,8 @@ describe('GlobalStorage', () => {
|
|
|
86
121
|
}
|
|
87
122
|
}
|
|
88
123
|
});
|
|
89
|
-
const
|
|
124
|
+
const metricMocks = getMetricMock();
|
|
125
|
+
const globalStorage = getStorage(apiClientMock, metricMocks.mockMetrics);
|
|
90
126
|
const returnedValue = await globalStorage.get('testKey');
|
|
91
127
|
verifyApiClientCalledWith(apiClientMock, {
|
|
92
128
|
contextAri,
|
|
@@ -94,6 +130,7 @@ describe('GlobalStorage', () => {
|
|
|
94
130
|
encrypted: false
|
|
95
131
|
});
|
|
96
132
|
expect(returnedValue).toEqual(0);
|
|
133
|
+
checkMetricsFired(metricMocks, { store: 'untyped', operation: 'get', encrypted: false }, true);
|
|
97
134
|
});
|
|
98
135
|
it('should call the storage API, passing the provided key and returning the stored empty string', async () => {
|
|
99
136
|
const apiClientMock = getApiClientMock({
|
|
@@ -103,7 +140,8 @@ describe('GlobalStorage', () => {
|
|
|
103
140
|
}
|
|
104
141
|
}
|
|
105
142
|
});
|
|
106
|
-
const
|
|
143
|
+
const metricMocks = getMetricMock();
|
|
144
|
+
const globalStorage = getStorage(apiClientMock, metricMocks.mockMetrics);
|
|
107
145
|
const returnedValue = await globalStorage.get('testKey');
|
|
108
146
|
verifyApiClientCalledWith(apiClientMock, {
|
|
109
147
|
contextAri,
|
|
@@ -111,29 +149,36 @@ describe('GlobalStorage', () => {
|
|
|
111
149
|
encrypted: false
|
|
112
150
|
});
|
|
113
151
|
expect(returnedValue).toEqual('');
|
|
152
|
+
checkMetricsFired(metricMocks, { store: 'untyped', operation: 'get', encrypted: false }, true);
|
|
114
153
|
});
|
|
115
154
|
it('should throw an error with the returned status for non-200 status codes', async () => {
|
|
116
155
|
const apiClientMock = getApiClientMock(undefined, 400);
|
|
117
|
-
const
|
|
156
|
+
const metricMocks = getMetricMock();
|
|
157
|
+
const globalStorage = getStorage(apiClientMock, metricMocks.mockMetrics);
|
|
118
158
|
const response = globalStorage.get('testKey');
|
|
119
159
|
expect(apiClientMock).toHaveBeenCalled();
|
|
120
160
|
await expect(response).rejects.toThrow(errors_1.APIError.forStatus(400));
|
|
161
|
+
checkMetricsFired(metricMocks, { store: 'untyped', operation: 'get', encrypted: false }, false);
|
|
121
162
|
});
|
|
122
163
|
it('should throw an error with the returned error message for failed responses', async () => {
|
|
123
164
|
const apiClientMock = getApiClientMock({
|
|
124
165
|
errors: [INVALID_CURSOR_ERROR]
|
|
125
166
|
}, 200);
|
|
126
|
-
const
|
|
167
|
+
const metricMocks = getMetricMock();
|
|
168
|
+
const globalStorage = getStorage(apiClientMock, metricMocks.mockMetrics);
|
|
127
169
|
const response = globalStorage.get('testKey');
|
|
128
170
|
expect(apiClientMock).toHaveBeenCalled();
|
|
129
171
|
await expect(response).rejects.toThrow(errors_1.APIError.forErrorCode('CURSOR_INVALID', 'error message'));
|
|
172
|
+
checkMetricsFired(metricMocks, { store: 'untyped', operation: 'get', encrypted: false }, false);
|
|
130
173
|
});
|
|
131
174
|
it('should throw an error if the response is not a valid JSON', async () => {
|
|
132
175
|
const apiClientMock = getApiClientMockInvalidJson('test', 200);
|
|
133
|
-
const
|
|
176
|
+
const metricMocks = getMetricMock();
|
|
177
|
+
const globalStorage = getStorage(apiClientMock, metricMocks.mockMetrics);
|
|
134
178
|
const response = globalStorage.get('testKey');
|
|
135
179
|
expect(apiClientMock).toHaveBeenCalled();
|
|
136
180
|
await expect(response).rejects.toThrow(errors_1.APIError.forUnexpected('Response text was not a valid JSON: test'));
|
|
181
|
+
checkMetricsFired(metricMocks, { store: 'untyped', operation: 'get', encrypted: false }, false);
|
|
137
182
|
});
|
|
138
183
|
});
|
|
139
184
|
describe('get secret', () => {
|
|
@@ -145,7 +190,8 @@ describe('GlobalStorage', () => {
|
|
|
145
190
|
}
|
|
146
191
|
}
|
|
147
192
|
});
|
|
148
|
-
const
|
|
193
|
+
const metricMocks = getMetricMock();
|
|
194
|
+
const globalStorage = getStorage(apiClientMock, metricMocks.mockMetrics);
|
|
149
195
|
const returnedValue = await globalStorage.getSecret('testKey');
|
|
150
196
|
verifyApiClientCalledWith(apiClientMock, {
|
|
151
197
|
contextAri,
|
|
@@ -153,6 +199,7 @@ describe('GlobalStorage', () => {
|
|
|
153
199
|
encrypted: true
|
|
154
200
|
});
|
|
155
201
|
expect(returnedValue).toEqual('testValue');
|
|
202
|
+
checkMetricsFired(metricMocks, { store: 'untyped', operation: 'get', encrypted: true }, true);
|
|
156
203
|
});
|
|
157
204
|
});
|
|
158
205
|
describe('set', () => {
|
|
@@ -166,7 +213,8 @@ describe('GlobalStorage', () => {
|
|
|
166
213
|
}
|
|
167
214
|
}
|
|
168
215
|
});
|
|
169
|
-
const
|
|
216
|
+
const metricMocks = getMetricMock();
|
|
217
|
+
const globalStorage = getStorage(apiClientMock, metricMocks.mockMetrics);
|
|
170
218
|
await globalStorage.set('testKey', 'testValue');
|
|
171
219
|
verifyApiClientCalledWith(apiClientMock, {
|
|
172
220
|
input: {
|
|
@@ -176,6 +224,7 @@ describe('GlobalStorage', () => {
|
|
|
176
224
|
encrypted: false
|
|
177
225
|
}
|
|
178
226
|
});
|
|
227
|
+
checkMetricsFired(metricMocks, { store: 'untyped', operation: 'set', encrypted: false }, true);
|
|
179
228
|
});
|
|
180
229
|
it('should throw an error if the storage API returns successful = false', async () => {
|
|
181
230
|
const apiClientMock = getApiClientMock({
|
|
@@ -188,17 +237,21 @@ describe('GlobalStorage', () => {
|
|
|
188
237
|
}
|
|
189
238
|
}
|
|
190
239
|
});
|
|
191
|
-
const
|
|
240
|
+
const metricMocks = getMetricMock();
|
|
241
|
+
const globalStorage = getStorage(apiClientMock, metricMocks.mockMetrics);
|
|
192
242
|
const response = globalStorage.set('testKey', 'testValue');
|
|
193
243
|
expect(apiClientMock).toHaveBeenCalled();
|
|
194
244
|
await expect(response).rejects.toThrow(errors_1.APIError.forErrorCode('INVALID_CURSOR', 'error message'));
|
|
245
|
+
checkMetricsFired(metricMocks, { store: 'untyped', operation: 'set', encrypted: false }, false);
|
|
195
246
|
});
|
|
196
247
|
it('should throw an error if the storage API returns a non 200 status code', async () => {
|
|
197
248
|
const apiClientMock = getApiClientMockInvalidJson('', 400);
|
|
198
|
-
const
|
|
249
|
+
const metricMocks = getMetricMock();
|
|
250
|
+
const globalStorage = getStorage(apiClientMock, metricMocks.mockMetrics);
|
|
199
251
|
const response = globalStorage.set('testKey', 'testValue');
|
|
200
252
|
expect(apiClientMock).toHaveBeenCalled();
|
|
201
253
|
await expect(response).rejects.toThrow(errors_1.APIError.forStatus(400));
|
|
254
|
+
checkMetricsFired(metricMocks, { store: 'untyped', operation: 'set', encrypted: false }, false);
|
|
202
255
|
});
|
|
203
256
|
it('should throw a 500 error if success=false but no errors were returned', async () => {
|
|
204
257
|
const apiClientMock = getApiClientMock({
|
|
@@ -210,7 +263,8 @@ describe('GlobalStorage', () => {
|
|
|
210
263
|
}
|
|
211
264
|
}
|
|
212
265
|
});
|
|
213
|
-
const
|
|
266
|
+
const metricMocks = getMetricMock();
|
|
267
|
+
const globalStorage = getStorage(apiClientMock, metricMocks.mockMetrics);
|
|
214
268
|
await expect(globalStorage.set('testKey', 'testValue')).rejects.toThrow(errors_1.APIError.forStatus(500));
|
|
215
269
|
verifyApiClientCalledWith(apiClientMock, {
|
|
216
270
|
input: {
|
|
@@ -220,6 +274,7 @@ describe('GlobalStorage', () => {
|
|
|
220
274
|
encrypted: false
|
|
221
275
|
}
|
|
222
276
|
});
|
|
277
|
+
checkMetricsFired(metricMocks, { store: 'untyped', operation: 'set', encrypted: false }, false);
|
|
223
278
|
});
|
|
224
279
|
});
|
|
225
280
|
describe('set secret', () => {
|
|
@@ -233,7 +288,8 @@ describe('GlobalStorage', () => {
|
|
|
233
288
|
}
|
|
234
289
|
}
|
|
235
290
|
});
|
|
236
|
-
const
|
|
291
|
+
const metricMocks = getMetricMock();
|
|
292
|
+
const globalStorage = getStorage(apiClientMock, metricMocks.mockMetrics);
|
|
237
293
|
await globalStorage.setSecret('testKey', 'testValue');
|
|
238
294
|
verifyApiClientCalledWith(apiClientMock, {
|
|
239
295
|
input: {
|
|
@@ -243,6 +299,7 @@ describe('GlobalStorage', () => {
|
|
|
243
299
|
encrypted: true
|
|
244
300
|
}
|
|
245
301
|
});
|
|
302
|
+
checkMetricsFired(metricMocks, { store: 'untyped', operation: 'set', encrypted: true }, true);
|
|
246
303
|
});
|
|
247
304
|
});
|
|
248
305
|
describe('delete', () => {
|
|
@@ -256,7 +313,8 @@ describe('GlobalStorage', () => {
|
|
|
256
313
|
}
|
|
257
314
|
}
|
|
258
315
|
});
|
|
259
|
-
const
|
|
316
|
+
const metricMocks = getMetricMock();
|
|
317
|
+
const globalStorage = getStorage(apiClientMock, metricMocks.mockMetrics);
|
|
260
318
|
await globalStorage.delete('testKey');
|
|
261
319
|
verifyApiClientCalledWith(apiClientMock, {
|
|
262
320
|
input: {
|
|
@@ -265,6 +323,7 @@ describe('GlobalStorage', () => {
|
|
|
265
323
|
encrypted: false
|
|
266
324
|
}
|
|
267
325
|
});
|
|
326
|
+
checkMetricsFired(metricMocks, { store: 'untyped', operation: 'delete', encrypted: false }, true);
|
|
268
327
|
});
|
|
269
328
|
it('should throw an error if the storage API returns successful = false', async () => {
|
|
270
329
|
const apiClientMock = getApiClientMock({
|
|
@@ -277,17 +336,21 @@ describe('GlobalStorage', () => {
|
|
|
277
336
|
}
|
|
278
337
|
}
|
|
279
338
|
});
|
|
280
|
-
const
|
|
339
|
+
const metricMocks = getMetricMock();
|
|
340
|
+
const globalStorage = getStorage(apiClientMock, metricMocks.mockMetrics);
|
|
281
341
|
const response = globalStorage.delete('testKey');
|
|
282
342
|
expect(apiClientMock).toHaveBeenCalled();
|
|
283
343
|
await expect(response).rejects.toThrow(errors_1.APIError.forErrorCode('CURSOR_INVALID', 'error message'));
|
|
344
|
+
checkMetricsFired(metricMocks, { store: 'untyped', operation: 'delete', encrypted: false }, false);
|
|
284
345
|
});
|
|
285
346
|
it('should throw an error if the storage API returns a non 200 status code and has no body', async () => {
|
|
286
347
|
const apiClientMock = getApiClientMockInvalidJson('', 400);
|
|
287
|
-
const
|
|
348
|
+
const metricMocks = getMetricMock();
|
|
349
|
+
const globalStorage = getStorage(apiClientMock, metricMocks.mockMetrics);
|
|
288
350
|
const response = globalStorage.delete('testKey');
|
|
289
351
|
expect(apiClientMock).toHaveBeenCalled();
|
|
290
352
|
await expect(response).rejects.toThrow(errors_1.APIError.forStatus(400));
|
|
353
|
+
checkMetricsFired(metricMocks, { store: 'untyped', operation: 'delete', encrypted: false }, false);
|
|
291
354
|
});
|
|
292
355
|
});
|
|
293
356
|
describe('delete secret', () => {
|
|
@@ -301,7 +364,8 @@ describe('GlobalStorage', () => {
|
|
|
301
364
|
}
|
|
302
365
|
}
|
|
303
366
|
});
|
|
304
|
-
const
|
|
367
|
+
const metricMocks = getMetricMock();
|
|
368
|
+
const globalStorage = getStorage(apiClientMock, metricMocks.mockMetrics);
|
|
305
369
|
await globalStorage.deleteSecret('testKey');
|
|
306
370
|
verifyApiClientCalledWith(apiClientMock, {
|
|
307
371
|
input: {
|
|
@@ -310,6 +374,7 @@ describe('GlobalStorage', () => {
|
|
|
310
374
|
encrypted: true
|
|
311
375
|
}
|
|
312
376
|
});
|
|
377
|
+
checkMetricsFired(metricMocks, { store: 'untyped', operation: 'delete', encrypted: true }, true);
|
|
313
378
|
});
|
|
314
379
|
});
|
|
315
380
|
describe('getEntity', () => {
|
|
@@ -321,7 +386,8 @@ describe('GlobalStorage', () => {
|
|
|
321
386
|
}
|
|
322
387
|
}
|
|
323
388
|
});
|
|
324
|
-
const
|
|
389
|
+
const metricMocks = getMetricMock();
|
|
390
|
+
const globalStorage = getStorage(apiClientMock, metricMocks.mockMetrics);
|
|
325
391
|
const returnedValue = await globalStorage.getEntity('testEntityName', 'testEntityKey');
|
|
326
392
|
verifyApiClientCalledWith(apiClientMock, {
|
|
327
393
|
contextAri,
|
|
@@ -329,6 +395,7 @@ describe('GlobalStorage', () => {
|
|
|
329
395
|
key: 'testEntityKey'
|
|
330
396
|
});
|
|
331
397
|
expect(returnedValue).toEqual('testValue');
|
|
398
|
+
checkMetricsFired(metricMocks, { store: 'typed', operation: 'get', encrypted: false }, true);
|
|
332
399
|
});
|
|
333
400
|
it('should call the storage API, passing the provided entity key and returning undefined if the key doesnt exist', async () => {
|
|
334
401
|
const apiClientMock = getApiClientMock({
|
|
@@ -338,7 +405,8 @@ describe('GlobalStorage', () => {
|
|
|
338
405
|
}
|
|
339
406
|
}
|
|
340
407
|
});
|
|
341
|
-
const
|
|
408
|
+
const metricMocks = getMetricMock();
|
|
409
|
+
const globalStorage = getStorage(apiClientMock, metricMocks.mockMetrics);
|
|
342
410
|
const returnedValue = await globalStorage.getEntity('testEntityName', 'testEntityKey');
|
|
343
411
|
verifyApiClientCalledWith(apiClientMock, {
|
|
344
412
|
contextAri,
|
|
@@ -346,6 +414,7 @@ describe('GlobalStorage', () => {
|
|
|
346
414
|
key: 'testEntityKey'
|
|
347
415
|
});
|
|
348
416
|
expect(returnedValue).toEqual(undefined);
|
|
417
|
+
checkMetricsFired(metricMocks, { store: 'typed', operation: 'get', encrypted: false }, true);
|
|
349
418
|
});
|
|
350
419
|
it('should call the storage API, passing the provided key and returning the stored falsey value 0', async () => {
|
|
351
420
|
const apiClientMock = getApiClientMock({
|
|
@@ -355,7 +424,8 @@ describe('GlobalStorage', () => {
|
|
|
355
424
|
}
|
|
356
425
|
}
|
|
357
426
|
});
|
|
358
|
-
const
|
|
427
|
+
const metricMocks = getMetricMock();
|
|
428
|
+
const globalStorage = getStorage(apiClientMock, metricMocks.mockMetrics);
|
|
359
429
|
const returnedValue = await globalStorage.getEntity('testEntityName', 'testEntityKey');
|
|
360
430
|
verifyApiClientCalledWith(apiClientMock, {
|
|
361
431
|
contextAri,
|
|
@@ -363,6 +433,7 @@ describe('GlobalStorage', () => {
|
|
|
363
433
|
key: 'testEntityKey'
|
|
364
434
|
});
|
|
365
435
|
expect(returnedValue).toEqual(0);
|
|
436
|
+
checkMetricsFired(metricMocks, { store: 'typed', operation: 'get', encrypted: false }, true);
|
|
366
437
|
});
|
|
367
438
|
it('should call the storage API, passing the provided key and returning the stored empty string', async () => {
|
|
368
439
|
const apiClientMock = getApiClientMock({
|
|
@@ -372,7 +443,8 @@ describe('GlobalStorage', () => {
|
|
|
372
443
|
}
|
|
373
444
|
}
|
|
374
445
|
});
|
|
375
|
-
const
|
|
446
|
+
const metricMocks = getMetricMock();
|
|
447
|
+
const globalStorage = getStorage(apiClientMock, metricMocks.mockMetrics);
|
|
376
448
|
const returnedValue = await globalStorage.getEntity('testEntityName', 'testEntityKey');
|
|
377
449
|
verifyApiClientCalledWith(apiClientMock, {
|
|
378
450
|
contextAri,
|
|
@@ -380,29 +452,36 @@ describe('GlobalStorage', () => {
|
|
|
380
452
|
key: 'testEntityKey'
|
|
381
453
|
});
|
|
382
454
|
expect(returnedValue).toEqual('');
|
|
455
|
+
checkMetricsFired(metricMocks, { store: 'typed', operation: 'get', encrypted: false }, true);
|
|
383
456
|
});
|
|
384
457
|
it('should throw an error with the returned status for non-200 status codes', async () => {
|
|
385
458
|
const apiClientMock = getApiClientMock(undefined, 400);
|
|
386
|
-
const
|
|
459
|
+
const metricMocks = getMetricMock();
|
|
460
|
+
const globalStorage = getStorage(apiClientMock, metricMocks.mockMetrics);
|
|
387
461
|
const response = globalStorage.getEntity('testEntityName', 'testEntityKey');
|
|
388
462
|
expect(apiClientMock).toHaveBeenCalled();
|
|
389
463
|
await expect(response).rejects.toThrow(errors_1.APIError.forStatus(400));
|
|
464
|
+
checkMetricsFired(metricMocks, { store: 'typed', operation: 'get', encrypted: false }, false);
|
|
390
465
|
});
|
|
391
466
|
it('should throw an error with the returned error message for failed responses', async () => {
|
|
392
467
|
const apiClientMock = getApiClientMock({
|
|
393
468
|
errors: [INVALID_CURSOR_ERROR]
|
|
394
469
|
}, 200);
|
|
395
|
-
const
|
|
470
|
+
const metricMocks = getMetricMock();
|
|
471
|
+
const globalStorage = getStorage(apiClientMock, metricMocks.mockMetrics);
|
|
396
472
|
const response = globalStorage.getEntity('testEntityName', 'testEntityKey');
|
|
397
473
|
expect(apiClientMock).toHaveBeenCalled();
|
|
398
474
|
await expect(response).rejects.toThrow(errors_1.APIError.forErrorCode('CURSOR_INVALID', 'error message'));
|
|
475
|
+
checkMetricsFired(metricMocks, { store: 'typed', operation: 'get', encrypted: false }, false);
|
|
399
476
|
});
|
|
400
477
|
it('should throw an error if the response is not a valid JSON', async () => {
|
|
401
478
|
const apiClientMock = getApiClientMockInvalidJson('test', 200);
|
|
402
|
-
const
|
|
479
|
+
const metricMocks = getMetricMock();
|
|
480
|
+
const globalStorage = getStorage(apiClientMock, metricMocks.mockMetrics);
|
|
403
481
|
const response = globalStorage.getEntity('testEntityName', 'testEntityKey');
|
|
404
482
|
expect(apiClientMock).toHaveBeenCalled();
|
|
405
483
|
await expect(response).rejects.toThrow(errors_1.APIError.forUnexpected('Response text was not a valid JSON: test'));
|
|
484
|
+
checkMetricsFired(metricMocks, { store: 'typed', operation: 'get', encrypted: false }, false);
|
|
406
485
|
});
|
|
407
486
|
});
|
|
408
487
|
describe('setEntity', () => {
|
|
@@ -416,7 +495,8 @@ describe('GlobalStorage', () => {
|
|
|
416
495
|
}
|
|
417
496
|
}
|
|
418
497
|
});
|
|
419
|
-
const
|
|
498
|
+
const metricMocks = getMetricMock();
|
|
499
|
+
const globalStorage = getStorage(apiClientMock, metricMocks.mockMetrics);
|
|
420
500
|
await globalStorage.setEntity('testEntityName', 'testEntityKey', 'testValue');
|
|
421
501
|
verifyApiClientCalledWith(apiClientMock, {
|
|
422
502
|
input: {
|
|
@@ -426,6 +506,7 @@ describe('GlobalStorage', () => {
|
|
|
426
506
|
value: 'testValue'
|
|
427
507
|
}
|
|
428
508
|
});
|
|
509
|
+
checkMetricsFired(metricMocks, { store: 'typed', operation: 'set', encrypted: false }, true);
|
|
429
510
|
});
|
|
430
511
|
it('should throw an error if the storage API returns successful = false', async () => {
|
|
431
512
|
const apiClientMock = getApiClientMock({
|
|
@@ -438,17 +519,21 @@ describe('GlobalStorage', () => {
|
|
|
438
519
|
}
|
|
439
520
|
}
|
|
440
521
|
});
|
|
441
|
-
const
|
|
522
|
+
const metricMocks = getMetricMock();
|
|
523
|
+
const globalStorage = getStorage(apiClientMock, metricMocks.mockMetrics);
|
|
442
524
|
const response = globalStorage.setEntity('testEntityName', 'testEntityKey', 'testValue');
|
|
443
525
|
expect(apiClientMock).toHaveBeenCalled();
|
|
444
526
|
await expect(response).rejects.toThrow(errors_1.APIError.forErrorCode('INVALID_CURSOR', 'error message'));
|
|
527
|
+
checkMetricsFired(metricMocks, { store: 'typed', operation: 'set', encrypted: false }, false);
|
|
445
528
|
});
|
|
446
529
|
it('should throw an error if the storage API returns a non 200 status code', async () => {
|
|
447
530
|
const apiClientMock = getApiClientMockInvalidJson('', 400);
|
|
448
|
-
const
|
|
531
|
+
const metricMocks = getMetricMock();
|
|
532
|
+
const globalStorage = getStorage(apiClientMock, metricMocks.mockMetrics);
|
|
449
533
|
const response = globalStorage.setEntity('testEntityName', 'testEntityKey', 'testValue');
|
|
450
534
|
expect(apiClientMock).toHaveBeenCalled();
|
|
451
535
|
await expect(response).rejects.toThrow(errors_1.APIError.forStatus(400));
|
|
536
|
+
checkMetricsFired(metricMocks, { store: 'typed', operation: 'set', encrypted: false }, false);
|
|
452
537
|
});
|
|
453
538
|
it('should throw a 500 error if success=false but no errors were returned', async () => {
|
|
454
539
|
const apiClientMock = getApiClientMock({
|
|
@@ -460,7 +545,8 @@ describe('GlobalStorage', () => {
|
|
|
460
545
|
}
|
|
461
546
|
}
|
|
462
547
|
});
|
|
463
|
-
const
|
|
548
|
+
const metricMocks = getMetricMock();
|
|
549
|
+
const globalStorage = getStorage(apiClientMock, metricMocks.mockMetrics);
|
|
464
550
|
await expect(globalStorage.setEntity('testEntityName', 'testEntityKey', 'testValue')).rejects.toThrow(errors_1.APIError.forStatus(500));
|
|
465
551
|
verifyApiClientCalledWith(apiClientMock, {
|
|
466
552
|
input: {
|
|
@@ -470,6 +556,7 @@ describe('GlobalStorage', () => {
|
|
|
470
556
|
value: 'testValue'
|
|
471
557
|
}
|
|
472
558
|
});
|
|
559
|
+
checkMetricsFired(metricMocks, { store: 'typed', operation: 'set', encrypted: false }, false);
|
|
473
560
|
});
|
|
474
561
|
});
|
|
475
562
|
describe('deleteEntity', () => {
|
|
@@ -483,7 +570,8 @@ describe('GlobalStorage', () => {
|
|
|
483
570
|
}
|
|
484
571
|
}
|
|
485
572
|
});
|
|
486
|
-
const
|
|
573
|
+
const metricMocks = getMetricMock();
|
|
574
|
+
const globalStorage = getStorage(apiClientMock, metricMocks.mockMetrics);
|
|
487
575
|
await globalStorage.deleteEntity('testEntityName', 'testEntityKey');
|
|
488
576
|
verifyApiClientCalledWith(apiClientMock, {
|
|
489
577
|
input: {
|
|
@@ -492,6 +580,7 @@ describe('GlobalStorage', () => {
|
|
|
492
580
|
key: 'testEntityKey'
|
|
493
581
|
}
|
|
494
582
|
});
|
|
583
|
+
checkMetricsFired(metricMocks, { store: 'typed', operation: 'delete', encrypted: false }, true);
|
|
495
584
|
});
|
|
496
585
|
it('should throw an error if the storage API returns successful = false', async () => {
|
|
497
586
|
const apiClientMock = getApiClientMock({
|
|
@@ -504,17 +593,21 @@ describe('GlobalStorage', () => {
|
|
|
504
593
|
}
|
|
505
594
|
}
|
|
506
595
|
});
|
|
507
|
-
const
|
|
596
|
+
const metricMocks = getMetricMock();
|
|
597
|
+
const globalStorage = getStorage(apiClientMock, metricMocks.mockMetrics);
|
|
508
598
|
const response = globalStorage.deleteEntity('testEntityKey', 'testEntityKey');
|
|
509
599
|
expect(apiClientMock).toHaveBeenCalled();
|
|
510
600
|
await expect(response).rejects.toThrow(errors_1.APIError.forErrorCode('CURSOR_INVALID', 'error message'));
|
|
601
|
+
checkMetricsFired(metricMocks, { store: 'typed', operation: 'delete', encrypted: false }, false);
|
|
511
602
|
});
|
|
512
603
|
it('should throw an error if the storage API returns a non 200 status code and has no body', async () => {
|
|
513
604
|
const apiClientMock = getApiClientMockInvalidJson('', 400);
|
|
514
|
-
const
|
|
605
|
+
const metricMocks = getMetricMock();
|
|
606
|
+
const globalStorage = getStorage(apiClientMock, metricMocks.mockMetrics);
|
|
515
607
|
const response = globalStorage.deleteEntity('testEntityKey', 'testEntityKey');
|
|
516
608
|
expect(apiClientMock).toHaveBeenCalled();
|
|
517
609
|
await expect(response).rejects.toThrow(errors_1.APIError.forStatus(400));
|
|
610
|
+
checkMetricsFired(metricMocks, { store: 'typed', operation: 'delete', encrypted: false }, false);
|
|
518
611
|
});
|
|
519
612
|
});
|
|
520
613
|
describe('list', () => {
|
|
@@ -529,7 +622,8 @@ describe('GlobalStorage', () => {
|
|
|
529
622
|
}
|
|
530
623
|
}
|
|
531
624
|
});
|
|
532
|
-
const
|
|
625
|
+
const metricMocks = getMetricMock();
|
|
626
|
+
const globalStorage = getStorage(apiClientMock, metricMocks.mockMetrics);
|
|
533
627
|
const where = [
|
|
534
628
|
{
|
|
535
629
|
field: 'key',
|
|
@@ -553,6 +647,7 @@ describe('GlobalStorage', () => {
|
|
|
553
647
|
],
|
|
554
648
|
nextCursor: 'cursor2'
|
|
555
649
|
}));
|
|
650
|
+
checkMetricsFired(metricMocks, { store: 'untyped', operation: 'query', encrypted: false }, true);
|
|
556
651
|
});
|
|
557
652
|
it('should query the appStoredEntitiesForCleanup endpoint given process.env.IS_CLEANUP_FUNCTION is set to true', async () => {
|
|
558
653
|
process.env.IS_CLEANUP_FUNCTION = 'true';
|
|
@@ -566,7 +661,8 @@ describe('GlobalStorage', () => {
|
|
|
566
661
|
}
|
|
567
662
|
}
|
|
568
663
|
});
|
|
569
|
-
const
|
|
664
|
+
const metricMocks = getMetricMock();
|
|
665
|
+
const globalStorage = getStorage(apiClientMock, metricMocks.mockMetrics);
|
|
570
666
|
const where = [
|
|
571
667
|
{
|
|
572
668
|
field: 'key',
|
|
@@ -590,6 +686,7 @@ describe('GlobalStorage', () => {
|
|
|
590
686
|
],
|
|
591
687
|
nextCursor: 'cursor2'
|
|
592
688
|
}));
|
|
689
|
+
checkMetricsFired(metricMocks, { store: 'untyped', operation: 'query', encrypted: false }, true);
|
|
593
690
|
process.env.IS_CLEANUP_FUNCTION = '';
|
|
594
691
|
});
|
|
595
692
|
it('should use default values', async () => {
|
|
@@ -600,7 +697,8 @@ describe('GlobalStorage', () => {
|
|
|
600
697
|
}
|
|
601
698
|
}
|
|
602
699
|
});
|
|
603
|
-
const
|
|
700
|
+
const metricMocks = getMetricMock();
|
|
701
|
+
const globalStorage = getStorage(apiClientMock, metricMocks.mockMetrics);
|
|
604
702
|
await globalStorage.list({});
|
|
605
703
|
verifyApiClientCalledWith(apiClientMock, {
|
|
606
704
|
contextAri,
|
|
@@ -608,6 +706,7 @@ describe('GlobalStorage', () => {
|
|
|
608
706
|
cursor: null,
|
|
609
707
|
limit: null
|
|
610
708
|
}, gql_queries_1.UntypedQueries.listQuery(contextAri, {}).query);
|
|
709
|
+
checkMetricsFired(metricMocks, { store: 'untyped', operation: 'query', encrypted: false }, true);
|
|
611
710
|
});
|
|
612
711
|
it('should handle an empty result set', async () => {
|
|
613
712
|
const apiClientMock = getApiClientMock({
|
|
@@ -617,7 +716,8 @@ describe('GlobalStorage', () => {
|
|
|
617
716
|
}
|
|
618
717
|
}
|
|
619
718
|
});
|
|
620
|
-
const
|
|
719
|
+
const metricMocks = getMetricMock();
|
|
720
|
+
const globalStorage = getStorage(apiClientMock, metricMocks.mockMetrics);
|
|
621
721
|
const where = [
|
|
622
722
|
{
|
|
623
723
|
field: 'key',
|
|
@@ -630,22 +730,27 @@ describe('GlobalStorage', () => {
|
|
|
630
730
|
results: [],
|
|
631
731
|
nextCursor: undefined
|
|
632
732
|
}));
|
|
733
|
+
checkMetricsFired(metricMocks, { store: 'untyped', operation: 'query', encrypted: false }, true);
|
|
633
734
|
});
|
|
634
735
|
it('should throw an error if the storage API returns an error', async () => {
|
|
635
736
|
const apiClientMock = getApiClientMock({
|
|
636
737
|
errors: [INVALID_CURSOR_ERROR]
|
|
637
738
|
});
|
|
638
|
-
const
|
|
739
|
+
const metricMocks = getMetricMock();
|
|
740
|
+
const globalStorage = getStorage(apiClientMock, metricMocks.mockMetrics);
|
|
639
741
|
const response = globalStorage.list({});
|
|
640
742
|
expect(apiClientMock).toHaveBeenCalled();
|
|
641
743
|
await expect(response).rejects.toThrow(errors_1.APIError.forErrorCode('CURSOR_INVALID', 'error message'));
|
|
744
|
+
checkMetricsFired(metricMocks, { store: 'untyped', operation: 'query', encrypted: false }, false);
|
|
642
745
|
});
|
|
643
746
|
it('should throw an error if the storage API returns a non 200 status code and has no body', async () => {
|
|
644
747
|
const apiClientMock = getApiClientMockInvalidJson('', 400);
|
|
645
|
-
const
|
|
748
|
+
const metricMocks = getMetricMock();
|
|
749
|
+
const globalStorage = getStorage(apiClientMock, metricMocks.mockMetrics);
|
|
646
750
|
const response = globalStorage.list({});
|
|
647
751
|
expect(apiClientMock).toHaveBeenCalled();
|
|
648
752
|
await expect(response).rejects.toThrow(errors_1.APIError.forStatus(400));
|
|
753
|
+
checkMetricsFired(metricMocks, { store: 'untyped', operation: 'query', encrypted: false }, false);
|
|
649
754
|
});
|
|
650
755
|
});
|
|
651
756
|
describe('listCustomEntities', () => {
|
|
@@ -657,7 +762,8 @@ describe('GlobalStorage', () => {
|
|
|
657
762
|
}
|
|
658
763
|
}
|
|
659
764
|
});
|
|
660
|
-
const
|
|
765
|
+
const metricMocks = getMetricMock();
|
|
766
|
+
const globalStorage = getStorage(apiClientMock, metricMocks.mockMetrics);
|
|
661
767
|
const response = await globalStorage.listCustomEntities({});
|
|
662
768
|
expect(response).toMatchObject({
|
|
663
769
|
results: [],
|
|
@@ -666,6 +772,7 @@ describe('GlobalStorage', () => {
|
|
|
666
772
|
verifyApiClientCalledWith(apiClientMock, {
|
|
667
773
|
contextAri
|
|
668
774
|
}, gql_queries_1.CustomEntityQueries.listQuery(contextAri, {}).query);
|
|
775
|
+
checkMetricsFired(metricMocks, { store: 'typed', operation: 'query', encrypted: false }, true);
|
|
669
776
|
});
|
|
670
777
|
it('should return cursor when results are not present', async () => {
|
|
671
778
|
const apiClientMock = getApiClientMock({
|
|
@@ -676,7 +783,8 @@ describe('GlobalStorage', () => {
|
|
|
676
783
|
}
|
|
677
784
|
}
|
|
678
785
|
});
|
|
679
|
-
const
|
|
786
|
+
const metricMocks = getMetricMock();
|
|
787
|
+
const globalStorage = getStorage(apiClientMock, metricMocks.mockMetrics);
|
|
680
788
|
const response = await globalStorage.listCustomEntities({});
|
|
681
789
|
expect(response).toMatchObject({
|
|
682
790
|
results: [],
|
|
@@ -685,6 +793,27 @@ describe('GlobalStorage', () => {
|
|
|
685
793
|
verifyApiClientCalledWith(apiClientMock, {
|
|
686
794
|
contextAri
|
|
687
795
|
}, gql_queries_1.CustomEntityQueries.listQuery(contextAri, {}).query);
|
|
796
|
+
checkMetricsFired(metricMocks, { store: 'typed', operation: 'query', encrypted: false }, true);
|
|
797
|
+
});
|
|
798
|
+
it('should throw an error if the storage API returns an error', async () => {
|
|
799
|
+
const apiClientMock = getApiClientMock({
|
|
800
|
+
errors: [INVALID_CURSOR_ERROR]
|
|
801
|
+
});
|
|
802
|
+
const metricMocks = getMetricMock();
|
|
803
|
+
const globalStorage = getStorage(apiClientMock, metricMocks.mockMetrics);
|
|
804
|
+
const response = globalStorage.listCustomEntities({});
|
|
805
|
+
expect(apiClientMock).toHaveBeenCalled();
|
|
806
|
+
await expect(response).rejects.toThrow(errors_1.APIError.forErrorCode('CURSOR_INVALID', 'error message'));
|
|
807
|
+
checkMetricsFired(metricMocks, { store: 'typed', operation: 'query', encrypted: false }, false);
|
|
808
|
+
});
|
|
809
|
+
it('should throw an error if the storage API returns a non 200 status code and has no body', async () => {
|
|
810
|
+
const apiClientMock = getApiClientMockInvalidJson('', 400);
|
|
811
|
+
const metricMocks = getMetricMock();
|
|
812
|
+
const globalStorage = getStorage(apiClientMock, metricMocks.mockMetrics);
|
|
813
|
+
const response = globalStorage.listCustomEntities({});
|
|
814
|
+
expect(apiClientMock).toHaveBeenCalled();
|
|
815
|
+
await expect(response).rejects.toThrow(errors_1.APIError.forStatus(400));
|
|
816
|
+
checkMetricsFired(metricMocks, { store: 'typed', operation: 'query', encrypted: false }, false);
|
|
688
817
|
});
|
|
689
818
|
});
|
|
690
819
|
});
|
|
@@ -2,17 +2,26 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.CustomEntityBuilder = exports.CustomEntityIndexBuilder = void 0;
|
|
4
4
|
class CustomEntityQueryBuilder {
|
|
5
|
+
globalStorage;
|
|
6
|
+
queryOptions;
|
|
5
7
|
constructor(globalStorage, queryOptions = {}) {
|
|
6
8
|
this.globalStorage = globalStorage;
|
|
7
9
|
this.queryOptions = queryOptions;
|
|
8
|
-
this.queryOptions =
|
|
10
|
+
this.queryOptions = {
|
|
11
|
+
...queryOptions
|
|
12
|
+
};
|
|
9
13
|
}
|
|
10
14
|
clone(overrides) {
|
|
11
|
-
return new (Object.getPrototypeOf(this).constructor)(this.globalStorage,
|
|
15
|
+
return new (Object.getPrototypeOf(this).constructor)(this.globalStorage, {
|
|
16
|
+
...this.queryOptions,
|
|
17
|
+
...overrides
|
|
18
|
+
});
|
|
12
19
|
}
|
|
13
20
|
where(condition) {
|
|
14
21
|
return this.clone({
|
|
15
|
-
range:
|
|
22
|
+
range: {
|
|
23
|
+
...condition
|
|
24
|
+
}
|
|
16
25
|
});
|
|
17
26
|
}
|
|
18
27
|
sort(sort) {
|
|
@@ -32,7 +41,7 @@ class CustomEntityQueryBuilder {
|
|
|
32
41
|
}
|
|
33
42
|
async getOne() {
|
|
34
43
|
const { results } = await this.limit(1).getMany();
|
|
35
|
-
return results
|
|
44
|
+
return results?.[0];
|
|
36
45
|
}
|
|
37
46
|
async getMany() {
|
|
38
47
|
if (!this.queryOptions.entityName) {
|
|
@@ -41,7 +50,7 @@ class CustomEntityQueryBuilder {
|
|
|
41
50
|
if (!this.queryOptions.indexName) {
|
|
42
51
|
throw new Error('indexName is mandatory');
|
|
43
52
|
}
|
|
44
|
-
const queryOptions =
|
|
53
|
+
const queryOptions = { ...this.queryOptions };
|
|
45
54
|
if (!queryOptions.filterOperator && queryOptions.filters) {
|
|
46
55
|
queryOptions.filterOperator = 'and';
|
|
47
56
|
}
|
|
@@ -49,41 +58,55 @@ class CustomEntityQueryBuilder {
|
|
|
49
58
|
}
|
|
50
59
|
}
|
|
51
60
|
class CustomEntityAndFilterQueryBuilder extends CustomEntityQueryBuilder {
|
|
61
|
+
globalStorage;
|
|
62
|
+
queryOptions;
|
|
52
63
|
constructor(globalStorage, queryOptions = {}) {
|
|
53
64
|
super(globalStorage, queryOptions);
|
|
54
65
|
this.globalStorage = globalStorage;
|
|
55
66
|
this.queryOptions = queryOptions;
|
|
56
|
-
this.queryOptions =
|
|
67
|
+
this.queryOptions = {
|
|
68
|
+
...queryOptions
|
|
69
|
+
};
|
|
57
70
|
}
|
|
58
71
|
andFilter(field, condition) {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
72
|
+
const newQueryOptions = {
|
|
73
|
+
...this.queryOptions
|
|
74
|
+
};
|
|
75
|
+
newQueryOptions.filters = [...(this.queryOptions.filters ?? []), { property: field, ...condition }];
|
|
62
76
|
newQueryOptions.filterOperator = 'and';
|
|
63
77
|
return new CustomEntityAndFilterQueryBuilder(this.globalStorage, newQueryOptions);
|
|
64
78
|
}
|
|
65
79
|
}
|
|
66
80
|
class CustomEntityOrFilterQueryBuilder extends CustomEntityQueryBuilder {
|
|
81
|
+
globalStorage;
|
|
82
|
+
queryOptions;
|
|
67
83
|
constructor(globalStorage, queryOptions = {}) {
|
|
68
84
|
super(globalStorage, queryOptions);
|
|
69
85
|
this.globalStorage = globalStorage;
|
|
70
86
|
this.queryOptions = queryOptions;
|
|
71
|
-
this.queryOptions =
|
|
87
|
+
this.queryOptions = {
|
|
88
|
+
...queryOptions
|
|
89
|
+
};
|
|
72
90
|
}
|
|
73
91
|
orFilter(field, condition) {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
92
|
+
const newQueryOptions = {
|
|
93
|
+
...this.queryOptions
|
|
94
|
+
};
|
|
95
|
+
newQueryOptions.filters = [...(this.queryOptions.filters ?? []), { property: field, ...condition }];
|
|
77
96
|
newQueryOptions.filterOperator = 'or';
|
|
78
97
|
return new CustomEntityOrFilterQueryBuilder(this.globalStorage, newQueryOptions);
|
|
79
98
|
}
|
|
80
99
|
}
|
|
81
100
|
class CustomEntityFilterQueryBuilder extends CustomEntityQueryBuilder {
|
|
101
|
+
globalStorage;
|
|
102
|
+
queryOptions;
|
|
82
103
|
constructor(globalStorage, queryOptions = {}) {
|
|
83
104
|
super(globalStorage, queryOptions);
|
|
84
105
|
this.globalStorage = globalStorage;
|
|
85
106
|
this.queryOptions = queryOptions;
|
|
86
|
-
this.queryOptions =
|
|
107
|
+
this.queryOptions = {
|
|
108
|
+
...queryOptions
|
|
109
|
+
};
|
|
87
110
|
}
|
|
88
111
|
andFilter(field, condition) {
|
|
89
112
|
return new CustomEntityAndFilterQueryBuilder(this.globalStorage, this.queryOptions).andFilter(field, condition);
|
|
@@ -93,25 +116,39 @@ class CustomEntityFilterQueryBuilder extends CustomEntityQueryBuilder {
|
|
|
93
116
|
}
|
|
94
117
|
}
|
|
95
118
|
class CustomEntityIndexBuilder {
|
|
119
|
+
globalStorage;
|
|
120
|
+
queryOptions;
|
|
96
121
|
constructor(globalStorage, queryOptions = {}) {
|
|
97
122
|
this.globalStorage = globalStorage;
|
|
98
123
|
this.queryOptions = queryOptions;
|
|
99
|
-
this.queryOptions =
|
|
124
|
+
this.queryOptions = {
|
|
125
|
+
...queryOptions
|
|
126
|
+
};
|
|
100
127
|
}
|
|
101
128
|
index(name, indexOptions) {
|
|
102
|
-
const indexProperties = indexOptions ?
|
|
103
|
-
return new CustomEntityFilterQueryBuilder(this.globalStorage,
|
|
129
|
+
const indexProperties = indexOptions ? { indexName: name, ...indexOptions } : { indexName: name };
|
|
130
|
+
return new CustomEntityFilterQueryBuilder(this.globalStorage, {
|
|
131
|
+
...this.queryOptions,
|
|
132
|
+
...indexProperties
|
|
133
|
+
});
|
|
104
134
|
}
|
|
105
135
|
}
|
|
106
136
|
exports.CustomEntityIndexBuilder = CustomEntityIndexBuilder;
|
|
107
137
|
class CustomEntityBuilder {
|
|
138
|
+
globalStorage;
|
|
139
|
+
queryOptions;
|
|
108
140
|
constructor(globalStorage, queryOptions = {}) {
|
|
109
141
|
this.globalStorage = globalStorage;
|
|
110
142
|
this.queryOptions = queryOptions;
|
|
111
|
-
this.queryOptions =
|
|
143
|
+
this.queryOptions = {
|
|
144
|
+
...queryOptions
|
|
145
|
+
};
|
|
112
146
|
}
|
|
113
147
|
entity(name) {
|
|
114
|
-
return new CustomEntityIndexBuilder(this.globalStorage,
|
|
148
|
+
return new CustomEntityIndexBuilder(this.globalStorage, {
|
|
149
|
+
...this.queryOptions,
|
|
150
|
+
entityName: name
|
|
151
|
+
});
|
|
115
152
|
}
|
|
116
153
|
}
|
|
117
154
|
exports.CustomEntityBuilder = CustomEntityBuilder;
|
|
@@ -3,6 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.EntityStorageBuilder = void 0;
|
|
4
4
|
const query_api_1 = require("./query-api");
|
|
5
5
|
class EntityStorageBuilder {
|
|
6
|
+
entityName;
|
|
7
|
+
globalStorage;
|
|
6
8
|
constructor(entityName, globalStorage) {
|
|
7
9
|
this.entityName = entityName;
|
|
8
10
|
this.globalStorage = globalStorage;
|
package/out/errors.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.APIError = exports.getErrorMessage = exports.getErrorMessageFromCode = void 0;
|
|
4
4
|
const getErrorMessageFromCode = (code, message) => {
|
|
5
|
-
return message
|
|
5
|
+
return message ?? code;
|
|
6
6
|
};
|
|
7
7
|
exports.getErrorMessageFromCode = getErrorMessageFromCode;
|
|
8
8
|
const getErrorMessage = (statusCode) => {
|
package/out/global-storage.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { FetchMethod } from './index';
|
|
2
2
|
import { CustomEntityListOptions, ListOptions } from './query-interfaces';
|
|
3
3
|
import { SharedStorageAdapter } from './storage-adapter';
|
|
4
|
+
import type { Metrics } from '@forge/util/packages/metrics-interface';
|
|
4
5
|
interface ListResults {
|
|
5
6
|
results: {
|
|
6
7
|
key: string;
|
|
@@ -8,11 +9,14 @@ interface ListResults {
|
|
|
8
9
|
}[];
|
|
9
10
|
nextCursor?: string;
|
|
10
11
|
}
|
|
12
|
+
export declare type StoreType = 'typed' | 'untyped';
|
|
13
|
+
export declare type OperationType = 'get' | 'set' | 'query' | 'delete';
|
|
11
14
|
export declare class GlobalStorage implements SharedStorageAdapter {
|
|
12
15
|
private getAppContextAri;
|
|
13
16
|
private apiClient;
|
|
17
|
+
private readonly getMetrics;
|
|
14
18
|
private readonly endpoint;
|
|
15
|
-
constructor(getAppContextAri: (() => string) | string, apiClient: FetchMethod);
|
|
19
|
+
constructor(getAppContextAri: (() => string) | string, apiClient: FetchMethod, getMetrics: () => Metrics);
|
|
16
20
|
private doGetAppContextAri;
|
|
17
21
|
get(key: string): Promise<any>;
|
|
18
22
|
getSecret(key: string): Promise<any>;
|
|
@@ -30,6 +34,7 @@ export declare class GlobalStorage implements SharedStorageAdapter {
|
|
|
30
34
|
private buildRequest;
|
|
31
35
|
private query;
|
|
32
36
|
private mutation;
|
|
37
|
+
private wrapInMetric;
|
|
33
38
|
}
|
|
34
39
|
export {};
|
|
35
40
|
//# sourceMappingURL=global-storage.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"global-storage.d.ts","sourceRoot":"","sources":["../src/global-storage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,WAAW,EAAE,MAAM,SAAS,CAAC;AAInD,OAAO,EAAE,uBAAuB,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAC1E,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"global-storage.d.ts","sourceRoot":"","sources":["../src/global-storage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,WAAW,EAAE,MAAM,SAAS,CAAC;AAInD,OAAO,EAAE,uBAAuB,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAC1E,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,wCAAwC,CAAC;AAEtE,UAAU,WAAW;IACnB,OAAO,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,GAAG,CAAA;KAAE,EAAE,CAAC;IACvC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAcD,oBAAY,SAAS,GAAG,OAAO,GAAG,SAAS,CAAC;AAC5C,oBAAY,aAAa,GAAG,KAAK,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,CAAC;AA+B/D,qBAAa,aAAc,YAAW,oBAAoB;IAGtD,OAAO,CAAC,gBAAgB;IACxB,OAAO,CAAC,SAAS;IACjB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAJ7B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA6B;gBAE5C,gBAAgB,EAAE,CAAC,MAAM,MAAM,CAAC,GAAG,MAAM,EACzC,SAAS,EAAE,WAAW,EACb,UAAU,EAAE,MAAM,OAAO;IAG5C,OAAO,CAAC,kBAAkB;IAIpB,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC;IAI9B,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC;IAIpC,IAAI,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;IAqBhD,kBAAkB,CAAC,OAAO,EAAE,uBAAuB,GAAG,OAAO,CAAC,WAAW,CAAC;IAc1E,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC;IAU3C,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC;IAUjD,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAOlC,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAOxC,SAAS,CAAC,CAAC,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC;IAI/D,SAAS,CAAC,CAAC,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAO5E,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;YAU1D,WAAW;YAUX,iBAAiB;IAU/B,OAAO,CAAC,YAAY;YAUN,KAAK;YAML,QAAQ;YAsBR,YAAY;CAoC3B"}
|
package/out/global-storage.js
CHANGED
|
@@ -25,10 +25,14 @@ async function getResponseBody(response) {
|
|
|
25
25
|
return responseBody.data;
|
|
26
26
|
}
|
|
27
27
|
class GlobalStorage {
|
|
28
|
-
|
|
28
|
+
getAppContextAri;
|
|
29
|
+
apiClient;
|
|
30
|
+
getMetrics;
|
|
31
|
+
endpoint = '/forge/entities/graphql';
|
|
32
|
+
constructor(getAppContextAri, apiClient, getMetrics) {
|
|
29
33
|
this.getAppContextAri = getAppContextAri;
|
|
30
34
|
this.apiClient = apiClient;
|
|
31
|
-
this.
|
|
35
|
+
this.getMetrics = getMetrics;
|
|
32
36
|
}
|
|
33
37
|
doGetAppContextAri() {
|
|
34
38
|
return typeof this.getAppContextAri === 'function' ? this.getAppContextAri() : this.getAppContextAri;
|
|
@@ -43,7 +47,7 @@ class GlobalStorage {
|
|
|
43
47
|
const requestBody = process.env.IS_CLEANUP_FUNCTION === 'true'
|
|
44
48
|
? gql_queries_1.UntypedQueries.listQueryForCleanup(this.doGetAppContextAri(), options)
|
|
45
49
|
: gql_queries_1.UntypedQueries.listQuery(this.doGetAppContextAri(), options);
|
|
46
|
-
const response = await this.query(requestBody);
|
|
50
|
+
const response = await this.wrapInMetric('untyped', 'query', false, async () => await this.query(requestBody));
|
|
47
51
|
const edges = process.env.IS_CLEANUP_FUNCTION === 'true'
|
|
48
52
|
? response.appStoredEntitiesForCleanup.edges
|
|
49
53
|
: response.appStoredEntities.edges;
|
|
@@ -56,7 +60,7 @@ class GlobalStorage {
|
|
|
56
60
|
}
|
|
57
61
|
async listCustomEntities(options) {
|
|
58
62
|
const requestBody = gql_queries_1.CustomEntityQueries.listQuery(this.doGetAppContextAri(), options);
|
|
59
|
-
const response = await this.query(requestBody);
|
|
63
|
+
const response = await this.wrapInMetric('typed', 'query', false, async () => await this.query(requestBody));
|
|
60
64
|
const edges = response.appStoredCustomEntities.edges;
|
|
61
65
|
const results = edges.map(({ node }) => node);
|
|
62
66
|
return {
|
|
@@ -66,40 +70,40 @@ class GlobalStorage {
|
|
|
66
70
|
}
|
|
67
71
|
async set(key, value) {
|
|
68
72
|
const requestBody = gql_queries_1.UntypedQueries.set(this.doGetAppContextAri(), key, value, false);
|
|
69
|
-
await this.mutation(requestBody, 'appStorage', 'setAppStoredEntity');
|
|
73
|
+
await this.wrapInMetric('untyped', 'set', false, async () => await this.mutation(requestBody, 'appStorage', 'setAppStoredEntity'));
|
|
70
74
|
}
|
|
71
75
|
async setSecret(key, value) {
|
|
72
76
|
const requestBody = gql_queries_1.UntypedQueries.set(this.doGetAppContextAri(), key, value, true);
|
|
73
|
-
await this.mutation(requestBody, 'appStorage', 'setAppStoredEntity');
|
|
77
|
+
await this.wrapInMetric('untyped', 'set', true, async () => await this.mutation(requestBody, 'appStorage', 'setAppStoredEntity'));
|
|
74
78
|
}
|
|
75
79
|
async delete(key) {
|
|
76
80
|
const requestBody = gql_queries_1.UntypedQueries.delete(this.doGetAppContextAri(), key, false);
|
|
77
|
-
await this.mutation(requestBody, 'appStorage', 'deleteAppStoredEntity');
|
|
81
|
+
await this.wrapInMetric('untyped', 'delete', false, async () => this.mutation(requestBody, 'appStorage', 'deleteAppStoredEntity'));
|
|
78
82
|
}
|
|
79
83
|
async deleteSecret(key) {
|
|
80
84
|
const requestBody = gql_queries_1.UntypedQueries.delete(this.doGetAppContextAri(), key, true);
|
|
81
|
-
await this.mutation(requestBody, 'appStorage', 'deleteAppStoredEntity');
|
|
85
|
+
await this.wrapInMetric('untyped', 'delete', true, async () => this.mutation(requestBody, 'appStorage', 'deleteAppStoredEntity'));
|
|
82
86
|
}
|
|
83
87
|
async getEntity(entityName, entityKey) {
|
|
84
88
|
return this.getEntityInternal(entityName, entityKey);
|
|
85
89
|
}
|
|
86
90
|
async setEntity(entityName, entityKey, value) {
|
|
87
91
|
const requestBody = gql_queries_1.CustomEntityQueries.set(this.doGetAppContextAri(), entityName, entityKey, value);
|
|
88
|
-
await this.mutation(requestBody, 'appStorageCustomEntity', 'setAppStoredCustomEntity');
|
|
92
|
+
await this.wrapInMetric('typed', 'set', false, async () => this.mutation(requestBody, 'appStorageCustomEntity', 'setAppStoredCustomEntity'));
|
|
89
93
|
}
|
|
90
94
|
async deleteEntity(entityName, entityKey) {
|
|
91
95
|
const requestBody = gql_queries_1.CustomEntityQueries.delete(this.doGetAppContextAri(), entityName, entityKey);
|
|
92
|
-
await this.mutation(requestBody, 'appStorageCustomEntity', 'deleteAppStoredCustomEntity');
|
|
96
|
+
await this.wrapInMetric('typed', 'delete', false, async () => await this.mutation(requestBody, 'appStorageCustomEntity', 'deleteAppStoredCustomEntity'));
|
|
93
97
|
}
|
|
94
98
|
async getInternal(key, encrypted) {
|
|
95
99
|
const requestBody = gql_queries_1.UntypedQueries.get(this.doGetAppContextAri(), key, encrypted);
|
|
96
|
-
const { appStoredEntity: { value } } = await this.query(requestBody);
|
|
97
|
-
return value
|
|
100
|
+
const { appStoredEntity: { value } } = await this.wrapInMetric('untyped', 'get', encrypted, async () => await this.query(requestBody));
|
|
101
|
+
return value ?? undefined;
|
|
98
102
|
}
|
|
99
103
|
async getEntityInternal(entityName, entityKey) {
|
|
100
104
|
const requestBody = gql_queries_1.CustomEntityQueries.get(this.doGetAppContextAri(), entityName, entityKey);
|
|
101
|
-
const { appStoredCustomEntity: { value } } = await this.query(requestBody);
|
|
102
|
-
return value
|
|
105
|
+
const { appStoredCustomEntity: { value } } = await this.wrapInMetric('typed', 'get', false, async () => await this.query(requestBody));
|
|
106
|
+
return value ?? undefined;
|
|
103
107
|
}
|
|
104
108
|
buildRequest(requestBody) {
|
|
105
109
|
return {
|
|
@@ -123,5 +127,36 @@ class GlobalStorage {
|
|
|
123
127
|
}
|
|
124
128
|
return response;
|
|
125
129
|
}
|
|
130
|
+
async wrapInMetric(store, operation, encrypted, fn) {
|
|
131
|
+
const metrics = this.getMetrics();
|
|
132
|
+
const timer = metrics
|
|
133
|
+
.timing('forge.runtime.storage.operation.latency', { store, operation, encrypted: String(encrypted) })
|
|
134
|
+
.measure();
|
|
135
|
+
try {
|
|
136
|
+
const result = await fn();
|
|
137
|
+
timer.stop({ success: 'true' });
|
|
138
|
+
metrics
|
|
139
|
+
.counter('forge.runtime.storage.operation', {
|
|
140
|
+
store,
|
|
141
|
+
operation,
|
|
142
|
+
encrypted: String(encrypted),
|
|
143
|
+
success: 'true'
|
|
144
|
+
})
|
|
145
|
+
.incr();
|
|
146
|
+
return result;
|
|
147
|
+
}
|
|
148
|
+
catch (error) {
|
|
149
|
+
timer.stop({ success: 'false' });
|
|
150
|
+
metrics
|
|
151
|
+
.counter('forge.runtime.storage.operation', {
|
|
152
|
+
store,
|
|
153
|
+
operation,
|
|
154
|
+
encrypted: String(encrypted),
|
|
155
|
+
success: 'false'
|
|
156
|
+
})
|
|
157
|
+
.incr();
|
|
158
|
+
throw error;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
126
161
|
}
|
|
127
162
|
exports.GlobalStorage = GlobalStorage;
|
package/out/gql-queries.js
CHANGED
|
@@ -2,10 +2,8 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.CustomEntityQueries = exports.UntypedQueries = void 0;
|
|
4
4
|
class UntypedQueries {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
UntypedQueries.get = (contextAri, key, encrypted) => ({
|
|
8
|
-
query: `
|
|
5
|
+
static get = (contextAri, key, encrypted) => ({
|
|
6
|
+
query: `
|
|
9
7
|
query forge_app_getApplicationStorageEntity($contextAri: ID!, $key: ID!, $encrypted: Boolean!) {
|
|
10
8
|
appStoredEntity(contextAri: $contextAri, key: $key, encrypted: $encrypted) {
|
|
11
9
|
key
|
|
@@ -13,14 +11,14 @@ UntypedQueries.get = (contextAri, key, encrypted) => ({
|
|
|
13
11
|
}
|
|
14
12
|
}
|
|
15
13
|
`,
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
|
|
14
|
+
variables: {
|
|
15
|
+
contextAri,
|
|
16
|
+
key,
|
|
17
|
+
encrypted
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
static set = (contextAri, key, value, encrypted) => ({
|
|
21
|
+
query: `
|
|
24
22
|
mutation forge_app_setApplicationStorageEntity($input: SetAppStoredEntityMutationInput!) {
|
|
25
23
|
appStorage{
|
|
26
24
|
setAppStoredEntity(input: $input) {
|
|
@@ -37,17 +35,17 @@ UntypedQueries.set = (contextAri, key, value, encrypted) => ({
|
|
|
37
35
|
}
|
|
38
36
|
}
|
|
39
37
|
`,
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
38
|
+
variables: {
|
|
39
|
+
input: {
|
|
40
|
+
contextAri,
|
|
41
|
+
key,
|
|
42
|
+
value,
|
|
43
|
+
encrypted
|
|
44
|
+
}
|
|
46
45
|
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
query: `
|
|
46
|
+
});
|
|
47
|
+
static delete = (contextAri, key, encrypted) => ({
|
|
48
|
+
query: `
|
|
51
49
|
mutation forge_app_deleteApplicationStorageEntity($input: DeleteAppStoredEntityMutationInput!) {
|
|
52
50
|
appStorage {
|
|
53
51
|
deleteAppStoredEntity(input: $input) {
|
|
@@ -64,17 +62,15 @@ UntypedQueries.delete = (contextAri, key, encrypted) => ({
|
|
|
64
62
|
}
|
|
65
63
|
}
|
|
66
64
|
`,
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
65
|
+
variables: {
|
|
66
|
+
input: {
|
|
67
|
+
contextAri,
|
|
68
|
+
key,
|
|
69
|
+
encrypted
|
|
70
|
+
}
|
|
72
71
|
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
UntypedQueries.listQuery = (contextAri, options) => {
|
|
76
|
-
var _a, _b, _c;
|
|
77
|
-
return ({
|
|
72
|
+
});
|
|
73
|
+
static listQuery = (contextAri, options) => ({
|
|
78
74
|
query: `
|
|
79
75
|
query forge_app_getApplicationStorageEntities($contextAri: ID!, $where: [AppStoredEntityFilter!], $cursor: String, $limit: Int) {
|
|
80
76
|
appStoredEntities(contextAri: $contextAri, where: $where, after: $cursor, first: $limit) {
|
|
@@ -91,15 +87,12 @@ UntypedQueries.listQuery = (contextAri, options) => {
|
|
|
91
87
|
`,
|
|
92
88
|
variables: {
|
|
93
89
|
contextAri,
|
|
94
|
-
where:
|
|
95
|
-
cursor:
|
|
96
|
-
limit:
|
|
90
|
+
where: options.where ?? null,
|
|
91
|
+
cursor: options.cursor ?? null,
|
|
92
|
+
limit: options.limit ?? null
|
|
97
93
|
}
|
|
98
94
|
});
|
|
99
|
-
|
|
100
|
-
UntypedQueries.listQueryForCleanup = (contextAri, options) => {
|
|
101
|
-
var _a, _b, _c;
|
|
102
|
-
return ({
|
|
95
|
+
static listQueryForCleanup = (contextAri, options) => ({
|
|
103
96
|
query: `
|
|
104
97
|
query forge_app_getApplicationStorageEntitiesForCleanup($contextAri: ID!, $where: [AppStoredEntityFilter!], $cursor: String, $limit: Int) {
|
|
105
98
|
appStoredEntitiesForCleanup(contextAri: $contextAri, where: $where, after: $cursor, first: $limit) {
|
|
@@ -116,17 +109,16 @@ UntypedQueries.listQueryForCleanup = (contextAri, options) => {
|
|
|
116
109
|
`,
|
|
117
110
|
variables: {
|
|
118
111
|
contextAri,
|
|
119
|
-
where:
|
|
120
|
-
cursor:
|
|
121
|
-
limit:
|
|
112
|
+
where: options.where ?? null,
|
|
113
|
+
cursor: options.cursor ?? null,
|
|
114
|
+
limit: options.limit ?? null
|
|
122
115
|
}
|
|
123
116
|
});
|
|
124
|
-
};
|
|
125
|
-
class CustomEntityQueries {
|
|
126
117
|
}
|
|
127
|
-
exports.
|
|
128
|
-
CustomEntityQueries
|
|
129
|
-
|
|
118
|
+
exports.UntypedQueries = UntypedQueries;
|
|
119
|
+
class CustomEntityQueries {
|
|
120
|
+
static get = (contextAri, entityName, key) => ({
|
|
121
|
+
query: `
|
|
130
122
|
query forge_app_getApplicationStorageCustomEntity ($contextAri: ID!, $key: ID!, $entityName: String!) {
|
|
131
123
|
appStoredCustomEntity(contextAri: $contextAri, key: $key, entityName: $entityName) {
|
|
132
124
|
value
|
|
@@ -135,14 +127,14 @@ CustomEntityQueries.get = (contextAri, entityName, key) => ({
|
|
|
135
127
|
}
|
|
136
128
|
}
|
|
137
129
|
`,
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
|
|
130
|
+
variables: {
|
|
131
|
+
contextAri,
|
|
132
|
+
entityName,
|
|
133
|
+
key
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
static set = (contextAri, entityName, key, value) => ({
|
|
137
|
+
query: `
|
|
146
138
|
mutation forge_app_setApplicationStorageCustomEntity($input: SetAppStoredCustomEntityMutationInput!) {
|
|
147
139
|
appStorageCustomEntity{
|
|
148
140
|
setAppStoredCustomEntity(input: $input) {
|
|
@@ -159,17 +151,17 @@ CustomEntityQueries.set = (contextAri, entityName, key, value) => ({
|
|
|
159
151
|
}
|
|
160
152
|
}
|
|
161
153
|
`,
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
154
|
+
variables: {
|
|
155
|
+
input: {
|
|
156
|
+
contextAri,
|
|
157
|
+
entityName,
|
|
158
|
+
key,
|
|
159
|
+
value
|
|
160
|
+
}
|
|
168
161
|
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
query: `
|
|
162
|
+
});
|
|
163
|
+
static delete = (contextAri, entityName, key) => ({
|
|
164
|
+
query: `
|
|
173
165
|
mutation forge_app_deleteApplicationStorageCustomEntity($input: DeleteAppStoredCustomEntityMutationInput!) {
|
|
174
166
|
appStorageCustomEntity {
|
|
175
167
|
deleteAppStoredCustomEntity(input: $input) {
|
|
@@ -186,17 +178,17 @@ CustomEntityQueries.delete = (contextAri, entityName, key) => ({
|
|
|
186
178
|
}
|
|
187
179
|
}
|
|
188
180
|
`,
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
181
|
+
variables: {
|
|
182
|
+
input: {
|
|
183
|
+
contextAri,
|
|
184
|
+
entityName,
|
|
185
|
+
key
|
|
186
|
+
}
|
|
194
187
|
}
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
query: `
|
|
188
|
+
});
|
|
189
|
+
static listQuery = (contextAri, options) => {
|
|
190
|
+
return {
|
|
191
|
+
query: `
|
|
200
192
|
query AppStorageCustomEntityQueries ($contextAri: ID!, $entityName: String!, $indexName: String!, $range: AppStoredCustomEntityRange, $filters: AppStoredCustomEntityFilters, $sort:SortOrder, $limit: Int, $cursor: String, $partition: [AppStoredCustomEntityFieldValue!]) {
|
|
201
193
|
appStoredCustomEntities(contextAri: $contextAri, entityName: $entityName, indexName: $indexName, range: $range, filters: $filters, sort:$sort, limit: $limit, cursor: $cursor, partition: $partition) {
|
|
202
194
|
edges {
|
|
@@ -215,12 +207,24 @@ CustomEntityQueries.listQuery = (contextAri, options) => {
|
|
|
215
207
|
}
|
|
216
208
|
}
|
|
217
209
|
`,
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
210
|
+
variables: {
|
|
211
|
+
contextAri,
|
|
212
|
+
entityName: options.entityName,
|
|
213
|
+
indexName: options.indexName,
|
|
214
|
+
range: options.range,
|
|
215
|
+
...(options.filters && options.filters.length
|
|
216
|
+
? {
|
|
217
|
+
filters: {
|
|
218
|
+
[options.filterOperator || 'and']: options.filters
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
: {}),
|
|
222
|
+
...(options.partition ? { partition: options.partition } : {}),
|
|
223
|
+
...(options.sort ? { sort: options.sort } : {}),
|
|
224
|
+
...(options.cursor ? { cursor: options.cursor } : {}),
|
|
225
|
+
...(options.limit ? { limit: options.limit } : {})
|
|
223
226
|
}
|
|
224
|
-
|
|
227
|
+
};
|
|
225
228
|
};
|
|
226
|
-
}
|
|
229
|
+
}
|
|
230
|
+
exports.CustomEntityQueries = CustomEntityQueries;
|
package/out/query-api.js
CHANGED
|
@@ -2,20 +2,34 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.DefaultQueryBuilder = void 0;
|
|
4
4
|
class DefaultQueryBuilder {
|
|
5
|
+
globalStorage;
|
|
6
|
+
queryOptions;
|
|
5
7
|
constructor(globalStorage, queryOptions = {}) {
|
|
6
8
|
this.globalStorage = globalStorage;
|
|
7
9
|
this.queryOptions = queryOptions;
|
|
8
10
|
}
|
|
9
11
|
where(field, where) {
|
|
10
|
-
return new DefaultQueryBuilder(this.globalStorage,
|
|
11
|
-
|
|
12
|
-
|
|
12
|
+
return new DefaultQueryBuilder(this.globalStorage, {
|
|
13
|
+
...this.queryOptions,
|
|
14
|
+
where: [
|
|
15
|
+
{
|
|
16
|
+
field,
|
|
17
|
+
...where
|
|
18
|
+
}
|
|
19
|
+
]
|
|
20
|
+
});
|
|
13
21
|
}
|
|
14
22
|
cursor(cursor) {
|
|
15
|
-
return new DefaultQueryBuilder(this.globalStorage,
|
|
23
|
+
return new DefaultQueryBuilder(this.globalStorage, {
|
|
24
|
+
...this.queryOptions,
|
|
25
|
+
cursor
|
|
26
|
+
});
|
|
16
27
|
}
|
|
17
28
|
limit(limit) {
|
|
18
|
-
return new DefaultQueryBuilder(this.globalStorage,
|
|
29
|
+
return new DefaultQueryBuilder(this.globalStorage, {
|
|
30
|
+
...this.queryOptions,
|
|
31
|
+
limit
|
|
32
|
+
});
|
|
19
33
|
}
|
|
20
34
|
async getOne() {
|
|
21
35
|
const { results } = await this.limit(1).getMany();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@forge/storage",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0-next.0",
|
|
4
4
|
"description": "Forge Storage methods",
|
|
5
5
|
"author": "Atlassian",
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -17,6 +17,8 @@
|
|
|
17
17
|
"devDependencies": {
|
|
18
18
|
"@types/node": "14.18.63",
|
|
19
19
|
"@types/node-fetch": "^2.6.11",
|
|
20
|
-
"node-fetch": "2.7.0"
|
|
20
|
+
"node-fetch": "2.7.0",
|
|
21
|
+
"@forge/util": "1.4.4",
|
|
22
|
+
"@atlassian/metrics-interface": "4.0.0"
|
|
21
23
|
}
|
|
22
|
-
}
|
|
24
|
+
}
|