Skip to content

Commit 8fe6d9a

Browse files
authored
Ng/nested relations support (#238)
1 parent 03f1d51 commit 8fe6d9a

25 files changed

+597
-145
lines changed

apps/events/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"preview": "vite preview"
99
},
1010
"dependencies": {
11-
"@graphprotocol/grc-20": "^0.20.0",
11+
"@graphprotocol/grc-20": "^0.21.2",
1212
"@graphprotocol/hypergraph": "workspace:*",
1313
"@graphprotocol/hypergraph-react": "workspace:*",
1414
"@noble/hashes": "^1.8.0",
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
import { getSmartAccountWalletClient } from '@/lib/smart-account';
2+
import { type GeoSmartAccount, Graph, type Op } from '@graphprotocol/grc-20';
3+
import { publishOps, useHypergraphSpace } from '@graphprotocol/hypergraph-react';
4+
import { Button } from './ui/button';
5+
6+
const createEvents = async ({
7+
smartAccountWalletClient,
8+
space,
9+
}: { smartAccountWalletClient: GeoSmartAccount; space: string }) => {
10+
try {
11+
const ops: Array<Op> = [];
12+
13+
const { id: jobOfferTypeId, ops: createJobOfferTypeOps } = Graph.createEntity({
14+
name: 'My Test Job Offer',
15+
types: ['a107c081-3089-4a94-8208-6a10775557d2'],
16+
values: [
17+
{
18+
property: '20d18713-5352-4e1f-987c-d853bf9f8831',
19+
value: '80000',
20+
},
21+
],
22+
});
23+
ops.push(...createJobOfferTypeOps);
24+
25+
const { id: jobOfferTypeId2, ops: createJobOfferTypeOps2 } = Graph.createEntity({
26+
name: 'My Test Job Offer 2',
27+
types: ['a107c081-3089-4a94-8208-6a10775557d2'],
28+
values: [
29+
{
30+
property: '20d18713-5352-4e1f-987c-d853bf9f8831',
31+
value: '90000',
32+
},
33+
],
34+
});
35+
ops.push(...createJobOfferTypeOps2);
36+
37+
console.log('jobOfferTypeId', jobOfferTypeId);
38+
console.log('jobOfferTypeId2', jobOfferTypeId2);
39+
40+
const { id: companyTypeId, ops: createCompanyTypeOps } = Graph.createEntity({
41+
name: 'My Test Company',
42+
types: ['e8932986-67a9-4fff-89a6-07f03973014c'],
43+
relations: {
44+
'96beadca-0846-4e56-9628-c196f7f3c4cd': [{ toEntity: jobOfferTypeId }, { toEntity: jobOfferTypeId2 }],
45+
},
46+
});
47+
ops.push(...createCompanyTypeOps);
48+
49+
const { id: eventTypeId, ops: createEventTypeOps } = Graph.createEntity({
50+
name: 'My Test Event',
51+
types: ['6b8dbe76-389f-4bde-acdd-db9d5e387882'],
52+
relations: {
53+
'd8e4ea54-cb8c-4dca-9c2b-64dbbbe78397': [{ toEntity: companyTypeId }],
54+
},
55+
});
56+
ops.push(...createEventTypeOps);
57+
58+
const result = await publishOps({
59+
ops,
60+
walletClient: smartAccountWalletClient,
61+
space,
62+
name: 'Create Job Offers, Companies and Events',
63+
network: 'TESTNET',
64+
});
65+
console.log('result', result);
66+
alert('Events created');
67+
} catch (error) {
68+
console.error('error', error);
69+
}
70+
};
71+
72+
export const CreateEvents = () => {
73+
const space = useHypergraphSpace();
74+
75+
return (
76+
<div>
77+
<Button
78+
onClick={async () => {
79+
const smartAccountWalletClient = await getSmartAccountWalletClient();
80+
if (!smartAccountWalletClient) {
81+
throw new Error('Missing smartAccountWalletClient');
82+
}
83+
await createEvents({
84+
// @ts-expect-error TODO: in the future we probably only only use one smart account wallet client
85+
smartAccountWalletClient,
86+
space,
87+
});
88+
}}
89+
>
90+
Create Job Offers, Companies and Events
91+
</Button>
92+
</div>
93+
);
94+
};
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
import { getSmartAccountWalletClient } from '@/lib/smart-account';
2+
import { type GeoSmartAccount, Graph, type Op } from '@graphprotocol/grc-20';
3+
import { publishOps, useHypergraphSpace } from '@graphprotocol/hypergraph-react';
4+
import { useState } from 'react';
5+
import { Button } from './ui/button';
6+
import { Card, CardContent } from './ui/card';
7+
8+
const createPropertiesAndTypesEvent = async ({
9+
smartAccountWalletClient,
10+
space,
11+
}: { smartAccountWalletClient: GeoSmartAccount; space: string }) => {
12+
const ops: Array<Op> = [];
13+
const { id: salaryPropertyId, ops: createSalaryPropertyOps } = Graph.createProperty({
14+
dataType: 'NUMBER',
15+
name: 'Salary',
16+
});
17+
ops.push(...createSalaryPropertyOps);
18+
19+
const { id: jobOfferTypeId, ops: createJobOfferTypeOps } = Graph.createType({
20+
name: 'Job Offer',
21+
properties: [salaryPropertyId],
22+
});
23+
ops.push(...createJobOfferTypeOps);
24+
25+
const { id: jobOffersRelationTypeId, ops: createJobOffersRelationTypeOps } = Graph.createProperty({
26+
dataType: 'RELATION',
27+
name: 'Job Offer',
28+
relationValueTypes: [jobOfferTypeId],
29+
});
30+
ops.push(...createJobOffersRelationTypeOps);
31+
32+
const { id: companyTypeId, ops: createCompanyTypeOps } = Graph.createType({
33+
name: 'Company',
34+
properties: [salaryPropertyId, jobOffersRelationTypeId],
35+
});
36+
ops.push(...createCompanyTypeOps);
37+
38+
const { id: sponsorsRelationTypeId, ops: createSponsorsRelationTypeOps } = Graph.createProperty({
39+
dataType: 'RELATION',
40+
name: 'Sponsor',
41+
relationValueTypes: [companyTypeId],
42+
});
43+
ops.push(...createSponsorsRelationTypeOps);
44+
45+
const { id: eventTypeId, ops: createEventTypeOps } = Graph.createType({
46+
name: 'Event',
47+
properties: [sponsorsRelationTypeId],
48+
});
49+
ops.push(...createEventTypeOps);
50+
51+
const result = await publishOps({
52+
ops,
53+
walletClient: smartAccountWalletClient,
54+
space,
55+
name: 'Create properties and types',
56+
network: 'TESTNET',
57+
});
58+
return {
59+
result,
60+
eventTypeId,
61+
companyTypeId,
62+
jobOfferTypeId,
63+
salaryPropertyId,
64+
jobOffersRelationTypeId,
65+
sponsorsRelationTypeId,
66+
};
67+
};
68+
69+
export const CreatePropertiesAndTypesEvent = () => {
70+
const [mapping, setMapping] = useState<string>('');
71+
const space = useHypergraphSpace();
72+
73+
return (
74+
<div>
75+
{mapping && (
76+
<Card>
77+
<CardContent>
78+
<pre>{mapping}</pre>
79+
</CardContent>
80+
</Card>
81+
)}
82+
<Button
83+
onClick={async () => {
84+
const smartAccountWalletClient = await getSmartAccountWalletClient();
85+
if (!smartAccountWalletClient) {
86+
throw new Error('Missing smartAccountWalletClient');
87+
}
88+
const {
89+
eventTypeId,
90+
companyTypeId,
91+
jobOfferTypeId,
92+
salaryPropertyId,
93+
jobOffersRelationTypeId,
94+
sponsorsRelationTypeId,
95+
} = await createPropertiesAndTypesEvent({
96+
// @ts-expect-error TODO: in the future we probably only only use one smart account wallet client
97+
smartAccountWalletClient,
98+
space,
99+
});
100+
101+
const newMapping = `Event: {
102+
typeIds: [Id.Id('${eventTypeId}')],
103+
properties: {
104+
name: Id.Id('a126ca53-0c8e-48d5-b888-82c734c38935'),
105+
},
106+
relations: {
107+
sponsors: Id.Id('${sponsorsRelationTypeId}'),
108+
},
109+
},
110+
Company: {
111+
typeIds: [Id.Id('${companyTypeId}')],
112+
properties: {
113+
name: Id.Id('a126ca53-0c8e-48d5-b888-82c734c38935'),
114+
jobOffers: Id.Id('${jobOffersRelationTypeId}'),
115+
},
116+
},
117+
JobOffer: {
118+
typeIds: [Id.Id('${jobOfferTypeId}')],
119+
properties: {
120+
name: Id.Id('a126ca53-0c8e-48d5-b888-82c734c38935'),
121+
salary: Id.Id('${salaryPropertyId}'),
122+
},
123+
},
124+
`;
125+
setMapping(newMapping);
126+
}}
127+
>
128+
Create properties and types for Event, Company and JobOffer
129+
</Button>
130+
</div>
131+
);
132+
};

apps/events/src/components/create-properties-and-types.tsx renamed to apps/events/src/components/create-properties-and-types-todos.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { useState } from 'react';
55
import { Button } from './ui/button';
66
import { Card, CardContent } from './ui/card';
77

8-
const createPropertiesAndTypes = async ({
8+
const createPropertiesAndTypesTodos = async ({
99
smartAccountWalletClient,
1010
space,
1111
}: { smartAccountWalletClient: GeoSmartAccount; space: string }) => {
@@ -84,7 +84,7 @@ const createPropertiesAndTypes = async ({
8484
};
8585
};
8686

87-
export const CreatePropertiesAndTypes = () => {
87+
export const CreatePropertiesAndTypesTodos = () => {
8888
const [mapping, setMapping] = useState<string>('');
8989
const space = useHypergraphSpace();
9090

@@ -112,15 +112,15 @@ export const CreatePropertiesAndTypes = () => {
112112
pointPropertyId,
113113
websitePropertyId,
114114
amountPropertyId,
115-
} = await createPropertiesAndTypes({
115+
} = await createPropertiesAndTypesTodos({
116116
smartAccountWalletClient,
117117
space,
118118
});
119119

120120
const newMapping = `Todo2: {
121121
typeIds: [Id.Id('${todoTypeId}')],
122122
properties: {
123-
name: Id.Id('LuBWqZAu6pz54eiJS5mLv8'),
123+
name: Id.Id('a126ca53-0c8e-48d5-b888-82c734c38935'),
124124
checked: Id.Id('${checkedPropertyId}'),
125125
due: Id.Id('${duePropertyId}'),
126126
point: Id.Id('${pointPropertyId}'),
@@ -134,7 +134,7 @@ export const CreatePropertiesAndTypes = () => {
134134
User: {
135135
typeIds: [Id.Id('${userId}')],
136136
properties: {
137-
name: Id.Id('LuBWqZAu6pz54eiJS5mLv8'),
137+
name: Id.Id('a126ca53-0c8e-48d5-b888-82c734c38935'),
138138
},
139139
}
140140
`;

apps/events/src/components/playground.tsx

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,18 @@ import { useQuery } from '@graphprotocol/hypergraph-react';
22
import { Event } from '../schema';
33

44
export const Playground = () => {
5-
const { data: entityData, isLoading, isError } = useQuery(Event, { mode: 'public' });
5+
const {
6+
data: entityData,
7+
isLoading,
8+
isError,
9+
} = useQuery(Event, {
10+
mode: 'public',
11+
include: {
12+
sponsors: {
13+
jobOffers: {},
14+
},
15+
},
16+
});
617

718
console.log({ isLoading, isError, entityData });
819

apps/events/src/lib/smart-account.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
1-
import { getSmartAccountWalletClient as grc20getSmartAccountWalletClient } from '@graphprotocol/grc-20';
1+
import { getWalletClient } from '@graphprotocol/grc-20';
22
import type { Hex } from 'viem';
33

4-
const privateKey = `0x${import.meta.env.VITE_ACCOUNT_KEY}` as Hex;
4+
const privateKey = import.meta.env.VITE_ACCOUNT_KEY as Hex;
55

66
export const getSmartAccountWalletClient = async () => {
77
try {
8-
return await grc20getSmartAccountWalletClient({
8+
// return await grc20getSmartAccountWalletClient({
9+
// privateKey,
10+
// });
11+
console.log('privateKey', privateKey);
12+
return await getWalletClient({
913
privateKey,
1014
});
1115
} catch (err) {

apps/events/src/mapping.ts

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,35 @@ import { Id } from '@graphprotocol/grc-20';
22
import type { Mapping } from '@graphprotocol/hypergraph';
33

44
export const mapping: Mapping = {
5-
RelationEntry: {
6-
typeIds: [Id.Id('8f151ba4-de20-4e3c-9cb4-99ddf96f48f1')],
5+
Event: {
6+
typeIds: [Id.Id('6b8dbe76-389f-4bde-acdd-db9d5e387882')],
77
properties: {
88
name: Id.Id('a126ca53-0c8e-48d5-b888-82c734c38935'),
99
},
10+
relations: {
11+
sponsors: Id.Id('d8e4ea54-cb8c-4dca-9c2b-64dbbbe78397'),
12+
},
1013
},
11-
Event: {
12-
typeIds: [Id.Id('4d876b81-787e-41fc-ab5d-075d4da66a3f')],
14+
Company: {
15+
typeIds: [Id.Id('e8932986-67a9-4fff-89a6-07f03973014c')],
16+
properties: {
17+
name: Id.Id('a126ca53-0c8e-48d5-b888-82c734c38935'),
18+
},
19+
relations: {
20+
jobOffers: Id.Id('96beadca-0846-4e56-9628-c196f7f3c4cd'),
21+
},
22+
},
23+
JobOffer: {
24+
typeIds: [Id.Id('a107c081-3089-4a94-8208-6a10775557d2')],
1325
properties: {
1426
name: Id.Id('a126ca53-0c8e-48d5-b888-82c734c38935'),
15-
// description: Id.Id('9b1f76ff-9711-404c-861e-59dc3fa7d037'),
27+
salary: Id.Id('20d18713-5352-4e1f-987c-d853bf9f8831'),
1628
},
17-
// relations: {
18-
// any: Id.Id('8f151ba4-de20-4e3c-9cb4-99ddf96f48f1'),
19-
// },
2029
},
2130
// Todo2: {
2231
// typeIds: [Id.Id('LJuM8ju67mCv78FhAiK9k9')],
2332
// properties: {
24-
// name: Id.Id('LuBWqZAu6pz54eiJS5mLv8'),
33+
// name: Id.Id('a126ca53-0c8e-48d5-b888-82c734c38935'),
2534
// checked: Id.Id('Ud9kn9gAUsCr1pxvxcgDj8'),
2635
// due: Id.Id('CFisPgjjWVdnaMtSWJDBqA'),
2736
// point: Id.Id('BkcVo7JZHF5LsWw7XZJwwe'),
@@ -35,7 +44,7 @@ export const mapping: Mapping = {
3544
// User: {
3645
// typeIds: [Id.Id('Fk5qzwdpKsD35gm5ts4SZA')],
3746
// properties: {
38-
// name: Id.Id('LuBWqZAu6pz54eiJS5mLv8'),
47+
// name: Id.Id('a126ca53-0c8e-48d5-b888-82c734c38935'),
3948
// },
4049
// },
4150
};

apps/events/src/routes/index.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Button } from '@/components/ui/button';
2-
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
2+
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
33
import { Input } from '@/components/ui/input';
44
import { store } from '@graphprotocol/hypergraph';
55
import { useHypergraphApp, useSpaces } from '@graphprotocol/hypergraph-react';
@@ -117,6 +117,7 @@ function Index() {
117117
<Card>
118118
<CardHeader>
119119
<CardTitle>{space.name}</CardTitle>
120+
<CardDescription className="text-xs">{space.id}</CardDescription>
120121
</CardHeader>
121122
</Card>
122123
</li>

0 commit comments

Comments
 (0)