Skip to content

[FIX] 구형 MIDI 데이터 호환 마이그레이션 추가 - #112

Merged
on1yoneprivate merged 1 commit into
developfrom
refactor/#56-history
Aug 1, 2026
Merged

[FIX] 구형 MIDI 데이터 호환 마이그레이션 추가 #112
on1yoneprivate merged 1 commit into
developfrom
refactor/#56-history

Conversation

@ownue

@ownue ownue commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

📍 개요

히스토리 API 테스트 중 발견한 오류를 수정합니다.

⛓️‍💥 관련 이슈


🛠️ 작업 내용

히스토리 API 테스트 중 COMMON_500_01 에러가 뜨는 것을 확인했습니다. -> 로컬 테스트상 문제가 없어, 커밋 목록을 확인한 결과 midi_data의 구조를 변경했을 때 서버 DB에는 반영이 되지 않았던 게 문제라고 판단했습니당...
따라서 마이그레이션 파일을 추가하였습니다.


🔥 리뷰 요청 사항

리뷰어가 중점적으로 확인해주었으면 하는 내용을 작성해주세요.

X


✅ 체크리스트

  • 코드 컨벤션을 준수했습니다.
  • 불필요한 코드 및 import를 제거했습니다.
  • 예외 처리를 적용했습니다.
  • 테스트를 완료했습니다.
  • 관련 Issue를 연결했습니다.

📎 참고 사항

X

Summary by CodeRabbit

  • 개선 사항
    • 기존 MIDI 데이터의 형식과 값 범위를 검증해 잘못된 데이터가 처리되지 않도록 했습니다.
    • 누락된 데이터는 빈 배열로 정리하고, sequence 값을 자동으로 보완합니다.
    • MIDI 타임스탬프 필드명을 일관된 형식으로 표준화했습니다.

@coderabbitai

coderabbitai Bot commented Aug 1, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

playing.midi_data의 MIDI JSON 이벤트를 검증하고 정규화하는 V3 데이터베이스 마이그레이션을 추가했습니다. 잘못된 이벤트는 예외를 발생시키며, 유효한 데이터는 표준 키와 sequence를 사용하도록 변환됩니다.

Changes

MIDI 데이터 정규화

Layer / File(s) Summary
MIDI 이벤트 검증
src/main/resources/db/migration/V3__normalize_legacy_playing_midi_data.sql
배열과 이벤트 객체를 확인합니다. type, pitch, velocity, timestamp, 선택적 sequence의 타입과 범위를 검증합니다. 오류 발생 시 이벤트 위치를 예외에 포함합니다.
MIDI JSON 정규화
src/main/resources/db/migration/V3__normalize_legacy_playing_midi_data.sql
NULL을 빈 배열로 변환합니다. 누락된 sequence를 배열 순서로 채웁니다. timestampMstimestamp_ms로 변경하고 기존 키를 제거합니다.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant V3Migration as V3 migration
  participant ValidationBlock as PLpgSQL validation block
  participant MidiData as playing.midi_data
  V3Migration->>ValidationBlock: execute validation
  ValidationBlock->>MidiData: read non-NULL midi_data
  MidiData-->>ValidationBlock: return JSON events
  ValidationBlock->>ValidationBlock: validate fields and ranges
  ValidationBlock->>MidiData: update normalized JSON
  MidiData-->>V3Migration: complete migration
Loading

Possibly related PRs

  • Musereview/BE#23: Playing.midiData 이벤트 구조를 도입한 변경과 직접 연결됩니다. 이 PR은 해당 이벤트의 레거시 키와 값을 검증하고 정규화합니다.

Poem

MIDI 배열은 줄을 서고
sequence는 번호를 얻네.
timestampMs는 새 이름을 입고
잘못된 음표는 예외로 멈추네.
PostgreSQL이 박자를 맞추네.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 제목은 구형 MIDI 데이터 호환을 위한 마이그레이션 추가라는 변경 목적을 명확하게 요약합니다.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor/#56-history

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
src/main/resources/db/migration/V3__normalize_legacy_playing_midi_data.sql (2)

