66} from "@tanstack/db-collections"
77// import { DevTools } from "./DevTools"
88import { QueryClient } from "@tanstack/query-core"
9- import { updateConfigSchema , updateTodoSchema } from "./db/validation"
9+ import { selectConfigSchema , selectTodoSchema } from "./db/validation"
1010import type { Collection } from "@tanstack/react-db"
11- import type { UpdateConfig , UpdateTodo } from "./db/validation"
11+ import type { SelectConfig , SelectTodo } from "./db/validation"
1212import type { FormEvent } from "react"
1313
1414// API helper for todos and config
@@ -17,21 +17,21 @@ const API_BASE_URL = `http://localhost:3001/api`
1717const api = {
1818 // Todo API methods
1919 todos : {
20- getAll : async ( ) : Promise < Array < UpdateTodo > > => {
20+ getAll : async ( ) : Promise < Array < SelectTodo > > => {
2121 const response = await fetch ( `${ API_BASE_URL } /todos` )
2222 if ( ! response . ok )
2323 throw new Error ( `HTTP error! Status: ${ response . status } ` )
2424 return response . json ( )
2525 } ,
26- getById : async ( id : number ) : Promise < UpdateTodo > => {
26+ getById : async ( id : number ) : Promise < SelectTodo > => {
2727 const response = await fetch ( `${ API_BASE_URL } /todos/${ id } ` )
2828 if ( ! response . ok )
2929 throw new Error ( `HTTP error! Status: ${ response . status } ` )
3030 return response . json ( )
3131 } ,
3232 create : async (
33- todo : Partial < UpdateTodo >
34- ) : Promise < { todo : UpdateTodo ; txid : number } > => {
33+ todo : Partial < SelectTodo >
34+ ) : Promise < { todo : SelectTodo ; txid : number } > => {
3535 const response = await fetch ( `${ API_BASE_URL } /todos` , {
3636 method : `POST` ,
3737 headers : { "Content-Type" : `application/json` } ,
@@ -43,8 +43,8 @@ const api = {
4343 } ,
4444 update : async (
4545 id : unknown ,
46- changes : Partial < UpdateTodo >
47- ) : Promise < { todo : UpdateTodo ; txid : number } > => {
46+ changes : Partial < SelectTodo >
47+ ) : Promise < { todo : SelectTodo ; txid : number } > => {
4848 const response = await fetch ( `${ API_BASE_URL } /todos/${ id } ` , {
4949 method : `PUT` ,
5050 headers : { "Content-Type" : `application/json` } ,
@@ -68,21 +68,21 @@ const api = {
6868
6969 // Config API methods
7070 config : {
71- getAll : async ( ) : Promise < Array < UpdateConfig > > => {
71+ getAll : async ( ) : Promise < Array < SelectConfig > > => {
7272 const response = await fetch ( `${ API_BASE_URL } /config` )
7373 if ( ! response . ok )
7474 throw new Error ( `HTTP error! Status: ${ response . status } ` )
7575 return response . json ( )
7676 } ,
77- getById : async ( id : number ) : Promise < UpdateConfig > => {
77+ getById : async ( id : number ) : Promise < SelectConfig > => {
7878 const response = await fetch ( `${ API_BASE_URL } /config/${ id } ` )
7979 if ( ! response . ok )
8080 throw new Error ( `HTTP error! Status: ${ response . status } ` )
8181 return response . json ( )
8282 } ,
8383 create : async (
84- config : Partial < UpdateConfig >
85- ) : Promise < { config : UpdateConfig ; txid : number } > => {
84+ config : Partial < SelectConfig >
85+ ) : Promise < { config : SelectConfig ; txid : number } > => {
8686 const response = await fetch ( `${ API_BASE_URL } /config` , {
8787 method : `POST` ,
8888 headers : { "Content-Type" : `application/json` } ,
@@ -94,8 +94,8 @@ const api = {
9494 } ,
9595 update : async (
9696 id : number ,
97- changes : Partial < UpdateConfig >
98- ) : Promise < { config : UpdateConfig ; txid : number } > => {
97+ changes : Partial < SelectConfig >
98+ ) : Promise < { config : SelectConfig ; txid : number } > => {
9999 const response = await fetch ( `${ API_BASE_URL } /config/${ id } ` , {
100100 method : `PUT` ,
101101 headers : { "Content-Type" : `application/json` } ,
@@ -130,12 +130,12 @@ const collectionsCache = new Map()
130130// Function to create the appropriate todo collection based on type
131131const createTodoCollection = ( type : CollectionType ) => {
132132 if ( collectionsCache . has ( `todo` ) ) {
133- return collectionsCache . get ( `todo` ) as Collection < UpdateTodo >
133+ return collectionsCache . get ( `todo` ) as Collection < SelectTodo >
134134 } else {
135- let newCollection : Collection < UpdateTodo >
135+ let newCollection : Collection < SelectTodo >
136136 if ( type === CollectionType . Electric ) {
137137 newCollection = createCollection (
138- electricCollectionOptions < UpdateTodo > ( {
138+ electricCollectionOptions ( {
139139 id : `todos` ,
140140 shapeOptions : {
141141 url : `http://localhost:3003/v1/shape` ,
@@ -147,10 +147,15 @@ const createTodoCollection = (type: CollectionType) => {
147147 timestamptz : ( date : string ) => new Date ( date ) ,
148148 } ,
149149 } ,
150- getKey : ( item ) => item . id ! ,
151- schema : updateTodoSchema ,
150+ getKey : ( item ) => item . id ,
151+ schema : selectTodoSchema ,
152152 onInsert : async ( { transaction } ) => {
153- const modified = transaction . mutations [ 0 ] . modified
153+ const {
154+ id : _id ,
155+ created_at : _f ,
156+ updated_at : _ff ,
157+ ...modified
158+ } = transaction . mutations [ 0 ] . modified
154159 const response = await api . todos . create ( modified )
155160
156161 return { txid : String ( response . txid ) }
@@ -165,7 +170,7 @@ const createTodoCollection = (type: CollectionType) => {
165170 } )
166171 )
167172
168- return { txid : String ( txids [ 0 ] . txid ) }
173+ return { txid : String ( txids [ 0 ] ! . txid ) }
169174 } ,
170175 onDelete : async ( { transaction } ) => {
171176 const txids = await Promise . all (
@@ -177,7 +182,7 @@ const createTodoCollection = (type: CollectionType) => {
177182 } )
178183 )
179184
180- return { txid : String ( txids [ 0 ] . txid ) }
185+ return { txid : String ( txids [ 0 ] ! . txid ) }
181186 } ,
182187 } )
183188 )
@@ -190,22 +195,23 @@ const createTodoCollection = (type: CollectionType) => {
190195 refetchInterval : 3000 ,
191196 queryFn : async ( ) => {
192197 const todos = await api . todos . getAll ( )
193- // Turn date strings into Dates if needed
198+ // Turn date strings into Dates
194199 return todos . map ( ( todo ) => ( {
195200 ...todo ,
196- created_at : todo . created_at
197- ? new Date ( todo . created_at )
198- : undefined ,
199- updated_at : todo . updated_at
200- ? new Date ( todo . updated_at )
201- : undefined ,
201+ created_at : new Date ( todo . created_at ) ,
202+ updated_at : new Date ( todo . updated_at ) ,
202203 } ) )
203204 } ,
204- getKey : ( item : UpdateTodo ) => item . id ! ,
205- schema : updateTodoSchema ,
205+ getKey : ( item : SelectTodo ) => item . id ,
206+ schema : selectTodoSchema ,
206207 queryClient,
207208 onInsert : async ( { transaction } ) => {
208- const modified = transaction . mutations [ 0 ] . modified
209+ const {
210+ id : _id ,
211+ created_at : _crea ,
212+ updated_at : _up ,
213+ ...modified
214+ } = transaction . mutations [ 0 ] . modified
209215 return await api . todos . create ( modified )
210216 } ,
211217 onUpdate : async ( { transaction } ) => {
@@ -235,9 +241,9 @@ const createTodoCollection = (type: CollectionType) => {
235241// Function to create the appropriate config collection based on type
236242const createConfigCollection = ( type : CollectionType ) => {
237243 if ( collectionsCache . has ( `config` ) ) {
238- return collectionsCache . get ( `config` )
244+ return collectionsCache . get ( `config` ) as Collection < SelectConfig >
239245 } else {
240- let newCollection : Collection < UpdateConfig >
246+ let newCollection : Collection < SelectConfig >
241247 if ( type === CollectionType . Electric ) {
242248 newCollection = createCollection (
243249 electricCollectionOptions ( {
@@ -254,8 +260,8 @@ const createConfigCollection = (type: CollectionType) => {
254260 } ,
255261 } ,
256262 } ,
257- getKey : ( item : UpdateConfig ) => item . id ! ,
258- schema : updateConfigSchema ,
263+ getKey : ( item : SelectConfig ) => item . id ,
264+ schema : selectConfigSchema ,
259265 onInsert : async ( { transaction } ) => {
260266 const modified = transaction . mutations [ 0 ] . modified
261267 const response = await api . config . create ( modified )
@@ -286,19 +292,15 @@ const createConfigCollection = (type: CollectionType) => {
286292 refetchInterval : 3000 ,
287293 queryFn : async ( ) => {
288294 const configs = await api . config . getAll ( )
289- // Turn date strings into Dates if needed
295+ // Turn date strings into Dates
290296 return configs . map ( ( config ) => ( {
291297 ...config ,
292- created_at : config . created_at
293- ? new Date ( config . created_at )
294- : undefined ,
295- updated_at : config . updated_at
296- ? new Date ( config . updated_at )
297- : undefined ,
298+ created_at : new Date ( config . created_at ) ,
299+ updated_at : new Date ( config . updated_at ) ,
298300 } ) )
299301 } ,
300- getKey : ( item : UpdateConfig ) => item . id ,
301- schema : updateConfigSchema ,
302+ getKey : ( item : SelectConfig ) => item . id ,
303+ schema : selectConfigSchema ,
302304 queryClient,
303305 onInsert : async ( { transaction } ) => {
304306 const modified = transaction . mutations [ 0 ] . modified
@@ -348,12 +350,12 @@ export default function App() {
348350 q
349351 . from ( { todoCollection : todoCollection } )
350352 . orderBy ( `@created_at` )
351- . select ( `@id` , `@created_at` , `@text` , `@completed `)
353+ . select ( `@* ` )
352354 )
353355
354356 const { data : configData } = useLiveQuery ( ( q ) =>
355357 q
356- . from ( { configCollection : configCollection as Collection < UpdateConfig > } )
358+ . from ( { configCollection : configCollection } )
357359 . select ( `@id` , `@key` , `@value` )
358360 )
359361
@@ -371,7 +373,7 @@ export default function App() {
371373 const getConfigValue = ( key : string ) : string => {
372374 for ( const config of configData ) {
373375 if ( config . key === key ) {
374- return config . value !
376+ return config . value
375377 }
376378 }
377379 return ``
@@ -391,8 +393,11 @@ export default function App() {
391393
392394 // If the config doesn't exist yet, create it
393395 configCollection . insert ( {
396+ id : Math . random ( ) ,
394397 key,
395398 value,
399+ created_at : new Date ( ) ,
400+ updated_at : new Date ( ) ,
396401 } )
397402 }
398403
@@ -457,17 +462,12 @@ export default function App() {
457462 text : newTodo ,
458463 completed : false ,
459464 id : Math . round ( Math . random ( ) * 1000000 ) ,
465+ created_at : new Date ( ) ,
466+ updated_at : new Date ( ) ,
460467 } )
461468 setNewTodo ( `` )
462469 }
463470
464- const toggleTodo = ( todo : UpdateTodo ) => {
465- console . log ( todoCollection )
466- todoCollection . update ( todo . id , ( draft ) => {
467- draft . completed = ! draft . completed
468- } )
469- }
470-
471471 const activeTodos = todos . filter ( ( todo ) => ! todo . completed )
472472 const completedTodos = todos . filter ( ( todo ) => todo . completed )
473473
@@ -597,7 +597,11 @@ export default function App() {
597597 < input
598598 type = "checkbox"
599599 checked = { todo . completed }
600- onChange = { ( ) => toggleTodo ( todo ) }
600+ onChange = { ( ) =>
601+ todoCollection . update ( todo . id , ( draft ) => {
602+ draft . completed = ! draft . completed
603+ } )
604+ }
601605 className = "absolute left-[12px] top-0 bottom-0 my-auto h-[40px] w-[40px] cursor-pointer"
602606 />
603607 < label
0 commit comments