Skip to content

Commit 8929bfe

Browse files
committed
feat: add prisma plugin to start
1 parent fe882bc commit 8929bfe

File tree

10 files changed

+346
-7
lines changed

10 files changed

+346
-7
lines changed

examples/react/start/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,5 @@ count.txt
1010
.output
1111
.vinxi
1212
todos.json
13+
14+
/generated/prisma

examples/react/start/package.json

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,16 @@
66
"dev": "vite dev --port 3000",
77
"start": "node .output/server/index.mjs",
88
"serve": "vite preview",
9-
"test": "vitest run"
9+
"test": "vitest run",
10+
"db:migrate": "prisma migrate dev --name init",
11+
"db:reset": " prisma migrate reset",
12+
"db:gen": "prisma generate",
13+
"db:studio": "prisma studio"
1014
},
1115
"dependencies": {
16+
"@prisma/client": "^6.13.0",
17+
"@prisma/extension-accelerate": "^2.0.2",
18+
"@prisma/studio-core": "^0.5.1",
1219
"@tailwindcss/vite": "^4.0.6",
1320
"@tanstack/react-devtools": "^0.0.0",
1421
"@tanstack/react-query": "^5.83.0",
@@ -18,6 +25,7 @@
1825
"@tanstack/react-router-with-query": "^1.130.2",
1926
"@tanstack/react-start": "^1.130.2",
2027
"@tanstack/router-plugin": "^1.121.2",
28+
"prisma": "^6.13.0",
2129
"react": "^19.1.0",
2230
"react-dom": "^19.1.0",
2331
"tailwindcss": "^4.0.6",
@@ -35,4 +43,4 @@
3543
"vitest": "^3.1.2",
3644
"web-vitals": "^4.2.4"
3745
}
38-
}
46+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
-- CreateTable
2+
CREATE TABLE "public"."User" (
3+
"id" TEXT NOT NULL,
4+
"name" TEXT,
5+
"email" TEXT,
6+
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
7+
"updatedAt" TIMESTAMP(3) NOT NULL,
8+
9+
CONSTRAINT "User_pkey" PRIMARY KEY ("id")
10+
);
11+
12+
-- CreateTable
13+
CREATE TABLE "public"."Post" (
14+
"id" TEXT NOT NULL,
15+
"title" TEXT NOT NULL,
16+
"content" TEXT,
17+
"published" BOOLEAN NOT NULL DEFAULT false,
18+
"authorId" TEXT,
19+
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
20+
"updatedAt" TIMESTAMP(3) NOT NULL,
21+
22+
CONSTRAINT "Post_pkey" PRIMARY KEY ("id")
23+
);
24+
25+
-- CreateIndex
26+
CREATE UNIQUE INDEX "User_email_key" ON "public"."User"("email");
27+
28+
-- AddForeignKey
29+
ALTER TABLE "public"."Post" ADD CONSTRAINT "Post_authorId_fkey" FOREIGN KEY ("authorId") REFERENCES "public"."User"("id") ON DELETE SET NULL ON UPDATE CASCADE;
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Please do not edit this file manually
2+
# It should be added in your version-control system (e.g., Git)
3+
provider = "postgresql"
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// This is your Prisma schema file,
2+
// learn more about it in the docs: https://pris.ly/d/prisma-schema
3+
4+
// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?
5+
// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init
6+
7+
generator client {
8+
provider = "prisma-client-js"
9+
output = "../generated/prisma"
10+
}
11+
12+
datasource db {
13+
provider = "postgresql"
14+
url = env("DATABASE_URL")
15+
}
16+
17+
model User {
18+
id String @id @default(cuid())
19+
name String?
20+
email String? @unique
21+
createdAt DateTime @default(now())
22+
updatedAt DateTime @updatedAt
23+
24+
Post Post[]
25+
}
26+
27+
model Post {
28+
id String @id @default(cuid())
29+
title String
30+
content String?
31+
published Boolean @default(false)
32+
authorId String?
33+
author User? @relation(fields: [authorId], references: [id])
34+
createdAt DateTime @default(now())
35+
updatedAt DateTime @updatedAt
36+
}

examples/react/start/src/components/devtools.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
22
import { ReactQueryDevtoolsPanel } from '@tanstack/react-query-devtools'
33
import { TanStackRouterDevtoolsPanel } from '@tanstack/react-router-devtools'
44
import { Devtools } from '@tanstack/react-devtools'
5-
import { createRouter } from '@/router'
5+
import { StudioPlugin } from './prisma-plugin'
66

77
const queryClient = new QueryClient()
88

@@ -18,7 +18,11 @@ export default function DevtoolsExample() {
1818
},
1919
{
2020
name: 'Tanstack Router',
21-
render: <TanStackRouterDevtoolsPanel router={createRouter()} />,
21+
render: <TanStackRouterDevtoolsPanel />,
22+
},
23+
{
24+
name: 'Prisma Studio',
25+
render: <StudioPlugin />,
2226
},
2327
]}
2428
/>
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { Studio } from '@prisma/studio-core/ui'
2+
import { createPostgresAdapter } from '@prisma/studio-core/data/postgres-core'
3+
import { createStudioBFFClient } from '@prisma/studio-core/data/bff'
4+
import { useMemo } from 'react'
5+
6+
import '@prisma/studio-core/ui/index.css'
7+
8+
export function StudioPlugin() {
9+
const adapter = useMemo(() => {
10+
// 1. Create a client that points to your backend endpoint
11+
const executor = createStudioBFFClient({
12+
url: 'http://localhost:3000/studio',
13+
})
14+
15+
// 2. Create a Postgres adapter with the executor
16+
const adapter = createPostgresAdapter({ executor })
17+
return adapter
18+
}, [])
19+
20+
return <Studio adapter={adapter} />
21+
}

