@uipath/data-fabric-tool 1.0.4 → 1.195.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/browser.json +3 -0
- package/dist/index.js +20 -43167
- package/dist/tool.js +29174 -28399
- package/package.json +16 -32
- package/src/commands/choice-sets.spec.ts +849 -0
- package/src/commands/choice-sets.ts +690 -0
- package/src/commands/entities.spec.ts +411 -137
- package/src/commands/entities.ts +189 -368
- package/src/commands/files.spec.ts +18 -32
- package/src/commands/files.ts +43 -92
- package/src/commands/records.spec.ts +171 -207
- package/src/commands/records.ts +150 -342
- package/src/index.ts +5 -10
- package/src/tool.ts +6 -0
- package/src/utils/output.spec.ts +78 -0
- package/src/utils/output.ts +51 -0
- package/src/utils/sdk-client.spec.ts +59 -0
- package/src/utils/sdk-client.ts +23 -0
package/src/commands/records.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
type CommandExample,
|
|
3
3
|
catchError,
|
|
4
|
+
createHiddenDeprecatedTenantOption,
|
|
4
5
|
extractErrorMessage,
|
|
5
6
|
OutputFormatter,
|
|
6
7
|
processContext,
|
|
@@ -10,7 +11,8 @@ import { getFileSystem } from "@uipath/filesystem";
|
|
|
10
11
|
import type { EntityRecord } from "@uipath/uipath-typescript";
|
|
11
12
|
import type { Command } from "commander";
|
|
12
13
|
import { readFileBinary, readJsonInput } from "../utils/input";
|
|
13
|
-
import {
|
|
14
|
+
import { fail } from "../utils/output";
|
|
15
|
+
import { connectOrFail } from "../utils/sdk-client";
|
|
14
16
|
|
|
15
17
|
interface ListOptions {
|
|
16
18
|
tenant?: string;
|
|
@@ -60,14 +62,13 @@ interface BatchResult {
|
|
|
60
62
|
|
|
61
63
|
const RECORDS_LIST_EXAMPLES: CommandExample[] = [
|
|
62
64
|
{
|
|
63
|
-
Description: "List records in an entity",
|
|
65
|
+
Description: "List records in an entity.",
|
|
64
66
|
Command:
|
|
65
67
|
"uip df records list a1b2c3d4-0000-0000-0000-000000000001 --limit 2",
|
|
66
68
|
Output: {
|
|
67
69
|
Code: "RecordList",
|
|
68
70
|
Data: {
|
|
69
|
-
|
|
70
|
-
Records: [
|
|
71
|
+
items: [
|
|
71
72
|
{
|
|
72
73
|
Id: "b2c3d4e5-0000-0000-0000-000000000001",
|
|
73
74
|
amount: 1500,
|
|
@@ -77,7 +78,8 @@ const RECORDS_LIST_EXAMPLES: CommandExample[] = [
|
|
|
77
78
|
amount: 2750,
|
|
78
79
|
},
|
|
79
80
|
],
|
|
80
|
-
|
|
81
|
+
totalCount: 2,
|
|
82
|
+
hasNextPage: false,
|
|
81
83
|
},
|
|
82
84
|
},
|
|
83
85
|
},
|
|
@@ -113,6 +115,25 @@ const RECORDS_INSERT_EXAMPLES: CommandExample[] = [
|
|
|
113
115
|
},
|
|
114
116
|
},
|
|
115
117
|
},
|
|
118
|
+
{
|
|
119
|
+
Description:
|
|
120
|
+
"Insert a record into an entity that has choice-set and relationship fields. " +
|
|
121
|
+
"CHOICE_SET_SINGLE → pass the choice value's 'numberId' (integer, NOT the name string — look it up via 'df choice-sets list-values <id>'). " +
|
|
122
|
+
"CHOICE_SET_MULTIPLE → pass an array of numberId integers. " +
|
|
123
|
+
"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
|
+
Command:
|
|
125
|
+
'uip df records insert a1b2c3d4-0000-0000-0000-000000000004 --body \'{"category":0,"tags":[1,3],"submitter":"e1f2a3b4-0000-0000-0000-000000000001","amount":250}\'',
|
|
126
|
+
Output: {
|
|
127
|
+
Code: "RecordInserted",
|
|
128
|
+
Data: {
|
|
129
|
+
Id: "b2c3d4e5-0000-0000-0000-000000000020",
|
|
130
|
+
category: 0,
|
|
131
|
+
tags: [1, 3],
|
|
132
|
+
submitter: "e1f2a3b4-0000-0000-0000-000000000001",
|
|
133
|
+
amount: 250,
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
},
|
|
116
137
|
];
|
|
117
138
|
|
|
118
139
|
const RECORDS_UPDATE_EXAMPLES: CommandExample[] = [
|
|
@@ -158,7 +179,9 @@ export const registerRecordsCommand = (program: Command) => {
|
|
|
158
179
|
.command("list")
|
|
159
180
|
.description("List records in a Data Fabric entity")
|
|
160
181
|
.argument("<id>", "Entity ID")
|
|
161
|
-
.
|
|
182
|
+
.addOption(
|
|
183
|
+
createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>"),
|
|
184
|
+
)
|
|
162
185
|
.option(
|
|
163
186
|
"-l, --limit <number>",
|
|
164
187
|
"Number of records to return per page",
|
|
@@ -178,58 +201,36 @@ export const registerRecordsCommand = (program: Command) => {
|
|
|
178
201
|
async (entityId: string, options: ListOptions) => {
|
|
179
202
|
const pageSize = Number(options.limit);
|
|
180
203
|
if (Number.isNaN(pageSize) || pageSize < 1) {
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
});
|
|
186
|
-
processContext.exit(1);
|
|
187
|
-
return;
|
|
204
|
+
return fail(
|
|
205
|
+
"Invalid --limit value",
|
|
206
|
+
"Provide a positive integer for --limit.",
|
|
207
|
+
);
|
|
188
208
|
}
|
|
189
209
|
|
|
190
210
|
if (
|
|
191
211
|
options.cursor !== undefined &&
|
|
192
212
|
options.offset !== undefined
|
|
193
213
|
) {
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
"Use --offset to jump to a position by record count, or --cursor to continue from a previous response.",
|
|
199
|
-
});
|
|
200
|
-
processContext.exit(1);
|
|
201
|
-
return;
|
|
214
|
+
return fail(
|
|
215
|
+
"--offset and --cursor are mutually exclusive",
|
|
216
|
+
"Use --offset to jump to a position by record count, or --cursor to continue from a previous response.",
|
|
217
|
+
);
|
|
202
218
|
}
|
|
203
219
|
|
|
204
220
|
let jumpToPage: number | undefined;
|
|
205
221
|
if (options.offset !== undefined) {
|
|
206
222
|
const offsetValue = Number(options.offset);
|
|
207
223
|
if (Number.isNaN(offsetValue) || offsetValue < 0) {
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
"Provide a non-negative integer for --offset.",
|
|
213
|
-
});
|
|
214
|
-
processContext.exit(1);
|
|
215
|
-
return;
|
|
224
|
+
return fail(
|
|
225
|
+
"Invalid --offset value",
|
|
226
|
+
"Provide a non-negative integer for --offset.",
|
|
227
|
+
);
|
|
216
228
|
}
|
|
217
229
|
jumpToPage = Math.floor(offsetValue / pageSize) + 1;
|
|
218
230
|
}
|
|
219
231
|
|
|
220
|
-
const
|
|
221
|
-
|
|
222
|
-
);
|
|
223
|
-
|
|
224
|
-
if (clientError) {
|
|
225
|
-
OutputFormatter.error({
|
|
226
|
-
Result: RESULTS.Failure,
|
|
227
|
-
Message: "Error connecting to Data Fabric",
|
|
228
|
-
Instructions: await extractErrorMessage(clientError),
|
|
229
|
-
});
|
|
230
|
-
processContext.exit(1);
|
|
231
|
-
return;
|
|
232
|
-
}
|
|
232
|
+
const sdk = await connectOrFail(options.tenant);
|
|
233
|
+
if (!sdk) return;
|
|
233
234
|
|
|
234
235
|
const [listError, result] = await catchError(
|
|
235
236
|
sdk.entities.getAllRecords(entityId, {
|
|
@@ -242,42 +243,16 @@ export const registerRecordsCommand = (program: Command) => {
|
|
|
242
243
|
);
|
|
243
244
|
|
|
244
245
|
if (listError) {
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
});
|
|
250
|
-
processContext.exit(1);
|
|
251
|
-
return;
|
|
246
|
+
return fail(
|
|
247
|
+
"Error listing records",
|
|
248
|
+
await extractErrorMessage(listError),
|
|
249
|
+
);
|
|
252
250
|
}
|
|
253
251
|
|
|
254
|
-
const r = result as {
|
|
255
|
-
items: unknown[];
|
|
256
|
-
totalCount?: number;
|
|
257
|
-
hasNextPage?: boolean;
|
|
258
|
-
nextCursor?: unknown;
|
|
259
|
-
currentPage?: number;
|
|
260
|
-
totalPages?: number;
|
|
261
|
-
};
|
|
262
|
-
const nextCursor = extractCursorValue(r.nextCursor);
|
|
263
|
-
|
|
264
252
|
OutputFormatter.success({
|
|
265
253
|
Result: RESULTS.Success,
|
|
266
254
|
Code: "RecordList",
|
|
267
|
-
Data:
|
|
268
|
-
TotalCount: r.totalCount ?? r.items.length,
|
|
269
|
-
Records: r.items,
|
|
270
|
-
HasNextPage: r.hasNextPage ?? false,
|
|
271
|
-
...(nextCursor !== undefined && {
|
|
272
|
-
NextCursor: nextCursor,
|
|
273
|
-
}),
|
|
274
|
-
...(r.currentPage !== undefined && {
|
|
275
|
-
CurrentPage: r.currentPage,
|
|
276
|
-
}),
|
|
277
|
-
...(r.totalPages !== undefined && {
|
|
278
|
-
TotalPages: r.totalPages,
|
|
279
|
-
}),
|
|
280
|
-
},
|
|
255
|
+
Data: result,
|
|
281
256
|
});
|
|
282
257
|
},
|
|
283
258
|
);
|
|
@@ -287,48 +262,32 @@ export const registerRecordsCommand = (program: Command) => {
|
|
|
287
262
|
.description("Get a single record by ID")
|
|
288
263
|
.argument("<id>", "Entity ID")
|
|
289
264
|
.argument("<key>", "Record ID")
|
|
290
|
-
.
|
|
265
|
+
.addOption(
|
|
266
|
+
createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>"),
|
|
267
|
+
)
|
|
291
268
|
.examples(RECORDS_GET_EXAMPLES)
|
|
292
269
|
.trackedAction(
|
|
293
270
|
processContext,
|
|
294
271
|
async (entityId: string, recordId: string, options: GetOptions) => {
|
|
295
|
-
const
|
|
296
|
-
|
|
297
|
-
);
|
|
298
|
-
|
|
299
|
-
if (clientError) {
|
|
300
|
-
OutputFormatter.error({
|
|
301
|
-
Result: RESULTS.Failure,
|
|
302
|
-
Message: "Error connecting to Data Fabric",
|
|
303
|
-
Instructions: await extractErrorMessage(clientError),
|
|
304
|
-
});
|
|
305
|
-
processContext.exit(1);
|
|
306
|
-
return;
|
|
307
|
-
}
|
|
272
|
+
const sdk = await connectOrFail(options.tenant);
|
|
273
|
+
if (!sdk) return;
|
|
308
274
|
|
|
309
275
|
const [getError, record] = await catchError(
|
|
310
276
|
sdk.entities.getRecordById(entityId, recordId),
|
|
311
277
|
);
|
|
312
278
|
|
|
313
279
|
if (getError) {
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
});
|
|
319
|
-
processContext.exit(1);
|
|
320
|
-
return;
|
|
280
|
+
return fail(
|
|
281
|
+
`Error getting record '${recordId}'`,
|
|
282
|
+
await extractErrorMessage(getError),
|
|
283
|
+
);
|
|
321
284
|
}
|
|
322
285
|
|
|
323
286
|
if (!record) {
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
"Verify the record ID exists. Use 'df records list' to see available records.",
|
|
329
|
-
});
|
|
330
|
-
processContext.exit(1);
|
|
331
|
-
return;
|
|
287
|
+
return fail(
|
|
288
|
+
`Record '${recordId}' not found in entity '${entityId}'`,
|
|
289
|
+
"Verify the record ID exists. Use 'df records list' to see available records.",
|
|
290
|
+
);
|
|
332
291
|
}
|
|
333
292
|
|
|
334
293
|
OutputFormatter.success({
|
|
@@ -343,7 +302,9 @@ export const registerRecordsCommand = (program: Command) => {
|
|
|
343
302
|
.command("insert")
|
|
344
303
|
.description("Insert records into a Data Fabric entity")
|
|
345
304
|
.argument("<id>", "Entity ID")
|
|
346
|
-
.
|
|
305
|
+
.addOption(
|
|
306
|
+
createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>"),
|
|
307
|
+
)
|
|
347
308
|
.option(
|
|
348
309
|
"-f, --file <path>",
|
|
349
310
|
"Path to JSON file with record data (object or array of objects)",
|
|
@@ -361,28 +322,11 @@ export const registerRecordsCommand = (program: Command) => {
|
|
|
361
322
|
);
|
|
362
323
|
|
|
363
324
|
if (parseError) {
|
|
364
|
-
|
|
365
|
-
Result: RESULTS.Failure,
|
|
366
|
-
Message: "Error parsing input data",
|
|
367
|
-
Instructions: parseError.message,
|
|
368
|
-
});
|
|
369
|
-
processContext.exit(1);
|
|
370
|
-
return;
|
|
325
|
+
return fail("Error parsing input data", parseError.message);
|
|
371
326
|
}
|
|
372
327
|
|
|
373
|
-
const
|
|
374
|
-
|
|
375
|
-
);
|
|
376
|
-
|
|
377
|
-
if (clientError) {
|
|
378
|
-
OutputFormatter.error({
|
|
379
|
-
Result: RESULTS.Failure,
|
|
380
|
-
Message: "Error connecting to Data Fabric",
|
|
381
|
-
Instructions: await extractErrorMessage(clientError),
|
|
382
|
-
});
|
|
383
|
-
processContext.exit(1);
|
|
384
|
-
return;
|
|
385
|
-
}
|
|
328
|
+
const sdk = await connectOrFail(options.tenant);
|
|
329
|
+
if (!sdk) return;
|
|
386
330
|
|
|
387
331
|
const data = rawData as
|
|
388
332
|
| Record<string, unknown>
|
|
@@ -395,14 +339,10 @@ export const registerRecordsCommand = (program: Command) => {
|
|
|
395
339
|
);
|
|
396
340
|
|
|
397
341
|
if (insertError) {
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
await extractErrorMessage(insertError),
|
|
403
|
-
});
|
|
404
|
-
processContext.exit(1);
|
|
405
|
-
return;
|
|
342
|
+
return fail(
|
|
343
|
+
"Error inserting record",
|
|
344
|
+
await extractErrorMessage(insertError),
|
|
345
|
+
);
|
|
406
346
|
}
|
|
407
347
|
|
|
408
348
|
OutputFormatter.success({
|
|
@@ -416,14 +356,10 @@ export const registerRecordsCommand = (program: Command) => {
|
|
|
416
356
|
);
|
|
417
357
|
|
|
418
358
|
if (insertError) {
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
await extractErrorMessage(insertError),
|
|
424
|
-
});
|
|
425
|
-
processContext.exit(1);
|
|
426
|
-
return;
|
|
359
|
+
return fail(
|
|
360
|
+
"Error inserting records",
|
|
361
|
+
await extractErrorMessage(insertError),
|
|
362
|
+
);
|
|
427
363
|
}
|
|
428
364
|
|
|
429
365
|
const r = result as BatchResult;
|
|
@@ -449,7 +385,9 @@ export const registerRecordsCommand = (program: Command) => {
|
|
|
449
385
|
.command("update")
|
|
450
386
|
.description("Update records in a Data Fabric entity")
|
|
451
387
|
.argument("<id>", "Entity ID")
|
|
452
|
-
.
|
|
388
|
+
.addOption(
|
|
389
|
+
createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>"),
|
|
390
|
+
)
|
|
453
391
|
.option(
|
|
454
392
|
"-f, --file <path>",
|
|
455
393
|
"Path to JSON file with record data (must include Id field)",
|
|
@@ -467,28 +405,11 @@ export const registerRecordsCommand = (program: Command) => {
|
|
|
467
405
|
);
|
|
468
406
|
|
|
469
407
|
if (parseError) {
|
|
470
|
-
|
|
471
|
-
Result: RESULTS.Failure,
|
|
472
|
-
Message: "Error parsing input data",
|
|
473
|
-
Instructions: parseError.message,
|
|
474
|
-
});
|
|
475
|
-
processContext.exit(1);
|
|
476
|
-
return;
|
|
408
|
+
return fail("Error parsing input data", parseError.message);
|
|
477
409
|
}
|
|
478
410
|
|
|
479
|
-
const
|
|
480
|
-
|
|
481
|
-
);
|
|
482
|
-
|
|
483
|
-
if (clientError) {
|
|
484
|
-
OutputFormatter.error({
|
|
485
|
-
Result: RESULTS.Failure,
|
|
486
|
-
Message: "Error connecting to Data Fabric",
|
|
487
|
-
Instructions: await extractErrorMessage(clientError),
|
|
488
|
-
});
|
|
489
|
-
processContext.exit(1);
|
|
490
|
-
return;
|
|
491
|
-
}
|
|
411
|
+
const sdk = await connectOrFail(options.tenant);
|
|
412
|
+
if (!sdk) return;
|
|
492
413
|
|
|
493
414
|
const data = rawData as
|
|
494
415
|
| Record<string, unknown>
|
|
@@ -500,14 +421,10 @@ export const registerRecordsCommand = (program: Command) => {
|
|
|
500
421
|
const recordId =
|
|
501
422
|
record.Id !== undefined ? record.Id : record.id;
|
|
502
423
|
if (recordId === undefined || recordId === null) {
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
"Provide the record ID in the JSON data.",
|
|
508
|
-
});
|
|
509
|
-
processContext.exit(1);
|
|
510
|
-
return;
|
|
424
|
+
return fail(
|
|
425
|
+
"Record must include an 'Id' field",
|
|
426
|
+
"Provide the record ID in the JSON data.",
|
|
427
|
+
);
|
|
511
428
|
}
|
|
512
429
|
|
|
513
430
|
const [updateError, result] = await catchError(
|
|
@@ -519,14 +436,10 @@ export const registerRecordsCommand = (program: Command) => {
|
|
|
519
436
|
);
|
|
520
437
|
|
|
521
438
|
if (updateError) {
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
await extractErrorMessage(updateError),
|
|
527
|
-
});
|
|
528
|
-
processContext.exit(1);
|
|
529
|
-
return;
|
|
439
|
+
return fail(
|
|
440
|
+
"Error updating record",
|
|
441
|
+
await extractErrorMessage(updateError),
|
|
442
|
+
);
|
|
530
443
|
}
|
|
531
444
|
|
|
532
445
|
OutputFormatter.success({
|
|
@@ -539,14 +452,10 @@ export const registerRecordsCommand = (program: Command) => {
|
|
|
539
452
|
(r) => r.Id == null && r.id == null,
|
|
540
453
|
);
|
|
541
454
|
if (missingId) {
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
"Provide the record ID in each JSON object.",
|
|
547
|
-
});
|
|
548
|
-
processContext.exit(1);
|
|
549
|
-
return;
|
|
455
|
+
return fail(
|
|
456
|
+
"All records must include an 'Id' field",
|
|
457
|
+
"Provide the record ID in each JSON object.",
|
|
458
|
+
);
|
|
550
459
|
}
|
|
551
460
|
|
|
552
461
|
const [updateError, result] = await catchError(
|
|
@@ -557,14 +466,10 @@ export const registerRecordsCommand = (program: Command) => {
|
|
|
557
466
|
);
|
|
558
467
|
|
|
559
468
|
if (updateError) {
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
await extractErrorMessage(updateError),
|
|
565
|
-
});
|
|
566
|
-
processContext.exit(1);
|
|
567
|
-
return;
|
|
469
|
+
return fail(
|
|
470
|
+
"Error updating records",
|
|
471
|
+
await extractErrorMessage(updateError),
|
|
472
|
+
);
|
|
568
473
|
}
|
|
569
474
|
|
|
570
475
|
const r = result as BatchResult;
|
|
@@ -595,7 +500,9 @@ export const registerRecordsCommand = (program: Command) => {
|
|
|
595
500
|
"aggregates (function: COUNT/SUM/AVG/MIN/MAX, field, alias?), groupBy.",
|
|
596
501
|
)
|
|
597
502
|
.argument("<id>", "Entity ID")
|
|
598
|
-
.
|
|
503
|
+
.addOption(
|
|
504
|
+
createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>"),
|
|
505
|
+
)
|
|
599
506
|
.option(
|
|
600
507
|
"-f, --file <path>",
|
|
601
508
|
"Path to JSON file with query options (filterGroup, selectedFields, sortOptions, aggregates, groupBy)",
|
|
@@ -622,41 +529,30 @@ export const registerRecordsCommand = (program: Command) => {
|
|
|
622
529
|
async (entityId: string, options: QueryOptions) => {
|
|
623
530
|
const pageSize = Number(options.limit);
|
|
624
531
|
if (Number.isNaN(pageSize) || pageSize < 1) {
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
});
|
|
630
|
-
processContext.exit(1);
|
|
631
|
-
return;
|
|
532
|
+
return fail(
|
|
533
|
+
"Invalid --limit value",
|
|
534
|
+
"Provide a positive integer for --limit.",
|
|
535
|
+
);
|
|
632
536
|
}
|
|
633
537
|
|
|
634
538
|
if (
|
|
635
539
|
options.cursor !== undefined &&
|
|
636
540
|
options.offset !== undefined
|
|
637
541
|
) {
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
"Use --offset to jump to a position by record count, or --cursor to continue from a previous response.",
|
|
643
|
-
});
|
|
644
|
-
processContext.exit(1);
|
|
645
|
-
return;
|
|
542
|
+
return fail(
|
|
543
|
+
"--offset and --cursor are mutually exclusive",
|
|
544
|
+
"Use --offset to jump to a position by record count, or --cursor to continue from a previous response.",
|
|
545
|
+
);
|
|
646
546
|
}
|
|
647
547
|
|
|
648
548
|
let jumpToPage: number | undefined;
|
|
649
549
|
if (options.offset !== undefined) {
|
|
650
550
|
const offsetValue = Number(options.offset);
|
|
651
551
|
if (Number.isNaN(offsetValue) || offsetValue < 0) {
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
"Provide a non-negative integer for --offset.",
|
|
657
|
-
});
|
|
658
|
-
processContext.exit(1);
|
|
659
|
-
return;
|
|
552
|
+
return fail(
|
|
553
|
+
"Invalid --offset value",
|
|
554
|
+
"Provide a non-negative integer for --offset.",
|
|
555
|
+
);
|
|
660
556
|
}
|
|
661
557
|
jumpToPage = Math.floor(offsetValue / pageSize) + 1;
|
|
662
558
|
}
|
|
@@ -671,44 +567,26 @@ export const registerRecordsCommand = (program: Command) => {
|
|
|
671
567
|
),
|
|
672
568
|
);
|
|
673
569
|
if (parseError) {
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
});
|
|
679
|
-
processContext.exit(1);
|
|
680
|
-
return;
|
|
570
|
+
return fail(
|
|
571
|
+
"Error parsing query options",
|
|
572
|
+
parseError.message,
|
|
573
|
+
);
|
|
681
574
|
}
|
|
682
575
|
if (
|
|
683
576
|
typeof parsed !== "object" ||
|
|
684
577
|
parsed === null ||
|
|
685
578
|
Array.isArray(parsed)
|
|
686
579
|
) {
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
"Provide a JSON object (not an array) with filterGroup, selectedFields, sortOptions, aggregates, or groupBy.",
|
|
692
|
-
});
|
|
693
|
-
processContext.exit(1);
|
|
694
|
-
return;
|
|
580
|
+
return fail(
|
|
581
|
+
"Query options must be a JSON object",
|
|
582
|
+
"Provide a JSON object (not an array) with filterGroup, selectedFields, sortOptions, aggregates, or groupBy.",
|
|
583
|
+
);
|
|
695
584
|
}
|
|
696
585
|
queryBody = parsed as Record<string, unknown>;
|
|
697
586
|
}
|
|
698
587
|
|
|
699
|
-
const
|
|
700
|
-
|
|
701
|
-
);
|
|
702
|
-
|
|
703
|
-
if (clientError) {
|
|
704
|
-
OutputFormatter.error({
|
|
705
|
-
Result: RESULTS.Failure,
|
|
706
|
-
Message: "Error connecting to Data Fabric",
|
|
707
|
-
Instructions: await extractErrorMessage(clientError),
|
|
708
|
-
});
|
|
709
|
-
processContext.exit(1);
|
|
710
|
-
return;
|
|
711
|
-
}
|
|
588
|
+
const sdk = await connectOrFail(options.tenant);
|
|
589
|
+
if (!sdk) return;
|
|
712
590
|
|
|
713
591
|
const [queryError, result] = await catchError(
|
|
714
592
|
sdk.entities.queryRecordsById(entityId, {
|
|
@@ -722,42 +600,16 @@ export const registerRecordsCommand = (program: Command) => {
|
|
|
722
600
|
);
|
|
723
601
|
|
|
724
602
|
if (queryError) {
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
});
|
|
730
|
-
processContext.exit(1);
|
|
731
|
-
return;
|
|
603
|
+
return fail(
|
|
604
|
+
"Error querying records",
|
|
605
|
+
await extractErrorMessage(queryError),
|
|
606
|
+
);
|
|
732
607
|
}
|
|
733
608
|
|
|
734
|
-
const r = result as {
|
|
735
|
-
items: unknown[];
|
|
736
|
-
totalCount?: number;
|
|
737
|
-
hasNextPage?: boolean;
|
|
738
|
-
nextCursor?: unknown;
|
|
739
|
-
currentPage?: number;
|
|
740
|
-
totalPages?: number;
|
|
741
|
-
};
|
|
742
|
-
const nextCursor = extractCursorValue(r.nextCursor);
|
|
743
|
-
|
|
744
609
|
OutputFormatter.success({
|
|
745
610
|
Result: RESULTS.Success,
|
|
746
611
|
Code: "RecordQuery",
|
|
747
|
-
Data:
|
|
748
|
-
TotalCount: r.totalCount ?? r.items.length,
|
|
749
|
-
Records: r.items,
|
|
750
|
-
HasNextPage: r.hasNextPage ?? false,
|
|
751
|
-
...(nextCursor !== undefined && {
|
|
752
|
-
NextCursor: nextCursor,
|
|
753
|
-
}),
|
|
754
|
-
...(r.currentPage !== undefined && {
|
|
755
|
-
CurrentPage: r.currentPage,
|
|
756
|
-
}),
|
|
757
|
-
...(r.totalPages !== undefined && {
|
|
758
|
-
TotalPages: r.totalPages,
|
|
759
|
-
}),
|
|
760
|
-
},
|
|
612
|
+
Data: result,
|
|
761
613
|
});
|
|
762
614
|
},
|
|
763
615
|
);
|
|
@@ -766,19 +618,18 @@ export const registerRecordsCommand = (program: Command) => {
|
|
|
766
618
|
.command("import")
|
|
767
619
|
.description("Import records from a CSV file into a Data Fabric entity")
|
|
768
620
|
.argument("<id>", "Entity ID")
|
|
769
|
-
.
|
|
621
|
+
.addOption(
|
|
622
|
+
createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>"),
|
|
623
|
+
)
|
|
770
624
|
.option("-f, --file <path>", "Path to the CSV file to import")
|
|
771
625
|
.trackedAction(
|
|
772
626
|
processContext,
|
|
773
627
|
async (entityId: string, options: ImportOptions) => {
|
|
774
628
|
if (options.file === undefined) {
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
});
|
|
780
|
-
processContext.exit(1);
|
|
781
|
-
return;
|
|
629
|
+
return fail(
|
|
630
|
+
"A CSV file path is required",
|
|
631
|
+
"Provide a CSV file path via --file.",
|
|
632
|
+
);
|
|
782
633
|
}
|
|
783
634
|
|
|
784
635
|
const [readError, fileContent] = await catchError(
|
|
@@ -786,28 +637,11 @@ export const registerRecordsCommand = (program: Command) => {
|
|
|
786
637
|
);
|
|
787
638
|
|
|
788
639
|
if (readError) {
|
|
789
|
-
|
|
790
|
-
Result: RESULTS.Failure,
|
|
791
|
-
Message: "Error reading CSV file",
|
|
792
|
-
Instructions: readError.message,
|
|
793
|
-
});
|
|
794
|
-
processContext.exit(1);
|
|
795
|
-
return;
|
|
640
|
+
return fail("Error reading CSV file", readError.message);
|
|
796
641
|
}
|
|
797
642
|
|
|
798
|
-
const
|
|
799
|
-
|
|
800
|
-
);
|
|
801
|
-
|
|
802
|
-
if (clientError) {
|
|
803
|
-
OutputFormatter.error({
|
|
804
|
-
Result: RESULTS.Failure,
|
|
805
|
-
Message: "Error connecting to Data Fabric",
|
|
806
|
-
Instructions: await extractErrorMessage(clientError),
|
|
807
|
-
});
|
|
808
|
-
processContext.exit(1);
|
|
809
|
-
return;
|
|
810
|
-
}
|
|
643
|
+
const sdk = await connectOrFail(options.tenant);
|
|
644
|
+
if (!sdk) return;
|
|
811
645
|
|
|
812
646
|
const fs = getFileSystem();
|
|
813
647
|
const fileName = fs.path.basename(options.file) || "import.csv";
|
|
@@ -821,13 +655,10 @@ export const registerRecordsCommand = (program: Command) => {
|
|
|
821
655
|
);
|
|
822
656
|
|
|
823
657
|
if (importError) {
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
});
|
|
829
|
-
processContext.exit(1);
|
|
830
|
-
return;
|
|
658
|
+
return fail(
|
|
659
|
+
"Error importing records",
|
|
660
|
+
await extractErrorMessage(importError),
|
|
661
|
+
);
|
|
831
662
|
}
|
|
832
663
|
|
|
833
664
|
const r = result as {
|
|
@@ -855,7 +686,9 @@ export const registerRecordsCommand = (program: Command) => {
|
|
|
855
686
|
.description("Delete records from a Data Fabric entity")
|
|
856
687
|
.argument("<id>", "Entity ID")
|
|
857
688
|
.argument("<key...>", "Record IDs to delete")
|
|
858
|
-
.
|
|
689
|
+
.addOption(
|
|
690
|
+
createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>"),
|
|
691
|
+
)
|
|
859
692
|
.examples(RECORDS_DELETE_EXAMPLES)
|
|
860
693
|
.trackedAction(
|
|
861
694
|
processContext,
|
|
@@ -864,32 +697,18 @@ export const registerRecordsCommand = (program: Command) => {
|
|
|
864
697
|
recordIds: string[],
|
|
865
698
|
options: DeleteOptions,
|
|
866
699
|
) => {
|
|
867
|
-
const
|
|
868
|
-
|
|
869
|
-
);
|
|
870
|
-
|
|
871
|
-
if (clientError) {
|
|
872
|
-
OutputFormatter.error({
|
|
873
|
-
Result: RESULTS.Failure,
|
|
874
|
-
Message: "Error connecting to Data Fabric",
|
|
875
|
-
Instructions: await extractErrorMessage(clientError),
|
|
876
|
-
});
|
|
877
|
-
processContext.exit(1);
|
|
878
|
-
return;
|
|
879
|
-
}
|
|
700
|
+
const sdk = await connectOrFail(options.tenant);
|
|
701
|
+
if (!sdk) return;
|
|
880
702
|
|
|
881
703
|
const [deleteError, result] = await catchError(
|
|
882
704
|
sdk.entities.deleteRecordsById(entityId, recordIds),
|
|
883
705
|
);
|
|
884
706
|
|
|
885
707
|
if (deleteError) {
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
});
|
|
891
|
-
processContext.exit(1);
|
|
892
|
-
return;
|
|
708
|
+
return fail(
|
|
709
|
+
"Error deleting records",
|
|
710
|
+
await extractErrorMessage(deleteError),
|
|
711
|
+
);
|
|
893
712
|
}
|
|
894
713
|
|
|
895
714
|
const r = result as BatchResult;
|
|
@@ -911,17 +730,6 @@ export const registerRecordsCommand = (program: Command) => {
|
|
|
911
730
|
);
|
|
912
731
|
};
|
|
913
732
|
|
|
914
|
-
/** Normalises the SDK cursor to a plain string for CLI output.
|
|
915
|
-
* The SDK returns `PaginationCursor = { value: string }` but we want
|
|
916
|
-
* to expose just the string so the user can pass it directly to --cursor. */
|
|
917
|
-
function extractCursorValue(cursor: unknown): string | undefined {
|
|
918
|
-
if (cursor === undefined || cursor === null) return undefined;
|
|
919
|
-
if (typeof cursor === "string") return cursor;
|
|
920
|
-
const c = cursor as Record<string, unknown>;
|
|
921
|
-
if (typeof c.value === "string") return c.value;
|
|
922
|
-
return undefined;
|
|
923
|
-
}
|
|
924
|
-
|
|
925
733
|
const isRecordObject = (value: unknown): value is Record<string, unknown> =>
|
|
926
734
|
typeof value === "object" && value !== null && !Array.isArray(value);
|
|
927
735
|
|