fix(data-fabric): align entity field type emission with UI's narrower FieldType enum#489
fix(data-fabric): align entity field type emission with UI's narrower FieldType enum#489AditiGoyalUipath wants to merge 2 commits into
Conversation
| sqlTypeName: SqlFieldType; | ||
| fieldDisplayType: FieldDisplayType; | ||
| /** Value emitted as the field's `type` on the wire. */ | ||
| apiTypeName: string; |
There was a problem hiding this comment.
apiTypeName: string holds a finite, fixed set of API wire values — 'uniqueid', 'text', 'number', 'dateTime', 'date', 'boolean', 'multiline', 'relationship', 'choiceSetSingle', 'choiceSetMultiple', 'autonumber'. Per the SDK convention ("Use enums for fixed value sets — NEVER leave raw strings/numbers"), these should be an enum, e.g.:
// entities.types.ts (public — FieldMetaData.type uses it)
export enum EntityApiFieldType {
UniqueId = 'uniqueid',
Text = 'text',
Number = 'number',
DateTime = 'dateTime',
Date = 'date',
Boolean = 'boolean',
Multiline = 'multiline',
Relationship = 'relationship',
ChoiceSetSingle = 'choiceSetSingle',
ChoiceSetMultiple = 'choiceSetMultiple',
AutoNumber = 'autonumber',
}Then:
EntitySchemaFieldMapping.apiTypeName: EntityApiFieldTypeFieldSchemaPayload.type?: EntityApiFieldTypeFieldMetaData.type?: EntityApiFieldType(entities.types.ts:539)EntitySchemaFieldTypeMapvalues useEntityApiFieldType.Textetc.
Since FieldMetaData is public, the enum lives in entities.types.ts, not internal-types.ts.
vnaren23
left a comment
There was a problem hiding this comment.
The Manage Entity UI accepts a narrower set of SQL types than the backend (FE doc §3.1, §3.4). When the SDK emitted INT/BIGINT/FLOAT/REAL/DATETIME2 — or omitted the field-level type discriminator entirely
Is the backend meant to accept such wider set of SQL types? Forcing SDK changes just to confer to lack of support from DF UI seems incorrect. If anything we should add these support into DF UI rather than making SDK changes.
| expect(mockApiClient.get).toHaveBeenCalledWith( | ||
| DATA_FABRIC_ENDPOINTS.ENTITY.GET_BY_ID(ENTITY_TEST_CONSTANTS.ENTITY_ID), | ||
| {}, | ||
| { headers: {} }, |
There was a problem hiding this comment.
The getById describe block only tests the no-folderKey path. The PR adds options?: EntityGetByIdOptions (with folderKey) to getById, but there's no test that passes a folderKey and verifies the X-UIPATH-FolderKey header is forwarded.
The same gap exists for:
downloadAttachment(line ~1188 — only the no-folderKey case is asserted)deleteAttachment(line ~1301)uploadAttachment(theexpansionLeveltest was updated to includeheaders: {}, but no folderKey path)updateById— both the schema-update (inner UPSERT/GET calls) and the metadata-update (patch) paths
deleteById (line 2072) already shows the pattern:
it("should pass folderKey via X-UIPATH-FolderKey header when provided", async () => {
mockApiClient.get.mockResolvedValue(mockResponse);
const result = await entityService.getById(
ENTITY_TEST_CONSTANTS.ENTITY_ID,
{ folderKey: ENTITY_TEST_CONSTANTS.FIELD_ID },
);
expect(result).toBeDefined();
expect(mockApiClient.get).toHaveBeenCalledWith(
DATA_FABRIC_ENDPOINTS.ENTITY.GET_BY_ID(ENTITY_TEST_CONSTANTS.ENTITY_ID),
{ headers: { "X-UIPATH-FolderKey": ENTITY_TEST_CONSTANTS.FIELD_ID } },
);
});Please add the equivalent test for each of the five methods listed above. Per conventions, new API-call code paths need 100% coverage.
Review summaryOne new finding this run: Missing Note: the open thread about converting |
816898a to
f527b0b
Compare
| displayName?: string; | ||
| description?: string; | ||
| /** UI logical type (e.g. "text", "number", "dateTime"). Required for Manage Entity round-trip. */ | ||
| type?: string; |
There was a problem hiding this comment.
The JSDoc says "Required for Manage Entity round-trip" but the field is typed as optional (?). buildSchemaFieldPayload() always populates this from EntitySchemaFieldTypeMap, where apiTypeName: string is a required field for every EntityFieldDataType entry — so type will always be present on every outbound FieldSchemaPayload.
Making it required matches the documentation and gives compile-time enforcement that future code paths can't accidentally produce a schema payload without the type discriminator (which is precisely the bug this PR fixes):
| type?: string; | |
| /** UI logical type (e.g. "text", "number", "dateTime"). Required for Manage Entity round-trip. */ | |
| type: string; |
Review summaryOne new finding this run:
Two prior threads remain open (enum for apiTypeName; missing folderKey header tests) — not duplicated here. |
|
✅ No issues found. Checked for bugs and CLAUDE.md compliance. |
… FieldType enum The Manage Entity UI accepts a smaller set of SQL types than the backend (FE doc §3.1, §3.4). When the SDK emitted INT/BIGINT/FLOAT/REAL/DATETIME2 or omitted the field-level `type` discriminator, the UI silently rewrote those fields to NVARCHAR on load. The backend then rejected the next save with "Field type cannot be changed" (backend doc §6.4 — SqlType.Name is immutable on update), even when the user made no changes. Two changes: - Emit `type` (UI logical type: "text", "number", "dateTime", etc.) on every outbound field. Carried forward via FieldMetaData on re-upsert. - Collapse INT/BIGINT/FLOAT/REAL → DECIMAL and DATETIME2 → DATETIMEOFFSET in EntitySchemaFieldTypeMap. EntityFieldDataType.INTEGER/BIG_INTEGER set decimalPrecision: 0 to preserve integer semantics; FLOAT/DOUBLE retain the user-overridable precision (default 2). FILE behaviour is unchanged in this PR — it still requires user-supplied references and forwards them on the wire. The FILE → server-provisioned- references change ships separately in #491. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…ieldSchemaPayload
Two PR review fixes:
- Promote the raw wire-vocabulary strings ('text', 'number', 'dateTime', …)
to a typed enum EntityApiFieldType. Per SDK convention ("Use enums for
fixed value sets — NEVER leave raw strings/numbers"), and gives users a
typo-safe contract on the public FieldMetaData.type field.
- Make FieldSchemaPayload.type required (was optional with a JSDoc claim
of "Required for Manage Entity round-trip"). buildSchemaFieldPayload
always populates it from EntitySchemaFieldTypeMap, so the optional
marker only allowed future code paths to silently omit the discriminator
that this PR exists to fix.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
55a2b68 to
6d0b375
Compare
| expect(f.sqlType).toEqual({ name: "UNIQUEIDENTIFIER", lengthLimit: 300 }); | ||
| }); | ||
|
|
||
| it("should emit isForeignKey, referenceEntity, referenceField — but NOT referenceType — for FILE fields", async () => { |
There was a problem hiding this comment.
The PR description (point 3) states the FILE validation guard was tightened from (isRelationship || isFile) to isRelationship only, and that FILE no longer emits isForeignKey. But buildSchemaFieldPayload in entities.ts is unchanged — lines 1061 and 1084 still read (isRelationship || isFile), so FILE still requires reference IDs and still emits isForeignKey: true.
This test correctly reflects the actual (unchanged) code. The issue is that the parallel updateById test "should throw ValidationError when FILE field is missing reference IDs" was removed from the updateById section on the assumption the guard had been changed — but it wasn't. The create-section equivalent at line 2046 still covers the same buildSchemaFieldPayload code path, so no functional gap, but the updateById-specific explicit assertion was lost without the corresponding implementation change.
Please either:
- Restore the removed
updateByIdtest (it("should throw ValidationError when FILE field is missing reference IDs", ...)) to match the unchanged service code, or - Implement the described relaxation (change
(isRelationship || isFile)→isRelationshipon both lines 1061 and 1084 ofentities.ts) and remove the test as planned
Review summaryOne new finding this run: Unimplemented FILE-field relaxation (discussion_r3348609731) — The PR description (point 3) claims the FILE validation guard was tightened from Three prior threads remain open (not duplicated here):
|
Summary
The Manage Entity UI accepts a narrower set of SQL types than the backend (FE doc §3.1, §3.4). When the SDK emitted
INT/BIGINT/FLOAT/REAL/DATETIME2— or omitted the field-leveltypediscriminator entirely — the UI silently rewrote those fields toNVARCHARon load. Saving again then failed with "Field type cannot be changed" becauseSqlType.Nameis immutable on update (backend doc §6.4), even when the user made no changes.Changes
1. Emit
type(UI logical type) on every outbound fieldapiTypeNamecolumn inEntitySchemaFieldTypeMap("text","number","dateTime","relationship", etc.)buildSchemaFieldPayload()now setstype: mapping.apiTypeNameon the wire payloadFieldMetaData.typecarries it back on read so re-upserts preserve it2. Collapse types the UI rewrites
INTEGER,BIG_INTEGER,FLOAT,DOUBLE→DECIMAL(wasINT/BIGINT/FLOAT/REAL)DATETIME→DATETIMEOFFSET(wasDATETIME2)INTEGER/BIG_INTEGERsetdecimalPrecision: 0(newINTEGER_DECIMAL_PRECISIONconstant) to preserve integer semanticsFLOAT/DOUBLEretain the user-overridable precision (default 2)3. Relax FILE-field create
referenceEntityId/referenceFieldId— server auto-provisions the EntityAttachment FK (backend doc §5.10)isForeignKey/referenceType/referenceEntity/referenceField(those are RELATIONSHIP-only)(isRelationship || isFile)toisRelationshiponlyTest plan
npm run typecheck— cleannpm run lint— cleannpm run test:unit— passes (unit assertions updated for new SQL types, precision, andtypefield)referenceEntityId/referenceFieldId🤖 Generated with Claude Code