Skip to content

Commit 7ed329b

Browse files
authored
fix resolving optional values in a Relation Entity (#556)
1 parent 62be585 commit 7ed329b

File tree

5 files changed

+146
-12
lines changed

5 files changed

+146
-12
lines changed

.changeset/pretty-sheep-push.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"@graphprotocol/hypergraph-react": patch
3+
"@graphprotocol/hypergraph": patch
4+
---
5+
6+
fix resolving optional values in a Relation Entity
7+

apps/events/src/routes/podcasts-infinite.lazy.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ function RouteComponent() {
1515
offset: 0,
1616
space: space,
1717
include: {
18-
projects: {},
18+
listenOn: {},
1919
},
2020
});
2121

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

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ function RouteComponent() {
1717
id: 'f5d27d3e-3a51-452d-bac2-702574381633',
1818
space: space,
1919
include: {
20-
projects: {},
20+
listenOn: {},
2121
},
2222
});
2323
console.log('findOnePublic result:', result);
@@ -29,7 +29,7 @@ function RouteComponent() {
2929
first: 100,
3030
space: space,
3131
include: {
32-
projects: {},
32+
listenOn: {},
3333
},
3434
orderBy: { property: 'dateFounded', direction: 'asc' },
3535
backlinksTotalCountsTypeId1: '972d201a-d780-4568-9e01-543f67b26bee',
@@ -45,15 +45,14 @@ function RouteComponent() {
4545
<h2>
4646
{podcast.backlinksTotalCountsTypeId1} - {podcast.dateFounded.toISOString()} {podcast.name} - {podcast.id}
4747
</h2>
48-
{podcast.projects.map((project) => (
49-
<div key={project._relation.id}>
50-
<h3>- {project.name}</h3>
51-
<div>--{project._relation.website}</div>
48+
{podcast.listenOn.map((listenOn) => (
49+
<div key={listenOn._relation.id}>
50+
<h3>- {listenOn.name}</h3>
51+
<div>--{listenOn._relation.website}</div>
5252
</div>
5353
))}
5454
</div>
5555
))}
56-
<pre className="text-xs">{JSON.stringify(data, null, 2)}</pre>
5756
</>
5857
);
5958
}

apps/events/src/schema.ts

Lines changed: 125 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,13 +118,60 @@ export const Project = Entity.Schema(
118118
},
119119
);
120120

