Skip to content

Commit

Permalink
Add anthem and verse data migration
Browse files Browse the repository at this point in the history
  • Loading branch information
DavidRobertAnsart committed May 5, 2024
1 parent 958b6d8 commit b776cf2
Show file tree
Hide file tree
Showing 12 changed files with 252 additions and 12 deletions.
240 changes: 240 additions & 0 deletions server/migrations/1714929595777-new-anthem-data.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,240 @@
import type { MigrationInterface, QueryRunner } from 'typeorm';

import type { AnthemData } from '../../types/anthem.type';
import type { ClassAnthemData } from '../../types/classAnthem.types';

enum SampleType {
VOCALS = 0,
HARMONIC1 = 1,
HARMONIC2 = 2,
MELODIC1 = 3,
MELODIC2 = 4,
RYTHMIC1 = 5,
RYTHMIC2 = 6,
INTRO_CHORUS = 7,
OUTRO = 8,
}
type Syllable = {
value: string;
back: boolean;
};
type Sample = {
value: string;
display: boolean;
label: string;
type: SampleType;
time: number;
};
type OldAnthemData = {
verseAudios: Sample[];
introOutro: Sample[];
verseLyrics: Syllable[];
chorus: Syllable[];
finalVerse: string;
finalMix: string;
verseTime: number;
};
type OldVerseData = {
verseAudios: Sample[];
introOutro: Sample[];
verseLyrics: Syllable[];
chorus: Syllable[];
verse: string;
verseStart: number;
customizedMix: string;
customizedMixBlob?: Blob;
verseTime: number;
mixWithoutLyrics: string;
classRecord: string;
slicedRecord: string;
customizedMixWithVocals: string;
};

const sampleTypeToTrackType = {
[SampleType.VOCALS]: 1,
[SampleType.HARMONIC1]: 2,
[SampleType.HARMONIC2]: 3,
[SampleType.MELODIC1]: 4,
[SampleType.MELODIC2]: 5,
[SampleType.RYTHMIC1]: 6,
[SampleType.RYTHMIC2]: 7,
[SampleType.INTRO_CHORUS]: 0,
[SampleType.OUTRO]: 8,
};
const trackTypeToSampleType = {
1: SampleType.VOCALS,
2: SampleType.HARMONIC1,
3: SampleType.HARMONIC2,
4: SampleType.MELODIC1,
5: SampleType.MELODIC2,
6: SampleType.RYTHMIC1,
7: SampleType.RYTHMIC2,
0: SampleType.INTRO_CHORUS,
8: SampleType.OUTRO,
9: SampleType.VOCALS,
};

type NewAnthemData = AnthemData;
type NewVerseData = ClassAnthemData;

const isOldAnthemData = (data: unknown): data is OldAnthemData => typeof data === 'object' && data !== null && 'introOutro' in data;
const isOldVerseData = (data: unknown): data is OldVerseData => typeof data === 'object' && data !== null && 'introOutro' in data;

const isNewAnthemData = (data: unknown): data is NewAnthemData => typeof data === 'object' && data !== null && 'tracks' in data;
const isNewVerseData = (data: unknown): data is NewVerseData => typeof data === 'object' && data !== null && 'tracks' in data;

export class NewAnthemData1714929595777 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
// Update current anthems and verses to use new data structure

const anthems: { id: number; data: unknown }[] = await queryRunner.query('SELECT `id`, `data` FROM `activity` WHERE `type` = 11');
for (const { id, data } of anthems) {
if (isOldAnthemData(data)) {
const newData: NewAnthemData = {
tracks: [
...data.verseAudios.map((sample) => ({
type: sampleTypeToTrackType[sample.type],
label: sample.label,
sampleUrl: sample.value,
sampleDuration: sample.time,
sampleStartTime: 0,
sampleVolume: 0.5,
iconUrl: 'accordion',
})),
...data.introOutro.map((sample) => ({
type: sampleTypeToTrackType[sample.type],
label: sample.label,
sampleUrl: sample.value,
sampleDuration: 0,
sampleStartTime: 0,
sampleVolume: 0.5,
iconUrl: 'accordion',
})),
],
verseLyrics: data.verseLyrics,
chorusLyrics: data.chorus,
mixUrl: data.finalVerse,
fullMixUrl: data.finalMix,
};
await queryRunner.query('UPDATE `activity` SET `data` = ? WHERE `id` = ?', [JSON.stringify(newData), id]);
}
}

