-
Notifications
You must be signed in to change notification settings - Fork 9
feat(data-fabric): add query method with joins, aggregates, and filters #334
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
4f545cc
b00d482
24cd4a5
7eec3c3
b55f4e1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -21,7 +21,9 @@ import { | |
| EntityUpdateRecordsOptions, | ||
| EntityDeleteRecordsOptions, | ||
| EntityGetAllRecordsOptions, | ||
| EntityInsertRecordOptions | ||
| EntityInsertRecordOptions, | ||
| EntityQueryOptions, | ||
| EntityQueryResponse | ||
| } from './entities.types'; | ||
| import { PaginatedResponse, NonPaginatedResponse, HasPaginationOptions } from '../../utils/pagination/types'; | ||
|
|
||
|
|
@@ -461,6 +463,60 @@ export interface EntityServiceModel { | |
| * ``` | ||
| */ | ||
| deleteAttachment(entityId: string, recordId: string, fieldName: string): Promise<EntityDeleteAttachmentResponse>; | ||
|
|
||
| /** | ||
| * | ||
| * @experimental | ||
| * | ||
| * /// warning | ||
| Preview: This method is experimental and may change or be removed in future releases. | ||
| /// | ||
| * | ||
| * Queries an entity by ID with support for joins, aggregates, filters, grouping, and sorting | ||
| * | ||
| * @param entityId - UUID of the entity to query | ||
| * @param options - Query options including selectedFields, aggregates, joins, filterGroup, groupBy, sortOptions, start, limit | ||
| * @returns Promise resolving to query response with matching records | ||
| * {@link EntityQueryResponse} | ||
| * @example | ||
| * ```typescript | ||
| * import { Entities } from '@uipath/uipath-typescript/entities'; | ||
| * | ||
| * const entities = new Entities(sdk); | ||
| * | ||
| * // Simple query with filters | ||
| * const result = await entities.query('<entityId>', { | ||
| * selectedFields: ['name', 'email'], | ||
| * filterGroup: { | ||
| * logicalOperator: 0, | ||
| * queryFilters: [{ fieldName: 'status', operator: '=', value: 'active' }] | ||
| * }, | ||
| * limit: 50 | ||
| * }); | ||
| * | ||
| * // Cross-entity join query | ||
| * const joinResult = await entities.query('<entityId>', { | ||
| * selectedFields: ['Orders.orderId', 'Customer.name'], | ||
| * joins: [{ | ||
| * type: 'INNER', | ||
| * entity: 'Customer', | ||
| * on: { left: 'customerId', right: 'Id' } | ||
| * }], | ||
| * sortOptions: [{ fieldName: 'Orders.createdDate', isDescending: true }], | ||
| * limit: 100 | ||
| * }); | ||
| * | ||
| * // Aggregate query | ||
| * const stats = await entities.query('<entityId>', { | ||
| * aggregates: [ | ||
| * { function: 'COUNT', field: 'Id', alias: 'totalOrders' }, | ||
| * { function: 'SUM', field: 'amount', alias: 'totalAmount' } | ||
| * ], | ||
| * groupBy: ['status'] | ||
| * }); | ||
|
Comment on lines
+487
to
+516
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since we have defined enums for these values, why not use them in the examples as well? |
||
| * ``` | ||
| */ | ||
| query(entityId: string, options?: EntityQueryOptions): Promise<EntityQueryResponse>; | ||
| } | ||
|
|
||
| /** | ||
|
|
@@ -576,6 +632,21 @@ export interface EntityMethods { | |
| */ | ||
| deleteAttachment(recordId: string, fieldName: string): Promise<EntityDeleteAttachmentResponse>; | ||
|
|
||
| /** | ||
| * | ||
| * @experimental | ||
| * | ||
| * /// warning | ||
| Preview: This method is experimental and may change or be removed in future releases. | ||
| /// | ||
| * | ||
| * Queries this entity with support for joins, aggregates, filters, grouping, and sorting | ||
| * | ||
| * @param options - Query options | ||
| * @returns Promise resolving to query response with matching records | ||
| */ | ||
| query(options?: EntityQueryOptions): Promise<EntityQueryResponse>; | ||
|
|
||
| /** | ||
| * @deprecated Use {@link insertRecord} instead. | ||
| * @hidden | ||
|
|
@@ -691,6 +762,12 @@ function createEntityMethods(entityData: RawEntityGetResponse, service: EntitySe | |
| return service.deleteAttachment(entityData.id, recordId, fieldName); | ||
| }, | ||
|
|
||
| async query(options?: EntityQueryOptions): Promise<EntityQueryResponse> { | ||
| if (!entityData.id) throw new Error('Entity ID is undefined'); | ||
|
|
||
| return service.query(entityData.id, options); | ||
| }, | ||
|
|
||
| async insert(data: Record<string, any>, options?: EntityInsertOptions): Promise<EntityInsertResponse> { | ||
| return this.insertRecord(data, options); | ||
| }, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -191,6 +191,212 @@ export interface EntityUpdateResponse extends EntityOperationResponse {} | |
| */ | ||
| export interface EntityDeleteResponse extends EntityOperationResponse {} | ||
|
|
||
| /** | ||
| * | ||
| * @experimental | ||
| * | ||
| * /// warning | ||
| Preview: This type is experimental and may change or be removed in future releases. | ||
| /// | ||
| * | ||
| * Aggregate function types for query operations | ||
| */ | ||
| export enum QueryAggregateFunction { | ||
| COUNT = "COUNT", | ||
| SUM = "SUM", | ||
| AVG = "AVG", | ||
| MIN = "MIN", | ||
| MAX = "MAX", | ||
| } | ||
|
|
||
| /** | ||
| * | ||
| * @experimental | ||
| * | ||
| * /// warning | ||
| Preview: This type is experimental and may change or be removed in future releases. | ||
| /// | ||
| * | ||
| * Join types for cross-entity query operations | ||
| */ | ||
| export enum QueryJoinType { | ||
| INNER = "INNER", | ||
| LEFT = "LEFT", | ||
| RIGHT = "RIGHT", | ||
| FULL = "FULL", | ||
| } | ||
|
|
||
| /** | ||
| * | ||
| * @experimental | ||
| * | ||
| * /// warning | ||
| Preview: This type is experimental and may change or be removed in future releases. | ||
| /// | ||
| * | ||
| * Logical operators for combining query filters | ||
| */ | ||
| export enum QueryLogicalOperator { | ||
| AND = 0, | ||
| OR = 1, | ||
| } | ||
|
|
||
| /** | ||
| * | ||
| * @experimental | ||
| * | ||
| * /// warning | ||
| Preview: This type is experimental and may change or be removed in future releases. | ||
| /// | ||
| * | ||
| * An aggregate operation in a query | ||
| */ | ||
| export interface QueryAggregate { | ||
| /** Aggregate function to apply */ | ||
| function: QueryAggregateFunction; | ||
| /** Field to aggregate on */ | ||
| field: string; | ||
| /** Alias for the aggregated result */ | ||
| alias: string; | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. question : Is alias always required by the API? |
||
| } | ||
|
|
||
| /** | ||
| * | ||
| * @experimental | ||
| * | ||
| * /// warning | ||
| Preview: This type is experimental and may change or be removed in future releases. | ||
| /// | ||
| * | ||
| * A join condition for cross-entity queries | ||
| */ | ||
| export interface QueryJoinCondition { | ||
| /** Left side field name (from the primary entity) */ | ||
| left: string; | ||
| /** Right side field name (from the joined entity) */ | ||
| right: string; | ||
| } | ||
|
|
||
| /** | ||
| * | ||
| * @experimental | ||
| * | ||
| * /// warning | ||
| Preview: This type is experimental and may change or be removed in future releases. | ||
| /// | ||
| * | ||
| * A join clause for cross-entity queries | ||
| */ | ||
| export interface QueryJoin { | ||
| /** Type of join */ | ||
| type: QueryJoinType; | ||
| /** Name of the entity to join */ | ||
| entity: string; | ||
| /** Join condition specifying left and right field mappings */ | ||
| on: QueryJoinCondition; | ||
| } | ||
|
|
||
| /** | ||
| * | ||
| * @experimental | ||
| * | ||
| * /// warning | ||
| Preview: This type is experimental and may change or be removed in future releases. | ||
| /// | ||
| * | ||
| * A single query filter condition | ||
| */ | ||
| export interface QueryFilter { | ||
| /** Field name to filter on */ | ||
| fieldName: string; | ||
| /** Comparison operator: "=", "!=", ">", "<", ">=", "<=", "contains", "startswith", "endswith" (lowercase for string operators) */ | ||
| operator: string; | ||
|
Comment on lines
+312
to
+313
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could we have this as an enum? |
||
| /** Value to compare against */ | ||
| value: unknown; | ||
| } | ||
|
|
||
| /** | ||
| * | ||
| * @experimental | ||
| * | ||
| * /// warning | ||
| Preview: This type is experimental and may change or be removed in future releases. | ||
| /// | ||
| * | ||
| * A group of query filters combined with a logical operator | ||
| */ | ||
| export interface QueryFilterGroup { | ||
| /** Logical operator to combine filters (0 = AND, 1 = OR) */ | ||
| logicalOperator: QueryLogicalOperator; | ||
| /** Array of filter conditions */ | ||
| queryFilters: QueryFilter[]; | ||
| /** Nested filter groups for complex conditions */ | ||
| queryFilterGroups?: QueryFilterGroup[]; | ||
| } | ||
|
|
||
| /** | ||
| * | ||
| * @experimental | ||
| * | ||
| * /// warning | ||
| Preview: This type is experimental and may change or be removed in future releases. | ||
| /// | ||
| * | ||
| * Sort option for query results | ||
| */ | ||
| export interface QuerySortOption { | ||
| /** Field name to sort by */ | ||
| fieldName: string; | ||
| /** Whether to sort in descending order (default: false) */ | ||
| isDescending?: boolean; | ||
| } | ||
|
|
||
| /** | ||
| * | ||
| * @experimental | ||
| * | ||
| * /// warning | ||
| Preview: This type is experimental and may change or be removed in future releases. | ||
| /// | ||
| * | ||
| * Options for querying an entity with joins, aggregates, and filters | ||
| */ | ||
| export interface EntityQueryOptions { | ||
| /** Fields to include in the result set. Required when using aggregates — must include the groupBy fields. */ | ||
| selectedFields?: string[]; | ||
| /** Aggregate operations to perform. Requires selectedFields to include the groupBy fields. */ | ||
| aggregates?: QueryAggregate[]; | ||
| /** Cross-entity join clauses. Joined entity fields can be referenced as "entityName.fieldName" in selectedFields. */ | ||
| joins?: QueryJoin[]; | ||
| /** Filter conditions */ | ||
| filterGroup?: QueryFilterGroup; | ||
| /** Fields to group results by (used with aggregates). These fields must also appear in selectedFields. */ | ||
| groupBy?: string[]; | ||
| /** Sort options for result ordering */ | ||
| sortOptions?: QuerySortOption[]; | ||
| /** Starting offset for pagination (default: 0) */ | ||
| start?: number; | ||
| /** Maximum number of records to return (default: 100) */ | ||
| limit?: number; | ||
| } | ||
|
Comment on lines
+377
to
+381
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The SDK already supports pagination. Can't we use that instead? |
||
|
|
||
| /** | ||
| * | ||
| * @experimental | ||
| * | ||
| * /// warning | ||
| Preview: This type is experimental and may change or be removed in future releases. | ||
| /// | ||
| * | ||
| * Response from a query operation | ||
| */ | ||
| export interface EntityQueryResponse { | ||
| /** Array of matching records */ | ||
| value: Record<string, unknown>[]; | ||
| /** Total count of matching records (before pagination) */ | ||
| totalRecordCount?: number; | ||
| } | ||
|
|
||
| /** | ||
| * Entity type enum | ||
| */ | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This example uses
aggregateswithoutselectedFields. Wouldn't this error out?