@uipath/data-fabric-tool 1.201.0-preview.115 → 1.201.0-preview.121
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/index.js +1 -1
- package/dist/{tool-cyfkvxhw.js → tool-4g47skgm.js} +1059 -373
- package/dist/tool.js +1 -1
- package/package.json +2 -2
- package/src/commands/directory.ts +21 -22
- package/src/commands/entities.spec.ts +513 -112
- package/src/commands/entities.ts +402 -160
- package/src/commands/roles.ts +8 -6
- package/src/utils/output.spec.ts +21 -1
- package/src/utils/output.ts +22 -1
- package/src/utils/validate.spec.ts +57 -62
- package/src/utils/validate.ts +12 -16
- package/tests/entities-lifecycle.e2e.test.ts +92 -17
- package/tests/files-management.e2e.test.ts +2 -2
- package/tests/records-management.e2e.test.ts +1 -1
|
@@ -143,7 +143,7 @@ describe("df entities — entities lifecycle", () => {
|
|
|
143
143
|
"create",
|
|
144
144
|
scratchName,
|
|
145
145
|
"--body",
|
|
146
|
-
'{"fields":[{"
|
|
146
|
+
'{"fields":[{"name":"note","type":"STRING"}]}',
|
|
147
147
|
]);
|
|
148
148
|
if (isAuthDenial(create)) {
|
|
149
149
|
dfAccessDenied = true;
|
|
@@ -168,7 +168,7 @@ describe("df entities — entities lifecycle", () => {
|
|
|
168
168
|
"--folder-key",
|
|
169
169
|
scratchFolderKey,
|
|
170
170
|
"--body",
|
|
171
|
-
'{"fields":[{"
|
|
171
|
+
'{"fields":[{"name":"note","type":"STRING"}]}',
|
|
172
172
|
]);
|
|
173
173
|
if (createFolderEntity.exitCode === 0) {
|
|
174
174
|
folderScopedEntityId = (
|
|
@@ -322,7 +322,7 @@ describe("df entities — entities lifecycle", () => {
|
|
|
322
322
|
"create",
|
|
323
323
|
name,
|
|
324
324
|
"--body",
|
|
325
|
-
'{"fields":[{"
|
|
325
|
+
'{"fields":[{"name":"amount","type":"DECIMAL","decimalPrecision":2}]}',
|
|
326
326
|
]);
|
|
327
327
|
try {
|
|
328
328
|
expect(created.Result).toBe("Success");
|
|
@@ -364,13 +364,13 @@ describe("df entities — entities lifecycle", () => {
|
|
|
364
364
|
message: "Entity definition must include a 'fields' array",
|
|
365
365
|
},
|
|
366
366
|
{
|
|
367
|
-
label: "field without
|
|
367
|
+
label: "field without name",
|
|
368
368
|
body: '{"fields":[{"type":"STRING"}]}',
|
|
369
|
-
message: "Each field must include a '
|
|
369
|
+
message: "Each field must include a 'name' string",
|
|
370
370
|
},
|
|
371
371
|
{
|
|
372
372
|
label: "unknown field type",
|
|
373
|
-
body: '{"fields":[{"
|
|
373
|
+
body: '{"fields":[{"name":"amount","type":"NOT_A_TYPE"}]}',
|
|
374
374
|
message: "Invalid field type in fields",
|
|
375
375
|
},
|
|
376
376
|
];
|
|
@@ -388,7 +388,7 @@ describe("df entities — entities lifecycle", () => {
|
|
|
388
388
|
|
|
389
389
|
// ── S9 ── update composition on a transient scratch ─────────────────────
|
|
390
390
|
it(
|
|
391
|
-
"S9: update adds, edits,
|
|
391
|
+
"S9: update adds, edits, removes fields, and normalizes read-shaped add fields",
|
|
392
392
|
(ctx) => {
|
|
393
393
|
if (dfAccessDenied) return ctx.skip();
|
|
394
394
|
const name = `${scratchName}S9`;
|
|
@@ -397,7 +397,7 @@ describe("df entities — entities lifecycle", () => {
|
|
|
397
397
|
"create",
|
|
398
398
|
name,
|
|
399
399
|
"--body",
|
|
400
|
-
'{"fields":[{"
|
|
400
|
+
'{"fields":[{"name":"oldColumn","type":"STRING"},{"name":"sourceNote","type":"STRING","lengthLimit":512}]}',
|
|
401
401
|
]);
|
|
402
402
|
const id: string = created.Data.Id;
|
|
403
403
|
try {
|
|
@@ -407,11 +407,11 @@ describe("df entities — entities lifecycle", () => {
|
|
|
407
407
|
);
|
|
408
408
|
if (!oldField) throw new Error("scratch missing 'oldColumn'");
|
|
409
409
|
const body = JSON.stringify({
|
|
410
|
-
addFields: [{
|
|
410
|
+
addFields: [{ name: "status", type: "STRING" }],
|
|
411
411
|
updateFields: [
|
|
412
412
|
{ id: oldField.Id, displayName: "Old Column" },
|
|
413
413
|
],
|
|
414
|
-
removeFields: [{
|
|
414
|
+
removeFields: [{ name: "oldColumn" }],
|
|
415
415
|
});
|
|
416
416
|
const updated = cli([
|
|
417
417
|
"entities",
|
|
@@ -428,6 +428,34 @@ describe("df entities — entities lifecycle", () => {
|
|
|
428
428
|
expect(updated.Data.Id).toBe(id);
|
|
429
429
|
expect(updated.Data.RemovedFields).toContain("oldColumn");
|
|
430
430
|
expect(updated.Data.Reason).toBe("S9 composition test");
|
|
431
|
+
|
|
432
|
+
const sourceNoteField = (schema.Data.Fields as Json[]).find(
|
|
433
|
+
(field) => field.Name === "sourceNote",
|
|
434
|
+
);
|
|
435
|
+
if (!sourceNoteField)
|
|
436
|
+
throw new Error("scratch missing 'sourceNote'");
|
|
437
|
+
const readShapeAddField = {
|
|
438
|
+
...sourceNoteField,
|
|
439
|
+
Name: "note",
|
|
440
|
+
DisplayName: "Note",
|
|
441
|
+
};
|
|
442
|
+
|
|
443
|
+
const readShapeUpdated = cli([
|
|
444
|
+
"entities",
|
|
445
|
+
"update",
|
|
446
|
+
id,
|
|
447
|
+
"--body",
|
|
448
|
+
JSON.stringify({ addFields: [readShapeAddField] }),
|
|
449
|
+
]);
|
|
450
|
+
expect(readShapeUpdated.Result).toBe("Success");
|
|
451
|
+
expect(readShapeUpdated.Code).toBe("EntityUpdated");
|
|
452
|
+
|
|
453
|
+
const afterReadShape = cli(["entities", "get", id]);
|
|
454
|
+
const noteField = (afterReadShape.Data.Fields as Json[]).find(
|
|
455
|
+
(field) => field.Name === "note",
|
|
456
|
+
);
|
|
457
|
+
expect(noteField?.FieldDataType?.Name).toBe("STRING");
|
|
458
|
+
expect(noteField?.FieldDataType?.LengthLimit).toBe(512);
|
|
431
459
|
} finally {
|
|
432
460
|
runDf([
|
|
433
461
|
"entities",
|
|
@@ -452,7 +480,7 @@ describe("df entities — entities lifecycle", () => {
|
|
|
452
480
|
message: string;
|
|
453
481
|
}> = [
|
|
454
482
|
{
|
|
455
|
-
label: "addFields missing
|
|
483
|
+
label: "addFields missing name",
|
|
456
484
|
argv: [
|
|
457
485
|
"entities",
|
|
458
486
|
"update",
|
|
@@ -461,7 +489,7 @@ describe("df entities — entities lifecycle", () => {
|
|
|
461
489
|
'{"addFields":[{"type":"STRING"}]}',
|
|
462
490
|
],
|
|
463
491
|
message:
|
|
464
|
-
"Each field in addFields must include a non-empty '
|
|
492
|
+
"Each field in addFields must include a non-empty 'name' string",
|
|
465
493
|
},
|
|
466
494
|
{
|
|
467
495
|
label: "updateFields missing id",
|
|
@@ -476,13 +504,13 @@ describe("df entities — entities lifecycle", () => {
|
|
|
476
504
|
"Each field in updateFields must include a non-empty 'id' string",
|
|
477
505
|
},
|
|
478
506
|
{
|
|
479
|
-
label: "duplicate
|
|
507
|
+
label: "duplicate name in addFields",
|
|
480
508
|
argv: [
|
|
481
509
|
"entities",
|
|
482
510
|
"update",
|
|
483
511
|
"pre-network",
|
|
484
512
|
"--body",
|
|
485
|
-
'{"addFields":[{"
|
|
513
|
+
'{"addFields":[{"name":"duplicate","type":"STRING"},{"name":"DUPLICATE","type":"STRING"}]}',
|
|
486
514
|
],
|
|
487
515
|
message:
|
|
488
516
|
"Duplicate field name 'DUPLICATE' (case-insensitive)",
|
|
@@ -494,7 +522,7 @@ describe("df entities — entities lifecycle", () => {
|
|
|
494
522
|
"update",
|
|
495
523
|
"pre-network",
|
|
496
524
|
"--body",
|
|
497
|
-
'{"addFields":[{"
|
|
525
|
+
'{"addFields":[{"name":"col","type":"STRING"}],"removeFields":[{"name":"col"}]}',
|
|
498
526
|
"--yes",
|
|
499
527
|
"--reason",
|
|
500
528
|
"x",
|
|
@@ -502,12 +530,57 @@ describe("df entities — entities lifecycle", () => {
|
|
|
502
530
|
message:
|
|
503
531
|
"Field 'col' appears in both addFields and removeFields",
|
|
504
532
|
},
|
|
533
|
+
{
|
|
534
|
+
label: "name is immutable",
|
|
535
|
+
argv: [
|
|
536
|
+
"entities",
|
|
537
|
+
"update",
|
|
538
|
+
"pre-network",
|
|
539
|
+
"--body",
|
|
540
|
+
'{"name":"Renamed","displayName":"Renamed"}',
|
|
541
|
+
],
|
|
542
|
+
message: "Entity name cannot be changed after creation",
|
|
543
|
+
},
|
|
544
|
+
{
|
|
545
|
+
label: "metadata update without displayName",
|
|
546
|
+
argv: [
|
|
547
|
+
"entities",
|
|
548
|
+
"update",
|
|
549
|
+
"pre-network",
|
|
550
|
+
"--body",
|
|
551
|
+
'{"description":"New description"}',
|
|
552
|
+
],
|
|
553
|
+
message:
|
|
554
|
+
"'displayName' is required when updating entity metadata",
|
|
555
|
+
},
|
|
505
556
|
];
|
|
506
557
|
|
|
507
558
|
for (const row of rows) {
|
|
508
559
|
const parsed = expectFailure(runDf(row.argv), row.label);
|
|
509
560
|
expect(parsed.Message, row.label).toBe(row.message);
|
|
561
|
+
expect(parsed.ErrorCode, row.label).toBe("invalid_argument");
|
|
510
562
|
}
|
|
563
|
+
|
|
564
|
+
const aggregate = expectFailure(
|
|
565
|
+
runDf([
|
|
566
|
+
"entities",
|
|
567
|
+
"update",
|
|
568
|
+
"pre-network",
|
|
569
|
+
"--body",
|
|
570
|
+
'{"addFields":[{"type":"STRING"}],"removeFields":["code"]}',
|
|
571
|
+
"--yes",
|
|
572
|
+
"--reason",
|
|
573
|
+
"temporary validation",
|
|
574
|
+
]),
|
|
575
|
+
"aggregate addFields and removeFields errors",
|
|
576
|
+
);
|
|
577
|
+
expect(aggregate.Message).toContain(
|
|
578
|
+
"Each field in addFields must include a non-empty 'name' string",
|
|
579
|
+
);
|
|
580
|
+
expect(aggregate.Message).toContain(
|
|
581
|
+
"Each field in removeFields must include a non-empty 'name' string",
|
|
582
|
+
);
|
|
583
|
+
expect(aggregate.ErrorCode).toBe("invalid_argument");
|
|
511
584
|
},
|
|
512
585
|
EXEC_TIMEOUT,
|
|
513
586
|
);
|
|
@@ -516,7 +589,7 @@ describe("df entities — entities lifecycle", () => {
|
|
|
516
589
|
it(
|
|
517
590
|
"S11: update refuses removeFields without --yes and --reason",
|
|
518
591
|
() => {
|
|
519
|
-
const body = '{"removeFields":[{"
|
|
592
|
+
const body = '{"removeFields":[{"name":"oldColumn"}]}';
|
|
520
593
|
|
|
521
594
|
const noFlags = expectFailure(
|
|
522
595
|
runDf(["entities", "update", "pre-network", "--body", body]),
|
|
@@ -538,6 +611,7 @@ describe("df entities — entities lifecycle", () => {
|
|
|
538
611
|
expect(yesNoReason.Message).toBe(
|
|
539
612
|
"Reason required for destructive operation",
|
|
540
613
|
);
|
|
614
|
+
expect(yesNoReason.ErrorCode).toBe("invalid_argument");
|
|
541
615
|
|
|
542
616
|
const reasonNoYes = expectFailure(
|
|
543
617
|
runDf([
|
|
@@ -573,6 +647,7 @@ describe("df entities — entities lifecycle", () => {
|
|
|
573
647
|
expect(yesNoReason.Message).toBe(
|
|
574
648
|
"Reason required for destructive operation",
|
|
575
649
|
);
|
|
650
|
+
expect(yesNoReason.ErrorCode).toBe("invalid_argument");
|
|
576
651
|
|
|
577
652
|
const reasonNoYes = expectFailure(
|
|
578
653
|
runDf(["entities", "delete", "pre-network", "--reason", "x"]),
|
|
@@ -594,7 +669,7 @@ describe("df entities — entities lifecycle", () => {
|
|
|
594
669
|
"create",
|
|
595
670
|
name,
|
|
596
671
|
"--body",
|
|
597
|
-
'{"fields":[{"
|
|
672
|
+
'{"fields":[{"name":"note","type":"STRING"}]}',
|
|
598
673
|
]);
|
|
599
674
|
const id: string = created.Data.Id;
|
|
600
675
|
const deleted = cli([
|
|
@@ -152,7 +152,7 @@ describe("df files — file attachments management", () => {
|
|
|
152
152
|
"create",
|
|
153
153
|
scratchEntityName,
|
|
154
154
|
"--body",
|
|
155
|
-
`{"fields":[{"
|
|
155
|
+
`{"fields":[{"name":"note","type":"STRING"},{"name":"${FILE_FIELD}","type":"FILE"}]}`,
|
|
156
156
|
]);
|
|
157
157
|
if (isAuthDenial(createEntity)) {
|
|
158
158
|
dfAccessDenied = true;
|
|
@@ -191,7 +191,7 @@ describe("df files — file attachments management", () => {
|
|
|
191
191
|
"--folder-key",
|
|
192
192
|
scratchFolderKey,
|
|
193
193
|
"--body",
|
|
194
|
-
`{"fields":[{"
|
|
194
|
+
`{"fields":[{"name":"note","type":"STRING"},{"name":"${FILE_FIELD}","type":"FILE"}]}`,
|
|
195
195
|
]);
|
|
196
196
|
if (createFolderEntity.exitCode !== 0) return;
|
|
197
197
|
folderScopedEntityId = (extractJson(createFolderEntity.stdout) as Json)
|
|
@@ -156,7 +156,7 @@ describe("df records — records management", () => {
|
|
|
156
156
|
"create",
|
|
157
157
|
scratchEntityName,
|
|
158
158
|
"--body",
|
|
159
|
-
'{"fields":[{"
|
|
159
|
+
'{"fields":[{"name":"note","type":"STRING"},{"name":"amount","type":"DECIMAL","decimalPrecision":2},{"name":"status","type":"STRING"}]}',
|
|
160
160
|
]);
|
|
161
161
|
if (isAuthDenial(createEntity)) {
|
|
162
162
|
dfAccessDenied = true;
|