### Install TanStack Dexie DB Collection and React DB Source: https://github.com/himanshukumardutt094/tanstack-dexie-db-collection/blob/master/README.md This command installs the necessary packages for using tanstack-dexie-db-collection with @tanstack/react-db. Ensure you have Node.js and npm/yarn/pnpm installed. ```bash npm install tanstack-dexie-db-collection @tanstack/react-db ``` -------------------------------- ### Bootstrap Initial Data Locally (TypeScript) Source: https://github.com/himanshukumardutt094/tanstack-dexie-db-collection/blob/master/EXAMPLES.md Demonstrates how to load initial data from a server into a Dexie collection without triggering existing handlers like `onInsert`. It uses `bulkInsertLocally` for efficiency and stores the last sync time in local storage. ```typescript const productsCollection = createCollection( dexieCollectionOptions({ id: "products", schema: productSchema, getKey: (product) => product.id, // Handlers for user-initiated changes onInsert: async ({ transaction }) => { await api.products.create(transaction.mutations[0].modified) }, }) ) // Bootstrap function - loads initial data without triggering onInsert async function bootstrapProducts() { const lastSync = localStorage.getItem("products-last-sync") // Fetch all products from server const serverProducts = await fetch("/api/products").then((r) => r.json()) // Write directly to local storage without triggering handlers await productsCollection.utils.bulkInsertLocally(serverProducts) localStorage.setItem("products-last-sync", new Date().toISOString()) console.log(`Bootstrapped ${serverProducts.length} products`) } // Call on app startup bootstrapProducts() ``` -------------------------------- ### Define and Create E-commerce Products Collection (TypeScript) Source: https://github.com/himanshukumardutt094/tanstack-dexie-db-collection/blob/master/EXAMPLES.md Defines a Zod schema for products and creates a Dexie collection for managing them. Includes serialization/deserialization logic for dates and an onUpdate handler to sync changes with a backend API. ```typescript const productSchema = z.object({ id: z.string(), name: z.string(), price: z.number(), category: z.string(), inStock: z.boolean(), lastUpdated: z.date(), }) const productsCollection = createCollection( dexieCollectionOptions({ id: "products", schema: productSchema, getKey: (product) => product.id, dbName: "ecommerce-app", syncBatchSize: 100, codec: { serialize: (product) => ({ ...product, lastUpdated: product.lastUpdated.toISOString(), }), parse: (stored) => ({ ...stored, lastUpdated: new Date(stored.lastUpdated), }), }, onUpdate: async ({ transaction }) => { const updates = transaction.mutations.map((m) => ({ id: m.key, changes: m.changes, })) await fetch("/api/products/bulk-update", { method: "PATCH", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ updates }), }) }, }) ) ``` -------------------------------- ### Complete React Todo App with TanStack DB and Dexie Source: https://github.com/himanshukumardutt094/tanstack-dexie-db-collection/blob/master/EXAMPLES.md Demonstrates a full React Todo application using TanStack DB with Dexie.js for local data management and optimistic UI updates. It includes backend synchronization handlers for insert, update, and delete operations. Assumes a `todoAPI` object is available for backend interactions. ```typescript import React, { useState } from "react" import { createCollection } from "@tanstack/db" import { useLiveQuery } from "@tanstack/react-db" import { dexieCollectionOptions } from "tanstack-dexie-db-collection" import { z } from "zod" const todoSchema = z.object({ id: z.string(), text: z.string(), completed: z.boolean(), createdAt: z.date(), }) type Todo = z.infer // Create collection with backend sync const todosCollection = createCollection( dexieCollectionOptions({ id: "todos", schema: todoSchema, getKey: (item) => item.id, // Optimistic updates with background sync awaitPersistence: false, swallowPersistenceErrors: true, onInsert: async ({ transaction }) => { for (const mutation of transaction.mutations) { try { await todoAPI.create(mutation.modified) } catch (error) { console.error("Backend sync failed for insert:", error) } } }, onUpdate: async ({ transaction }) => { for (const mutation of transaction.mutations) { try { await todoAPI.update( mutation.key, mutation.changes || mutation.modified ) } catch (error) { console.error("Backend sync failed for update:", error) } } }, onDelete: async ({ transaction }) => { for (const mutation of transaction.mutations) { try { await todoAPI.delete(mutation.key) } catch (error) { console.error("Backend sync failed for delete:", error) } } }, }) ) function TodoApp() { const { data: todos = [] } = useLiveQuery(todosCollection) const [newTodoText, setNewTodoText] = useState("") const addTodo = async () => { if (!newTodoText.trim()) return const tx = todosCollection.insert({ id: crypto.randomUUID(), text: newTodoText.trim(), completed: false, createdAt: new Date(), }) await tx.isPersisted.promise setNewTodoText("") } const toggleTodo = async (id: string) => { const tx = todosCollection.update(id, (todo) => { todo.completed = !todo.completed }) await tx.isPersisted.promise } const deleteTodo = async (id: string) => { const tx = todosCollection.delete(id) await tx.isPersisted.promise } return (

