Skip to content

feat(entities): add Data Fabric Entity v3 (composite entity) service#586

Open
RohanKharvi1211 wants to merge 1 commit into
mainfrom
feat/entities-v3
Open

feat(entities): add Data Fabric Entity v3 (composite entity) service#586
RohanKharvi1211 wants to merge 1 commit into
mainfrom
feat/entities-v3

Conversation

@RohanKharvi1211

Copy link
Copy Markdown

Summary

Adds the full v3 Data Fabric Entity API as a new modular service, EntityV3Service, exposed via the @uipath/uipath-typescript/entities-v3 subpath (alias EntitiesV3). Additive — the existing v1/v2 Entities service is untouched.

v3 introduces composite entities: a logical business entity backed by multiple related member tables (a tree linked by FKs). Every read/query resolves to EntityV3WriteResponse records and every write returns an EntityV3WriteResponse; composite child records are keyed by member instance name under children. Non-composite entities return an empty children map, so callers use one record model everywhere. Record field values are returned exactly as the API sends them (Data Fabric schema columns are user-defined — casing is part of the schema contract and is never transformed).

⚠️ Not yet live-validated. No PAT was available in the authoring environment, so the workflow's live-curl and browser-E2E steps were skipped. All offline gates pass (typecheck, lint, 2203 unit tests incl. 154 new, build). The composite create and schema-write request-body shapes were derived from the backend C# controllers + composite-entity LLD + external swagger, and the LLD and swagger disagree on FK-reference field naming — confirm these against a live tenant with DataFabric.Schema.Write before release. The data plane (read/query/insert/update/delete/members/attachments) is high-confidence.

Methods Added

New service EntitiesV3 (@uipath/uipath-typescript/entities-v3). Data ops are addressed by entity name; schema ops by entity id.

Group Methods
Listing / metadata getAll, getAllWithChoiceSets, getFolderEntities, getById, getMetadata
Schema CUD create (single + composite), deleteById, updateMetadata, createField, updateField, deleteField
Data reads getRecords, getRecord, getRecordByKey, query, queryWithExpansion
Data writes insert, insertRecords, insertBulk, upsert, update, updateByKey, updateRecords, updateWhere, deleteRecord, deleteRecords, deleteRecordsBatch
Composite members queryMember, getMemberRecords, getMemberRecord, getMemberRecordByKey, deleteMemberRecord, deleteMemberRecords, createMemberField, updateMemberField, deleteMemberField, deleteMemberFieldHard
Attachments downloadAttachment, uploadAttachment, deleteAttachment
Autopilot manageWithAutopilot, manageWithAutopilotStream (SSE)

getById / getMetadata return an entity with bound operation methods (entity.getRecords(), entity.query(), entity.insert(), entity.delete(), …) capturing the entity's name (data ops) and id (schema ops).

Endpoints

All under base …/dataservice_/api/v3/entities (DATA_FABRIC_V3_ENDPOINTS). OAuth scopes: data ops DataFabric.Data.Read/Write; schema ops DataFabric.Schema.Read/Write (full table in docs/oauth-scopes.md).

Sample HTTP Endpoint
query POST /api/v3/entities/{entityName}/query
getRecords GET /api/v3/entities/{entityName}/read
insert POST /api/v3/entities/{entityName}/insert
queryMember POST /api/v3/entities/{compositeName}/members/{memberName}/query
getById GET /api/v3/entities/{entityId}
create POST /api/v3/entities
manageWithAutopilotStream POST /api/v3/entities/autopilot/manage/stream

Example Usage

import { UiPath } from '@uipath/uipath-typescript/core';
import { EntitiesV3 } from '@uipath/uipath-typescript/entities-v3';
import { LogicalOperator, QueryFilterOperator } from '@uipath/uipath-typescript/entities-v3';

const sdk = new UiPath(config);
await sdk.initialize();
const entitiesV3 = new EntitiesV3(sdk);

// List entities (composites appear with isComposite: true)
const entities = await entitiesV3.getAll();

// Query a composite entity with nested children (one level deep, capped)
const result = await entitiesV3.query('LoanCaseForBank', {
  selectedFields: ['CaseId', 'CaseStatus', 'Comments.Comment'],
  filterGroup: {
    logicalOperator: LogicalOperator.And,
    queryFilters: [{ fieldName: 'CaseStatus', operator: QueryFilterOperator.Equals, value: 'Open' }],
  },
  childLimit: 100,
});

