added test case for episode; improved types; minor improvements

main
Inga 🏳‍🌈 6 months ago
parent 08840712af
commit 92d836a9f5
  1. 49
      src/integration/movies/omdb/converters.spec.ts
  2. 8
      src/integration/movies/omdb/converters.ts
  3. 7
      src/integration/movies/omdb/types.ts
  4. 43
      src/integration/movies/types.ts
  5. 6
      src/utils/objectHelpers.ts

@ -268,4 +268,53 @@ describe('normalizeRawOmdbData', () => {
writers: ['Olivia Vieweg'], writers: ['Olivia Vieweg'],
}); });
}); });
it('normalizes data correctly for tt10703258 (episode)', () => {
const result = normalizeRawOmdbData({
Title: "Seo Hee's Resentment",
Year: '2019',
Rated: 'N/A',
Released: '24 Aug 2019',
Season: '1',
Episode: '13',
Runtime: '82 min',
Genre: 'Action, Comedy, Drama',
Director: 'Choong Hwan Oh',
Writer: 'Jeong-eun Hong, Mi-ran Hong',
Actors: 'Ji-eun Lee, Yeo Jin-gu, Shin Jeong-geun',
Plot: "Choi Seo Hee prepares to move on to the next life. The killer ghost terrorizes Chan Seong's friends. Man Wol witnesses a startling relationship.",
Language: 'Korean',
Country: 'South Korea',
Awards: 'N/A',
Poster: 'https://m.media-amazon.com/images/M/MV5BODVlYzg4MWYtOTU2Ny00OWY0LWIzYTItNWExYmM3MjJhNmJjXkEyXkFqcGdeQXVyNzk0NTA5NQ@@._V1_SX300.jpg',
Ratings: [],
Metascore: 'N/A',
imdbRating: 'N/A',
imdbVotes: '147',
imdbID: 'tt10703258',
seriesID: 't10220588',
Type: 'episode',
});
expect(result).toEqual({
actors: ['Ji-eun Lee', 'Yeo Jin-gu', 'Shin Jeong-geun'],
description:
"Choi Seo Hee prepares to move on to the next life. The killer ghost terrorizes Chan Seong's friends. Man Wol witnesses a startling relationship.",
directors: ['Choong Hwan Oh'],
duration: 82,
episodeNumber: 13,
genres: ['Action', 'Comedy', 'Drama'],
imdbId: 'tt10703258',
posterUrl:
'https://m.media-amazon.com/images/M/MV5BODVlYzg4MWYtOTU2Ny00OWY0LWIzYTItNWExYmM3MjJhNmJjXkEyXkFqcGdeQXVyNzk0NTA5NQ@@._V1_SX300.jpg',
productionCountries: ['South Korea'],
productionYear: 2019,
ratings: [],
releaseDate: '24 Aug 2019',
seasonNumber: 1,
seriesImdbId: 't10220588',
title: "Seo Hee's Resentment",
type: 'episode',
writers: ['Jeong-eun Hong', 'Mi-ran Hong'],
});
});
}); });

