@uipath/data-fabric-tool 1.1.0 → 1.196.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/dist/tool.js +6246 -5365
- package/package.json +16 -24
- package/src/commands/choice-sets.spec.ts +571 -83
- package/src/commands/choice-sets.ts +561 -147
- package/src/commands/entities.spec.ts +109 -159
- package/src/commands/entities.ts +181 -372
- package/src/commands/files.spec.ts +62 -34
- package/src/commands/files.ts +51 -88
- package/src/commands/records.spec.ts +188 -206
- package/src/commands/records.ts +133 -330
- package/src/tool.ts +5 -1
- package/src/utils/input.spec.ts +127 -0
- package/src/utils/input.ts +30 -1
- package/src/utils/output.spec.ts +91 -0
- package/src/utils/output.ts +69 -0
- package/src/utils/sdk-client.spec.ts +59 -0
- package/src/utils/sdk-client.ts +23 -0
- package/src/utils/pagination.ts +0 -10
package/src/commands/records.ts
CHANGED
|
@@ -9,10 +9,10 @@ import {
|
|
|
9
9
|
} from "@uipath/common";
|
|
10
10
|
import { getFileSystem } from "@uipath/filesystem";
|
|
11
11
|
import type { EntityRecord } from "@uipath/uipath-typescript";
|
|
12
|
-
import type
|
|
12
|
+
import { type Command, Option } from "commander";
|
|
13
13
|
import { readFileBinary, readJsonInput } from "../utils/input";
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
14
|
+
import { fail, requireDestructiveConfirmation } from "../utils/output";
|
|
15
|
+
import { connectOrFail } from "../utils/sdk-client";
|
|
16
16
|
|
|
17
17
|
interface ListOptions {
|
|
18
18
|
tenant?: string;
|
|
@@ -39,6 +39,9 @@ interface UpdateOptions {
|
|
|
39
39
|
|
|
40
40
|
interface DeleteOptions {
|
|
41
41
|
tenant?: string;
|
|
42
|
+
yes?: boolean;
|
|
43
|
+
confirm?: boolean;
|
|
44
|
+
reason?: string;
|
|
42
45
|
}
|
|
43
46
|
|
|
44
47
|
interface QueryOptions {
|
|
@@ -62,14 +65,13 @@ interface BatchResult {
|
|
|
62
65
|
|
|
63
66
|
const RECORDS_LIST_EXAMPLES: CommandExample[] = [
|
|
64
67
|
{
|
|
65
|
-
Description: "List records in an entity",
|
|
68
|
+
Description: "List records in an entity.",
|
|
66
69
|
Command:
|
|
67
70
|
"uip df records list a1b2c3d4-0000-0000-0000-000000000001 --limit 2",
|
|
68
71
|
Output: {
|
|
69
72
|
Code: "RecordList",
|
|
70
73
|
Data: {
|
|
71
|
-
|
|
72
|
-
Records: [
|
|
74
|
+
items: [
|
|
73
75
|
{
|
|
74
76
|
Id: "b2c3d4e5-0000-0000-0000-000000000001",
|
|
75
77
|
amount: 1500,
|
|
@@ -79,7 +81,8 @@ const RECORDS_LIST_EXAMPLES: CommandExample[] = [
|
|
|
79
81
|
amount: 2750,
|
|
80
82
|
},
|
|
81
83
|
],
|
|
82
|
-
|
|
84
|
+
totalCount: 2,
|
|
85
|
+
hasNextPage: false,
|
|
83
86
|
},
|
|
84
87
|
},
|
|
85
88
|
},
|
|
@@ -118,9 +121,9 @@ const RECORDS_INSERT_EXAMPLES: CommandExample[] = [
|
|
|
118
121
|
{
|
|
119
122
|
Description:
|
|
120
123
|
"Insert a record into an entity that has choice-set and relationship fields. " +
|
|
121
|
-
"CHOICE_SET_SINGLE → pass the choice value's '
|
|
122
|
-
"CHOICE_SET_MULTIPLE → pass an array of
|
|
123
|
-
"RELATIONSHIP → always pass the target record's Id (UUID),
|
|
124
|
+
"CHOICE_SET_SINGLE → pass the choice value's 'numberId' (integer, NOT the name string — look it up via 'df choice-sets list-values <id>'). " +
|
|
125
|
+
"CHOICE_SET_MULTIPLE → pass an array of numberId integers. " +
|
|
126
|
+
"RELATIONSHIP → always pass the target record's Id (UUID), regardless of which 'referenceFieldId' the schema uses for the join (the referenceFieldId configures the join, not the stored value).",
|
|
124
127
|
Command:
|
|
125
128
|
'uip df records insert a1b2c3d4-0000-0000-0000-000000000004 --body \'{"category":0,"tags":[1,3],"submitter":"e1f2a3b4-0000-0000-0000-000000000001","amount":250}\'',
|
|
126
129
|
Output: {
|
|
@@ -201,58 +204,36 @@ export const registerRecordsCommand = (program: Command) => {
|
|
|
201
204
|
async (entityId: string, options: ListOptions) => {
|
|
202
205
|
const pageSize = Number(options.limit);
|
|
203
206
|
if (Number.isNaN(pageSize) || pageSize < 1) {
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
});
|
|
209
|
-
processContext.exit(1);
|
|
210
|
-
return;
|
|
207
|
+
return fail(
|
|
208
|
+
"Invalid --limit value",
|
|
209
|
+
"Provide a positive integer for --limit.",
|
|
210
|
+
);
|
|
211
211
|
}
|
|
212
212
|
|
|
213
213
|
if (
|
|
214
214
|
options.cursor !== undefined &&
|
|
215
215
|
options.offset !== undefined
|
|
216
216
|
) {
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
"Use --offset to jump to a position by record count, or --cursor to continue from a previous response.",
|
|
222
|
-
});
|
|
223
|
-
processContext.exit(1);
|
|
224
|
-
return;
|
|
217
|
+
return fail(
|
|
218
|
+
"--offset and --cursor are mutually exclusive",
|
|
219
|
+
"Use --offset to jump to a position by record count, or --cursor to continue from a previous response.",
|
|
220
|
+
);
|
|
225
221
|
}
|
|
226
222
|
|
|
227
223
|
let jumpToPage: number | undefined;
|
|
228
224
|
if (options.offset !== undefined) {
|
|
229
225
|
const offsetValue = Number(options.offset);
|
|
230
226
|
if (Number.isNaN(offsetValue) || offsetValue < 0) {
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
"Provide a non-negative integer for --offset.",
|
|
236
|
-
});
|
|
237
|
-
processContext.exit(1);
|
|
238
|
-
return;
|
|
227
|
+
return fail(
|
|
228
|
+
"Invalid --offset value",
|
|
229
|
+
"Provide a non-negative integer for --offset.",
|
|
230
|
+
);
|
|
239
231
|
}
|
|
240
232
|
jumpToPage = Math.floor(offsetValue / pageSize) + 1;
|
|
241
233
|
}
|
|
242
234
|
|
|
243
|
-
const
|
|
244
|
-
|
|
245
|
-
);
|
|
246
|
-
|
|
247
|
-
if (clientError) {
|
|
248
|
-
OutputFormatter.error({
|
|
249
|
-
Result: RESULTS.Failure,
|
|
250
|
-
Message: "Error connecting to Data Fabric",
|
|
251
|
-
Instructions: await extractErrorMessage(clientError),
|
|
252
|
-
});
|
|
253
|
-
processContext.exit(1);
|
|
254
|
-
return;
|
|
255
|
-
}
|
|
235
|
+
const sdk = await connectOrFail(options.tenant);
|
|
236
|
+
if (!sdk) return;
|
|
256
237
|
|
|
257
238
|
const [listError, result] = await catchError(
|
|
258
239
|
sdk.entities.getAllRecords(entityId, {
|
|
@@ -265,42 +246,16 @@ export const registerRecordsCommand = (program: Command) => {
|
|
|
265
246
|
);
|
|
266
247
|
|
|
267
248
|
if (listError) {
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
});
|
|
273
|
-
processContext.exit(1);
|
|
274
|
-
return;
|
|
249
|
+
return fail(
|
|
250
|
+
"Error listing records",
|
|
251
|
+
await extractErrorMessage(listError),
|
|
252
|
+
);
|
|
275
253
|
}
|
|
276
254
|
|
|
277
|
-
const r = result as {
|
|
278
|
-
items: unknown[];
|
|
279
|
-
totalCount?: number;
|
|
280
|
-
hasNextPage?: boolean;
|
|
281
|
-
nextCursor?: unknown;
|
|
282
|
-
currentPage?: number;
|
|
283
|
-
totalPages?: number;
|
|
284
|
-
};
|
|
285
|
-
const nextCursor = extractCursorValue(r.nextCursor);
|
|
286
|
-
|
|
287
255
|
OutputFormatter.success({
|
|
288
256
|
Result: RESULTS.Success,
|
|
289
257
|
Code: "RecordList",
|
|
290
|
-
Data:
|
|
291
|
-
TotalCount: r.totalCount ?? r.items.length,
|
|
292
|
-
Records: r.items,
|
|
293
|
-
HasNextPage: r.hasNextPage ?? false,
|
|
294
|
-
...(nextCursor !== undefined && {
|
|
295
|
-
NextCursor: nextCursor,
|
|
296
|
-
}),
|
|
297
|
-
...(r.currentPage !== undefined && {
|
|
298
|
-
CurrentPage: r.currentPage,
|
|
299
|
-
}),
|
|
300
|
-
...(r.totalPages !== undefined && {
|
|
301
|
-
TotalPages: r.totalPages,
|
|
302
|
-
}),
|
|
303
|
-
},
|
|
258
|
+
Data: result,
|
|
304
259
|
});
|
|
305
260
|
},
|
|
306
261
|
);
|
|
@@ -317,43 +272,25 @@ export const registerRecordsCommand = (program: Command) => {
|
|
|
317
272
|
.trackedAction(
|
|
318
273
|
processContext,
|
|
319
274
|
async (entityId: string, recordId: string, options: GetOptions) => {
|
|
320
|
-
const
|
|
321
|
-
|
|
322
|
-
);
|
|
323
|
-
|
|
324
|
-
if (clientError) {
|
|
325
|
-
OutputFormatter.error({
|
|
326
|
-
Result: RESULTS.Failure,
|
|
327
|
-
Message: "Error connecting to Data Fabric",
|
|
328
|
-
Instructions: await extractErrorMessage(clientError),
|
|
329
|
-
});
|
|
330
|
-
processContext.exit(1);
|
|
331
|
-
return;
|
|
332
|
-
}
|
|
275
|
+
const sdk = await connectOrFail(options.tenant);
|
|
276
|
+
if (!sdk) return;
|
|
333
277
|
|
|
334
278
|
const [getError, record] = await catchError(
|
|
335
279
|
sdk.entities.getRecordById(entityId, recordId),
|
|
336
280
|
);
|
|
337
281
|
|
|
338
282
|
if (getError) {
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
});
|
|
344
|
-
processContext.exit(1);
|
|
345
|
-
return;
|
|
283
|
+
return fail(
|
|
284
|
+
`Error getting record '${recordId}'`,
|
|
285
|
+
await extractErrorMessage(getError),
|
|
286
|
+
);
|
|
346
287
|
}
|
|
347
288
|
|
|
348
289
|
if (!record) {
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
"Verify the record ID exists. Use 'df records list' to see available records.",
|
|
354
|
-
});
|
|
355
|
-
processContext.exit(1);
|
|
356
|
-
return;
|
|
290
|
+
return fail(
|
|
291
|
+
`Record '${recordId}' not found in entity '${entityId}'`,
|
|
292
|
+
"Verify the record ID exists. Use 'df records list' to see available records.",
|
|
293
|
+
);
|
|
357
294
|
}
|
|
358
295
|
|
|
359
296
|
OutputFormatter.success({
|
|
@@ -377,7 +314,7 @@ export const registerRecordsCommand = (program: Command) => {
|
|
|
377
314
|
)
|
|
378
315
|
.option(
|
|
379
316
|
"--body <json>",
|
|
380
|
-
"Inline JSON record data (object or array of objects)",
|
|
317
|
+
"Inline JSON record data (object or array of objects; use `-` to read from stdin)",
|
|
381
318
|
)
|
|
382
319
|
.examples(RECORDS_INSERT_EXAMPLES)
|
|
383
320
|
.trackedAction(
|
|
@@ -388,28 +325,11 @@ export const registerRecordsCommand = (program: Command) => {
|
|
|
388
325
|
);
|
|
389
326
|
|
|
390
327
|
if (parseError) {
|
|
391
|
-
|
|
392
|
-
Result: RESULTS.Failure,
|
|
393
|
-
Message: "Error parsing input data",
|
|
394
|
-
Instructions: parseError.message,
|
|
395
|
-
});
|
|
396
|
-
processContext.exit(1);
|
|
397
|
-
return;
|
|
328
|
+
return fail("Error parsing input data", parseError.message);
|
|
398
329
|
}
|
|
399
330
|
|
|
400
|
-
const
|
|
401
|
-
|
|
402
|
-
);
|
|
403
|
-
|
|
404
|
-
if (clientError) {
|
|
405
|
-
OutputFormatter.error({
|
|
406
|
-
Result: RESULTS.Failure,
|
|
407
|
-
Message: "Error connecting to Data Fabric",
|
|
408
|
-
Instructions: await extractErrorMessage(clientError),
|
|
409
|
-
});
|
|
410
|
-
processContext.exit(1);
|
|
411
|
-
return;
|
|
412
|
-
}
|
|
331
|
+
const sdk = await connectOrFail(options.tenant);
|
|
332
|
+
if (!sdk) return;
|
|
413
333
|
|
|
414
334
|
const data = rawData as
|
|
415
335
|
| Record<string, unknown>
|
|
@@ -422,14 +342,10 @@ export const registerRecordsCommand = (program: Command) => {
|
|
|
422
342
|
);
|
|
423
343
|
|
|
424
344
|
if (insertError) {
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
await extractErrorMessage(insertError),
|
|
430
|
-
});
|
|
431
|
-
processContext.exit(1);
|
|
432
|
-
return;
|
|
345
|
+
return fail(
|
|
346
|
+
"Error inserting record",
|
|
347
|
+
await extractErrorMessage(insertError),
|
|
348
|
+
);
|
|
433
349
|
}
|
|
434
350
|
|
|
435
351
|
OutputFormatter.success({
|
|
@@ -443,14 +359,10 @@ export const registerRecordsCommand = (program: Command) => {
|
|
|
443
359
|
);
|
|
444
360
|
|
|
445
361
|
if (insertError) {
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
await extractErrorMessage(insertError),
|
|
451
|
-
});
|
|
452
|
-
processContext.exit(1);
|
|
453
|
-
return;
|
|
362
|
+
return fail(
|
|
363
|
+
"Error inserting records",
|
|
364
|
+
await extractErrorMessage(insertError),
|
|
365
|
+
);
|
|
454
366
|
}
|
|
455
367
|
|
|
456
368
|
const r = result as BatchResult;
|
|
@@ -485,7 +397,7 @@ export const registerRecordsCommand = (program: Command) => {
|
|
|
485
397
|
)
|
|
486
398
|
.option(
|
|
487
399
|
"--body <json>",
|
|
488
|
-
"Inline JSON record data (must include Id field)",
|
|
400
|
+
"Inline JSON record data (must include Id field; use `-` to read from stdin)",
|
|
489
401
|
)
|
|
490
402
|
.examples(RECORDS_UPDATE_EXAMPLES)
|
|
491
403
|
.trackedAction(
|
|
@@ -496,28 +408,11 @@ export const registerRecordsCommand = (program: Command) => {
|
|
|
496
408
|
);
|
|
497
409
|
|
|
498
410
|
if (parseError) {
|
|
499
|
-
|
|
500
|
-
Result: RESULTS.Failure,
|
|
501
|
-
Message: "Error parsing input data",
|
|
502
|
-
Instructions: parseError.message,
|
|
503
|
-
});
|
|
504
|
-
processContext.exit(1);
|
|
505
|
-
return;
|
|
411
|
+
return fail("Error parsing input data", parseError.message);
|
|
506
412
|
}
|
|
507
413
|
|
|
508
|
-
const
|
|
509
|
-
|
|
510
|
-
);
|
|
511
|
-
|
|
512
|
-
if (clientError) {
|
|
513
|
-
OutputFormatter.error({
|
|
514
|
-
Result: RESULTS.Failure,
|
|
515
|
-
Message: "Error connecting to Data Fabric",
|
|
516
|
-
Instructions: await extractErrorMessage(clientError),
|
|
517
|
-
});
|
|
518
|
-
processContext.exit(1);
|
|
519
|
-
return;
|
|
520
|
-
}
|
|
414
|
+
const sdk = await connectOrFail(options.tenant);
|
|
415
|
+
if (!sdk) return;
|
|
521
416
|
|
|
522
417
|
const data = rawData as
|
|
523
418
|
| Record<string, unknown>
|
|
@@ -529,14 +424,10 @@ export const registerRecordsCommand = (program: Command) => {
|
|
|
529
424
|
const recordId =
|
|
530
425
|
record.Id !== undefined ? record.Id : record.id;
|
|
531
426
|
if (recordId === undefined || recordId === null) {
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
"Provide the record ID in the JSON data.",
|
|
537
|
-
});
|
|
538
|
-
processContext.exit(1);
|
|
539
|
-
return;
|
|
427
|
+
return fail(
|
|
428
|
+
"Record must include an 'Id' field",
|
|
429
|
+
"Provide the record ID in the JSON data.",
|
|
430
|
+
);
|
|
540
431
|
}
|
|
541
432
|
|
|
542
433
|
const [updateError, result] = await catchError(
|
|
@@ -548,14 +439,10 @@ export const registerRecordsCommand = (program: Command) => {
|
|
|
548
439
|
);
|
|
549
440
|
|
|
550
441
|
if (updateError) {
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
await extractErrorMessage(updateError),
|
|
556
|
-
});
|
|
557
|
-
processContext.exit(1);
|
|
558
|
-
return;
|
|
442
|
+
return fail(
|
|
443
|
+
"Error updating record",
|
|
444
|
+
await extractErrorMessage(updateError),
|
|
445
|
+
);
|
|
559
446
|
}
|
|
560
447
|
|
|
561
448
|
OutputFormatter.success({
|
|
@@ -568,14 +455,10 @@ export const registerRecordsCommand = (program: Command) => {
|
|
|
568
455
|
(r) => r.Id == null && r.id == null,
|
|
569
456
|
);
|
|
570
457
|
if (missingId) {
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
"Provide the record ID in each JSON object.",
|
|
576
|
-
});
|
|
577
|
-
processContext.exit(1);
|
|
578
|
-
return;
|
|
458
|
+
return fail(
|
|
459
|
+
"All records must include an 'Id' field",
|
|
460
|
+
"Provide the record ID in each JSON object.",
|
|
461
|
+
);
|
|
579
462
|
}
|
|
580
463
|
|
|
581
464
|
const [updateError, result] = await catchError(
|
|
@@ -586,14 +469,10 @@ export const registerRecordsCommand = (program: Command) => {
|
|
|
586
469
|
);
|
|
587
470
|
|
|
588
471
|
if (updateError) {
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
await extractErrorMessage(updateError),
|
|
594
|
-
});
|
|
595
|
-
processContext.exit(1);
|
|
596
|
-
return;
|
|
472
|
+
return fail(
|
|
473
|
+
"Error updating records",
|
|
474
|
+
await extractErrorMessage(updateError),
|
|
475
|
+
);
|
|
597
476
|
}
|
|
598
477
|
|
|
599
478
|
const r = result as BatchResult;
|
|
@@ -633,7 +512,7 @@ export const registerRecordsCommand = (program: Command) => {
|
|
|
633
512
|
)
|
|
634
513
|
.option(
|
|
635
514
|
"--body <json>",
|
|
636
|
-
"Inline JSON query options (filterGroup, selectedFields, sortOptions, aggregates, groupBy)",
|
|
515
|
+
"Inline JSON query options (filterGroup, selectedFields, sortOptions, aggregates, groupBy; use `-` to read from stdin)",
|
|
637
516
|
)
|
|
638
517
|
.option(
|
|
639
518
|
"-l, --limit <number>",
|
|
@@ -653,41 +532,30 @@ export const registerRecordsCommand = (program: Command) => {
|
|
|
653
532
|
async (entityId: string, options: QueryOptions) => {
|
|
654
533
|
const pageSize = Number(options.limit);
|
|
655
534
|
if (Number.isNaN(pageSize) || pageSize < 1) {
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
});
|
|
661
|
-
processContext.exit(1);
|
|
662
|
-
return;
|
|
535
|
+
return fail(
|
|
536
|
+
"Invalid --limit value",
|
|
537
|
+
"Provide a positive integer for --limit.",
|
|
538
|
+
);
|
|
663
539
|
}
|
|
664
540
|
|
|
665
541
|
if (
|
|
666
542
|
options.cursor !== undefined &&
|
|
667
543
|
options.offset !== undefined
|
|
668
544
|
) {
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
"Use --offset to jump to a position by record count, or --cursor to continue from a previous response.",
|
|
674
|
-
});
|
|
675
|
-
processContext.exit(1);
|
|
676
|
-
return;
|
|
545
|
+
return fail(
|
|
546
|
+
"--offset and --cursor are mutually exclusive",
|
|
547
|
+
"Use --offset to jump to a position by record count, or --cursor to continue from a previous response.",
|
|
548
|
+
);
|
|
677
549
|
}
|
|
678
550
|
|
|
679
551
|
let jumpToPage: number | undefined;
|
|
680
552
|
if (options.offset !== undefined) {
|
|
681
553
|
const offsetValue = Number(options.offset);
|
|
682
554
|
if (Number.isNaN(offsetValue) || offsetValue < 0) {
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
"Provide a non-negative integer for --offset.",
|
|
688
|
-
});
|
|
689
|
-
processContext.exit(1);
|
|
690
|
-
return;
|
|
555
|
+
return fail(
|
|
556
|
+
"Invalid --offset value",
|
|
557
|
+
"Provide a non-negative integer for --offset.",
|
|
558
|
+
);
|
|
691
559
|
}
|
|
692
560
|
jumpToPage = Math.floor(offsetValue / pageSize) + 1;
|
|
693
561
|
}
|
|
@@ -702,44 +570,26 @@ export const registerRecordsCommand = (program: Command) => {
|
|
|
702
570
|
),
|
|
703
571
|
);
|
|
704
572
|
if (parseError) {
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
});
|
|
710
|
-
processContext.exit(1);
|
|
711
|
-
return;
|
|
573
|
+
return fail(
|
|
574
|
+
"Error parsing query options",
|
|
575
|
+
parseError.message,
|
|
576
|
+
);
|
|
712
577
|
}
|
|
713
578
|
if (
|
|
714
579
|
typeof parsed !== "object" ||
|
|
715
580
|
parsed === null ||
|
|
716
581
|
Array.isArray(parsed)
|
|
717
582
|
) {
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
"Provide a JSON object (not an array) with filterGroup, selectedFields, sortOptions, aggregates, or groupBy.",
|
|
723
|
-
});
|
|
724
|
-
processContext.exit(1);
|
|
725
|
-
return;
|
|
583
|
+
return fail(
|
|
584
|
+
"Query options must be a JSON object",
|
|
585
|
+
"Provide a JSON object (not an array) with filterGroup, selectedFields, sortOptions, aggregates, or groupBy.",
|
|
586
|
+
);
|
|
726
587
|
}
|
|
727
588
|
queryBody = parsed as Record<string, unknown>;
|
|
728
589
|
}
|
|
729
590
|
|
|
730
|
-
const
|
|
731
|
-
|
|
732
|
-
);
|
|
733
|
-
|
|
734
|
-
if (clientError) {
|
|
735
|
-
OutputFormatter.error({
|
|
736
|
-
Result: RESULTS.Failure,
|
|
737
|
-
Message: "Error connecting to Data Fabric",
|
|
738
|
-
Instructions: await extractErrorMessage(clientError),
|
|
739
|
-
});
|
|
740
|
-
processContext.exit(1);
|
|
741
|
-
return;
|
|
742
|
-
}
|
|
591
|
+
const sdk = await connectOrFail(options.tenant);
|
|
592
|
+
if (!sdk) return;
|
|
743
593
|
|
|
744
594
|
const [queryError, result] = await catchError(
|
|
745
595
|
sdk.entities.queryRecordsById(entityId, {
|
|
@@ -753,42 +603,16 @@ export const registerRecordsCommand = (program: Command) => {
|
|
|
753
603
|
);
|
|
754
604
|
|
|
755
605
|
if (queryError) {
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
});
|
|
761
|
-
processContext.exit(1);
|
|
762
|
-
return;
|
|
606
|
+
return fail(
|
|
607
|
+
"Error querying records",
|
|
608
|
+
await extractErrorMessage(queryError),
|
|
609
|
+
);
|
|
763
610
|
}
|
|
764
611
|
|
|
765
|
-
const r = result as {
|
|
766
|
-
items: unknown[];
|
|
767
|
-
totalCount?: number;
|
|
768
|
-
hasNextPage?: boolean;
|
|
769
|
-
nextCursor?: unknown;
|
|
770
|
-
currentPage?: number;
|
|
771
|
-
totalPages?: number;
|
|
772
|
-
};
|
|
773
|
-
const nextCursor = extractCursorValue(r.nextCursor);
|
|
774
|
-
|
|
775
612
|
OutputFormatter.success({
|
|
776
613
|
Result: RESULTS.Success,
|
|
777
614
|
Code: "RecordQuery",
|
|
778
|
-
Data:
|
|
779
|
-
TotalCount: r.totalCount ?? r.items.length,
|
|
780
|
-
Records: r.items,
|
|
781
|
-
HasNextPage: r.hasNextPage ?? false,
|
|
782
|
-
...(nextCursor !== undefined && {
|
|
783
|
-
NextCursor: nextCursor,
|
|
784
|
-
}),
|
|
785
|
-
...(r.currentPage !== undefined && {
|
|
786
|
-
CurrentPage: r.currentPage,
|
|
787
|
-
}),
|
|
788
|
-
...(r.totalPages !== undefined && {
|
|
789
|
-
TotalPages: r.totalPages,
|
|
790
|
-
}),
|
|
791
|
-
},
|
|
615
|
+
Data: result,
|
|
792
616
|
});
|
|
793
617
|
},
|
|
794
618
|
);
|
|
@@ -805,13 +629,10 @@ export const registerRecordsCommand = (program: Command) => {
|
|
|
805
629
|
processContext,
|
|
806
630
|
async (entityId: string, options: ImportOptions) => {
|
|
807
631
|
if (options.file === undefined) {
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
});
|
|
813
|
-
processContext.exit(1);
|
|
814
|
-
return;
|
|
632
|
+
return fail(
|
|
633
|
+
"A CSV file path is required",
|
|
634
|
+
"Provide a CSV file path via --file.",
|
|
635
|
+
);
|
|
815
636
|
}
|
|
816
637
|
|
|
817
638
|
const [readError, fileContent] = await catchError(
|
|
@@ -819,28 +640,11 @@ export const registerRecordsCommand = (program: Command) => {
|
|
|
819
640
|
);
|
|
820
641
|
|
|
821
642
|
if (readError) {
|
|
822
|
-
|
|
823
|
-
Result: RESULTS.Failure,
|
|
824
|
-
Message: "Error reading CSV file",
|
|
825
|
-
Instructions: readError.message,
|
|
826
|
-
});
|
|
827
|
-
processContext.exit(1);
|
|
828
|
-
return;
|
|
643
|
+
return fail("Error reading CSV file", readError.message);
|
|
829
644
|
}
|
|
830
645
|
|
|
831
|
-
const
|
|
832
|
-
|
|
833
|
-
);
|
|
834
|
-
|
|
835
|
-
if (clientError) {
|
|
836
|
-
OutputFormatter.error({
|
|
837
|
-
Result: RESULTS.Failure,
|
|
838
|
-
Message: "Error connecting to Data Fabric",
|
|
839
|
-
Instructions: await extractErrorMessage(clientError),
|
|
840
|
-
});
|
|
841
|
-
processContext.exit(1);
|
|
842
|
-
return;
|
|
843
|
-
}
|
|
646
|
+
const sdk = await connectOrFail(options.tenant);
|
|
647
|
+
if (!sdk) return;
|
|
844
648
|
|
|
845
649
|
const fs = getFileSystem();
|
|
846
650
|
const fileName = fs.path.basename(options.file) || "import.csv";
|
|
@@ -854,13 +658,10 @@ export const registerRecordsCommand = (program: Command) => {
|
|
|
854
658
|
);
|
|
855
659
|
|
|
856
660
|
if (importError) {
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
});
|
|
862
|
-
processContext.exit(1);
|
|
863
|
-
return;
|
|
661
|
+
return fail(
|
|
662
|
+
"Error importing records",
|
|
663
|
+
await extractErrorMessage(importError),
|
|
664
|
+
);
|
|
864
665
|
}
|
|
865
666
|
|
|
866
667
|
const r = result as {
|
|
@@ -891,6 +692,14 @@ export const registerRecordsCommand = (program: Command) => {
|
|
|
891
692
|
.addOption(
|
|
892
693
|
createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>"),
|
|
893
694
|
)
|
|
695
|
+
.option("-y, --yes", "Acknowledge this is an irreversible operation")
|
|
696
|
+
.addOption(
|
|
697
|
+
new Option("--confirm", "Deprecated alias for --yes").hideHelp(),
|
|
698
|
+
)
|
|
699
|
+
.option(
|
|
700
|
+
"--reason <reason>",
|
|
701
|
+
"Reason for the deletion — echoed back in the response so the caller can log it",
|
|
702
|
+
)
|
|
894
703
|
.examples(RECORDS_DELETE_EXAMPLES)
|
|
895
704
|
.trackedAction(
|
|
896
705
|
processContext,
|
|
@@ -899,32 +708,25 @@ export const registerRecordsCommand = (program: Command) => {
|
|
|
899
708
|
recordIds: string[],
|
|
900
709
|
options: DeleteOptions,
|
|
901
710
|
) => {
|
|
902
|
-
const
|
|
903
|
-
|
|
711
|
+
const reason = requireDestructiveConfirmation(
|
|
712
|
+
options,
|
|
713
|
+
`delete ${recordIds.length} record(s) from entity '${entityId}'`,
|
|
714
|
+
'Pass --reason "<text>" to record why the records are being deleted.',
|
|
904
715
|
);
|
|
716
|
+
if (reason === null) return;
|
|
905
717
|
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
Result: RESULTS.Failure,
|
|
909
|
-
Message: "Error connecting to Data Fabric",
|
|
910
|
-
Instructions: await extractErrorMessage(clientError),
|
|
911
|
-
});
|
|
912
|
-
processContext.exit(1);
|
|
913
|
-
return;
|
|
914
|
-
}
|
|
718
|
+
const sdk = await connectOrFail(options.tenant);
|
|
719
|
+
if (!sdk) return;
|
|
915
720
|
|
|
916
721
|
const [deleteError, result] = await catchError(
|
|
917
722
|
sdk.entities.deleteRecordsById(entityId, recordIds),
|
|
918
723
|
);
|
|
919
724
|
|
|
920
725
|
if (deleteError) {
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
});
|
|
926
|
-
processContext.exit(1);
|
|
927
|
-
return;
|
|
726
|
+
return fail(
|
|
727
|
+
"Error deleting records",
|
|
728
|
+
await extractErrorMessage(deleteError),
|
|
729
|
+
);
|
|
928
730
|
}
|
|
929
731
|
|
|
930
732
|
const r = result as BatchResult;
|
|
@@ -937,6 +739,7 @@ export const registerRecordsCommand = (program: Command) => {
|
|
|
937
739
|
FailureCount: failureCount,
|
|
938
740
|
SuccessRecords: r.successRecords ?? [],
|
|
939
741
|
FailureRecords: r.failureRecords ?? [],
|
|
742
|
+
Reason: reason,
|
|
940
743
|
},
|
|
941
744
|
});
|
|
942
745
|
if (failureCount > 0) {
|