Todos ({todos.length})

setNewTodoText(e.target.value)} placeholder="Add a todo..." onKeyPress={(e) => e.key === "Enter" && addTodo()} />
) } export default TodoApp ``` -------------------------------- ### Bootstraping Collection with Server Data in TypeScript Source: https://github.com/himanshukumardutt094/tanstack-dexie-db-collection/blob/master/README.md Shows an example of bootstrapping a local Dexie collection with data fetched from a server API. The `bulkInsertLocally` utility is used to efficiently insert multiple records, and the sequential ID counter is initialized based on the maximum existing ID. ```typescript // Bootstrap from server const serverTodos = await fetch("/api/todos").then((r) => r.json()) await todosCollection.utils.bulkInsertLocally(serverTodos) // If server has IDs 1-100, counter initializes to 100 // Create new todo const nextId = await todosCollection.utils.getNextId() // Returns 101 ``` -------------------------------- ### Offline-First with Background Sync in TypeScript Source: https://github.com/himanshukumardutt094/tanstack-dexie-db-collection/blob/master/EXAMPLES.md Demonstrates an offline-first approach for a 'tasks' collection. It initializes data from the server and performs background synchronization periodically. Errors during sync are handled gracefully to maintain local data availability. Dependencies include the TanStack collection API, Dexie.js, and the Navigator.onLine API. ```typescript const tasksCollection = createCollection( dexieCollectionOptions({ id: "tasks", schema: taskSchema, getKey: (task) => task.id, // Fire-and-forget sync to server awaitPersistence: false, swallowPersistenceErrors: true, onInsert: async ({ transaction }) => { try { await api.tasks.create(transaction.mutations[0].modified) } catch (error) { console.error("Failed to sync task to server:", error) // Task is still saved locally } }, }) ) // Bootstrap on app start async function initializeTasks() { try { // Fetch latest from server const serverTasks = await api.tasks.list() // Merge with local data (server is source of truth) await tasksCollection.utils.bulkInsertLocally(serverTasks) console.log("Tasks synchronized") } catch (error) { console.log("Offline mode - using local data") } } // Periodic background sync async function backgroundSync() { if (!navigator.onLine) return try { const lastSync = localStorage.getItem("tasks-last-sync") const changes = await api.tasks.changes(lastSync) await tasksCollection.utils.bulkInsertLocally(changes.created) await tasksCollection.utils.bulkUpdateLocally(changes.updated) await tasksCollection.utils.bulkDeleteLocally(changes.deleted) localStorage.setItem("tasks-last-sync", new Date().toISOString()) } catch (error) { console.error("Background sync failed:", error) } } // Initialize and start background sync initializeTasks() setInterval(backgroundSync, 30000) // Every 30 seconds ``` -------------------------------- ### Create TanStack Collection with Schema and Validation Source: https://github.com/himanshukumardutt094/tanstack-dexie-db-collection/blob/master/README.md This example demonstrates creating a TanStack DB collection with a Zod schema, enabling type inference and runtime validation for the data. It also customizes the database and table names for Dexie. ```typescript import { z } from "zod" const todoSchema = z.object({ id: z.string(), text: z.string(), completed: z.boolean(), createdAt: z.date().optional(), }) const todosCollection = createCollection( dexieCollectionOptions({ id: "todos", schema: todoSchema, getKey: (item) => item.id, // `item` is fully typed from schema dbName: "my-todo-app", tableName: "todos", }) ) ``` -------------------------------- ### Manage User Profiles with Real-time Updates (TypeScript) Source: https://github.com/himanshukumardutt094/tanstack-dexie-db-collection/blob/master/EXAMPLES.md Sets up a user profile collection with a defined schema, including nested objects and enums. Features an onUpdate handler that syncs individual user profile updates to a backend API and a React component demonstrating live query usage and preference updates. ```typescript const userProfileSchema = z.object({ id: z.string(), name: z.string(), email: z.string().email(), avatar: z.string().optional(), preferences: z.object({ theme: z.enum(["light", "dark"]), notifications: z.boolean(), }), lastSeen: z.date(), }) const userProfileCollection = createCollection( dexieCollectionOptions({ id: "user-profiles", schema: userProfileSchema, getKey: (user) => user.id, awaitPersistence: true, persistenceTimeoutMs: 8000, onUpdate: async ({ transaction }) => { for (const mutation of transaction.mutations) { await fetch(`/api/users/${mutation.key}`, { method: "PATCH", headers: { "Content-Type": "application/json" }, body: JSON.stringify(mutation.changes || mutation.modified), }) } }, }) ) function UserSettings() { const { data: users = [] } = useLiveQuery(userProfileCollection) const currentUser = users[0] const updatePreferences = async (newPrefs: any) => { const tx = userProfileCollection.update(currentUser.id, (user) => { user.preferences = { ...user.preferences, ...newPrefs } }) try { await tx.isPersisted.promise showNotification("Settings saved!", "success") } catch (error) { showNotification("Failed to save settings", "error") } } } ``` -------------------------------- ### Incremental Sync from Server with TypeScript Source: https://github.com/himanshukumardutt094/tanstack-dexie-db-collection/blob/master/EXAMPLES.md Implements incremental synchronization for a 'notes' collection. It fetches changes since the last sync from the server and applies them locally. Dependencies include the TanStack collection API and Dexie.js. It uses local storage to track the last sync timestamp. ```typescript const notesCollection = createCollection( dexieCollectionOptions({ id: "notes", schema: noteSchema, getKey: (note) => note.id, onInsert: async ({ transaction }) => { await api.notes.create(transaction.mutations[0].modified) }, onUpdate: async ({ transaction }) => { await api.notes.update( transaction.mutations[0].key, transaction.mutations[0].changes ) }, onDelete: async ({ transaction }) => { await api.notes.delete(transaction.mutations[0].key) }, }) ) // Incremental sync - only fetch changes since last sync async function syncNotes() { const lastSync = localStorage.getItem("notes-last-sync") // Fetch only changes since last sync const changes = await fetch(`/api/notes/changes?since=${lastSync}`).then( (r) => r.json() ) // Apply changes locally without triggering handlers if (changes.created.length > 0) { await notesCollection.utils.bulkInsertLocally(changes.created) } if (changes.updated.length > 0) { await notesCollection.utils.bulkUpdateLocally(changes.updated) } if (changes.deleted.length > 0) { await notesCollection.utils.bulkDeleteLocally(changes.deleted) } localStorage.setItem("notes-last-sync", new Date().toISOString()) console.log( `Synced: ${changes.created.length} created, ${changes.updated.length} updated, ${changes.deleted.length} deleted` ) } // Sync periodically setInterval(syncNotes, 60000) // Every minute ``` -------------------------------- ### Implement Real-time Chat Messages Sync (TypeScript) Source: https://github.com/himanshukumardutt094/tanstack-dexie-db-collection/blob/master/EXAMPLES.md Creates a Dexie collection for chat messages with a schema including timestamps and status enums. It utilizes `onInsert` to send new messages to a server and update their status, and a React component for displaying and sending messages within a chat window. ```typescript const messageSchema = z.object({ id: z.string(), chatId: z.string(), senderId: z.string(), content: z.string(), timestamp: z.date(), status: z.enum(["sending", "sent", "delivered", "read"]), }) const messagesCollection = createCollection( dexieCollectionOptions({ id: "messages", schema: messageSchema, getKey: (message) => message.id, awaitPersistence: false, onInsert: async ({ transaction }) => { for (const mutation of transaction.mutations) { const message = mutation.modified await sendMessageToServer(message) messagesCollection.update(message.id, (msg) => { msg.status = "sent" }) } }, }) ) function ChatWindow({ chatId }: { chatId: string }) { const { data: allMessages = [] } = useLiveQuery(messagesCollection) const chatMessages = allMessages.filter((msg) => msg.chatId === chatId) const sendMessage = async (content: string) => { const newMessage = { id: crypto.randomUUID(), chatId, senderId: getCurrentUserId(), content, timestamp: new Date(), status: "sending" as const, } messagesCollection.insert(newMessage) } } ``` -------------------------------- ### TanStack Dexie DB: Local vs. Regular Write Utilities Comparison Source: https://github.com/himanshukumardutt094/tanstack-dexie-db-collection/blob/master/EXAMPLES.md Compares the behavior of regular `insert` and `utils.insertLocally` methods in TanStack Dexie DB. A regular `insert` triggers defined handlers (e.g., `onInsert` for server synchronization), while `utils.insertLocally` writes data directly to the local database without invoking these handlers. This is useful for scenarios like initial data loading or server-sent updates. ```typescript const collection = createCollection( dexieCollectionOptions({ id: "items", getKey: (item) => item.id, onInsert: async ({ transaction }) => { console.log("onInsert called - syncing to server") await api.items.create(transaction.mutations[0].modified) }, }) ) // ❌ Regular insert - triggers onInsert handler await collection.insert({ id: "1", name: "Item 1" }) // Console: "onInsert called - syncing to server" // ✅ Local insert - does NOT trigger onInsert handler await collection.utils.insertLocally({ id: "2", name: "Item 2" }) // No console output - handler not called // Use cases: // - Regular insert: User creates new item → sync to server // - Local insert: Server sends new item → write locally only ``` -------------------------------- ### WebSocket Real-time Updates with TypeScript Source: https://github.com/himanshukumardutt094/tanstack-dexie-db-collection/blob/master/EXAMPLES.md Handles real-time updates for a 'messages' collection using WebSockets. It listens for incoming messages and applies them locally using Dexie.js utilities, bypassing handlers to prevent redundant operations. Dependencies include the TanStack collection API, Dexie.js, and the WebSocket API. ```typescript const messagesCollection = createCollection( dexieCollectionOptions({ id: "messages", schema: messageSchema, getKey: (message) => message.id, // Handler for user sending messages onInsert: async ({ transaction }) => { const message = transaction.mutations[0].modified await api.messages.send(message) }, }) ) // WebSocket connection for real-time updates from other users const ws = new WebSocket("wss://api.example.com/messages") ws.onmessage = async (event) => { const update = JSON.parse(event.data) switch (update.type) { case "message:created": // Write directly without triggering onInsert await messagesCollection.utils.insertLocally(update.message) break case "message:updated": await messagesCollection.utils.updateLocally( update.message.id, update.message ) break case "message:deleted": await messagesCollection.utils.deleteLocally(update.messageId) break case "messages:bulk": // Handle bulk updates efficiently await messagesCollection.utils.bulkInsertLocally(update.messages) break } } // User sends a message (triggers onInsert handler) async function sendMessage(content: string) { await messagesCollection.insert({ id: crypto.randomUUID(), content, senderId: getCurrentUserId(), timestamp: new Date(), }) } ``` -------------------------------- ### Dexie Table Access via Collection Utilities in TypeScript Source: https://github.com/himanshukumardutt094/tanstack-dexie-db-collection/blob/master/README.md Demonstrates how to get direct access to the underlying Dexie table from a collection's utilities. This allows for advanced querying and manipulation of the data using Dexie's native API, such as filtering by 'completed' status. ```typescript // Get direct access to the Dexie table const table = todosCollection.utils.getTable() await table.where("completed").equals(true).toArray() ``` -------------------------------- ### WebSocket Real-time Integration with TanStack Dexie DB Source: https://context7.com/himanshukumardutt094/tanstack-dexie-db-collection/llms.txt Integrates real-time server updates via WebSocket with local-only write utilities to avoid triggering user persistence handlers. This example uses Zod for schema validation and a custom codec for date serialization. It handles message creation, updates, deletions, and bulk operations received over WebSocket, and also includes a mechanism for users to send messages which triggers backend synchronization. ```typescript import { createCollection } from "@tanstack/react-db" import { dexieCollectionOptions } from "tanstack-dexie-db-collection" import { z } from "zod" const messageSchema = z.object({ id: z.string(), chatId: z.string(), senderId: z.string(), content: z.string(), timestamp: z.date(), status: z.enum(["sending", "sent", "delivered", "read"]), }) const messagesCollection = createCollection( dexieCollectionOptions({ id: "messages", schema: messageSchema, getKey: (message) => message.id, codec: { parse: (stored) => ({ ...stored, timestamp: new Date(stored.timestamp as string), }), serialize: (item) => ({ ...item, timestamp: item.timestamp.toISOString(), }), }, // Handler for USER sending messages (not triggered by local writes) onInsert: async ({ transaction }) => { const message = transaction.mutations[0].modified await fetch("/api/messages", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(message), }) // Update status after server confirms messagesCollection.update(message.id, (msg) => { msg.status = "sent" }) }, }) ) // WebSocket connection for real-time updates from other users const ws = new WebSocket("wss://api.example.com/messages") ws.onmessage = async (event) => { const update = JSON.parse(event.data) switch (update.type) { case "message:created": // Write directly to local storage (doesn't trigger onInsert) await messagesCollection.utils.insertLocally(update.message) break case "message:updated": await messagesCollection.utils.updateLocally( update.message.id, update.message ) break case "message:deleted": await messagesCollection.utils.deleteLocally(update.messageId) break case "messages:bulk": // Handle bulk updates efficiently await messagesCollection.utils.bulkInsertLocally(update.messages) break } } // User sends a message (triggers onInsert handler for backend sync) async function sendMessage(chatId: string, content: string) { const tx = messagesCollection.insert({ id: crypto.randomUUID(), chatId, senderId: getCurrentUserId(), content, timestamp: new Date(), status: "sending", }) await tx.isPersisted.promise } // Get current user ID helper function getCurrentUserId(): string { return "user-123" // Replace with actual user ID logic } ``` -------------------------------- ### Advanced Queries with Dexie Table Access in TanStack Source: https://context7.com/himanshukumardutt094/tanstack-dexie-db-collection/llms.txt Provides direct access to the underlying Dexie table for advanced queries and operations beyond standard collection methods. This example demonstrates filtering orders by status, paginating customer orders, counting orders by status, and retrieving high-value orders using Dexie's query API. ```typescript import { createCollection } from "@tanstack/react-db" import { dexieCollectionOptions } from "tanstack-dexie-db-collection" import { z } from "zod" const orderSchema = z.object({ id: z.string(), customerId: z.string(), status: z.enum(["pending", "processing", "shipped", "delivered"]), total: z.number(), createdAt: z.date(), }) const ordersCollection = createCollection( dexieCollectionOptions({ id: "orders", schema: orderSchema, getKey: (item) => item.id, }) ) // Advanced query using Dexie's query API async function getOrdersByStatus(status: string) { const table = ordersCollection.utils.getTable() // Use Dexie's where clause for efficient filtering const orders = await table .where("status") .equals(status) .toArray() return orders } // Get orders by customer with pagination async function getCustomerOrders(customerId: string, page: number = 0, pageSize: number = 20) { const table = ordersCollection.utils.getTable() const orders = await table .where("customerId") .equals(customerId) .offset(page * pageSize) .limit(pageSize) .toArray() return orders } // Count orders by status async function countOrdersByStatus() { const table = ordersCollection.utils.getTable() const pending = await table.where("status").equals("pending").count() const processing = await table.where("status").equals("processing").count() const shipped = await table.where("status").equals("shipped").count() const delivered = await table.where("status").equals("delivered").count() return { pending, processing, shipped, delivered } } // Complex query with filtering and sorting async function getHighValueOrders(minTotal: number) { const table = ordersCollection.utils.getTable() const allOrders = await table.toArray() return allOrders .filter(order => order.total >= minTotal) .sort((a, b) => b.total - a.total) .slice(0, 10) } ``` -------------------------------- ### SSE Integration for Real-time Notifications with TanStack Dexie DB Source: https://github.com/himanshukumardutt094/tanstack-dexie-db-collection/blob/master/EXAMPLES.md Connects to a Server-Sent Events (SSE) stream to receive real-time notifications. Upon receiving a 'notification' event, it inserts the data locally using `insertLocally` and displays a browser notification if granted. For 'notification:read' events, it updates the local record using `updateLocally`. The `onUpdate` handler is triggered when a user explicitly marks a notification as read. ```typescript const notificationsCollection = createCollection( dexieCollectionOptions({ id: "notifications", schema: notificationSchema, getKey: (notification) => notification.id, // Handler for user marking notifications as read onUpdate: async ({ transaction }) => { const mutation = transaction.mutations[0] await api.notifications.markRead(mutation.key) }, }) ) // SSE connection for real-time notifications const eventSource = new EventSource("/api/notifications/stream") eventSource.addEventListener("notification", async (event) => { const notification = JSON.parse(event.data) // Write directly without triggering handlers await notificationsCollection.utils.insertLocally(notification) // Show browser notification if (Notification.permission === "granted") { new Notification(notification.title, { body: notification.message, }) } }) eventSource.addEventListener("notification:read", async (event) => { const { id } = JSON.parse(event.data) await notificationsCollection.utils.updateLocally(id, { id, read: true, readAt: new Date(), }) }) // User marks notification as read (triggers onUpdate handler) async function markAsRead(notificationId: string) { await notificationsCollection.update(notificationId, (notification) => { notification.read = true notification.readAt = new Date() }) } ``` -------------------------------- ### TypeScript: Generate Sequential IDs with getNextId() Source: https://github.com/himanshukumardutt094/tanstack-dexie-db-collection/blob/master/EXAMPLES.md Demonstrates how to use `getNextId()` to generate sequential IDs for a 'todos' collection. This requires `autoIncrement: true` in the collection options and `z.number()` for the ID schema field. It covers single inserts, bulk inserts using `bulkInsertLocally`, and bootstrapping from server data, where `getNextId()` automatically initializes from the maximum existing ID. ```typescript import React, { useState } from "react" import { createCollection } from "@tanstack/db" import { useLiveQuery } from "@tanstack/react-db" import { dexieCollectionOptions } from "tanstack-dexie-db-collection" import { z } from "zod" const todoSchema = z.object({ id: z.number(), // Use z.number() for sequential IDs text: z.string(), completed: z.boolean(), createdAt: z.date(), }) const todosCollection = createCollection( dexieCollectionOptions({ id: "todos", schema: todoSchema, getKey: (item) => item.id, autoIncrement: true, // ⚠️ REQUIRED for getNextId() onInsert: async ({ transaction }) => { await api.todos.create(transaction.mutations[0].modified) }, }) ) // Single insert async function addTodo(text: string) { const id = await todosCollection.utils.getNextId() // Returns 1, 2, 3... await todosCollection.insert({ id, text, completed: false, createdAt: new Date(), }) } // Bulk insert async function bulkAddTodos() { const todos = [] for (let i = 0; i < 100; i++) { const id = await todosCollection.utils.getNextId() todos.push({ id, text: `Todo ${id}`, completed: false, createdAt: new Date() }) } // Use bulkInsertLocally for efficiency (doesn't trigger handlers) await todosCollection.utils.bulkInsertLocally(todos) } // Bootstrap from server async function bootstrapTodos() { const serverTodos = await fetch("/api/todos").then((r) => r.json()) // Example: [{ id: 1, ... }, { id: 2, ... }, ..., { id: 100, ... }] await todosCollection.utils.bulkInsertLocally(serverTodos) // After bootstrap, getNextId() auto-initializes from max ID // If server had IDs 1-100, next getNextId() returns 101 } // React component function TodoApp() { const { data: todos = [] } = useLiveQuery(todosCollection) const [text, setText] = useState("") const handleAdd = async () => { if (!text.trim()) return await addTodo(text.trim()) setText("") } return (

