zinkee 0.1.29 → 0.1.31

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.
@@ -63,7 +63,8 @@
63
63
  "Bash(./gradlew :api:spotbugsMain)",
64
64
  "Bash(./gradlew spotlessCheck)",
65
65
  "Bash(git --no-pager diff --stat)",
66
- "Bash(git --no-pager diff -- src/commands/records.ts src/api/records.ts)"
66
+ "Bash(git --no-pager diff -- src/commands/records.ts src/api/records.ts)",
67
+ "Bash(echo \"===EXIT: $?===\")"
67
68
  ]
68
69
  }
69
70
  }
package/AGENTS.md CHANGED
@@ -48,6 +48,19 @@ Use this order when reasoning about behavior:
48
48
  - parsers live in `src/parsers`
49
49
  - shell completion (engine, scripts, install, runtime) lives in `src/completion`
50
50
 
51
+ ## API Examples (`--example`)
52
+
53
+ - `--example` output comes 100% from hand-written `src/utils/examples.ts`
54
+ (`specificExamples`, keyed by command path e.g. `"schemas update"`). No
55
+ codegen, no OpenAPI import.
56
+ - These MIRROR the swagger `@ExampleObject`s in the `z2-backend` repo
57
+ (`api/src/main/java/com/zinkee/api/infra/web/v2/ApiV2<Resource>Documentation.java`).
58
+ When you add/change an example on either side, update the other with the same
59
+ payload (request `raw` and `response`). Nothing keeps them in sync
60
+ automatically.
61
+ - Keep `response` shapes aligned with the backend DTO field order (e.g.
62
+ `SchemaV2ResourceResponse`: `… commentable, highlightedField, fields`).
63
+
51
64
  ## Testing
52
65
 
53
66
  Prefer focused command tests and parser/client unit tests.
package/README.md CHANGED
@@ -248,6 +248,30 @@ date_format(44b72f55-3fc3-40f4-88bb-343bb4a6270c, "AAAA-MM")
248
248
  - Functions: `concat`, `if`, `date_format`, `datetime_diff`, arithmetic (`+`,`-`,`*`,`/`)
249
249
  - Invalid formulas are created with status `DRAFT` and evaluate to `null`
250
250
 
251
+ ### Set unique fields
252
+
253
+ Define a composite unique constraint: the listed fields must be unique **together**
254
+ across the schema's records. `--field` accepts a field UUID or slug and is repeatable;
255
+ the order you pass them is the order of the constraint.
256
+
257
+ ```bash
258
+ # Single field must be unique
259
+ zinkee schemas set-unique-fields contacts --field email
260
+
261
+ # Composite: the (contact-name, notes) combination must be unique
262
+ zinkee schemas set-unique-fields contacts --field contact-name --field notes
263
+
264
+ # Remove the unique constraint
265
+ zinkee schemas set-unique-fields contacts --clear
266
+ ```
267
+
268
+ Notes:
269
+
270
+ - Pass either one or more `--field`, or `--clear` — not both, and not neither.
271
+ - Every `--field` must already exist in the schema, otherwise the command fails.
272
+ - If existing records already violate the requested constraint, the backend rejects
273
+ it with `409 Conflict`.
274
+
251
275
  ---
252
276
 
253
277
  ## Records
package/dist/index.js CHANGED
@@ -667,6 +667,13 @@ var commandRegistry = {
667
667
  supportsRaw: false,
668
668
  output: writeOutput
669
669
  },
