Skip to content

Commit 85591bd

Browse files
authored
Merge pull request #29 from geobrowser/space-events
Extend API
2 parents ed93e87 + e0eccd3 commit 85591bd

File tree

27 files changed

+440
-56
lines changed

27 files changed

+440
-56
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export const assertExhaustive = (_value: never, message = 'Reached unexpected case in exhaustive switch'): never => {
2+
throw new Error(message);
3+
};

apps/events/src/lib/counter.ts

Lines changed: 0 additions & 6 deletions
This file was deleted.

apps/events/src/lib/deserialize.ts

Lines changed: 0 additions & 8 deletions
This file was deleted.

apps/events/src/lib/serialize.ts

Lines changed: 0 additions & 9 deletions
This file was deleted.

apps/events/src/routes/playground.tsx

Lines changed: 107 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,49 @@
11
import { Button } from '@/components/ui/button';
2+
import { assertExhaustive } from '@/lib/assertExhaustive';
23
import { createFileRoute } from '@tanstack/react-router';
3-
import { createIdentity, createSpace } from 'graph-framework';
4+
import * as Schema from 'effect/Schema';
5+
import type { EventMessage, RequestListSpaces, RequestSubscribeToSpace } from 'graph-framework';
6+
import { ResponseMessage, createIdentity, createSpace } from 'graph-framework';
47
import { useEffect, useState } from 'react';
58

9+
const decodeResponseMessage = Schema.decodeUnknownEither(ResponseMessage);
10+
611
export const Route = createFileRoute('/playground')({
7-
component: () => <Playground />,
12+
component: () => <ChooseAccount />,
813
});
914

10-
const Playground = () => {
15+
const App = ({ accountId }: { accountId: string }) => {
1116
const [websocketConnection, setWebsocketConnection] = useState<WebSocket>();
17+
const [spaces, setSpaces] = useState<{ id: string }[]>([]);
1218

1319
useEffect(() => {
14-
const websocketConnection = new WebSocket(`ws://localhost:3030/`);
20+
// temporary until we have a way to create accounts and authenticate them
21+
const websocketConnection = new WebSocket(`ws://localhost:3030/?accountId=${accountId}`);
1522
setWebsocketConnection(websocketConnection);
1623

1724
const onMessage = (event: MessageEvent) => {
1825
console.log('message received', event.data);
26+
const data = JSON.parse(event.data);
27+
const message = decodeResponseMessage(data);
28+
if (message._tag === 'Right') {
29+
const response = message.right;
30+
switch (response.type) {
31+
case 'list-spaces': {
32+
setSpaces(response.spaces.map((space) => ({ id: space.id })));
33+
break;
34+
}
35+
case 'space': {
36+
console.log('space', response);
37+
break;
38+
}
39+
case 'event': {
40+
console.log('event', response);
41+
break;
42+
}
43+
default:
44+
assertExhaustive(response);
45+
}
46+
}
1947
};
2048
websocketConnection.addEventListener('message', onMessage);
2149

@@ -41,19 +69,89 @@ const Playground = () => {
4169
websocketConnection.removeEventListener('close', onClose);
4270
websocketConnection.close();
4371
};
44-
}, []);
72+
}, [accountId]);
73+
74+
return (
75+
<>
76+
<div>
77+
<Button
78+
onClick={() => {
79+
const identity = createIdentity();
80+
const spaceEvent = createSpace({ author: identity });
81+
const message: EventMessage = { type: 'event', event: spaceEvent };
82+
websocketConnection?.send(JSON.stringify(message));
83+
}}
84+
>
85+
Create space
86+
</Button>
87+
88+
<Button
89+
onClick={() => {
90+
const message: RequestListSpaces = { type: 'list-spaces' };
91+
websocketConnection?.send(JSON.stringify(message));
92+
}}
93+
>
94+
List Spaces
95+
</Button>
96+
</div>
97+
<h2>Spaces</h2>
98+
<ul>
99+
{spaces.map((space) => {
100+
return (
101+
<li key={space.id}>
102+
<h3>{space.id}</h3>
103+
<Button
104+
onClick={() => {
105+
const message: RequestSubscribeToSpace = { type: 'subscribe-space', id: space.id };
106+
websocketConnection?.send(JSON.stringify(message));
107+
}}
108+
>
109+
Get data and subscribe to Space
110+
</Button>
111+
</li>
112+
);
113+
})}
114+
</ul>
115+
</>
116+
);
117+
};
118+
119+
export const ChooseAccount = () => {
120+
const [accountId, setAccountId] = useState<string | null>();
45121

46122
return (
47123
<div>
124+
<h1>Choose account</h1>
125+
<Button
126+
onClick={() => {
127+
setAccountId('abc');
128+
}}
129+
>
130+
`abc`
131+
</Button>
132+
<Button
133+
onClick={() => {
134+
setAccountId('cde');
135+
}}
136+
>
137+
`cde`
138+
</Button>
48139
<Button
49140
onClick={() => {
50-
const identity = createIdentity();
51-
const spaceEvent = createSpace({ author: identity });
52-
websocketConnection?.send(JSON.stringify(spaceEvent));
141+
setAccountId('def');
53142
}}
54143
>
55-
Create space
144+
`def`
56145
</Button>
146+
Account: {accountId ? accountId : 'none'}
147+
<hr />
148+
{accountId && (
149+
<App
150+
// forcing a remount of the App component when the accountId changes
151+
key={accountId}
152+
accountId={accountId}
153+
/>
154+
)}
57155
</div>
58156
);
59157
};