const verses: { id: number; data: unknown }[] = await queryRunner.query('SELECT `id`, `data` FROM `activity` WHERE `type` = 12');
for (const { id, data } of verses) {
if (isOldVerseData(data)) {
const newData: NewVerseData = {
anthemTracks: [
...data.verseAudios.map((sample) => ({
type: sampleTypeToTrackType[sample.type],
label: sample.label,
sampleUrl: sample.value,
sampleDuration: sample.time,
sampleStartTime: 0,
sampleVolume: 0.5,
iconUrl: 'accordion',
})),
...data.introOutro.map((sample) => ({
type: sampleTypeToTrackType[sample.type],
label: sample.label,
sampleUrl: sample.value,
sampleDuration: 0,
sampleStartTime: 0,
sampleVolume: 0.5,
iconUrl: 'accordion',
})),
],
classRecordTrack: {
type: 9,
label: '',
sampleUrl: data.classRecord,
sampleDuration: data.verseTime,
sampleStartTime: data.verseStart,
sampleVolume: 1,
iconUrl: 'accordion',
},
verseLyrics: data.verseLyrics,
chorusLyrics: data.chorus,
verseMixUrl: data.mixWithoutLyrics,
verseMixWithIntroUrl: '',
verseMixWithVocalsUrl: data.customizedMix,
verseFinalMixUrl: data.customizedMixWithVocals,
};
await queryRunner.query('UPDATE `activity` SET `data` = ? WHERE `id` = ?', [JSON.stringify(newData), id]);
}
}
}

public async down(queryRunner: QueryRunner): Promise<void> {
// Revert current anthems and verses to use old data structure

const anthems: { id: number; data: unknown }[] = await queryRunner.query('SELECT `id`, `data` FROM `activity` WHERE `type` = 11');
for (const { id, data } of anthems) {
if (isNewAnthemData(data)) {
const newData: OldAnthemData = {
verseAudios: data.tracks
.filter((track) => track.type !== 0 && track.type !== 8)
.map((track) => ({
value: track.sampleUrl,
display: true,
label: track.label,
type: trackTypeToSampleType[track.type],
time: track.sampleDuration,
})),
introOutro: data.tracks
.filter((track) => track.type === 0 || track.type === 8)
.map((track) => ({
value: track.sampleUrl,
display: true,
label: track.label,
type: trackTypeToSampleType[track.type],
time: track.sampleDuration,
})),
verseLyrics: data.verseLyrics,
chorus: data.chorusLyrics,
finalVerse: data.mixUrl ?? '',
finalMix: data.fullMixUrl ?? '',
verseTime: data.tracks.find((track) => track.type === 1)?.sampleDuration ?? 0,
};
await queryRunner.query('UPDATE `activity` SET `data` = ? WHERE `id` = ?', [JSON.stringify(newData), id]);
}
}

const verses: { id: number; data: unknown }[] = await queryRunner.query('SELECT `id`, `data` FROM `activity` WHERE `type` = 12');
for (const { id, data } of verses) {
if (isNewVerseData(data)) {
const newData: OldVerseData = {
verseAudios: data.anthemTracks
.filter((track) => track.type !== 0 && track.type !== 8)
.map((track) => ({
value: track.sampleUrl,
display: true,
label: track.label,
type: trackTypeToSampleType[track.type],
time: track.sampleDuration,
})),
introOutro: data.anthemTracks
.filter((track) => track.type === 0 || track.type === 8)
.map((track) => ({
value: track.sampleUrl,
display: true,
label: track.label,
type: trackTypeToSampleType[track.type],
time: track.sampleDuration,
})),
verseLyrics: data.verseLyrics,
chorus: data.chorusLyrics,
verse: '',
verseStart: data.classRecordTrack.sampleStartTime,
customizedMix: data.verseMixWithVocalsUrl,
verseTime: data.classRecordTrack.sampleDuration,
mixWithoutLyrics: data.verseMixUrl,
classRecord: data.classRecordTrack.sampleUrl,
slicedRecord: data.classRecordTrack.sampleUrl,
customizedMixWithVocals: data.verseFinalMixUrl,
};
await queryRunner.query('UPDATE `activity` SET `data` = ? WHERE `id` = ?', [JSON.stringify(newData), id]);
}
}
}
}
2 changes: 1 addition & 1 deletion src/activity-types/activity.constants.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { ActivityType } from '../../types/activity.type';
import { DEFI } from './defi.constants';
import { ENIGME } from './enigme.constants';
import { INDICE } from './indice.constants';
import { REPORTAGE } from './reportage.constants';
import { SYMBOL } from './symbol.constants';
import { ActivityType } from 'types/activity.type';

