Skip to content

Commit 852c957

Browse files
committed
implement useEntity public
1 parent 8f958df commit 852c957

File tree

6 files changed

+105
-86
lines changed

6 files changed

+105
-86
lines changed

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { CreateEvents } from '@/components/create-events';
22
import { CreatePropertiesAndTypesEvent } from '@/components/create-properties-and-types-event';
3+
import { Event } from '@/components/event';
34
import { Playground } from '@/components/playground';
45
import { HypergraphSpaceProvider } from '@graphprotocol/hypergraph-react';
56
import { createLazyFileRoute } from '@tanstack/react-router';
@@ -12,7 +13,7 @@ function RouteComponent() {
1213
const space = '282aee96-48b0-4c6e-b020-736430a82a87';
1314
return (
1415
<>
15-
{/* <Event spaceId={space} entityId="cf7c620b-d724-498f-b134-8280dc8249ae" /> */}
16+
<Event spaceId={space} entityId="22aa0386-3365-4425-a60e-eaaec919c034" />
1617
<Playground spaceId={space} />
1718
{/* <Projects spaceId="3f32353d-3b27-4a13-b71a-746f06e1f7db" /> */}
1819
<HypergraphSpaceProvider space={space}>
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { Constants, Utils } from '@graphprotocol/hypergraph';
2+
import * as Option from 'effect/Option';
3+
import type * as Schema from 'effect/Schema';
4+
import * as SchemaAST from 'effect/SchemaAST';
5+
6+
export const getRelationTypeIds = (
7+
type: Schema.Schema.AnyNoContext,
8+
include:
9+
| { [K in keyof Schema.Schema.Type<Schema.Schema.AnyNoContext>]?: Record<string, Record<string, never>> }
10+
| undefined,
11+
) => {
12+
const relationTypeIdsLevel1: string[] = [];
13+
const relationTypeIdsLevel2: string[] = [];
14+
15+
const ast = type.ast as SchemaAST.TypeLiteral;
16+
17+
for (const prop of ast.propertySignatures) {
18+
if (!Utils.isRelation(prop.type)) continue;
19+
20+
const result = SchemaAST.getAnnotation<string>(Constants.PropertyIdSymbol)(prop.type);
21+
if (Option.isSome(result) && include?.[prop.name]) {
22+
relationTypeIdsLevel1.push(result.value);
23+
const relationTransformation = prop.type.rest?.[0]?.type;
24+
const typeIds2: string[] = SchemaAST.getAnnotation<string[]>(Constants.TypeIdsSymbol)(
25+
relationTransformation,
26+
).pipe(Option.getOrElse(() => []));
27+
if (typeIds2.length === 0) {
28+
continue;
29+
}
30+
for (const nestedProp of relationTransformation.propertySignatures) {
31+
if (!Utils.isRelation(nestedProp.type)) continue;
32+
33+
const nestedResult = SchemaAST.getAnnotation<string>(Constants.PropertyIdSymbol)(nestedProp.type);
34+
if (Option.isSome(nestedResult) && include?.[prop.name][nestedProp.name]) {
35+
relationTypeIdsLevel2.push(nestedResult.value);
36+
}
37+
}
38+
}
39+
}
40+
41+
return {
42+
level1: relationTypeIdsLevel1,
43+
level2: relationTypeIdsLevel2,
44+
};
45+
};

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

Lines changed: 45 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
import { Graph } from '@graphprotocol/grc-20';
2-
import { type Entity, type Mapping, store } from '@graphprotocol/hypergraph';
2+
import { Constants, type Entity } from '@graphprotocol/hypergraph';
33
import { useQuery as useQueryTanstack } from '@tanstack/react-query';
4-
import { useSelector } from '@xstate/store/react';
54
import * as Either from 'effect/Either';
5+
import * as Option from 'effect/Option';
66
import * as Schema from 'effect/Schema';
7+
import * as SchemaAST from 'effect/SchemaAST';
78
import { gql, request } from 'graphql-request';
89
import { useMemo } from 'react';
910
import { convertPropertyValue } from './convert-property-value.js';
1011
import { convertRelations } from './convert-relations.js';
12+
import { getRelationTypeIds } from './get-relation-type-ids.js';
1113
import { useHypergraphSpaceInternal } from './use-hypergraph-space-internal.js';
1214

1315
const entityQueryDocumentLevel0 = gql`
@@ -47,6 +49,7 @@ query entity($id: UUID!, $spaceId: UUID!, $relationTypeIdsLevel1: [UUID!]!) {
4749
relationsList(
4850
filter: {spaceId: {is: $spaceId}, typeId:{ in: $relationTypeIdsLevel1}},
4951
) {
52+
id
5053
toEntity {
5154
id
5255
name
@@ -83,6 +86,7 @@ query entity($id: UUID!, $spaceId: UUID!, $relationTypeIdsLevel1: [UUID!]!, $rel
8386
relationsList(
8487
filter: {spaceId: {is: $spaceId}, typeId:{ in: $relationTypeIdsLevel1}},
8588
) {
89+
id
8690
toEntity {
8791
id
8892
name
@@ -97,6 +101,7 @@ query entity($id: UUID!, $spaceId: UUID!, $relationTypeIdsLevel1: [UUID!]!, $rel
97101
relationsList(
98102
filter: {spaceId: {is: $spaceId}, typeId:{ in: $relationTypeIdsLevel2}},
99103
) {
104+
id
100105
toEntity {
101106
id
102107
name
@@ -131,6 +136,7 @@ type EntityQueryResult = {
131136
point: string;
132137
}[];
133138
relationsList?: {
139+
id: string;
134140
toEntity: {
135141
id: string;
136142
name: string;
@@ -143,6 +149,7 @@ type EntityQueryResult = {
143149
point: string;
144150
}[];
145151
relationsList?: {
152+
id: string;
146153
toEntity: {
147154
id: string;
148155
name: string;
@@ -163,41 +170,51 @@ type EntityQueryResult = {
163170
} | null;
164171
};
165172

166-
export const parseResult = <S extends Schema.Schema.AnyNoContext>(
167-
queryData: EntityQueryResult,
168-
type: S,
169-
mappingEntry: Mapping.MappingEntry,
170-
mapping: Mapping.Mapping,
171-
) => {
173+
export const parseResult = <S extends Schema.Schema.AnyNoContext>(queryData: EntityQueryResult, type: S) => {
172174
if (!queryData.entity) {
173175
return { data: null, invalidEntity: null };
174176
}
175177

176-
const decode = Schema.decodeUnknownEither(type);
178+
const schemaWithId = Schema.extend(Schema.Struct({ id: Schema.String }))(type);
179+
const decode = Schema.decodeUnknownEither(schemaWithId);
177180
const queryEntity = queryData.entity;
178181
let rawEntity: Record<string, string | boolean | number | unknown[] | Date> = {
179182
id: queryEntity.id,
180183
};
181184

182-
// take the mappingEntry and assign the attributes to the rawEntity
183-
for (const [key, value] of Object.entries(mappingEntry?.properties ?? {})) {
184-
const property = queryEntity.valuesList.find((a) => a.propertyId === value);
185-
if (property) {
186-
rawEntity[key] = convertPropertyValue(property, type);
185+
const ast = type.ast as SchemaAST.TypeLiteral;
186+
187+
for (const prop of ast.propertySignatures) {
188+
const propType = prop.isOptional ? prop.type.types[0] : prop.type;
189+
const result = SchemaAST.getAnnotation<string>(Constants.PropertyIdSymbol)(propType);
190+
191+
if (Option.isSome(result)) {
192+
const value = queryEntity.valuesList.find((a) => a.propertyId === result.value);
193+
if (value) {
194+
const rawValue = convertPropertyValue(value, propType);
195+
if (rawValue) {
196+
rawEntity[String(prop.name)] = rawValue;
197+
}
198+
}
187199
}
188200
}
189201

190202
rawEntity = {
191203
...rawEntity,
192-
...convertRelations(queryEntity, type, mappingEntry, mapping),
204+
...convertRelations(queryEntity, ast),
193205
};
194206

207+
console.log('rawEntity', rawEntity);
208+
195209
const decodeResult = decode({
196210
...rawEntity,
197211
__deleted: false,
212+
// __version: queryEntity.currentVersion.versionId,
198213
__version: '',
199214
});
200215

216+
console.log('decodeResult', decodeResult);
217+
201218
if (Either.isRight(decodeResult)) {
202219
return {
203220
data: { ...decodeResult.right, __schema: type } as Entity.Entity<S>,
@@ -220,61 +237,42 @@ export const useEntityPublic = <S extends Schema.Schema.AnyNoContext>(type: S, p
220237
const { id, enabled = true, space: spaceFromParams, include } = params;
221238
const { space: spaceFromContext } = useHypergraphSpaceInternal();
222239
const space = spaceFromParams ?? spaceFromContext;
223-
const mapping = useSelector(store, (state) => state.context.mapping);
224-
225-
// @ts-expect-error TODO should use the actual type instead of the name in the mapping
226-
const typeName = type.name;
227-
const mappingEntry = mapping?.[typeName];
228-
if (enabled && !mappingEntry) {
229-
throw new Error(`Mapping entry for ${typeName} not found`);
230-
}
231240

232241
// constructing the relation type ids for the query
233-
const relationTypeIdsLevel1: string[] = [];
234-
const relationTypeIdsLevel2: string[] = [];
235-
for (const key in mappingEntry?.relations ?? {}) {
236-
if (include?.[key] && mappingEntry?.relations?.[key]) {
237-
relationTypeIdsLevel1.push(mappingEntry?.relations?.[key]);
238-
const field = type.fields[key];
239-
// @ts-expect-error TODO find a better way to access the relation type name
240-
const typeName2 = field.value.name;
241-
const mappingEntry2 = mapping[typeName2];
242-
for (const key2 in mappingEntry2?.relations ?? {}) {
243-
if (include?.[key][key2] && mappingEntry2?.relations?.[key2]) {
244-
relationTypeIdsLevel2.push(mappingEntry2?.relations?.[key2]);
245-
}
246-
}
247-
}
248-
}
242+
const relationTypeIds = getRelationTypeIds(type, include);
243+
244+
const typeIds = SchemaAST.getAnnotation<string[]>(Constants.TypeIdsSymbol)(type.ast as SchemaAST.TypeLiteral).pipe(
245+
Option.getOrElse(() => []),
246+
);
249247

250248
const result = useQueryTanstack({
251-
queryKey: ['hypergraph-public-entity', typeName, id, space, relationTypeIdsLevel1, relationTypeIdsLevel2, include],
249+
queryKey: ['hypergraph-public-entity', id, typeIds, space, relationTypeIds.level1, relationTypeIds.level2, include],
252250
queryFn: async () => {
253251
let queryDocument = entityQueryDocumentLevel0;
254-
if (relationTypeIdsLevel1.length > 0) {
252+
if (relationTypeIds.level1.length > 0) {
255253
queryDocument = entityQueryDocumentLevel1;
256254
}
257-
if (relationTypeIdsLevel2.length > 0) {
255+
if (relationTypeIds.level2.length > 0) {
258256
queryDocument = entityQueryDocumentLevel2;
259257
}
260258

261259
const result = await request<EntityQueryResult>(`${Graph.TESTNET_API_ORIGIN}/graphql`, queryDocument, {
262260
id,
263261
spaceId: space,
264-
relationTypeIdsLevel1,
265-
relationTypeIdsLevel2,
262+
relationTypeIdsLevel1: relationTypeIds.level1,
263+
relationTypeIdsLevel2: relationTypeIds.level2,
266264
});
267265
return result;
268266
},
269267
enabled: enabled && !!id && !!space,
270268
});
271269

272270
const { data, invalidEntity } = useMemo(() => {
273-
if (result.data && mappingEntry) {
274-
return parseResult(result.data, type, mappingEntry, mapping);
271+
if (result.data) {
272+
return parseResult(result.data, type);
275273
}
276274
return { data: null, invalidEntity: null };
277-
}, [result.data, type, mappingEntry, mapping]);
275+
}, [result.data, type]);
278276

279277
return { ...result, data, invalidEntity };
280278
};

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

Lines changed: 11 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { Graph } from '@graphprotocol/grc-20';
22
import type { Entity } from '@graphprotocol/hypergraph';
3-
import { PropertyIdSymbol, TypeIdsSymbol } from '@graphprotocol/hypergraph/constants';
4-
import { isRelation } from '@graphprotocol/hypergraph/utils/isRelation';
3+
import { Constants } from '@graphprotocol/hypergraph';
54
import { useQuery as useQueryTanstack } from '@tanstack/react-query';
65
import * as Either from 'effect/Either';
76
import * as Option from 'effect/Option';
@@ -11,6 +10,7 @@ import { gql, request } from 'graphql-request';
1110
import { useMemo } from 'react';
1211
import { convertPropertyValue } from './convert-property-value.js';
1312
import { convertRelations } from './convert-relations.js';
13+
import { getRelationTypeIds } from './get-relation-type-ids.js';
1414
import { translateFilterToGraphql } from './translate-filter-to-graphql.js';
1515
import type { QueryPublicParams } from './types.js';
1616
import { useHypergraphSpaceInternal } from './use-hypergraph-space-internal.js';
@@ -201,7 +201,7 @@ export const parseResult = <S extends Schema.Schema.AnyNoContext>(queryData: Ent
201201

202202
for (const prop of ast.propertySignatures) {
203203
const propType = prop.isOptional ? prop.type.types[0] : prop.type;
204-
const result = SchemaAST.getAnnotation<string>(PropertyIdSymbol)(propType);
204+
const result = SchemaAST.getAnnotation<string>(Constants.PropertyIdSymbol)(propType);
205205

206206
if (Option.isSome(result)) {
207207
const value = queryEntity.valuesList.find((a) => a.propertyId === result.value);
@@ -242,63 +242,36 @@ export const useQueryPublic = <S extends Schema.Schema.AnyNoContext>(type: S, pa
242242
const space = spaceFromParams ?? spaceFromContext;
243243

244244
// constructing the relation type ids for the query
245-
const relationTypeIdsLevel1: string[] = [];
246-
const relationTypeIdsLevel2: string[] = [];
245+
const relationTypeIds = getRelationTypeIds(type, include);
247246

248-
const typeIds = SchemaAST.getAnnotation<string[]>(TypeIdsSymbol)(type.ast as SchemaAST.TypeLiteral).pipe(
247+
const typeIds = SchemaAST.getAnnotation<string[]>(Constants.TypeIdsSymbol)(type.ast as SchemaAST.TypeLiteral).pipe(
249248
Option.getOrElse(() => []),
250249
);
251250

252-
const ast = type.ast as SchemaAST.TypeLiteral;
253-
254-
for (const prop of ast.propertySignatures) {
255-
if (!isRelation(prop.type)) continue;
256-
257-
const result = SchemaAST.getAnnotation<string>(PropertyIdSymbol)(prop.type);
258-
if (Option.isSome(result) && include?.[prop.name]) {
259-
relationTypeIdsLevel1.push(result.value);
260-
const relationTransformation = prop.type.rest?.[0]?.type;
261-
const typeIds: string[] = SchemaAST.getAnnotation<string[]>(TypeIdsSymbol)(relationTransformation).pipe(
262-
Option.getOrElse(() => []),
263-
);
264-
if (typeIds.length === 0) {
265-
continue;
266-
}
267-
for (const nestedProp of relationTransformation.propertySignatures) {
268-
if (!isRelation(nestedProp.type)) continue;
269-
270-
const nestedResult = SchemaAST.getAnnotation<string>(PropertyIdSymbol)(nestedProp.type);
271-
if (Option.isSome(nestedResult) && include?.[prop.name][nestedProp.name]) {
272-
relationTypeIdsLevel2.push(nestedResult.value);
273-
}
274-
}
275-
}
276-
}
277-
278251
const result = useQueryTanstack({
279252
queryKey: [
280253
'hypergraph-public-entities',
281254
space,
282255
typeIds,
283-
relationTypeIdsLevel1,
284-
relationTypeIdsLevel2,
256+
relationTypeIds.level1,
257+
relationTypeIds.level2,
285258
filter,
286259
first,
287260
],
288261
queryFn: async () => {
289262
let queryDocument = entitiesQueryDocumentLevel0;
290-
if (relationTypeIdsLevel1.length > 0) {
263+
if (relationTypeIds.level1.length > 0) {
291264
queryDocument = entitiesQueryDocumentLevel1;
292265
}
293-
if (relationTypeIdsLevel2.length > 0) {
266+
if (relationTypeIds.level2.length > 0) {
294267
queryDocument = entitiesQueryDocumentLevel2;
295268
}
296269

297270
const result = await request<EntityQueryResult>(`${Graph.TESTNET_API_ORIGIN}/graphql`, queryDocument, {
298271
spaceId: space,
299272
typeIds,
300-
relationTypeIdsLevel1,
301-
relationTypeIdsLevel2,
273+
relationTypeIdsLevel1: relationTypeIds.level1,
274+
relationTypeIdsLevel2: relationTypeIds.level2,
302275
first,
303276
filter: filter ? translateFilterToGraphql(filter, type) : {},
304277
});

packages/hypergraph/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
export { Id } from '@graphprotocol/grc-20';
22
export * as Typesync from './cli/services/Model.js';
33
export * as Connect from './connect/index.js';
4+
export * as Constants from './constants.js';
45
export { EntitySchema } from './entity/entity.js';
56
export * as Entity from './entity/index.js';
67
export * as Identity from './identity/index.js';

packages/hypergraph/src/utils/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ export * from './automergeId.js';
33
export * from './base58.js';
44
export * from './generateId.js';
55
export * from './hexBytesAddressUtils.js';
6+
export * from './isRelation.js';
67
export * from './isRelationField.js';
78
export * from './jsc.js';
89
export * from './stringToUint8Array.js';

0 commit comments

Comments
 (0)