-
Notifications
You must be signed in to change notification settings - Fork 13
add orderBy to Entities.findManyPublic and useEntities(mode: public) #553
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
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 |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| --- | ||
| "@graphprotocol/hypergraph-react": patch | ||
| "@graphprotocol/hypergraph": patch | ||
| --- | ||
|
|
||
| add orderBy to Entities.findManyPublic and useEntities(mode: 'public') | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
|
|
@@ -13,6 +13,12 @@ export type FindManyPublicParams<S extends Schema.Schema.AnyNoContext> = { | |||||||
| space: string; | ||||||||
| first?: number | undefined; | ||||||||
| offset?: number | undefined; | ||||||||
| orderBy?: | ||||||||
| | { | ||||||||
| property: keyof Schema.Schema.Type<S>; | ||||||||
| direction: 'asc' | 'desc'; | ||||||||
| } | ||||||||
| | undefined; | ||||||||
| }; | ||||||||
|
|
||||||||
| const entitiesQueryDocumentLevel0 = gql` | ||||||||
|
|
@@ -172,6 +178,168 @@ query entities($spaceId: UUID!, $typeIds: [UUID!]!, $relationTypeIdsLevel1: [UUI | |||||||
| } | ||||||||
| `; | ||||||||
|
|
||||||||
| const entitiesOrderedByPropertyQueryDocumentLevel0 = gql` | ||||||||
| query entitiesOrderedByProperty($spaceId: UUID!, $typeIds: [UUID!]!, $first: Int, $filter: EntityFilter!, $offset: Int, $propertyId: UUID!, $sortDirection: SortOrder!) { | ||||||||
| entities: entitiesOrderedByProperty( | ||||||||
| filter: { and: [{ | ||||||||
| relations: {some: {typeId: {is: "8f151ba4-de20-4e3c-9cb4-99ddf96f48f1"}, toEntityId: {in: $typeIds}}}, | ||||||||
| spaceIds: {in: [$spaceId]}, | ||||||||
| }, $filter]} | ||||||||
| first: $first | ||||||||
| offset: $offset | ||||||||
| propertyId: $propertyId | ||||||||
| sortDirection: $sortDirection | ||||||||
| ) { | ||||||||
| id | ||||||||
| name | ||||||||
| valuesList(filter: {spaceId: {is: $spaceId}}) { | ||||||||
| propertyId | ||||||||
| string | ||||||||
| boolean | ||||||||
| number | ||||||||
| time | ||||||||
| point | ||||||||
| } | ||||||||
| } | ||||||||
| } | ||||||||
| `; | ||||||||
|
|
||||||||
| const entitiesOrderedByPropertyQueryDocumentLevel1 = gql` | ||||||||
| query entitiesOrderedByProperty($spaceId: UUID!, $typeIds: [UUID!]!, $relationTypeIdsLevel1: [UUID!]!, $first: Int, $filter: EntityFilter!, $offset: Int, $propertyId: UUID!, $sortDirection: SortOrder!) { | ||||||||
| entities: entitiesOrderedByProperty( | ||||||||
| first: $first | ||||||||
| filter: { and: [{ | ||||||||
| relations: {some: {typeId: {is: "8f151ba4-de20-4e3c-9cb4-99ddf96f48f1"}, toEntityId: {in: $typeIds}}}, | ||||||||
| spaceIds: {in: [$spaceId]}, | ||||||||
| }, $filter]} | ||||||||
| offset: $offset | ||||||||
| propertyId: $propertyId | ||||||||
| sortDirection: $sortDirection | ||||||||
| ) { | ||||||||
| id | ||||||||
| name | ||||||||
| valuesList(filter: {spaceId: {is: $spaceId}}) { | ||||||||
| propertyId | ||||||||
| string | ||||||||
| boolean | ||||||||
| number | ||||||||
| time | ||||||||
| point | ||||||||
| } | ||||||||
| relationsList( | ||||||||
| filter: {spaceId: {is: $spaceId}, typeId:{ in: $relationTypeIdsLevel1}}, | ||||||||
| ) { | ||||||||
| id | ||||||||
| entity { | ||||||||
| valuesList(filter: {spaceId: {is: $spaceId}}) { | ||||||||
| propertyId | ||||||||
| string | ||||||||
| boolean | ||||||||
| number | ||||||||
| time | ||||||||
| point | ||||||||
| } | ||||||||
| } | ||||||||
| toEntity { | ||||||||
| id | ||||||||
| name | ||||||||
| valuesList(filter: {spaceId: {is: $spaceId}}) { | ||||||||
| propertyId | ||||||||
| string | ||||||||
| boolean | ||||||||
| number | ||||||||
| time | ||||||||
| point | ||||||||
| } | ||||||||
| } | ||||||||
| typeId | ||||||||
| } | ||||||||
| } | ||||||||
| } | ||||||||
| `; | ||||||||
|
|
||||||||
| const entitiesOrderedByPropertyQueryDocumentLevel2 = gql` | ||||||||
| query entitiesOrderedByProperty($spaceId: UUID!, $typeIds: [UUID!]!, $relationTypeIdsLevel1: [UUID!]!, $relationTypeIdsLevel2: [UUID!]!, $first: Int, $filter: EntityFilter!, $offset: Int, $propertyId: UUID!, $sortDirection: SortOrder!) { | ||||||||
| entities: entitiesOrderedByProperty( | ||||||||
| first: $first | ||||||||
| filter: { and: [{ | ||||||||
| relations: {some: {typeId: {is: "8f151ba4-de20-4e3c-9cb4-99ddf96f48f1"}, toEntityId: {in: $typeIds}}}, | ||||||||
| spaceIds: {in: [$spaceId]}, | ||||||||
| }, $filter]} | ||||||||
| offset: $offset | ||||||||
| propertyId: $propertyId | ||||||||
| sortDirection: $sortDirection | ||||||||
| ) { | ||||||||
| id | ||||||||
| name | ||||||||
| valuesList(filter: {spaceId: {is: $spaceId}}) { | ||||||||
| propertyId | ||||||||
| string | ||||||||
| boolean | ||||||||
| number | ||||||||
| time | ||||||||
| point | ||||||||
| } | ||||||||
| relationsList( | ||||||||
| filter: {spaceId: {is: $spaceId}, typeId:{ in: $relationTypeIdsLevel1}}, | ||||||||
| ) { | ||||||||
| id | ||||||||
| entity { | ||||||||
| valuesList(filter: {spaceId: {is: $spaceId}}) { | ||||||||
| propertyId | ||||||||
| string | ||||||||
| boolean | ||||||||
| number | ||||||||
| time | ||||||||
| point | ||||||||
| } | ||||||||
| } | ||||||||
| toEntity { | ||||||||
| id | ||||||||
| name | ||||||||
| valuesList(filter: {spaceId: {is: $spaceId}}) { | ||||||||
| propertyId | ||||||||
| string | ||||||||
| boolean | ||||||||
| number | ||||||||
| time | ||||||||
| point | ||||||||
| } | ||||||||
| relationsList( | ||||||||
| filter: {spaceId: {is: $spaceId}, typeId:{ in: $relationTypeIdsLevel2}}, | ||||||||
| ) { | ||||||||
| id | ||||||||
| entity { | ||||||||
| valuesList(filter: {spaceId: {is: $spaceId}}) { | ||||||||
| propertyId | ||||||||
| string | ||||||||
| boolean | ||||||||
| number | ||||||||
| time | ||||||||
| point | ||||||||
| } | ||||||||
| } | ||||||||
| toEntity { | ||||||||
| id | ||||||||
| name | ||||||||
| valuesList(filter: {spaceId: {is: $spaceId}}) { | ||||||||
| propertyId | ||||||||
| string | ||||||||
| boolean | ||||||||
| number | ||||||||
| time | ||||||||
| point | ||||||||
| } | ||||||||
| } | ||||||||
| typeId | ||||||||
| } | ||||||||
| } | ||||||||
| typeId | ||||||||
| } | ||||||||
| } | ||||||||
| } | ||||||||
| `; | ||||||||
|
Comment on lines
+181
to
+341
|
||||||||
|
|
||||||||
| type EntityQueryResult = { | ||||||||
| entities: { | ||||||||
| id: string; | ||||||||
|
|
@@ -239,6 +407,8 @@ type EntityQueryResult = { | |||||||
| }[]; | ||||||||
| }; | ||||||||
|
|
||||||||
| type GraphSortDirection = 'ASC' | 'DESC'; | ||||||||
|
|
||||||||
| export const parseResult = <S extends Schema.Schema.AnyNoContext>(queryData: EntityQueryResult, type: S) => { | ||||||||
| const schemaWithId = Utils.addIdSchemaField(type); | ||||||||
| const decode = Schema.decodeUnknownEither(schemaWithId); | ||||||||
|
|
@@ -296,7 +466,7 @@ export const findManyPublic = async <S extends Schema.Schema.AnyNoContext>( | |||||||
| type: S, | ||||||||
| params?: FindManyPublicParams<S>, | ||||||||
| ) => { | ||||||||
| const { filter, include, space, first = 100, offset = 0 } = params ?? {}; | ||||||||
| const { filter, include, space, first = 100, offset = 0, orderBy } = params ?? {}; | ||||||||
|
|
||||||||
| // constructing the relation type ids for the query | ||||||||
| const relationTypeIds = Utils.getRelationTypeIds(type, include); | ||||||||
|
|
@@ -305,25 +475,66 @@ export const findManyPublic = async <S extends Schema.Schema.AnyNoContext>( | |||||||
| Option.getOrElse(() => []), | ||||||||
| ); | ||||||||
|
|
||||||||
| let queryDocument = entitiesQueryDocumentLevel0; | ||||||||
| if (relationTypeIds.level1.length > 0) { | ||||||||
| queryDocument = entitiesQueryDocumentLevel1; | ||||||||
| } | ||||||||
| if (relationTypeIds.level2.length > 0) { | ||||||||
| queryDocument = entitiesQueryDocumentLevel2; | ||||||||
| const relationLevel = relationTypeIds.level2.length > 0 ? 2 : relationTypeIds.level1.length > 0 ? 1 : 0; | ||||||||
|
|
||||||||
| let orderByPropertyId: string | undefined; | ||||||||
| let sortDirection: GraphSortDirection | undefined; | ||||||||
|
|
||||||||
| if (orderBy) { | ||||||||
| const ast = type.ast as SchemaAST.TypeLiteral; | ||||||||
| const propertySignature = ast.propertySignatures.find((prop) => String(prop.name) === String(orderBy.property)); | ||||||||
|
|
||||||||
| if (!propertySignature) { | ||||||||
| throw new Error(`Cannot order by unknown property "${String(orderBy.property)}"`); | ||||||||
|
||||||||
| throw new Error(`Cannot order by unknown property "${String(orderBy.property)}"`); | |
| const availableProps = ast.propertySignatures.map((prop) => String(prop.name)).join(', '); | |
| throw new Error(`Cannot order by unknown property "${String(orderBy.property)}". Available properties: ${availableProps}`); |
Copilot
AI
Nov 17, 2025
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.
The orderBy logic should validate that the property being ordered by is not a relation field. Ordering by relation fields is not supported and would fail at the GraphQL layer. Consider adding a check using Utils.isRelation(propertyType) and throwing an error if it's a relation.
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.
Remove trailing whitespace at the end of this line. Trailing whitespace is typically considered a linting issue and should be avoided.