@ -30,6 +30,7 @@ export const normalizeRawOmdbData = (
Country, Country,
DVD, DVD,
Director, Director,
Episode,
Genre, Genre,
Language: _language, Language: _language,
Metascore: _metascore, Metascore: _metascore,
@ -40,6 +41,7 @@ export const normalizeRawOmdbData = (
Ratings, Ratings,
Released, Released,
Runtime, Runtime,
Season,
Title, Title,
Type, Type,
Website, Website,
@ -48,6 +50,7 @@ export const normalizeRawOmdbData = (
imdbID, imdbID,
imdbRating: _imdbRating, imdbRating: _imdbRating,
imdbVotes: _imdbVotes, imdbVotes: _imdbVotes,
seriesID,
totalSeasons, totalSeasons,
...rest ...rest
} = rawOmdbData; } = rawOmdbData;
@ -61,13 +64,14 @@ export const normalizeRawOmdbData = (
return { return {
...createRequiredField('actors', Actors, stringToArray), ...createRequiredField('actors', Actors, stringToArray),
...createRequiredField('awards', Awards, identity), ...createOptionalField('awards', Awards, identity),
...createOptionalField('boxOffice', BoxOffice, identity), ...createOptionalField('boxOffice', BoxOffice, identity),
...createOptionalField('contentRating', Rated, identity), ...createOptionalField('contentRating', Rated, identity),
...createRequiredField('description', Plot, identity), ...createRequiredField('description', Plot, identity),
...createOptionalField('directors', Director, stringToArray), ...createOptionalField('directors', Director, stringToArray),
...createRequiredField('duration', Runtime, stringToDuration), ...createRequiredField('duration', Runtime, stringToDuration),
...createOptionalField('dvdReleaseDate', DVD, identity), ...createOptionalField('dvdReleaseDate', DVD, identity),
...createOptionalField('episodeNumber', Episode, stringToNumber),
...createRequiredField('genres', Genre, stringToArray), ...createRequiredField('genres', Genre, stringToArray),
...createRequiredField('imdbId', imdbID, identity), ...createRequiredField('imdbId', imdbID, identity),
...createRequiredField('posterUrl', Poster, identity), ...createRequiredField('posterUrl', Poster, identity),
@ -79,6 +83,8 @@ export const normalizeRawOmdbData = (
omdbRatingsToNormalizedRatings, omdbRatingsToNormalizedRatings,
), ),
...createRequiredField('releaseDate', Released, identity), ...createRequiredField('releaseDate', Released, identity),
...createOptionalField('seasonNumber', Season, stringToNumber),
...createOptionalField('seriesImdbId', seriesID, identity),
...createRequiredField('title', Title, identity), ...createRequiredField('title', Title, identity),
...createOptionalField('totalSeasons', totalSeasons, stringToNumber), ...createOptionalField('totalSeasons', totalSeasons, stringToNumber),
...createRequiredField('type', Type, identity), ...createRequiredField('type', Type, identity),

@ -1,10 +1,11 @@
export type RawOmdbData = { export type RawOmdbData = {
Actors: string; Actors: string;
Awards: string; Awards?: string;
BoxOffice?: string; BoxOffice?: string;
Country: string; Country: string;
DVD?: string; DVD?: string;
Director: string; Director: string;
Episode?: string;
Genre: string; Genre: string;
Language: string; Language: string;
Metascore: string; Metascore: string;
@ -18,14 +19,16 @@ export type RawOmdbData = {
}[]; }[];
Released: string; Released: string;
Runtime: string; Runtime: string;
Season?: string;
Title: string; Title: string;
Type: 'movie' | 'series'; Type: 'movie' | 'series' | 'episode';
Website?: string; Website?: string;
Writer: string; Writer: string;
Year: string; Year: string;
imdbID: string; imdbID: string;
imdbRating: string; imdbRating: string;
imdbVotes: string; imdbVotes: string;
seriesID?: string;
totalSeasons?: string; totalSeasons?: string;
}; };

@ -6,12 +6,15 @@ type MovieData = {
description: string; description: string;
localDescription: string; localDescription: string;
posterUrl: string; posterUrl: string;
type: 'movie' | 'series'; type: 'movie' | 'series' | 'episode';
seriesImdbId?: string;
episodeNumber?: number;
seasonNumber?: number;
/** /**
* A whole number of minutes * A whole number of minutes
*/ */
duration: number; duration: number;
totalSeasons: number; totalSeasons?: number;
/** /**
* Two-letter code * Two-letter code
*/ */
@ -22,45 +25,33 @@ type MovieData = {
availableLanguages: string[]; availableLanguages: string[];
productionYear: number; productionYear: number;
releaseDate: string; releaseDate: string;
dvdReleaseDate: string; dvdReleaseDate?: string;
genres: string[]; genres: string[];
directors: string[]; directors?: string[];
writers: string[]; writers: string[];
actors: string[]; actors: string[];
studios: string[]; studios: string[];
awards: string; awards?: string;
productionCountries: string[]; productionCountries: string[];
boxOffice: string; boxOffice?: string;
contentRating: string; contentRating?: string;
website: string; website?: string;
ratings: { ratings: {
source: string; source: string;
value: string; value: string;
}[]; }[];
}; };
type StrictPartial< export type NormalizedOmdbData = Omit<
T,
TForbiddenKeys extends keyof T,
TOptionalKeys extends Exclude<keyof T, TForbiddenKeys>,
> = Omit<T, TForbiddenKeys | TOptionalKeys> & Partial<Pick<T, TOptionalKeys>>;
export type NormalizedOmdbData = StrictPartial<
MovieData, MovieData,
| 'availableLanguages' | 'availableLanguages'
| 'localDescription' | 'localDescription'
| 'localTitle' | 'localTitle'
| 'originalLanguage' | 'originalLanguage'
| 'studios', | 'studios'
| 'boxOffice'
| 'contentRating'
| 'directors'
| 'dvdReleaseDate'
| 'totalSeasons'
| 'website'
>; >;
export type NormalizedInternalData = StrictPartial< export type NormalizedInternalData = Omit<
MovieData, MovieData,
| 'actors' | 'actors'
| 'awards' | 'awards'
@ -69,16 +60,18 @@ export type NormalizedInternalData = StrictPartial<
| 'description' | 'description'
| 'directors' | 'directors'
| 'dvdReleaseDate' | 'dvdReleaseDate'
| 'episodeNumber'
| 'genres' | 'genres'
| 'posterUrl' | 'posterUrl'
| 'productionCountries' | 'productionCountries'
| 'releaseDate' | 'releaseDate'
| 'seasonNumber'
| 'seriesImdbId'
| 'title' | 'title'
| 'totalSeasons' | 'totalSeasons'
| 'type' | 'type'
| 'website' | 'website'
| 'writers', | 'writers'
never
> & { > & {
internalId: number; internalId: number;
}; };

@ -9,7 +9,7 @@ export const createTargetHelpers = <TTarget>(
>( >(
key: TKey, key: TKey,
value: TRawValue, value: TRawValue,
transformer: (value: TRawValue) => TTarget[TKey], transformer: (value: TRawValue) => Exclude<TTarget[TKey], undefined>,
) => { ) => {
if (value === undefined) { if (value === undefined) {
throw new Error(`Value for ${key} is not defined`); throw new Error(`Value for ${key} is not defined`);
@ -30,7 +30,9 @@ export const createTargetHelpers = <TTarget>(
>( >(
key: TKey, key: TKey,
value: TRawValue, value: TRawValue,
transformer: (value: Exclude<TRawValue, undefined>) => TTarget[TKey], transformer: (
value: Exclude<TRawValue, undefined>,
) => Exclude<TTarget[TKey], undefined>,
) => { ) => {
if (value === undefined || missingValueIndicators.includes(value)) { if (value === undefined || missingValueIndicators.includes(value)) {
return undefined; return undefined;

Loading…
Cancel
Save