// Insert a composite record; FKs are inferred from nesting
const created = await entitiesV3.insert('LoanCaseForBank', {
  CaseId: 'CASE-001',
  CaseStatus: 'Open',
  Comments: [{ CommentId: 'CMT-001', Comment: 'Initial triage' }],
});
console.log(created.children.Comments.records);

// Bound methods on a retrieved entity
const entity = await entitiesV3.getMetadata('LoanCaseForBank');
if (entity.isComposite) console.log(entity.compositeInfo?.members?.map(m => m.entityName));
const comments = await entity.queryMember('Comments', { pageSize: 50 });

Response model

  • Reads/queries → paginated EntityV3WriteResponse records (value/totalRecordCount envelope unwrapped by the pagination layer). getRecords/query/queryMember/getMemberRecords support SDK pagination (offset-based, limit/start).
  • WritesEntityV3WriteResponse (root fields flattened + children map). Batch ops → EntityV3BatchResponse (per-record success/failure). Member deletes → EntityV3MemberDeleteResponse (with cascade counts).
  • No field transforms on record data — DF schema contract. Schema metadata (EntityV3Metadata, compositeInfo) is returned wire-close.

Composition / infra notes

  • Composite children are keyed by member instance name; each block carries records, hasMore, and a server-provided ref for paging remaining children.
  • manageWithAutopilotStream returns a ReadableStream<Uint8Array> — enabled by a new general RESPONSE_TYPES.STREAM path added to ApiClient (returns the raw body without buffering; sits after the 204 short-circuit).
  • Bound delegates are async (guards reject, matching the v1 pattern) and use direct return (no await).

Files

Area Files
Endpoints src/utils/constants/endpoints/data-fabric.ts (DATA_FABRIC_V3_ENDPOINTS)
Types src/models/data-fabric/entities-v3.types.ts
Models src/models/data-fabric/entities-v3.models.ts (EntityV3ServiceModel, EntityV3Methods, factory)
Service src/services/data-fabric/entities-v3.ts
Barrel / subpath src/services/data-fabric/entities-v3/index.ts, src/models/data-fabric/index.ts, package.json, rollup.config.js
HTTP infra src/core/http/api-client.ts, src/utils/constants/headers.ts (RESPONSE_TYPES.STREAM)
Unit tests tests/unit/services/data-fabric/entities-v3.test.ts (89), tests/unit/models/data-fabric/entities-v3.test.ts (65)
Integration tests tests/integration/shared/data-fabric/entities-v3.integration.test.ts (v1-only), tests/integration/config/unified-setup.ts
Docs docs/oauth-scopes.md, mkdocs.yml

Follow-ups before release

  • Live-validate composite create + schema-write (createField/updateField/updateMetadata/member field) request bodies against a tenant with DataFabric.Schema.Write.
  • Run browser E2E against a live composite entity.
  • Whitelist /api/v3/entities routes in Cloudflare Workers (apps-dev-tools — not accessible in the authoring environment; pattern: new RegExp('^\\/${DATAFABRIC_BASE}\\/api\\/v3\\/entities') and sub-paths).
  • Version bump in a separate PR (per repo policy).

🤖 Auto-generated using onboarding skills

Adds the full v3 Entity API as a new modular service EntityV3Service,
exposed via the @uipath/uipath-typescript/entities-v3 subpath. Additive —
the existing v1/v2 Entities service is unchanged.

v3 introduces composite entities (a logical entity backed by multiple
related "member" tables). Every read/query resolves to EntityV3WriteResponse
records and every write returns an EntityV3WriteResponse; composite children
are keyed by member instance name. Record field values are returned
untransformed (Data Fabric schema contract).

Surface (~43 methods): name-addressed data plane (read/query/query_expansion/
insert/insert-batch/insert_bulk/upsert/update/updateByKey/update-batch/
update-where/delete/delete-batch), id-addressed schema (getById/getMetadata/
create[single+composite]/deleteById/updateMetadata/field CUD), composite
members (query/read/readByKey/delete + member field CUD), attachments, and
autopilot manage + streaming. Adds a general RESPONSE_TYPES.STREAM path to
ApiClient for the SSE stream endpoint.

