Skip to main content
Glama
drizzle.ts7.03 kB
import { pgTable, text, timestamp, integer, boolean, foreignKey } from 'drizzle-orm/pg-core'; import { drizzle } from 'drizzle-orm/node-postgres'; import { eq, like, desc, sql, and } from 'drizzle-orm'; import { Pool } from 'pg'; import { migrate } from 'drizzle-orm/node-postgres/migrator'; // ============================================ // Schema Definition // ============================================ export const users = pgTable('users', { id: integer('id').primaryKey().generatedAlwaysAsIdentity(), email: text('email').unique().notNull(), name: text('name').notNull(), passwordHash: text('password_hash').notNull(), role: text('role', { enum: ['user', 'admin'] }).default('user'), createdAt: timestamp('created_at').defaultNow(), updatedAt: timestamp('updated_at').defaultNow(), }); export const posts = pgTable('posts', { id: integer('id').primaryKey().generatedAlwaysAsIdentity(), authorId: integer('author_id').references(() => users.id, { onDelete: 'cascade' }), title: text('title').notNull(), content: text('content'), published: boolean('published').default(false), viewCount: integer('view_count').default(0), createdAt: timestamp('created_at').defaultNow(), updatedAt: timestamp('updated_at').defaultNow(), }); export const comments = pgTable('comments', { id: integer('id').primaryKey().generatedAlwaysAsIdentity(), postId: integer('post_id').references(() => posts.id, { onDelete: 'cascade' }), authorId: integer('author_id').references(() => users.id, { onDelete: 'set null' }), content: text('content').notNull(), createdAt: timestamp('created_at').defaultNow(), }); // ============================================ // Database Connection // ============================================ const pool = new Pool({ connectionString: process.env.DATABASE_URL || 'postgres://postgres:password@localhost:5432/myapp', }); // Create Drizzle instance export const db = drizzle(pool, { schema: { users, posts, comments }, }); // ============================================ // Types (Inferred) // ============================================ export type User = typeof users.$inferSelect; export type NewUser = typeof users.$inferInsert; export type Post = typeof posts.$inferSelect; export type NewPost = typeof posts.$inferInsert; // ============================================ // Repository Pattern Example // ============================================ export class UserRepository { static async getAll() { return db.select().from(users).orderBy(desc(users.createdAt)); } static async getById(id: number) { return db.query.users.findFirst({ where: eq(users.id, id), with: { posts: { limit: 5, orderBy: desc(posts.createdAt), }, }, }); } static async getByEmail(email: string) { return db.query.users.findFirst({ where: eq(users.email, email), }); } static async create(data: NewUser) { const result = await db.insert(users).values(data).returning(); return result[0]; } static async update(id: number, data: Partial<NewUser>) { const result = await db .update(users) .set({ ...data, updatedAt: new Date() }) .where(eq(users.id, id)) .returning(); return result[0]; } static async delete(id: number) { return db.delete(users).where(eq(users.id, id)).returning(); } } export class PostRepository { static async getFeed(limit = 20, offset = 0) { return db.query.posts.findMany({ where: eq(posts.published, true), limit, offset, orderBy: desc(posts.createdAt), with: { author: { columns: { id: true, name: true, email: true, }, }, comments: { limit: 3, with: { author: { columns: { name: true }, }, }, }, }, }); } static async search(term: string) { return db .select() .from(posts) .where( and( eq(posts.published, true), like(posts.title, `%${term}%`) ) ); } static async create(data: NewPost) { return db.insert(posts).values(data).returning(); } static async incrementViewCount(id: number) { return db .update(posts) .set({ viewCount: sql`${posts.viewCount} + 1` }) .where(eq(posts.id, id)) .returning(); } } // ============================================ // Migration Runner // ============================================ export async function runMigrations() { console.log('Running migrations...'); try { await migrate(db, { migrationsFolder: './drizzle' }); console.log('Migrations completed successfully'); } catch (error) { console.error('Migration failed:', error); process.exit(1); } } // ============================================ // Seeding Helper // ============================================ export async function seed() { console.log('Seeding database...'); // Clear existing data await db.delete(comments); await db.delete(posts); await db.delete(users); // Create users const [user1] = await db.insert(users).values({ email: 'alice@example.com', name: 'Alice', passwordHash: 'hashed_password', role: 'admin', }).returning(); const [user2] = await db.insert(users).values({ email: 'bob@example.com', name: 'Bob', passwordHash: 'hashed_password', role: 'user', }).returning(); // Create posts await db.insert(posts).values([ { title: 'Hello Drizzle', content: 'Drizzle ORM is awesome!', authorId: user1.id, published: true, }, { title: 'Draft Post', content: 'Work in progress...', authorId: user1.id, published: false, }, { title: 'Bob\'s Thoughts', content: 'TypeScript is great.', authorId: user2.id, published: true, }, ]); console.log('Seeding completed'); } // ============================================ // Usage Example // ============================================ /* import { UserRepository, PostRepository } from './db'; async function main() { const users = await UserRepository.getAll(); const feed = await PostRepository.getFeed(); console.log({ users, feed }); } */

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/millsydotdev/Code-MCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server