670
+ "schemas set-unique-fields": {
671
+ command: "schemas set-unique-fields",
672
+ accessLevel: "write",
673
+ supportsExample: true,
674
+ supportsRaw: false,
675
+ output: writeOutput
676
+ },
670
677
  "schemas delete": {
671
678
  command: "schemas delete",
672
679
  accessLevel: "destructive",
@@ -2402,6 +2409,7 @@ var specificExamples = {
2402
2409
  },
2403
2410
  "auditable": true,
2404
2411
  "commentable": true,
2412
+ "highlightedField": "c60b8526-5835-4c9f-aecd-9a16c7704a34",
2405
2413
  "fields": [
2406
2414
  {
2407
2415
  "id": "c60b8526-5835-4c9f-aecd-9a16c7704a34",
@@ -2416,7 +2424,8 @@ var specificExamples = {
2416
2424
  "conditionalFormatting": []
2417
2425
  }
2418
2426
  }
2419
- ]
2427
+ ],
2428
+ "uniqueFields": []
2420
2429
  }`
2421
2430
  },
2422
2431
  {
@@ -2432,6 +2441,86 @@ var specificExamples = {
2432
2441
  command: "zinkee --json schemas update contacts --auditable true",
2433
2442
  raw: `{
2434
2443
  "auditable": true
2444
+ }`
2445
+ },
2446
+ {
2447
+ description: "Set the highlighted (main) field of a schema.",
2448
+ command: "zinkee --json schemas update contacts --highlighted-field contact-name",
2449
+ raw: `{
2450
+ "highlightedField": "c60b8526-5835-4c9f-aecd-9a16c7704a34"
2451
+ }`
2452
+ }
2453
+ ]),
2454
+ "schemas set-unique-fields": buildCommandExamples([
2455
+ {
2456
+ description: "Set a composite unique constraint: the listed fields must be unique together across records.",
2457
+ command: "zinkee --json schemas set-unique-fields contacts --field contact-name --field notes",
2458
+ raw: `{
2459
+ "fieldIds": [
2460
+ "c60b8526-5835-4c9f-aecd-9a16c7704a34",
2461
+ "1d2e3f4a-5b6c-7d8e-9f01-23456789abcd"
2462
+ ]
2463
+ }`,
2464
+ response: `{
2465
+ "id": "2eb8bdcf-6d9c-4fbb-9018-7fa8180f4c5e",
2466
+ "name": "Contacts",
2467
+ "slug": "contacts",
2468
+ "folder": {
2469
+ "id": "7f4e7c25-d8b2-4c1a-9f3e-6a7b5c8d9e1f",
2470
+ "name": "Customers",
2471
+ "isRoot": false
2472
+ },
2473
+ "auditable": true,
2474
+ "commentable": true,
2475
+ "highlightedField": "c60b8526-5835-4c9f-aecd-9a16c7704a34",
2476
+ "fields": [
2477
+ {
2478
+ "id": "c60b8526-5835-4c9f-aecd-9a16c7704a34",
2479
+ "type": "TextField",
2480
+ "slug": "contact-name",
2481
+ "label": "Customer Name",
2482
+ "required": true,
2483
+ "system": false,
2484
+ "config": {
2485
+ "textType": "NORMAL",
2486
+ "defaultValue": "Unknown",
2487
+ "conditionalFormatting": []
2488
+ }
2489
+ },
2490
+ {
2491
+ "id": "1d2e3f4a-5b6c-7d8e-9f01-23456789abcd",
2492
+ "type": "TextField",
2493
+ "slug": "notes",
2494
+ "label": "Notes",
2495
+ "required": false,
2496
+ "system": false,
2497
+ "config": {
2498
+ "textType": "LONG",
2499
+ "defaultValue": null,
2500
+ "conditionalFormatting": []
2501
+ }
2502
+ }
2503
+ ],
2504
+ "uniqueFields": [
2505
+ "c60b8526-5835-4c9f-aecd-9a16c7704a34",
2506
+ "1d2e3f4a-5b6c-7d8e-9f01-23456789abcd"
2507
+ ]
2508
+ }`
2509
+ },
2510
+ {
2511
+ description: "Set a single-field unique constraint.",
2512
+ command: "zinkee --json schemas set-unique-fields contacts --field contact-name",
2513
+ raw: `{
2514
+ "fieldIds": [
2515
+ "c60b8526-5835-4c9f-aecd-9a16c7704a34"
2516
+ ]
2517
+ }`
2518
+ },
2519
+ {
2520
+ description: "Clear the unique constraint (no field must be unique anymore).",
2521
+ command: "zinkee --json schemas set-unique-fields contacts --clear",
2522
+ raw: `{
2523
+ "fieldIds": []
2435
2524
  }`
2436
2525
  }
2437
2526
  ]),
@@ -3973,6 +4062,7 @@ var specificExamples = {
3973
4062
  },
3974
4063
  "auditable": true,
3975
4064
  "commentable": true,
4065
+ "highlightedField": "c60b8526-5835-4c9f-aecd-9a16c7704a34",
3976
4066
  "fields": [
3977
4067
  {
3978
4068
  "id": "c60b8526-5835-4c9f-aecd-9a16c7704a34",
@@ -4281,6 +4371,10 @@ var specificExamples = {
4281
4371
  "conditionalFormatting": []
4282
4372
  }
4283
4373
  }
4374
+ ],
4375
+ "uniqueFields": [
4376
+ "c60b8526-5835-4c9f-aecd-9a16c7704a34",
4377
+ "1d2e3f4a-5b6c-7d8e-9f01-23456789abcd"
4284
4378
  ]
4285
4379
  }`