Verified offline: typecheck, lint, unit tests (154 new v3 tests), build.
NOT yet live-validated (no PAT): the composite create + schema-write request
body shapes are derived from backend source + LLD + swagger and must be
confirmed against a live tenant before release.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@RohanKharvi1211
RohanKharvi1211 requested a review from a team July 8, 2026 06:33
Comment on lines +116 to +121
DOWNLOAD: (entityName: string, recordId: string, fieldName: string) =>
`${V3_BASE}/${entityName}/records/${recordId}/attachments/${fieldName}`,
UPLOAD: (entityName: string, recordId: string, fieldName: string) =>
`${V3_BASE}/${entityName}/records/${recordId}/attachments/${fieldName}`,
DELETE: (entityName: string, recordId: string, fieldName: string) =>
`${V3_BASE}/${entityName}/records/${recordId}/attachments/${fieldName}`,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Per convention, duplicate URL-pattern constants must either be collapsed or carry an explicit comment explaining the intentional duplication. There are four sets of duplicates in this file that need it:

  1. ENTITY.LIST and ENTITY.CREATE — both equal V3_BASE
  2. ENTITY.GET_BY_ID and ENTITY.DELETE_BY_ID — both produce ${V3_BASE}/${entityId}
  3. ENTITY.FIELD.UPDATE and ENTITY.FIELD.DELETE — both produce ${V3_BASE}/${entityId}/field/${fieldId}
  4. These three attachment constants — all produce the same ${V3_BASE}/${entityName}/records/${recordId}/attachments/${fieldName} URL

For attachment-group (and the field pair), distinct names aid readability, so a comment is the right fix. For example:

Suggested change
DOWNLOAD: (entityName: string, recordId: string, fieldName: string) =>
`${V3_BASE}/${entityName}/records/${recordId}/attachments/${fieldName}`,
UPLOAD: (entityName: string, recordId: string, fieldName: string) =>
`${V3_BASE}/${entityName}/records/${recordId}/attachments/${fieldName}`,
DELETE: (entityName: string, recordId: string, fieldName: string) =>
`${V3_BASE}/${entityName}/records/${recordId}/attachments/${fieldName}`,
// Attachments (by entity name) — DOWNLOAD, UPLOAD, and DELETE share the same URL path;
// the HTTP method (GET / POST / DELETE) is resolved at the call site.
ATTACHMENT: {
DOWNLOAD: (entityName: string, recordId: string, fieldName: string) =>
`${V3_BASE}/${entityName}/records/${recordId}/attachments/${fieldName}`,
UPLOAD: (entityName: string, recordId: string, fieldName: string) =>
`${V3_BASE}/${entityName}/records/${recordId}/attachments/${fieldName}`,
DELETE: (entityName: string, recordId: string, fieldName: string) =>
`${V3_BASE}/${entityName}/records/${recordId}/attachments/${fieldName}`,
},

Apply equivalent comments at the other three duplicate sites (lines 80–85 and 110–111).

* @returns Promise resolving to the new entity id (single) or composite descriptor {@link EntityV3CreateResponse}
* @example
* ```typescript
* import { EntityFieldDataType } from '@uipath/uipath-typescript/entities';

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Per convention, @example imports must be self-contained and copy-pasteable — they should import from the same subpath the user would already have imported. EntityFieldDataType is re-exported from @uipath/uipath-typescript/entities-v3 (see src/services/data-fabric/entities-v3/index.ts), so the example import should use that path, not entities.

Suggested change
* import { EntityFieldDataType } from '@uipath/uipath-typescript/entities';
* import { EntityFieldDataType } from '@uipath/uipath-typescript/entities-v3';

The same fix applies to four other occurrences in this file:

  • Line 207 (EntityFieldDataType in createField example)
  • Line 302 (LogicalOperator, QueryFilterOperator in query example)
  • Line 454 (QueryFilterOperator in updateWhere example)
  • Line 615 (EntityFieldDataType in createMemberField example)

In each case, replace '@uipath/uipath-typescript/entities' with '@uipath/uipath-typescript/entities-v3'.

@claude

claude Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Two findings this run. 1. Duplicate endpoint constants without comments in data-fabric.ts (lines 116-121): Four sets of constants share identical URL patterns. Convention requires either collapsing them or adding an explanatory comment that HTTP-method differences are resolved at the call site. 2. JSDoc examples use wrong subpath in entities-v3.models.ts (line 157 + 4 others): Five examples import EntityFieldDataType, LogicalOperator, or QueryFilterOperator from entities instead of entities-v3 where they are already re-exported. Examples must be importable from the subpath the user is already using.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant