Skip to content

add orderBy to Entities.findManyPublic and useEntities(mode: public) - #553

Merged
nikgraf merged 1 commit into
mainfrom
nik/add-order-by
Nov 17, 2025
Merged

add orderBy to Entities.findManyPublic and useEntities(mode: public)#553
nikgraf merged 1 commit into
mainfrom
nik/add-order-by

Conversation

@nikgraf

@nikgraf nikgraf commented Nov 17, 2025

Copy link
Copy Markdown
Collaborator

No description provided.

@nikgraf nikgraf self-assigned this Nov 17, 2025
@nikgraf
nikgraf requested a review from Copilot November 17, 2025 13:04
@nikgraf
nikgraf merged commit 69923e1 into main Nov 17, 2025
10 checks passed
@nikgraf
nikgraf deleted the nik/add-order-by branch November 17, 2025 13:06

Copilot AI left a comment

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.

Pull Request Overview

This PR adds support for ordering entities by property values in the public entity query APIs. The feature enables developers to sort results by any property field in ascending or descending order.

  • Adds orderBy parameter to FindManyPublicParams and QueryPublicParams types
  • Implements ordering logic with new GraphQL queries for entitiesOrderedByProperty
  • Updates React hooks (useEntities, useEntitiesPublic) to support the orderBy parameter

Reviewed Changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
packages/hypergraph/src/entity/find-many-public.ts Adds orderBy parameter support, new GraphQL queries for ordered entity retrieval (Level 0-2), and validation logic to extract propertyId from schema
packages/hypergraph-react/src/internal/use-entities-public.tsx Updates hook to extract and pass orderBy parameter to findManyPublic, includes it in query key for cache invalidation
packages/hypergraph-react/src/internal/types.ts Adds orderBy type definition to QueryPublicParams
packages/hypergraph-react/src/hooks/use-entities.tsx Updates useEntities hook to extract and forward orderBy parameter when mode is 'public'
apps/events/src/routes/podcasts.lazy.tsx Demonstrates orderBy usage by sorting podcasts by dateFounded in ascending order
.changeset/calm-games-trade.md Documents the feature addition for the patch release

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +497 to +501
const propertyIdAnnotation = SchemaAST.getAnnotation<string>(Constants.PropertyIdSymbol)(propertyType);

if (Option.isNone(propertyIdAnnotation)) {
throw new Error(`Property "${String(orderBy.property)}" is missing a propertyId annotation`);
}

Copilot AI Nov 17, 2025

Copy link

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.

Copilot uses AI. Check for mistakes.
Comment on lines +181 to +341
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
}
}
}
`;

Copilot AI Nov 17, 2025

Copy link

Choose a reason for hiding this comment

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

[nitpick] The three new entitiesOrderedByProperty GraphQL query documents (Level0, Level1, Level2) are essentially duplicates of the original queries with added sorting parameters. This creates significant code duplication (~160 lines) that will be difficult to maintain. Consider refactoring to use a query builder pattern or template string functions to generate these queries dynamically, reducing duplication and making future changes easier to maintain.

Copilot uses AI. Check for mistakes.
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)}"`);

Copilot AI Nov 17, 2025

Copy link

Choose a reason for hiding this comment

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

The error message should provide more actionable guidance. Consider including available properties in the error message to help developers debug the issue, e.g., Cannot order by unknown property "${String(orderBy.property)}". Available properties: ${availableProps.join(', ')}.

Suggested change
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 uses AI. Check for mistakes.
Comment on lines +6 to +7
add orderBy to Entities.findManyPublic and useEntities(mode: 'public')

No newline at end of file

Copilot AI Nov 17, 2025

Copy link

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.

Suggested change
add orderBy to Entities.findManyPublic and useEntities(mode: 'public')
add orderBy to Entities.findManyPublic and useEntities(mode: 'public')

Copilot uses AI. Check for mistakes.
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.

2 participants