Todos

setText(e.target.value)} />
) } ``` -------------------------------- ### Update Collection Items with TanStack DB and Dexie.js Source: https://context7.com/himanshukumardutt094/tanstack-dexie-db-collection/llms.txt Demonstrates updating existing items in a TanStack DB collection, with changes automatically syncing to Dexie.js IndexedDB. This function supports partial updates, where only changed fields are synchronized, enhancing efficiency. It utilizes a callback function for in-place updates and shows how to update multiple fields. The example also includes a React component demonstrating live querying and updating of todo items. ```typescript import { createCollection } from "@tanstack/react-db" import { useLiveQuery } from "@tanstack/react-db" import { dexieCollectionOptions } from "tanstack-dexie-db-collection" import { z } from "zod" const todoSchema = z.object({ id: z.string(), text: z.string(), completed: z.boolean(), }) const todosCollection = createCollection( dexieCollectionOptions({ id: "todos", schema: todoSchema, getKey: (item) => item.id, rowUpdateMode: "partial", // Only updates changed fields }) ) // Update using callback function async function toggleTodo(id: string) { const tx = todosCollection.update(id, (todo) => { todo.completed = !todo.completed }) await tx.isPersisted.promise console.log(`Todo ${id} toggled`) } // Update multiple fields async function editTodo(id: string, newText: string) { const tx = todosCollection.update(id, (todo) => { todo.text = newText todo.lastModified = new Date() }) await tx.isPersisted.promise } // React component usage function TodoItem({ id }: { id: string }) { const { data: todos } = useLiveQuery(todosCollection) const todo = todos.find(t => t.id === id) return (
toggleTodo(id)} /> {todo?.text}
) } ``` -------------------------------- ### TanStack DB Live Query with Dexie Integration (TypeScript) Source: https://context7.com/himanshukumardutt094/tanstack-dexie-db-collection/llms.txt This snippet demonstrates setting up collections using Dexie persistence and defining live queries for reactive data fetching. It includes schema definitions with Zod, base collections for users and tasks, and a complex live query for active user tasks with joins and filtering. It also shows a simple live query for completed tasks. Dependencies include `@tanstack/react-db`, `tanstack-dexie-db-collection`, and `zod`. ```typescript import { createCollection, liveQueryCollectionOptions, eq, gt, } from "@tanstack/react-db" import { dexieCollectionOptions } from "tanstack-dexie-db-collection" import { useLiveQuery } from "@tanstack/react-db" import { z } from "zod" const userSchema = z.object({ id: z.string(), name: z.string(), isActive: z.boolean(), }) const taskSchema = z.object({ id: z.string(), title: z.string(), userId: z.string(), priority: z.number(), dueDate: z.date(), status: z.enum(["pending", "completed"]), }) // Base collections with Dexie persistence const usersCollection = createCollection( dexieCollectionOptions({ id: "users", schema: userSchema, getKey: (user) => user.id, }) ) const tasksCollection = createCollection( dexieCollectionOptions({ id: "tasks", schema: taskSchema, getKey: (task) => task.id, }) ) // Live query for high-priority tasks of active users const activeUserTasksCollection = createCollection( liveQueryCollectionOptions({ id: "active-user-tasks", startSync: true, query: (q) => q .from({ user: usersCollection }) .join({ task: tasksCollection }, ({ user, task }) => eq(user.id, task.userId) ) .where(({ user }) => eq(user.isActive, true)) .where(({ task }) => gt(task.priority, 2)) .where(({ task }) => eq(task.status, "pending")) .select(({ user, task }) => ({ taskId: task.id, taskTitle: task.title, userName: user.name, priority: task.priority, dueDate: task.dueDate, })) .orderBy(({ task }) => task.dueDate, "asc"), }) ) // React component that displays high-priority tasks function HighPriorityTasks() { const { data: tasks, isLoading } = useLiveQuery(activeUserTasksCollection) if (isLoading) { return
Loading tasks...
} return (

High Priority Tasks ({tasks.length})

{tasks.map((task) => (

{task.taskTitle}

Assigned to: {task.userName}

Priority: {task.priority}

Due: {task.dueDate.toLocaleDateString()}

))}
) } // Simple filtered live query const completedTasksCollection = createCollection( liveQueryCollectionOptions({ id: "completed-tasks", startSync: true, query: (q) => q .from({ task: tasksCollection }) .where(({ task }) => eq(task.status, "completed")), .orderBy(({ task }) => task.dueDate, "desc"), }) ) function CompletedTasksList() { const { data: tasks } = useLiveQuery(completedTasksCollection) return (