10-22: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

검증 루프를 집합 기반 SQL로 바꾸는 것을 검토하세요.

현재 구조는 playing 전체 행을 PL/pgSQL 루프로 읽고, 각 행의 이벤트를 다시 루프로 읽습니다. 행 수와 이벤트 수의 곱만큼 인터프리터 오버헤드가 발생합니다. 마이그레이션은 배포 중 테이블 잠금 시간에 직접 영향을 줍니다.

집합 기반 검증으로 바꾸면 단일 쿼리로 위반 행을 찾을 수 있습니다. 예를 들어 jsonb_array_elementsLATERAL로 펼친 뒤 위반 조건을 WHERE로 모아 count(*) 또는 첫 위반 행만 조회하고, 결과가 있을 때 한 번만 RAISE EXCEPTION을 호출하는 방식입니다.

또한 검증 루프는 이미 정규화된 행까지 전부 재검사합니다. UPDATE의 WHERE 절(Line 109-116)과 같은 조건으로 대상을 좁히면 불필요한 작업을 줄일 수 있습니다.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/resources/db/migration/V3__normalize_legacy_playing_midi_data.sql`
around lines 10 - 22, Replace the nested validation loops around playing_row and
midi_event with a set-based query using jsonb_array_elements via LATERAL,
applying the same normalization eligibility conditions as the UPDATE WHERE
clause and checking array validity in the query. Capture the first violating
playing_id (or equivalent aggregate result) and raise a single exception only
when a violation exists, preserving the current error behavior.

109-116: 🚀 Performance & Scalability | 🔵 Trivial

멱등성 조건은 정확합니다. 배포 차단 위험과 잠금 시간을 함께 검토하세요.

WHERE 절이 sequence 누락, timestamp_ms 누락, timestampMs 잔존을 모두 확인하므로 재실행 시 대상 행이 0건이 됩니다. 멱등성 설계가 깔끔합니다.

운영 측면에서 두 가지를 검토하세요.

  1. 검증 블록은 손상 이벤트를 하나만 발견해도 예외를 발생시킵니다. Flyway 마이그레이션이 실패하면 배포가 중단되고 애플리케이션이 기동하지 않습니다. 운영 DB의 레거시 데이터 상태를 미리 확인할 수 없다면, 위반 행을 격리 테이블에 기록하고 정상 행만 정규화하는 방식이 배포 위험을 낮춥니다. 최소한 스테이징에서 같은 데이터셋으로 검증 블록을 먼저 실행하세요.
  2. UPDATEplaying 테이블 전체를 대상 후보로 삼고, Flyway 기본 설정에서 단일 트랜잭션으로 실행됩니다. 행 수가 많으면 잠금 시간과 WAL 증가량이 커집니다. 대용량이라면 playing_id 범위 기준 배치 처리를 고려하세요.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/resources/db/migration/V3__normalize_legacy_playing_midi_data.sql`
