Skip to content

Commit d502673

Browse files
authored
fetch total count (#558)
1 parent 083edfd commit d502673

21 files changed

+304
-152
lines changed

.changeset/four-papers-thank.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
---
2+
"@graphprotocol/hypergraph-react": patch
3+
"@graphprotocol/hypergraph": patch
4+
---
5+
6+
add fetching of totalCount on relations
7+
8+
For:
9+
10+
```ts
11+
export const Podcast = Entity.Schema(
12+
{
13+
name: Type.String,
14+
hosts: Type.Relation(Person),
15+
},
16+
{
17+
types: [Id('4c81561d-1f95-4131-9cdd-dd20ab831ba2')],
18+
properties: {
19+
name: Id('a126ca53-0c8e-48d5-b888-82c734c38935'),
20+
hosts: Id('c72d9abb-bca8-4e86-b7e8-b71e91d2b37e'),
21+
},
22+
},
23+
);
24+
```
25+
26+
you can now use:
27+
28+
```ts
29+
useEntities(Podcast, {
30+
mode: 'public',
31+
include: {
32+
hostsTotalCount: true,
33+
},
34+
});
35+
```

apps/events/src/routes/podcasts.lazy.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,11 @@ function RouteComponent() {
4444
listenOn: {},
4545
hosts: {
4646
avatar: {},
47+
avatarTotalCount: true,
4748
},
49+
hostsTotalCount: true,
4850
episodes: {},
51+
episodesTotalCount: true,
4952
},
5053
orderBy: { property: 'dateFounded', direction: 'asc' },
5154
backlinksTotalCountsTypeId1: '972d201a-d780-4568-9e01-543f67b26bee',
@@ -67,6 +70,8 @@ function RouteComponent() {
6770
<div>--{listenOn._relation.website}</div>
6871
</div>
6972
))}
73+
<div>Total hosts: {podcast.hostsTotalCount ?? 0}</div>
74+
<div>Total episodes: {podcast.episodesTotalCount ?? 0}</div>
7075
</div>
7176
))}
7277
</>