export const getType = (typeValue: number): string | undefined => {
const type = Object.keys(ActivityType).find((key) => ActivityType[key] === typeValue);
Expand Down
2 changes: 1 addition & 1 deletion src/activity-types/anyActivity.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import type { AnthemActivity } from '../../types/anthem.type';
import type { GameActivity } from '../../types/game.type';
import type { ClassAnthemActivity } from './classAnthem.types';
import type { DefiActivity } from './defi.types';
import type { EnigmeActivity } from './enigme.types';
import type { FreeContentActivity } from './freeContent.types';
Expand All @@ -13,6 +12,7 @@ import type { ReportageActivity } from './reportage.types';
import type { SymbolActivity } from './symbol.types';
import { ActivityType } from 'types/activity.type';
import type { Activity } from 'types/activity.type';
import type { ClassAnthemActivity } from 'types/classAnthem.types';
import type { StoryActivity } from 'types/story.type';

export const isPresentation = (activity: Activity): activity is PresentationActivity => {
Expand Down
2 changes: 1 addition & 1 deletion src/components/activities/ActivityCard/VerseRecordCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Button } from '@mui/material';

import { CommentIcon } from './CommentIcon';
import type { ActivityCardProps } from './activity-card.types';
import type { ClassAnthemActivity } from 'src/activity-types/classAnthem.types';
import type { ClassAnthemActivity } from 'types/classAnthem.types';
import { RedButton } from 'src/components/buttons/RedButton';

Check failure on line 9 in src/components/activities/ActivityCard/VerseRecordCard.tsx

View workflow job for this annotation

GitHub Actions / lint

`src/components/buttons/RedButton` import should occur before import of `types/classAnthem.types`

export const VerseRecordCard = ({ activity, isSelf, noButtons, isDraft, showEditButtons, onDelete }: ActivityCardProps<ClassAnthemActivity>) => (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react';

import type { ActivityViewProps } from './activity-view.types';
import type { ClassAnthemActivity } from 'src/activity-types/classAnthem.types';
import type { ClassAnthemActivity } from 'types/classAnthem.types';

Check failure on line 4 in src/components/activities/ActivityView/VerseActivityView.tsx

View workflow job for this annotation

GitHub Actions / lint

`types/classAnthem.types` import should occur after import of `src/styles/variables.const`
import { SyllableEditor } from 'src/components/activities/content/editors/SyllableEditor';
import { bgPage } from 'src/styles/variables.const';

Expand Down
2 changes: 1 addition & 1 deletion src/pages/chanter-un-couplet/1.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import Backdrop from '@mui/material/Backdrop';
import CircularProgress from '@mui/material/CircularProgress';

import styles from '../../styles/chanter-un-couplet.module.css';
import type { ClassAnthemData } from 'src/activity-types/classAnthem.types';
import type { ClassAnthemData } from 'types/classAnthem.types';

Check failure on line 8 in src/pages/chanter-un-couplet/1.tsx

View workflow job for this annotation

GitHub Actions / lint

`types/classAnthem.types` import should occur after import of `types/anthem.type`
import { postMixAudio } from 'src/api/audio/audio-mix.post';
import { deleteAudio } from 'src/api/audio/audio.delete';
import { Base } from 'src/components/Base';
Expand Down
2 changes: 1 addition & 1 deletion src/pages/chanter-un-couplet/2.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useRouter } from 'next/router';
import React from 'react';

import styles from '../../styles/chanter-un-couplet.module.css';
import type { ClassAnthemData } from 'src/activity-types/classAnthem.types';
import type { ClassAnthemData } from 'types/classAnthem.types';

Check failure on line 5 in src/pages/chanter-un-couplet/2.tsx

View workflow job for this annotation

GitHub Actions / lint

`types/classAnthem.types` import should occur after import of `types/anthem.type`
import { Base } from 'src/components/Base';
import { Steps } from 'src/components/Steps';
import { StepsButton } from 'src/components/StepsButtons';
Expand Down
2 changes: 1 addition & 1 deletion src/pages/chanter-un-couplet/3.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useRouter } from 'next/router';
import React from 'react';

