Skip to content

Commit 604724b

Browse files
authored
remove useQueryEntity and add useEntity hook (#532)
1 parent a9b4d61 commit 604724b

File tree

10 files changed

+504
-27
lines changed

10 files changed

+504
-27
lines changed

.changeset/wise-mugs-swim.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@graphprotocol/hypergraph": patch
3+
---
4+
5+
improve include type for fineOne
6+

.changeset/yummy-beans-float.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@graphprotocol/hypergraph-react": minor
3+
---
4+
5+
remove useQueryEntity and add useEntity hook
6+
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { useEntity } from '@graphprotocol/hypergraph-react';
2+
import { Event as EventType } from '../schema';
3+
4+
export const Event = ({ spaceId, entityId }: { spaceId: string; entityId: string }) => {
5+
const { data, isPending, isError } = useEntity(EventType, {
6+
mode: 'public',
7+
include: {
8+
sponsors: {
9+
jobOffers: {},
10+
},
11+
},
12+
id: entityId,
13+
space: spaceId,
14+
});
15+
16+
console.log({ component: 'Event', isPending, isError, data });
17+
18+
return (
19+
<div>
20+
{isPending && <div>Loading...</div>}
21+
{isError && <div>Error</div>}
22+
{data && (
23+
<div>
24+
<h2>Event Details</h2>
25+
<pre className="text-xs">{JSON.stringify(data, null, 2)}</pre>
26+
</div>
27+
)}
28+
</div>
29+
);
30+
};

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { HypergraphSpaceProvider } from '@graphprotocol/hypergraph-react';
22
import { createLazyFileRoute } from '@tanstack/react-router';
33
import { CreateEvents } from '@/components/create-events';
44
import { CreatePropertiesAndTypesEvent } from '@/components/create-properties-and-types-event';
5+
import { Event } from '@/components/event';
56
import { Playground } from '@/components/playground';
67

78
export const Route = createLazyFileRoute('/playground')({
@@ -12,6 +13,7 @@ function RouteComponent() {
1213
const space = 'a393e509-ae56-4d99-987c-bed71d9db631';
1314
return (
1415
<>
16+
<Event spaceId={space} entityId="cf7c620b-d724-498f-b134-8280dc8249ae" />
1517
<Playground spaceId={space} />
1618
<HypergraphSpaceProvider space={space}>
1719
<div className="flex flex-col gap-4 max-w-(--breakpoint-sm) mx-auto py-8">

packages/hypergraph-react/src/HypergraphSpaceContext.tsx

Lines changed: 48 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use client';
22

3-
import { Entity, store } from '@graphprotocol/hypergraph';
3+
import { Entity, type Id, store } from '@graphprotocol/hypergraph';
44
import { useSelector } from '@xstate/store/react';
55
import * as Schema from 'effect/Schema';
66
import {
@@ -14,6 +14,7 @@ import {
1414
useSyncExternalStore,
1515
} from 'react';
1616
import { useHypergraphApp } from './HypergraphAppContext.js';
17+
import { useEntityPublic } from './internal/use-entity-public.js';
1718
import { usePublicSpace } from './internal/use-public-space.js';
1819

1920
// TODO space can be undefined
@@ -181,19 +182,28 @@ export function useQueryLocal<const S extends Entity.AnyNoContext>(type: S, para
181182
return { entities, deletedEntities };
182183
}
183184

184-
export function useQueryEntity<const S extends Entity.AnyNoContext>(
185+
function useEntityPrivate<const S extends Entity.AnyNoContext>(
185186
type: S,
186-
id: string,
187-
params?: { space?: string; include?: { [K in keyof Schema.Schema.Type<S>]?: Record<string, never> } },
187+
params: {
188+
id: string | Id;
189+
enabled?: boolean;
190+
space?: string;
191+
include?: { [K in keyof Schema.Schema.Type<S>]?: Record<string, Record<string, never>> } | undefined;
192+
},
188193
) {
189194
const { space: spaceFromContext } = useHypergraphSpaceInternal();
190-
const { space: spaceFromParams, include } = params ?? {};
191-
const handle = useSubscribeToSpaceAndGetHandle({ spaceId: spaceFromParams ?? spaceFromContext, enabled: true });
192-
const prevEntityRef = useRef<Entity.Entity<S> | undefined>(undefined);
195+
const { space: spaceFromParams, include, id, enabled = true } = params;
196+
const handle = useSubscribeToSpaceAndGetHandle({ spaceId: spaceFromParams ?? spaceFromContext, enabled });
197+
const prevEntityRef = useRef<{
198+
data: Entity.Entity<S> | undefined;
199+
invalidEntity: Record<string, string | boolean | number | Date> | undefined;
200+
isPending: boolean;
201+
isError: boolean;
202+
}>({ data: undefined, invalidEntity: undefined, isPending: false, isError: false });
193203
const equals = Schema.equivalence(type);
194204

195205
const subscribe = (callback: () => void) => {
196-
if (!handle) {
206+
if (!handle || !enabled) {
197207
return () => {};
198208
}
199209
const handleChange = () => {
@@ -214,7 +224,7 @@ export function useQueryEntity<const S extends Entity.AnyNoContext>(
214224
};
215225

216226
return useSyncExternalStore(subscribe, () => {
217-
if (!handle) {
227+
if (!handle || !enabled) {
218228
return prevEntityRef.current;
219229
}
220230
const doc = handle.doc();
@@ -223,16 +233,39 @@ export function useQueryEntity<const S extends Entity.AnyNoContext>(
223233
}
224234

225235
const found = Entity.findOne(handle, type, include)(id);
226-
if (found === undefined && prevEntityRef.current !== undefined) {
236+
if (found === undefined && prevEntityRef.current.data !== undefined) {
227237
// entity was maybe deleted, delete from the ref
228-
prevEntityRef.current = undefined;
229-
} else if (found !== undefined && prevEntityRef.current === undefined) {
230-
prevEntityRef.current = found;
231-
} else if (found !== undefined && prevEntityRef.current !== undefined && !equals(found, prevEntityRef.current)) {
238+
prevEntityRef.current = { data: undefined, invalidEntity: undefined, isPending: false, isError: false };
239+
} else if (found !== undefined && prevEntityRef.current.data === undefined) {
240+
prevEntityRef.current = { data: found, invalidEntity: undefined, isPending: false, isError: false };
241+
} else if (
242+
found !== undefined &&
243+
prevEntityRef.current.data !== undefined &&
244+
!equals(found, prevEntityRef.current.data)
245+
) {
232246
// found and ref have a value, compare for equality, if they are not equal, update the ref and return
233-
prevEntityRef.current = found;
247+
prevEntityRef.current = { data: found, invalidEntity: undefined, isPending: false, isError: false };
234248
}
235249

236250
return prevEntityRef.current;
237251
});
238252
}
253+
254+
export function useEntity<const S extends Entity.AnyNoContext>(
255+
type: S,
256+
params: {
257+
id: string | Id;
258+
space?: string;
259+
mode: 'private' | 'public';
260+
include?: { [K in keyof Schema.Schema.Type<S>]?: Record<string, Record<string, never>> } | undefined;
261+
},
262+
) {
263+
const resultPublic = useEntityPublic(type, { ...params, enabled: params.mode === 'public' });
264+
const resultPrivate = useEntityPrivate(type, { ...params, enabled: params.mode === 'private' });
265+
266+
if (params.mode === 'public') {
267+
return resultPublic;
268+
}
269+
270+
return resultPrivate;
271+
}

packages/hypergraph-react/src/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ export {
99
HypergraphSpaceProvider,
1010
useCreateEntity,
1111
useDeleteEntity,
12+
useEntity,
1213
useHardDeleteEntity,
13-
useQueryEntity,
1414
useQueryLocal as _useQueryLocal,
1515
useRemoveRelation,
1616
useSpace,
@@ -26,6 +26,7 @@ export { usePublishToPublicSpace } from './hooks/usePublishToSpace.js';
2626
export { generateDeleteOps as _generateDeleteOps } from './internal/generate-delete-ops.js';
2727
export { useCreateEntityPublic as _useCreateEntityPublic } from './internal/use-create-entity-public.js';
2828
export { useDeleteEntityPublic as _useDeleteEntityPublic } from './internal/use-delete-entity-public.js';
29+
export { useEntityPublic as _useEntityPublic } from './internal/use-entity-public.js';
2930
export { useQueryPublic as _useQueryPublic } from './internal/use-query-public.js';
3031
export { preparePublish } from './prepare-publish.js';
3132
export { publishOps } from './publish-ops.js';

0 commit comments

Comments
 (0)