packages/hypergraph-react/src/hooks/use-entities.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ import { useEntitiesPublic } from '../internal/use-entities-public.js';
66
type UseEntitiesParams<S extends Schema.Schema.AnyNoContext> = {
77
mode: 'public' | 'private';
88
filter?: Entity.EntityFilter<Schema.Schema.Type<S>> | undefined;
9-
// TODO: for multi-level nesting it should only allow the allowed properties instead of Record<string, Record<string, never>>
10-
include?: { [K in keyof Schema.Schema.Type<S>]?: Record<string, Record<string, never>> } | undefined;
9+
// TODO: restrict multi-level nesting to the actual relation keys
10+
include?: Entity.EntityInclude<S> | undefined;
1111
space?: string | undefined;
1212
first?: number | undefined;
1313
offset?: number | undefined;

packages/hypergraph-react/src/hooks/use-entity.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { Id } from '@graphprotocol/hypergraph';
1+
import type { Entity, Id } from '@graphprotocol/hypergraph';
22
import type * as Schema from 'effect/Schema';
33
import { useEntityPrivate } from '../internal/use-entity-private.js';
44
import { useEntityPublic } from '../internal/use-entity-public.js';
@@ -9,7 +9,7 @@ export function useEntity<const S extends Schema.Schema.AnyNoContext>(
99
id: string | Id;
1010
space?: string;
1111
mode: 'private' | 'public';
12-
include?: { [K in keyof Schema.Schema.Type<S>]?: Record<string, Record<string, never>> } | undefined;
12+
include?: Entity.EntityInclude<S> | undefined;
1313
},
1414
) {
1515
const resultPublic = useEntityPublic(type, { ...params, enabled: params.mode === 'public' });

packages/hypergraph-react/src/internal/types.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ import type * as Schema from 'effect/Schema';
44
export type QueryPublicParams<S extends Schema.Schema.AnyNoContext> = {
55
enabled?: boolean | undefined;
66
filter?: Entity.EntityFilter<Schema.Schema.Type<S>> | undefined;
7-
// TODO: for multi-level nesting it should only allow the allowed properties instead of Record<string, Record<string, never>>
8-
include?: { [K in keyof Schema.Schema.Type<S>]?: Record<string, Record<string, never>> } | undefined;
7+
// TODO: restrict multi-level nesting to the actual relation keys
8+
include?: Entity.EntityInclude<S> | undefined;
99
space?: string | undefined;
1010
first?: number | undefined;
1111
offset?: number | undefined;

packages/hypergraph-react/src/internal/use-entities-private.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ type QueryParams<S extends Schema.Schema.AnyNoContext> = {
88
space?: string | undefined;
99
enabled: boolean;
1010
filter?: Entity.EntityFilter<Schema.Schema.Type<S>> | undefined;
11-
include?: { [K in keyof Schema.Schema.Type<S>]?: Record<string, Record<string, never>> } | undefined;
11+
include?: Entity.EntityInclude<S> | undefined;
1212
};
1313

1414
export function useEntitiesPrivate<const S extends Schema.Schema.AnyNoContext>(type: S, params?: QueryParams<S>) {

packages/hypergraph-react/src/internal/use-entity-private.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ export function useEntityPrivate<const S extends Schema.Schema.AnyNoContext>(
1010
id: string | Id;
1111
enabled?: boolean;
1212
space?: string;
13-
include?: { [K in keyof Schema.Schema.Type<S>]?: Record<string, Record<string, never>> } | undefined;
13+
include?: Entity.EntityInclude<S> | undefined;
1414
},
1515
) {
1616
const { space: spaceFromContext } = useHypergraphSpaceInternal();

packages/hypergraph-react/src/internal/use-entity-public.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ type UseEntityPublicParams<S extends Schema.Schema.AnyNoContext> = {
99
id: string;
1010
enabled?: boolean;
1111
space?: string;
12-
// TODO: for multi-level nesting it should only allow the allowed properties instead of Record<string, Record<string, never>>
13-
include?: { [K in keyof Schema.Schema.Type<S>]?: Record<string, Record<string, never>> } | undefined;
12+
// TODO: restrict multi-level nesting to the actual relation keys
13+
include?: Entity.EntityInclude<S> | undefined;
1414
};
1515

1616
export const useEntityPublic = <S extends Schema.Schema.AnyNoContext>(type: S, params: UseEntityPublicParams<S>) => {

packages/hypergraph/src/entity/decodedEntitiesCache.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import type * as Schema from 'effect/Schema';
2-
import type { Entity } from './types.js';
2+
import type { Entity, EntityInclude } from './types.js';
33

44
export type QueryEntry = {
55
data: Array<Entity<Schema.Schema.AnyNoContext>>; // holds the decoded entities of this query and must be a stable reference and use the same reference for the `entities` array
66
listeners: Array<() => void>; // listeners to this query
77
isInvalidated: boolean;
8-
include: { [K in keyof Schema.Schema.Type<Schema.Schema.AnyNoContext>]?: Record<string, Record<string, never>> };
8+
include: EntityInclude<Schema.Schema.AnyNoContext>;
99
};
1010

1111
export type DecodedEntitiesCacheEntry = {

packages/hypergraph/src/entity/find-many-private.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import type {
1616
Entity,
1717
EntityFieldFilter,
1818
EntityFilter,
19+
EntityInclude,
1920
EntityNumberFilter,
2021
EntityStringFilter,
2122
} from './types.js';
@@ -77,7 +78,7 @@ const subscribeToDocumentChanges = (handle: DocHandle<DocumentContent>) => {
7778
const cacheEntry = decodedEntitiesCache.get(typeId);
7879
if (!cacheEntry) continue;
7980

80-
let includeFromAllQueries = {};
81+
let includeFromAllQueries: EntityInclude<Schema.Schema.AnyNoContext> = {};
8182
for (const [, query] of cacheEntry.queries) {
8283
includeFromAllQueries = deepMerge(includeFromAllQueries, query.include);
8384
}
@@ -244,7 +245,7 @@ export function findManyPrivate<const S extends Schema.Schema.AnyNoContext>(
244245
handle: DocHandle<DocumentContent>,
245246
type: S,
246247
filter: EntityFilter<Schema.Schema.Type<S>> | undefined,
247-
include: { [K in keyof Schema.Schema.Type<S>]?: Record<string, Record<string, never>> } | undefined,
248+
include: EntityInclude<S> | undefined,
248249
): { entities: Readonly<Array<Entity<S>>>; corruptEntityIds: Readonly<Array<string>> } {
249250
const typeId = SchemaAST.getAnnotation<string[]>(TypeIdsSymbol)(type.ast as SchemaAST.TypeLiteral).pipe(
250251
Option.getOrElse(() => []),
@@ -413,7 +414,7 @@ export function subscribeToFindMany<const S extends Schema.Schema.AnyNoContext>(
413414
handle: DocHandle<DocumentContent>,
414415
type: S,
415416
filter: { [K in keyof Schema.Schema.Type<S>]?: EntityFieldFilter<Schema.Schema.Type<S>[K]> } | undefined,
416-
include: { [K in keyof Schema.Schema.Type<S>]?: Record<string, Record<string, never>> } | undefined,
417+
include: EntityInclude<S> | undefined,
417418
): FindManySubscription<S> {
418419
const queryKey = filter ? canonicalize(filter) : 'all';
419420
const typeIds = SchemaAST.getAnnotation<string[]>(TypeIdsSymbol)(type.ast as SchemaAST.TypeLiteral).pipe(

0 commit comments

Comments
 (0)