ydb-embedded-ui 1.13.1 → 1.14.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/dist/assets/icons/flask.svg +3 -0
  3. package/dist/components/InfoViewer/formatters/common.ts +15 -0
  4. package/dist/components/InfoViewer/formatters/index.ts +2 -0
  5. package/dist/components/InfoViewer/formatters/schema.ts +43 -0
  6. package/dist/components/InfoViewer/schemaInfo/CDCStreamInfo.tsx +44 -0
  7. package/dist/components/InfoViewer/schemaInfo/PersQueueGroupInfo.tsx +34 -0
  8. package/dist/components/{IndexInfoViewer/IndexInfoViewer.tsx → InfoViewer/schemaInfo/TableIndexInfo.tsx} +7 -18
  9. package/dist/components/InfoViewer/schemaInfo/index.ts +3 -0
  10. package/dist/components/InfoViewer/schemaOverview/CDCStreamOverview.tsx +44 -0
  11. package/dist/components/InfoViewer/schemaOverview/PersQueueGroupOverview.tsx +35 -0
  12. package/dist/components/InfoViewer/schemaOverview/index.ts +2 -0
  13. package/dist/components/QueryResultTable/Cell/Cell.tsx +33 -0
  14. package/dist/components/QueryResultTable/Cell/index.ts +1 -0
  15. package/dist/components/QueryResultTable/QueryResultTable.scss +11 -0
  16. package/dist/components/QueryResultTable/QueryResultTable.tsx +115 -0
  17. package/dist/components/QueryResultTable/i18n/en.json +3 -0
  18. package/dist/components/QueryResultTable/i18n/index.ts +11 -0
  19. package/dist/components/QueryResultTable/i18n/ru.json +3 -0
  20. package/dist/components/QueryResultTable/index.ts +1 -0
  21. package/dist/containers/App/App.scss +1 -0
  22. package/dist/containers/Storage/DiskStateProgressBar/DiskStateProgressBar.scss +39 -14
  23. package/dist/containers/Storage/DiskStateProgressBar/DiskStateProgressBar.tsx +18 -7
  24. package/dist/containers/Storage/Pdisk/__tests__/colors.tsx +4 -3
  25. package/dist/containers/Storage/Vdisk/__tests__/colors.tsx +7 -7
  26. package/dist/containers/Tenant/Acl/Acl.js +7 -1
  27. package/dist/containers/Tenant/Diagnostics/DiagnosticsPages.ts +6 -2
  28. package/dist/containers/Tenant/Diagnostics/HotKeys/HotKeys.js +1 -1
  29. package/dist/containers/Tenant/Diagnostics/Overview/Overview.tsx +8 -3
  30. package/dist/containers/Tenant/Diagnostics/TopQueries/TopQueries.js +1 -1
  31. package/dist/containers/Tenant/Diagnostics/TopShards/TopShards.js +1 -1
  32. package/dist/containers/Tenant/ObjectSummary/ObjectSummary.tsx +36 -10
  33. package/dist/containers/Tenant/Preview/Preview.js +15 -57
  34. package/dist/containers/Tenant/Preview/Preview.scss +4 -8
  35. package/dist/containers/Tenant/QueryEditor/QueryEditor.js +12 -41
  36. package/dist/containers/Tenant/QueryEditor/QueryEditor.scss +1 -5
  37. package/dist/containers/Tenant/QueryEditor/QueryExplain/QueryExplain.scss +1 -2
  38. package/dist/containers/Tenant/QueryEditor/QueryResult/QueryResult.scss +2 -2
  39. package/dist/containers/Tenant/Schema/SchemaTree/SchemaTree.tsx +9 -1
  40. package/dist/containers/Tenant/Tenant.scss +2 -50
  41. package/dist/containers/Tenant/Tenant.tsx +24 -22
  42. package/dist/containers/Tenant/utils/schema.ts +3 -0
  43. package/dist/containers/Tenant/utils/schemaActions.ts +1 -2
  44. package/dist/containers/Tenants/Tenants.js +12 -2
  45. package/dist/containers/UserSettings/UserSettings.tsx +26 -3
  46. package/dist/services/api.d.ts +19 -2
  47. package/dist/services/api.js +2 -2
  48. package/dist/setupTests.js +4 -0
  49. package/dist/store/reducers/executeQuery.js +4 -9
  50. package/dist/store/reducers/{preview.js → preview.ts} +22 -18
  51. package/dist/store/reducers/settings.js +3 -1
  52. package/dist/store/utils.ts +88 -0
  53. package/dist/types/api/query.ts +147 -0
  54. package/dist/types/api/schema.ts +235 -2
  55. package/dist/types/index.ts +33 -0
  56. package/dist/types/store/query.ts +9 -0
  57. package/dist/utils/{constants.js → constants.ts} +11 -6
  58. package/dist/utils/index.js +0 -24
  59. package/dist/utils/query.test.ts +189 -0
  60. package/dist/utils/query.ts +156 -0
  61. package/dist/utils/tests/providers.tsx +29 -0
  62. package/package.json +2 -2
  63. package/dist/store/utils.js +0 -51
