Skip to content

Conversation

@nikgraf
Copy link
Collaborator

@nikgraf nikgraf commented Nov 19, 2025

No description provided.

@nikgraf nikgraf changed the title relations per alias + backlinks graphql alias per relation + backlinks support Nov 19, 2025
@nikgraf nikgraf requested a review from Copilot November 19, 2025 19:31
Copilot finished reviewing on behalf of nikgraf November 19, 2025 19:33
Copy link
Contributor

Copilot AI left a comment

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 introduces GraphQL alias support per relation and adds backlink functionality to the hypergraph package. The changes enable more efficient querying of relations by using aliased fields in GraphQL queries, eliminating the need for client-side filtering, and adds a new Type.Backlink API for defining reverse relations.

Key changes:

  • Introduced Type.Backlink function and RelationBacklinkSymbol to support backlink relations
  • Refactored GraphQL query generation to use dynamic aliasing per relation type ID instead of multiple static query documents
  • Updated relation conversion logic to leverage aliased fields for improved query efficiency

Reviewed Changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
packages/hypergraph/src/constants.ts Added new RelationBacklinkSymbol constant for marking backlink relations
packages/hypergraph/src/type/type.ts Introduced Backlink function and updated Relation to support backlink option
packages/hypergraph/src/utils/get-relation-type-ids.ts Refactored to return structured RelationTypeIdInfo objects with listField metadata
packages/hypergraph/src/utils/relation-query-helpers.ts New utility for building GraphQL relation selections with aliases and backlink support
packages/hypergraph/src/utils/convert-relations.ts Updated to use aliased relation fields with fallback to legacy behavior
packages/hypergraph/src/entity/find-one-public.ts Simplified query building using dynamic relation selection helpers
packages/hypergraph/src/entity/find-many-public.ts Consolidated multiple query variants into single dynamic query builder
packages/hypergraph/src/entity/search-many-public.ts Refactored to use dynamic query building with relation aliases
packages/hypergraph-react/src/internal/use-entity-public.tsx Simplified to delegate to Entity.findOnePublic instead of duplicating logic
packages/hypergraph-react/src/internal/use-entities-public.tsx Removed manual relation type ID extraction, now handled internally
packages/hypergraph-react/src/hooks/use-entities-public-infinite.ts Updated query key to use include parameter instead of relation type IDs
apps/events/src/schema.ts Added example schema demonstrating backlink usage with Episode2 and Podcast
apps/events/src/routes/podcasts.lazy.tsx Updated test route with commented debugging code
.changeset/plain-turkeys-matter.md Added changeset for the new feature

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

