Skip to content

Commit 343fd95

Browse files
committed
implement Type.optional
1 parent eb5ab5e commit 343fd95

File tree

14 files changed

+175
-26
lines changed

14 files changed

+175
-26
lines changed

apps/events/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
"@noble/hashes": "^1.8.0",
1616
"@radix-ui/react-avatar": "^1.1.9",
1717
"@radix-ui/react-icons": "^1.3.2",
18+
"@radix-ui/react-label": "^2.1.7",
1819
"@radix-ui/react-slot": "^1.2.2",
1920
"@tanstack/react-query": "^5.75.5",
2021
"@tanstack/react-router": "^1.120.2",

apps/events/src/components/events/events.tsx

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { useState } from 'react';
1010
import { Event } from '../../schema';
1111
import { Button } from '../ui/button';
1212
import { Input } from '../ui/input';
13+
import { Label } from '../ui/label';
1314

1415
export const Events = () => {
1516
const { data: eventsLocalData } = useQuery(Event, { mode: 'private' });
@@ -43,6 +44,7 @@ export const Events = () => {
4344
{eventsLocalData.map((event) => (
4445
<div key={event.id} className="flex flex-row items-center gap-2">
4546
<h2>{event.name}</h2>
47+
<p>{event.description}</p>
4648
<div className="text-xs">{event.id}</div>
4749
<select
4850
value={selectedSpace}
@@ -66,10 +68,22 @@ export const Events = () => {
6668
e.preventDefault();
6769
const formData = new FormData(e.target as HTMLFormElement);
6870
const name = formData.get('name') as string;
69-
createEvent({ name });
71+
const description = formData.get('description') as string;
72+
if (!name) {
73+
alert('Name is required');
74+
return;
75+
}
76+
if (description) {
77+
createEvent({ name, description });
78+
} else {
79+
createEvent({ name });
80+
}
7081
}}
7182
>
72-
<Input type="text" name="name" />
83+
<Label htmlFor="name">Name</Label>
84+
<Input type="text" name="name" required />
85+
<Label htmlFor="description">Description</Label>
86+
<Input type="text" name="description" />
7387
<Button type="submit">Create Event</Button>
7488
</form>
7589
</>
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import * as React from "react"
2+
import * as LabelPrimitive from "@radix-ui/react-label"
3+
4+
import { cn } from "@/lib/utils"
5+
6+
function Label({
7+
className,
8+
...props
9+
}: React.ComponentProps<typeof LabelPrimitive.Root>) {
10+
return (
11+
<LabelPrimitive.Root
12+
data-slot="label"
13+
className={cn(
14+
"flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50",
15+
className
16+
)}
17+
{...props}
18+
/>
19+
)
20+
}
21+
22+
export { Label }

apps/events/src/mapping.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ export const mapping: Mapping = {
66
typeIds: [Id.Id('7f9562d4-034d-4385-bf5c-f02cdebba47a')],
77
properties: {
88
name: Id.Id('a126ca53-0c8e-48d5-b888-82c734c38935'),
9+
description: Id.Id('9b1f76ff-9711-404c-861e-59dc3fa7d037'),
910
},
1011
relations: {
1112
sponsors: Id.Id('6860bfac-f703-4289-b789-972d0aaf3abe'),

apps/events/src/schema.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,6 @@ export class Company extends Entity.Class<Company>('Company')({
3333

3434
export class Event extends Entity.Class<Event>('Event')({
3535
name: Type.Text,
36-
// description: Type.Text,
36+
description: Type.optional(Type.Text),
3737
sponsors: Type.Relation(Company),
3838
}) {}

apps/typesync/client/src/Components/App/Schema/utils.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type { AppSchema } from '../../../schema.js';
22

3+
// TODO
34
function fieldToEntityString({
45
name,
56
type_name,

apps/typesync/src/Generator.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
import { execSync } from 'node:child_process';
2-
import { readdirSync } from 'node:fs';
31
import { FileSystem, Path, type Error as PlatformError } from '@effect/platform';
42
import { NodeFileSystem } from '@effect/platform-node';
53
import { Doc } from '@effect/printer';
64
import { Mapping } from '@graphprotocol/typesync';
75
import { Cause, Console, Data, Effect, Array as EffectArray, String as EffectString } from 'effect';
6+
import { execSync } from 'node:child_process';
7+
import { readdirSync } from 'node:fs';
88

99
import type * as Domain from '../domain/Domain.js';
1010
import * as Utils from './Utils.js';
@@ -301,6 +301,7 @@ function validatePackageName(name: string): {
301301
};
302302
}
303303

304+
// TODO
304305
// --------------------
305306
// schema builder
306307
// --------------------

docs/docs/schema.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
The Hypergraph schema allows you to define the data model for your application. It is based on the GRC-20 specification and allows you to define Types with properties and relations to other Types.
44

5+
TODO update this doc
6+
57
## Example
68

79
Here is an example of a schema for an Event app with the properties `name` and `description`.

packages/hypergraph-react/src/internal/use-create-entity-public.ts

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Graph, Id, type PropertiesParam, type RelationsParam } from '@graphprotocol/grc-20';
22
import type { Connect, Entity } from '@graphprotocol/hypergraph';
3-
import { store, Type } from '@graphprotocol/hypergraph';
3+
import { store, TypeUtils } from '@graphprotocol/hypergraph';
44
import { useQueryClient } from '@tanstack/react-query';
55
import { useSelector } from '@xstate/store/react';
66
import type * as Schema from 'effect/Schema';
@@ -33,14 +33,20 @@ export function useCreateEntityPublic<const S extends Entity.AnyNoContext>(
3333
const fields = type.fields;
3434
const values: PropertiesParam = [];
3535
for (const [key, value] of Object.entries(mappingEntry.properties || {})) {
36+
if (data[key] === undefined) {
37+
if (TypeUtils.isOptional(fields[key])) {
38+
continue;
39+
}
40+
throw new Error(`Value for ${key} is undefined`);
41+
}
3642
let serializedValue: string = data[key];
37-
if (fields[key] === Type.Checkbox) {
43+
if (TypeUtils.isCheckboxOrOptionalCheckboxType(fields[key])) {
3844
serializedValue = Graph.serializeCheckbox(data[key]);
39-
} else if (fields[key] === Type.Date) {
45+
} else if (TypeUtils.isDateOrOptionalDateType(fields[key])) {
4046
serializedValue = Graph.serializeDate(data[key]);
41-
} else if (fields[key] === Type.Point) {
47+
} else if (TypeUtils.isPointOrOptionalPointType(fields[key])) {
4248
serializedValue = Graph.serializePoint(data[key]);
43-
} else if (fields[key] === Type.Number) {
49+
} else if (TypeUtils.isNumberOrOptionalNumberType(fields[key])) {
4450
serializedValue = Graph.serializeNumber(data[key]);
4551
}
4652

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Graph } from '@graphprotocol/grc-20';
2-
import { type Entity, store, Type } from '@graphprotocol/hypergraph';
2+
import { type Entity, store, TypeUtils } from '@graphprotocol/hypergraph';
33
import type { Mapping, MappingEntry } from '@graphprotocol/typesync/Mapping';
44
import { useQuery as useQueryTanstack } from '@tanstack/react-query';
55
import { useSelector } from '@xstate/store/react';
@@ -154,16 +154,16 @@ const convertPropertyValue = (
154154
key: string,
155155
type: Entity.AnyNoContext,
156156
) => {
157-
if (type.fields[key] === Type.Checkbox) {
157+
if (TypeUtils.isCheckboxOrOptionalCheckboxType(type.fields[key]) && property.value !== undefined) {
158158
return Boolean(property.value);
159159
}
160-
if (type.fields[key] === Type.Point) {
160+
if (TypeUtils.isPointOrOptionalPointType(type.fields[key]) && property.value !== undefined) {
161161
return property.value;
162162
}
163-
if (type.fields[key] === Type.Date) {
163+
if (TypeUtils.isDateOrOptionalDateType(type.fields[key]) && property.value !== undefined) {
164164
return property.value;
165165
}
166-
if (type.fields[key] === Type.Number) {
166+
if (TypeUtils.isNumberOrOptionalNumberType(type.fields[key]) && property.value !== undefined) {
167167
return Number(property.value);
168168
}
169169
return property.value;

0 commit comments

Comments
 (0)