@@ -0,0 +1,147 @@
1
+ // common
2
+
3
+ type Plan = Record<string, any>;
4
+ type AST = string;
5
+ type Stats = Record<string, any>;
6
+
7
+ export interface CommonFields {
8
+ ast?: AST;
9
+ plan?: Plan;
10
+ stats?: Stats;
11
+ };
12
+
13
+ interface DeprecatedCommonFields {
14
+ stats?: Stats;
15
+ }
16
+
17
+ export interface ErrorRepsonse {
18
+ error?: any;
19
+ issues?: any;
20
+ };
21
+
22
+ export type ExecuteActions = 'execute-script' | 'execute' | 'execute-scan' | undefined;
23
+ export type ExplainActions = 'explain' | 'explain-ast';
24
+ export type Actions = ExecuteActions | ExplainActions;
25
+
26
+ // undefined == 'classic'
27
+ export type Schemas = 'classic' | 'modern' | 'ydb' | undefined;
28
+
29
+ // ==== EXECUTE ====
30
+
31
+ // common types
32
+
33
+ type CellValue = string | number | null | undefined;
34
+
35
+ export type KeyValueRow<T = CellValue> = {
36
+ [key: string]: T;
37
+ }
38
+
39
+ export type ArrayRow<T = CellValue> = Array<T>;
40
+
41
+ export interface ColumnType {
42
+ name: string;
43
+ type: string;
44
+ }
45
+
46
+ // modern response
47
+
48
+ export type ExecuteModernResponse = {
49
+ // either both fields exist, or neither one does
50
+ // they can be undefined for queries like `insert into`
51
+ result?: ArrayRow[];
52
+ columns?: ColumnType[];
53
+ } & CommonFields;
54
+
55
+ export type ExecuteClassicResponseDeep = {
56
+ // can be undefined for queries like `insert into`
57
+ result?: KeyValueRow[];
58
+ } & CommonFields;
59
+
60
+ // can be undefined for queries like `insert into`
61
+ export type ExecuteClassicResponsePlain = KeyValueRow[] | undefined;
62
+
63
+ export type ExecuteClassicResponse = ExecuteClassicResponseDeep | ExecuteClassicResponsePlain;
64
+
65
+ export type ExecuteYdbResponse = {
66
+ // can be undefined for queries like `insert into`
67
+ result?: KeyValueRow[];
68
+ } & CommonFields;
69
+
70
+ type ExecuteResponse<Schema extends Schemas> = (
71
+ Schema extends 'modern'
72
+ ? ExecuteModernResponse
73
+ : Schema extends 'ydb'
74
+ ? ExecuteYdbResponse
75
+ : Schema extends 'classic' | undefined
76
+ ? ExecuteClassicResponse
77
+ : unknown
78
+ );
79
+
80
+ // deprecated response from older versions, backward compatibility
81
+
82
+ type DeprecatedExecuteResponseValue =
83
+ | KeyValueRow[]
84
+ | string
85
+ // can be here because of a bug in the previous backend version
86
+ // should be ignored in parsing
87
+ | Plan;
88
+
89
+ export type DeprecatedExecuteResponseDeep = {
90
+ // can be undefined for queries like `insert into`
91
+ result?: DeprecatedExecuteResponseValue;
92
+ } & DeprecatedCommonFields;
93
+
94
+ // can be undefined for queries like `insert into`
95
+ export type DeprecatedExecuteResponsePlain = DeprecatedExecuteResponseValue | undefined;
96
+
97
+ export type DeprecatedExecuteResponse = DeprecatedExecuteResponseDeep | DeprecatedExecuteResponsePlain;
98
+
99
+
100
+ // ==== EXPLAIN ====
101
+
102
+ // modern response
103
+
104
+ type ExplainResponse = CommonFields;
105
+
106
+ // deprecated response from older versions, backward compatibility
107
+
108
+ type DeprecatedExplainResponse<Action extends ExplainActions> = (
109
+ Action extends 'explain-ast'
110
+ ? {ast: AST} & DeprecatedCommonFields
111
+ : Actions extends 'explain'
112
+ ? ({result: Plan} & DeprecatedCommonFields) | Plan
113
+ : unknown
114
+ );
115
+
116
+
117
+ // ==== COMBINED API RESPONSE ====
118
+
119
+ export type QueryAPIExecuteResponse<Schema extends Schemas = undefined> =
120
+ | ExecuteResponse<Schema>
121
+ | DeprecatedExecuteResponse
122
+ | null;
123
+
124
+ export type QueryAPIExplainResponse<Action extends ExplainActions> =
125
+ | ExplainResponse
126
+ | DeprecatedExplainResponse<Action>
127
+ | null;
128
+
129
+ export type QueryAPIResponse<Action extends Actions, Schema extends Schemas = undefined> = (
130
+ Action extends ExecuteActions
131
+ ? QueryAPIExecuteResponse<Schema>
132
+ : Action extends ExplainActions
133
+ ? QueryAPIExplainResponse<Action>
134
+ : unknown
135
+ );
136
+
137
+ export type AnyExecuteResponse =
138
+ | ExecuteModernResponse
139
+ | ExecuteClassicResponse
140
+ | ExecuteYdbResponse
141
+ | DeprecatedExecuteResponse;
142
+
143
+ export type DeepExecuteResponse =
144
+ | ExecuteModernResponse
145
+ | ExecuteClassicResponseDeep
146
+ | ExecuteYdbResponse
147
+ | DeprecatedExecuteResponseDeep;
@@ -56,9 +56,12 @@ interface TPathDescription {
56
56
  ColumnTableDescription?: unknown;
57
57
 
58
58
  TableIndex?: TIndexDescription;
59
+
60
+ CdcStreamDescription?: TCdcStreamDescription;
61
+ PersQueueGroup?: TPersQueueGroupDescription;
59
62
  }