around lines 109 - 116, Review the migration’s validation and UPDATE flow for
production safety: run the validation against an equivalent staging dataset
before deployment, and if operationally required, isolate rows containing
malformed events so valid rows can still be normalized instead of aborting the
migration. For large playing tables, replace the single full-table transaction
with playing_id-range batches while preserving the existing idempotent
predicates for sequence, timestamp_ms, and timestampMs.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/main/resources/db/migration/V3__normalize_legacy_playing_midi_data.sql`:
- Around line 89-101: Update the sequence fallback in the JSON aggregation to
represent the 0-based order within each identical timestamp group, rather than
the array-wide event_ordinality. Compute the timestamp-partitioned row number in
a subquery before jsonb_agg, while preserving existing sequence values and
timestamp_ms fallback behavior.

---

Nitpick comments:
In `@src/main/resources/db/migration/V3__normalize_legacy_playing_midi_data.sql`:
- Around line 10-22: Replace the nested validation loops around playing_row and
midi_event with a set-based query using jsonb_array_elements via LATERAL,
applying the same normalization eligibility conditions as the UPDATE WHERE
clause and checking array validity in the query. Capture the first violating
playing_id (or equivalent aggregate result) and raise a single exception only
when a violation exists, preserving the current error behavior.
- Around line 109-116: Review the migration’s validation and UPDATE flow for
production safety: run the validation against an equivalent staging dataset
before deployment, and if operationally required, isolate rows containing
malformed events so valid rows can still be normalized instead of aborting the
migration. For large playing tables, replace the single full-table transaction
with playing_id-range batches while preserving the existing idempotent
predicates for sequence, timestamp_ms, and timestampMs.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: cea82cd3-88de-475a-b6b5-05da42af5d9e

📥 Commits

Reviewing files that changed from the base of the PR and between 8c55446 and 2a4036e.

📒 Files selected for processing (1)
  • src/main/resources/db/migration/V3__normalize_legacy_playing_midi_data.sql

Comment on lines +89 to +101
SELECT jsonb_agg(
(midi_event - 'timestampMs' - 'sequence')
|| jsonb_build_object(
'sequence', COALESCE(
NULLIF(midi_event -> 'sequence', 'null'::JSONB),
to_jsonb((event_ordinality - 1)::INTEGER)
),
'timestamp_ms', COALESCE(
NULLIF(midi_event -> 'timestamp_ms', 'null'::JSONB),
NULLIF(midi_event -> 'timestampMs', 'null'::JSONB)
)
)
ORDER BY event_ordinality

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

sequence 기본값의 의미를 재확인하세요.

MidiEventData.sequence의 주석은 "동일 timestamp 내 순서 값"입니다. 여기서는 배열 전체의 0-based 인덱스를 넣습니다. 값은 sequence >= 0 검증을 통과하지만, 의미는 원래 정의와 다릅니다. 이후 동일 timestamp 그룹을 sequence로 정렬하거나 그룹 크기를 계산하는 로직이 추가되면 잘못된 결과가 나옵니다.

동일 timestamp 내 순번으로 채우려면 timestamp 값으로 파티션한 윈도 함수를 사용하세요.

♻️ timestamp 기준 순번을 부여하는 예시
             SELECT jsonb_agg(
                 (midi_event - 'timestampMs' - 'sequence')
                     || jsonb_build_object(
                         'sequence', COALESCE(
                             NULLIF(midi_event -> 'sequence', 'null'::JSONB),
-                            to_jsonb((event_ordinality - 1)::INTEGER)
+                            to_jsonb((row_number() OVER (
+                                PARTITION BY COALESCE(
+                                    NULLIF(midi_event -> 'timestamp_ms', 'null'::JSONB),
+                                    NULLIF(midi_event -> 'timestampMs', 'null'::JSONB)
+                                )
+                                ORDER BY event_ordinality
+                            ) - 1)::INTEGER)
                         ),

참고: PostgreSQL 윈도 함수 문서(row_number, PARTITION BY)를 확인하세요. 윈도 함수와 jsonb_agg 집계를 같은 SELECT 절에 두면 계산 순서 문제가 생기므로, 서브쿼리로 순번을 먼저 계산한 뒤 집계하는 구조를 권장합니다.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/resources/db/migration/V3__normalize_legacy_playing_midi_data.sql`
around lines 89 - 101, Update the sequence fallback in the JSON aggregation to
represent the 0-based order within each identical timestamp group, rather than
the array-wide event_ordinality. Compute the timestamp-partitioned row number in
a subquery before jsonb_agg, while preserving existing sequence values and
timestamp_ms fallback behavior.

@on1yoneprivate
on1yoneprivate merged commit 4fe7edf into develop Aug 1, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants