Skip to main content
Glama
drizzle.ts6.39 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