Completed Tasks

) } ``` -------------------------------- ### Bootstrap Data from Server (TypeScript) Source: https://context7.com/himanshukumardutt094/tanstack-dexie-db-collection/llms.txt Initializes the local task collection by fetching data from the backend API upon application startup. It merges server data with local data, using the server as the source of truth, and records the last sync time. Handles potential errors by falling back to local data if the server is unreachable. ```typescript // Bootstrap on app start async function initializeTasks() { try { console.log("Fetching tasks from server...") const response = await fetch("/api/tasks") const serverTasks = await response.json() // Merge with local data (server is source of truth) await tasksCollection.utils.bulkInsertLocally(serverTasks) localStorage.setItem("tasks-last-sync", new Date().toISOString()) console.log(`Bootstrapped ${serverTasks.length} tasks`) } catch (error) { console.log("Offline mode - using local data only") } } initializeTasks() ``` -------------------------------- ### Create a Basic TanStack DB Collection with Dexie Source: https://github.com/himanshukumardutt094/tanstack-dexie-db-collection/blob/master/README.md Demonstrates the basic usage of creating a TanStack DB collection that synchronizes with a Dexie.js table. It uses Zod for schema definition and specifies the collection ID, schema, and a key extraction function. ```typescript import { createCollection } from "@tanstack/react-db" import { dexieCollectionOptions } from "tanstack-dexie-db-collection" import { z } from "zod" const todoSchema = z.object({ id: z.string(), text: z.string(), completed: z.boolean(), }) const todosCollection = createCollection( dexieCollectionOptions({ id: "todos", schema: todoSchema, getKey: (item) => item.id, }) ) ``` -------------------------------- ### Advanced Live Query with Joins and Select (TypeScript) Source: https://github.com/himanshukumardutt094/tanstack-dexie-db-collection/blob/master/README.md This snippet demonstrates an advanced live query that joins two collections: 'users' and 'tasks'. It filters for active users with tasks having a priority greater than 2, selects specific fields from both, and orders the results by due date. This showcases complex querying capabilities and automatic UI updates. It requires `@tanstack/react-db`, `tanstack-dexie-db-collection`, and `zod`. ```typescript import { createCollection, liveQueryCollectionOptions, eq, gt, } from "@tanstack/react-db" import { z } from "zod" const userSchema = z.object({ id: z.string(), name: z.string(), isActive: z.boolean(), }) const taskSchema = z.object({ id: z.string(), title: z.string(), userId: z.string(), priority: z.number(), dueDate: z.date(), }) // Base collections const usersCollection = createCollection( dexieCollectionOptions({ id: "users", schema: userSchema, getKey: (user) => user.id, }) ) const tasksCollection = createCollection( dexieCollectionOptions({ id: "tasks", schema: taskSchema, getKey: (task) => task.id, }) ) // Live query for active user tasks export const activeUserTasksCollection = createCollection( liveQueryCollectionOptions({ id: "active-user-tasks", startSync: true, query: (q) => q .from({ user: usersCollection }) .join({ task: tasksCollection }, ({ user, task }) => eq(user.id, task.userId) ) .where(({ user }) => eq(user.isActive, true)) .where(({ task }) => gt(task.priority, 2)) .select(({ user, task }) => ({ taskId: task.id, taskTitle: task.title, userName: user.name, priority: task.priority, dueDate: task.dueDate, })) .orderBy(({ task }) => task.dueDate, "asc"), }) ) // Use in component function HighPriorityTasks() { const { data: tasks } = useLiveQuery(activeUserTasksCollection) return (

