Skip to content

Commit 4ebcb3f

Browse files
committed
feat: Add database skill with Drizzle ORM and bun:sqlite
1 parent c4b28aa commit 4ebcb3f

File tree

10 files changed

+478
-115
lines changed

10 files changed

+478
-115
lines changed

.agent/skills/riligar-design-system/references/design-system.md

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -104,10 +104,3 @@ Ao pedir código ou design para uma IA, use este formato:
104104
- **Modais:** Devem ter um backdrop com blur (`backdrop-blur-sm`) e fundo branco sólido. Sem cabeçalhos coloridos.
105105
- **Dashboards:** Devem privilegiar números grandes (Big Numbers) em monocromia, com rótulos pequenos abaixo. Gráficos devem ser limpos, sem grid lines pesadas.
106106

107-
---
108-
109-
## 🤖 Integração com Gemini CLI
110-
111-
Este repositório possui uma **Skill do Gemini CLI** configurada em [`riligar-design-system/SKILL.md`](../SKILL.md). Ao usar o Gemini CLI neste repositório, o agente aplicará automaticamente estas diretrizes a qualquer código ou design gerado.
112-
113-
Para saber como usar, veja o [README principal](../../README.md).
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
---
2+
name: riligar-dev-database
3+
description: Database patterns for RiLiGar using Drizzle ORM + bun:sqlite. Use when setting up database connections, defining schemas, creating migrations, or writing queries. Covers SQLite on Fly.io volumes with the drizzle-kit workflow.
4+
---
5+
6+
# Database — Drizzle + bun:sqlite
7+
8+
> SQLite nativo no Bun. Zero drivers externos. Base de dados no volume do Fly.io (`/app/data`).
9+
10+
## Referências
11+
12+
| Arquivo | Quando usar |
13+
| --- | --- |
14+
| [connection.md](references/connection.md) | Setup inicial: instalação, db.js, drizzle.config |
15+
| [schema.md](references/schema.md) | Definir tabelas, tipos de colunas, relações |
16+
| [migrations.md](references/migrations.md) | Criar e executar migrations com drizzle-kit |
17+
| [queries.md](references/queries.md) | Select, insert, update, delete, queries com relações |
18+
19+
## Quick Start
20+
21+
```javascript
22+
// database/db.js
23+
import { drizzle } from 'drizzle-orm/bun-sqlite'
24+
import Database from 'bun:sqlite'
25+
26+
const sqlite = new Database(process.env.DB_PATH ?? './data/database.db')
27+
const db = drizzle({ client: sqlite })
28+
29+
export { db }
30+
```
31+
32+
## Regras
33+
34+
- **Caminho do banco:** `/app/data/database.db` em produção (volume Fly.io). `./data/database.db` em desenvolvimento.
35+
- **Migrations sempre:** Use `drizzle-kit generate` + `drizzle-kit migrate`. Nunca edite migrations à mão.
36+
- **Schema único:** Todas as tabelas em `database/schema.js`.
37+
- **Migrations no startup:** Use `migrate()` no `index.js` antes de `.listen()`.
38+
39+
## Related Skills
40+
41+
| Need | Skill |
42+
| --- | --- |
43+
| **Backend (Elysia)** | @[.agent/skills/riligar-dev-manager] |
44+
| **Payments (Stripe)** | @[.agent/skills/riligar-infra-stripe] |
45+
| **Infrastructure** | @[.agent/skills/riligar-infra-fly] |
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# Database Connection
2+
3+
## Installation
4+
5+
```bash
6+
bun add drizzle-orm
7+
bun add -d drizzle-kit
8+
```
9+
10+
No additional drivers needed — `bun:sqlite` is built into Bun.
11+
12+
## db.js
13+
14+
```javascript
15+
// database/db.js
16+
import { drizzle } from 'drizzle-orm/bun-sqlite'
17+
import Database from 'bun:sqlite'
18+
19+
const sqlite = new Database(process.env.DB_PATH ?? './data/database.db')
20+
const db = drizzle({ client: sqlite })
21+
22+
export { db }
23+
```
24+
25+
- Em **desenvolvimento**: `DB_PATH` não é definido → usa `./data/database.db`
26+
- Em **produção** (Fly.io): `fly secrets set DB_PATH=/app/data/database.db`
27+
28+
## drizzle.config.js
29+
30+
```javascript
31+
// drizzle.config.js (na raiz do projeto)
32+
import { defineConfig } from 'drizzle-kit'
33+
34+
export default defineConfig({
35+
dialect: 'sqlite',
36+
schema: './database/schema.js',
37+
out: './database/migrations',
38+
dbCredentials: {
39+
url: process.env.DB_PATH ?? './data/database.db',
40+
},
41+
})
42+
```
43+
44+
## Migrations no Startup
45+
46+
No `index.js`, execute migrations antes de iniciar o servidor:
47+
48+
```javascript
49+
// index.js
50+
import { migrate } from 'drizzle-orm/bun-sqlite/migrator'
51+
import { db } from './database/db'
52+
53+
await migrate(db, { migrationsFolder: './database/migrations' })
54+
55+
// ... resto do setup
56+
const app = new Elysia()
57+
.use(routes)
58+
.listen(3000)
59+
```
60+
61+
Isso garante que o banco esteja sempre atualizado quando o servidor inicia no Fly.io.
62+
63+
## Estrutura de Arquivos
64+
65+
```
66+
database/
67+
├── db.js # Conexão (drizzle + bun:sqlite)
68+
├── schema.js # Todas as tabelas e relações
69+
└── migrations/
70+
├── 0000_*.sql # Migrations geradas pelo drizzle-kit
71+
├── 0001_*.sql
72+
└── meta/
73+
└── _journal.json
74+
```
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# Migrations — drizzle-kit
2+
3+
## Fluxo Padrão
4+
5+
```
6+
1. Edite database/schema.js
7+
2. bun run db:generate → gera migration SQL
8+
3. bun run db:migrate → aplica no banco
9+
```
10+
11+
## Scripts no package.json
12+
13+
```javascript
14+
{
15+
"scripts": {
16+
"db:generate": "drizzle-kit generate",
17+
"db:migrate": "drizzle-kit migrate",
18+
"db:push": "drizzle-kit push",
19+
"db:studio": "drizzle-kit studio"
20+
}
21+
}
22+
```
23+
24+
## Comandos
25+
26+
### Gerar migration
27+
28+
```bash
29+
bun run db:generate
30+
```
31+
32+
Compara o schema atual com o último snapshot. Gera um arquivo `.sql` em `database/migrations/`. Pergunta se algum campo foi renomeado (vs criado novo + deletado).
33+
34+
### Aplicar migrations
35+
36+
```bash
37+
bun run db:migrate
38+
```
39+
40+
Lê as migrations não aplicadas, executa em ordem. Mantém histórico no banco.
41+
42+
### Push (apenas desenvolvimento)
43+
44+
```bash
45+
bun run db:push
46+
```
47+
48+
Aplica mudanças diretamente no banco sem gerar arquivos de migration. Útil durante prototipage rápido. **Nunca use em produção.**
49+
50+
### Studio (GUI)
51+
52+
```bash
53+
bun run db:studio
54+
```
55+
56+
Abre uma interface visual para explorar e editar dados no banco.
57+
58+
## Migrations Programáticas (Startup)
59+
60+
Em produção, as migrations são executadas automaticamente no startup da aplicação:
61+
62+
```javascript
63+
// index.js
64+
import { migrate } from 'drizzle-orm/bun-sqlite/migrator'
65+
import { db } from './database/db'
66+
67+
await migrate(db, { migrationsFolder: './database/migrations' })
68+
```
69+
70+
Isso garante que o banco esteja sempre atualizado quando o servidor inicia no Fly.io.
Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
# Queries — Drizzle
2+
3+
## Imports Comuns
4+
5+
```javascript
6+
import { db } from '../database/db'
7+
import { users, posts } from '../database/schema'
8+
import { eq, and, or, desc, asc } from 'drizzle-orm'
9+
```
10+
11+
## Select
12+
13+
### Básico
14+
15+
```javascript
16+
// Todos os registros
17+
const allUsers = await db.select().from(users)
18+
19+
// Campos específicos
20+
const names = await db.select({
21+
id: users.id,
22+
name: users.name,
23+
}).from(users)
24+
```
25+
26+
### Filtrar
27+
28+
```javascript
29+
// Por campo único
30+
const [user] = await db.select().from(users).where(eq(users.id, userId)).limit(1)
31+
32+
// Múltiplos filtros (AND)
33+
const results = await db.select().from(users).where(
34+
and(
35+
eq(users.active, true),
36+
eq(users.plan, 'pro')
37+
)
38+
)
39+
40+
// OR
41+
const results = await db.select().from(users).where(
42+
or(eq(users.id, '1'), eq(users.id, '2'))
43+
)
44+
```
45+
46+
### Ordenar e Paginar
47+
48+
```javascript
49+
const page = await db.select().from(posts)
50+
.orderBy(desc(posts.createdAt))
51+
.limit(10)
52+
.offset(pageIndex * 10)
53+
```
54+
55+
## Insert
56+
57+
```javascript
58+
// Básico
59+
await db.insert(users).values({ name: 'Dan', email: 'dan@email.com' })
60+
61+
// Com retorno
62+
const [user] = await db.insert(users)
63+
.values({ name: 'Dan', email: 'dan@email.com' })
64+
.returning()
65+
66+
// Múltiplos
67+
await db.insert(users).values([
68+
{ name: 'Dan', email: 'dan@email.com' },
69+
{ name: 'Ana', email: 'ana@email.com' },
70+
])
71+
72+
// Upsert (conflict handling)
73+
await db.insert(users)
74+
.values({ id: '1', name: 'Dan' })
75+
.onConflictDoUpdate({
76+
target: users.id,
77+
set: { name: 'Dan', updatedAt: new Date() },
78+
})
79+
```
80+
81+
## Update
82+
83+
```javascript
84+
await db.update(users)
85+
.set({ name: 'Mr. Dan', updatedAt: new Date() })
86+
.where(eq(users.id, userId))
87+
88+
// Com retorno
89+
const [updated] = await db.update(users)
90+
.set({ plan: 'pro' })
91+
.where(eq(users.id, userId))
92+
.returning()
93+
```
94+
95+
## Delete
96+
97+
```javascript
98+
await db.delete(users).where(eq(users.id, userId))
99+
100+
// Com retorno
101+
const [deleted] = await db.delete(users)
102+
.where(eq(users.id, userId))
103+
.returning()
104+
```
105+
106+
## Queries com Relações
107+
108+
Quando tiver relações definidas no schema, use `db.query` em vez de `db.select`:
109+
110+
```javascript
111+
// Usuário com todos os posts
112+
const user = await db.query.users.findOne({
113+
where: eq(users.id, userId),
114+
with: {
115+
posts: true,
116+
},
117+
})
118+
119+
// Posts com autor
120+
const posts = await db.query.posts.findMany({
121+
with: {
122+
author: true,
123+
},
124+
orderBy: desc(posts.createdAt),
125+
limit: 10,
126+
})
127+
128+
// Nesting profundo
129+
const user = await db.query.users.findOne({
130+
where: eq(users.id, userId),
131+
with: {
132+
posts: {
133+
with: {
134+
comments: true,
135+
},
136+
},
137+
},
138+
})
139+
```
140+
141+
## Padrão de Serviço
142+
143+
Sempre encapsule queries em serviços:
144+
145+
```javascript
146+
// services/user.js
147+
import { db } from '../database/db'
148+
import { users } from '../database/schema'
149+
import { eq } from 'drizzle-orm'
150+
151+
export async function getUserById(id) {
152+
const [user] = await db.select().from(users).where(eq(users.id, id)).limit(1)
153+
return user ?? null
154+
}
155+
156+
export async function createUser(data) {
157+
const [user] = await db.insert(users).values(data).returning()
158+
return user
159+
}
160+
161+
export async function updateUser(id, data) {
162+
const [user] = await db.update(users)
163+
.set({ ...data, updatedAt: new Date() })
164+
.where(eq(users.id, id))
165+
.returning()
166+
return user ?? null
167+
}
168+
169+
export async function deleteUser(id) {
170+
const [user] = await db.delete(users).where(eq(users.id, id)).returning()
171+
return user ?? null
172+
}
173+
```

0 commit comments

Comments
 (0)