Metadata-Version: 2.4
Name: compare-schema
Version: 1.0.1
Summary: Compare schema and data between databases
Author-email: Gu Park <doctorgu@kakao.com>
License-Expression: MIT
Project-URL: homepage, https://github.com/doctorgu/compare_schema
Project-URL: repository, https://github.com/doctorgu/compare_schema
Project-URL: documentation, https://github.com/doctorgu/compare_schema
Keywords: compare schema,database comparison,schema diff,mysql,sqlite
Requires-Python: >=3.13
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: sqlite3-client>=1.2.0
Requires-Dist: mysqlclient-client>=1.2.0
Requires-Dist: pydantic>=2.0
Requires-Dist: pydantic-settings>=2.0
Requires-Dist: xlsxwriter>=3.0
Requires-Dist: tabulate>=0.9
Requires-Dist: types-tabulate>=0.10
Requires-Dist: requests>=2.28
Requires-Dist: PyYAML>=6.0
Requires-Dist: SQLAlchemy>=2.0
Requires-Dist: PyMySQL>=1.0
Requires-Dist: python-dotenv>=1.0.0
Requires-Dist: ruff
Provides-Extra: test
Requires-Dist: pytest; extra == "test"
Requires-Dist: pytest-cov; extra == "test"
Requires-Dist: pytest-env; extra == "test"
Requires-Dist: pytest-mock; extra == "test"
Requires-Dist: pytest-asyncio; extra == "test"
Requires-Dist: build; extra == "test"
Dynamic: license-file

# compare-schema — 데이터베이스 스키마 및 데이터 비교 도구

[English](README.md) | [한국어](README_KO.md)

다양한 환경(예: dev, stg, prd) 간의 데이터베이스 스키마 및 데이터를 비교하는 도구입니다.

> [!NOTE]
> 현재 **MySQL** 스키마 및 데이터만 지원됩니다. 비교 메타데이터 및 버전 히스토리는 로컬 임베디드 SQLite 데이터베이스에 저장됩니다.

## 주요 기능

- **스키마 비교**: 데이터베이스 간 테이블, 뷰, 컬럼, 인덱스, 외래키(Foreign Key) 참조 관계 비교.
- **데이터 비교**: 환경 간 키(Key) 기준 데이터 레코드 비교.
- **데이터베이스 히스토리 추적**: 버전을 비교하여 동일한 데이터베이스의 시간 경과에 따른 변경 이력 추적.
- **다양한 출력 형식**: 마크다운(`.md`) 또는 엑셀(`.xlsx`) 형식으로 비교 보고서 내보내기.
- **히스토리 및 버전 관리**: SQLite에 버전을 기록하여 시간 경과에 따른 스키마 드리프트(Schema Drift) 감지.
- **알림 기능**: 스키마 및 데이터 변경 시 Discord 웹훅(Webhook) 알림 지원.
- **CLI 및 모듈 지원**: `compare-schema` CLI 명령 또는 `python -m src.main`으로 실행 가능.

## 설치

```bash
pip install compare-schema
```

## 빠른 시작

### 1. 설정 (`config/config.yaml`)

설정 YAML 파일을 생성합니다:

```yaml
output_type: md # md 또는 xlsx
output_dir: ./compare_schema/result
prev_version: ""
process_when_changed: true

data_tables:
  - table: users
    columns:
      - name
      - email
      - nick_name
    key_columns:
      - id

exclude_tables: ["alembic_version"]
exclude_columns: []
db_host: 127.0.0.1
envs:
  - name: dev
    port: 3306
    db_names: [shop, logs]
  - name: stg
    port: 3306
    db_names: [shop]
  - name: prd
    port: 3306
    db_names: [shop]

compare_list:
  # 서로 다른 데이터베이스 또는 환경 간 비교
  - a: dev.shop
    b: dev.logs
  - a: dev.shop
    b: stg.shop
  - a: stg.shop
    b: prd.shop
  # a와 b가 동일한 경우, 최신 버전과 이전 버전을 비교하여 해당 DB의 변경 이력을 표시
  - a: dev.shop
    b: dev.shop
  - a: stg.shop
    b: stg.shop
  - a: prd.shop
    b: prd.shop
```