High Priority Tasks

{tasks.map((task) => (

{task.taskTitle}

Assigned to: {task.userName}

Priority: {task.priority}

Due: {task.dueDate}

))}
) } ``` -------------------------------- ### Basic Live Query for Pinned Notes (TypeScript) Source: https://github.com/himanshukumardutt094/tanstack-dexie-db-collection/blob/master/README.md This snippet demonstrates how to create a basic live query for notes that are pinned. It uses `createCollection` with `liveQueryCollectionOptions` to define a query that filters notes based on the `isPinned` field and orders them by `updatedAt`. The query automatically synchronizes and updates the UI when changes occur in the `notesCollection`. It requires `@tanstack/react-db`, `tanstack-dexie-db-collection`, and `zod`. ```typescript import { createCollection, liveQueryCollectionOptions, eq, } from "@tanstack/react-db" import { dexieCollectionOptions } from "tanstack-dexie-db-collection" import { z } from "zod" const noteSchema = z.object({ id: z.string(), title: z.string(), content: z.string(), isPinned: z.boolean(), updatedAt: z.date(), }) // Base collection with Dexie persistence const notesCollection = createCollection( dexieCollectionOptions({ id: "notes", schema: noteSchema, getKey: (note) => note.id, }) ) // Live query for pinned notes export const pinnedNotesCollection = createCollection( liveQueryCollectionOptions({ id: "pinned-notes-live", startSync: true, query: (q) => q .from({ note: notesCollection }) .where(({ note }) => eq(note.isPinned, true)) .orderBy(({ note }) => note.updatedAt, "desc"), }) ) // Use in React component function PinnedNotes() { const { data: pinnedNotes } = useLiveQuery(pinnedNotesCollection) return (
{pinnedNotes.map((note) => (
{note.title}
))}
) } ``` -------------------------------- ### Create TanStack Collection with Schema and Custom DB/Table Names Source: https://github.com/himanshukumardutt094/tanstack-dexie-db-collection/blob/master/README.md Illustrates how to configure a TanStack DB collection with a Zod schema, specifying custom database and table names for Dexie.js. This allows for more organized data storage in IndexedDB. ```typescript import { z } from "zod" const todoSchema = z.object({ id: z.string(), text: z.string(), completed: z.boolean(), }) const todosCollection = createCollection( dexieCollectionOptions({ id: "todos", schema: todoSchema, dbName: "my-app-db", tableName: "user_todos", getKey: (item) => item.id, }) ) ``` -------------------------------- ### Create Dexie Collection Options with TanStack DB Source: https://context7.com/himanshukumardutt094/tanstack-dexie-db-collection/llms.txt This function creates collection options for TanStack DB that integrate with Dexie.js persistence. It configures synchronization handlers and utility methods for managing data between an in-memory collection and an IndexedDB table. Requires `@tanstack/react-db`, `dexie-collection-options`, and `zod` for schema validation. It returns a configured collection object and demonstrates an optimistic insert operation, waiting for persistence confirmation. ```typescript import { createCollection } from "@tanstack/react-db" import { dexieCollectionOptions } from "tanstack-dexie-db-collection" import { z } from "zod" const todoSchema = z.object({ id: z.string(), text: z.string(), completed: z.boolean(), createdAt: z.date(), }) const todosCollection = createCollection( dexieCollectionOptions({ id: "todos", schema: todoSchema, getKey: (item) => item.id, dbName: "my-app-db", tableName: "todos", syncBatchSize: 1000, rowUpdateMode: "partial", ackTimeoutMs: 2000, awaitTimeoutMs: 10000, }) ) // Insert with optimistic update const tx = todosCollection.insert({ id: crypto.randomUUID(), text: "Buy groceries", completed: false, createdAt: new Date(), }) // Wait for persistence await tx.isPersisted.promise console.log("Todo saved to IndexedDB") ``` -------------------------------- ### Bulk Local Data Insertion in TypeScript Source: https://context7.com/himanshukumardutt094/tanstack-dexie-db-collection/llms.txt Inserts multiple items directly into IndexedDB and memory without triggering user-defined persistence handlers, ideal for bootstrapping from server data or performing bulk updates. This utility bypasses event handlers like `onInsert`, `onUpdate`, and `onDelete`. It depends on `@tanstack/react-db`, `tanstack-dexie-db-collection`, and `zod`. ```typescript import { createCollection } from "@tanstack/react-db" import { dexieCollectionOptions } from "tanstack-dexie-db-collection" import { z } from "zod" const productSchema = z.object({ id: z.string(), name: z.string(), price: z.number(), category: z.string(), inStock: z.boolean(), }) const productsCollection = createCollection( dexieCollectionOptions({ id: "products", schema: productSchema, getKey: (product) => product.id, // This handler is for user-initiated creates (NOT triggered by bulkInsertLocally) onInsert: async ({ transaction }) => { await fetch("/api/products", { method: "POST", body: JSON.stringify(transaction.mutations[0].modified), }) }, }) ) // Bootstrap data from server (does NOT trigger onInsert handler) async function bootstrapProducts() { try { const response = await fetch("/api/products") const serverProducts = await response.json() // Write all products locally without triggering backend sync await productsCollection.utils.bulkInsertLocally(serverProducts) localStorage.setItem("products-last-sync", new Date().toISOString()) console.log(`Bootstrapped ${serverProducts.length} products`) } catch (error) { console.error("Failed to bootstrap products:", error) } } // Incremental sync from server async function syncProducts() { const lastSync = localStorage.getItem("products-last-sync") const response = await fetch(`/api/products/changes?since=${lastSync}`) const changes = await response.json() // Apply server changes locally without triggering handlers if (changes.created.length > 0) { await productsCollection.utils.bulkInsertLocally(changes.created) } if (changes.updated.length > 0) { await productsCollection.utils.bulkUpdateLocally(changes.updated) } if (changes.deleted.length > 0) { await productsCollection.utils.bulkDeleteLocally(changes.deleted) } localStorage.setItem("products-last-sync", new Date().toISOString()) console.log(`Synced: ${changes.created.length} new, ${changes.updated.length} updated, ${changes.deleted.length} deleted`) } ```