Skip to content

Commit aab8eed

Browse files
authored
add createEntityPublic (#240)
1 parent 35aaab2 commit aab8eed

File tree

3 files changed

+131
-1
lines changed

3 files changed

+131
-1
lines changed

apps/events/src/components/playground.tsx

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { getSmartAccountWalletClient } from '@/lib/smart-account';
2-
import { _useDeleteEntityPublic, useQuery } from '@graphprotocol/hypergraph-react';
2+
import { _useCreateEntityPublic, _useDeleteEntityPublic, useQuery } from '@graphprotocol/hypergraph-react';
33
import { useState } from 'react';
44
import { Event } from '../schema';
55
import { Button } from './ui/button';
@@ -14,17 +14,46 @@ export const Playground = () => {
1414
},
1515
});
1616
const [isDeleting, setIsDeleting] = useState(false);
17+
const [isCreating, setIsCreating] = useState(false);
1718

1819
const deleteEntity = _useDeleteEntityPublic(Event, {
1920
space: '1c954768-7e14-4f0f-9396-0fe9dcd55fe8',
2021
});
2122

23+
const createEntity = _useCreateEntityPublic(Event, {
24+
space: '1c954768-7e14-4f0f-9396-0fe9dcd55fe8',
25+
});
26+
2227
console.log({ isLoading, isError, data });
2328

2429
return (
2530
<div>
2631
{isLoading && <div>Loading...</div>}
2732
{isError && <div>Error</div>}
33+
<Button
34+
disabled={isCreating}
35+
onClick={async () => {
36+
setIsCreating(true);
37+
const walletClient = await getSmartAccountWalletClient();
38+
if (!walletClient) {
39+
alert('Wallet client not found');
40+
setIsCreating(false);
41+
return;
42+
}
43+
const { success, cid, txResult } = await createEntity(
44+
{
45+
name: 'Test Event 42 by Nik',
46+
sponsors: ['347676a1-7cef-47dc-b6a7-c94fc6237dcd'],
47+
},
48+
// @ts-expect-error - TODO: fix the types error
49+
{ walletClient },
50+
);
51+
console.log('created', { success, cid, txResult });
52+
setIsCreating(false);
53+
}}
54+
>
55+
Create
56+
</Button>
2857
{data?.map((event) => (
2958
<div key={event.id}>
3059
<h2>{event.name}</h2>

packages/hypergraph-react/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ export {
2323
useUpdateEntity,
2424
} from './HypergraphSpaceContext.js';
2525
export { generateDeleteOps as _generateDeleteOps } from './internal/generate-delete-ops.js';
26+
export { useCreateEntityPublic as _useCreateEntityPublic } from './internal/use-create-entity-public.js';
2627
export { useDeleteEntityPublic as _useDeleteEntityPublic } from './internal/use-delete-entity-public.js';
2728
export { useGenerateCreateOps as _useGenerateCreateOps } from './internal/use-generate-create-ops.js';
2829
export { useQueryPublic as _useQueryPublic } from './internal/use-query-public.js';
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
import { type GeoSmartAccount, Graph, Id, type PropertiesParam, type RelationsParam } from '@graphprotocol/grc-20';
2+
import type { Entity } from '@graphprotocol/hypergraph';
3+
import { Type, store } from '@graphprotocol/hypergraph';
4+
import { useQueryClient } from '@tanstack/react-query';
5+
import { useSelector } from '@xstate/store/react';
6+
import type * as Schema from 'effect/Schema';
7+
import { publishOps } from '../publish-ops.js';
8+
9+
type CreateEntityPublicParams = {
10+
space: string;
11+
};
12+
13+
export function useCreateEntityPublic<const S extends Entity.AnyNoContext>(
14+
type: S,
15+
{ space }: CreateEntityPublicParams,
16+
) {
17+
const mapping = useSelector(store, (state) => state.context.mapping);
18+
const queryClient = useQueryClient();
19+
20+
return async (
21+
data: Readonly<Schema.Schema.Type<Entity.Insert<S>>>,
22+
{ walletClient }: { walletClient: GeoSmartAccount },
23+
// TODO: return the entity with this type: Promise<Entity.Entity<S>>
24+
) => {
25+
try {
26+
// @ts-expect-error TODO should use the actual type instead of the name in the mapping
27+
const typeName = type.name;
28+
const mappingEntry = mapping?.[typeName];
29+
if (!mappingEntry) {
30+
throw new Error(`Mapping entry for ${typeName} not found`);
31+
}
32+
33+
const fields = type.fields;
34+
const values: PropertiesParam = [];
35+
for (const [key, value] of Object.entries(mappingEntry.properties || {})) {
36+
let serializedValue: string = data[key];
37+
if (fields[key] === Type.Checkbox) {
38+
serializedValue = Graph.serializeCheckbox(data[key]);
39+
} else if (fields[key] === Type.Date) {
40+
serializedValue = Graph.serializeDate(data[key]);
41+
} else if (fields[key] === Type.Point) {
42+
serializedValue = Graph.serializePoint(data[key]);
43+
} else if (fields[key] === Type.Number) {
44+
serializedValue = Graph.serializeNumber(data[key]);
45+
}
46+
47+
values.push({
48+
property: Id.Id(value),
49+
value: serializedValue,
50+
});
51+
}
52+
53+
const relations: RelationsParam = {};
54+
for (const [key, relationId] of Object.entries(mappingEntry.relations || {})) {
55+
const toIds: { toEntity: Id.Id }[] = [];
56+
57+
if (data[key]) {
58+
// @ts-expect-error - TODO: fix the types error
59+
for (const entity of data[key]) {
60+
if (typeof entity === 'string') {
61+
toIds.push({ toEntity: Id.Id(entity) });
62+
} else {
63+
toIds.push({ toEntity: Id.Id(entity.id) });
64+
}
65+
}
66+
relations[Id.Id(relationId)] = toIds;
67+
}
68+
}
69+
70+
const { ops } = Graph.createEntity({
71+
types: mappingEntry.typeIds,
72+
id: data.id,
73+
values,
74+
relations,
75+
});
76+
77+
const { cid, txResult } = await publishOps({
78+
ops,
79+
space,
80+
name: `Create entity ${data.id}`,
81+
walletClient,
82+
network: 'TESTNET',
83+
});
84+
// TODO: temporary fix until we get the information from the API when a transaction is confirmed
85+
await new Promise((resolve) => setTimeout(resolve, 2000));
86+
queryClient.invalidateQueries({
87+
queryKey: [
88+
'hypergraph-public-entities',
89+
// @ts-expect-error - TODO: find a better way to access the type.name
90+
type.name,
91+
space,
92+
],
93+
});
94+
return { success: true, cid, txResult };
95+
} catch (error) {
96+
console.error(error);
97+
return { success: false, error: 'Failed to create entity' };
98+
}
99+
};
100+
}

0 commit comments

Comments
 (0)