Skip to content

Latest commit

 

History

History
360 lines (246 loc) · 9.21 KB

File metadata and controls

360 lines (246 loc) · 9.21 KB

Jinx — JPA → DDL SQL 마이그레이션 생성기

Maven Central Gradle Plugin Portal License

Jinx는 컴파일 타임에 JPA 애노테이션을 분석하여
**스키마 스냅샷(JSON)**을 생성하고,
스냅샷 간 차이를 비교해 DDL SQL을 자동으로 생성하는 도구입니다.

Liquibase YAML도 출력 포맷 중 하나로 지원하지만,
SQL이 주력이며 가장 많이 검증된 출력 결과입니다.

MySQL & PostgreSQL | JDK 21+ 필요 | 최신 버전: 0.1.4 | JPA 3.2.0 지원


왜 Jinx인가?

Jinx는 데이터베이스 스키마 변경을
명시적이고, 검수 가능하며, 자동화 친화적으로 만들기 위해 존재합니다.

1. DDL 작성 시 발생하는 휴먼 에러 사전 차단

DDL을 직접 작성하지 않고 JPA 메타데이터에서 생성합니다.
오타, 누락된 컬럼, 잘못된 제약 조건이 운영 환경으로 가는 것을 막습니다.

2. 개발자가 직접 검수 가능한 마이그레이션

Jinx는 사람이 읽을 수 있는 순수 SQL 파일을 생성합니다.
스키마 변경 역시 애플리케이션 코드처럼 리뷰와 승인 과정을 거칠 수 있습니다.

3. CI/CD 파이프라인에 자연스럽게 통합

결과물이 SQL 파일이기 때문에
별도의 런타임 도구 없이 기존 CI/CD 흐름에 쉽게 포함할 수 있습니다.
실제 데이터베이스 연결도 필요하지 않습니다.

4. 데이터베이스 없이도 동작

스키마 분석과 diff는 스냅샷 파일만으로 수행됩니다.
로컬이나 CI 환경에서 DB 없이도 마이그레이션을 생성·검증할 수 있습니다.

5. 별도 마이그레이션 런타임 없이 이력 관리 가능

생성된 SQL 파일을 Git에 커밋하면
Git 자체가 스키마 변경 이력이 됩니다.

추가적인 마이그레이션 런타임 도입이 부담스럽다면,
Jinx + Git만으로도 충분히 추적 가능한 구조를 만들 수 있습니다.


설계 철학

컴파일 타임 분석 (리플렉션 미사용)

Jinx는 애노테이션 프로세싱 기반으로
컴파일 타임에 스키마를 분석합니다.

런타임 리플렉션에 의존하지 않으며,
리플렉션 기반 JPA 표준 모델을 그대로 따르지 않습니다.

이는 의도적인 선택입니다.

  • 결정적이고 재현 가능한 스키마 생성
  • 런타임 메타데이터 요구사항 제거
  • AOT 지향 빌드 파이프라인과의 높은 궁합

자바 생태계가 점점 리플렉션 사용을 줄이는 방향으로 가는 상황에서,
Jinx는 자연스럽게 장기적인 빌드 환경 변화에 대응합니다.

Jinx는 Hibernate와 같은 JPA 런타임을 대체하지 않습니다.
스키마 분석과 마이그레이션 생성에만 집중합니다.


출력 포맷

SQL (주력)

DDL SQL은 Jinx의 1급 출력 포맷이며
가장 많은 테스트와 검증이 이루어집니다.

Liquibase YAML (부가)

Liquibase를 이미 사용 중인 팀을 위해
호환 가능한 출력 포맷으로 제공됩니다.

Liquibase는 핵심 모델이 아니라
SQL 생성 결과를 변환한 표현 방식 중 하나입니다.


빠른 시작

1. 의존성 추가

dependencies {
    annotationProcessor("io.github.yyubin:jinx-processor:0.1.4")
    implementation("io.github.yyubin:jinx-core:0.1.4")
}

2. 엔티티 작성

@Entity
public class Bird {
    @Id @GeneratedValue
    private Long id;

    private String name;
    private Long zooId;
}

3. 스냅샷 생성

컴파일 시 자동으로 생성됩니다.

build/classes/java/main/jinx/

파일 이름 형식:

schema-<yyyyMMddHHmmss>.json

4. 마이그레이션 생성 (CLI)

jinx db migrate \
  -p build/classes/java/main/jinx \
  -d mysql \
  --out build/jinx \
  --rollback \
  --liquibase
# PostgreSQL (Gradle 플러그인 경유 권장)
jinx db migrate \
  -p build/classes/java/main/jinx \
  -d postgresql \
  --out build/jinx \
  --rollback

참고: CLI에서 PostgreSQL을 직접 사용하는 것은 현재 제한적으로 지원됩니다. PostgreSQL 프로젝트에는 Gradle 플러그인을 통해 dialect.set("postgresql")을 설정하는 방법을 권장합니다.


