Initial commit
This commit is contained in:
97
templates/drizzle-mysql.ts
Normal file
97
templates/drizzle-mysql.ts
Normal file
@@ -0,0 +1,97 @@
|
||||
/**
|
||||
* Drizzle ORM with MySQL
|
||||
*
|
||||
* Type-safe ORM for MySQL via Hyperdrive.
|
||||
*
|
||||
* Install: npm install drizzle-orm mysql2
|
||||
* Install (dev): npm install -D drizzle-kit
|
||||
*
|
||||
* Minimum version: mysql2@3.13.0
|
||||
*/
|
||||
|
||||
import { drizzle } from "drizzle-orm/mysql2";
|
||||
import { createConnection } from "mysql2";
|
||||
import { mysqlTable, int, varchar, timestamp } from "drizzle-orm/mysql-core";
|
||||
import { eq } from "drizzle-orm";
|
||||
|
||||
// Define schema
|
||||
export const users = mysqlTable("users", {
|
||||
id: int("id").primaryKey().autoincrement(),
|
||||
name: varchar("name", { length: 255 }).notNull(),
|
||||
email: varchar("email", { length: 255 }).notNull(),
|
||||
createdAt: timestamp("created_at").defaultNow(),
|
||||
});
|
||||
|
||||
type Bindings = {
|
||||
HYPERDRIVE: Hyperdrive;
|
||||
};
|
||||
|
||||
export default {
|
||||
async fetch(
|
||||
request: Request,
|
||||
env: Bindings,
|
||||
ctx: ExecutionContext
|
||||
): Promise<Response> {
|
||||
// Create mysql2 connection
|
||||
const connection = createConnection({
|
||||
host: env.HYPERDRIVE.host,
|
||||
user: env.HYPERDRIVE.user,
|
||||
password: env.HYPERDRIVE.password,
|
||||
database: env.HYPERDRIVE.database,
|
||||
port: env.HYPERDRIVE.port,
|
||||
disableEval: true // REQUIRED for Workers
|
||||
});
|
||||
|
||||
// Create Drizzle client
|
||||
const db = drizzle(connection);
|
||||
|
||||
try {
|
||||
// Example: Select all users
|
||||
const allUsers = await db.select().from(users);
|
||||
|
||||
// Example: Select with where clause
|
||||
const user = await db
|
||||
.select()
|
||||
.from(users)
|
||||
.where(eq(users.id, 1));
|
||||
|
||||
// Example: Insert
|
||||
await db.insert(users).values({
|
||||
name: "John Doe",
|
||||
email: `john.${Date.now()}@example.com`
|
||||
});
|
||||
|
||||
// Example: Update
|
||||
await db
|
||||
.update(users)
|
||||
.set({ name: "Jane Doe" })
|
||||
.where(eq(users.id, 1));
|
||||
|
||||
return Response.json({
|
||||
success: true,
|
||||
data: {
|
||||
allUsers,
|
||||
user
|
||||
}
|
||||
});
|
||||
|
||||
} catch (error: any) {
|
||||
console.error("Database error:", error);
|
||||
|
||||
return Response.json({
|
||||
success: false,
|
||||
error: error.message
|
||||
}, {
|
||||
status: 500
|
||||
});
|
||||
|
||||
} finally {
|
||||
// CRITICAL: Clean up connection
|
||||
ctx.waitUntil(
|
||||
new Promise<void>((resolve) => {
|
||||
connection.end(() => resolve());
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
96
templates/drizzle-postgres.ts
Normal file
96
templates/drizzle-postgres.ts
Normal file
@@ -0,0 +1,96 @@
|
||||
/**
|
||||
* Drizzle ORM with PostgreSQL
|
||||
*
|
||||
* Type-safe ORM for PostgreSQL via Hyperdrive.
|
||||
*
|
||||
* Install: npm install drizzle-orm postgres
|
||||
* Install (dev): npm install -D drizzle-kit
|
||||
*
|
||||
* Minimum version: postgres@3.4.5
|
||||
*/
|
||||
|
||||
import { drizzle } from "drizzle-orm/postgres-js";
|
||||
import postgres from "postgres";
|
||||
import { pgTable, serial, varchar, timestamp } from "drizzle-orm/pg-core";
|
||||
import { eq } from "drizzle-orm";
|
||||
|
||||
// Define schema
|
||||
export const users = pgTable("users", {
|
||||
id: serial("id").primaryKey(),
|
||||
name: varchar("name", { length: 255 }).notNull(),
|
||||
email: varchar("email", { length: 255 }).notNull().unique(),
|
||||
createdAt: timestamp("created_at").defaultNow(),
|
||||
});
|
||||
|
||||
type Bindings = {
|
||||
HYPERDRIVE: Hyperdrive;
|
||||
};
|
||||
|
||||
export default {
|
||||
async fetch(
|
||||
request: Request,
|
||||
env: Bindings,
|
||||
ctx: ExecutionContext
|
||||
): Promise<Response> {
|
||||
// Create postgres.js connection
|
||||
const sql = postgres(env.HYPERDRIVE.connectionString, {
|
||||
max: 5,
|
||||
prepare: true,
|
||||
fetch_types: false
|
||||
});
|
||||
|
||||
// Create Drizzle client
|
||||
const db = drizzle(sql);
|
||||
|
||||
try {
|
||||
// Example: Select all users
|
||||
const allUsers = await db.select().from(users);
|
||||
|
||||
// Example: Select with where clause
|
||||
const recentUsers = await db
|
||||
.select()
|
||||
.from(users)
|
||||
.where(eq(users.createdAt, new Date('2024-01-01')));
|
||||
|
||||
// Example: Insert
|
||||
const [newUser] = await db
|
||||
.insert(users)
|
||||
.values({
|
||||
name: "John Doe",
|
||||
email: `john.${Date.now()}@example.com`
|
||||
})
|
||||
.returning();
|
||||
|
||||
// Example: Update
|
||||
await db
|
||||
.update(users)
|
||||
.set({ name: "Jane Doe" })
|
||||
.where(eq(users.id, newUser.id));
|
||||
|
||||
// Example: Delete
|
||||
// await db.delete(users).where(eq(users.id, 123));
|
||||
|
||||
return Response.json({
|
||||
success: true,
|
||||
data: {
|
||||
allUsers,
|
||||
recentUsers,
|
||||
newUser
|
||||
}
|
||||
});
|
||||
|
||||
} catch (error: any) {
|
||||
console.error("Database error:", error);
|
||||
|
||||
return Response.json({
|
||||
success: false,
|
||||
error: error.message
|
||||
}, {
|
||||
status: 500
|
||||
});
|
||||
|
||||
} finally {
|
||||
ctx.waitUntil(sql.end());
|
||||
}
|
||||
}
|
||||
};
|
||||
94
templates/local-dev-setup.sh
Executable file
94
templates/local-dev-setup.sh
Executable file
@@ -0,0 +1,94 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Hyperdrive Local Development Setup Helper
|
||||
#
|
||||
# This script helps set up environment variables for local development
|
||||
# with Hyperdrive. Use this to avoid committing credentials to wrangler.jsonc.
|
||||
#
|
||||
# Usage:
|
||||
# ./local-dev-setup.sh
|
||||
# source .env.local # Load variables into current shell
|
||||
# npm run dev # Start wrangler dev
|
||||
#
|
||||
|
||||
set -e
|
||||
|
||||
echo "🚀 Hyperdrive Local Development Setup"
|
||||
echo ""
|
||||
|
||||
# Get binding name from wrangler.jsonc
|
||||
BINDING_NAME=$(grep -A 2 '"hyperdrive"' wrangler.jsonc | grep '"binding"' | cut -d'"' -f4 | head -1)
|
||||
|
||||
if [ -z "$BINDING_NAME" ]; then
|
||||
echo "❌ Could not find Hyperdrive binding in wrangler.jsonc"
|
||||
echo " Please ensure you have a hyperdrive configuration with a binding."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Found Hyperdrive binding: $BINDING_NAME"
|
||||
echo ""
|
||||
|
||||
# Ask for database details
|
||||
echo "Enter your local database connection details:"
|
||||
echo ""
|
||||
|
||||
read -p "Database type (postgres/mysql): " DB_TYPE
|
||||
read -p "Host (default: localhost): " DB_HOST
|
||||
DB_HOST=${DB_HOST:-localhost}
|
||||
|
||||
if [ "$DB_TYPE" = "postgres" ]; then
|
||||
read -p "Port (default: 5432): " DB_PORT
|
||||
DB_PORT=${DB_PORT:-5432}
|
||||
else
|
||||
read -p "Port (default: 3306): " DB_PORT
|
||||
DB_PORT=${DB_PORT:-3306}
|
||||
fi
|
||||
|
||||
read -p "Database name: " DB_NAME
|
||||
read -p "Username: " DB_USER
|
||||
read -sp "Password: " DB_PASSWORD
|
||||
echo ""
|
||||
|
||||
# Build connection string
|
||||
if [ "$DB_TYPE" = "postgres" ]; then
|
||||
CONNECTION_STRING="postgres://${DB_USER}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_NAME}"
|
||||
else
|
||||
CONNECTION_STRING="mysql://${DB_USER}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_NAME}"
|
||||
fi
|
||||
|
||||
# Create .env.local file
|
||||
ENV_VAR_NAME="CLOUDFLARE_HYPERDRIVE_LOCAL_CONNECTION_STRING_${BINDING_NAME}"
|
||||
|
||||
cat > .env.local <<EOF
|
||||
# Hyperdrive Local Development Environment Variables
|
||||
# Generated on: $(date)
|
||||
#
|
||||
# Load these variables before running wrangler dev:
|
||||
# source .env.local
|
||||
# npm run dev
|
||||
#
|
||||
# DO NOT commit this file to version control!
|
||||
|
||||
export ${ENV_VAR_NAME}="${CONNECTION_STRING}"
|
||||
EOF
|
||||
|
||||
# Add to .gitignore
|
||||
if ! grep -q ".env.local" .gitignore 2>/dev/null; then
|
||||
echo ".env.local" >> .gitignore
|
||||
echo "✅ Added .env.local to .gitignore"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "✅ Created .env.local with environment variable:"
|
||||
echo " ${ENV_VAR_NAME}"
|
||||
echo ""
|
||||
echo "Next steps:"
|
||||
echo "1. Load the environment variable:"
|
||||
echo " source .env.local"
|
||||
echo ""
|
||||
echo "2. Start local development server:"
|
||||
echo " npx wrangler dev"
|
||||
echo ""
|
||||
echo "3. Your Worker will connect to:"
|
||||
echo " ${DB_TYPE}://${DB_HOST}:${DB_PORT}/${DB_NAME}"
|
||||
echo ""
|
||||
80
templates/mysql2-basic.ts
Normal file
80
templates/mysql2-basic.ts
Normal file
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* MySQL with mysql2
|
||||
*
|
||||
* MySQL driver for Cloudflare Workers via Hyperdrive.
|
||||
*
|
||||
* CRITICAL: Must set disableEval: true (eval() not supported in Workers)
|
||||
* Minimum version: mysql2@3.13.0
|
||||
*/
|
||||
|
||||
import { createConnection } from "mysql2/promise";
|
||||
|
||||
type Bindings = {
|
||||
HYPERDRIVE: Hyperdrive;
|
||||
};
|
||||
|
||||
export default {
|
||||
async fetch(
|
||||
request: Request,
|
||||
env: Bindings,
|
||||
ctx: ExecutionContext
|
||||
): Promise<Response> {
|
||||
// Create MySQL connection via Hyperdrive
|
||||
const connection = await createConnection({
|
||||
host: env.HYPERDRIVE.host,
|
||||
user: env.HYPERDRIVE.user,
|
||||
password: env.HYPERDRIVE.password,
|
||||
database: env.HYPERDRIVE.database,
|
||||
port: env.HYPERDRIVE.port,
|
||||
|
||||
// CRITICAL: Required for Workers (eval() not supported)
|
||||
disableEval: true
|
||||
});
|
||||
|
||||
try {
|
||||
// Example: Simple query
|
||||
const [rows] = await connection.query('SELECT NOW() as current_time');
|
||||
console.log("Query executed successfully");
|
||||
|
||||
// Example: Parameterized query (prevents SQL injection)
|
||||
const [users] = await connection.query(
|
||||
'SELECT id, name, email FROM users WHERE created_at > ? LIMIT ?',
|
||||
['2024-01-01', 10]
|
||||
);
|
||||
|
||||
// Example: Execute multiple statements
|
||||
const [results] = await connection.query(
|
||||
'SELECT COUNT(*) as total FROM users'
|
||||
);
|
||||
|
||||
return Response.json({
|
||||
success: true,
|
||||
data: {
|
||||
currentTime: (rows as any[])[0].current_time,
|
||||
users: users,
|
||||
totalUsers: (results as any[])[0].total
|
||||
},
|
||||
// Hyperdrive metadata
|
||||
hyperdriveInfo: {
|
||||
host: env.HYPERDRIVE.host,
|
||||
database: env.HYPERDRIVE.database,
|
||||
port: env.HYPERDRIVE.port
|
||||
}
|
||||
});
|
||||
|
||||
} catch (error: any) {
|
||||
console.error("Database error:", error.message);
|
||||
|
||||
return Response.json({
|
||||
success: false,
|
||||
error: error.message
|
||||
}, {
|
||||
status: 500
|
||||
});
|
||||
|
||||
} finally {
|
||||
// CRITICAL: Clean up connection AFTER response is sent
|
||||
ctx.waitUntil(connection.end());
|
||||
}
|
||||
}
|
||||
};
|
||||
68
templates/postgres-basic.ts
Normal file
68
templates/postgres-basic.ts
Normal file
@@ -0,0 +1,68 @@
|
||||
/**
|
||||
* PostgreSQL with node-postgres (pg) - Basic Usage
|
||||
*
|
||||
* Simple pattern using pg.Client for straightforward queries.
|
||||
* Good for: Single query per request, simple operations
|
||||
*/
|
||||
|
||||
import { Client } from "pg";
|
||||
|
||||
type Bindings = {
|
||||
HYPERDRIVE: Hyperdrive;
|
||||
};
|
||||
|
||||
export default {
|
||||
async fetch(
|
||||
request: Request,
|
||||
env: Bindings,
|
||||
ctx: ExecutionContext
|
||||
): Promise<Response> {
|
||||
// Create a new client for this request
|
||||
const client = new Client({
|
||||
connectionString: env.HYPERDRIVE.connectionString
|
||||
});
|
||||
|
||||
try {
|
||||
// Connect to the database
|
||||
await client.connect();
|
||||
console.log("Connected to PostgreSQL via Hyperdrive");
|
||||
|
||||
// Example: Simple query
|
||||
const result = await client.query('SELECT NOW() as current_time');
|
||||
console.log("Query executed successfully");
|
||||
|
||||
// Example: Parameterized query (prevents SQL injection)
|
||||
const users = await client.query(
|
||||
'SELECT id, name, email FROM users WHERE created_at > $1 LIMIT $2',
|
||||
['2024-01-01', 10]
|
||||
);
|
||||
|
||||
return Response.json({
|
||||
success: true,
|
||||
currentTime: result.rows[0].current_time,
|
||||
users: users.rows,
|
||||
// Hyperdrive metadata
|
||||
hyperdriveInfo: {
|
||||
host: env.HYPERDRIVE.host,
|
||||
database: env.HYPERDRIVE.database,
|
||||
port: env.HYPERDRIVE.port
|
||||
}
|
||||
});
|
||||
|
||||
} catch (error: any) {
|
||||
console.error("Database error:", error.message);
|
||||
|
||||
return Response.json({
|
||||
success: false,
|
||||
error: error.message
|
||||
}, {
|
||||
status: 500
|
||||
});
|
||||
|
||||
} finally {
|
||||
// CRITICAL: Clean up connection AFTER response is sent
|
||||
// ctx.waitUntil() runs in background (non-blocking)
|
||||
ctx.waitUntil(client.end());
|
||||
}
|
||||
}
|
||||
};
|
||||
111
templates/postgres-js.ts
Normal file
111
templates/postgres-js.ts
Normal file
@@ -0,0 +1,111 @@
|
||||
/**
|
||||
* PostgreSQL with postgres.js
|
||||
*
|
||||
* Modern PostgreSQL driver with better performance and tagged template literals.
|
||||
* Good for: Fast queries, streaming, modern API
|
||||
*
|
||||
* Minimum version: postgres@3.4.5
|
||||
*/
|
||||
|
||||
import postgres from "postgres";
|
||||
|
||||
type Bindings = {
|
||||
HYPERDRIVE: Hyperdrive;
|
||||
};
|
||||
|
||||
export default {
|
||||
async fetch(
|
||||
request: Request,
|
||||
env: Bindings,
|
||||
ctx: ExecutionContext
|
||||
): Promise<Response> {
|
||||
// Create postgres.js connection
|
||||
const sql = postgres(env.HYPERDRIVE.connectionString, {
|
||||
// CRITICAL: max 5 connections (Workers limit: 6)
|
||||
max: 5,
|
||||
|
||||
// CRITICAL for caching: Enable prepared statements
|
||||
prepare: true,
|
||||
|
||||
// Disable fetch_types if not using array types (reduces latency)
|
||||
fetch_types: false,
|
||||
|
||||
// Connection timeout
|
||||
connect_timeout: 10,
|
||||
|
||||
// Idle connection timeout
|
||||
idle_timeout: 30
|
||||
});
|
||||
|
||||
try {
|
||||
// Example: Simple query with tagged template literal
|
||||
const currentTime = await sql`SELECT NOW() as current_time`;
|
||||
|
||||
// Example: Parameterized query (auto-escaped)
|
||||
const users = await sql`
|
||||
SELECT id, name, email
|
||||
FROM users
|
||||
WHERE created_at > ${new Date('2024-01-01')}
|
||||
LIMIT 10
|
||||
`;
|
||||
|
||||
// Example: Dynamic columns (use sql() for identifiers)
|
||||
const orderBy = 'created_at';
|
||||
const sortedUsers = await sql`
|
||||
SELECT * FROM users
|
||||
ORDER BY ${sql(orderBy)} DESC
|
||||
LIMIT 5
|
||||
`;
|
||||
|
||||
// Example: Bulk insert
|
||||
const newUsers = [
|
||||
{ name: 'Alice', email: 'alice@example.com' },
|
||||
{ name: 'Bob', email: 'bob@example.com' }
|
||||
];
|
||||
|
||||
await sql`
|
||||
INSERT INTO users ${sql(newUsers, 'name', 'email')}
|
||||
`;
|
||||
|
||||
// Example: Transaction
|
||||
const result = await sql.begin(async sql => {
|
||||
const [user] = await sql`
|
||||
INSERT INTO users (name, email)
|
||||
VALUES ('Charlie', 'charlie@example.com')
|
||||
RETURNING *
|
||||
`;
|
||||
|
||||
await sql`
|
||||
INSERT INTO audit_log (action, user_id)
|
||||
VALUES ('User created', ${user.id})
|
||||
`;
|
||||
|
||||
return user;
|
||||
});
|
||||
|
||||
return Response.json({
|
||||
success: true,
|
||||
data: {
|
||||
currentTime: currentTime[0].current_time,
|
||||
users: users,
|
||||
sortedUsers: sortedUsers,
|
||||
newUser: result
|
||||
}
|
||||
});
|
||||
|
||||
} catch (error: any) {
|
||||
console.error("Database error:", error);
|
||||
|
||||
return Response.json({
|
||||
success: false,
|
||||
error: error.message
|
||||
}, {
|
||||
status: 500
|
||||
});
|
||||
|
||||
} finally {
|
||||
// CRITICAL: Close all connections
|
||||
ctx.waitUntil(sql.end({ timeout: 5 }));
|
||||
}
|
||||
}
|
||||
};
|
||||
80
templates/postgres-pool.ts
Normal file
80
templates/postgres-pool.ts
Normal file
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* PostgreSQL with node-postgres (pg) - Connection Pool
|
||||
*
|
||||
* Advanced pattern using pg.Pool for parallel queries.
|
||||
* Good for: Multiple queries per request, better performance
|
||||
*/
|
||||
|
||||
import { Pool } from "pg";
|
||||
|
||||
type Bindings = {
|
||||
HYPERDRIVE: Hyperdrive;
|
||||
};
|
||||
|
||||
export default {
|
||||
async fetch(
|
||||
request: Request,
|
||||
env: Bindings,
|
||||
ctx: ExecutionContext
|
||||
): Promise<Response> {
|
||||
// Create a connection pool
|
||||
// CRITICAL: max: 5 (Workers limit is 6 concurrent external connections)
|
||||
const pool = new Pool({
|
||||
connectionString: env.HYPERDRIVE.connectionString,
|
||||
max: 5, // Max connections in pool (stay within Workers' limit)
|
||||
idleTimeoutMillis: 30000, // Close idle connections after 30 seconds
|
||||
connectionTimeoutMillis: 10000 // Timeout after 10 seconds if can't acquire connection
|
||||
});
|
||||
|
||||
try {
|
||||
// Example: Run multiple queries in parallel
|
||||
const [usersResult, postsResult, statsResult] = await Promise.all([
|
||||
pool.query('SELECT id, name, email FROM users ORDER BY created_at DESC LIMIT 10'),
|
||||
pool.query('SELECT id, title, author_id FROM posts ORDER BY published_at DESC LIMIT 10'),
|
||||
pool.query(`
|
||||
SELECT
|
||||
(SELECT COUNT(*) FROM users) as total_users,
|
||||
(SELECT COUNT(*) FROM posts) as total_posts,
|
||||
(SELECT COUNT(*) FROM comments) as total_comments
|
||||
`)
|
||||
]);
|
||||
|
||||
// Example: Transaction
|
||||
const client = await pool.connect();
|
||||
try {
|
||||
await client.query('BEGIN');
|
||||
await client.query('INSERT INTO users (name, email) VALUES ($1, $2)', ['John Doe', 'john@example.com']);
|
||||
await client.query('INSERT INTO audit_log (action) VALUES ($1)', ['User created']);
|
||||
await client.query('COMMIT');
|
||||
} catch (error) {
|
||||
await client.query('ROLLBACK');
|
||||
throw error;
|
||||
} finally {
|
||||
client.release(); // Return connection to pool
|
||||
}
|
||||
|
||||
return Response.json({
|
||||
success: true,
|
||||
data: {
|
||||
users: usersResult.rows,
|
||||
posts: postsResult.rows,
|
||||
stats: statsResult.rows[0]
|
||||
}
|
||||
});
|
||||
|
||||
} catch (error: any) {
|
||||
console.error("Database error:", error.message);
|
||||
|
||||
return Response.json({
|
||||
success: false,
|
||||
error: error.message
|
||||
}, {
|
||||
status: 500
|
||||
});
|
||||
|
||||
} finally {
|
||||
// CRITICAL: Clean up all pool connections
|
||||
ctx.waitUntil(pool.end());
|
||||
}
|
||||
}
|
||||
};
|
||||
151
templates/prisma-postgres.ts
Normal file
151
templates/prisma-postgres.ts
Normal file
@@ -0,0 +1,151 @@
|
||||
/**
|
||||
* Prisma ORM with PostgreSQL
|
||||
*
|
||||
* Type-safe ORM for PostgreSQL via Hyperdrive using driver adapters.
|
||||
*
|
||||
* Install: npm install prisma @prisma/client pg @prisma/adapter-pg
|
||||
*
|
||||
* Setup:
|
||||
* 1. npx prisma init
|
||||
* 2. Define schema in prisma/schema.prisma
|
||||
* 3. npx prisma generate --no-engine
|
||||
* 4. npx prisma migrate dev (for migrations)
|
||||
*
|
||||
* CRITICAL: Must use driver adapters (@prisma/adapter-pg) for Hyperdrive
|
||||
*/
|
||||
|
||||
import { PrismaPg } from "@prisma/adapter-pg";
|
||||
import { PrismaClient } from "@prisma/client";
|
||||
import { Pool } from "pg";
|
||||
|
||||
type Bindings = {
|
||||
HYPERDRIVE: Hyperdrive;
|
||||
};
|
||||
|
||||
/**
|
||||
* Example Prisma schema (prisma/schema.prisma):
|
||||
*
|
||||
* generator client {
|
||||
* provider = "prisma-client-js"
|
||||
* previewFeatures = ["driverAdapters"]
|
||||
* }
|
||||
*
|
||||
* datasource db {
|
||||
* provider = "postgresql"
|
||||
* url = env("DATABASE_URL")
|
||||
* }
|
||||
*
|
||||
* model User {
|
||||
* id Int @id @default(autoincrement())
|
||||
* name String
|
||||
* email String @unique
|
||||
* createdAt DateTime @default(now())
|
||||
* posts Post[]
|
||||
* }
|
||||
*
|
||||
* model Post {
|
||||
* id Int @id @default(autoincrement())
|
||||
* title String
|
||||
* content String?
|
||||
* published Boolean @default(false)
|
||||
* authorId Int
|
||||
* author User @relation(fields: [authorId], references: [id])
|
||||
* }
|
||||
*/
|
||||
|
||||
export default {
|
||||
async fetch(
|
||||
request: Request,
|
||||
env: Bindings,
|
||||
ctx: ExecutionContext
|
||||
): Promise<Response> {
|
||||
// Create pg.Pool for driver adapter
|
||||
const pool = new Pool({
|
||||
connectionString: env.HYPERDRIVE.connectionString,
|
||||
max: 5
|
||||
});
|
||||
|
||||
// Create Prisma driver adapter
|
||||
const adapter = new PrismaPg(pool);
|
||||
|
||||
// Create Prisma client with adapter
|
||||
const prisma = new PrismaClient({ adapter });
|
||||
|
||||
try {
|
||||
// Example: Create user
|
||||
const newUser = await prisma.user.create({
|
||||
data: {
|
||||
name: "John Doe",
|
||||
email: `john.${Date.now()}@example.com`
|
||||
}
|
||||
});
|
||||
|
||||
// Example: Find all users
|
||||
const allUsers = await prisma.user.findMany({
|
||||
include: {
|
||||
posts: true // Include related posts
|
||||
}
|
||||
});
|
||||
|
||||
// Example: Find user by email
|
||||
const user = await prisma.user.findUnique({
|
||||
where: {
|
||||
email: "john@example.com"
|
||||
}
|
||||
});
|
||||
|
||||
// Example: Update user
|
||||
await prisma.user.update({
|
||||
where: { id: newUser.id },
|
||||
data: { name: "Jane Doe" }
|
||||
});
|
||||
|
||||
// Example: Create post with relation
|
||||
await prisma.post.create({
|
||||
data: {
|
||||
title: "My First Post",
|
||||
content: "Hello World!",
|
||||
published: true,
|
||||
authorId: newUser.id
|
||||
}
|
||||
});
|
||||
|
||||
// Example: Complex query with filters
|
||||
const recentUsers = await prisma.user.findMany({
|
||||
where: {
|
||||
createdAt: {
|
||||
gte: new Date('2024-01-01')
|
||||
}
|
||||
},
|
||||
orderBy: {
|
||||
createdAt: 'desc'
|
||||
},
|
||||
take: 10
|
||||
});
|
||||
|
||||
return Response.json({
|
||||
success: true,
|
||||
data: {
|
||||
newUser,
|
||||
allUsers,
|
||||
user,
|
||||
recentUsers
|
||||
}
|
||||
});
|
||||
|
||||
} catch (error: any) {
|
||||
console.error("Database error:", error);
|
||||
|
||||
return Response.json({
|
||||
success: false,
|
||||
error: error.message
|
||||
}, {
|
||||
status: 500
|
||||
});
|
||||
|
||||
} finally {
|
||||
// Clean up connections
|
||||
ctx.waitUntil(pool.end());
|
||||
}
|
||||
}
|
||||
};
|
||||
38
templates/wrangler-hyperdrive-config.jsonc
Normal file
38
templates/wrangler-hyperdrive-config.jsonc
Normal file
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"name": "my-worker-with-hyperdrive",
|
||||
"main": "src/index.ts",
|
||||
"compatibility_date": "2024-09-23",
|
||||
"compatibility_flags": [
|
||||
"nodejs_compat" // REQUIRED for database drivers (pg, postgres, mysql2)
|
||||
],
|
||||
"hyperdrive": [
|
||||
{
|
||||
// Binding name - access as env.HYPERDRIVE in your Worker
|
||||
"binding": "HYPERDRIVE",
|
||||
|
||||
// Hyperdrive configuration ID from: wrangler hyperdrive create
|
||||
"id": "<your-hyperdrive-id-here>",
|
||||
|
||||
// (Optional) Local development connection string
|
||||
// Alternative: Use CLOUDFLARE_HYPERDRIVE_LOCAL_CONNECTION_STRING_HYPERDRIVE env var
|
||||
"localConnectionString": "postgres://user:password@localhost:5432/local_db"
|
||||
}
|
||||
],
|
||||
|
||||
// Example: Multiple Hyperdrive configurations
|
||||
// "hyperdrive": [
|
||||
// {
|
||||
// "binding": "POSTGRES_DB",
|
||||
// "id": "postgres-hyperdrive-id"
|
||||
// },
|
||||
// {
|
||||
// "binding": "MYSQL_DB",
|
||||
// "id": "mysql-hyperdrive-id"
|
||||
// }
|
||||
// ],
|
||||
|
||||
// Optional: Enable observability
|
||||
"observability": {
|
||||
"enabled": true
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user