Loading space...
;
+ }
+
const userOptions = users.map((user) => ({ value: user.id, label: user.name }));
return (
<>
diff --git a/apps/events/src/components/todos2.tsx b/apps/events/src/components/todos2.tsx
index 98ac882a..22de6fc9 100644
--- a/apps/events/src/components/todos2.tsx
+++ b/apps/events/src/components/todos2.tsx
@@ -6,8 +6,8 @@ import {
publishOps,
useCreateEntity,
useDeleteEntity,
- useHypergraphSpace,
useQuery,
+ useSpace,
useUpdateEntity,
} from '@graphprotocol/hypergraph-react';
import { useQueryClient } from '@tanstack/react-query';
@@ -34,7 +34,7 @@ export const Todos2 = () => {
isError: isErrorUsers,
// preparePublish: preparePublishUsers,
} = useQuery(User, { mode: 'private' });
- const space = useHypergraphSpace();
+ const { ready: spaceReady, id: spaceId } = useSpace({ mode: 'private' });
const createTodo = useCreateEntity(Todo2);
const updateTodo = useUpdateEntity(Todo2);
const createUser = useCreateEntity(User);
@@ -57,6 +57,10 @@ export const Todos2 = () => {
const userOptions = dataUsers.map((user) => ({ value: user.id, label: user.name }));
+ if (!spaceReady) {
+ return Loading space...
;
+ }
+
return (
<>
@@ -231,7 +235,7 @@ export const Todos2 = () => {
ops,
// @ts-expect-error - TODO: fix the types error
walletClient: smartAccountWalletClient,
- space,
+ space: spaceId,
name: 'Update users and todos',
});
console.log('publishOpsResult', publishOpsResult);
diff --git a/apps/events/src/components/users.tsx b/apps/events/src/components/users.tsx
index 4d848cb3..f1441952 100644
--- a/apps/events/src/components/users.tsx
+++ b/apps/events/src/components/users.tsx
@@ -1,4 +1,4 @@
-import { useCreateEntity, useQuery } from '@graphprotocol/hypergraph-react';
+import { useCreateEntity, useQuery, useSpace } from '@graphprotocol/hypergraph-react';
import { useState } from 'react';
import { User } from '../schema.js';
import { Button } from './ui/button.js';
@@ -7,9 +7,14 @@ import { UserEntry } from './user-entry.js';
export const Users = () => {
const { data: users } = useQuery(User, { mode: 'private' });
- const createEntity = useCreateEntity(User);
+ const { ready: spaceReady } = useSpace({ mode: 'private' });
+ const createEntity = useCreateEntity(User, { space: '1c954768-7e14-4f0f-9396-0fe9dcd55fe8' });
const [newUserName, setNewUserName] = useState('');
+ if (!spaceReady) {
+ return
Loading space...
;
+ }
+
return (
<>
Users
diff --git a/apps/events/src/components/users/users-public.tsx b/apps/events/src/components/users/users-public.tsx
index 490e78af..cee023e2 100644
--- a/apps/events/src/components/users/users-public.tsx
+++ b/apps/events/src/components/users/users-public.tsx
@@ -1,11 +1,11 @@
import { getSmartAccountWalletClient } from '@/lib/smart-account';
-import { _generateDeleteOps, publishOps, useHypergraphSpace, useQuery } from '@graphprotocol/hypergraph-react';
+import { _generateDeleteOps, publishOps, useQuery, useSpace } from '@graphprotocol/hypergraph-react';
import { User } from '../../schema';
import { Spinner } from '../spinner';
import { Button } from '../ui/button';
export const UsersPublic = () => {
- const space = useHypergraphSpace();
+ const { id: spaceId } = useSpace({ mode: 'public' });
const { data: dataPublic, isLoading: isLoadingPublic, isError: isErrorPublic } = useQuery(User, { mode: 'public' });
return (
@@ -26,11 +26,12 @@ export const UsersPublic = () => {
if (!smartAccountWalletClient) {
throw new Error('Missing smartAccountWalletClient');
}
- const ops = await _generateDeleteOps({ id: user.id, space });
+ const ops = await _generateDeleteOps({ id: user.id, space: spaceId });
const result = await publishOps({
ops,
+ // @ts-expect-error - TODO: fix the types error
walletClient: smartAccountWalletClient,
- space,
+ space: spaceId,
name: 'Delete User',
});
console.log('result', result);
diff --git a/apps/events/src/routes/playground.lazy.tsx b/apps/events/src/routes/playground.lazy.tsx
index 10f05864..3fc4a459 100644
--- a/apps/events/src/routes/playground.lazy.tsx
+++ b/apps/events/src/routes/playground.lazy.tsx
@@ -14,8 +14,8 @@ function RouteComponent() {
);
diff --git a/apps/events/src/routes/space/$spaceId/chat.tsx b/apps/events/src/routes/space/$spaceId/chat.tsx
index 4121bcda..d91ca91a 100644
--- a/apps/events/src/routes/space/$spaceId/chat.tsx
+++ b/apps/events/src/routes/space/$spaceId/chat.tsx
@@ -1,9 +1,6 @@
import { SpaceChat } from '@/components/SpaceChat';
-import { store } from '@graphprotocol/hypergraph';
-import { HypergraphSpaceProvider, useHypergraphApp } from '@graphprotocol/hypergraph-react';
+import { useHypergraphApp } from '@graphprotocol/hypergraph-react';
import { createFileRoute } from '@tanstack/react-router';
-import { useSelector } from '@xstate/store/react';
-import { useEffect } from 'react';
export const Route = createFileRoute('/space/$spaceId/chat')({
component: RouteComponent,
@@ -11,29 +8,15 @@ export const Route = createFileRoute('/space/$spaceId/chat')({
function RouteComponent() {
const { spaceId } = Route.useParams();
- const spaces = useSelector(store, (state) => state.context.spaces);
- const { subscribeToSpace, isConnecting } = useHypergraphApp();
- useEffect(() => {
- if (!isConnecting) {
- subscribeToSpace({ spaceId });
- }
- }, [isConnecting, subscribeToSpace, spaceId]);
-
- const space = spaces.find((space) => space.id === spaceId);
+ const { isConnecting } = useHypergraphApp();
if (isConnecting) {
return
Loading …
;
}
- if (!space) {
- return
Space not found
;
- }
-
return (
-
-
-
+
);
}
diff --git a/apps/events/src/routes/space/$spaceId/index.tsx b/apps/events/src/routes/space/$spaceId/index.tsx
index e9e5a4fb..f7e9d7a3 100644
--- a/apps/events/src/routes/space/$spaceId/index.tsx
+++ b/apps/events/src/routes/space/$spaceId/index.tsx
@@ -4,11 +4,9 @@ import { TodosReadOnly } from '@/components/todos-read-only';
import { TodosReadOnlyFilter } from '@/components/todos-read-only-filter';
import { Button } from '@/components/ui/button';
import { Users } from '@/components/users';
-import { store } from '@graphprotocol/hypergraph';
import { HypergraphSpaceProvider, useHypergraphApp } from '@graphprotocol/hypergraph-react';
import { createFileRoute } from '@tanstack/react-router';
-import { useSelector } from '@xstate/store/react';
-import { useEffect, useState } from 'react';
+import { useState } from 'react';
export const Route = createFileRoute('/space/$spaceId/')({
component: Space,
@@ -16,25 +14,13 @@ export const Route = createFileRoute('/space/$spaceId/')({
function Space() {
const { spaceId } = Route.useParams();
- const spaces = useSelector(store, (state) => state.context.spaces);
- const { subscribeToSpace, isConnecting } = useHypergraphApp();
- useEffect(() => {
- if (!isConnecting) {
- subscribeToSpace({ spaceId });
- }
- }, [isConnecting, subscribeToSpace, spaceId]);
+ const { isConnecting } = useHypergraphApp();
const [show2ndTodos, setShow2ndTodos] = useState(false);
- const space = spaces.find((space) => space.id === spaceId);
-
if (isConnecting) {
return
Loading …
;
}
- if (!space) {
- return
Space not found
;
- }
-
return (
diff --git a/apps/events/src/routes/space/$spaceId/playground.tsx b/apps/events/src/routes/space/$spaceId/playground.tsx
index 59900560..fc33e265 100644
--- a/apps/events/src/routes/space/$spaceId/playground.tsx
+++ b/apps/events/src/routes/space/$spaceId/playground.tsx
@@ -1,9 +1,6 @@
import { TodosPublic } from '@/components/todo/todos-public';
-import { store } from '@graphprotocol/hypergraph';
import { HypergraphSpaceProvider, useHypergraphApp } from '@graphprotocol/hypergraph-react';
import { createFileRoute } from '@tanstack/react-router';
-import { useSelector } from '@xstate/store/react';
-import { useEffect } from 'react';
export const Route = createFileRoute('/space/$spaceId/playground')({
component: PlaygroundRouteComponent,
@@ -11,24 +8,12 @@ export const Route = createFileRoute('/space/$spaceId/playground')({
function PlaygroundRouteComponent() {
const { spaceId } = Route.useParams();
- const spaces = useSelector(store, (state) => state.context.spaces);
- const { subscribeToSpace, isConnecting, isLoadingSpaces } = useHypergraphApp();
- useEffect(() => {
- if (!isConnecting) {
- subscribeToSpace({ spaceId });
- }
- }, [isConnecting, subscribeToSpace, spaceId]);
-
- const space = spaces.find((space) => space.id === spaceId);
+ const { isConnecting, isLoadingSpaces } = useHypergraphApp();
if (isConnecting || isLoadingSpaces[spaceId]) {
return Loading …
;
}
- if (!space) {
- return Space not found
;
- }
-
return (
diff --git a/apps/events/src/routes/space/$spaceId/public-integration.tsx b/apps/events/src/routes/space/$spaceId/public-integration.tsx
index d23b55f0..836d6688 100644
--- a/apps/events/src/routes/space/$spaceId/public-integration.tsx
+++ b/apps/events/src/routes/space/$spaceId/public-integration.tsx
@@ -1,10 +1,7 @@
import { CreatePropertiesAndTypesTodos } from '@/components/create-properties-and-types-todos';
import { Todos2 } from '@/components/todos2';
-import { store } from '@graphprotocol/hypergraph';
import { HypergraphSpaceProvider, useHypergraphApp } from '@graphprotocol/hypergraph-react';
import { createFileRoute } from '@tanstack/react-router';
-import { useSelector } from '@xstate/store/react';
-import { useEffect } from 'react';
export const Route = createFileRoute('/space/$spaceId/public-integration')({
component: PublicIntegration,
@@ -12,28 +9,16 @@ export const Route = createFileRoute('/space/$spaceId/public-integration')({
function PublicIntegration() {
const { spaceId } = Route.useParams();
- const spaces = useSelector(store, (state) => state.context.spaces);
- const { subscribeToSpace, isConnecting, isLoadingSpaces } = useHypergraphApp();
- useEffect(() => {
- if (!isConnecting) {
- subscribeToSpace({ spaceId });
- }
- }, [isConnecting, subscribeToSpace, spaceId]);
-
- const space = spaces.find((space) => space.id === spaceId);
+ const { isConnecting, isLoadingSpaces } = useHypergraphApp();
if (isConnecting || isLoadingSpaces[spaceId]) {
return Loading …
;
}
- if (!space) {
- return Space not found
;
- }
-
return (
-
+
diff --git a/apps/events/src/routes/space/$spaceId/users.tsx b/apps/events/src/routes/space/$spaceId/users.tsx
index 6fb5d901..00f20ba2 100644
--- a/apps/events/src/routes/space/$spaceId/users.tsx
+++ b/apps/events/src/routes/space/$spaceId/users.tsx
@@ -1,10 +1,7 @@
import { UsersMerged } from '@/components/users/users-merged';
import { UsersPublic } from '@/components/users/users-public';
-import { store } from '@graphprotocol/hypergraph';
import { HypergraphSpaceProvider, useHypergraphApp } from '@graphprotocol/hypergraph-react';
import { createFileRoute } from '@tanstack/react-router';
-import { useSelector } from '@xstate/store/react';
-import { useEffect } from 'react';
import { UsersLocal } from '../../../components/users/users-local';
export const Route = createFileRoute('/space/$spaceId/users')({
component: UsersRouteComponent,
@@ -12,24 +9,12 @@ export const Route = createFileRoute('/space/$spaceId/users')({
function UsersRouteComponent() {
const { spaceId } = Route.useParams();
- const spaces = useSelector(store, (state) => state.context.spaces);
- const { subscribeToSpace, isConnecting, isLoadingSpaces } = useHypergraphApp();
- useEffect(() => {
- if (!isConnecting) {
- subscribeToSpace({ spaceId });
- }
- }, [isConnecting, subscribeToSpace, spaceId]);
-
- const space = spaces.find((space) => space.id === spaceId);
+ const { isConnecting, isLoadingSpaces } = useHypergraphApp();
if (isConnecting || isLoadingSpaces[spaceId]) {
return Loading …
;
}
- if (!space) {
- return Space not found
;
- }
-
return (
diff --git a/packages/hypergraph-react/src/HypergraphSpaceContext.tsx b/packages/hypergraph-react/src/HypergraphSpaceContext.tsx
index 85677479..6d74b0eb 100644
--- a/packages/hypergraph-react/src/HypergraphSpaceContext.tsx
+++ b/packages/hypergraph-react/src/HypergraphSpaceContext.tsx
@@ -1,21 +1,27 @@
'use client';
-import type { AnyDocumentId, DocHandle, Repo } from '@automerge/automerge-repo';
+import type { AnyDocumentId } from '@automerge/automerge-repo';
import { useRepo } from '@automerge/automerge-repo-react-hooks';
-import { Entity, Utils } from '@graphprotocol/hypergraph';
+import { Entity, Utils, store } from '@graphprotocol/hypergraph';
+import { useSelector } from '@xstate/store/react';
import * as Schema from 'effect/Schema';
-import { type ReactNode, createContext, useContext, useMemo, useRef, useState, useSyncExternalStore } from 'react';
-
-export type HypergraphContext = {
- space: string;
- repo: Repo;
- id: AnyDocumentId;
- handle: DocHandle;
-};
+import {
+ type ReactNode,
+ createContext,
+ useContext,
+ useEffect,
+ useLayoutEffect,
+ useMemo,
+ useRef,
+ useSyncExternalStore,
+} from 'react';
+import { useHypergraphApp } from './HypergraphAppContext.js';
+
+export type HypergraphContext = { space: string };
export const HypergraphReactContext = createContext(undefined);
-function useHypergraphSpaceInternal() {
+export function useHypergraphSpaceInternal() {
const context = useContext(HypergraphReactContext);
if (!context) {
throw new Error('useHypergraphSpace must be used within a HypergraphSpaceProvider');
@@ -25,75 +31,109 @@ function useHypergraphSpaceInternal() {
}
export function HypergraphSpaceProvider({ space, children }: { space: string; children: ReactNode }) {
- const repo = useRepo();
- const ref = useRef(undefined);
+ return {children};
+}
- let current = ref.current;
- if (current === undefined || space !== current.space || repo !== current.repo) {
- const id = Utils.idToAutomergeId(space) as AnyDocumentId;
+function useSubscribeToSpaceAndGetHandle({ spaceId, enabled }: { spaceId: string; enabled: boolean }) {
+ const repo = useRepo();
+ const handle = useMemo(() => {
+ const id = Utils.idToAutomergeId(spaceId) as AnyDocumentId;
const result = repo.findWithProgress(id);
-
- current = ref.current = {
- space,
- repo,
- id,
- handle: result.handle,
+ return result.handle;
+ }, [spaceId, repo]);
+
+ const { subscribeToSpace, isConnecting } = useHypergraphApp();
+ useEffect(() => {
+ if (!isConnecting && enabled) {
+ // TODO: only subscribe to space if it is not already subscribed
+ subscribeToSpace({ spaceId });
+ }
+ return () => {
+ // TODO: unsubscribe from space in case the space ID changes
};
- }
+ }, [isConnecting, subscribeToSpace, spaceId, enabled]);
- return {children};
+ return handle;
}
-export function useCreateEntity(type: S) {
- const hypergraph = useHypergraphSpaceInternal();
- return Entity.create(hypergraph.handle, type);
+export function useSpace(options: { space?: string; mode: 'private' | 'public' }) {
+ const { space: spaceIdFromContext } = useHypergraphSpaceInternal();
+ const { space: spaceIdFromParams } = options ?? {};
+ const spaceId = spaceIdFromParams ?? spaceIdFromContext;
+ const handle = useSubscribeToSpaceAndGetHandle({ spaceId, enabled: options.mode === 'private' });
+ const ready = options.mode === 'public' ? true : handle.isReady();
+ const space = useSelector(store, (state) => state.context.spaces.find((space) => space.id === spaceId));
+ return { ready, name: space?.name, id: spaceId };
}
-export function useUpdateEntity(type: S) {
- const hypergraph = useHypergraphSpaceInternal();
- return Entity.update(hypergraph.handle, type);
+export function useCreateEntity(type: S, options?: { space?: string }) {
+ const { space } = options ?? {};
+ const { space: spaceFromContext } = useHypergraphSpaceInternal();
+ const handle = useSubscribeToSpaceAndGetHandle({ spaceId: space ?? spaceFromContext, enabled: true });
+ return Entity.create(handle, type);
}
-export function useDeleteEntity() {
- const hypergraph = useHypergraphSpaceInternal();
- return Entity.markAsDeleted(hypergraph.handle);
+export function useUpdateEntity(type: S, options?: { space?: string }) {
+ const { space: spaceFromContext } = useHypergraphSpaceInternal();
+ const { space } = options ?? {};
+ const handle = useSubscribeToSpaceAndGetHandle({ spaceId: space ?? spaceFromContext, enabled: true });
+ return Entity.update(handle, type);
}
-export function useRemoveRelation() {
- const hypergraph = useHypergraphSpaceInternal();
- return Entity.removeRelation(hypergraph.handle);
+export function useDeleteEntity(options?: { space?: string }) {
+ const { space: spaceFromContext } = useHypergraphSpaceInternal();
+ const { space } = options ?? {};
+ const handle = useSubscribeToSpaceAndGetHandle({ spaceId: space ?? spaceFromContext, enabled: true });
+ return Entity.markAsDeleted(handle);
}
-export function useHardDeleteEntity() {
- const hypergraph = useHypergraphSpaceInternal();
- return Entity.delete(hypergraph.handle);
+export function useRemoveRelation(options?: { space?: string }) {
+ const { space: spaceFromContext } = useHypergraphSpaceInternal();
+ const { space } = options ?? {};
+ const handle = useSubscribeToSpaceAndGetHandle({ spaceId: space ?? spaceFromContext, enabled: true });
+ return Entity.removeRelation(handle);
+}
+
+export function useHardDeleteEntity(options?: { space?: string }) {
+ const { space: spaceFromContext } = useHypergraphSpaceInternal();
+ const { space } = options ?? {};
+ const handle = useSubscribeToSpaceAndGetHandle({ spaceId: space ?? spaceFromContext, enabled: true });
+ return Entity.delete(handle);
}
type QueryParams = {
+ space?: string | undefined;
enabled: boolean;
filter?: { [K in keyof Schema.Schema.Type]?: Entity.EntityFieldFilter[K]> } | undefined;
include?: { [K in keyof Schema.Schema.Type]?: Record> } | undefined;
};
export function useQueryLocal(type: S, params?: QueryParams) {
- const { enabled = true, filter, include } = params ?? {};
+ const { enabled = true, filter, include, space: spaceFromParams } = params ?? {};
const entitiesRef = useRef[]>([]);
-
- const hypergraph = useHypergraphSpaceInternal();
- const [subscription] = useState(() => {
- if (!enabled) {
- return {
- subscribe: () => () => undefined,
- getEntities: () => entitiesRef.current,
- };
- }
-
- return Entity.subscribeToFindMany(hypergraph.handle, type, filter, include);
+ const subscriptionRef = useRef>({
+ subscribe: () => () => undefined,
+ getEntities: () => entitiesRef.current,
});
+ const { space: spaceFromContext } = useHypergraphSpaceInternal();
+ const handle = useSubscribeToSpaceAndGetHandle({ spaceId: spaceFromParams ?? spaceFromContext, enabled: true });
+ const handleIsReady = handle.isReady();
+
+ // biome-ignore lint/correctness/useExhaustiveDependencies: allow to change filter and include
+ useLayoutEffect(() => {
+ if (enabled && handleIsReady) {
+ const subscription = Entity.subscribeToFindMany(handle, type, filter, include);
+ subscriptionRef.current.subscribe = subscription.subscribe;
+ subscriptionRef.current.getEntities = subscription.getEntities;
+ }
+ }, [enabled, handleIsReady, handle, type]);
// TODO: allow to change the enabled state
-
- const allEntities = useSyncExternalStore(subscription.subscribe, subscription.getEntities, () => entitiesRef.current);
+ const allEntities = useSyncExternalStore(
+ subscriptionRef.current.subscribe,
+ subscriptionRef.current.getEntities,
+ () => entitiesRef.current,
+ );
const { entities, deletedEntities } = useMemo(() => {
const entities: Entity.Entity[] = [];
@@ -114,9 +154,11 @@ export function useQueryLocal(type: S, para
export function useQueryEntity(
type: S,
id: string,
- include?: { [K in keyof Schema.Schema.Type]?: Record },
+ params?: { space?: string; include?: { [K in keyof Schema.Schema.Type]?: Record } },
) {
- const hypergraph = useHypergraphSpaceInternal();
+ const { space: spaceFromContext } = useHypergraphSpaceInternal();
+ const { space: spaceFromParams, include } = params ?? {};
+ const handle = useSubscribeToSpaceAndGetHandle({ spaceId: spaceFromParams ?? spaceFromContext, enabled: true });
const prevEntityRef = useRef | undefined>(undefined);
const equals = Schema.equivalence(type);
@@ -129,22 +171,22 @@ export function useQueryEntity(
callback();
};
- hypergraph.handle.on('change', handleChange);
- hypergraph.handle.on('delete', handleDelete);
+ handle.on('change', handleChange);
+ handle.on('delete', handleDelete);
return () => {
- hypergraph.handle.off('change', handleChange);
- hypergraph.handle.off('delete', handleDelete);
+ handle.off('change', handleChange);
+ handle.off('delete', handleDelete);
};
};
return useSyncExternalStore(subscribe, () => {
- const doc = hypergraph.handle.doc();
+ const doc = handle.doc();
if (doc === undefined) {
return prevEntityRef.current;
}
- const found = Entity.findOne(hypergraph.handle, type, include)(id);
+ const found = Entity.findOne(handle, type, include)(id);
if (found === undefined && prevEntityRef.current !== undefined) {
// entity was maybe deleted, delete from the ref
prevEntityRef.current = undefined;
@@ -158,8 +200,3 @@ export function useQueryEntity(
return prevEntityRef.current;
});
}
-
-export const useHypergraphSpace = () => {
- const { space } = useHypergraphSpaceInternal();
- return space;
-};
diff --git a/packages/hypergraph-react/src/index.ts b/packages/hypergraph-react/src/index.ts
index a4d826ad..c3d19c1a 100644
--- a/packages/hypergraph-react/src/index.ts
+++ b/packages/hypergraph-react/src/index.ts
@@ -17,9 +17,9 @@ export {
useCreateEntity,
useDeleteEntity,
useHardDeleteEntity,
- useHypergraphSpace,
useQueryEntity,
useRemoveRelation,
+ useSpace,
useUpdateEntity,
} from './HypergraphSpaceContext.js';
export { generateDeleteOps as _generateDeleteOps } from './internal/generate-delete-ops.js';
diff --git a/packages/hypergraph-react/src/internal/use-query-public.tsx b/packages/hypergraph-react/src/internal/use-query-public.tsx
index a54b9bc1..ab0dc48b 100644
--- a/packages/hypergraph-react/src/internal/use-query-public.tsx
+++ b/packages/hypergraph-react/src/internal/use-query-public.tsx
@@ -5,7 +5,7 @@ import * as Either from 'effect/Either';
import * as Schema from 'effect/Schema';
import { gql, request } from 'graphql-request';
import { useMemo } from 'react';
-import { useHypergraphSpace } from '../HypergraphSpaceContext.js';
+import { useHypergraphSpaceInternal } from '../HypergraphSpaceContext.js';
import { GEO_API_TESTNET_ENDPOINT } from './constants.js';
import type { QueryPublicParams } from './types.js';
@@ -322,7 +322,7 @@ export const parseResult = (
export const useQueryPublic = (type: S, params?: QueryPublicParams) => {
const { enabled = true, include } = params ?? {};
- const space = useHypergraphSpace();
+ const { space } = useHypergraphSpaceInternal();
const mapping = useSelector(store, (state) => state.context.mapping);
// @ts-expect-error TODO should use the actual type instead of the name in the mapping
diff --git a/packages/hypergraph-react/src/use-query.tsx b/packages/hypergraph-react/src/use-query.tsx
index 6e9e9f5b..f6f87302 100644
--- a/packages/hypergraph-react/src/use-query.tsx
+++ b/packages/hypergraph-react/src/use-query.tsx
@@ -9,6 +9,7 @@ type QueryParams = {
filter?: { [K in keyof Schema.Schema.Type]?: Entity.EntityFieldFilter[K]> } | undefined;
// TODO: for multi-level nesting it should only allow the allowed properties instead of Record>
include?: { [K in keyof Schema.Schema.Type]?: Record> } | undefined;
+ space?: string;
};
// @ts-expect-error TODO: remove this function
@@ -143,9 +144,9 @@ const getDiff = (
const preparePublishDummy = () => undefined;
export function useQuery(type: S, params: QueryParams) {
- const { mode, filter, include } = params;
+ const { mode, filter, include, space } = params;
const publicResult = useQueryPublic(type, { enabled: mode === 'public', include });
- const localResult = useQueryLocal(type, { enabled: mode === 'private', filter, include });
+ const localResult = useQueryLocal(type, { enabled: mode === 'private', filter, include, space });
// const mapping = useSelector(store, (state) => state.context.mapping);
// const generateCreateOps = useGenerateCreateOps(type, mode === 'merged');
// const generateUpdateOps = useGenerateUpdateOps(type, mode === 'merged');
diff --git a/packages/hypergraph-react/test/HypergraphSpaceContext.test.tsx b/packages/hypergraph-react/test/HypergraphSpaceContext.test.tsx
index 63dcec4c..5e339c70 100644
--- a/packages/hypergraph-react/test/HypergraphSpaceContext.test.tsx
+++ b/packages/hypergraph-react/test/HypergraphSpaceContext.test.tsx
@@ -60,6 +60,7 @@ describe('HypergraphSpaceContext', () => {
describe('useCreateEntity', () => {
it('should be able to create an entity through the useCreateEntity Hook', async () => {
const { result: createEntityResult } = renderHook(() => useCreateEntity(Event), { wrapper });
+ const { result: queryEntitiesResult, rerender } = renderHook(() => useQueryLocal(Event), { wrapper });
let createdEntity: Entity.Entity | null = null;
@@ -78,7 +79,8 @@ describe('HypergraphSpaceContext', () => {
expect(queryEntityResult.current).toEqual(createdEntity);
}
- const { result: queryEntitiesResult } = renderHook(() => useQueryLocal(Event), { wrapper });
+ rerender();
+
expect(queryEntitiesResult.current).toEqual({ deletedEntities: [], entities: [createdEntity] });
});
});
@@ -117,11 +119,16 @@ describe('HypergraphSpaceContext', () => {
expect(createdEntity).toEqual({ id, name: 'Test User', age: 2112, type: Person.name });
const { result: queryEntityResult } = renderHook(() => useQueryEntity(Person, id), { wrapper });
+ // @ts-expect-error - TODO: fix the types error
expect(queryEntityResult.current).toEqual({ ...createdEntity, __version: '', __deleted: false });
- const { result: queryEntitiesResult } = renderHook(() => useQueryLocal(Person), { wrapper });
+ const { result: queryEntitiesResult, rerender } = renderHook(() => useQueryLocal(Person), { wrapper });
+
+ rerender();
+
expect(queryEntitiesResult.current).toEqual({
deletedEntities: [],
+ // @ts-expect-error - TODO: fix the types error
entities: [{ ...createdEntity, __version: '', __deleted: false }],
});
});
@@ -147,6 +154,7 @@ describe('HypergraphSpaceContext', () => {
const { result: queryEntitiesResult, rerender: rerenderQueryEntities } = renderHook(() => useQueryLocal(User), {
wrapper,
});
+ rerenderQueryEntities();
expect(queryEntitiesResult.current).toEqual({ deletedEntities: [], entities: [createdEntity] });
const { result: deleteEntityResult } = renderHook(() => useDeleteEntity(), { wrapper });
diff --git a/packages/hypergraph/src/entity/findMany.ts b/packages/hypergraph/src/entity/findMany.ts
index babe2dca..912294b5 100644
--- a/packages/hypergraph/src/entity/findMany.ts
+++ b/packages/hypergraph/src/entity/findMany.ts
@@ -374,15 +374,17 @@ export function findMany(
const stableEmptyArray: Array = [];
+export type FindManySubscription = {
+ subscribe: (callback: () => void) => () => void;
+ getEntities: () => Readonly>>;
+};
+
export function subscribeToFindMany(
handle: DocHandle,
type: S,
filter: { [K in keyof Schema.Schema.Type]?: EntityFieldFilter[K]> } | undefined,
include: { [K in keyof Schema.Schema.Type]?: Record> } | undefined,
-): {
- subscribe: (callback: () => void) => () => void;
- getEntities: () => Readonly>>;
-} {
+): FindManySubscription {
const queryKey = filter ? canonicalize(filter) : 'all';
const decode = Schema.decodeUnknownSync(type);
// TODO: what's the right way to get the name of the type?