Patterns de Base de Données (Drizzle ORM)

VérifiéSûr

Fournit des patrons de base de données pour PostgreSQL avec Drizzle ORM, incluant une couche d'accès aux données basée sur le pattern Repository. Impose des conventions comme les noms en snake_case, les clés primaires UUID et les timestamps. Inclut un workflow de migration et des motifs de requêtes courants pour le filtrage.

Spar Skills Guide Bot
DeveloppementIntermédiaire
18002/06/2026
Claude Code
#database#drizzle-orm#postgresql#repository-pattern#migrations

Recommandé pour

Notre avis

Fournit des modèles de base de données PostgreSQL avec Drizzle ORM, incluant des schémas, des repositories et des workflows de migration.

Points forts

  • Encapsulation des requêtes via des repositories réutilisables
  • Conventions claires pour les noms de tables et colonnes
  • Gestion des migrations intégrée avec nommage standardisé

Limites

  • Limité à PostgreSQL et Drizzle ORM
  • Ne couvre pas les tests ou le seeding de données
  • Les repositories génériques peuvent devenir verbeux pour des cas simples
Quand l'utiliser

Quand vous bâtissez une application avec Drizzle ORM et voulez une structure de couche d'accès aux données cohérente et maintenable.

Quand l'éviter

Si la base de données est très simple et peut-être gérée directement, ou si vous utilisez un ORM différent.

Analyse de sécurité

Sûr
Score qualité92/100

The skill provides code patterns and best practices for Drizzle ORM usage. It contains no destructive, exfiltrating, or evasive instructions. All commands shown are standard development operations (e.g., migrations) and no sensitive data handling is demonstrated.

Aucun point d'attention détecté

Exemples

Create Repository
Create a new repository for the 'comments' table following Drizzle ORM patterns with findById, create, update, delete methods.
Generate Migration
Generate a migration named 'add_category_to_posts' to add a text column 'category' to the posts table using Drizzle ORM.

Database Skill (Drizzle ORM)

This skill provides database patterns for PostgreSQL with Drizzle ORM. Run /db for full reference.

Project Structure

src/db/
├── index.ts           # Singleton db connection
├── schema.ts          # All table definitions
├── migrate.ts         # Migration runner
└── repositories/      # Data access layer (REQUIRED)

CRITICAL: Always Use Repositories

NEVER access db directly. Always use repository classes.

// ✅ CORRECT
import { featureRepository } from '@/db/repositories/feature.repository';
const feature = await featureRepository.findById(id);

// ❌ WRONG - Direct db access
import { db } from '@/db';
const feature = await db.select().from(features); // NEVER DO THIS

Schema Definition

// src/db/schema.ts
import { pgTable, uuid, text, timestamp, integer } from 'drizzle-orm/pg-core';

export const posts = pgTable('posts', {
  id: uuid('id').defaultRandom().primaryKey(),
  title: text('title').notNull(),
  content: text('content'),
  userId: uuid('user_id').references(() => users.id, { onDelete: 'cascade' }),
  status: text('status').notNull().default('draft'),
  priority: integer('priority').notNull().default(0),
  createdAt: timestamp('created_at').defaultNow().notNull(),
  updatedAt: timestamp('updated_at').defaultNow().notNull(),
});

// Type exports
export type Post = typeof posts.$inferSelect;
export type NewPost = typeof posts.$inferInsert;

Schema Conventions

  • Table names: lowercase plural (users, posts)
  • Column names: snake_case (created_at, user_id)
  • Primary keys: UUID with defaultRandom()
  • Timestamps: Always include created_at and updated_at

Repository Pattern

// src/db/repositories/post.repository.ts
import { eq, and, desc, asc } from 'drizzle-orm';
import { db, schema } from '@/db';
import type { Post, NewPost } from '@/db/schema';

export class PostRepository {
  async findById(id: string): Promise<Post | null> {
    return await db.query.posts.findFirst({
      where: eq(schema.posts.id, id),
    }) ?? null;
  }

