-
Notifications
You must be signed in to change notification settings - Fork 174
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
example: debug through-the-db pattern.
- Loading branch information
Showing
9 changed files
with
437 additions
and
64 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
147 changes: 147 additions & 0 deletions
147
examples/write-patterns/patterns/4-through-the-db/index.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
import React from 'react' | ||
import { v4 as uuidv4 } from 'uuid' | ||
|
||
import { | ||
PGliteProvider, | ||
useLiveQuery, | ||
usePGlite, | ||
} from '@electric-sql/pglite-react' | ||
|
||
import pglite from '../../shared/app/db' | ||
|
||
import SyncChanges from './sync' | ||
import localSchemaMigrations from './local-schema.sql?raw' | ||
|
||
const ELECTRIC_URL = import.meta.env.ELECTRIC_URL || 'http://localhost:3000' | ||
|
||
type Todo = { | ||
id: string | ||
title: string | ||
completed: boolean | ||
created_at: Date | ||
} | ||
|
||
// Note that the resources defined in the schema for this pattern | ||
// are all suffixed with `p4_`. | ||
await pglite.exec(localSchemaMigrations) | ||
|
||
// This starts the read path sync using Electric. | ||
await pglite.electric.syncShapeToTable({ | ||
shape: { | ||
url: `${ELECTRIC_URL}/v1/shape`, | ||
table: 'todos', | ||
}, | ||
shapeKey: 'todos', | ||
table: 'p4_todos_synced', | ||
primaryKey: ['id'], | ||
}) | ||
|
||
// This starts the write path sync of changes captured in the triggers from | ||
// writes to the local DB. | ||
const syncChanges = new SyncChanges(pglite) | ||
syncChanges.start() | ||
|
||
export default function Wrapper() { | ||
return ( | ||
<PGliteProvider db={pglite}> | ||
<ThroughTheDB /> | ||
</PGliteProvider> | ||
) | ||
} | ||
|
||
function ThroughTheDB() { | ||
const db = usePGlite() | ||
const results = useLiveQuery<Todo>('SELECT * FROM p4_todos ORDER BY created_at') | ||
|
||
async function createTodo(event: React.FormEvent) { | ||
event.preventDefault() | ||
|
||
const form = event.target as HTMLFormElement | ||
const formData = new FormData(form) | ||
const title = formData.get('todo') as string | ||
|
||
await db.sql` | ||
INSERT INTO p4_todos ( | ||
id, | ||
title, | ||
completed, | ||
created_at | ||
) | ||
VALUES ( | ||
${uuidv4()}, | ||
${title}, | ||
${false}, | ||
${new Date()} | ||
) | ||
` | ||
|
||
form.reset() | ||
} | ||
|
||
async function updateTodo(todo: Todo) { | ||
const { id, completed } = todo | ||
|
||
await db.sql` | ||
UPDATE p4_todos | ||
SET completed = ${!completed} | ||
WHERE id = ${id} | ||
` | ||
} | ||
|
||
async function deleteTodo(event: React.MouseEvent, todo: Todo) { | ||
event.preventDefault() | ||
|
||
await db.sql` | ||
DELETE FROM p4_todos | ||
WHERE id = ${todo.id} | ||
` | ||
} | ||
|
||
if (results === undefined) { | ||
return <div className="loading">Loading …</div> | ||
} | ||
|
||
const todos = results.rows | ||
|
||
// The template below the heading is identical to the other patterns. | ||
|
||
// prettier-ignore | ||
return ( | ||
<div id="optimistic-state" className="example"> | ||
<h3> | ||
<span className="title"> | ||
4. Through the DB sync | ||
</span> | ||
</h3> | ||
<ul> | ||
{todos.map((todo: Todo) => ( | ||
<li key={todo.id}> | ||
<label> | ||
<input type="checkbox" checked={todo.completed} | ||
onChange={() => updateTodo(todo)} | ||
/> | ||
<span className={`title ${ todo.completed ? 'completed' : '' }`}> | ||
{ todo.title } | ||
</span> | ||
</label> | ||
<a href="#delete" className="close" | ||
onClick={(event) => deleteTodo(event, todo)}> | ||
✕</a> | ||
</li> | ||
))} | ||
{todos.length === 0 && ( | ||
<li>All done 🎉</li> | ||
)} | ||
</ul> | ||
<form onSubmit={createTodo}> | ||
<input type="text" name="todo" | ||
placeholder="Type here …" | ||
required | ||
/> | ||
<button type="submit"> | ||
Add | ||
</button> | ||
</form> | ||
</div> | ||
) | ||
} |
Oops, something went wrong.