Gradle 연동 (Spring Boot & JDK 21)

플러그인 적용

plugins {
    id("io.github.yyubin.jinx") version "0.1.4"
}

DSL 설정 예시

jinx {
    profile.set("local")

    naming {
        maxLength.set(63)
        strategy.set("SNAKE_CASE")
    }

    database {
        dialect.set("mysql")
    }

    output {
        format.set("sql")
        directory.set("build/jinx")
    }
}

PostgreSQL을 사용하려면:

database {
    dialect.set("postgresql")  // 또는 "mysql"
}

설정

우선순위

설정은 다음 순서로 적용됩니다 (위가 더 높은 우선순위):

Gradle DSL / -A 컴파일러 옵션  >  jinx.yaml  >  기본값

jinx.yaml

프로젝트 루트에 jinx.yaml을 생성합니다. 작업 디렉토리에서 상위 디렉토리로 순차 탐색하므로, 저장소 루트에 두면 모든 서브프로젝트에 적용됩니다.

profiles:
  dev:
    naming:
      maxLength: 30
      strategy: NO_OP

  prod:
    naming:
      maxLength: 63
      strategy: SNAKE_CASE

프로파일 활성화 (우선순위 순):

  1. Gradle DSL: profile.set("prod")
  2. 환경변수: JINX_PROFILE=prod
  3. 기본값: dev

설정 항목

naming.maxLength

제약 조건·인덱스명 생성 시 적용할 최대 길이입니다.

기본값 권장값
30 PostgreSQL: 63 / MySQL: 64

naming.strategy

Java 필드명·클래스명을 DB 물리 컬럼명으로 변환하는 방식을 지정합니다.

동작 예시
NO_OP 변환 없이 그대로 사용 (기본값) myColumnmyColumn
SNAKE_CASE camelCase → snake_case 변환 myColumnmy_column

Gradle DSL

jinx {
    profile.set("prod")

    naming {
        maxLength.set(63)
        strategy.set("SNAKE_CASE")
    }
}

Gradle DSL 값은 jinx.yaml보다 우선 적용됩니다. 플러그인이 -A 컴파일러 인자로 자동 변환해 전달합니다.


Annotation Processor 직접 옵션 (-A)

Gradle 플러그인 없이 Annotation Processor를 직접 사용하는 경우:

compileJava {
    options.compilerArgs += [
        '-Ajinx.naming.maxLength=63',
        '-Ajinx.naming.strategy=SNAKE_CASE',
        '-Ajinx.profile=prod'
    ]
}
설명
jinx.naming.maxLength 제약 조건·인덱스명 최대 길이
jinx.naming.strategy 네이밍 전략 (NO_OP 또는 SNAKE_CASE)
jinx.profile jinx.yaml 프로파일 지정

CLI 옵션 요약

옵션 설명
db migrate 스냅샷 diff 기반 SQL 생성
promote-baseline 현재 스냅샷을 기준선으로 승격
-d, --dialect 데이터베이스 방언 (mysql, postgresql)
--rollback 롤백 SQL 생성
--liquibase Liquibase YAML 출력
--force 파괴적 변경 허용

안전한 마이그레이션 순서

여러 테이블을 한 번에 추가하거나 삭제할 때, Jinx는 외래 키 의존성을 기반으로 위상정렬을 수행해 올바른 실행 순서를 자동으로 결정합니다.

수동으로 순서를 지정할 필요가 없습니다. Jinx가 FK 그래프를 분석해 코드에서 엔티티가 등장하는 순서와 무관하게 올바른 CREATE/DROP 문을 생성합니다.

작업 순서
CREATE TABLE 부모 테이블 → 자식 테이블
DROP TABLE 자식 테이블(FK 보유) → 부모 테이블

지원하는 구조:

  • 선형 체인: A → B → C
  • 다이아몬드: A → C, B → C
  • 조인 테이블: AB → A, AB → B
  • 복수의 독립 트리

순환 FK가 감지되면 경고를 출력하고 원본 순서를 안전하게 유지합니다.


지원 기능

  • 테이블 / 컬럼 / PK / 인덱스 / 제약 조건 diff
  • FK 의존성 기반 테이블 순서 결정 — 외래 키 그래프를 분석해 CREATE/DROP 순서를 자동으로 결정
  • 롤백 SQL 생성
  • Liquibase YAML 출력
  • MySQL 방언 (기본값)
  • PostgreSQL 방언 — 큰따옴표 식별자, BIGSERIAL/SERIAL, SEQUENCE, BOOLEAN, uuid, BYTEA, DOUBLE PRECISION, TIMESTAMP WITH TIME ZONE

예제 & 테스트 저장소

https://github.com/yyubin/jinx-test


기여

  • 새로운 DB 방언 추가
  • DDL / Liquibase 매핑 개선
  • 테스트 및 문서 보강

PR과 이슈는 언제든 환영합니다.