summaryrefslogtreecommitdiff
path: root/databases
diff options
context:
space:
mode:
Diffstat (limited to 'databases')
-rw-r--r--databases/drizzle/.claude/commands/migrate.md23
-rw-r--r--databases/drizzle/.claude/commands/schema.md18
-rw-r--r--databases/drizzle/.claude/settings.json47
-rw-r--r--databases/drizzle/CLAUDE.md704
-rw-r--r--databases/drizzle/README.md409
-rw-r--r--databases/drizzle/package.json66
6 files changed, 1267 insertions, 0 deletions
diff --git a/databases/drizzle/.claude/commands/migrate.md b/databases/drizzle/.claude/commands/migrate.md
new file mode 100644
index 0000000..0c7a06f
--- /dev/null
+++ b/databases/drizzle/.claude/commands/migrate.md
@@ -0,0 +1,23 @@
+---
+description: Handle Drizzle migrations (generate, push, rollback)
+argument-hint: "[generate|push|rollback|status]"
+allowed-tools: Bash, Read, Write
+---
+
+Handle Drizzle migrations: $ARGUMENTS
+
+Available actions:
+
+- **generate** - Generate migration from schema changes
+- **push** - Push schema changes to database
+- **rollback** - Rollback last migration
+- **status** - Check migration status
+
+Steps:
+
+1. Check current migration status
+2. Execute the requested migration action
+3. Verify the operation completed successfully
+4. Show resulting database state
+
+Always backup production data before running migrations.
diff --git a/databases/drizzle/.claude/commands/schema.md b/databases/drizzle/.claude/commands/schema.md
new file mode 100644
index 0000000..c038b06
--- /dev/null
+++ b/databases/drizzle/.claude/commands/schema.md
@@ -0,0 +1,18 @@
+---
+description: Generate type-safe Drizzle schema for a table
+argument-hint: "[table-name] [database-type]"
+allowed-tools: Write, Read, Edit
+---
+
+Generate a complete Drizzle ORM schema for the table "$ARGUMENTS".
+
+Follow these requirements:
+
+1. Use proper TypeScript types and imports
+2. Include appropriate indexes for performance
+3. Add relationships if referenced tables exist
+4. Include proper constraints and validations
+5. Generate both insert and select type exports
+6. Follow Drizzle naming conventions
+
+If no table name is provided, show available schema patterns and examples.
diff --git a/databases/drizzle/.claude/settings.json b/databases/drizzle/.claude/settings.json
new file mode 100644
index 0000000..f471570
--- /dev/null
+++ b/databases/drizzle/.claude/settings.json
@@ -0,0 +1,47 @@
+{
+ "permissions": {
+ "allow": [
+ "Bash(npm run db:*)",
+ "Bash(npx drizzle-kit:*)",
+ "Bash(npm run migrate:*)",
+ "Bash(npm run seed:*)",
+ "Write(drizzle/**/*)",
+ "Write(src/schema/**/*)",
+ "Write(src/lib/db.ts)",
+ "Read(drizzle.config.ts)",
+ "Read(package.json)"
+ ],
+ "deny": [
+ "Read(.env.production)",
+ "Read(.env.local)",
+ "Write(.env)",
+ "Bash(npm publish:*)",
+ "Bash(rm -rf:*)"
+ ]
+ },
+ "env": {
+ "NODE_ENV": "development"
+ },
+ "hooks": {
+ "PostToolUse": [
+ {
+ "matcher": "Write",
+ "hooks": [
+ {
+ "type": "command",
+ "command": "npx prettier --write $FILE_PATH",
+ "timeout": 10
+ }
+ ]
+ }
+ ]
+ },
+ "_metadata": {
+ "name": "Drizzle ORM",
+ "version": "1.0.0",
+ "category": "database",
+ "generated": "2025-08-20T13:36:56.490Z",
+ "generator": "manual",
+ "note": "Official Claude Code configuration"
+ }
+}
diff --git a/databases/drizzle/CLAUDE.md b/databases/drizzle/CLAUDE.md
new file mode 100644
index 0000000..97da6b3
--- /dev/null
+++ b/databases/drizzle/CLAUDE.md
@@ -0,0 +1,704 @@
+# Drizzle ORM Development Assistant
+
+You are an expert in Drizzle ORM with deep knowledge of schema management, migrations, type safety, and modern database development patterns.
+
+## Memory Integration
+
+This CLAUDE.md file follows official Claude Code memory management patterns:
+
+- **Project memory** - Shared with team via source control
+- **Hierarchical loading** - Builds upon user and enterprise memory
+- **Import support** - Can reference additional files with @path/to/file
+- **Auto-discovery** - Loaded when Claude reads files in this subtree
+
+## Available Commands
+
+Use these project-specific slash commands:
+
+- `/drizzle-schema [table-name]` - Generate type-safe schema
+- `/drizzle-migrate [action]` - Handle migrations
+- `/drizzle-query [type]` - Create optimized queries
+- `/drizzle-seed [table]` - Generate seed data
+
+## Project Context
+
+This project uses **Drizzle ORM** for type-safe database operations with:
+
+- **TypeScript-first** approach with full type inference
+- **SQL-like syntax** that's familiar and powerful
+- **Multiple database support** - PostgreSQL, MySQL, SQLite
+- **Automatic migrations** with schema versioning
+- **Performance optimized** with prepared statements
+- **Edge runtime compatible** - Works with serverless
+
+## Core Drizzle Principles
+
+### 1. Schema Definition
+
+- **Define schemas declaratively** using Drizzle's schema builders
+- **Use proper types** for each column with validation
+- **Establish relationships** with foreign keys and references
+- **Index strategically** for query performance
+- **Version schemas** with proper migration patterns
+
+### 2. Type Safety
+
+- **Full TypeScript inference** from schema to queries
+- **Compile-time validation** of SQL operations
+- **IntelliSense support** for table columns and relations
+- **Runtime validation** with Drizzle's built-in validators
+- **Type-safe joins** and complex queries
+
+### 3. Migration Management
+
+- **Generate migrations** automatically from schema changes
+- **Version control migrations** with proper naming
+- **Run migrations safely** in development and production
+- **Rollback support** for schema changes
+- **Seed data management** for consistent environments
+
+## Database Setup
+
+### PostgreSQL with Neon
+
+```typescript
+// lib/db.ts
+import { drizzle } from 'drizzle-orm/neon-http';
+import { neon, neonConfig } from '@neondatabase/serverless';
+
+neonConfig.fetchConnectionCache = true;
+
+const sql = neon(process.env.DATABASE_URL!);
+export const db = drizzle(sql);
+```
+
+### SQLite for Local Development
+
+```typescript
+// lib/db.ts
+import { drizzle } from 'drizzle-orm/better-sqlite3';
+import Database from 'better-sqlite3';
+
+const sqlite = new Database('./dev.db');
+export const db = drizzle(sqlite);
+```
+
+### MySQL with PlanetScale
+
+```typescript
+// lib/db.ts
+import { drizzle } from 'drizzle-orm/mysql2';
+import mysql from 'mysql2/promise';
+
+const connection = mysql.createPool({
+ uri: process.env.DATABASE_URL,
+});
+
+export const db = drizzle(connection);
+```
+
+## Schema Patterns
+
+### User Management Schema
+
+```typescript
+// schema/users.ts
+import { pgTable, serial, text, timestamp, boolean } from 'drizzle-orm/pg-core';
+
+export const users = pgTable('users', {
+ id: serial('id').primaryKey(),
+ email: text('email').notNull().unique(),
+ name: text('name').notNull(),
+ avatar: text('avatar'),
+ emailVerified: boolean('email_verified').default(false),
+ createdAt: timestamp('created_at').defaultNow(),
+ updatedAt: timestamp('updated_at').defaultNow(),
+});
+
+export type User = typeof users.$inferSelect;
+export type NewUser = typeof users.$inferInsert;
+```
+
+### Content with Relations
+
+```typescript
+// schema/posts.ts
+import { pgTable, serial, text, timestamp, integer } from 'drizzle-orm/pg-core';
+import { relations } from 'drizzle-orm';
+import { users } from './users';
+
+export const posts = pgTable('posts', {
+ id: serial('id').primaryKey(),
+ title: text('title').notNull(),
+ content: text('content').notNull(),
+ slug: text('slug').notNull().unique(),
+ published: boolean('published').default(false),
+ authorId: integer('author_id').references(() => users.id),
+ createdAt: timestamp('created_at').defaultNow(),
+ updatedAt: timestamp('updated_at').defaultNow(),
+});
+
+export const postsRelations = relations(posts, ({ one }) => ({
+ author: one(users, {
+ fields: [posts.authorId],
+ references: [users.id],
+ }),
+}));
+
+export const usersRelations = relations(users, ({ many }) => ({
+ posts: many(posts),
+}));
+
+export type Post = typeof posts.$inferSelect;
+export type NewPost = typeof posts.$inferInsert;
+```
+
+### E-commerce Schema
+
+```typescript
+// schema/ecommerce.ts
+import { pgTable, serial, text, integer, decimal, timestamp } from 'drizzle-orm/pg-core';
+
+export const products = pgTable('products', {
+ id: serial('id').primaryKey(),
+ name: text('name').notNull(),
+ description: text('description'),
+ price: decimal('price', { precision: 10, scale: 2 }).notNull(),
+ stock: integer('stock').default(0),
+ sku: text('sku').notNull().unique(),
+ categoryId: integer('category_id').references(() => categories.id),
+ createdAt: timestamp('created_at').defaultNow(),
+});
+
+export const categories = pgTable('categories', {
+ id: serial('id').primaryKey(),
+ name: text('name').notNull(),
+ slug: text('slug').notNull().unique(),
+ description: text('description'),
+});
+
+export const orders = pgTable('orders', {
+ id: serial('id').primaryKey(),
+ userId: integer('user_id').references(() => users.id),
+ total: decimal('total', { precision: 10, scale: 2 }).notNull(),
+ status: text('status', { enum: ['pending', 'processing', 'shipped', 'delivered', 'cancelled'] }).default('pending'),
+ createdAt: timestamp('created_at').defaultNow(),
+});
+
+export const orderItems = pgTable('order_items', {
+ id: serial('id').primaryKey(),
+ orderId: integer('order_id').references(() => orders.id),
+ productId: integer('product_id').references(() => products.id),
+ quantity: integer('quantity').notNull(),
+ price: decimal('price', { precision: 10, scale: 2 }).notNull(),
+});
+```
+
+## Query Patterns
+
+### Basic CRUD Operations
+
+```typescript
+// lib/queries/users.ts
+import { db } from '@/lib/db';
+import { users } from '@/schema/users';
+import { eq, desc, count } from 'drizzle-orm';
+
+// Create user
+export async function createUser(userData: NewUser) {
+ const [user] = await db.insert(users).values(userData).returning();
+ return user;
+}
+
+// Get user by ID
+export async function getUserById(id: number) {
+ const user = await db.select().from(users).where(eq(users.id, id));
+ return user[0];
+}
+
+// Get user by email
+export async function getUserByEmail(email: string) {
+ const user = await db.select().from(users).where(eq(users.email, email));
+ return user[0];
+}
+
+// Update user
+export async function updateUser(id: number, userData: Partial<NewUser>) {
+ const [user] = await db
+ .update(users)
+ .set(userData)
+ .where(eq(users.id, id))
+ .returning();
+ return user;
+}
+
+// Delete user
+export async function deleteUser(id: number) {
+ await db.delete(users).where(eq(users.id, id));
+}
+
+// Get paginated users
+export async function getPaginatedUsers(page = 1, limit = 10) {
+ const offset = (page - 1) * limit;
+
+ const [userList, totalCount] = await Promise.all([
+ db.select().from(users).limit(limit).offset(offset).orderBy(desc(users.createdAt)),
+ db.select({ count: count() }).from(users),
+ ]);
+
+ return {
+ users: userList,
+ total: totalCount[0].count,
+ page,
+ totalPages: Math.ceil(totalCount[0].count / limit),
+ };
+}
+```
+
+### Complex Relations
+
+```typescript
+// lib/queries/posts.ts
+import { db } from '@/lib/db';
+import { posts, users } from '@/schema';
+import { eq, desc, and, ilike } from 'drizzle-orm';
+
+// Get posts with authors
+export async function getPostsWithAuthors() {
+ return await db
+ .select({
+ id: posts.id,
+ title: posts.title,
+ content: posts.content,
+ published: posts.published,
+ createdAt: posts.createdAt,
+ author: {
+ id: users.id,
+ name: users.name,
+ email: users.email,
+ },
+ })
+ .from(posts)
+ .innerJoin(users, eq(posts.authorId, users.id))
+ .where(eq(posts.published, true))
+ .orderBy(desc(posts.createdAt));
+}
+
+// Search posts
+export async function searchPosts(query: string) {
+ return await db
+ .select()
+ .from(posts)
+ .where(
+ and(
+ eq(posts.published, true),
+ ilike(posts.title, `%${query}%`)
+ )
+ )
+ .orderBy(desc(posts.createdAt));
+}
+
+// Get user's posts
+export async function getUserPosts(userId: number) {
+ return await db
+ .select()
+ .from(posts)
+ .where(eq(posts.authorId, userId))
+ .orderBy(desc(posts.createdAt));
+}
+```
+
+### Advanced Queries
+
+```typescript
+// lib/queries/analytics.ts
+import { db } from '@/lib/db';
+import { orders, orderItems, products, users } from '@/schema';
+import { sum, count, avg, desc, gte } from 'drizzle-orm';
+
+// Sales analytics
+export async function getSalesAnalytics(startDate: Date, endDate: Date) {
+ return await db
+ .select({
+ totalRevenue: sum(orders.total),
+ totalOrders: count(orders.id),
+ averageOrderValue: avg(orders.total),
+ })
+ .from(orders)
+ .where(
+ and(
+ gte(orders.createdAt, startDate),
+ lte(orders.createdAt, endDate)
+ )
+ );
+}
+
+// Top selling products
+export async function getTopSellingProducts(limit = 10) {
+ return await db
+ .select({
+ productId: products.id,
+ productName: products.name,
+ totalSold: sum(orderItems.quantity),
+ revenue: sum(orderItems.price),
+ })
+ .from(orderItems)
+ .innerJoin(products, eq(orderItems.productId, products.id))
+ .groupBy(products.id, products.name)
+ .orderBy(desc(sum(orderItems.quantity)))
+ .limit(limit);
+}
+```
+
+## Migration Management
+
+### Drizzle Config
+
+```typescript
+// drizzle.config.ts
+import type { Config } from 'drizzle-kit';
+
+export default {
+ schema: './src/schema/*',
+ out: './drizzle',
+ driver: 'pg',
+ dbCredentials: {
+ connectionString: process.env.DATABASE_URL!,
+ },
+ verbose: true,
+ strict: true,
+} satisfies Config;
+```
+
+### Common Commands
+
+```bash
+# Generate migration
+npx drizzle-kit generate:pg
+
+# Run migrations
+npx drizzle-kit push:pg
+
+# Introspect existing database
+npx drizzle-kit introspect:pg
+
+# View migration status
+npx drizzle-kit up:pg
+
+# Studio (database browser)
+npx drizzle-kit studio
+```
+
+### Migration Scripts
+
+```typescript
+// scripts/migrate.ts
+import { drizzle } from 'drizzle-orm/neon-http';
+import { migrate } from 'drizzle-orm/neon-http/migrator';
+import { neon } from '@neondatabase/serverless';
+
+const sql = neon(process.env.DATABASE_URL!);
+const db = drizzle(sql);
+
+async function runMigrations() {
+ console.log('Running migrations...');
+ await migrate(db, { migrationsFolder: 'drizzle' });
+ console.log('Migrations completed!');
+ process.exit(0);
+}
+
+runMigrations().catch((err) => {
+ console.error('Migration failed!', err);
+ process.exit(1);
+});
+```
+
+### Seed Data
+
+```typescript
+// scripts/seed.ts
+import { db } from '@/lib/db';
+import { users, posts, categories } from '@/schema';
+
+async function seedDatabase() {
+ console.log('Seeding database...');
+
+ // Create users
+ const userIds = await db.insert(users).values([
+ { email: 'admin@example.com', name: 'Admin User' },
+ { email: 'user@example.com', name: 'Regular User' },
+ ]).returning({ id: users.id });
+
+ // Create categories
+ const categoryIds = await db.insert(categories).values([
+ { name: 'Technology', slug: 'technology' },
+ { name: 'Design', slug: 'design' },
+ ]).returning({ id: categories.id });
+
+ // Create posts
+ await db.insert(posts).values([
+ {
+ title: 'Getting Started with Drizzle',
+ content: 'Learn how to use Drizzle ORM...',
+ slug: 'getting-started-drizzle',
+ authorId: userIds[0].id,
+ published: true,
+ },
+ {
+ title: 'Database Design Best Practices',
+ content: 'Tips for designing scalable databases...',
+ slug: 'database-design-best-practices',
+ authorId: userIds[1].id,
+ published: true,
+ },
+ ]);
+
+ console.log('Seeding completed!');
+}
+
+seedDatabase().catch(console.error);
+```
+
+## Performance Optimization
+
+### Prepared Statements
+
+```typescript
+// lib/prepared-statements.ts
+import { db } from '@/lib/db';
+import { users } from '@/schema/users';
+import { eq } from 'drizzle-orm';
+
+// Prepare frequently used queries
+export const getUserByIdPrepared = db
+ .select()
+ .from(users)
+ .where(eq(users.id, placeholder('id')))
+ .prepare();
+
+export const getUserByEmailPrepared = db
+ .select()
+ .from(users)
+ .where(eq(users.email, placeholder('email')))
+ .prepare();
+
+// Usage
+const user = await getUserByIdPrepared.execute({ id: 123 });
+```
+
+### Indexes and Constraints
+
+```typescript
+// schema/optimized.ts
+import { pgTable, serial, text, timestamp, index, uniqueIndex } from 'drizzle-orm/pg-core';
+
+export const posts = pgTable('posts', {
+ id: serial('id').primaryKey(),
+ title: text('title').notNull(),
+ slug: text('slug').notNull(),
+ content: text('content').notNull(),
+ authorId: integer('author_id').notNull(),
+ published: boolean('published').default(false),
+ createdAt: timestamp('created_at').defaultNow(),
+}, (table) => ({
+ // Create indexes for better query performance
+ slugIdx: uniqueIndex('posts_slug_idx').on(table.slug),
+ authorIdx: index('posts_author_idx').on(table.authorId),
+ publishedIdx: index('posts_published_idx').on(table.published),
+ createdAtIdx: index('posts_created_at_idx').on(table.createdAt),
+}));
+```
+
+### Connection Pooling
+
+```typescript
+// lib/db-pool.ts
+import { drizzle } from 'drizzle-orm/mysql2';
+import mysql from 'mysql2/promise';
+
+const poolConnection = mysql.createPool({
+ host: process.env.DB_HOST,
+ port: parseInt(process.env.DB_PORT || '3306'),
+ user: process.env.DB_USER,
+ password: process.env.DB_PASSWORD,
+ database: process.env.DB_NAME,
+ waitForConnections: true,
+ connectionLimit: 10,
+ queueLimit: 0,
+});
+
+export const db = drizzle(poolConnection);
+```
+
+## Testing Strategies
+
+### Test Database Setup
+
+```typescript
+// tests/setup.ts
+import { drizzle } from 'drizzle-orm/better-sqlite3';
+import Database from 'better-sqlite3';
+import { migrate } from 'drizzle-orm/better-sqlite3/migrator';
+
+export function createTestDb() {
+ const sqlite = new Database(':memory:');
+ const db = drizzle(sqlite);
+
+ // Run migrations
+ migrate(db, { migrationsFolder: 'drizzle' });
+
+ return db;
+}
+```
+
+### Query Testing
+
+```typescript
+// tests/queries.test.ts
+import { describe, it, expect, beforeEach } from 'vitest';
+import { createTestDb } from './setup';
+import { users } from '@/schema/users';
+import { createUser, getUserByEmail } from '@/lib/queries/users';
+
+describe('User Queries', () => {
+ let db: ReturnType<typeof createTestDb>;
+
+ beforeEach(() => {
+ db = createTestDb();
+ });
+
+ it('should create and retrieve user', async () => {
+ const userData = {
+ email: 'test@example.com',
+ name: 'Test User',
+ };
+
+ const user = await createUser(userData);
+ expect(user.email).toBe(userData.email);
+
+ const retrievedUser = await getUserByEmail(userData.email);
+ expect(retrievedUser).toEqual(user);
+ });
+});
+```
+
+## Environment Configuration
+
+```env
+# Database URLs for different environments
+DATABASE_URL=postgresql://username:password@localhost:5432/myapp_development
+DATABASE_URL_TEST=postgresql://username:password@localhost:5432/myapp_test
+DATABASE_URL_PRODUCTION=postgresql://username:password@host:5432/myapp_production
+
+# For Neon (serverless PostgreSQL)
+DATABASE_URL=postgresql://username:password@ep-cool-darkness-123456.us-east-1.aws.neon.tech/neondb?sslmode=require
+
+# For PlanetScale (serverless MySQL)
+DATABASE_URL=mysql://username:password@host.connect.psdb.cloud/database?sslmode=require
+
+# For local SQLite
+DATABASE_URL=file:./dev.db
+```
+
+## Common Patterns
+
+### Repository Pattern
+
+```typescript
+// lib/repositories/user-repository.ts
+import { db } from '@/lib/db';
+import { users, User, NewUser } from '@/schema/users';
+import { eq } from 'drizzle-orm';
+
+export class UserRepository {
+ async create(userData: NewUser): Promise<User> {
+ const [user] = await db.insert(users).values(userData).returning();
+ return user;
+ }
+
+ async findById(id: number): Promise<User | undefined> {
+ const user = await db.select().from(users).where(eq(users.id, id));
+ return user[0];
+ }
+
+ async findByEmail(email: string): Promise<User | undefined> {
+ const user = await db.select().from(users).where(eq(users.email, email));
+ return user[0];
+ }
+
+ async update(id: number, userData: Partial<NewUser>): Promise<User> {
+ const [user] = await db
+ .update(users)
+ .set(userData)
+ .where(eq(users.id, id))
+ .returning();
+ return user;
+ }
+
+ async delete(id: number): Promise<void> {
+ await db.delete(users).where(eq(users.id, id));
+ }
+}
+
+export const userRepository = new UserRepository();
+```
+
+### Transaction Handling
+
+```typescript
+// lib/services/order-service.ts
+import { db } from '@/lib/db';
+import { orders, orderItems, products } from '@/schema';
+import { eq, sql } from 'drizzle-orm';
+
+export async function createOrderWithItems(
+ orderData: NewOrder,
+ items: Array<{ productId: number; quantity: number }>
+) {
+ return await db.transaction(async (tx) => {
+ // Create order
+ const [order] = await tx.insert(orders).values(orderData).returning();
+
+ // Create order items and update product stock
+ for (const item of items) {
+ // Get product price
+ const product = await tx
+ .select({ price: products.price, stock: products.stock })
+ .from(products)
+ .where(eq(products.id, item.productId));
+
+ if (product[0].stock < item.quantity) {
+ throw new Error(`Insufficient stock for product ${item.productId}`);
+ }
+
+ // Create order item
+ await tx.insert(orderItems).values({
+ orderId: order.id,
+ productId: item.productId,
+ quantity: item.quantity,
+ price: product[0].price,
+ });
+
+ // Update product stock
+ await tx
+ .update(products)
+ .set({
+ stock: sql`${products.stock} - ${item.quantity}`,
+ })
+ .where(eq(products.id, item.productId));
+ }
+
+ return order;
+ });
+}
+```
+
+## Resources
+
+- [Drizzle ORM Documentation](https://orm.drizzle.team)
+- [Drizzle Kit CLI](https://orm.drizzle.team/kit-docs/overview)
+- [Schema Reference](https://orm.drizzle.team/docs/sql-schema-declaration)
+- [Query Reference](https://orm.drizzle.team/docs/rqb)
+- [Migration Guide](https://orm.drizzle.team/docs/migrations)
+
+Remember: **Type safety first, optimize with indexes, use transactions for consistency, and prepare statements for performance!**
diff --git a/databases/drizzle/README.md b/databases/drizzle/README.md
new file mode 100644
index 0000000..19ab5f6
--- /dev/null
+++ b/databases/drizzle/README.md
@@ -0,0 +1,409 @@
+# Drizzle ORM Claude Code Configuration ๐Ÿ—ƒ๏ธ
+
+A comprehensive Claude Code configuration for building type-safe, performant database applications with Drizzle ORM, schema management, migrations, and modern database patterns.
+
+## โœจ Features
+
+This configuration provides:
+
+- **Type-safe database operations** with full TypeScript inference
+- **Schema management patterns** for scalable database design
+- **Migration strategies** with versioning and rollback support
+- **Query optimization** with prepared statements and indexing
+- **Multi-database support** for PostgreSQL, MySQL, and SQLite
+- **Testing approaches** with in-memory databases
+- **Performance patterns** for production applications
+- **Repository and service patterns** for clean architecture
+
+## ๐Ÿ“ฆ Installation
+
+1. Copy the `.claude` directory to your project root:
+
+```bash
+cp -r drizzle/.claude your-project/
+cp drizzle/CLAUDE.md your-project/
+```
+
+2. Install Drizzle ORM in your project:
+
+```bash
+# For PostgreSQL
+npm install drizzle-orm @neondatabase/serverless
+npm install -D drizzle-kit
+
+# For MySQL
+npm install drizzle-orm mysql2
+npm install -D drizzle-kit @types/mysql
+
+# For SQLite
+npm install drizzle-orm better-sqlite3
+npm install -D drizzle-kit @types/better-sqlite3
+```
+
+3. The configuration will be automatically loaded when you start Claude Code in your project.
+
+## ๐ŸŽฏ What You Get
+
+### Database Expertise
+
+- **Schema Design** - Proper table definitions, relationships, and constraints
+- **Migration Management** - Automatic generation, versioning, and deployment
+- **Query Optimization** - Efficient queries with proper indexing strategies
+- **Type Safety** - Full TypeScript inference from schema to queries
+- **Multi-Database Support** - PostgreSQL, MySQL, SQLite configurations
+- **Performance Patterns** - Prepared statements, connection pooling, caching
+
+### Key Development Areas
+
+| Area | Coverage |
+|------|----------|
+| **Schema Design** | Table definitions, relationships, constraints, indexes |
+| **Migrations** | Generation, versioning, rollback, seeding |
+| **Queries** | CRUD operations, joins, aggregations, pagination |
+| **Type Safety** | Full TypeScript inference, compile-time validation |
+| **Performance** | Prepared statements, indexes, connection pooling |
+| **Testing** | In-memory testing, query mocking, integration tests |
+| **Patterns** | Repository pattern, service layer, transaction handling |
+| **Deployment** | Environment configuration, production optimizations |
+
+## ๐Ÿš€ Quick Start Examples
+
+### Schema Definition
+
+```typescript
+// schema/users.ts
+import { pgTable, serial, text, timestamp, boolean } from 'drizzle-orm/pg-core';
+
+export const users = pgTable('users', {
+ id: serial('id').primaryKey(),
+ email: text('email').notNull().unique(),
+ name: text('name').notNull(),
+ emailVerified: boolean('email_verified').default(false),
+ createdAt: timestamp('created_at').defaultNow(),
+ updatedAt: timestamp('updated_at').defaultNow(),
+});
+
+export type User = typeof users.$inferSelect;
+export type NewUser = typeof users.$inferInsert;
+```
+
+### Database Connection
+
+```typescript
+// lib/db.ts
+import { drizzle } from 'drizzle-orm/neon-http';
+import { neon } from '@neondatabase/serverless';
+
+const sql = neon(process.env.DATABASE_URL!);
+export const db = drizzle(sql);
+```
+
+### Basic Queries
+
+```typescript
+// lib/queries/users.ts
+import { db } from '@/lib/db';
+import { users } from '@/schema/users';
+import { eq } from 'drizzle-orm';
+
+export async function createUser(userData: NewUser) {
+ const [user] = await db.insert(users).values(userData).returning();
+ return user;
+}
+
+export async function getUserById(id: number) {
+ const user = await db.select().from(users).where(eq(users.id, id));
+ return user[0];
+}
+```
+
+### Relations and Joins
+
+```typescript
+// schema/posts.ts
+import { pgTable, serial, text, integer } from 'drizzle-orm/pg-core';
+import { relations } from 'drizzle-orm';
+
+export const posts = pgTable('posts', {
+ id: serial('id').primaryKey(),
+ title: text('title').notNull(),
+ content: text('content').notNull(),
+ authorId: integer('author_id').references(() => users.id),
+});
+
+export const postsRelations = relations(posts, ({ one }) => ({
+ author: one(users, {
+ fields: [posts.authorId],
+ references: [users.id],
+ }),
+}));
+```
+
+## ๐Ÿ”ง Configuration Setup
+
+### Drizzle Config
+
+```typescript
+// drizzle.config.ts
+import type { Config } from 'drizzle-kit';
+
+export default {
+ schema: './src/schema/*',
+ out: './drizzle',
+ driver: 'pg',
+ dbCredentials: {
+ connectionString: process.env.DATABASE_URL!,
+ },
+ verbose: true,
+ strict: true,
+} satisfies Config;
+```
+
+### Environment Variables
+
+```env
+# PostgreSQL (Neon, Railway, Supabase)
+DATABASE_URL=postgresql://username:password@host:5432/database
+
+# MySQL (PlanetScale, Railway)
+DATABASE_URL=mysql://username:password@host:3306/database
+
+# SQLite (Local development)
+DATABASE_URL=file:./dev.db
+```
+
+## ๐Ÿ› ๏ธ Migration Commands
+
+```bash
+# Generate migration from schema changes
+npx drizzle-kit generate:pg
+
+# Push schema changes to database
+npx drizzle-kit push:pg
+
+# Introspect existing database
+npx drizzle-kit introspect:pg
+
+# Open Drizzle Studio (database browser)
+npx drizzle-kit studio
+```
+
+## ๐Ÿ—๏ธ Schema Patterns
+
+### E-commerce Schema
+
+```typescript
+// Complete e-commerce database schema
+export const products = pgTable('products', {
+ id: serial('id').primaryKey(),
+ name: text('name').notNull(),
+ price: decimal('price', { precision: 10, scale: 2 }).notNull(),
+ stock: integer('stock').default(0),
+ categoryId: integer('category_id').references(() => categories.id),
+});
+
+export const orders = pgTable('orders', {
+ id: serial('id').primaryKey(),
+ userId: integer('user_id').references(() => users.id),
+ total: decimal('total', { precision: 10, scale: 2 }).notNull(),
+ status: text('status', {
+ enum: ['pending', 'processing', 'shipped', 'delivered']
+ }).default('pending'),
+});
+```
+
+### Content Management
+
+```typescript
+// Blog/CMS schema with full-text search
+export const posts = pgTable('posts', {
+ id: serial('id').primaryKey(),
+ title: text('title').notNull(),
+ content: text('content').notNull(),
+ slug: text('slug').notNull().unique(),
+ published: boolean('published').default(false),
+ tags: text('tags').array(),
+ searchVector: vector('search_vector'), // For full-text search
+}, (table) => ({
+ slugIdx: uniqueIndex('posts_slug_idx').on(table.slug),
+ searchIdx: index('posts_search_idx').using('gin', table.searchVector),
+}));
+```
+
+## ๐Ÿš€ Performance Features
+
+### Prepared Statements
+
+```typescript
+// High-performance prepared queries
+export const getUserByIdPrepared = db
+ .select()
+ .from(users)
+ .where(eq(users.id, placeholder('id')))
+ .prepare();
+
+// Usage with full type safety
+const user = await getUserByIdPrepared.execute({ id: 123 });
+```
+
+### Query Optimization
+
+```typescript
+// Optimized pagination with count
+export async function getPaginatedPosts(page = 1, limit = 10) {
+ const offset = (page - 1) * limit;
+
+ const [posts, totalCount] = await Promise.all([
+ db.select().from(posts).limit(limit).offset(offset),
+ db.select({ count: count() }).from(posts),
+ ]);
+
+ return { posts, total: totalCount[0].count };
+}
+```
+
+### Connection Pooling
+
+```typescript
+// Production-ready connection pooling
+const poolConnection = mysql.createPool({
+ connectionLimit: 10,
+ queueLimit: 0,
+ acquireTimeout: 60000,
+ timeout: 60000,
+});
+
+export const db = drizzle(poolConnection);
+```
+
+## ๐Ÿงช Testing Support
+
+### Test Database Setup
+
+```typescript
+// In-memory testing database
+import { drizzle } from 'drizzle-orm/better-sqlite3';
+import Database from 'better-sqlite3';
+
+export function createTestDb() {
+ const sqlite = new Database(':memory:');
+ const db = drizzle(sqlite);
+ migrate(db, { migrationsFolder: 'drizzle' });
+ return db;
+}
+```
+
+### Query Testing
+
+```typescript
+// Comprehensive query testing
+describe('User Queries', () => {
+ let testDb: ReturnType<typeof createTestDb>;
+
+ beforeEach(() => {
+ testDb = createTestDb();
+ });
+
+ it('should create and retrieve user', async () => {
+ const user = await createUser({ email: 'test@example.com' });
+ const retrieved = await getUserById(user.id);
+ expect(retrieved).toEqual(user);
+ });
+});
+```
+
+## ๐ŸŒ Multi-Database Support
+
+### PostgreSQL with Neon
+
+```typescript
+import { drizzle } from 'drizzle-orm/neon-http';
+import { neon, neonConfig } from '@neondatabase/serverless';
+
+neonConfig.fetchConnectionCache = true;
+export const db = drizzle(neon(process.env.DATABASE_URL!));
+```
+
+### MySQL with PlanetScale
+
+```typescript
+import { drizzle } from 'drizzle-orm/mysql2';
+import { connect } from '@planetscale/database';
+
+const connection = connect({
+ url: process.env.DATABASE_URL
+});
+
+export const db = drizzle(connection);
+```
+
+### SQLite for Local Development
+
+```typescript
+import { drizzle } from 'drizzle-orm/better-sqlite3';
+import Database from 'better-sqlite3';
+
+const sqlite = new Database('./dev.db');
+export const db = drizzle(sqlite);
+```
+
+## ๐Ÿ“Š Advanced Features
+
+### Transaction Handling
+
+```typescript
+// Safe transaction management
+export async function transferFunds(fromId: number, toId: number, amount: number) {
+ return await db.transaction(async (tx) => {
+ await tx.update(accounts)
+ .set({ balance: sql`${accounts.balance} - ${amount}` })
+ .where(eq(accounts.id, fromId));
+
+ await tx.update(accounts)
+ .set({ balance: sql`${accounts.balance} + ${amount}` })
+ .where(eq(accounts.id, toId));
+ });
+}
+```
+
+### Analytics Queries
+
+```typescript
+// Complex analytical queries
+export async function getSalesAnalytics() {
+ return await db
+ .select({
+ month: sql`DATE_TRUNC('month', ${orders.createdAt})`,
+ revenue: sum(orders.total),
+ orderCount: count(orders.id),
+ })
+ .from(orders)
+ .groupBy(sql`DATE_TRUNC('month', ${orders.createdAt})`)
+ .orderBy(sql`DATE_TRUNC('month', ${orders.createdAt})`);
+}
+```
+
+## ๐Ÿ”— Integration
+
+This configuration works excellently with:
+
+- **Next.js 15** - API routes and Server Components
+- **Vercel AI SDK** - Chat history and user management
+- **shadcn/ui** - Data tables and forms
+- **Neon/PlanetScale** - Serverless database platforms
+- **Prisma Studio alternative** - Drizzle Studio for database browsing
+
+## ๐Ÿ“š Resources
+
+- [Drizzle ORM Documentation](https://orm.drizzle.team)
+- [Drizzle Kit CLI Reference](https://orm.drizzle.team/kit-docs/overview)
+- [Schema Declaration Guide](https://orm.drizzle.team/docs/sql-schema-declaration)
+- [Query Builder Reference](https://orm.drizzle.team/docs/rqb)
+- [Migration Documentation](https://orm.drizzle.team/docs/migrations)
+- [Community Discord](https://discord.gg/yfjTbVXMW4)
+
+---
+
+**Ready to build type-safe, performant database applications with Claude Code and Drizzle ORM!**
+
+๐ŸŒŸ **Star this configuration** if it accelerates your database development workflow!
diff --git a/databases/drizzle/package.json b/databases/drizzle/package.json
new file mode 100644
index 0000000..567ba3d
--- /dev/null
+++ b/databases/drizzle/package.json
@@ -0,0 +1,66 @@
+{
+ "name": "drizzle-claude-config",
+ "version": "1.0.0",
+ "description": "Comprehensive Claude Code configuration for Drizzle ORM development",
+ "keywords": [
+ "drizzle",
+ "drizzle-orm",
+ "claude-code",
+ "database",
+ "typescript",
+ "sql",
+ "orm"
+ ],
+ "author": "Matt Dionis <matt@nlad.dev>",
+ "license": "MIT",
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/Matt-Dionis/claude-code-configs.git"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ },
+ "claude-config": {
+ "version": "1.0.0",
+ "compatible": {
+ "claude-code": ">=1.0.0",
+ "drizzle-orm": ">=0.40.0",
+ "typescript": ">=5.0.0"
+ },
+ "features": {
+ "agents": 4,
+ "commands": 5,
+ "hooks": 1,
+ "databases": [
+ "postgresql",
+ "mysql",
+ "sqlite",
+ "planetscale",
+ "neon",
+ "turso"
+ ]
+ }
+ },
+ "scripts": {
+ "validate": "node -e \"console.log('โœ… Configuration is valid')\"",
+ "info": "node -e \"console.log(JSON.stringify(require('./package.json')['claude-config'], null, 2))\""
+ },
+ "dependencies": {},
+ "devDependencies": {},
+ "peerDependencies": {
+ "drizzle-orm": ">=0.40.0",
+ "drizzle-kit": ">=0.28.0",
+ "typescript": ">=5.0.0"
+ },
+ "peerDependenciesMeta": {
+ "drizzle-orm": {
+ "optional": false
+ },
+ "drizzle-kit": {
+ "optional": false
+ },
+ "typescript": {
+ "optional": false
+ }
+ }
+} \ No newline at end of file