60
63
 
61
- interface TDirEntry {
64
+ export interface TDirEntry {
62
65
  Name?: string;
63
66
  /** uint64 */
64
67
  PathId?: string;
@@ -208,12 +211,50 @@ export interface TIndexDescription {
208
211
  DataSize?: string;
209
212
  }
210
213
 
214
+ enum ECdcStreamMode {
215
+ ECdcStreamModeInvalid = 'ECdcStreamModeInvalid',
216
+ ECdcStreamModeKeysOnly = 'ECdcStreamModeKeysOnly',
217
+ ECdcStreamModeUpdate = 'ECdcStreamModeUpdate',
218
+ ECdcStreamModeNewImage = 'ECdcStreamModeNewImage',
219
+ ECdcStreamModeOldImage = 'ECdcStreamModeOldImage',
220
+ ECdcStreamModeNewAndOldImages = 'ECdcStreamModeNewAndOldImages',
221
+ }
222
+
223
+ enum ECdcStreamFormat {
224
+ ECdcStreamFormatInvalid = 'ECdcStreamFormatInvalid',
225
+ ECdcStreamFormatProto = 'ECdcStreamFormatProto',
226
+ ECdcStreamFormatJson = 'ECdcStreamFormatJson',
227
+ }
228
+
229
+ enum ECdcStreamState {
230
+ ECdcStreamStateInvalid = 'ECdcStreamStateInvalid',
231
+ ECdcStreamStateReady = 'ECdcStreamStateReady',
232
+ ECdcStreamStateDisabled = 'ECdcStreamStateDisabled',
233
+ }
234
+
235
+ interface TPathID {
236
+ /** fixed64 */
237
+ OwnerId?: string;
238
+ /** uint64 */
239
+ LocalId?: string;
240
+ }
241
+
242
+ export interface TCdcStreamDescription {
243
+ Name?: string;
244
+ Mode?: ECdcStreamMode;
245
+ Format?: ECdcStreamFormat;
246
+ PathId?: TPathID;
247
+ State?: ECdcStreamState;
248
+ /** uint64 */
249
+ SchemaVersion?: string;
250
+ }
251
+
211
252
  // incomplete
212
253
  export enum EPathType {
213
254
  EPathTypeInvalid = 'EPathTypeInvalid',
214
255
  EPathTypeDir = 'EPathTypeDir',
215
256
  EPathTypeTable = 'EPathTypeTable',
216
-
257
+ EPathTypePersQueueGroup = 'EPathTypePersQueueGroup',
217
258
  EPathTypeSubDomain = 'EPathTypeSubDomain',
218
259
 
219
260
  EPathTypeTableIndex = 'EPathTypeTableIndex',
@@ -264,3 +305,195 @@ interface TPathVersion {
264
305
  /** uint64 */
265
306
  GeneralVersion?: string;
266
307
  }
308
+
309
+ interface TPartitionKeyRange {
310
+ // Inclusive left border. Emptiness means -inf.
311
+ FromBound?: string;
312
+ // Exclusive right border. Emptiness means +inf.
313
+ ToBound?: string;
314
+ }
315
+
316
+ interface TPartition {
317
+ PartitionId?: number;
318
+ /** uint64 */
319
+ TabletId?: string;
320
+ KeyRange?: TPartitionKeyRange;
321
+ }
322
+
323
+ interface TPartitionToAdd {
324
+ PartitionId?: number;
325
+ GroupId?: number;
326
+ }
327
+
328
+ interface TCodecs {
329
+ /** int64 */
330
+ Ids?: string[];
331
+ Codecs?: string[];
332
+ }
333
+
334
+ interface TKeyComponentSchema {
335
+ Name?: string;
336
+ TypeId?: number;
337
+ }
338
+
339
+ enum EMeteringMode {
340
+ METERING_MODE_RESERVED_CAPACITY = 'METERING_MODE_RESERVED_CAPACITY',
341
+ METERING_MODE_REQUEST_UNITS = 'METERING_MODE_REQUEST_UNITS',
342
+ }
343
+
344
+ interface TReadQuota {
345
+ ClientId?: string;
346
+ /** uint64 */
347
+ SpeedInBytesPerSecond?: string;
348
+ /** uint64 */
349
+ BurstSize?: string;
350
+ }
351
+
352
+ interface TChannelProfile {
353
+ PoolKind?: string;
354
+ /** uint64 */
355
+ Size?: string;
356
+ ReadIops?: number;
357
+ ReadBandwidth?: number;
358
+ WriteIops?: number;
359
+ WriteBandwidth?: number;
360
+ }
361
+
362
+ interface IamCredentials {
363
+ Endpoint?: string;
364
+ ServiceAccountKey?: string;
365
+ }
366
+
367
+ interface TCredentials {
368
+ OauthToken?: string;
369
+ JwtParams?: string;
370
+ Iam?: IamCredentials;
371
+ }
372
+
373
+ interface TMirrorPartitionConfig {
374
+ Endpoint?: string;
375
+ EndpointPort?: number;
376
+ Topic?: string;
377
+ Consumer?: string;
378
+ /** uint64 */
379
+ ReadFromTimestampsMs?: string;
380
+ Credentials?: TCredentials;
381
+ Database?: string;
382
+ UseSecureConnection?: boolean;
383
+ SyncWriteTime?: boolean;
384
+ }
385
+
386
+ interface TPQPartitionConfig {
387
+ MaxCountInPartition?: number;
388
+ /** int64 */
389
+ MaxSizeInPartition?: string;
390
+ LifetimeSeconds: number;
391
+ /** uint64 */
392
+ StorageLimitBytes?: string;
393
+
394
+ ImportantClientId?: string[];
395
+ LowWatermark?: number;
396
+ SourceIdLifetimeSeconds?: number;
397
+ SourceIdMaxCounts?: number;
398
+
399
+ /** uint64 */
400
+ WriteSpeedInBytesPerSecond?: string;
401
+ /** uint64 */
402
+ BurstSize?: string;
403
+
404
+ ReadQuota?: TReadQuota[];
405
+ /** uint64 */
406
+ MaxWriteInflightSize?: string;
407
+ /** uint64 */
408
+ BorderWriteInflightSize?: string;
409
+
410
+ NumChannels?: number;
411
+
412
+ TotalPartitions?: number;
413
+
414
+ ExplicitChannelProfiles?: TChannelProfile[];
415
+
416
+ MirrorFrom?: TMirrorPartitionConfig;
417
+ };
418
+
419
+ interface TPQTabletConfig {
420
+ /** uint64 */
421
+ CacheSize?: string;
422
+ PartitionConfig: TPQPartitionConfig;
423
+ /** @deprecated use Partitions */
424
+ PartitionIds?: number[];
425
+ TopicName?: string;
426
+ Version?: number;
427
+ LocalDC?: boolean;
428
+ RequireAuthWrite?: boolean;
429
+ RequireAuthRead?: boolean;
430
+ Producer?: string;
431
+ Ident?: string;
432
+ Topic?: string;
433
+ DC?: string;
434
+
435
+ ReadRules?: string[];
436
+ /** uint64[] */
437
+ ReadFromTimestampsMs?: number[];
438
+ /** uint64[] */
439
+ ConsumerFormatVersions?: number[];
440
+
441
+ ConsumerCodecs?: TCodecs[];
442
+ ReadRuleServiceTypes?: string;
443
+
444
+ /** uint64 */
445
+ FormatVersion?: string;
446
+ Codecs?: TCodecs;
447
+
448
+ /** uint64[] */
449
+ ReadRuleVersions?: string[];
450
+ /** uint64[] */
451
+ ReadRuleGenerations?: string[];
452
+
453
+ TopicPath?: string;
454
+
455
+ YcCloudId?: string;
456
+ YcFolderId?: string;
457
+ YdbDatabaseId?: string;
458
+ YdbDatabasePath?: string;
459
+ FederationAccount?: string;
460
+
461
+ PartitionKeySchema?: TKeyComponentSchema[];
462
+
463
+ Partitions?: TPartition[];
464
+
465
+ MeteringMode?: EMeteringMode;
466
+ }
467
+
468
+ interface TMessageGroup {
469
+ // Id of message group (SourceId)
470
+ Id?: string;
471
+ // Range of the key to which it is allowed to write.
472
+ KeyRange?: TPartitionKeyRange;
473
+ }
474
+
475
+ interface TBootstrapConfig {
476
+ ExplicitMessageGroups?: TMessageGroup[];
477
+ }
478
+
479
+ export interface TPersQueueGroupDescription {
480
+ Name: string;
481
+ /** uint64 */
482
+ PathId?: string;
483
+ TotalGroupCount: number;
484
+
485
+ PartitionsToAdd?: TPartitionToAdd[];
486
+ PartitionsToDelete?: number[];
487
+ NextPartitionId?: number;
488
+ PartitionPerTablet?: number;
489
+ PQTabletConfig: TPQTabletConfig;
490
+ Partitions?: TPartition[];
491
+ /** uint64 */
492
+ AlterVersion?: string;
493
+ /** uint64 */
494
+ BalancerTabletID?: string;
495
+
496
+ PartitionBoundaries?: any;
497
+
498
+ BootstrapConfig?: TBootstrapConfig;
499
+ }
@@ -1 +1,34 @@
1
1
  export type RequiredField<Src, Fields extends keyof Src> = Src & Required<Pick<Src, Fields>>;
2
+
3
+ export enum YQLType {
4
+ // Numeric
5
+ Bool = 'Bool',
6
+ Int8 = 'Int8',
7
+ Int16 = 'Int16',
8
+ Int32 = 'Int32',
9
+ Int64 = 'Int64',
10
+ Uint8 = 'Uint8',
11
+ Uint16 = 'Uint16',
12
+ Uint32 = 'Uint32',
13
+ Uint64 = 'Uint64',
14
+ Float = 'Float',
15
+ Double = 'Double',
16
+ Decimal = 'Decimal',
17
+
18
+ // String
19
+ String = 'String',
20
+ Utf8 = 'Utf8',
21
+ Json = 'Json',
22
+ JsonDocument = 'JsonDocument',
23
+ Yson = 'Yson',
24
+ Uuid = 'Uuid',
25
+
26
+ // Date and time
27
+ Date = 'Date',
28
+ Datetime = 'Datetime',
29
+ Timestamp = 'Timestamp',
30
+ Interval = 'Interval',
31
+ TzDate = 'TzDate',
32
+ TzDateTime = 'TzDateTime',
33
+ TzTimestamp = 'TzTimestamp',
34
+ }
@@ -0,0 +1,9 @@
1
+ import type {KeyValueRow, ColumnType} from '../api/query';
2
+
3
+ export interface IQueryResult {
4
+ result?: KeyValueRow[];
5
+ columns?: ColumnType[];
6
+ stats?: any;
7
+ plan?: any;
8
+ ast?: any;
9
+ }
@@ -14,7 +14,8 @@ export const GIGABYTE = 1_000_000_000;
14
14
  export const TERABYTE = 1_000_000_000_000;
15
15
  export const GROUP = 'group';
16
16
 
17
- export const DAY_IN_SECONDS = 24 * 60 * 60;
17
+ export const HOUR_IN_SECONDS = 60 * 60;
18
+ export const DAY_IN_SECONDS = 24 * HOUR_IN_SECONDS;
18
19
 
19
20
  export const TABLET_STATES = {
20
21
  TABLET_VOLATILE_STATE_UNKNOWN: 'unknown',
@@ -87,13 +88,15 @@ export const TABLET_SYMBOLS = {
87
88
  TenantSlotBroker: 'TB',
88
89
  };
89
90
 
90
- export const getTabletLabel = (type) => {
91
+ const isTabletType = (type: string): type is keyof typeof TABLET_SYMBOLS => type in TABLET_SYMBOLS;
92
+
93
+ export const getTabletLabel = (type?: string) => {
91
94
  if (!type) {
92
- return;
95
+ return undefined;
93
96
  }
94
- const defaultValue = type.match(/[A-Z]/g).join('');
97
+ const defaultValue = type.match(/[A-Z]/g)?.join('');
95
98
 
96
- return TABLET_SYMBOLS[type] || defaultValue;
99
+ return isTabletType(type) ? TABLET_SYMBOLS[type] : defaultValue;
97
100
  };
98
101
 
99
102
  export const LOAD_AVERAGE_TIME_INTERVALS = ['1 min', '5 min', '15 min'];
@@ -116,12 +119,14 @@ export const ALL = 'All';
116
119
  export const PROBLEMS = 'With problems';
117
120
 
118
121
  export const THEME_KEY = 'theme';
122
+ export const INVERTED_DISKS_KEY = 'invertedDisks';
119
123
  export const SAVED_QUERIES_KEY = 'saved_queries';
120
124
  export const QUERIES_HISTORY_KEY = 'queries_history';
121
125
  export const DATA_QA_TUNE_COLUMNS_POPUP = 'tune-columns-popup';
122
126
 
123
127
  export const defaultUserSettings = {
124
128
  [THEME_KEY]: 'light',
129
+ [INVERTED_DISKS_KEY]: false,
125
130
  };
126
131
  export const DEFAULT_SIZE_RESULT_PANE_KEY = 'default-size-result-pane';
127
132
  export const DEFAULT_SIZE_TENANT_SUMMARY_KEY = 'default-size-tenant-summary-pane';
@@ -139,7 +144,7 @@ export const DEFAULT_TABLE_SETTINGS = {
139
144
  syncHeadOnResize: true,
140
145
  dynamicRender: true,
141
146
  highlightRows: true,
142
- };
147
+ } as const;
143
148
 
144
149
  export const TENANT_INITIAL_TAB_KEY = 'saved_tenant_initial_tab';
145
150
  export const QUERY_INITIAL_RUN_ACTION_KEY = 'query_initial_run_action';
@@ -1,6 +1,5 @@
1
1
  import numeral from 'numeral';
2
2
  import locales from 'numeral/locales'; // eslint-disable-line no-unused-vars
3
- import _ from 'lodash';
4
3
 
5
4
  import {i18n} from './i18n';
6
5
  import {MEGABYTE, TERABYTE, DAY_IN_SECONDS, GIGABYTE} from './constants';
@@ -143,26 +142,3 @@ export const getMetaForExplainNode = (node) => {
143
142
  return '';
144
143
  }
145
144
  };
146
-
147
- export const prepareQueryResponse = (data) => {
148
- return _.map(data, (item) => {
149
- const formattedData = {};
150
-
151
- for (const field in item) {
152
- if (Object.prototype.hasOwnProperty.call(item, field)) {
153
- const type = typeof item[field];
154
- if (type === 'object' || type === 'boolean' || Array.isArray(item[field])) {
155
- formattedData[field] = JSON.stringify(item[field]);
156
- } else {
157
- formattedData[field] = item[field];
158
- }
159
- }
160
- }
161
-
162
- return formattedData;
163
- });
164
- };
165
-
166
- export function prepareQueryError(error) {
167
- return error.data?.error?.message || error.data || error
168
- }