@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/entities.ts
CHANGED
|
@@ -15,9 +15,10 @@ import type {
|
|
|
15
15
|
RawEntityGetResponse,
|
|
16
16
|
} from "@uipath/uipath-typescript";
|
|
17
17
|
import { EntityFieldDataType } from "@uipath/uipath-typescript";
|
|
18
|
-
import type
|
|
18
|
+
import { type Command, Option } from "commander";
|
|
19
19
|
import { readJsonInput } from "../utils/input";
|
|
20
|
-
import {
|
|
20
|
+
import { fail, requireDestructiveConfirmation } from "../utils/output";
|
|
21
|
+
import { connectOrFail } from "../utils/sdk-client";
|
|
21
22
|
|
|
22
23
|
interface ListOptions {
|
|
23
24
|
tenant?: string;
|
|
@@ -38,40 +39,39 @@ interface UpdateEntityOptions {
|
|
|
38
39
|
tenant?: string;
|
|
39
40
|
file?: string;
|
|
40
41
|
body?: string;
|
|
42
|
+
yes?: boolean;
|
|
41
43
|
confirm?: boolean;
|
|
42
44
|
reason?: string;
|
|
43
45
|
}
|
|
44
46
|
|
|
45
47
|
interface DeleteOptions {
|
|
46
48
|
tenant?: string;
|
|
49
|
+
yes?: boolean;
|
|
47
50
|
confirm?: boolean;
|
|
48
51
|
reason?: string;
|
|
49
52
|
}
|
|
50
53
|
|
|
51
54
|
const ENTITIES_LIST_EXAMPLES: CommandExample[] = [
|
|
52
55
|
{
|
|
53
|
-
Description: "List Data Fabric entities",
|
|
56
|
+
Description: "List Data Fabric entities.",
|
|
54
57
|
Command: "uip df entities list --native-only",
|
|
55
58
|
Output: {
|
|
56
59
|
Code: "EntityList",
|
|
57
60
|
Data: [
|
|
58
61
|
{
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
Source: "Native",
|
|
73
|
-
Description: "Customer records",
|
|
74
|
-
FieldCount: 6,
|
|
62
|
+
id: "a1b2c3d4-0000-0000-0000-000000000001",
|
|
63
|
+
name: "Invoice",
|
|
64
|
+
displayName: "Invoice",
|
|
65
|
+
entityType: "Standard",
|
|
66
|
+
description: "Invoice records",
|
|
67
|
+
isRbacEnabled: false,
|
|
68
|
+
fields: [
|
|
69
|
+
{
|
|
70
|
+
id: "f1000000-0000-0000-0000-000000000001",
|
|
71
|
+
name: "amount",
|
|
72
|
+
},
|
|
73
|
+
],
|
|
74
|
+
externalFields: [],
|
|
75
75
|
},
|
|
76
76
|
],
|
|
77
77
|
},
|
|
@@ -80,34 +80,35 @@ const ENTITIES_LIST_EXAMPLES: CommandExample[] = [
|
|
|
80
80
|
|
|
81
81
|
const ENTITIES_GET_EXAMPLES: CommandExample[] = [
|
|
82
82
|
{
|
|
83
|
-
Description: "Get entity schema by ID",
|
|
83
|
+
Description: "Get entity schema by ID.",
|
|
84
84
|
Command: "uip df entities get a1b2c3d4-0000-0000-0000-000000000001",
|
|
85
85
|
Output: {
|
|
86
86
|
Code: "EntitySchema",
|
|
87
87
|
Data: {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
ID: "f1000000-0000-0000-0000-000000000001",
|
|
96
|
-
Name: "id",
|
|
97
|
-
DisplayName: "ID",
|
|
98
|
-
Type: "Guid",
|
|
99
|
-
Required: true,
|
|
100
|
-
PrimaryKey: true,
|
|
101
|
-
System: true,
|
|
102
|
-
},
|
|
88
|
+
id: "a1b2c3d4-0000-0000-0000-000000000001",
|
|
89
|
+
name: "Invoice",
|
|
90
|
+
displayName: "Invoice",
|
|
91
|
+
entityType: "Standard",
|
|
92
|
+
description: "Invoice records",
|
|
93
|
+
isRbacEnabled: false,
|
|
94
|
+
fields: [
|
|
103
95
|
{
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
96
|
+
id: "f1000000-0000-0000-0000-000000000002",
|
|
97
|
+
name: "amount",
|
|
98
|
+
displayName: "Amount",
|
|
99
|
+
fieldDataType: { name: "DECIMAL" },
|
|
100
|
+
sqlType: {
|
|
101
|
+
name: "DECIMAL",
|
|
102
|
+
decimalPrecision: 2,
|
|
103
|
+
minValue: 0,
|
|
104
|
+
maxValue: 999999,
|
|
105
|
+
},
|
|
106
|
+
isRequired: true,
|
|
107
|
+
isUnique: false,
|
|
108
|
+
isEncrypted: false,
|
|
109
|
+
isRbacEnabled: false,
|
|
110
|
+
isPrimaryKey: false,
|
|
111
|
+
isSystemField: false,
|
|
111
112
|
},
|
|
112
113
|
],
|
|
113
114
|
},
|
|
@@ -134,12 +135,12 @@ const ENTITIES_DELETE_EXAMPLES: CommandExample[] = [
|
|
|
134
135
|
const ENTITIES_CREATE_EXAMPLES: CommandExample[] = [
|
|
135
136
|
{
|
|
136
137
|
Description:
|
|
137
|
-
"Create an entity with
|
|
138
|
+
"Create an entity with choice-set, relationship, and file fields. " +
|
|
138
139
|
"CHOICE_SET_SINGLE/CHOICE_SET_MULTIPLE require 'choiceSetId' (from 'df choice-sets list'). " +
|
|
139
|
-
"RELATIONSHIP
|
|
140
|
-
"Note:
|
|
140
|
+
"RELATIONSHIP and FILE both require 'referenceEntityId' (UUID of the target entity, from 'df entities list') and 'referenceFieldId' (UUID of the field on the target entity, from 'df entities get <target-id>'). " +
|
|
141
|
+
"Note: a RELATIONSHIP column on a record always stores the target record's UUID 'Id' (regardless of which 'referenceFieldId' configured the join) — see 'df records insert' for how to write the value.",
|
|
141
142
|
Command:
|
|
142
|
-
'uip df entities create Expense --body \'{"displayName":"Expense","fields":[{"fieldName":"category","type":"CHOICE_SET_SINGLE","choiceSetId":"c1d2e3f4-0000-0000-0000-000000000001","isRequired":true},{"fieldName":"tags","type":"CHOICE_SET_MULTIPLE","choiceSetId":"c1d2e3f4-0000-0000-0000-000000000002"},{"fieldName":"submitter","type":"RELATIONSHIP","
|
|
143
|
+
'uip df entities create Expense --body \'{"displayName":"Expense","fields":[{"fieldName":"category","type":"CHOICE_SET_SINGLE","choiceSetId":"c1d2e3f4-0000-0000-0000-000000000001","isRequired":true},{"fieldName":"tags","type":"CHOICE_SET_MULTIPLE","choiceSetId":"c1d2e3f4-0000-0000-0000-000000000002"},{"fieldName":"submitter","type":"RELATIONSHIP","referenceEntityId":"a1b2c3d4-0000-0000-0000-000000000010","referenceFieldId":"f1000000-0000-0000-0000-000000000100","isRequired":true},{"fieldName":"receipt","type":"FILE","referenceEntityId":"a1b2c3d4-0000-0000-0000-000000000099","referenceFieldId":"f1000000-0000-0000-0000-000000000199"}]}\'',
|
|
143
144
|
Output: {
|
|
144
145
|
Code: "EntityCreated",
|
|
145
146
|
Data: { ID: "a1b2c3d4-0000-0000-0000-000000000004" },
|
|
@@ -196,54 +197,25 @@ export const registerEntitiesCommand = (program: Command) => {
|
|
|
196
197
|
)
|
|
197
198
|
.examples(ENTITIES_LIST_EXAMPLES)
|
|
198
199
|
.trackedAction(processContext, async (options: ListOptions) => {
|
|
199
|
-
const
|
|
200
|
-
|
|
201
|
-
);
|
|
202
|
-
|
|
203
|
-
if (clientError) {
|
|
204
|
-
OutputFormatter.error({
|
|
205
|
-
Result: RESULTS.Failure,
|
|
206
|
-
Message: "Error connecting to Data Fabric",
|
|
207
|
-
Instructions: await extractErrorMessage(clientError),
|
|
208
|
-
});
|
|
209
|
-
processContext.exit(1);
|
|
210
|
-
return;
|
|
211
|
-
}
|
|
200
|
+
const sdk = await connectOrFail(options.tenant);
|
|
201
|
+
if (!sdk) return;
|
|
212
202
|
|
|
213
203
|
const [listError, result] = await catchError(sdk.entities.getAll());
|
|
214
204
|
|
|
215
205
|
if (listError) {
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
});
|
|
221
|
-
processContext.exit(1);
|
|
222
|
-
return;
|
|
206
|
+
return fail(
|
|
207
|
+
"Error listing entities",
|
|
208
|
+
await extractErrorMessage(listError),
|
|
209
|
+
);
|
|
223
210
|
}
|
|
224
211
|
|
|
225
|
-
const entityList = (result ?? [])
|
|
226
|
-
.
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
externalFields[0]?.externalConnectionDetail
|
|
233
|
-
?.connectorName;
|
|
234
|
-
return {
|
|
235
|
-
Name: entity.name,
|
|
236
|
-
DisplayName: entity.displayName || entity.name,
|
|
237
|
-
ID: entity.id,
|
|
238
|
-
Type: entity.entityType,
|
|
239
|
-
Source: isNative
|
|
240
|
-
? "Native"
|
|
241
|
-
: `Federated${connectorName ? ` (${connectorName})` : ""}`,
|
|
242
|
-
Description: entity.description || "",
|
|
243
|
-
FieldCount: entity.fields.length,
|
|
244
|
-
};
|
|
245
|
-
})
|
|
246
|
-
.filter((e) => !options.nativeOnly || e.Source === "Native");
|
|
212
|
+
const entityList = (result ?? []).filter((e) => {
|
|
213
|
+
if (!options.nativeOnly) return true;
|
|
214
|
+
const entity = e as unknown as RawEntityGetResponse;
|
|
215
|
+
const externalFields: ExternalSourceFields[] =
|
|
216
|
+
entity.externalFields ?? [];
|
|
217
|
+
return externalFields.length === 0;
|
|
218
|
+
});
|
|
247
219
|
|
|
248
220
|
OutputFormatter.success({
|
|
249
221
|
Result: RESULTS.Success,
|
|
@@ -263,68 +235,33 @@ export const registerEntitiesCommand = (program: Command) => {
|
|
|
263
235
|
.trackedAction(
|
|
264
236
|
processContext,
|
|
265
237
|
async (id: string, options: GetOptions) => {
|
|
266
|
-
const
|
|
267
|
-
|
|
268
|
-
);
|
|
269
|
-
|
|
270
|
-
if (clientError) {
|
|
271
|
-
OutputFormatter.error({
|
|
272
|
-
Result: RESULTS.Failure,
|
|
273
|
-
Message: "Error connecting to Data Fabric",
|
|
274
|
-
Instructions: await extractErrorMessage(clientError),
|
|
275
|
-
});
|
|
276
|
-
processContext.exit(1);
|
|
277
|
-
return;
|
|
278
|
-
}
|
|
238
|
+
const sdk = await connectOrFail(options.tenant);
|
|
239
|
+
if (!sdk) return;
|
|
279
240
|
|
|
280
241
|
const [getError, entity] = await catchError(
|
|
281
242
|
sdk.entities.getById(id),
|
|
282
243
|
);
|
|
283
244
|
|
|
284
245
|
if (getError) {
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
});
|
|
290
|
-
processContext.exit(1);
|
|
291
|
-
return;
|
|
246
|
+
return fail(
|
|
247
|
+
`Error getting entity schema '${id}'`,
|
|
248
|
+
await extractErrorMessage(getError),
|
|
249
|
+
);
|
|
292
250
|
}
|
|
293
251
|
|
|
294
252
|
const e = entity as unknown as RawEntityGetResponse;
|
|
295
253
|
|
|
296
254
|
if (!e?.fields) {
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
"Verify the entity ID exists. Use 'df entities list' to see available entities.",
|
|
302
|
-
});
|
|
303
|
-
processContext.exit(1);
|
|
304
|
-
return;
|
|
255
|
+
return fail(
|
|
256
|
+
`Entity '${id}' not found`,
|
|
257
|
+
"Verify the entity ID exists. Use 'df entities list' to see available entities.",
|
|
258
|
+
);
|
|
305
259
|
}
|
|
306
260
|
|
|
307
|
-
const fields = e.fields.map((field) => ({
|
|
308
|
-
ID: field.id,
|
|
309
|
-
Name: field.name,
|
|
310
|
-
DisplayName: field.displayName,
|
|
311
|
-
Type: field.fieldDataType?.name,
|
|
312
|
-
Required: field.isRequired,
|
|
313
|
-
PrimaryKey: field.isPrimaryKey,
|
|
314
|
-
System: field.isSystemField,
|
|
315
|
-
}));
|
|
316
|
-
|
|
317
261
|
OutputFormatter.success({
|
|
318
262
|
Result: RESULTS.Success,
|
|
319
263
|
Code: "EntitySchema",
|
|
320
|
-
Data:
|
|
321
|
-
Name: e.name,
|
|
322
|
-
DisplayName: e.displayName || e.name,
|
|
323
|
-
ID: e.id,
|
|
324
|
-
Type: e.entityType,
|
|
325
|
-
Description: e.description || "",
|
|
326
|
-
Fields: fields,
|
|
327
|
-
},
|
|
264
|
+
Data: e,
|
|
328
265
|
});
|
|
329
266
|
},
|
|
330
267
|
);
|
|
@@ -343,7 +280,10 @@ export const registerEntitiesCommand = (program: Command) => {
|
|
|
343
280
|
"-f, --file <path>",
|
|
344
281
|
"Path to JSON file with entity definition (fields array required; displayName, description, isRbacEnabled optional)",
|
|
345
282
|
)
|
|
346
|
-
.option(
|
|
283
|
+
.option(
|
|
284
|
+
"--body <json>",
|
|
285
|
+
"Inline JSON entity definition (use `-` to read from stdin)",
|
|
286
|
+
)
|
|
347
287
|
.examples(ENTITIES_CREATE_EXAMPLES)
|
|
348
288
|
.trackedAction(
|
|
349
289
|
processContext,
|
|
@@ -357,13 +297,10 @@ export const registerEntitiesCommand = (program: Command) => {
|
|
|
357
297
|
);
|
|
358
298
|
|
|
359
299
|
if (parseError) {
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
});
|
|
365
|
-
processContext.exit(1);
|
|
366
|
-
return;
|
|
300
|
+
return fail(
|
|
301
|
+
"Error parsing entity definition",
|
|
302
|
+
parseError.message,
|
|
303
|
+
);
|
|
367
304
|
}
|
|
368
305
|
|
|
369
306
|
if (
|
|
@@ -371,27 +308,18 @@ export const registerEntitiesCommand = (program: Command) => {
|
|
|
371
308
|
parsed === null ||
|
|
372
309
|
Array.isArray(parsed)
|
|
373
310
|
) {
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
"Provide a JSON object with a 'fields' array and optional displayName, description, isRbacEnabled.",
|
|
379
|
-
});
|
|
380
|
-
processContext.exit(1);
|
|
381
|
-
return;
|
|
311
|
+
return fail(
|
|
312
|
+
"Entity definition must be a JSON object",
|
|
313
|
+
"Provide a JSON object with a 'fields' array and optional displayName, description, isRbacEnabled.",
|
|
314
|
+
);
|
|
382
315
|
}
|
|
383
316
|
|
|
384
317
|
const definition = parsed as Record<string, unknown>;
|
|
385
318
|
if (!Array.isArray(definition.fields)) {
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
Instructions:
|
|
391
|
-
"Provide a JSON object with a 'fields' array containing field definitions.",
|
|
392
|
-
});
|
|
393
|
-
processContext.exit(1);
|
|
394
|
-
return;
|
|
319
|
+
return fail(
|
|
320
|
+
"Entity definition must include a 'fields' array",
|
|
321
|
+
"Provide a JSON object with a 'fields' array containing field definitions.",
|
|
322
|
+
);
|
|
395
323
|
}
|
|
396
324
|
|
|
397
325
|
const hasInvalidField = (definition.fields as unknown[]).some(
|
|
@@ -402,39 +330,21 @@ export const registerEntitiesCommand = (program: Command) => {
|
|
|
402
330
|
"string",
|
|
403
331
|
);
|
|
404
332
|
if (hasInvalidField) {
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
'Example: {"fieldName":"title","type":"STRING"}',
|
|
410
|
-
});
|
|
411
|
-
processContext.exit(1);
|
|
412
|
-
return;
|
|
333
|
+
return fail(
|
|
334
|
+
"Each field must include a 'fieldName' string",
|
|
335
|
+
'Example: {"fieldName":"title","type":"STRING"}',
|
|
336
|
+
);
|
|
413
337
|
}
|
|
414
338
|
|
|
415
339
|
if (hasInvalidFieldType(definition.fields as unknown[])) {
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
});
|
|
421
|
-
processContext.exit(1);
|
|
422
|
-
return;
|
|
340
|
+
return fail(
|
|
341
|
+
"Invalid field type in fields",
|
|
342
|
+
`Valid types: ${VALID_FIELD_TYPES_LIST}`,
|
|
343
|
+
);
|
|
423
344
|
}
|
|
424
345
|
|
|
425
|
-
const
|
|
426
|
-
|
|
427
|
-
);
|
|
428
|
-
|
|
429
|
-
if (clientError) {
|
|
430
|
-
OutputFormatter.error({
|
|
431
|
-
Result: RESULTS.Failure,
|
|
432
|
-
Message: "Error connecting to Data Fabric",
|
|
433
|
-
Instructions: await extractErrorMessage(clientError),
|
|
434
|
-
});
|
|
435
|
-
processContext.exit(1);
|
|
436
|
-
return;
|
|
437
|
-
}
|
|
346
|
+
const sdk = await connectOrFail(options.tenant);
|
|
347
|
+
if (!sdk) return;
|
|
438
348
|
|
|
439
349
|
const createOpts = {
|
|
440
350
|
...(definition.displayName !== undefined && {
|
|
@@ -460,13 +370,10 @@ export const registerEntitiesCommand = (program: Command) => {
|
|
|
460
370
|
);
|
|
461
371
|
|
|
462
372
|
if (createError) {
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
});
|
|
468
|
-
processContext.exit(1);
|
|
469
|
-
return;
|
|
373
|
+
return fail(
|
|
374
|
+
"Error creating entity",
|
|
375
|
+
await extractErrorMessage(createError),
|
|
376
|
+
);
|
|
470
377
|
}
|
|
471
378
|
|
|
472
379
|
OutputFormatter.success({
|
|
@@ -488,11 +395,17 @@ export const registerEntitiesCommand = (program: Command) => {
|
|
|
488
395
|
"-f, --file <path>",
|
|
489
396
|
"Path to JSON file with update options (addFields, updateFields, removeFields, displayName, description, isRbacEnabled)",
|
|
490
397
|
)
|
|
491
|
-
.option("--body <json>", "Inline JSON update options")
|
|
492
398
|
.option(
|
|
493
|
-
"--
|
|
399
|
+
"--body <json>",
|
|
400
|
+
"Inline JSON update options (use `-` to read from stdin)",
|
|
401
|
+
)
|
|
402
|
+
.option(
|
|
403
|
+
"-y, --yes",
|
|
494
404
|
"Required when 'removeFields' is non-empty — acknowledges the field deletion is irreversible",
|
|
495
405
|
)
|
|
406
|
+
.addOption(
|
|
407
|
+
new Option("--confirm", "Deprecated alias for --yes").hideHelp(),
|
|
408
|
+
)
|
|
496
409
|
.option(
|
|
497
410
|
"--reason <reason>",
|
|
498
411
|
"Required when 'removeFields' is non-empty — echoed back in the response so the caller can log it",
|
|
@@ -509,13 +422,10 @@ export const registerEntitiesCommand = (program: Command) => {
|
|
|
509
422
|
);
|
|
510
423
|
|
|
511
424
|
if (parseError) {
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
});
|
|
517
|
-
processContext.exit(1);
|
|
518
|
-
return;
|
|
425
|
+
return fail(
|
|
426
|
+
"Error parsing update options",
|
|
427
|
+
parseError.message,
|
|
428
|
+
);
|
|
519
429
|
}
|
|
520
430
|
|
|
521
431
|
if (
|
|
@@ -523,14 +433,10 @@ export const registerEntitiesCommand = (program: Command) => {
|
|
|
523
433
|
parsed === null ||
|
|
524
434
|
Array.isArray(parsed)
|
|
525
435
|
) {
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
"Provide a JSON object with addFields, updateFields, removeFields, displayName, description, or isRbacEnabled.",
|
|
531
|
-
});
|
|
532
|
-
processContext.exit(1);
|
|
533
|
-
return;
|
|
436
|
+
return fail(
|
|
437
|
+
"Update options must be a JSON object",
|
|
438
|
+
"Provide a JSON object with addFields, updateFields, removeFields, displayName, description, or isRbacEnabled.",
|
|
439
|
+
);
|
|
534
440
|
}
|
|
535
441
|
|
|
536
442
|
const input = parsed as Record<string, unknown>;
|
|
@@ -539,42 +445,30 @@ export const registerEntitiesCommand = (program: Command) => {
|
|
|
539
445
|
input.addFields !== undefined &&
|
|
540
446
|
!Array.isArray(input.addFields)
|
|
541
447
|
) {
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
'Example: {"addFields":[{"fieldName":"title","type":"STRING"}]}',
|
|
547
|
-
});
|
|
548
|
-
processContext.exit(1);
|
|
549
|
-
return;
|
|
448
|
+
return fail(
|
|
449
|
+
"'addFields' must be an array",
|
|
450
|
+
'Example: {"addFields":[{"fieldName":"title","type":"STRING"}]}',
|
|
451
|
+
);
|
|
550
452
|
}
|
|
551
453
|
|
|
552
454
|
if (
|
|
553
455
|
input.updateFields !== undefined &&
|
|
554
456
|
!Array.isArray(input.updateFields)
|
|
555
457
|
) {
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
'Example: {"updateFields":[{"id":"<fieldId>","displayName":"New Name"}]}',
|
|
561
|
-
});
|
|
562
|
-
processContext.exit(1);
|
|
563
|
-
return;
|
|
458
|
+
return fail(
|
|
459
|
+
"'updateFields' must be an array",
|
|
460
|
+
'Example: {"updateFields":[{"id":"<fieldId>","displayName":"New Name"}]}',
|
|
461
|
+
);
|
|
564
462
|
}
|
|
565
463
|
|
|
566
464
|
if (
|
|
567
465
|
input.removeFields !== undefined &&
|
|
568
466
|
!Array.isArray(input.removeFields)
|
|
569
467
|
) {
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
'Example: {"removeFields":[{"fieldName":"old_field"}]}',
|
|
575
|
-
});
|
|
576
|
-
processContext.exit(1);
|
|
577
|
-
return;
|
|
468
|
+
return fail(
|
|
469
|
+
"'removeFields' must be an array",
|
|
470
|
+
'Example: {"removeFields":[{"fieldName":"old_field"}]}',
|
|
471
|
+
);
|
|
578
472
|
}
|
|
579
473
|
|
|
580
474
|
let trimmedReason: string | undefined;
|
|
@@ -591,41 +485,19 @@ export const registerEntitiesCommand = (program: Command) => {
|
|
|
591
485
|
return typeof fn !== "string" || fn.trim() === "";
|
|
592
486
|
});
|
|
593
487
|
if (hasInvalidRemove) {
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
Instructions:
|
|
599
|
-
'Example: {"removeFields":[{"fieldName":"old_field"}]}',
|
|
600
|
-
});
|
|
601
|
-
processContext.exit(1);
|
|
602
|
-
return;
|
|
603
|
-
}
|
|
604
|
-
|
|
605
|
-
if (options.confirm !== true) {
|
|
606
|
-
OutputFormatter.error({
|
|
607
|
-
Result: RESULTS.Failure,
|
|
608
|
-
Message:
|
|
609
|
-
"Confirmation required for destructive operation",
|
|
610
|
-
Instructions:
|
|
611
|
-
"Pass --confirm to acknowledge field deletion is irreversible.",
|
|
612
|
-
});
|
|
613
|
-
processContext.exit(1);
|
|
614
|
-
return;
|
|
488
|
+
return fail(
|
|
489
|
+
"Each field in removeFields must include a non-empty 'fieldName' string",
|
|
490
|
+
'Example: {"removeFields":[{"fieldName":"old_field"}]}',
|
|
491
|
+
);
|
|
615
492
|
}
|
|
616
493
|
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
'Pass --reason "<text>" to record why fields are being removed.',
|
|
625
|
-
});
|
|
626
|
-
processContext.exit(1);
|
|
627
|
-
return;
|
|
628
|
-
}
|
|
494
|
+
const reason = requireDestructiveConfirmation(
|
|
495
|
+
options,
|
|
496
|
+
`remove fields from entity '${id}'`,
|
|
497
|
+
'Pass --reason "<text>" to record why fields are being removed.',
|
|
498
|
+
);
|
|
499
|
+
if (reason === null) return;
|
|
500
|
+
trimmedReason = reason;
|
|
629
501
|
|
|
630
502
|
removedFieldNames = (
|
|
631
503
|
removeFields as { fieldName: string }[]
|
|
@@ -642,25 +514,17 @@ export const registerEntitiesCommand = (program: Command) => {
|
|
|
642
514
|
},
|
|
643
515
|
);
|
|
644
516
|
if (hasInvalidField) {
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
Instructions:
|
|
650
|
-
'Example: {"fieldName":"title","type":"STRING"}',
|
|
651
|
-
});
|
|
652
|
-
processContext.exit(1);
|
|
653
|
-
return;
|
|
517
|
+
return fail(
|
|
518
|
+
"Each field in addFields must include a non-empty 'fieldName' string",
|
|
519
|
+
'Example: {"fieldName":"title","type":"STRING"}',
|
|
520
|
+
);
|
|
654
521
|
}
|
|
655
522
|
|
|
656
523
|
if (hasInvalidFieldType(input.addFields as unknown[])) {
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
});
|
|
662
|
-
processContext.exit(1);
|
|
663
|
-
return;
|
|
524
|
+
return fail(
|
|
525
|
+
"Invalid field type in addFields",
|
|
526
|
+
`Valid types: ${VALID_FIELD_TYPES_LIST}`,
|
|
527
|
+
);
|
|
664
528
|
}
|
|
665
529
|
|
|
666
530
|
const addNames = (
|
|
@@ -670,14 +534,10 @@ export const registerEntitiesCommand = (program: Command) => {
|
|
|
670
534
|
(name, i) => addNames.indexOf(name) !== i,
|
|
671
535
|
);
|
|
672
536
|
if (duplicateAdd !== undefined) {
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
"Each entry in addFields must have a unique fieldName.",
|
|
678
|
-
});
|
|
679
|
-
processContext.exit(1);
|
|
680
|
-
return;
|
|
537
|
+
return fail(
|
|
538
|
+
`Duplicate fieldName '${duplicateAdd}' in addFields`,
|
|
539
|
+
"Each entry in addFields must have a unique fieldName.",
|
|
540
|
+
);
|
|
681
541
|
}
|
|
682
542
|
|
|
683
543
|
if (removedFieldNames.length > 0) {
|
|
@@ -685,14 +545,10 @@ export const registerEntitiesCommand = (program: Command) => {
|
|
|
685
545
|
removedFieldNames.includes(name),
|
|
686
546
|
);
|
|
687
547
|
if (conflict !== undefined) {
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
"A single update cannot add and remove the same field. Split into two calls if you need to recreate it.",
|
|
693
|
-
});
|
|
694
|
-
processContext.exit(1);
|
|
695
|
-
return;
|
|
548
|
+
return fail(
|
|
549
|
+
`Field '${conflict}' appears in both addFields and removeFields`,
|
|
550
|
+
"A single update cannot add and remove the same field. Split into two calls if you need to recreate it.",
|
|
551
|
+
);
|
|
696
552
|
}
|
|
697
553
|
}
|
|
698
554
|
}
|
|
@@ -706,31 +562,15 @@ export const registerEntitiesCommand = (program: Command) => {
|
|
|
706
562
|
return typeof fid !== "string" || fid.trim() === "";
|
|
707
563
|
});
|
|
708
564
|
if (hasInvalidField) {
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
Instructions:
|
|
714
|
-
'Use \'df entities get <entityId>\' to find field IDs. Example: {"id":"<fieldId>","displayName":"Total Amount","isRequired":true}',
|
|
715
|
-
});
|
|
716
|
-
processContext.exit(1);
|
|
717
|
-
return;
|
|
565
|
+
return fail(
|
|
566
|
+
"Each field in updateFields must include a non-empty 'id' string",
|
|
567
|
+
'Use \'df entities get <entityId>\' to find field IDs. Example: {"id":"<fieldId>","displayName":"Total Amount","isRequired":true}',
|
|
568
|
+
);
|
|
718
569
|
}
|
|
719
570
|
}
|
|
720
571
|
|
|
721
|
-
const
|
|
722
|
-
|
|
723
|
-
);
|
|
724
|
-
|
|
725
|
-
if (clientError) {
|
|
726
|
-
OutputFormatter.error({
|
|
727
|
-
Result: RESULTS.Failure,
|
|
728
|
-
Message: "Error connecting to Data Fabric",
|
|
729
|
-
Instructions: await extractErrorMessage(clientError),
|
|
730
|
-
});
|
|
731
|
-
processContext.exit(1);
|
|
732
|
-
return;
|
|
733
|
-
}
|
|
572
|
+
const sdk = await connectOrFail(options.tenant);
|
|
573
|
+
if (!sdk) return;
|
|
734
574
|
|
|
735
575
|
const entityService: EntityServiceModel = sdk.entities;
|
|
736
576
|
const [updateError] = await catchError(
|
|
@@ -738,13 +578,10 @@ export const registerEntitiesCommand = (program: Command) => {
|
|
|
738
578
|
);
|
|
739
579
|
|
|
740
580
|
if (updateError) {
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
});
|
|
746
|
-
processContext.exit(1);
|
|
747
|
-
return;
|
|
581
|
+
return fail(
|
|
582
|
+
"Error updating entity",
|
|
583
|
+
await extractErrorMessage(updateError),
|
|
584
|
+
);
|
|
748
585
|
}
|
|
749
586
|
|
|
750
587
|
OutputFormatter.success({
|
|
@@ -768,7 +605,10 @@ export const registerEntitiesCommand = (program: Command) => {
|
|
|
768
605
|
.addOption(
|
|
769
606
|
createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>"),
|
|
770
607
|
)
|
|
771
|
-
.option("--
|
|
608
|
+
.option("-y, --yes", "Acknowledge this is an irreversible operation")
|
|
609
|
+
.addOption(
|
|
610
|
+
new Option("--confirm", "Deprecated alias for --yes").hideHelp(),
|
|
611
|
+
)
|
|
772
612
|
.option(
|
|
773
613
|
"--reason <reason>",
|
|
774
614
|
"Reason for the deletion — echoed back in the response so the caller can log it",
|
|
@@ -777,43 +617,15 @@ export const registerEntitiesCommand = (program: Command) => {
|
|
|
777
617
|
.trackedAction(
|
|
778
618
|
processContext,
|
|
779
619
|
async (id: string, options: DeleteOptions) => {
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
"Confirmation required for destructive operation",
|
|
785
|
-
Instructions:
|
|
786
|
-
"Pass --confirm to acknowledge this is irreversible.",
|
|
787
|
-
});
|
|
788
|
-
processContext.exit(1);
|
|
789
|
-
return;
|
|
790
|
-
}
|
|
791
|
-
|
|
792
|
-
const reason = options.reason?.trim();
|
|
793
|
-
if (reason === undefined || reason === "") {
|
|
794
|
-
OutputFormatter.error({
|
|
795
|
-
Result: RESULTS.Failure,
|
|
796
|
-
Message: "Reason required for destructive operation",
|
|
797
|
-
Instructions:
|
|
798
|
-
'Pass --reason "<text>" to record why the entity is being deleted.',
|
|
799
|
-
});
|
|
800
|
-
processContext.exit(1);
|
|
801
|
-
return;
|
|
802
|
-
}
|
|
803
|
-
|
|
804
|
-
const [clientError, sdk] = await catchError(
|
|
805
|
-
createDataFabricClient(options.tenant),
|
|
620
|
+
const reason = requireDestructiveConfirmation(
|
|
621
|
+
options,
|
|
622
|
+
`delete entity '${id}'`,
|
|
623
|
+
'Pass --reason "<text>" to record why the entity is being deleted.',
|
|
806
624
|
);
|
|
625
|
+
if (reason === null) return;
|
|
807
626
|
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
Result: RESULTS.Failure,
|
|
811
|
-
Message: "Error connecting to Data Fabric",
|
|
812
|
-
Instructions: await extractErrorMessage(clientError),
|
|
813
|
-
});
|
|
814
|
-
processContext.exit(1);
|
|
815
|
-
return;
|
|
816
|
-
}
|
|
627
|
+
const sdk = await connectOrFail(options.tenant);
|
|
628
|
+
if (!sdk) return;
|
|
817
629
|
|
|
818
630
|
const entityService: EntityServiceModel = sdk.entities;
|
|
819
631
|
const [deleteError] = await catchError(
|
|
@@ -821,13 +633,10 @@ export const registerEntitiesCommand = (program: Command) => {
|
|
|
821
633
|
);
|
|
822
634
|
|
|
823
635
|
if (deleteError) {
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
});
|
|
829
|
-
processContext.exit(1);
|
|
830
|
-
return;
|
|
636
|
+
return fail(
|
|
637
|
+
`Error deleting entity '${id}'`,
|
|
638
|
+
await extractErrorMessage(deleteError),
|
|
639
|
+
);
|
|
831
640
|
}
|
|
832
641
|
|
|
833
642
|
OutputFormatter.success({
|