-
Notifications
You must be signed in to change notification settings - Fork 76
feat(prisma): prisma postgres resources #1053
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
base: main
Are you sure you want to change the base?
Conversation
/** | ||
* Minimal client for the Prisma Postgres Management API | ||
*/ | ||
export class PrismaPostgresApi { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We've been trying to move away from hand-coding the API clients.
Does Prisma have a generated TypeScript SDK for its control plane?
@john-royal has been standardizing our API generation with hey-api. @john-royal, maybe you can take a look at their API spec and see how well it generates.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't have TypeScript SDK. hey-api looks really interesting.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be an option to use the hand-coded API client initially, and switch to a prisma provided SDK later?
commit: |
This is very exciting @sorenbs. Great job. Does Prisma Postgres support branching? I found this doc which indicates it does: https://www.prisma.io/blog/introducing-platform-environments One feature to make sure we nail here would be CI/CD (see https://alchemy.run/guides/ci/). The ideal workflow is to have each PR deploy a branched copy of the infrastructure. It's not always possible depending on the service, but Planetscale and Neon each have branching capability exposed as Alchemy Resources that slot in nicely to Alchemy's CI/CD. |
We don't support Branching natively yet, but we have the ability to create a database from a snapshot. Currently a snapshot can only be created from the Console UI - I will speak to the team about getting it enabled in the API. I believe that should enable a complete CI/CD workflow as you describe. |
That's similar to what we do for D1. Downside of this approach is cost, I'm assuming? Since it is a total copy? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
haven't looked at the code but read through the docs written here.
Its a good start, but some of the default behavior seems to differ from what we do for alchemy usually.
We'd prefer if we could align here but if there are good reasons for it we're open to discussion
const project = await Project("project", { | ||
name: "prisma-app", | ||
region: "us-east-1", | ||
createDatabase: false, | ||
}); | ||
|
||
const database = await Database("database", { | ||
project, | ||
name: "primary", | ||
region: "us-east-1", | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is it possible to make the region
on database optional and just do project.region
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The way the region selection works is this:
- projects do not have a concept of region
- when you create a project and specify createDatabase: true, then you need to specify the region. You will then get a database in that region
- When you create a database in a project, you need to specify the region
To simplify things, what we could do in Alchemy is hide the ability to automatically create a database with the project. That would eliminate the region
and createDatabase
flags from Project creation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To simplify things, what we could do in Alchemy is hide the ability to automatically create a database with the project. That would eliminate the region and createDatabase flags from Project creation.
This seems like the right approach. Centralize database config on the Database resource rather than conflate them.
## Rotate If Missing | ||
|
||
If the underlying connection is deleted, rerunning the resource automatically creates a replacement with a fresh secret: | ||
|
||
```ts | ||
await DatabaseConnection("application", { | ||
database, | ||
name: "application", | ||
}); | ||
``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel like this would work better as a tip
on the create a connection section since you're explaining how the resource works not showing any unique configuration.
import { Database } from "alchemy/prisma/postgres"; | ||
|
||
const database = await Database("primary", { | ||
project, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
where does project come from. its a bit ambiguous what project is here. Can we give an example with the simplest possible project?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch - thank you!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I noticed that Planetscale refers to orgs and databases by id instead of objects. Is that the preferred approach?
const devBranch = await Branch("feature-123", {
name: "feature-123",
organizationId: "my-org",
databaseName: "my-database",
parentBranch: "main",
isProduction: false,
});
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I noticed that Planetscale refers to orgs and databases by id instead of objects. Is that the preferred approach?
No, but great question.
The preferred approach is to drop the Id
suffix and use a union type. For example: organization: string | Organization
.
The planetscale should be:
const devBranch = await Branch("feature-123", {
name: "feature-123",
organization: "my-org" | MyOrg,
database: "my-database" | MyDatabase,
parentBranch: "main",
isProduction: false,
});
@Mkassabov we should make these changes in a separate PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@sorenbs
better example is our new clickhouse provider:
alchemy/alchemy/src/clickhouse/service.ts
Lines 390 to 395 in 80ef082
const organizationId = | |
typeof props.organization === "string" | |
? await OrganizationRef(props.organization) | |
.then((organization) => organization.id!) | |
.catch(() => props.organization as string) | |
: props.organization.id!; |
const connection = await DatabaseConnection("application", { | ||
database, | ||
name: "application", | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
where does database come from. its a bit ambiguous what project is here. Can we give an example with the simplest possible database?
const database = await Database("isolated", { | ||
project, | ||
name: "isolated", | ||
region: "eu-central-1", | ||
adopt: false, | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we generally have adopt: false and you have to specify it manually or run with the --adopt
flag. can we keep that behavior consistent with the rest of alchemy here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. I was unsure what to do, so thanks for calling it out.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inside a resource you need to check props.adopt ?? this.scope.adopt
.
this.scope.adopt
is how we apply blanket adopt across an app or scope.
|
||
## Promote to Default Database | ||
|
||
Set `isDefault` to true to promote the database when the workspace allows it: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this makes me hesitant since it could be isDefault
on multiple databases but only one of them promotes. It dilutes alchemy as being the sense of truth.
could we do something like canPromoteToDefault
or at least an output property to show if something is the default?
name: "fresh-project", | ||
region: "eu-central-1", | ||
createDatabase: false, | ||
adopt: false, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
adopt should be false by default
Yes, storage costs double. In you experience, is it a common use case to create a branch with the full production data? We haven't heard much request for this. |
👍
We are currently fixing this by 10x-ing the db limits. So Free will give you 50 databases, and the $10 plan will include 100 dbs. As soon as a PR is closed, the database can be deleted and freed up for the next PR. |
Nice, sounds good. 100 databases is high enough to not worry about it. |
export const connection = await DatabaseConnection("connection", { | ||
database, | ||
name: "application", | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we also use hyperdrive ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hyperdrive and bind to a Worker would be killer demo
No description provided.