Comparação de ORMs
Usuários & Posts
Gerenciando dados com Drizzle ORM
1 usuário
Novo Usuário
Novo Post
Comparação de ORMs
Gerenciando dados com Drizzle ORM
Comparativo de código
Schema e configuração lado a lado, com pontos rápidos sobre o que muda em cada ORM.
import { integer, sqliteTable, text } from 'drizzle-orm/sqlite-core'
import { relations } from 'drizzle-orm'
export const users = sqliteTable('users', {
id: integer('id').primaryKey({ autoIncrement: true }),
name: text('name').notNull(),
email: text('email').unique().notNull(),
birthDate: text('birth_date').notNull(),
createdAt: integer('created_at', { mode: 'timestamp' }).$defaultFn(() => new Date()),
})
export const usersRelations = relations(users, ({ many }) => ({
posts: many(posts),
}))
export const posts = sqliteTable('posts', {
id: integer('id').primaryKey({ autoIncrement: true }),
title: text('title').notNull(),
content: text('content').notNull(),
userId: integer('user_id').notNull().references(() => users.id, { onDelete: 'cascade' }),
createdAt: integer('created_at', { mode: 'timestamp' }).$defaultFn(() => new Date()),
})
export const postsRelations = relations(posts, ({ one }) => ({
user: one(users, {
fields: [posts.userId],
references: [users.id],
}),
}))
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema
generator client {
provider = "prisma-client"
output = "../src/generated/prisma"
}
datasource db {
provider = "sqlite"
}
model User {
id Int @id @default(autoincrement())
name String
email String @unique
birthDate String @map("birth_date")
createdAt DateTime @default(now()) @map("created_at")
posts Post[]
@@map("users")
}
model Post {
id Int @id @default(autoincrement())
title String
content String
userId Int @map("user_id")
createdAt DateTime @default(now()) @map("created_at")
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@map("posts")
}
import 'dotenv/config'
import { defineConfig } from 'drizzle-kit'
export default defineConfig({
out: './drizzle',
schema: './src/db/schema.ts',
dialect: 'sqlite',
dbCredentials: {
url: process.env.DATABASE_URL!,
},
})
// This file was generated by Prisma, and assumes you have installed the following:
// npm install --save-dev prisma dotenv
import 'dotenv/config'
import { defineConfig } from 'prisma/config'
export default defineConfig({
schema: 'prisma/schema.prisma',
migrations: {
path: 'prisma/migrations',
},
datasource: {
url: process.env['DATABASE_URL'],
},
})
Clients
Como cada ORM cria o client conectado ao SQLite/libSQL e expõe helpers tipados.
@libsql/client, injeta o schema e reexporta tabelas.import 'dotenv/config'
import { drizzle } from 'drizzle-orm/libsql'
import { createClient } from '@libsql/client'
import * as schema from './schema'
const client = createClient({
url: process.env.DATABASE_URL!,
})
export const db = drizzle(client, { schema })
export * from './schema'
PrismaLibSql como adapter e instancia o client gerado.import { PrismaLibSql } from '@prisma/adapter-libsql'
import { PrismaClient } from '@/generated/prisma/client'
const adapter = new PrismaLibSql({
url: process.env.DATABASE_URL!,
})
export const prisma = new PrismaClient({ adapter })
Requisições CRUD
Como o fluxo de criar, ler e deletar é escrito em cada ORM.
db.insert, db.query e helpers como eq.'use server'
import { db, users, posts } from '@/db'
import { revalidatePath } from 'next/cache'
import { eq } from 'drizzle-orm'
export async function createUserDrizzle(formData: FormData) {
const name = formData.get('name') as string
const email = formData.get('email') as string
const birthDate = formData.get('birthDate') as string
if (!name || !email || !birthDate) {
return { error: 'Todos os campos são obrigatórios' }
}
try {
await db.insert(users).values({
name,
email,
birthDate,
})
revalidatePath('/')
return { success: true }
} catch (error) {
if (error instanceof Error && error.message.includes('UNIQUE')) {
return { error: 'Este email já está cadastrado' }
}
return { error: 'Erro ao criar usuário' }
}
}
export async function createPostDrizzle(formData: FormData) {
const title = formData.get('title') as string
const content = formData.get('content') as string
const userId = formData.get('userId') as string
if (!title || !content || !userId) {
return { error: 'Todos os campos são obrigatórios' }
}
try {
await db.insert(posts).values({
title,
content,
userId: parseInt(userId),
})
revalidatePath('/')
return { success: true }
} catch (error) {
return { error: 'Erro ao criar post' }
}
}
export async function updateUserDrizzle(formData: FormData) {
const id = formData.get('id')
const name = formData.get('name') as string
const email = formData.get('email') as string
const birthDate = formData.get('birthDate') as string
const userId = Number(id)
if (!id || Number.isNaN(userId)) {
return { error: 'ID do usuário é obrigatório' }
}
const updateData: Partial<typeof users.$inferInsert> = {}
if (name) updateData.name = name
if (email) updateData.email = email
if (birthDate) updateData.birthDate = birthDate
if (Object.keys(updateData).length === 0) {
return { error: 'Nenhum campo para atualizar' }
}
try {
await db.update(users).set(updateData).where(eq(users.id, userId))
revalidatePath('/')
return { success: true }
} catch (error) {
if (error instanceof Error && error.message.includes('UNIQUE')) {
return { error: 'Este email já está cadastrado' }
}
return { error: 'Erro ao atualizar usuário' }
}
}
export async function updatePostDrizzle(formData: FormData) {
const id = formData.get('id')
const title = formData.get('title') as string
const content = formData.get('content') as string
const userId = formData.get('userId') as string
const postId = Number(id)
const parsedUserId = userId ? Number(userId) : undefined
if (!id || Number.isNaN(postId)) {
return { error: 'ID do post é obrigatório' }
}
if (parsedUserId !== undefined && Number.isNaN(parsedUserId)) {
return { error: 'Usuário do post inválido' }
}
const updateData: Partial<typeof posts.$inferInsert> = {}
if (title) updateData.title = title
if (content) updateData.content = content
if (parsedUserId !== undefined) updateData.userId = parsedUserId
if (Object.keys(updateData).length === 0) {
return { error: 'Nenhum campo para atualizar' }
}
try {
await db.update(posts).set(updateData).where(eq(posts.id, postId))
revalidatePath('/')
return { success: true }
} catch (error) {
return { error: 'Erro ao atualizar post' }
}
}
export async function getUsersDrizzle() {
return await db.query.users.findMany({
with: {
posts: {
orderBy: (posts, { desc }) => [desc(posts.createdAt)],
},
},
orderBy: (users, { desc }) => [desc(users.createdAt)],
})
}
export async function deleteUserDrizzle(userId: number) {
try {
await db.delete(users).where(eq(users.id, userId))
revalidatePath('/')
return { success: true }
} catch (error) {
return { error: 'Erro ao deletar usuário' }
}
}
export async function deletePostDrizzle(postId: number) {
try {
await db.delete(posts).where(eq(posts.id, postId))
revalidatePath('/')
return { success: true }
} catch (error) {
return { error: 'Erro ao deletar post' }
}
}
prisma.user.create, findMany) e inclusão de relações via include.'use server'
import { prisma } from '@/db/prisma'
import { revalidatePath } from 'next/cache'
export async function createUserPrisma(formData: FormData) {
const name = formData.get('name') as string
const email = formData.get('email') as string
const birthDate = formData.get('birthDate') as string
if (!name || !email || !birthDate) {
return { error: 'Todos os campos são obrigatórios' }
}
try {
await prisma.user.create({
data: {
name,
email,
birthDate,
},
})
revalidatePath('/')
return { success: true }
} catch (error) {
if (error instanceof Error && error.message.includes('Unique')) {
return { error: 'Este email já está cadastrado' }
}
return { error: 'Erro ao criar usuário' }
}
}
export async function createPostPrisma(formData: FormData) {
const title = formData.get('title') as string
const content = formData.get('content') as string
const userId = formData.get('userId') as string
if (!title || !content || !userId) {
return { error: 'Todos os campos são obrigatórios' }
}
try {
await prisma.post.create({
data: {
title,
content,
userId: parseInt(userId),
},
})
revalidatePath('/')
return { success: true }
} catch (error) {
return { error: 'Erro ao criar post' }
}
}
export async function updateUserPrisma(formData: FormData) {
const id = formData.get('id')
const name = formData.get('name') as string
const email = formData.get('email') as string
const birthDate = formData.get('birthDate') as string
const userId = Number(id)
if (!id || Number.isNaN(userId)) {
return { error: 'ID do usuário é obrigatório' }
}
const data: {
name?: string
email?: string
birthDate?: string
} = {}
if (name) data.name = name
if (email) data.email = email
if (birthDate) data.birthDate = birthDate
if (Object.keys(data).length === 0) {
return { error: 'Nenhum campo para atualizar' }
}
try {
await prisma.user.update({
where: { id: userId },
data,
})
revalidatePath('/')
return { success: true }
} catch (error) {
if (error instanceof Error && error.message.includes('Unique')) {
return { error: 'Este email já está cadastrado' }
}
return { error: 'Erro ao atualizar usuário' }
}
}
export async function updatePostPrisma(formData: FormData) {
const id = formData.get('id')
const title = formData.get('title') as string
const content = formData.get('content') as string
const userId = formData.get('userId') as string
const postId = Number(id)
const parsedUserId = userId ? Number(userId) : undefined
if (!id || Number.isNaN(postId)) {
return { error: 'ID do post é obrigatório' }
}
if (parsedUserId !== undefined && Number.isNaN(parsedUserId)) {
return { error: 'Usuário do post inválido' }
}
const data: {
title?: string
content?: string
userId?: number
} = {}
if (title) data.title = title
if (content) data.content = content
if (parsedUserId !== undefined) data.userId = parsedUserId
if (Object.keys(data).length === 0) {
return { error: 'Nenhum campo para atualizar' }
}
try {
await prisma.post.update({
where: { id: postId },
data,
})
revalidatePath('/')
return { success: true }
} catch (error) {
return { error: 'Erro ao atualizar post' }
}
}
export async function getUsersPrisma() {
return await prisma.user.findMany({
include: {
posts: {
orderBy: { createdAt: 'desc' },
},
},
orderBy: { createdAt: 'desc' },
})
}
export async function deleteUserPrisma(userId: number) {
try {
await prisma.user.delete({
where: { id: userId },
})
revalidatePath('/')
return { success: true }
} catch (error) {
return { error: 'Erro ao deletar usuário' }
}
}
export async function deletePostPrisma(postId: number) {
try {
await prisma.post.delete({
where: { id: postId },
})
revalidatePath('/')
return { success: true }
} catch (error) {
return { error: 'Erro ao deletar post' }
}
}
prisma migrate/generate no CI.include/select e writes aninhados (create com posts: { create: [...] }).revalidatePath ou cache por tags para evitar re-fetch completo após mutações maiores.