Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
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
32 changes: 32 additions & 0 deletions docs/content/docs/2.features/0.database.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ Install Drizzle ORM, Drizzle Kit, and the appropriate driver(s) for the database
NuxtHub automatically detects your database connection using environment variables:
- Uses `PGlite` (embedded PostgreSQL) if no environment variables are set.
- Uses `postgres-js` driver if you set `DATABASE_URL`, `POSTGRES_URL`, or `POSTGRESQL_URL` environment variable.
- Use `neon-http` driver with `@neondatabase/serverless` for [Neon](https://neon.com) serverless PostgreSQL.
::
:::
:::tabs-item{label="MySQL" icon="i-simple-icons-mysql"}
Expand Down Expand Up @@ -780,6 +781,37 @@ This driver requires the following environment variables:
You can find your Cloudflare account ID and create API tokens in the [Cloudflare dashboard](https://dash.cloudflare.com). The API token needs `D1:Edit` permissions.
::

### Neon Serverless

Use the `neon-http` driver to connect to [Neon](https://neon.com) serverless PostgreSQL. This driver uses HTTP protocol optimized for serverless environments.

```ts [nuxt.config.ts]
export default defineNuxtConfig({
hub: {
db: {
dialect: 'postgresql',
driver: 'neon-http'
}
}
})
```

Install the required dependency:

```bash
pnpm add @neondatabase/serverless
```

This driver requires the following environment variable:

| Variable | Description |
| --- | --- |
| `DATABASE_URL` | Your Neon database connection string (or `POSTGRES_URL` / `POSTGRESQL_URL`) |

::callout{icon="i-lucide-info"}
You can find your Neon connection string in the [Neon dashboard](https://console.neon.tech). The connection string format is `postgresql://user:password@hostname/database`.
::

## Migration guide

::important
Expand Down
7 changes: 7 additions & 0 deletions src/db/lib/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,13 @@ export async function createDrizzleClient(config: ResolvedDatabaseConfig, hubDir
pkg = 'drizzle-orm/postgres-js'
const { drizzle } = await import(pkg)
return drizzle({ client })
} else if (driver === 'neon-http') {
const clientPkg = '@neondatabase/serverless'
const { neon } = await import(clientPkg)
const sql = neon(connection.url)
pkg = 'drizzle-orm/neon-http'
const { drizzle } = await import(pkg)
return drizzle(sql)
} else if (driver === 'libsql') {
pkg = 'drizzle-orm/libsql'
} else if (driver === 'mysql2') {
Expand Down
14 changes: 14 additions & 0 deletions src/db/setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ export async function resolveDatabaseConfig(nuxt: Nuxt, hub: HubConfig): Promise
}
case 'postgresql': {
config.connection = defu(config.connection, { url: process.env.POSTGRES_URL || process.env.POSTGRESQL_URL || process.env.DATABASE_URL || '' })
if (config.driver && ['neon-http', 'postgres-js'].includes(config.driver) && !config.connection.url) {
throw new Error(`\`${config.driver}\` driver requires \`DATABASE_URL\`, \`POSTGRES_URL\`, or \`POSTGRESQL_URL\` environment variable`)
}
if (config.connection.url) {
config.driver ||= 'postgres-js'
break
Expand Down Expand Up @@ -103,6 +106,8 @@ export async function setupDatabase(nuxt: Nuxt, hub: HubConfig, deps: Record<str
}
if (driver === 'postgres-js' && !deps['postgres']) {
logWhenReady(nuxt, 'Please run `npx nypm i postgres` to use PostgreSQL as database.', 'error')
} else if (driver === 'neon-http' && !deps['@neondatabase/serverless']) {
logWhenReady(nuxt, 'Please run `npx nypm i @neondatabase/serverless` to use Neon serverless database.', 'error')
} else if (driver === 'pglite' && !deps['@electric-sql/pglite']) {
logWhenReady(nuxt, 'Please run `npx nypm i @electric-sql/pglite` to use PGlite as database.', 'error')
} else if (driver === 'mysql2' && !deps.mysql2) {
Expand Down Expand Up @@ -268,7 +273,16 @@ const db = drizzle({ client, schema });
export { db, schema }
`
}
if (driver === 'neon-http') {
drizzleOrmContent = `import { neon } from '@neondatabase/serverless'
import { drizzle } from 'drizzle-orm/neon-http'
import * as schema from './db/schema.mjs'

const sql = neon(${connection.connectionString})
const db = drizzle(sql, { schema })
export { db, schema }
`
}
if (driver === 'd1') {
// D1 requires lazy binding access - bindings only available in request context on CF Workers
drizzleOrmContent = `import { drizzle } from 'drizzle-orm/d1'
Expand Down
6 changes: 3 additions & 3 deletions src/types/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,10 +156,10 @@ export type DatabaseConfig = {
* Database driver (optional, auto-detected if not provided)
*
* SQLite drivers: 'better-sqlite3', 'libsql', 'bun-sqlite', 'd1', 'd1-http'
* PostgreSQL drivers: 'postgres-js', 'pglite'
* PostgreSQL drivers: 'postgres-js', 'pglite', 'neon-http'
* MySQL drivers: 'mysql2'
*/
driver?: 'better-sqlite3' | 'libsql' | 'bun-sqlite' | 'd1' | 'd1-http' | 'postgres-js' | 'pglite' | 'mysql2'
driver?: 'better-sqlite3' | 'libsql' | 'bun-sqlite' | 'd1' | 'd1-http' | 'postgres-js' | 'pglite' | 'neon-http' | 'mysql2'
/**
* Database connection configuration
*/
Expand All @@ -183,7 +183,7 @@ export type DatabaseConfig = {

export type ResolvedDatabaseConfig = DatabaseConfig & {
dialect: 'sqlite' | 'postgresql' | 'mysql'
driver: 'better-sqlite3' | 'libsql' | 'bun-sqlite' | 'd1' | 'd1-http' | 'postgres-js' | 'pglite' | 'mysql2'
driver: 'better-sqlite3' | 'libsql' | 'bun-sqlite' | 'd1' | 'd1-http' | 'postgres-js' | 'pglite' | 'neon-http' | 'mysql2'
connection: DatabaseConnection
migrationsDirs: string[]
queriesPaths: string[]
Expand Down
49 changes: 49 additions & 0 deletions test/database.config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,55 @@ describe('resolveDatabaseConfig', () => {
driver: 'custom-postgres'
})
})

it('should use neon-http driver when explicitly set', async () => {
process.env.DATABASE_URL = 'postgresql://user:pass@localhost:5432/db'

const nuxt = createMockNuxt()
const hub = createBaseHubConfig({
dialect: 'postgresql',
driver: 'neon-http'
})

const result = await resolveDatabaseConfig(nuxt, hub)

expect(result).toMatchObject({
dialect: 'postgresql',
driver: 'neon-http',
connection: {
url: 'postgresql://user:pass@localhost:5432/db'
}
})
})

it('should not use neon-http driver automatically', async () => {
process.env.DATABASE_URL = 'postgresql://user:pass@localhost:5432/db'

const nuxt = createMockNuxt()
const hub = createBaseHubConfig('postgresql')

const result = await resolveDatabaseConfig(nuxt, hub)

expect(result).toMatchObject({
dialect: 'postgresql',
driver: 'postgres-js',
connection: {
url: 'postgresql://user:pass@localhost:5432/db'
}
})
})

it('should throw error when DATABASE_URL is not set for neon-http', async () => {
const nuxt = createMockNuxt()
const hub = createBaseHubConfig({
dialect: 'postgresql',
driver: 'neon-http'
})

await expect(resolveDatabaseConfig(nuxt, hub)).rejects.toThrow(
'Neon HTTP driver requires DATABASE_URL, POSTGRES_URL, or POSTGRESQL_URL environment variable'
)
})
})

describe('MySQL dialect', () => {
Expand Down
Loading