Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Prisma TypedSQL #377

Open
wants to merge 20 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 9 additions & 5 deletions apps/backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@
"build-self-host-seed-script": "tsup --config prisma/tsup.config.ts",
"analyze-bundle": "ANALYZE_BUNDLE=1 pnpm run build",
"start": "next start --port 8102",
"codegen-prisma": "pnpm run prisma generate",
"codegen-prisma:watch": "pnpm run prisma generate --watch",
"codegen": "pnpm run with-env bash -c 'if [ \"$STACK_ACCELERATE_ENABLED\" = \"true\" ]; then pnpm run prisma generate --no-engine && pnpm run generate-docs; else pnpm run codegen-prisma && pnpm run generate-docs; fi'",
"codegen-prisma": "concurrently -k -s first \"tsx scripts/mock-postgres.mjs\" \"node -e \\\"setTimeout(() => process.exit(0), 2000)\\\" && cross-env STACK_DATABASE_CONNECTION_STRING=\\\"postgres://postgres@localhost:8118/postgres?pgbouncer=true&connection_limit=1\\\" STACK_DIRECT_DATABASE_CONNECTION_STRING=\\\"postgres://postgres@localhost:8118/postgres?connection_limit=1\\\" STACK_SEED_INTERNAL_PROJECT_PUBLISHABLE_CLIENT_KEY=\\\"test_key\\\" STACK_SEED_INTERNAL_PROJECT_SECRET_SERVER_KEY=\\\"test_secret\\\" STACK_SEED_INTERNAL_PROJECT_SUPER_SECRET_ADMIN_KEY=\\\"test_admin\\\" sh -c \\\"pnpm run prisma migrate reset --force && pnpm run prisma generate --sql\\\"\"",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we put this into a JS file instead (you can merge it with mock-postgres.mjs)

"codegen-prisma:watch": "pnpm run codegen-prisma && chokidar \"prisma/**/*\" -c \"pnpm run codegen-prisma\"",
"codegen": "pnpm run with-env bash -c 'if [ \"$STACK_ACCELERATE_ENABLED\" = \"true\" ]; then pnpm run prisma generate --sql --no-engine && pnpm run generate-docs; else pnpm run codegen-prisma && pnpm run generate-docs; fi'",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this change? Why prisma generate --sql when that environment variable is set, but pnpm run codegen-prisma otherwise?

