@uipath/data-fabric-tool 1.0.4 → 1.1.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 +24434 -24133
- package/package.json +5 -13
- package/src/commands/choice-sets.spec.ts +394 -0
- package/src/commands/choice-sets.ts +286 -0
- package/src/commands/entities.spec.ts +361 -0
- package/src/commands/entities.ts +33 -5
- package/src/commands/files.ts +10 -3
- package/src/commands/records.spec.ts +69 -0
- package/src/commands/records.ts +42 -18
- package/src/index.ts +5 -10
- package/src/tool.ts +2 -0
- package/src/utils/pagination.ts +10 -0
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type CommandExample,
|
|
3
|
+
catchError,
|
|
4
|
+
extractErrorMessage,
|
|
5
|
+
OutputFormatter,
|
|
6
|
+
processContext,
|
|
7
|
+
RESULTS,
|
|
8
|
+
} from "@uipath/common";
|
|
9
|
+
import type { Command } from "commander";
|
|
10
|
+
import { extractCursorValue } from "../utils/pagination";
|
|
11
|
+
import { createDataFabricClient } from "../utils/sdk-client";
|
|
12
|
+
|
|
13
|
+
interface ListOptions {
|
|
14
|
+
tenant?: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
interface GetOptions {
|
|
18
|
+
tenant?: string;
|
|
19
|
+
limit?: string;
|
|
20
|
+
offset?: string;
|
|
21
|
+
cursor?: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const CHOICE_SETS_LIST_EXAMPLES: CommandExample[] = [
|
|
25
|
+
{
|
|
26
|
+
Description:
|
|
27
|
+
"List all Data Fabric choice sets. The returned 'ID' is the value to pass as 'choiceSetId' on a CHOICE_SET_SINGLE/CHOICE_SET_MULTIPLE entity field, or to 'df choice-sets get <id>'.",
|
|
28
|
+
Command: "uip df choice-sets list",
|
|
29
|
+
Output: {
|
|
30
|
+
Code: "ChoiceSetList",
|
|
31
|
+
Data: [
|
|
32
|
+
{
|
|
33
|
+
ID: "c1d2e3f4-0000-0000-0000-000000000001",
|
|
34
|
+
Name: "ExpenseTypes",
|
|
35
|
+
DisplayName: "Expense Types",
|
|
36
|
+
Description: "Categories of expenses",
|
|
37
|
+
FolderId: "f1000000-0000-0000-0000-000000000001",
|
|
38
|
+
CreatedBy: "u1000000-0000-0000-0000-000000000001",
|
|
39
|
+
UpdatedBy: "u1000000-0000-0000-0000-000000000001",
|
|
40
|
+
CreatedTime: "2026-01-01T00:00:00Z",
|
|
41
|
+
UpdatedTime: "2026-01-02T00:00:00Z",
|
|
42
|
+
},
|
|
43
|
+
],
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
];
|
|
47
|
+
|
|
48
|
+
const CHOICE_SETS_GET_EXAMPLES: CommandExample[] = [
|
|
49
|
+
{
|
|
50
|
+
Description:
|
|
51
|
+
"Get values for a choice set. The 'NumberId' on each value is the integer to pass when inserting or updating a record into a CHOICE_SET_SINGLE field (or in an array for CHOICE_SET_MULTIPLE).",
|
|
52
|
+
Command:
|
|
53
|
+
"uip df choice-sets get c1d2e3f4-0000-0000-0000-000000000001 --limit 2",
|
|
54
|
+
Output: {
|
|
55
|
+
Code: "ChoiceSetValues",
|
|
56
|
+
Data: {
|
|
57
|
+
TotalCount: 2,
|
|
58
|
+
Values: [
|
|
59
|
+
{
|
|
60
|
+
Id: "v1000000-0000-0000-0000-000000000001",
|
|
61
|
+
Name: "travel",
|
|
62
|
+
DisplayName: "Travel",
|
|
63
|
+
NumberId: 1,
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
Id: "v1000000-0000-0000-0000-000000000002",
|
|
67
|
+
Name: "meals",
|
|
68
|
+
DisplayName: "Meals",
|
|
69
|
+
NumberId: 2,
|
|
70
|
+
},
|
|
71
|
+
],
|
|
72
|
+
HasNextPage: false,
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
];
|
|
77
|
+
|
|
78
|
+
export const registerChoiceSetsCommand = (program: Command) => {
|
|
79
|
+
const choiceSets = program
|
|
80
|
+
.command("choice-sets")
|
|
81
|
+
.description(
|
|
82
|
+
"Browse Data Fabric choice sets. Read-only: choice sets are authored in the Data Fabric web UI and cannot be created, updated, or deleted from the CLI. " +
|
|
83
|
+
"Use 'list' to find a choice set's ID (used as 'choiceSetId' on CHOICE_SET_SINGLE/CHOICE_SET_MULTIPLE entity fields), and 'get' to inspect its values.",
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
choiceSets
|
|
87
|
+
.command("list")
|
|
88
|
+
.description("List all Data Fabric choice sets")
|
|
89
|
+
.option("-t, --tenant <tenant-name>", "Tenant name")
|
|
90
|
+
.examples(CHOICE_SETS_LIST_EXAMPLES)
|
|
91
|
+
.trackedAction(processContext, async (options: ListOptions) => {
|
|
92
|
+
const [clientError, sdk] = await catchError(
|
|
93
|
+
createDataFabricClient(options.tenant),
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
if (clientError) {
|
|
97
|
+
OutputFormatter.error({
|
|
98
|
+
Result: RESULTS.Failure,
|
|
99
|
+
Message: "Error connecting to Data Fabric",
|
|
100
|
+
Instructions: await extractErrorMessage(clientError),
|
|
101
|
+
});
|
|
102
|
+
processContext.exit(1);
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const [listError, result] = await catchError(
|
|
107
|
+
sdk.entities.choicesets.getAll(),
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
if (listError) {
|
|
111
|
+
OutputFormatter.error({
|
|
112
|
+
Result: RESULTS.Failure,
|
|
113
|
+
Message: "Error listing choice sets",
|
|
114
|
+
Instructions: await extractErrorMessage(listError),
|
|
115
|
+
});
|
|
116
|
+
processContext.exit(1);
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const items = (result ?? []).map((cs) => ({
|
|
121
|
+
ID: (cs as { id?: string }).id,
|
|
122
|
+
Name: cs.name,
|
|
123
|
+
DisplayName: cs.displayName || cs.name,
|
|
124
|
+
Description: cs.description || "",
|
|
125
|
+
FolderId: cs.folderId,
|
|
126
|
+
CreatedBy: cs.createdBy,
|
|
127
|
+
UpdatedBy: cs.updatedBy,
|
|
128
|
+
CreatedTime: cs.createdTime,
|
|
129
|
+
UpdatedTime: cs.updatedTime,
|
|
130
|
+
}));
|
|
131
|
+
|
|
132
|
+
OutputFormatter.success({
|
|
133
|
+
Result: RESULTS.Success,
|
|
134
|
+
Code: "ChoiceSetList",
|
|
135
|
+
Data: items,
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
choiceSets
|
|
140
|
+
.command("get")
|
|
141
|
+
.description("Get values for a Data Fabric choice set")
|
|
142
|
+
.argument("<choice-set-id>", "Choice set ID")
|
|
143
|
+
.option("-t, --tenant <tenant-name>", "Tenant name")
|
|
144
|
+
.option(
|
|
145
|
+
"-l, --limit <number>",
|
|
146
|
+
"Number of values to return per page",
|
|
147
|
+
"50",
|
|
148
|
+
)
|
|
149
|
+
.option(
|
|
150
|
+
"-o, --offset <number>",
|
|
151
|
+
"Start from the page containing this record index (rounded down to the nearest page boundary; mutually exclusive with --cursor)",
|
|
152
|
+
)
|
|
153
|
+
.option(
|
|
154
|
+
"--cursor <cursor>",
|
|
155
|
+
"Pagination cursor from a previous response to fetch the next page",
|
|
156
|
+
)
|
|
157
|
+
.examples(CHOICE_SETS_GET_EXAMPLES)
|
|
158
|
+
.trackedAction(
|
|
159
|
+
processContext,
|
|
160
|
+
async (choiceSetId: string, options: GetOptions) => {
|
|
161
|
+
const pageSize = Number(options.limit ?? "50");
|
|
162
|
+
if (Number.isNaN(pageSize) || pageSize < 1) {
|
|
163
|
+
OutputFormatter.error({
|
|
164
|
+
Result: RESULTS.Failure,
|
|
165
|
+
Message: "Invalid --limit value",
|
|
166
|
+
Instructions: "Provide a positive integer for --limit.",
|
|
167
|
+
});
|
|
168
|
+
processContext.exit(1);
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (
|
|
173
|
+
options.cursor !== undefined &&
|
|
174
|
+
options.offset !== undefined
|
|
175
|
+
) {
|
|
176
|
+
OutputFormatter.error({
|
|
177
|
+
Result: RESULTS.Failure,
|
|
178
|
+
Message: "--offset and --cursor are mutually exclusive",
|
|
179
|
+
Instructions:
|
|
180
|
+
"Use --offset to jump to a position by record count, or --cursor to continue from a previous response.",
|
|
181
|
+
});
|
|
182
|
+
processContext.exit(1);
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
let jumpToPage: number | undefined;
|
|
187
|
+
if (options.offset !== undefined) {
|
|
188
|
+
const offsetValue = Number(options.offset);
|
|
189
|
+
if (Number.isNaN(offsetValue) || offsetValue < 0) {
|
|
190
|
+
OutputFormatter.error({
|
|
191
|
+
Result: RESULTS.Failure,
|
|
192
|
+
Message: "Invalid --offset value",
|
|
193
|
+
Instructions:
|
|
194
|
+
"Provide a non-negative integer for --offset.",
|
|
195
|
+
});
|
|
196
|
+
processContext.exit(1);
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
jumpToPage = Math.floor(offsetValue / pageSize) + 1;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const [clientError, sdk] = await catchError(
|
|
203
|
+
createDataFabricClient(options.tenant),
|
|
204
|
+
);
|
|
205
|
+
|
|
206
|
+
if (clientError) {
|
|
207
|
+
OutputFormatter.error({
|
|
208
|
+
Result: RESULTS.Failure,
|
|
209
|
+
Message: "Error connecting to Data Fabric",
|
|
210
|
+
Instructions: await extractErrorMessage(clientError),
|
|
211
|
+
});
|
|
212
|
+
processContext.exit(1);
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const paginationOptions =
|
|
217
|
+
options.cursor !== undefined
|
|
218
|
+
? { pageSize, cursor: { value: options.cursor } }
|
|
219
|
+
: jumpToPage !== undefined
|
|
220
|
+
? { pageSize, jumpToPage }
|
|
221
|
+
: { pageSize };
|
|
222
|
+
|
|
223
|
+
const [getError, result] = await catchError(
|
|
224
|
+
sdk.entities.choicesets.getById(
|
|
225
|
+
choiceSetId,
|
|
226
|
+
paginationOptions,
|
|
227
|
+
),
|
|
228
|
+
);
|
|
229
|
+
|
|
230
|
+
if (getError) {
|
|
231
|
+
OutputFormatter.error({
|
|
232
|
+
Result: RESULTS.Failure,
|
|
233
|
+
Message: `Error getting choice set '${choiceSetId}'`,
|
|
234
|
+
Instructions: await extractErrorMessage(getError),
|
|
235
|
+
});
|
|
236
|
+
processContext.exit(1);
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
type ChoiceSetValue = {
|
|
241
|
+
id?: string;
|
|
242
|
+
name?: string;
|
|
243
|
+
displayName?: string;
|
|
244
|
+
numberId?: number;
|
|
245
|
+
createdTime?: string;
|
|
246
|
+
updatedTime?: string;
|
|
247
|
+
};
|
|
248
|
+
const response = result as unknown as {
|
|
249
|
+
items?: ChoiceSetValue[];
|
|
250
|
+
totalCount?: number;
|
|
251
|
+
hasNextPage?: boolean;
|
|
252
|
+
nextCursor?: unknown;
|
|
253
|
+
currentPage?: number;
|
|
254
|
+
totalPages?: number;
|
|
255
|
+
};
|
|
256
|
+
const values = (response.items ?? []).map((v) => ({
|
|
257
|
+
Id: v.id,
|
|
258
|
+
Name: v.name,
|
|
259
|
+
DisplayName: v.displayName || v.name,
|
|
260
|
+
NumberId: v.numberId,
|
|
261
|
+
CreatedTime: v.createdTime,
|
|
262
|
+
UpdatedTime: v.updatedTime,
|
|
263
|
+
}));
|
|
264
|
+
const nextCursor = extractCursorValue(response.nextCursor);
|
|
265
|
+
|
|
266
|
+
OutputFormatter.success({
|
|
267
|
+
Result: RESULTS.Success,
|
|
268
|
+
Code: "ChoiceSetValues",
|
|
269
|
+
Data: {
|
|
270
|
+
TotalCount: response.totalCount ?? values.length,
|
|
271
|
+
Values: values,
|
|
272
|
+
HasNextPage: response.hasNextPage ?? false,
|
|
273
|
+
...(nextCursor !== undefined && {
|
|
274
|
+
NextCursor: nextCursor,
|
|
275
|
+
}),
|
|
276
|
+
...(response.currentPage !== undefined && {
|
|
277
|
+
CurrentPage: response.currentPage,
|
|
278
|
+
}),
|
|
279
|
+
...(response.totalPages !== undefined && {
|
|
280
|
+
TotalPages: response.totalPages,
|
|
281
|
+
}),
|
|
282
|
+
},
|
|
283
|
+
});
|
|
284
|
+
},
|
|
285
|
+
);
|
|
286
|
+
};
|
|
@@ -465,6 +465,128 @@ describe("entities create", () => {
|
|
|
465
465
|
);
|
|
466
466
|
});
|
|
467
467
|
|
|
468
|
+
it("should create entity with a CHOICE_SET_SINGLE field carrying choiceSetId", async () => {
|
|
469
|
+
const sdk = mockSdk();
|
|
470
|
+
vi.mocked(sdk.entities.create).mockResolvedValue(
|
|
471
|
+
"entity-choice-single",
|
|
472
|
+
);
|
|
473
|
+
const fields = [
|
|
474
|
+
{
|
|
475
|
+
fieldName: "opType",
|
|
476
|
+
type: "CHOICE_SET_SINGLE",
|
|
477
|
+
choiceSetId: "9db00b66-9952-f111-8ef3-6045bd07956d",
|
|
478
|
+
isRequired: true,
|
|
479
|
+
},
|
|
480
|
+
];
|
|
481
|
+
vi.mocked(readJsonInput).mockResolvedValue({ fields });
|
|
482
|
+
|
|
483
|
+
const program = buildProgram();
|
|
484
|
+
await program.parseAsync([
|
|
485
|
+
"node",
|
|
486
|
+
"test",
|
|
487
|
+
"entities",
|
|
488
|
+
"create",
|
|
489
|
+
"CliTestExpense",
|
|
490
|
+
"--body",
|
|
491
|
+
JSON.stringify({ fields }),
|
|
492
|
+
]);
|
|
493
|
+
|
|
494
|
+
expect(sdk.entities.create).toHaveBeenCalledWith(
|
|
495
|
+
"CliTestExpense",
|
|
496
|
+
expect.arrayContaining([
|
|
497
|
+
expect.objectContaining({
|
|
498
|
+
fieldName: "opType",
|
|
499
|
+
type: "CHOICE_SET_SINGLE",
|
|
500
|
+
choiceSetId: "9db00b66-9952-f111-8ef3-6045bd07956d",
|
|
501
|
+
}),
|
|
502
|
+
]),
|
|
503
|
+
undefined,
|
|
504
|
+
);
|
|
505
|
+
expect(OutputFormatter.success).toHaveBeenCalledWith(
|
|
506
|
+
expect.objectContaining({ Code: "EntityCreated" }),
|
|
507
|
+
);
|
|
508
|
+
});
|
|
509
|
+
|
|
510
|
+
it("should create entity with a CHOICE_SET_MULTIPLE field carrying choiceSetId", async () => {
|
|
511
|
+
const sdk = mockSdk();
|
|
512
|
+
vi.mocked(sdk.entities.create).mockResolvedValue("entity-choice-multi");
|
|
513
|
+
const fields = [
|
|
514
|
+
{
|
|
515
|
+
fieldName: "multiOpType",
|
|
516
|
+
type: "CHOICE_SET_MULTIPLE",
|
|
517
|
+
choiceSetId: "9db00b66-9952-f111-8ef3-6045bd07956d",
|
|
518
|
+
},
|
|
519
|
+
];
|
|
520
|
+
vi.mocked(readJsonInput).mockResolvedValue({ fields });
|
|
521
|
+
|
|
522
|
+
const program = buildProgram();
|
|
523
|
+
await program.parseAsync([
|
|
524
|
+
"node",
|
|
525
|
+
"test",
|
|
526
|
+
"entities",
|
|
527
|
+
"create",
|
|
528
|
+
"CliTestExpense",
|
|
529
|
+
"--body",
|
|
530
|
+
JSON.stringify({ fields }),
|
|
531
|
+
]);
|
|
532
|
+
|
|
533
|
+
expect(sdk.entities.create).toHaveBeenCalledWith(
|
|
534
|
+
"CliTestExpense",
|
|
535
|
+
expect.arrayContaining([
|
|
536
|
+
expect.objectContaining({
|
|
537
|
+
fieldName: "multiOpType",
|
|
538
|
+
type: "CHOICE_SET_MULTIPLE",
|
|
539
|
+
choiceSetId: "9db00b66-9952-f111-8ef3-6045bd07956d",
|
|
540
|
+
}),
|
|
541
|
+
]),
|
|
542
|
+
undefined,
|
|
543
|
+
);
|
|
544
|
+
expect(OutputFormatter.success).toHaveBeenCalledWith(
|
|
545
|
+
expect.objectContaining({ Code: "EntityCreated" }),
|
|
546
|
+
);
|
|
547
|
+
});
|
|
548
|
+
|
|
549
|
+
it("should create entity with a RELATIONSHIP field carrying referenceEntityName and referenceFieldName", async () => {
|
|
550
|
+
const sdk = mockSdk();
|
|
551
|
+
vi.mocked(sdk.entities.create).mockResolvedValue("entity-rel");
|
|
552
|
+
const fields = [
|
|
553
|
+
{
|
|
554
|
+
fieldName: "rel1",
|
|
555
|
+
type: "RELATIONSHIP",
|
|
556
|
+
referenceEntityName: "CodeEvalTestEntity",
|
|
557
|
+
referenceFieldName: "Email",
|
|
558
|
+
},
|
|
559
|
+
];
|
|
560
|
+
vi.mocked(readJsonInput).mockResolvedValue({ fields });
|
|
561
|
+
|
|
562
|
+
const program = buildProgram();
|
|
563
|
+
await program.parseAsync([
|
|
564
|
+
"node",
|
|
565
|
+
"test",
|
|
566
|
+
"entities",
|
|
567
|
+
"create",
|
|
568
|
+
"CliTestExpense",
|
|
569
|
+
"--body",
|
|
570
|
+
JSON.stringify({ fields }),
|
|
571
|
+
]);
|
|
572
|
+
|
|
573
|
+
expect(sdk.entities.create).toHaveBeenCalledWith(
|
|
574
|
+
"CliTestExpense",
|
|
575
|
+
expect.arrayContaining([
|
|
576
|
+
expect.objectContaining({
|
|
577
|
+
fieldName: "rel1",
|
|
578
|
+
type: "RELATIONSHIP",
|
|
579
|
+
referenceEntityName: "CodeEvalTestEntity",
|
|
580
|
+
referenceFieldName: "Email",
|
|
581
|
+
}),
|
|
582
|
+
]),
|
|
583
|
+
undefined,
|
|
584
|
+
);
|
|
585
|
+
expect(OutputFormatter.success).toHaveBeenCalledWith(
|
|
586
|
+
expect.objectContaining({ Code: "EntityCreated" }),
|
|
587
|
+
);
|
|
588
|
+
});
|
|
589
|
+
|
|
468
590
|
it("should error when no --body or --file provided", async () => {
|
|
469
591
|
vi.mocked(readJsonInput).mockRejectedValue(
|
|
470
592
|
new Error("Provide entity definition via --file or --body."),
|
|
@@ -684,6 +806,69 @@ describe("entities update", () => {
|
|
|
684
806
|
);
|
|
685
807
|
});
|
|
686
808
|
|
|
809
|
+
it("should update entity by adding a RELATIONSHIP field with referenceFieldName=Email", async () => {
|
|
810
|
+
const sdk = mockSdk();
|
|
811
|
+
const addFields = [
|
|
812
|
+
{
|
|
813
|
+
fieldName: "rel1",
|
|
814
|
+
type: "RELATIONSHIP",
|
|
815
|
+
referenceEntityName: "CodeEvalTestEntity",
|
|
816
|
+
referenceFieldName: "Email",
|
|
817
|
+
},
|
|
818
|
+
];
|
|
819
|
+
vi.mocked(readJsonInput).mockResolvedValue({ addFields });
|
|
820
|
+
|
|
821
|
+
const program = buildProgram();
|
|
822
|
+
await program.parseAsync([
|
|
823
|
+
"node",
|
|
824
|
+
"test",
|
|
825
|
+
"entities",
|
|
826
|
+
"update",
|
|
827
|
+
"entity-id",
|
|
828
|
+
"--body",
|
|
829
|
+
JSON.stringify({ addFields }),
|
|
830
|
+
]);
|
|
831
|
+
|
|
832
|
+
expect(sdk.entities.updateById).toHaveBeenCalledWith(
|
|
833
|
+
"entity-id",
|
|
834
|
+
expect.objectContaining({ addFields }),
|
|
835
|
+
);
|
|
836
|
+
expect(OutputFormatter.success).toHaveBeenCalledWith(
|
|
837
|
+
expect.objectContaining({ Code: "EntityUpdated" }),
|
|
838
|
+
);
|
|
839
|
+
});
|
|
840
|
+
|
|
841
|
+
it("should update entity by adding a CHOICE_SET_MULTIPLE field with choiceSetId", async () => {
|
|
842
|
+
const sdk = mockSdk();
|
|
843
|
+
const addFields = [
|
|
844
|
+
{
|
|
845
|
+
fieldName: "multiOpType",
|
|
846
|
+
type: "CHOICE_SET_MULTIPLE",
|
|
847
|
+
choiceSetId: "9db00b66-9952-f111-8ef3-6045bd07956d",
|
|
848
|
+
},
|
|
849
|
+
];
|
|
850
|
+
vi.mocked(readJsonInput).mockResolvedValue({ addFields });
|
|
851
|
+
|
|
852
|
+
const program = buildProgram();
|
|
853
|
+
await program.parseAsync([
|
|
854
|
+
"node",
|
|
855
|
+
"test",
|
|
856
|
+
"entities",
|
|
857
|
+
"update",
|
|
858
|
+
"entity-id",
|
|
859
|
+
"--body",
|
|
860
|
+
JSON.stringify({ addFields }),
|
|
861
|
+
]);
|
|
862
|
+
|
|
863
|
+
expect(sdk.entities.updateById).toHaveBeenCalledWith(
|
|
864
|
+
"entity-id",
|
|
865
|
+
expect.objectContaining({ addFields }),
|
|
866
|
+
);
|
|
867
|
+
expect(OutputFormatter.success).toHaveBeenCalledWith(
|
|
868
|
+
expect.objectContaining({ Code: "EntityUpdated" }),
|
|
869
|
+
);
|
|
870
|
+
});
|
|
871
|
+
|
|
687
872
|
it("should update entity by modifying existing fields (updateFields)", async () => {
|
|
688
873
|
const sdk = mockSdk();
|
|
689
874
|
vi.mocked(readJsonInput).mockResolvedValue({
|
|
@@ -727,6 +912,182 @@ describe("entities update", () => {
|
|
|
727
912
|
);
|
|
728
913
|
});
|
|
729
914
|
|
|
915
|
+
it("should update displayName on a CHOICE_SET_SINGLE field via updateFields", async () => {
|
|
916
|
+
const sdk = mockSdk();
|
|
917
|
+
const updateFields = [
|
|
918
|
+
{
|
|
919
|
+
id: "f9ccd648-ac52-f111-8ef3-6045bd07956d",
|
|
920
|
+
displayName: "Operator Type",
|
|
921
|
+
},
|
|
922
|
+
];
|
|
923
|
+
vi.mocked(readJsonInput).mockResolvedValue({ updateFields });
|
|
924
|
+
|
|
925
|
+
const program = buildProgram();
|
|
926
|
+
await program.parseAsync([
|
|
927
|
+
"node",
|
|
928
|
+
"test",
|
|
929
|
+
"entities",
|
|
930
|
+
"update",
|
|
931
|
+
"entity-id",
|
|
932
|
+
"--body",
|
|
933
|
+
JSON.stringify({ updateFields }),
|
|
934
|
+
]);
|
|
935
|
+
|
|
936
|
+
expect(sdk.entities.updateById).toHaveBeenCalledWith(
|
|
937
|
+
"entity-id",
|
|
938
|
+
expect.objectContaining({ updateFields }),
|
|
939
|
+
);
|
|
940
|
+
expect(OutputFormatter.success).toHaveBeenCalledWith(
|
|
941
|
+
expect.objectContaining({ Code: "EntityUpdated" }),
|
|
942
|
+
);
|
|
943
|
+
});
|
|
944
|
+
|
|
945
|
+
it("should update displayName and isRequired on a CHOICE_SET_MULTIPLE field via updateFields", async () => {
|
|
946
|
+
const sdk = mockSdk();
|
|
947
|
+
const updateFields = [
|
|
948
|
+
{
|
|
949
|
+
id: "8750af08-b252-f111-8ef3-6045bd07956d",
|
|
950
|
+
displayName: "Multi Operator Types",
|
|
951
|
+
isRequired: true,
|
|
952
|
+
},
|
|
953
|
+
];
|
|
954
|
+
vi.mocked(readJsonInput).mockResolvedValue({ updateFields });
|
|
955
|
+
|
|
956
|
+
const program = buildProgram();
|
|
957
|
+
await program.parseAsync([
|
|
958
|
+
"node",
|
|
959
|
+
"test",
|
|
960
|
+
"entities",
|
|
961
|
+
"update",
|
|
962
|
+
"entity-id",
|
|
963
|
+
"--body",
|
|
964
|
+
JSON.stringify({ updateFields }),
|
|
965
|
+
]);
|
|
966
|
+
|
|
967
|
+
expect(sdk.entities.updateById).toHaveBeenCalledWith(
|
|
968
|
+
"entity-id",
|
|
969
|
+
expect.objectContaining({ updateFields }),
|
|
970
|
+
);
|
|
971
|
+
expect(OutputFormatter.success).toHaveBeenCalledWith(
|
|
972
|
+
expect.objectContaining({ Code: "EntityUpdated" }),
|
|
973
|
+
);
|
|
974
|
+
});
|
|
975
|
+
|
|
976
|
+
it("should remove a CHOICE_SET_SINGLE field via removeFields with --confirm and --reason", async () => {
|
|
977
|
+
const sdk = mockSdk();
|
|
978
|
+
vi.mocked(readJsonInput).mockResolvedValue({
|
|
979
|
+
removeFields: [{ fieldName: "opType" }],
|
|
980
|
+
});
|
|
981
|
+
|
|
982
|
+
const program = buildProgram();
|
|
983
|
+
await program.parseAsync([
|
|
984
|
+
"node",
|
|
985
|
+
"test",
|
|
986
|
+
"entities",
|
|
987
|
+
"update",
|
|
988
|
+
"entity-id",
|
|
989
|
+
"--body",
|
|
990
|
+
'{"removeFields":[{"fieldName":"opType"}]}',
|
|
991
|
+
"--confirm",
|
|
992
|
+
"--reason",
|
|
993
|
+
"dropping single-select choice-set field",
|
|
994
|
+
]);
|
|
995
|
+
|
|
996
|
+
expect(sdk.entities.updateById).toHaveBeenCalledWith(
|
|
997
|
+
"entity-id",
|
|
998
|
+
expect.objectContaining({
|
|
999
|
+
removeFields: [{ fieldName: "opType" }],
|
|
1000
|
+
}),
|
|
1001
|
+
);
|
|
1002
|
+
expect(OutputFormatter.success).toHaveBeenCalledWith(
|
|
1003
|
+
expect.objectContaining({
|
|
1004
|
+
Result: "Success",
|
|
1005
|
+
Code: "EntityUpdated",
|
|
1006
|
+
Data: expect.objectContaining({
|
|
1007
|
+
RemovedFields: ["opType"],
|
|
1008
|
+
Reason: "dropping single-select choice-set field",
|
|
1009
|
+
}),
|
|
1010
|
+
}),
|
|
1011
|
+
);
|
|
1012
|
+
});
|
|
1013
|
+
|
|
1014
|
+
it("should remove a CHOICE_SET_MULTIPLE field via removeFields with --confirm and --reason", async () => {
|
|
1015
|
+
const sdk = mockSdk();
|
|
1016
|
+
vi.mocked(readJsonInput).mockResolvedValue({
|
|
1017
|
+
removeFields: [{ fieldName: "multiOpType" }],
|
|
1018
|
+
});
|
|
1019
|
+
|
|
1020
|
+
const program = buildProgram();
|
|
1021
|
+
await program.parseAsync([
|
|
1022
|
+
"node",
|
|
1023
|
+
"test",
|
|
1024
|
+
"entities",
|
|
1025
|
+
"update",
|
|
1026
|
+
"entity-id",
|
|
1027
|
+
"--body",
|
|
1028
|
+
'{"removeFields":[{"fieldName":"multiOpType"}]}',
|
|
1029
|
+
"--confirm",
|
|
1030
|
+
"--reason",
|
|
1031
|
+
"dropping multi-select choice-set field",
|
|
1032
|
+
]);
|
|
1033
|
+
|
|
1034
|
+
expect(sdk.entities.updateById).toHaveBeenCalledWith(
|
|
1035
|
+
"entity-id",
|
|
1036
|
+
expect.objectContaining({
|
|
1037
|
+
removeFields: [{ fieldName: "multiOpType" }],
|
|
1038
|
+
}),
|
|
1039
|
+
);
|
|
1040
|
+
expect(OutputFormatter.success).toHaveBeenCalledWith(
|
|
1041
|
+
expect.objectContaining({
|
|
1042
|
+
Data: expect.objectContaining({
|
|
1043
|
+
RemovedFields: ["multiOpType"],
|
|
1044
|
+
Reason: "dropping multi-select choice-set field",
|
|
1045
|
+
}),
|
|
1046
|
+
}),
|
|
1047
|
+
);
|
|
1048
|
+
});
|
|
1049
|
+
|
|
1050
|
+
it("should remove both choice-set fields in a single removeFields call", async () => {
|
|
1051
|
+
const sdk = mockSdk();
|
|
1052
|
+
vi.mocked(readJsonInput).mockResolvedValue({
|
|
1053
|
+
removeFields: [
|
|
1054
|
+
{ fieldName: "opType" },
|
|
1055
|
+
{ fieldName: "multiOpType" },
|
|
1056
|
+
],
|
|
1057
|
+
});
|
|
1058
|
+
|
|
1059
|
+
const program = buildProgram();
|
|
1060
|
+
await program.parseAsync([
|
|
1061
|
+
"node",
|
|
1062
|
+
"test",
|
|
1063
|
+
"entities",
|
|
1064
|
+
"update",
|
|
1065
|
+
"entity-id",
|
|
1066
|
+
"--body",
|
|
1067
|
+
'{"removeFields":[{"fieldName":"opType"},{"fieldName":"multiOpType"}]}',
|
|
1068
|
+
"--confirm",
|
|
1069
|
+
"--reason",
|
|
1070
|
+
"dropping all choice-set fields",
|
|
1071
|
+
]);
|
|
1072
|
+
|
|
1073
|
+
expect(sdk.entities.updateById).toHaveBeenCalledWith(
|
|
1074
|
+
"entity-id",
|
|
1075
|
+
expect.objectContaining({
|
|
1076
|
+
removeFields: [
|
|
1077
|
+
{ fieldName: "opType" },
|
|
1078
|
+
{ fieldName: "multiOpType" },
|
|
1079
|
+
],
|
|
1080
|
+
}),
|
|
1081
|
+
);
|
|
1082
|
+
expect(OutputFormatter.success).toHaveBeenCalledWith(
|
|
1083
|
+
expect.objectContaining({
|
|
1084
|
+
Data: expect.objectContaining({
|
|
1085
|
+
RemovedFields: ["opType", "multiOpType"],
|
|
1086
|
+
}),
|
|
1087
|
+
}),
|
|
1088
|
+
);
|
|
1089
|
+
});
|
|
1090
|
+
|
|
730
1091
|
it("should update entity metadata only (displayName and description)", async () => {
|
|
731
1092
|
const sdk = mockSdk();
|
|
732
1093
|
vi.mocked(readJsonInput).mockResolvedValue({
|