apps/server/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
"effect": "^3.10.12",
2525
"express": "^5.0.1",
2626
"graph-framework-space-events": "workspace:*",
27+
"graph-framework-messages": "workspace:*",
2728
"ws": "^8.17.1"
2829
},
2930
"devDependencies": {

apps/server/prisma/migrations/20241108124551_init/migration.sql

Lines changed: 0 additions & 12 deletions
This file was deleted.
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
-- CreateTable
2+
CREATE TABLE "SpaceEvent" (
3+
"id" TEXT NOT NULL PRIMARY KEY,
4+
"event" TEXT NOT NULL,
5+
"spaceId" TEXT NOT NULL,
6+
CONSTRAINT "SpaceEvent_spaceId_fkey" FOREIGN KEY ("spaceId") REFERENCES "Space" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
7+
);
8+
9+
-- CreateTable
10+
CREATE TABLE "Space" (
11+
"id" TEXT NOT NULL PRIMARY KEY
12+
);
13+
14+
-- CreateTable
15+
CREATE TABLE "Account" (
16+
"id" TEXT NOT NULL PRIMARY KEY
17+
);
18+
19+
-- CreateTable
20+
CREATE TABLE "_AccountToSpace" (
21+
"A" TEXT NOT NULL,
22+
"B" TEXT NOT NULL,
23+
CONSTRAINT "_AccountToSpace_A_fkey" FOREIGN KEY ("A") REFERENCES "Account" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
24+
CONSTRAINT "_AccountToSpace_B_fkey" FOREIGN KEY ("B") REFERENCES "Space" ("id") ON DELETE CASCADE ON UPDATE CASCADE
25+
);
26+
27+
-- CreateIndex
28+
CREATE UNIQUE INDEX "_AccountToSpace_AB_unique" ON "_AccountToSpace"("A", "B");
29+
30+
-- CreateIndex
31+
CREATE INDEX "_AccountToSpace_B_index" ON "_AccountToSpace"("B");

apps/server/prisma/schema.prisma

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@ model SpaceEvent {
1818
}
1919

2020
model Space {
21-
id String @id
22-
events SpaceEvent[]
21+
id String @id
22+
events SpaceEvent[]
23+
members Account[]
24+
}
25+
26+
model Account {
27+
id String @id
28+
spaces Space[]
2329
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { prisma } from '../prisma.js';
2+
3+
type Params = {
4+
accountId: string;
5+
};
6+
7+
export const createAccount = async ({ accountId }: Params) => {
8+
return await prisma.account.create({
9+
data: {
10+
id: accountId,
11+
},
12+
});
13+
};

0 commit comments

Comments
 (0)