基于 SOC 职业分类
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/puk0806/gugbab-claude --skill sqlx命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
正在显示 SKILL.md
DDD(Domain-Driven Design) 아키텍처 핵심 패턴 - 유비쿼터스 언어, 서브도메인, 바운디드 컨텍스트, Aggregate, Entity/VO, 도메인 서비스/이벤트, 레이어드 아키텍처
대규모 React/Next.js 프로젝트를 layer-first(types/·utils/·hooks/·api/·components/ 밑에 도메인이 반복되는 구조)에서 domain-first(feature/도메인 우선) 구조로 전환하는 설계 기준과 절차. Feature-Sliced Design 2.1 정본(layers 6종·slices·segments·import 규칙·@x 크로스임포트·public API), FSD를 쓰지 않는 경량 대안(features + shared 2~3계층 + ESLint import/no-restricted-paths), Next.js App Router 공존 전략(route group `()`·private folder `_`·colocation), Turborepo/Nx 모노레포에서 폴더↔패키지 승격 기준, colocation과 배럴 파일 성능 트레이드오프, 도메인 경계 역추출(import 그래프·change coupling·용어 클러스터), 전환 실패 패턴(shared 비대화·entities 남용·순환 의존·도메인=라우트 착각·조기 추상화). 도메인 개념 자체(바운디드 컨텍스트·유비쿼터스 언어)는 `architecture/ddd` 스킬을 참조한다.
소스 파일 수천 개 규모 프론트엔드 코드베이스를 멈추지 않고 점진 재구조화하는 실행 전략 - Strangler Fig / Branch by Abstraction / Parallel Change, ts-morph·jscodeshift codemod, PR 분할·검증 게이트·되돌리기, 테스트 없는 코드의 안전망, 작업 순서 설계와 위반 수 기반 진행 추적
| name | sqlx |
| description | Rust sqlx 비동기 SQL 툴킷 - Pool 연결, query 매크로, 트랜잭션, 마이그레이션, Axum 연동, 에러 처리 |
소스: https://docs.rs/sqlx/latest/sqlx/ | https://github.com/launchbadge/sqlx 검증일: 2026-06-20
주의: 이 문서는 sqlx 0.8.x 기준으로 작성되었습니다. 0.9.0이 2026-05-21 릴리즈되어 있으며 Breaking Change가 다수 있으므로 공식 CHANGELOG를 반드시 확인하세요. 신규 프로젝트는 0.9 도입을 검토하되 마이그레이션 노트를 참조하세요.
sqlx 0.9로의 마이그레이션 시 주요 Breaking Change (0.8 → 0.9):
query*()계열 함수의&str파라미터가SqlSafeStr트레이트로 변경 — 기존 동적 쿼리 문자열 전달 시AssertSqlSafe(..)래핑 필요Arguments트레이트에서 lifetime 파라미터 제거- MySQL: 텍스트 컬럼 타입 추론이
Vec<u8>→String으로 변경,SET NAMES동작 변경- PostgreSQL:
PgConnectOptions::options()에 전달한 값이 자동 escape됨 — 수동 escape 제거 필요sqlx.toml설정 파일 신규 지원 (선택적)
# Cargo.toml
# sqlx 0.8.x (현재 문서 기준) — 0.9가 2026-05-21 릴리즈됨, 마이그레이션 주의사항 참조
[dependencies]
sqlx = { version = "0.8", features = ["runtime-tokio", "tls-rustls", "postgres", "chrono", "uuid", "migrate"] }
tokio = { version = "1", features = ["full"] }
dotenvy = "0.15"
anyhow = "1"
thiserror = "2"
feature 선택 기준:
| feature | 설명 |
|---|---|
runtime-tokio | tokio 런타임 사용 (필수 선택: runtime-tokio 또는 runtime-async-std) |
tls-rustls | TLS 연결 (대안: tls-native-tls) |
postgres / mysql / sqlite | 데이터베이스 드라이버 (복수 선택 가능) |
chrono | chrono::NaiveDateTime 등 타입 지원 |
uuid | uuid::Uuid 타입 지원 |
migrate | 마이그레이션 매크로 migrate!() 사용 |
주의:
runtime-*과tls-*feature는 각각 정확히 하나만 선택해야 합니다. sqlx 0.8부터 복수 선택 시 컴파일 에러 대신 런타임 패닉이 발생합니다. tls feature를 복수 선택하면tls-native-tls가 우선 적용됩니다.
# .env 파일
DATABASE_URL=postgres://user:password@localhost:5432/mydb
// main.rs에서 .env 로드
dotenvy::dotenv().ok();
let database_url = std::env::var("DATABASE_URL")
.expect("DATABASE_URL must be set");
연결 문자열 형식:
| DB | 형식 |
|---|---|
| PostgreSQL | postgres://user:pass@host:5432/dbname |
| MySQL | mysql://user:pass@host:3306/dbname |
| SQLite | sqlite://path/to/db.sqlite 또는 sqlite::memory: |
use sqlx::postgres::PgPoolOptions;
use sqlx::PgPool;
let pool = PgPoolOptions::new()
.max_connections(5)
.acquire_timeout(std::time::Duration::from_secs(3))
.connect(&database_url)
.await
.expect("Failed to create pool");
use sqlx::mysql::MySqlPoolOptions;
use sqlx::sqlite::SqlitePoolOptions;
// MySQL
let mysql_pool = MySqlPoolOptions::new()
.max_connections(5)
.connect(&database_url)
.await?;
// SQLite
let sqlite_pool = SqlitePoolOptions::new()
.max_connections(5)
.connect("sqlite://data.db")
.await?;
// feature에 따라 자동으로 적절한 드라이버 선택
let pool = sqlx::Pool::<sqlx::Postgres>::connect(&database_url).await?;
Pool 주요 옵션:
| 메서드 | 기본값 | 설명 |
|---|---|---|
max_connections() | 10 | 최대 연결 수 |
min_connections() | 0 | 최소 유지 연결 수 |
acquire_timeout() | 30초 | 연결 획득 타임아웃 |
idle_timeout() | 10분 | 유휴 연결 제거 시간 |
max_lifetime() | 30분 | 연결 최대 수명 |
query! 매크로는 컴파일 타임에 SQL 문법과 타입을 검증한다. DATABASE_URL 환경변수가 설정되어 있어야 한다.
// SELECT - 익명 레코드 반환
let rows = sqlx::query!("SELECT id, name, email FROM users WHERE active = $1", true)
.fetch_all(&pool)
.await?;
for row in rows {
println!("id: {}, name: {}", row.id, row.name);
}
#[derive(Debug)]
struct User {
id: i64,
name: String,
email: String,
}
let user = sqlx::query_as!(
User,
"SELECT id, name, email FROM users WHERE id = $1",
user_id
)
.fetch_one(&pool)
.await?;
// INSERT - returning
let user = sqlx::query_as!(
User,
"INSERT INTO users (name, email) VALUES ($1, $2) RETURNING id, name, email",
name,
email
)
.fetch_one(&pool)
.await?;
// UPDATE
let result = sqlx::query!(
"UPDATE users SET name = $1 WHERE id = $2",
new_name,
user_id
)
.execute(&pool)
.await?;
println!("rows affected: {}", result.rows_affected());
// DELETE
sqlx::query!("DELETE FROM users WHERE id = $1", user_id)
.execute(&pool)
.await?;
| 메서드 | 반환 | 용도 |
|---|---|---|
fetch_one() | 단일 행 (없으면 에러) | 반드시 1행 존재할 때 |
fetch_optional() | Option<Row> | 0 또는 1행 |
fetch_all() | Vec<Row> | 모든 행을 메모리에 |
fetch() | Stream<Row> | 대량 데이터 스트리밍 |
execute() | PgQueryResult | INSERT/UPDATE/DELETE |
컴파일 타임 검증 없이 동적 SQL을 실행할 때:
use sqlx::{Row, FromRow};
// query() 함수 - 매크로가 아닌 런타임 버전
let row = sqlx::query("SELECT id, name FROM users WHERE id = $1")
.bind(user_id)
.fetch_one(&pool)
.await?;
let name: String = row.get("name");
// query_as() 함수 - FromRow derive 필요
#[derive(Debug, FromRow)]
struct User {
id: i64,
name: String,
}
let user = sqlx::query_as::<_, User>("SELECT id, name FROM users WHERE id = $1")
.bind(user_id)
.fetch_one(&pool)
.await?;
주의:
query!매크로는 컴파일 시 DB 연결이 필요합니다. CI 환경에서는sqlx prepare로 오프라인 모드를 사용하세요.
CI/CD 환경에서 DB 연결 없이 컴파일하려면:
# 개발 환경에서 쿼리 메타데이터 저장
cargo sqlx prepare
# .sqlx/ 디렉토리가 생성됨 -> git에 커밋
# CI에서는 SQLX_OFFLINE=true 환경변수 설정
# Cargo.toml - offline feature 추가 불필요 (0.8부터 기본 지원)
# CI 환경변수
SQLX_OFFLINE=true cargo build
let mut tx = pool.begin().await?;
sqlx::query!("INSERT INTO users (name, email) VALUES ($1, $2)", name, email)
.execute(&mut *tx)
.await?;
// 주의: lastval()은 현재 세션의 마지막 시퀀스 값을 반환한다.
// 동일 세션에서 다른 시퀀스가 먼저 사용되면 잘못된 ID를 반환할 수 있다.
// RETURNING id로 명시적으로 받아서 전달하는 방식이 더 안전하다.
sqlx::query!("INSERT INTO profiles (user_id, bio) VALUES (lastval(), $1)", bio)
.execute(&mut *tx)
.await?;
tx.commit().await?;
핵심 규칙:
tx.commit().await? 호출하지 않으면 Transaction drop 시 자동 rollback&mut *tx로 역참조하여 executor로 전달let mut tx = pool.begin().await?;
match do_something(&mut tx).await {
Ok(_) => tx.commit().await?,
Err(e) => {
tx.rollback().await?;
return Err(e);
}
}
use sqlx::{PgPool, Transaction, Postgres};
async fn create_user_with_profile(
tx: &mut Transaction<'_, Postgres>,
name: &str,
bio: &str,
) -> Result<i64, sqlx::Error> {
let user = sqlx::query_scalar!(
"INSERT INTO users (name) VALUES ($1) RETURNING id",
name
)
.fetch_one(&mut **tx)
.await?;
sqlx::query!(
"INSERT INTO profiles (user_id, bio) VALUES ($1, $2)",
user,
bio
)
.execute(&mut **tx)
.await?;
Ok(user)
}
// 호출부
let mut tx = pool.begin().await?;
let user_id = create_user_with_profile(&mut tx, "Alice", "Hello").await?;
tx.commit().await?;
# 전체 DB 드라이버 포함
cargo install sqlx-cli
# PostgreSQL만
cargo install sqlx-cli --no-default-features --features rustls,postgres
# 1. 마이그레이션 디렉토리 생성
sqlx database create # DATABASE_URL 기반으로 DB 생성
# 2. 마이그레이션 파일 생성
sqlx migrate add create_users
# -> migrations/20240101000000_create_users.sql 생성됨
# 3. SQL 작성
# migrations/20240101000000_create_users.sql
-- migrations/20240101000000_create_users.sql
CREATE TABLE users (
id BIGSERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
email VARCHAR(255) NOT NULL UNIQUE,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_users_email ON users(email);
# 4. 마이그레이션 실행
sqlx migrate run
# 5. 되돌리기 (reversible 마이그레이션인 경우)
sqlx migrate revert
# reversible 마이그레이션 생성 (-r 플래그)
sqlx migrate add -r create_users
# -> migrations/20240101000000_create_users.up.sql
# -> migrations/20240101000000_create_users.down.sql
// 앱 시작 시 자동 마이그레이션 (개발 환경 권장)
sqlx::migrate!("./migrations")
.run(&pool)
.await?;
주의:
migrate!()매크로 사용 시migratefeature가 활성화되어 있어야 합니다. 프로덕션 환경에서는 CLI로 마이그레이션을 실행하는 것이 안전합니다.
상세 레퍼런스 (예제·고급 패턴·흔한 실수) →
references/REFERENCE.md