### 2. 버전 비교 및 히스토리

`compare_list`에 정의된 항목(`{env}.{database}`)에 따라 두 가지 비교 모드를 지원합니다:

#### A. 데이터베이스 간 비교 (`a != b`)

서로 다른 환경 또는 데이터베이스 간의 스키마 및 데이터를 비교합니다 (예: `dev.shop` vs `stg.shop`):

- **스키마 차이점**:
  - `schema_not_exists`: 한쪽 데이터베이스에는 존재하지만 다른 쪽에는 없는 테이블, 뷰, 컬럼, 인덱스, 외래키 식별.
  - `schema_diff`: 일치하는 객체의 구조적 차이점 식별:
    - **컬럼**: 데이터 타입, NULL 허용 여부(`is_nullable`), 기본값(`column_default`), 최대 문자 길이, 숫자 정밀도/소수점 자리수, 컬럼 코멘트.
    - **인덱스**: 인덱스 타입(BTREE 등), 유니크 여부(`is_unique`), 인덱스 구성 컬럼 조합.
    - **외래키**: 참조 대상 테이블 및 컬럼.
- **데이터 차이점**:
  - `data_tables`에 지정된 테이블의 행(Row) 비교.
  - `key_columns`에 설정된 기본키/유니크 키를 기준으로 양쪽 데이터베이스의 행 매칭.
  - `data_not_exists`: 한쪽 데이터베이스에는 존재하지만 다른 쪽에는 없는 행.
  - `data_diff`: 양쪽 데이터베이스에 모두 존재하지만 모니터링 대상 `columns`의 값이 서로 다른 행.
- **출력**: `{version}_compare.md` (마크다운) 또는 엑셀의 `compare` 시트로 내보내기.

#### B. 데이터베이스 히스토리 및 드리프트 추적 (`a == b`)

`a`와 `b`가 동일한 데이터베이스를 참조할 때(예: `a: dev.shop, b: dev.shop`), 새로운 `version`(`YYYYMMDDHHmm` 타임스탬프)과 `prev_version`을 비교합니다:

- **변경 카테고리**:
  - `schema_added` / `data_added`: 새로 생성된 테이블, 뷰, 컬럼, 인덱스, 외래키 또는 추가된 데이터 행.
  - `schema_removed` / `data_removed`: 삭제된 스키마 객체 또는 데이터 행.
  - `schema_changed` / `data_changed`: 변경된 컬럼 속성/타입 또는 수정된 데이터 행 값.
- **출력**: `{version}_log.md` (마크다운) 또는 엑셀의 `log` 시트로 내보내기.

---

### 설정 참조 (`config.yaml`)