"codegen:watch": "concurrently -n \"prisma,docs\" -k \"pnpm run codegen-prisma:watch\" \"pnpm run watch-docs\"",
"psql-inner": "psql $STACK_DATABASE_CONNECTION_STRING",
"psql": "pnpm run with-env pnpm run psql-inner",
Expand All @@ -31,6 +31,7 @@
"seed": "pnpm run db-seed-script"
},
"dependencies": {
"@electric-sql/pglite": "0.2.7",
"@next/bundle-analyzer": "15.0.3",
"@node-oauth/oauth2-server": "^5.1.0",
"@opentelemetry/api": "^1.9.0",
Expand All @@ -44,7 +45,7 @@
"@opentelemetry/sdk-trace-base": "^1.26.0",
"@opentelemetry/sdk-trace-node": "^1.26.0",
"@opentelemetry/semantic-conventions": "^1.27.0",
"@prisma/client": "^6.0.1",
"@prisma/client": "^6.1.0",
"@prisma/extension-accelerate": "^1.2.1",
"@prisma/instrumentation": "^5.19.1",
"@sentry/nextjs": "^8.40.0",
Expand All @@ -55,6 +56,7 @@
"@vercel/functions": "^1.4.2",
"@vercel/otel": "^1.10.0",
"bcrypt": "^5.1.1",
"chokidar-cli": "^3.0.0",
"dotenv-cli": "^7.3.0",
"jose": "^5.2.2",
"next": "15.0.3",
Expand All @@ -63,6 +65,7 @@
"openid-client": "^5.6.4",
"oslo": "^1.2.1",
"pg": "^8.11.3",
"pg-gateway": "0.3.0-beta.3",
"posthog-node": "^4.1.0",
"react": "^19.0.0",
"react-dom": "^19.0.0",
Expand All @@ -82,9 +85,10 @@
"@types/react-dom": "^19.0.0",
"@types/semver": "^7.5.8",
"concurrently": "^8.2.2",
"cross-env": "^7.0.3",
"glob": "^10.4.1",
"import-in-the-middle": "^1.12.0",
"prisma": "^6.0.1",
"prisma": "^6.1.0",
"require-in-the-middle": "^7.4.0",
"rimraf": "^5.0.5",
"tsup": "^8.3.0",
Expand Down
2 changes: 1 addition & 1 deletion apps/backend/prisma/schema.prisma
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
generator client {
provider = "prisma-client-js"
previewFeatures = ["tracing", "relationJoins"]
previewFeatures = ["typedSql", "relationJoins"]
}

datasource db {
Expand Down
4 changes: 4 additions & 0 deletions apps/backend/prisma/sql/getUsersLastActiveAtMillis.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
SELECT data->>'userId' as "userId", MAX("createdAt") as "lastActiveAt"
FROM "Event"
WHERE data->>'userId' = ANY($1)
GROUP BY data->>'userId'
50 changes: 50 additions & 0 deletions apps/backend/scripts/mock-postgres.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { PGlite } from '@electric-sql/pglite';
import net from 'node:net';
import { fromNodeSocket } from 'pg-gateway/node';

const db = new PGlite();

const server = net.createServer(async (socket) => {
let activeDb;

console.info(`Client connected: ${socket.remoteAddress}:${socket.remotePort}`)
await fromNodeSocket(socket, {
serverVersion: '16.3',

auth: {
// No password required
method: 'trust',
},

async onStartup({ clientParams }) {
console.info(`Connecting client to ${clientParams?.database}`)
// If the DB is the Prisma shadow DB, create a temp in-memory instance
if (clientParams?.database === 'prisma-shadow') {
activeDb = new PGlite()
} else {
activeDb = db
}

// Wait for PGlite to be ready before further processing
await activeDb.waitReady
},

async onMessage(data, { isAuthenticated }) {
if (!isAuthenticated) {
// currently we have no authentication, but let's keep it for the future
return
}

// Forward raw message to PGlite and send response to client
return await activeDb.execProtocolRaw(data)
},
})

socket.on('end', () => {
console.info('Client disconnected')
})
})

server.listen(8118, () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you document this in the dev launchpad?

console.info('Postgres server listening on port 8118')
})
4 changes: 4 additions & 0 deletions apps/backend/sentry.client.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ Sentry.init({

enabled: process.env.NODE_ENV !== "development" && !process.env.CI,

// Sentry and Prisma are not compatible with the new tracing. https://github.com/prisma/prisma/issues/25885
// TODO: Remove this once sentry fixes the issue.
tracesSampleRate: 0,

// You can remove this option if you're not planning to use the Sentry Session Replay feature:
integrations: [
Sentry.replayIntegration({
Expand Down
10 changes: 3 additions & 7 deletions apps/backend/src/app/api/v1/users/crud.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { prismaClient, retryTransaction } from "@/prisma-client";
import { createCrudHandlers } from "@/route-handlers/crud-handler";
import { runAsynchronouslyAndWaitUntil } from "@/utils/vercel";
import { BooleanTrue, Prisma } from "@prisma/client";
import { getUsersLastActiveAtMillis as getUsersLastActiveAtMillisSql } from "@prisma/client/sql";
import { KnownErrors } from "@stackframe/stack-shared";
import { currentUserCrud } from "@stackframe/stack-shared/dist/interface/crud/current-user";
import { UsersCrud, usersCrud } from "@stackframe/stack-shared/dist/interface/crud/users";
Expand Down Expand Up @@ -228,16 +229,11 @@ export const getUsersLastActiveAtMillis = async (userIds: string[], fallbackTo:
return [];
}

const events = await prismaClient.$queryRaw<Array<{ userId: string, lastActiveAt: Date }>>`
SELECT data->>'userId' as "userId", MAX("createdAt") as "lastActiveAt"
FROM "Event"
WHERE data->>'userId' = ANY(${Prisma.sql`ARRAY[${Prisma.join(userIds)}]`})
GROUP BY data->>'userId'
`;
const events = await prismaClient.$queryRawTyped(getUsersLastActiveAtMillisSql(userIds));

return userIds.map((userId, index) => {
const event = events.find(e => e.userId === userId);
return event ? event.lastActiveAt.getTime() : (
return event && event.lastActiveAt ? event.lastActiveAt.getTime() : (
typeof fallbackTo[index] === "number" ? (fallbackTo[index] as number) : (fallbackTo[index] as Date).getTime()
);
});
Expand Down
51 changes: 0 additions & 51 deletions apps/backend/src/instrumentation.ts

This file was deleted.

Loading
Loading