examples/react/start/src/routeTree.gen.ts

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { Route as rootRouteImport } from './routes/__root'
1414
import { Route as IndexRouteImport } from './routes/index'
1515
import { Route as DemoStartServerFuncsRouteImport } from './routes/demo.start.server-funcs'
1616
import { Route as DemoStartApiRequestRouteImport } from './routes/demo.start.api-request'
17+
import { ServerRoute as StudioServerRouteImport } from './routes/studio'
1718
import { ServerRoute as ApiDemoNamesServerRouteImport } from './routes/api.demo-names'
1819

1920
const rootServerRouteImport = createServerRootRoute()
@@ -33,6 +34,11 @@ const DemoStartApiRequestRoute = DemoStartApiRequestRouteImport.update({
3334
path: '/demo/start/api-request',
3435
getParentRoute: () => rootRouteImport,
3536
} as any)
37+
const StudioServerRoute = StudioServerRouteImport.update({
38+
id: '/studio',
39+
path: '/studio',
40+
getParentRoute: () => rootServerRouteImport,
41+
} as any)
3642
const ApiDemoNamesServerRoute = ApiDemoNamesServerRouteImport.update({
3743
id: '/api/demo-names',
3844
path: '/api/demo-names',
@@ -69,24 +75,28 @@ export interface RootRouteChildren {
6975
DemoStartServerFuncsRoute: typeof DemoStartServerFuncsRoute
7076
}
7177
export interface FileServerRoutesByFullPath {
78+
'/studio': typeof StudioServerRoute
7279
'/api/demo-names': typeof ApiDemoNamesServerRoute
7380
}
7481
export interface FileServerRoutesByTo {
82+
'/studio': typeof StudioServerRoute
7583
'/api/demo-names': typeof ApiDemoNamesServerRoute
7684
}
7785
export interface FileServerRoutesById {
7886
__root__: typeof rootServerRouteImport
87+
'/studio': typeof StudioServerRoute
7988
'/api/demo-names': typeof ApiDemoNamesServerRoute
8089
}
8190
export interface FileServerRouteTypes {
8291
fileServerRoutesByFullPath: FileServerRoutesByFullPath
83-
fullPaths: '/api/demo-names'
92+
fullPaths: '/studio' | '/api/demo-names'
8493
fileServerRoutesByTo: FileServerRoutesByTo
85-
to: '/api/demo-names'
86-
id: '__root__' | '/api/demo-names'
94+
to: '/studio' | '/api/demo-names'
95+
id: '__root__' | '/studio' | '/api/demo-names'
8796
fileServerRoutesById: FileServerRoutesById
8897
}
8998
export interface RootServerRouteChildren {
99+
StudioServerRoute: typeof StudioServerRoute
90100
ApiDemoNamesServerRoute: typeof ApiDemoNamesServerRoute
91101
}
92102

@@ -117,6 +127,13 @@ declare module '@tanstack/react-router' {
117127
}
118128
declare module '@tanstack/react-start/server' {
119129
interface ServerFileRoutesByPath {
130+
'/studio': {
131+
id: '/studio'
132+
path: '/studio'
133+
fullPath: '/studio'
134+
preLoaderRoute: typeof StudioServerRouteImport
135+
parentRoute: typeof rootServerRouteImport
136+
}
120137
'/api/demo-names': {
121138
id: '/api/demo-names'
122139
path: '/api/demo-names'
@@ -136,6 +153,7 @@ export const routeTree = rootRouteImport
136153
._addFileChildren(rootRouteChildren)
137154
._addFileTypes<FileRouteTypes>()
138155
const rootServerRouteChildren: RootServerRouteChildren = {
156+
StudioServerRoute: StudioServerRoute,
139157
ApiDemoNamesServerRoute: ApiDemoNamesServerRoute,
140158
}
141159
export const serverRouteTree = rootServerRouteImport
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { createServerFileRoute } from '@tanstack/react-start/server'
2+
import { createPrismaPostgresHttpClient } from '@prisma/studio-core/data/ppg'
3+
import { serializeError } from '@prisma/studio-core/data/bff'
4+
5+
export const ServerRoute = createServerFileRoute('/studio').methods({
6+
POST: async ({ request }) => {
7+
const { query } = await request.json()
8+
// 2. Read DB URL from env vars
9+
const url = process.env.DATABASE_URL!
10+
11+
// 3. Execute the query against Prisma Postgres
12+
const [error, results] = await createPrismaPostgresHttpClient({
13+
url,
14+
}).execute(query)
15+
16+
if (error) {
17+
console.log(error)
18+
return new Response(JSON.stringify([serializeError(error)]), {
19+
status: 500,
20+
headers: {
21+
'Content-Type': 'application/json',
22+
},
23+
})
24+
}
25+
return new Response(JSON.stringify([null, results]), {
26+
status: 200,
27+
headers: {
28+
'Content-Type': 'application/json',
29+
},
30+
})
31+
},
32+
})

0 commit comments

Comments
 (0)