feat(db-vercel-postgres): allow to use a local database using pg instead of @vercel/postgres (#9771)

### What?
This PR allows you to use a local database when using
`vercelPostgresAdapter`. This adapter doesn't work with them because it
requires an SSL connection and Neon's WS proxy. Instead we fallback to
using pool from `pg` if `hostname` is either `127.0.0.1` or `localhost`.

If you still want to use `@vercel/postgres` even locally you can pass
`disableUsePgForLocalDatabase: true` here and you'd have to spin up the
DB with a special Neon's Docker Compose setup -
https://vercel.com/docs/storage/vercel-postgres/local-development#option-2:-local-postgres-instance-with-docker

### Why?
Forcing people to use a cloud database locally isn't great. Not only
they are slow but also paid.

---------

Co-authored-by: Dan Ribbens <dan.ribbens@gmail.com>
This commit is contained in:
Sasha
2024-12-16 23:55:08 +02:00
committed by GitHub
parent ed44ec0a9c
commit 41167bfbeb
4 changed files with 37 additions and 2 deletions

View File

@@ -50,6 +50,11 @@ export default buildConfig({
})
```
<Banner type="info">
<strong>Note:</strong>
If when using `vercelPostgresAdapter` your `process.env.POSTGRES_URL` or `pool.connectionString` points to a local database (e.g hostname has `localhost` or `127.0.0.1`) we use the `pg` module for pooling instead of `@vercel/postgres`. This is because `@vercel/postgres` doesn't work with local databases, if you want to disable that behavior, you can pass `forceUseVercelPostgres: true` to adapter's 'args and follow [Vercel guide](https://vercel.com/docs/storage/vercel-postgres/local-development#option-2:-local-postgres-instance-with-docker) for a Docker Neon DB setup.
</Banner>
## Options
| Option | Description |
@@ -178,7 +183,7 @@ postgresAdapter({
})
```
Make sure Payload doesn't overlap table names with its collections. For example, if you already have a collection with slug "users", you should either change the slug or `dbName` to change the table name for this collection.
Make sure Payload doesn't overlap table names with its collections. For example, if you already have a collection with slug "users", you should either change the slug or `dbName` to change the table name for this collection.
### afterSchemaInit

View File

@@ -4,6 +4,7 @@ import type { Connect } from 'payload'
import { pushDevSchema } from '@payloadcms/drizzle'
import { sql, VercelPool } from '@vercel/postgres'
import { drizzle } from 'drizzle-orm/node-postgres'
import pg from 'pg'
import type { VercelPostgresAdapter } from './types.js'
@@ -24,10 +25,30 @@ export const connect: Connect = async function connect(
try {
const logger = this.logger || false
let client: pg.Pool | VercelPool
const connectionString = this.poolOptions?.connectionString ?? process.env.POSTGRES_URL
// Use non-vercel postgres for local database
if (
!this.forceUseVercelPostgres &&
connectionString &&
['127.0.0.1', 'localhost'].includes(new URL(connectionString).hostname)
) {
client = new pg.Pool(
this.poolOptions ?? {
connectionString,
},
)
} else {
client = this.poolOptions ? new VercelPool(this.poolOptions) : sql
}
// Passed the poolOptions if provided,
// else have vercel/postgres detect the connection string from the environment
this.drizzle = drizzle({
client: this.poolOptions ? new VercelPool(this.poolOptions) : sql,
client,
logger,
schema: this.schema,
})

View File

@@ -99,6 +99,7 @@ export function vercelPostgresAdapter(args: Args = {}): DatabaseAdapterObj<Verce
json: true,
},
fieldConstraints: {},
forceUseVercelPostgres: args.forceUseVercelPostgres ?? false,
idType: postgresIDType,
indexes: new Set<string>(),
initializing,

View File

@@ -31,6 +31,13 @@ export type Args = {
*/
disableCreateDatabase?: boolean
extensions?: string[]
/**
* By default, we connect to a local database using the `pg` module instead of `@vercel/postgres`.
* This is because `@vercel/postgres` doesn't work with local databases.
* If you still want to use `@vercel/postgres` even locally you can pass `true` here
* and you'd to spin up the database with a special Neon's Docker Compose setup - https://vercel.com/docs/storage/vercel-postgres/local-development#option-2:-local-postgres-instance-with-docker
*/
forceUseVercelPostgres?: boolean
idType?: 'serial' | 'uuid'
localesSuffix?: string
logger?: DrizzleConfig['logger']
@@ -58,6 +65,7 @@ export type Args = {
}
export type VercelPostgresAdapter = {
forceUseVercelPostgres?: boolean
pool?: VercelPool
poolOptions?: Args['pool']
} & BasePostgresAdapter