121+
export const Person = Entity.Schema(
122+
{
123+
name: Type.String,
124+
description: Type.optional(Type.String),
125+
avatar: Type.Relation(Image),
126+
},
127+
{
128+
types: [Id('7ed45f2b-c48b-419e-8e46-64d5ff680b0d')],
129+
properties: {
130+
name: Id('a126ca53-0c8e-48d5-b888-82c734c38935'),
131+
description: Id('9b1f76ff-9711-404c-861e-59dc3fa7d037'),
132+
avatar: Id('1155beff-fad5-49b7-a2e0-da4777b8792c'),
133+
},
134+
},
135+
);
136+
137+
export const Topic = Entity.Schema(
138+
{
139+
name: Type.optional(Type.String),
140+
cover: Type.Relation(Image),
141+
},
142+
{
143+
types: [Id('5ef5a586-0f27-4d8e-8f6c-59ae5b3e89e2')],
144+
properties: {
145+
name: Id('a126ca53-0c8e-48d5-b888-82c734c38935'),
146+
cover: Id('34f53507-2e6b-42c5-a844-43981a77cfa2'),
147+
},
148+
},
149+
);
150+
151+
// Generic entity for platform links (Apple Podcasts, Spotify, etc.)
152+
// Using Project type since platforms like Apple Podcasts use this type
153+
export const GenericEntity = Entity.Schema(
154+
{
155+
name: Type.String,
156+
},
157+
{
158+
types: [Id('484a18c5-030a-499c-b0f2-ef588ff16d50')], // Project type
159+
properties: {
160+
name: Id('a126ca53-0c8e-48d5-b888-82c734c38935'),
161+
},
162+
},
163+
);
164+
121165
export const Podcast = Entity.Schema(
122166
{
123167
name: Type.String,
124168
description: Type.optional(Type.String),
125169
dateFounded: Type.Date,
126170
rssFeedUrl: Type.optional(Type.String),
127-
projects: Type.Relation(Project, {
171+
avatar: Type.Relation(Image),
172+
hosts: Type.Relation(Person),
173+
topics: Type.Relation(Topic),
174+
listenOn: Type.Relation(GenericEntity, {
128175
properties: {
129176
website: Type.optional(Type.String),
130177
},
@@ -137,7 +184,83 @@ export const Podcast = Entity.Schema(
137184
description: Id('9b1f76ff-9711-404c-861e-59dc3fa7d037'),
138185
dateFounded: Id('41aa3d98-47b6-4a97-b7ec-427e575b910e'),
139186
rssFeedUrl: Id('a5776138-deb8-436f-8c98-3eccd100d98f'),
140-
projects: {
187+
hosts: Id('c72d9abb-bca8-4e86-b7e8-b71e91d2b37e'),
188+
avatar: Id('1155beff-fad5-49b7-a2e0-da4777b8792c'),
189+
topics: Id('458fbc07-0dbf-4c92-8f57-16f3fdde7c32'),
190+
listenOn: {
191+
propertyId: Id('1367bac7-dcea-4b80-86ad-a4a4cdd7c2cb'),
192+
properties: {
193+
website: Id('eed38e74-e679-46bf-8a42-ea3e4f8fb5fb'),
194+
},
195+
},
196+
},
197+
},
198+
);
199+
200+
export const Quote = Entity.Schema(
201+
{
202+
name: Type.String,
203+
},
204+
{
205+
types: [Id('043a171c-6918-4dc3-a7db-b8471ca6fcc2')],
206+
properties: {
207+
name: Id('a126ca53-0c8e-48d5-b888-82c734c38935'),
208+
},
209+
},
210+
);
211+
212+
export const Claim = Entity.Schema(
213+
{
214+
name: Type.String,
215+
},
216+
{
217+
types: [Id('043a171c-6918-4dc3-a7db-b8471ca6fcc2')],
218+
properties: {
219+
name: Id('a126ca53-0c8e-48d5-b888-82c734c38935'),
220+
},
221+
},
222+
);
223+
224+
export const Episode = Entity.Schema(
225+
{
226+
name: Type.String,
227+
description: Type.optional(Type.String),
228+
airDate: Type.Date,
229+
avatar: Type.Relation(Image),
230+
duration: Type.optional(Type.Number), // in seconds
231+
audioUrl: Type.optional(Type.String),
232+
episodeNumber: Type.optional(Type.Number),
233+
guests: Type.Relation(Person),
234+
hosts: Type.Relation(Person),
235+
podcast: Type.Relation(Podcast),
236+
contributors: Type.Relation(Person),
237+
quotes: Type.Relation(Quote),
238+
claims: Type.Relation(Claim),
239+
topics: Type.Relation(Topic),
240+
listenOn: Type.Relation(GenericEntity, {
241+
properties: {
242+
website: Type.optional(Type.String),
243+
},
244+
}),
245+
},
246+
{
247+
types: [Id('972d201a-d780-4568-9e01-543f67b26bee')],
248+
properties: {
249+
name: Id('a126ca53-0c8e-48d5-b888-82c734c38935'),
250+
description: Id('9b1f76ff-9711-404c-861e-59dc3fa7d037'),
251+
airDate: Id('77999397-f78d-44a7-bbc5-d93a617af47c'),
252+
duration: Id('76996acc-d10f-4cd5-9ac9-4a705b8e03b4'),
253+
audioUrl: Id('87f919d5-560b-408c-be8d-318e2c5c098b'),
254+
episodeNumber: Id('9b5eced9-5c30-473b-8404-f474a777db3a'),
255+
hosts: Id('c72d9abb-bca8-4e86-b7e8-b71e91d2b37e'),
256+
guests: Id('cb60a1a6-6fb5-48c9-b936-200c5c271330'),
257+
avatar: Id('1155beff-fad5-49b7-a2e0-da4777b8792c'),
258+
podcast: Id('f1873bbc-381f-4604-abad-76fed4f6d73f'),
259+
contributors: Id('1ff59132-2d57-4671-934a-7b662e3cf66a'),
260+
quotes: Id('8d4ae49c-226d-4086-8ec3-af5d5b2a65d0'),
261+
claims: Id('e1371bcd-a704-4396-adb7-ea7ecc8fe3d4'),
262+
topics: Id('458fbc07-0dbf-4c92-8f57-16f3fdde7c32'),
263+
listenOn: {
141264
propertyId: Id('1367bac7-dcea-4b80-86ad-a4a4cdd7c2cb'),
142265
properties: {
143266
website: Id('eed38e74-e679-46bf-8a42-ea3e4f8fb5fb'),

packages/hypergraph/src/utils/convert-relations.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,13 +84,18 @@ export const convertRelations = <_S extends Schema.Schema.AnyNoContext>(
8484
};
8585

8686
for (const nestedProp of relationTransformation.propertySignatures) {
87-
const nestedResult = SchemaAST.getAnnotation<string>(Constants.PropertyIdSymbol)(nestedProp.type);
87+
const propType =
88+
nestedProp.isOptional && SchemaAST.isUnion(nestedProp.type)
89+
? (nestedProp.type.types.find((member) => !SchemaAST.isUndefinedKeyword(member)) ?? nestedProp.type)
90+
: nestedProp.type;
91+
92+
const nestedResult = SchemaAST.getAnnotation<string>(Constants.PropertyIdSymbol)(propType);
8893
if (Option.isSome(nestedResult)) {
8994
const value = relationEntry.toEntity.valuesList?.find((a) => a.propertyId === nestedResult.value);
9095
if (!value) {
9196
continue;
9297
}
93-
const rawValue = convertPropertyValue(value, nestedProp.type);
98+
const rawValue = convertPropertyValue(value, propType);
9499
if (rawValue) {
95100
nestedRawEntity[String(nestedProp.name)] = rawValue;
96101
}

0 commit comments

Comments
 (0)