From 535e69ef88d9e4cffeb616a7e38951e108fd944e Mon Sep 17 00:00:00 2001 From: Ivan Vasilov Date: Tue, 3 Mar 2026 15:06:06 +0100 Subject: [PATCH] Update the tanstack db block. --- .../registry/tanstack-db/_generators/db.ts | 10 +- .../app/api/registry/tanstack-db/route.ts | 6 +- .../content/docs/nextjs/tanstack-db.mdx | 124 ++++++++++-------- 3 files changed, 80 insertions(+), 60 deletions(-) diff --git a/apps/ui-library/app/api/registry/tanstack-db/_generators/db.ts b/apps/ui-library/app/api/registry/tanstack-db/_generators/db.ts index 575168b1912..3ef8c99a18e 100644 --- a/apps/ui-library/app/api/registry/tanstack-db/_generators/db.ts +++ b/apps/ui-library/app/api/registry/tanstack-db/_generators/db.ts @@ -6,12 +6,13 @@ export function generateDbContent(definitions: Record const tableNames = Object.keys(definitions).filter((name) => !name.startsWith('_')) const lines: string[] = [ - "import { createSupabaseCollection } from 'supabase-collection'", + "import { supabaseCollectionOptions} from 'supabase-collection'", "import { createClient } from '@/lib/supabase/client'", "import { getQueryClient } from '@/lib/query-client'", 'import {', ...tableNames.map((name) => ` ${toCamelCase(name)}Schema,`), "} from './schemas'", + "import { createCollection } from '@tanstack/db'", '', 'const supabase = createClient()', '', @@ -49,14 +50,15 @@ export function generateDbContent(definitions: Record whereFn = '(query, item) => query' } - lines.push(`export const ${collectionName} = createSupabaseCollection({`) + lines.push(`export const ${collectionName} = createCollection(supabaseCollectionOptions({`) lines.push(` tableName: '${tableName}',`) lines.push(` getKey: ${getKeyFn},`) lines.push(` where: ${whereFn},`) lines.push(` schema: ${schemaName},`) + lines.push(` realtime: true,`) lines.push(' queryClient: getQueryClient(),') - lines.push(' supabase: supabase as any,') - lines.push('})') + lines.push(' supabase: supabase,') + lines.push('}))') lines.push('') } diff --git a/apps/ui-library/app/api/registry/tanstack-db/route.ts b/apps/ui-library/app/api/registry/tanstack-db/route.ts index 1f701c6481a..6f425891a4b 100644 --- a/apps/ui-library/app/api/registry/tanstack-db/route.ts +++ b/apps/ui-library/app/api/registry/tanstack-db/route.ts @@ -1,5 +1,6 @@ -import { NextRequest, NextResponse } from 'next/server' +import fs from 'fs/promises' import path from 'path' +import { NextRequest, NextResponse } from 'next/server' import { RegistryItem } from 'shadcn/schema' import { @@ -11,7 +12,6 @@ import { } from './_generators' import { OpenAPISchema, RegistryFile } from './types' import { toSingular } from './utils' -import fs from 'fs/promises' // Read the base registry JSON async function readBaseRegistry(): Promise { @@ -64,7 +64,7 @@ export async function GET(request: NextRequest) { // Get the first table for the example CRUD page const tableNames = Object.keys(openApiSpec.definitions).filter((name) => !name.startsWith('_')) // TODO: remove this once we have a way to select the table - const firstTableName = 'persons' + const firstTableName = tableNames.length > 0 ? tableNames[0] : null const firstTableDefinition = firstTableName ? openApiSpec.definitions[firstTableName] : null // Read the base registry JSON diff --git a/apps/ui-library/content/docs/nextjs/tanstack-db.mdx b/apps/ui-library/content/docs/nextjs/tanstack-db.mdx index bc78ae9f2f0..9e5c546da1a 100644 --- a/apps/ui-library/content/docs/nextjs/tanstack-db.mdx +++ b/apps/ui-library/content/docs/nextjs/tanstack-db.mdx @@ -1,9 +1,9 @@ --- title: TanStack DB -description: Type-safe database collections with TanStack Query and Supabase +description: Local-first, reactive collections backed by Supabase --- -This block provides TanStack Query integration with Supabase collections for type-safe database operations. It generates Zod schemas and collection configurations based on your database schema. +A [TanStack/db](https://tanstack.com/db/latest) collection backed by [Supabase](https://supabase.com/). It wires up Supabase PostgREST queries, mutations, and real-time subscriptions so you get a reactive state that stays in sync with your Postgres database. ## Installation @@ -20,15 +20,14 @@ Enter your Supabase project credentials to generate a personalized installation This block installs the following files: -| File | Description | -| ---------------------------- | ---------------------------------------------------- | -| `lib/schemas.ts` | Zod schemas for all your database tables | -| `lib/db.ts` | Supabase collections for type-safe CRUD operations | -| `lib/query-client.ts` | TanStack Query client configuration with SSR support | -| `app/providers.tsx` | React Query provider component | -| `lib/supabase/client.ts` | Browser Supabase client | -| `lib/supabase/server.ts` | Server-side Supabase client | -| `lib/supabase/middleware.ts` | Middleware for session handling | +| File | Description | +| ---------------------------- | -------------------------------------------------- | +| `lib/schemas.ts` | Zod schemas for all your database tables | +| `lib/db.ts` | Supabase collections for type-safe CRUD operations | +| `lib/supabase/client.ts` | Browser Supabase client | +| `lib/supabase/server.ts` | Server-side Supabase client | +| `lib/supabase/middleware.ts` | Middleware for session handling | +| `app/providers.tsx` | Provider component for TanStack DB | ## Getting started @@ -59,62 +58,81 @@ export default function RootLayout({ children }: { children: React.ReactNode }) } ``` -### Using collections in your components +### Querying collections -Each table in your database gets a corresponding collection. Here's how to use them: +Each table in your database gets a corresponding collection. Query them with `useQuery` from `@tanstack/react-db`: ```tsx 'use client' -import { usersCollection } from '@/lib/db' +import { useQuery } from '@tanstack/react-db' +import { todos } from '@/lib/db' -export function UserList() { - const { data: users, isLoading } = usersCollection.useList() +export function TodoList() { + // all rows + const allTodos = useQuery(todos) - if (isLoading) return
Loading...
- - return
    {users?.map((user) =>
  • {user.name}
  • )}
-} -``` - -### Available collection methods - -Each collection provides the following methods: - -| Method | Description | -| ------------- | -------------------------- | -| `useList()` | Fetch all items | -| `useGet(key)` | Fetch a single item by key | -| `useCreate()` | Create a new item | -| `useUpdate()` | Update an existing item | -| `useDelete()` | Delete an item | - -### Server-side data fetching - -For server components, you can prefetch data using the query client: - -```tsx -import { HydrationBoundary, dehydrate } from '@tanstack/react-query' - -import { usersCollection } from '@/lib/db' -import { getQueryClient } from '@/lib/query-client' - -export default async function UsersPage() { - const queryClient = getQueryClient() - - // Prefetch users on the server - await queryClient.prefetchQuery(usersCollection.listQueryOptions()) + // with a filter + const done = useQuery(todos, { + where: { completed: { eq: true } }, + orderBy: { created_at: 'desc' }, + limit: 10, + }) return ( - - - +
    + {allTodos.map((todo) => ( +
  • {todo.title}
  • + ))} +
) } ``` +### Joins + +TanStack/db supports live joins across collections: + +```tsx +import { useQuery } from '@tanstack/react-db' +import { posts, users } from '@/lib/db' + +const postsWithAuthor = useQuery(posts, { + with: { + author: { + collection: users, + field: 'author_id', + references: 'id', + }, + }, +}) +// postsWithAuthor[0].author.name +``` + +### Mutations + +Mutations are **optimistic** — the local collection updates immediately and syncs to Supabase in the background. If the server rejects a change it rolls back automatically. + +#### Insert + +```ts +todos.insert({ title: 'Buy milk', completed: false }) +``` + +#### Update + +```ts +todos.update(todo, { completed: true }) +``` + +#### Delete + +```ts +todos.delete(todo) +``` + ## Further reading -- [TanStack Query documentation](https://tanstack.com/query/latest) +- [TanStack DB documentation](https://tanstack.com/db/latest) - [Supabase JavaScript client](https://supabase.com/docs/reference/javascript) - [Generating TypeScript types](https://supabase.com/docs/guides/api/rest/generating-types)