-
Notifications
You must be signed in to change notification settings - Fork 13
add multi spaces filter #562
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 support for querying public entities across multiple spaces (including an `all` scope) and expose the new API through the React hooks | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
| @@ -1,6 +1,6 @@ | ||||
| import { useEntities } from '@graphprotocol/hypergraph-react'; | ||||
| import { createLazyFileRoute } from '@tanstack/react-router'; | ||||
| import { Podcast, Topic } from '@/schema'; | ||||
| import { Podcast, Space, Topic } from '@/schema'; | ||||
|
|
||||
| export const Route = createLazyFileRoute('/podcasts')({ | ||||
| component: RouteComponent, | ||||
|
|
@@ -54,6 +54,8 @@ function RouteComponent() { | |||
| backlinksTotalCountsTypeId1: '972d201a-d780-4568-9e01-543f67b26bee', | ||||
| }); | ||||
|
|
||||
| console.log({ data, isLoading, isError }); | ||||
|
||||
| console.log({ data, isLoading, isError }); |
Copilot
AI
Dec 3, 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.
Debug console.log statement should be removed before merging to production. This log was added to test the new spaces: 'all' functionality.
| console.log('spaces', spaces); |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -8,12 +8,14 @@ import { request } from 'graphql-request'; | |||||
| import type { RelationsListWithNodes } from '../utils/convert-relations.js'; | ||||||
| import type { RelationTypeIdInfo } from '../utils/get-relation-type-ids.js'; | ||||||
| import { buildRelationsSelection } from '../utils/relation-query-helpers.js'; | ||||||
| import type { SpaceSelection } from './internal/space-selection.js'; | ||||||
| import { normalizeSpaceSelection } from './internal/space-selection.js'; | ||||||
| import type { SpaceSelectionInput } from './types.js'; | ||||||
|
|
||||||
| export type FindManyPublicParams<S extends Schema.Schema.AnyNoContext> = { | ||||||
| export type FindManyPublicParams<S extends Schema.Schema.AnyNoContext> = SpaceSelectionInput & { | ||||||
| filter?: Entity.EntityFilter<Schema.Schema.Type<S>> | undefined; | ||||||
| // TODO: restrict multi-level nesting to the actual relation keys | ||||||
| include?: Entity.EntityInclude<S> | undefined; | ||||||
| space: string; | ||||||
| first?: number | undefined; | ||||||
| offset?: number | undefined; | ||||||
| orderBy?: | ||||||
|
|
@@ -25,34 +27,73 @@ export type FindManyPublicParams<S extends Schema.Schema.AnyNoContext> = { | |||||
| backlinksTotalCountsTypeId1?: string | undefined; | ||||||
| }; | ||||||
|
|
||||||
| const buildEntitiesQuery = (relationInfoLevel1: RelationTypeIdInfo[], useOrderBy: boolean) => { | ||||||
| const level1Relations = buildRelationsSelection(relationInfoLevel1); | ||||||
| const buildEntitiesQuery = ( | ||||||
| relationInfoLevel1: RelationTypeIdInfo[], | ||||||
| useOrderBy: boolean, | ||||||
| spaceSelection: SpaceSelection, | ||||||
| ) => { | ||||||
| const level1Relations = buildRelationsSelection(relationInfoLevel1, spaceSelection.mode); | ||||||
|
|
||||||
| const queryName = useOrderBy ? 'entitiesOrderedByProperty' : 'entities'; | ||||||
| const orderByParams = useOrderBy ? '$propertyId: UUID!, $sortDirection: SortOrder!, ' : ''; | ||||||
| const variableDefinitions = [ | ||||||
| spaceSelection.mode === 'single' | ||||||
| ? '$spaceId: UUID!' | ||||||
| : spaceSelection.mode === 'many' | ||||||
| ? '$spaceIds: [UUID!]!' | ||||||
| : undefined, | ||||||
| '$typeIds: [UUID!]!', | ||||||
| useOrderBy ? '$propertyId: UUID!' : undefined, | ||||||
| useOrderBy ? '$sortDirection: SortOrder!' : undefined, | ||||||
| '$first: Int', | ||||||
| '$filter: EntityFilter!', | ||||||
| '$offset: Int', | ||||||
| '$backlinksTotalCountsTypeId1: UUID', | ||||||
| '$backlinksTotalCountsTypeId1Present: Boolean!', | ||||||
| ] | ||||||
| .filter(Boolean) | ||||||
| .join(', '); | ||||||
|
|
||||||
| const orderByArgs = useOrderBy ? 'propertyId: $propertyId\n sortDirection: $sortDirection\n ' : ''; | ||||||
| const entitySpaceFilter = | ||||||
| spaceSelection.mode === 'single' | ||||||
| ? 'spaceIds: {in: [$spaceId]},' | ||||||
| : spaceSelection.mode === 'many' | ||||||
| ? 'spaceIds: {in: $spaceIds},' | ||||||
| : ''; | ||||||
| const valuesListFilter = | ||||||
| spaceSelection.mode === 'single' | ||||||
| ? '(filter: { spaceId: { is: $spaceId } })' | ||||||
| : spaceSelection.mode === 'many' | ||||||
| ? '(filter: { spaceId: { in: $spaceIds } })' | ||||||
| : ''; | ||||||
| const backlinksSpaceFilter = | ||||||
| spaceSelection.mode === 'single' | ||||||
| ? 'spaceId: {is: $spaceId}, ' | ||||||
| : spaceSelection.mode === 'many' | ||||||
| ? 'spaceId: {in: $spaceIds}, ' | ||||||
| : ''; | ||||||
|
|
||||||
| return ` | ||||||
| query ${queryName}($spaceId: UUID!, $typeIds: [UUID!]!, ${orderByParams}$first: Int, $filter: EntityFilter!, $offset: Int, $backlinksTotalCountsTypeId1: UUID, $backlinksTotalCountsTypeId1Present: Boolean!) { | ||||||
| query ${queryName}(${variableDefinitions}) { | ||||||
| entities: ${queryName}( | ||||||
| ${orderByArgs}filter: { and: [{ | ||||||
| relations: {some: {typeId: {is: "8f151ba4-de20-4e3c-9cb4-99ddf96f48f1"}, toEntityId: {in: $typeIds}}}, | ||||||
| spaceIds: {in: [$spaceId]}, | ||||||
| ${entitySpaceFilter} | ||||||
| }, $filter]} | ||||||
| first: $first | ||||||
| offset: $offset | ||||||
| ) { | ||||||
| id | ||||||
| name | ||||||
| valuesList(filter: {spaceId: {is: $spaceId}}) { | ||||||
| valuesList${valuesListFilter} { | ||||||
| propertyId | ||||||
| string | ||||||
| boolean | ||||||
| number | ||||||
| time | ||||||
| point | ||||||
| } | ||||||
| backlinksTotalCountsTypeId1: backlinks(filter: { spaceId: {is: $spaceId}, fromEntity: { typeIds: { is: [$backlinksTotalCountsTypeId1] } }}) @include(if: $backlinksTotalCountsTypeId1Present) { | ||||||
| backlinksTotalCountsTypeId1: backlinks(filter: { ${backlinksSpaceFilter}fromEntity: { typeIds: { is: [$backlinksTotalCountsTypeId1] } }}) @include(if: $backlinksTotalCountsTypeId1Present) { | ||||||
| totalCount | ||||||
| } | ||||||
| ${level1Relations} | ||||||
|
|
@@ -150,7 +191,16 @@ export const findManyPublic = async <S extends Schema.Schema.AnyNoContext>( | |||||
| type: S, | ||||||
| params?: FindManyPublicParams<S>, | ||||||
| ) => { | ||||||
| const { filter, include, space, first = 100, offset = 0, orderBy, backlinksTotalCountsTypeId1 } = params ?? {}; | ||||||
| const { | ||||||
| filter, | ||||||
| include, | ||||||
| space, | ||||||
| spaces, | ||||||
| first = 100, | ||||||
| offset = 0, | ||||||
| orderBy, | ||||||
| backlinksTotalCountsTypeId1, | ||||||
| } = params ?? {}; | ||||||
|
|
||||||
| // constructing the relation type ids for the query | ||||||
| const relationTypeIds = Utils.getRelationTypeIds(type, include); | ||||||
|
|
@@ -187,18 +237,26 @@ export const findManyPublic = async <S extends Schema.Schema.AnyNoContext>( | |||||
| } | ||||||
|
|
||||||
| // Build the query dynamically with aliases for each relation type ID | ||||||
|
||||||
| // Build the query dynamically with aliases for each relation type ID | |
| // Normalize space selection from params |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| export type SpaceSelection = | ||
| | { | ||
| mode: 'single'; | ||
| spaceId: string; | ||
| } | ||
| | { | ||
| mode: 'many'; | ||
| spaceIds: readonly [string, ...string[]]; | ||
| } | ||
| | { | ||
| mode: 'all'; | ||
| }; | ||
|
|
||
| export const normalizeSpaceSelection = ( | ||
| space: string | undefined, | ||
| spaces: readonly [string, ...string[]] | 'all' | undefined, | ||
| ): SpaceSelection => { | ||
| if (space && spaces) { | ||
| throw new Error('Provide either "space" or "spaces", not both.'); | ||
| } | ||
|
|
||
| if (space) { | ||
| return { mode: 'single', spaceId: space }; | ||
| } | ||
|
|
||
| if (spaces === 'all') { | ||
| return { mode: 'all' }; | ||
| } | ||
|
|
||
| if (spaces && spaces.length > 0) { | ||
| return { mode: 'many', spaceIds: spaces }; | ||
| } | ||
|
|
||
| throw new Error('Either "space" or non-empty "spaces" must be provided.'); | ||
| }; |
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 the line.