| 파라미터 | 타입 | 기본값 | 설명 |
| :--- | :--- | :--- | :--- |
| `output_type` | `Literal["xlsx", "md"]` | 필수 | 출력 형식. `"md"`는 마크다운 파일, `"xlsx"`는 엑셀 워크북을 생성합니다. |
| `output_dir` | `str` | 필수 | 출력 보고서가 저장될 디렉토리 경로입니다. |
| `prev_version` | `str` | `""` | 비교 대상이 되는 이전 버전(`YYYYMMDDHHmm`). 비워둘 경우(`""`) SQLite에 기록된 가장 최신 버전을 자동으로 사용합니다. |
| `process_when_changed` | `bool` | 필수 | `true`인 경우 `prev_version` 대비 스키마나 데이터 변경 사항이 없을 때 보고서 생성을 중단하고 조기 종료합니다. `false`이면 매 실행마다 보고서를 생성합니다. |
| `data_tables` | `list[DataTableConfig]` | `[]` | 데이터를 비교할 테이블 및 컬럼 목록입니다. |
| `data_tables[].table` | `str` | 필수 | MySQL 테이블 이름입니다. |
| `data_tables[].columns` | `list[str]` | 필수 | 값 차이를 비교할 대상 컬럼 목록입니다. |
| `data_tables[].key_columns` | `list[str]` | 필수 | 데이터베이스 간 대응하는 행을 식별하고 매칭하기 위한 키 컬럼 목록(예: 기본키)입니다. |
| `exclude_tables` | `list[str]` | 필수 | 마이그레이션 테이블(예: `["alembic_version"]`)과 같이 이기종 환경 간 스키마 비교(`a != b`) 시 제외할 테이블 이름 목록입니다. *(동일 DB 히스토리 추적 `a == b` 시에는 제외되지 않습니다)*. |
| `exclude_columns` | `list[str]` | 필수 | 이기종 환경 간 컬럼 비교 시 무시할 컬럼 이름 목록입니다. |
| `db_host` | `str` | 필수 | MySQL 데이터베이스 접속을 위한 호스트 IP 또는 호스트명입니다. |
| `envs` | `list[EnvConfig]` | 필수 | 접속하여 추출할 데이터베이스 환경 목록입니다. |
| `envs[].name` | `str` | 필수 | 환경 식별자(예: `dev`, `stg`, `prd`)입니다. |
| `envs[].port` | `int` | 필수 | 해당 환경의 MySQL 포트 번호입니다. |
| `envs[].db_names` | `list[str]` | 필수 | 해당 환경에서 추출할 데이터베이스 이름 목록입니다. |
| `compare_list` | `list[EnvCompareConfig]` | 필수 | 비교 대상 데이터베이스 쌍 목록입니다 (예: `a: dev.shop`, `b: stg.shop`). |

---

### 동작 방식

1. **추출 및 스냅샷 저장 (Extraction & Snapshotting)**:
   - `.env`의 접속 정보를 사용하여 `envs`에 정의된 MySQL 인스턴스에 접속합니다.
   - 스키마 정의(`information_schema.TABLES`, `COLUMNS`, `STATISTICS`, `KEY_COLUMN_USAGE`) 및 `data_tables` 레코드를 추출합니다.
   - 현재 버전 타임스탬프(`YYYYMMDDHHmm`)를 태그하여 로컬 임베디드 SQLite 데이터베이스(`db_client/schema_data.sqlite3`)에 시점 스냅샷으로 저장합니다.
2. **변경 감지 (Change Detection)**:
   - 현재 버전과 `prev_version` 간에 스키마 또는 데이터 변경 사항이 있는지 SQLite에 조회합니다.
   - `process_when_changed: true`이고 변경 사항이 없으면 실행을 조기에 종료합니다.
3. **비교 실행 (Comparison Execution)**:
   - `#foreach` 리스트 필터링을 지원하는 파라미터화된 쿼리를 사용하여 `compare_list`의 모든 구성된 쌍을 비교합니다.
4. **보고서 내보내기 및 알림 (Report Export & Alerts)**:
   - `data/` 디렉토리에 마크다운 또는 엑셀 보고서를 작성합니다.
   - 로그 모드에서 스키마 또는 데이터 변경이 감지되면(`is_log: true`), `DISCORD_WEB_HOOK_URL`을 통해 Discord로 알림을 자동 전송합니다.
   - 런타임 오류 또는 예외 발생 시 포맷된 에러 메시지를 Discord 알림으로 전송합니다.

### 3. 환경 변수 (`.env`)

`.env` 파일에 데이터베이스 접속 정보를 설정합니다:

```env
DB_USERNAME=your_username
DB_PASSWORD=your_password
DISCORD_WEB_HOOK_URL=https://discord.com/api/webhooks/...
```

### 4. 비교 실행

```bash
# CLI로 실행
compare-schema --config_path config/config.yaml

# 또는 Python 모듈로 실행
python -m src.main --config_path config/config.yaml
```

## 라이선스

MIT License. 자세한 내용은 [LICENSE](LICENSE)를 참조하세요.
