-
Notifications
You must be signed in to change notification settings - Fork 2
[FIX] 구형 MIDI 데이터 호환 마이그레이션 추가 #112
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
116 changes: 116 additions & 0 deletions
116
src/main/resources/db/migration/V3__normalize_legacy_playing_midi_data.sql
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,116 @@ | ||
| DO | ||
| $$ | ||
| DECLARE | ||
| playing_row RECORD; | ||
| midi_event JSONB; | ||
| event_ordinality BIGINT; | ||
| timestamp_value JSONB; | ||
| numeric_value NUMERIC; | ||
| BEGIN | ||
| FOR playing_row IN | ||
| SELECT playing_id, midi_data | ||
| FROM playing | ||
| WHERE midi_data IS NOT NULL | ||
| LOOP | ||
| IF jsonb_typeof(playing_row.midi_data) IS DISTINCT FROM 'array' THEN | ||
| RAISE EXCEPTION 'playing %.midi_data must be a JSON array', playing_row.playing_id; | ||
| END IF; | ||
|
|
||
| FOR midi_event, event_ordinality IN | ||
| SELECT value, ordinality | ||
| FROM jsonb_array_elements(playing_row.midi_data) WITH ORDINALITY | ||
| LOOP | ||
| IF jsonb_typeof(midi_event) IS DISTINCT FROM 'object' THEN | ||
| RAISE EXCEPTION 'playing %.midi_data[%] must be a JSON object', | ||
| playing_row.playing_id, event_ordinality - 1; | ||
| END IF; | ||
|
|
||
| IF jsonb_typeof(midi_event -> 'type') IS DISTINCT FROM 'string' | ||
| OR midi_event ->> 'type' NOT IN ('NOTE_ON', 'NOTE_OFF') THEN | ||
| RAISE EXCEPTION 'playing %.midi_data[%] has an invalid type', | ||
| playing_row.playing_id, event_ordinality - 1; | ||
| END IF; | ||
|
|
||
| IF jsonb_typeof(midi_event -> 'pitch') IS DISTINCT FROM 'number' THEN | ||
| RAISE EXCEPTION 'playing %.midi_data[%] has an invalid pitch', | ||
| playing_row.playing_id, event_ordinality - 1; | ||
| END IF; | ||
| numeric_value := (midi_event ->> 'pitch')::NUMERIC; | ||
| IF numeric_value <> trunc(numeric_value) OR numeric_value < 0 OR numeric_value > 127 THEN | ||
| RAISE EXCEPTION 'playing %.midi_data[%] has an invalid pitch', | ||
| playing_row.playing_id, event_ordinality - 1; | ||
| END IF; | ||
|
|
||
| IF jsonb_typeof(midi_event -> 'velocity') IS DISTINCT FROM 'number' THEN | ||
| RAISE EXCEPTION 'playing %.midi_data[%] has an invalid velocity', | ||
| playing_row.playing_id, event_ordinality - 1; | ||
| END IF; | ||
| numeric_value := (midi_event ->> 'velocity')::NUMERIC; | ||
| IF numeric_value <> trunc(numeric_value) OR numeric_value < 0 OR numeric_value > 127 THEN | ||
| RAISE EXCEPTION 'playing %.midi_data[%] has an invalid velocity', | ||
| playing_row.playing_id, event_ordinality - 1; | ||
| END IF; | ||
|
|
||
| timestamp_value := COALESCE( | ||
| NULLIF(midi_event -> 'timestamp_ms', 'null'::JSONB), | ||
| NULLIF(midi_event -> 'timestampMs', 'null'::JSONB) | ||
| ); | ||
| IF jsonb_typeof(timestamp_value) IS DISTINCT FROM 'number' THEN | ||
| RAISE EXCEPTION 'playing %.midi_data[%] has an invalid timestamp', | ||
| playing_row.playing_id, event_ordinality - 1; | ||
| END IF; | ||
| numeric_value := (timestamp_value #>> '{}')::NUMERIC; | ||
| IF numeric_value <> trunc(numeric_value) OR numeric_value < 0 OR numeric_value > 9223372036854775807 THEN | ||
| RAISE EXCEPTION 'playing %.midi_data[%] has an invalid timestamp', | ||
| playing_row.playing_id, event_ordinality - 1; | ||
| END IF; | ||
|
|
||
| IF NULLIF(midi_event -> 'sequence', 'null'::JSONB) IS NOT NULL THEN | ||
| IF jsonb_typeof(midi_event -> 'sequence') IS DISTINCT FROM 'number' THEN | ||
| RAISE EXCEPTION 'playing %.midi_data[%] has an invalid sequence', | ||
| playing_row.playing_id, event_ordinality - 1; | ||
| END IF; | ||
| numeric_value := (midi_event ->> 'sequence')::NUMERIC; | ||
| IF numeric_value <> trunc(numeric_value) OR numeric_value < 0 OR numeric_value > 2147483647 THEN | ||
| RAISE EXCEPTION 'playing %.midi_data[%] has an invalid sequence', | ||
| playing_row.playing_id, event_ordinality - 1; | ||
| END IF; | ||
| END IF; | ||
| END LOOP; | ||
| END LOOP; | ||
| END | ||
| $$; | ||
|
|
||
| UPDATE playing AS p | ||
| SET midi_data = CASE | ||
| WHEN p.midi_data IS NULL THEN '[]'::JSONB | ||
| ELSE COALESCE( | ||
| ( | ||
| 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 | ||
| ) | ||
| FROM jsonb_array_elements(p.midi_data) WITH ORDINALITY | ||
| AS events(midi_event, event_ordinality) | ||
| ), | ||
| '[]'::JSONB | ||
| ) | ||
| END | ||
| WHERE p.midi_data IS NULL | ||
| OR EXISTS ( | ||
| SELECT 1 | ||
| FROM jsonb_array_elements(p.midi_data) AS events(midi_event) | ||
| WHERE NULLIF(midi_event -> 'sequence', 'null'::JSONB) IS NULL | ||
| OR NULLIF(midi_event -> 'timestamp_ms', 'null'::JSONB) IS NULL | ||
| OR midi_event ? 'timestampMs' | ||
| ); | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
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