  async findMany(limit = 10, offset = 0): Promise<Post[]> {
    return await db.query.posts.findMany({
      limit,
      offset,
      orderBy: desc(schema.posts.createdAt),
    });
  }

  async findByUserId(userId: string): Promise<Post[]> {
    return await db.query.posts.findMany({
      where: eq(schema.posts.userId, userId),
      orderBy: (posts, { desc }) => [desc(posts.createdAt)],
    });
  }

  async create(data: NewPost): Promise<Post> {
    const result = await db
      .insert(schema.posts)
      .values({
        ...data,
        createdAt: new Date(),
        updatedAt: new Date(),
      })
      .returning();
    return result[0];
  }

  async update(id: string, data: Partial<NewPost>): Promise<Post | null> {
    const result = await db
      .update(schema.posts)
      .set({
        ...data,
        updatedAt: new Date(),
      })
      .where(eq(schema.posts.id, id))
      .returning();
    return result[0] ?? null;
  }

  async delete(id: string): Promise<boolean> {
    const result = await db
      .delete(schema.posts)
      .where(eq(schema.posts.id, id))
      .returning();
    return result.length > 0;
  }
}

export const postRepository = new PostRepository();

Migration Workflow

# 1. Edit src/db/schema.ts
# 2. Generate migration
bun db:generate --name=create_posts_table

# 3. Review SQL in drizzle/migrations/
# 4. Apply migration
bun db:migrate

# 5. Commit migration files
git add drizzle/migrations/

Migration Naming

  • Use snake_case: create_posts_table, add_user_role_column
  • Start with action: create_, add_, update_, remove_

Common Query Patterns

Filtering with Multiple Conditions

import { eq, and, or, isNull, isNotNull, gt, lt, like } from 'drizzle-orm';

// AND conditions
where: and(
  eq(schema.posts.userId, userId),
  eq(schema.posts.status, 'published')
)

// OR conditions
where: or(
  eq(schema.posts.status, 'draft'),
  eq(schema.posts.status, 'review')
)

// NULL checks
where: isNull(schema.posts.deletedAt)

// Comparisons
where: gt(schema.posts.priority, 5)

// LIKE
where: like(schema.posts.title, '%search%')

Ordering

// Single column
orderBy: desc(schema.posts.createdAt)

// Multiple columns
orderBy: (posts, { asc, desc }) => [
  asc(posts.status),
  desc(posts.priority),
  desc(posts.createdAt),
]

Relations (with query API)

// In schema.ts - define relations
import { relations } from 'drizzle-orm';

export const postsRelations = relations(posts, ({ one, many }) => ({
  author: one(users, {
    fields: [posts.userId],
    references: [users.id],
  }),
  comments: many(comments),
}));

// In repository - query with relations
async findWithAuthor(id: string) {
  return await db.query.posts.findFirst({
    where: eq(schema.posts.id, id),
    with: {
      author: true,
      comments: true,
    },
  });
}

Database Client Setup

// src/db/index.ts
import { drizzle } from 'drizzle-orm/postgres-js';
import postgres from 'postgres';
import * as schema from './schema';

const client = postgres(process.env.DATABASE_URL!, {
  max: process.env.NODE_ENV === 'production' ? 10 : 1,
  idle_timeout: 20,
  max_lifetime: 60 * 30,
});

export const db = drizzle(client, { schema });
export type Database = typeof db;
export { schema };

Common Imports

// Schema and types
import { db, schema } from '@/db';
import type { Post, NewPost } from '@/db/schema';

// Query operators
import { eq, and, or, gt, lt, gte, lte, like, isNull, isNotNull, desc, asc } from 'drizzle-orm';

// Table definitions (for insert/update)
import { pgTable, uuid, text, timestamp, integer, jsonb, boolean } from 'drizzle-orm/pg-core';

// Relations
import { relations } from 'drizzle-orm';
Skills similaires