4286
4380
  }
@@ -10711,6 +10805,12 @@ var SchemasApi = class {
10711
10805
  jsonOptions7(input, "PATCH")
10712
10806
  );
10713
10807
  }
10808
+ setUniqueFields(schema, input) {
10809
+ return this.client.requestJson(
10810
+ `/api/v2/schemas/${selectorValue9(schema)}/unique-fields`,
10811
+ jsonOptions7(input, "PUT")
10812
+ );
10813
+ }
10714
10814
  deleteSchema(schema) {
10715
10815
  return this.client.requestJson(
10716
10816
  `/api/v2/schemas/${selectorValue9(schema)}`,
@@ -11239,6 +11339,9 @@ function parseUuidOrSlugSelector9(input) {
11239
11339
  throw new InvalidArgumentError9(message);
11240
11340
  }
11241
11341
  }
11342
+ function collectFieldSelectors(value, previous = []) {
11343
+ return [...previous, parseUuidOrSlugSelector9(value)];
11344
+ }
11242
11345
  function parseBooleanFlag(input) {
11243
11346
  const normalized = input.trim().toLowerCase();
11244
11347
  if (["true", "1", "yes", "y", "on"].includes(normalized)) {
@@ -11498,15 +11601,27 @@ function registerSchemasCommands(program, options = {}) {
11498
11601
  }
11499
11602
  writeLine11(stdout, `Created schema "${data.slug ?? commandOptions.slug}".`);
11500
11603
  });
11501
- schemas.command("update").description("Update a schema").argument("<schema>", "schema uuid or slug", parseUuidOrSlugSelector9).option("--name <name>", "schema name").option("--slug <slug>", "schema slug").option("--auditable <bool>", "auditable flag", parseBooleanFlag).option("--commentable <bool>", "commentable flag", parseBooleanFlag).action(async function action(schema, commandOptions) {
11604
+ schemas.command("update").description("Update a schema").argument("<schema>", "schema uuid or slug", parseUuidOrSlugSelector9).option("--name <name>", "schema name").option("--slug <slug>", "schema slug").option("--auditable <bool>", "auditable flag", parseBooleanFlag).option("--commentable <bool>", "commentable flag", parseBooleanFlag).option(
11605
+ "--highlighted-field <field>",
11606
+ "highlighted (main) field uuid or slug",
11607
+ parseUuidOrSlugSelector9
11608
+ ).action(async function action(schema, commandOptions) {
11502
11609
  const { api, json, readOnly } = createSchemasApi(this, filePath);
11503
11610
  ensureWritable8("schemas update", readOnly, "write");
11504
11611
  const resolvedSchema = await resolveSchemaSelector2(api, schema);
11505
11612
  const input = buildSchemaUpdateInput(commandOptions);
11613
+ if (commandOptions.highlightedField !== void 0) {
11614
+ const resolvedField = await resolveFieldSelector(
11615
+ api,
11616
+ resolvedSchema,
11617
+ commandOptions.highlightedField
11618
+ );
11619
+ input.highlightedField = resolvedField.value;
11620
+ }
11506
11621
  if (isEmptyObject6(input)) {
11507
11622
  throw new CliError(
11508
11623
  "invalid_cli_usage",
11509
- 'Provide at least one schema field to update via "--name", "--slug", "--auditable", or "--commentable".'
11624
+ 'Provide at least one schema field to update via "--name", "--slug", "--auditable", "--commentable", or "--highlighted-field".'
11510
11625
  );
11511
11626
  }
11512
11627
  const data = await api.updateSchema(resolvedSchema, input);
@@ -11516,6 +11631,49 @@ function registerSchemasCommands(program, options = {}) {
11516
11631
  }
11517
11632
  writeLine11(stdout, `Updated schema "${data.slug ?? schema.value}".`);
11518
11633
  });
11634
+ schemas.command("set-unique-fields").description("Set or clear the composite unique-field constraint on a schema").argument("<schema>", "schema uuid or slug", parseUuidOrSlugSelector9).option(
11635
+ "--field <field>",
11636
+ "field uuid or slug to include in the unique constraint (repeatable)",
11637
+ collectFieldSelectors,
11638
+ []
11639
+ ).option("--clear", "clear the unique constraint (sends an empty field list)").action(async function action(schema, commandOptions) {
11640
+ const { api, json, readOnly } = createSchemasApi(this, filePath);
11641
+ ensureWritable8("schemas set-unique-fields", readOnly, "write");
11642
+ const selectors = commandOptions.field ?? [];
11643
+ if (commandOptions.clear && selectors.length > 0) {
11644
+ throw new CliError(
11645
+ "invalid_cli_usage",
11646
+ 'Use either "--field" or "--clear", not both.'
11647
+ );
11648
+ }
11649
+ if (!commandOptions.clear && selectors.length === 0) {
11650
+ throw new CliError(
11651
+ "invalid_cli_usage",
11652
+ 'Provide at least one field via "--field", or pass "--clear" to remove the unique constraint.'
11653
+ );
11654
+ }
11655
+ const resolvedSchema = await resolveSchemaSelector2(api, schema);
11656
+ const resolvedFields = await Promise.all(
11657
+ selectors.map((selector) => resolveFieldSelector(api, resolvedSchema, selector))
11658
+ );
11659
+ const input = {
11660
+ fieldIds: resolvedFields.map((field) => field.value)
11661
+ };
11662
+ const data = await api.setUniqueFields(resolvedSchema, input);
11663
+ if (json) {
11664
+ emitJson11(stdout, "schemas set-unique-fields", data, filePath);
11665
+ return;
11666
+ }
11667
+ if (input.fieldIds.length === 0) {
11668
+ writeLine11(stdout, `Cleared unique fields on schema "${schema.value}".`);
11669
+ return;
11670
+ }
11671
+ const count = input.fieldIds.length;
11672
+ writeLine11(
11673
+ stdout,
11674
+ `Set unique fields on schema "${schema.value}" (${count} field${count === 1 ? "" : "s"}).`
11675
+ );
11676
+ });
11519
11677
  schemas.command("delete").description("Delete a schema").argument("<schema>", "schema uuid or slug", parseUuidOrSlugSelector9).action(async function action(schema) {
11520
11678
  const { api, json, readOnly } = createSchemasApi(this, filePath);
11521
11679
  ensureWritable8("schemas delete", readOnly, "destructive");