import styles from '../../styles/chanter-un-couplet.module.css';
import type { ClassAnthemData } from 'src/activity-types/classAnthem.types';
import type { ClassAnthemData } from 'types/classAnthem.types';

Check failure on line 5 in src/pages/chanter-un-couplet/3.tsx

View workflow job for this annotation

GitHub Actions / lint

`types/classAnthem.types` import should occur after import of `types/anthem.type`
import { Base } from 'src/components/Base';
import { Steps } from 'src/components/Steps';
import { StepsButton } from 'src/components/StepsButtons';
Expand Down
2 changes: 1 addition & 1 deletion src/pages/chanter-un-couplet/4.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import Button from '@mui/material/Button';
import CircularProgress from '@mui/material/CircularProgress';

import styles from '../../styles/chanter-un-couplet.module.css';
import type { ClassAnthemData } from 'src/activity-types/classAnthem.types';
import type { ClassAnthemData } from 'types/classAnthem.types';

Check failure on line 10 in src/pages/chanter-un-couplet/4.tsx

View workflow job for this annotation

GitHub Actions / lint

`types/classAnthem.types` import should occur after import of `types/anthem.type`
import { postMixAudio } from 'src/api/audio/audio-mix.post';
import { deleteAudio } from 'src/api/audio/audio.delete';
import { Base } from 'src/components/Base';
Expand Down
2 changes: 1 addition & 1 deletion src/pages/chanter-un-couplet/5.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import Backdrop from '@mui/material/Backdrop';
import Button from '@mui/material/Button';
import CircularProgress from '@mui/material/CircularProgress';

import type { ClassAnthemData } from 'src/activity-types/classAnthem.types';
import type { ClassAnthemData } from 'types/classAnthem.types';

Check failure on line 10 in src/pages/chanter-un-couplet/5.tsx

View workflow job for this annotation

GitHub Actions / lint

`types/classAnthem.types` import should occur after import of `types/activity.type`
import { Base } from 'src/components/Base';
import { Steps } from 'src/components/Steps';
import { StepsButton } from 'src/components/StepsButtons';
Expand Down
2 changes: 1 addition & 1 deletion src/pages/chanter-un-couplet/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useRouter } from 'next/router';
import React from 'react';

import type { ClassAnthemData } from 'src/activity-types/classAnthem.types';
import type { ClassAnthemData } from 'types/classAnthem.types';

Check failure on line 4 in src/pages/chanter-un-couplet/index.tsx

View workflow job for this annotation

GitHub Actions / lint

`types/classAnthem.types` import should occur after import of `types/anthem.type`
import { Base } from 'src/components/Base';
import { StepsButton } from 'src/components/StepsButtons';
import { AudioPlayer } from 'src/components/audio/AudioPlayer';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { Activity } from 'types/activity.type';
import type { Syllable, Track } from 'types/anthem.type';
import type { Activity } from './activity.type';
import type { Syllable, Track } from './anthem.type';

export type ClassAnthemData = {
anthemTracks: Track[];
Expand Down

0 comments on commit b776cf2

Please sign in to comment.