`;
type RelationsListWithTotalCount = {
totalCount: number;
} & RelationsListItem[];
Copy link

Copilot AI Nov 19, 2025

Choose a reason for hiding this comment

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

The type definition for RelationsListWithTotalCount is incorrect. It attempts to use an intersection type (&) between an object with a totalCount property and an array type, which is invalid. Consider defining it as an array type with an additional property, or restructure the type to properly represent the API response (e.g., { totalCount: number; items: RelationsListItem[] }).

Suggested change
} & RelationsListItem[];
items: RelationsListItem[];
};

Copilot uses AI. Check for mistakes.
Comment on lines +6 to +7
add Type.Backlink

No newline at end of file
Copy link

Copilot AI Nov 19, 2025

Choose a reason for hiding this comment

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

The changeset description is too brief and lacks proper capitalization. Consider providing a more descriptive message that explains what the change does, such as "Add Type.Backlink support for GraphQL alias per relation and backlinks".

Suggested change
add Type.Backlink
Add Type.Backlink support for GraphQL alias per relation and backlinks.

Copilot uses AI. Check for mistakes.
}, [result.data, type]);

return { ...result, data, invalidEntity };
return { ...result, data: result.data || null, invalidEntity: null };
Copy link

Copilot AI Nov 19, 2025

Choose a reason for hiding this comment

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

The return statement assumes result.data could be null/undefined but uses || which will also treat falsy values (like 0, false, "") as null. Consider using nullish coalescing (??) instead: data: result.data ?? null to only default on null/undefined values.

Suggested change
return { ...result, data: result.data || null, invalidEntity: null };
return { ...result, data: result.data ?? null, invalidEntity: null };

Copilot uses AI. Check for mistakes.

// @ts-expect-error TODO: fix this
const { data, invalidEntities } = parseResult({ entities: result.search }, type);
console.log('searchManyPublic result:', result);
Copy link

Copilot AI Nov 19, 2025

Choose a reason for hiding this comment

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

Debug console.log statement should be removed before merging to production. This appears to be leftover debugging code.

Suggested change
console.log('searchManyPublic result:', result);

Copilot uses AI. Check for mistakes.
? entityQueryDocumentLevel1
: entityQueryDocumentLevel0;
const queryDocument = buildEntityQuery(relationTypeIds);
console.log({ queryDocument });
Copy link

Copilot AI Nov 19, 2025

Choose a reason for hiding this comment

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

Debug console.log statement should be removed before merging to production. This appears to be leftover debugging code.

Suggested change
console.log({ queryDocument });

Copilot uses AI. Check for mistakes.
valuesList: ValuesList;
} & {
// For nested aliased relationsList_* fields at level 2
[K: `relationsList_${string}`]: RelationsListWithTotalCount;
Copy link

Copilot AI Nov 19, 2025

Choose a reason for hiding this comment

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

The template literal type syntax [K: \relationsList_${string}`]is incorrect. It should useinfor index signatures:[K in `relationsList_${string}`]. Without in`, this is not a valid TypeScript index signature.

Copilot uses AI. Check for mistakes.

type RelationsListWithTotalCount = {
totalCount: number;
} & RelationsListItem[];
Copy link

Copilot AI Nov 19, 2025

Choose a reason for hiding this comment

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

The type definition for RelationsListWithTotalCount is incorrect. It attempts to use an intersection type (&) between an object with a totalCount property and an array type, which is invalid. Consider defining it as an array type with an additional property, or restructure the type to properly represent the API response (e.g., { totalCount: number; items: RelationsListItem[] }).

Suggested change
} & RelationsListItem[];
items: RelationsListItem[];
};

Copilot uses AI. Check for mistakes.
relationsList?: RelationsListItem[];
} & {
// For aliased relationsList_* fields with proper typing
[K: `relationsList_${string}`]: RelationsListWithTotalCount;
Copy link

Copilot AI Nov 19, 2025

Choose a reason for hiding this comment

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

The template literal type syntax [K: \relationsList_${string}`]is incorrect. It should useinfor index signatures:[K in `relationsList_${string}`]. Without in`, this is not a valid TypeScript index signature.

Suggested change
[K: `relationsList_${string}`]: RelationsListWithTotalCount;
[K in `relationsList_${string}`]: RelationsListWithTotalCount;

Copilot uses AI. Check for mistakes.
}[];
} & {
// For aliased relationsList_* fields - provides proper typing with totalCount
[K: `relationsList_${string}`]: RelationsListWithTotalCount;
Copy link

Copilot AI Nov 19, 2025

Choose a reason for hiding this comment

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

The template literal type syntax [K: \relationsList_${string}`]is incorrect. It should useinfor index signatures:[K in `relationsList_${string}`]. Without in`, this is not a valid TypeScript index signature.

Copilot uses AI. Check for mistakes.
Comment on lines +12 to 38
// useEffect(() => {
// setTimeout(async () => {
// const result = await Entity.searchManyPublic(Podcast, {
// query: 'Joe',
// space: space,
// // include: {
// // listenOn: {},
// // },
// });
// console.log('searchManyPublic result:', result);
// }, 1000);
// }, []);

// const { data: podcast } = useEntity(Podcast, {
// id: 'f5d27d3e-3a51-452d-bac2-702574381633',
// mode: 'public',
// space: space,
// include: {
// listenOn: {},
// hosts: {
// avatar: {},
// },
// episodes: {},
// },
// });
// console.log({ podcast });

Copy link

Copilot AI Nov 19, 2025

Choose a reason for hiding this comment

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

Large blocks of commented-out code should be removed rather than left in the codebase. If this code is needed for reference, consider preserving it in git history or documentation instead.

Suggested change
// useEffect(() => {
// setTimeout(async () => {
// const result = await Entity.searchManyPublic(Podcast, {
// query: 'Joe',
// space: space,
// // include: {
// // listenOn: {},
// // },
// });
// console.log('searchManyPublic result:', result);
// }, 1000);
// }, []);
// const { data: podcast } = useEntity(Podcast, {
// id: 'f5d27d3e-3a51-452d-bac2-702574381633',
// mode: 'public',
// space: space,
// include: {
// listenOn: {},
// hosts: {
// avatar: {},
// },
// episodes: {},
// },
// });
// console.log({ podcast });

Copilot uses AI. Check for mistakes.
@nikgraf nikgraf merged commit 083edfd into main Nov 20, 2025
6 checks passed
@nikgraf nikgraf deleted the nik/relations-per-alias branch November 20, 2025 09:49
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