implemented enrichment service (without search support)

main
Inga 🏳‍🌈 5 months ago
parent 92d836a9f5
commit f7b261f513
  1. 1
      .eslintrc.js
  2. 2
      src/app.controller.spec.ts
  3. 4
      src/integration/movies/internal/converters.ts
  4. 10
      src/integration/movies/internal/index.ts
  5. 7
      src/integration/movies/internal/storage.ts
  6. 1
      src/integration/movies/internal/types.ts
  7. 4
      src/integration/movies/omdb/apiClient.ts
  8. 4
      src/integration/movies/omdb/converters.ts
  9. 4
      src/integration/movies/omdb/index.spec.ts
  10. 17
      src/integration/movies/omdb/index.ts
  11. 398
      src/services/omdbEnrichedDataService.spec.ts
  12. 41
      src/services/omdbEnrichedDataService.ts
  13. 15
      src/types.ts
  14. 4
      test/app.e2e-spec.ts

@ -17,6 +17,7 @@ module.exports = {
},
ignorePatterns: ['.eslintrc.js'],
rules: {
'@typescript-eslint/consistent-type-imports': 'error',
'@typescript-eslint/interface-name-prefix': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',

@ -1,4 +1,4 @@
import { Test, TestingModule } from '@nestjs/testing';
import { Test, type TestingModule } from '@nestjs/testing';
import { AppController } from './app.controller';
import { AppService } from './app.service';

@ -1,6 +1,6 @@
import type { NormalizedInternalData } from '../../../types';
import { createTargetHelpers, identity } from '../../../utils/objectHelpers';
import { NormalizedInternalData } from '../types';
import { StoredData } from './types';
import type { StoredData } from './types';
const { createRequiredField } = createTargetHelpers<NormalizedInternalData>([
null,

@ -1,4 +1,4 @@
import { InternalProvider } from '../types';
import type { InternalProvider } from '../../../types';
import { normalizeRawInternalData } from './converters';
import { createStorageClient } from './storage';
@ -6,7 +6,7 @@ export const createInternalProvider = (): InternalProvider => {
const storageClient = createStorageClient();
return {
getMetadataByInternalId: async (internalId: number) => {
getMetadataByInternalId: async (internalId) => {
const rawInternalData =
await storageClient.getMetadataByInternalId(internalId);
if (!rawInternalData) {
@ -15,7 +15,7 @@ export const createInternalProvider = (): InternalProvider => {
return normalizeRawInternalData(rawInternalData);
},
getMetadataByImdbId: async (imdbId: string) => {
getMetadataByImdbId: async (imdbId) => {
const rawInternalData =
await storageClient.getMetadataByImdbId(imdbId);
if (!rawInternalData) {
@ -24,5 +24,9 @@ export const createInternalProvider = (): InternalProvider => {
return normalizeRawInternalData(rawInternalData);
},
getAllMetadata: async () => {
const rawInternalData = await storageClient.getAllMetadata();
return rawInternalData.map(normalizeRawInternalData);
},
};
};

@ -2,15 +2,16 @@ import movie1 from '../../../resources/movies/3532674.json';
import movie2 from '../../../resources/movies/5979300.json';
import movie3 from '../../../resources/movies/11043689.json';
import movie4 from '../../../resources/movies/11528860.json';
import { StorageClient } from './types';
import type { StorageClient } from './types';
const movies = [movie1, movie2, movie3, movie4];
export const createStorageClient = (): StorageClient => {
return {
getMetadataByInternalId: async (internalId: number) =>
getMetadataByInternalId: async (internalId) =>
Promise.resolve(movies.find(({ id }) => id == internalId)),
getMetadataByImdbId: async (id: string) =>
getMetadataByImdbId: async (id) =>
Promise.resolve(movies.find(({ imdbId }) => imdbId == id)),
getAllMetadata: async () => Promise.resolve(movies),
};
};

@ -38,4 +38,5 @@ export type StorageClient = {
internalId: number,
): Promise<StoredData | undefined>;
getMetadataByImdbId(imdbId: string): Promise<StoredData | undefined>;
getAllMetadata(): Promise<StoredData[]>;
};

@ -1,6 +1,6 @@
import fetch from 'node-fetch';
import PQueue from 'p-queue';
import { OmdbApiClient, OmdbResponse } from './types';
import type { OmdbApiClient, OmdbResponse } from './types';
export const createOmdbApiClient = (apiKey: string): OmdbApiClient => {
// Rate limit (according to readme, it's 1k per day;
@ -13,7 +13,7 @@ export const createOmdbApiClient = (apiKey: string): OmdbApiClient => {
});
return {
fetchMetadata: async (imdbId: string) =>
fetchMetadata: async (imdbId) =>
queue.add(async () => {
const url = new URL('https://www.omdbapi.com/');
url.searchParams.append('i', imdbId);

@ -1,6 +1,6 @@
import type { NormalizedOmdbData } from '../../../types';
import { createTargetHelpers, identity } from '../../../utils/objectHelpers';
import { NormalizedOmdbData } from '../types';
import { RawOmdbData } from './types';
import type { RawOmdbData } from './types';
const { createRequiredField, createOptionalField } =
createTargetHelpers<NormalizedOmdbData>([null, '', 'N/A']);

@ -1,9 +1,9 @@
import { describe, it, expect } from '@jest/globals';
import { createOmdbProvider } from './index';
import { createOmdbProviderByApiKey } from './index';
describe('createOmdbProvider', () => {
const client = createOmdbProvider('68fd98ab');
const client = createOmdbProviderByApiKey('68fd98ab');
it('returns correct data for tt10687116', async () => {
const result = await client.getMetadata('tt10687116');
expect(result).toMatchObject({

@ -1,12 +1,13 @@
import { OmdbProvider } from '../types';
import type { OmdbProvider } from '../../../types';
import { createOmdbApiClient } from './apiClient';
import { normalizeRawOmdbData } from './converters';
import type { OmdbApiClient } from './types';
export const createOmdbProvider = (apiKey: string): OmdbProvider => {
const apiClient = createOmdbApiClient(apiKey);
export const createOmdbProviderByApiClient = (
apiClient: OmdbApiClient,
): OmdbProvider => {
return {
getMetadata: async (imdbId: string) => {
getMetadata: async (imdbId) => {
const rawOmdbData = await apiClient.fetchMetadata(imdbId);
if (!rawOmdbData) {
return undefined;
@ -16,3 +17,9 @@ export const createOmdbProvider = (apiKey: string): OmdbProvider => {
},
};
};
export const createOmdbProviderByApiKey = (apiKey: string): OmdbProvider => {
const apiClient = createOmdbApiClient(apiKey);
return createOmdbProviderByApiClient(apiClient);
};

@ -0,0 +1,398 @@
import { describe, it, expect } from '@jest/globals';
import { createInternalProvider } from '../integration/movies/internal';
import { createOmdbProviderByApiClient } from '../integration/movies/omdb';
import type {
OmdbApiClient,
RawOmdbData,
} from '../integration/movies/omdb/types';
import { createOmdbEnrichedDataService } from './omdbEnrichedDataService';
const omdbResponses: Record<string, RawOmdbData> = {
tt0401792: {
Title: 'Sin City',
Year: '2005',
Rated: 'R',
Released: '01 Apr 2005',
Runtime: '124 min',
Genre: 'Crime, Thriller',
Director: 'Frank Miller, Quentin Tarantino, Robert Rodriguez',
Writer: 'Frank Miller, Robert Rodriguez',
Actors: 'Mickey Rourke, Clive Owen, Bruce Willis',
Plot: "Four tales of crime adapted from Frank Miller's popular comics, focusing around a muscular brute who's looking for the person responsible for the death of his beloved Goldie (Jaime King), a man fed up with Sin City's corrupt law enforcement who takes the law into his own hands after a horrible mistake, a cop who risks his life to protect a girl from a deformed pedophile and a hitman looking to make a little cash.",
Language: 'English',
Country: 'United States',
Awards: '38 wins & 54 nominations',
Poster: 'https://m.media-amazon.com/images/M/MV5BODZmYjMwNzEtNzVhNC00ZTRmLTk2M2UtNzE1MTQ2ZDAxNjc2XkEyXkFqcGdeQXVyMTQxNzMzNDI@._V1_SX300.jpg',
Ratings: [
{ Source: 'Internet Movie Database', Value: '8.0/10' },
{ Source: 'Rotten Tomatoes', Value: '76%' },
{ Source: 'Metacritic', Value: '74/100' },
],
Metascore: '74',
imdbRating: '8.0',
imdbVotes: '786,745',
imdbID: 'tt0401792',
Type: 'movie',
DVD: '03 Sep 2016',
BoxOffice: '$74,103,820',
Production: 'N/A',
Website: 'N/A',
},
tt0097576: {
Title: 'Indiana Jones and the Last Crusade',
Year: '1989',
Rated: 'PG-13',
Released: '24 May 1989',
Runtime: '127 min',
Genre: 'Action, Adventure',
Director: 'Steven Spielberg',
Writer: 'Jeffrey Boam, George Lucas, Menno Meyjes',
Actors: 'Harrison Ford, Sean Connery, Alison Doody',
Plot: 'An art collector appeals to Indiana Jones to embark on a search for the Holy Grail. He learns that another archaeologist has disappeared while searching for the precious goblet, and the missing man is his own father, Dr. Henry Jones. The artifact is much harder to find than they expected, and its powers are too much for those impure of heart.',
Language: 'English, German, Greek, Latin, Italian',
Country: 'United States',
Awards: 'Won 1 Oscar. 9 wins & 24 nominations total',
Poster: 'https://m.media-amazon.com/images/M/MV5BY2Q0ODg4ZmItNDZiYi00ZWY5LTg2NzctNmYwZjA5OThmNzE1XkEyXkFqcGdeQXVyMjM4MzQ4OTQ@._V1_SX300.jpg',
Ratings: [
{ Source: 'Internet Movie Database', Value: '8.2/10' },
{ Source: 'Rotten Tomatoes', Value: '84%' },
{ Source: 'Metacritic', Value: '65/100' },
],
Metascore: '65',
imdbRating: '8.2',
imdbVotes: '797,615',
imdbID: 'tt0097576',
Type: 'movie',
DVD: '28 Jan 2014',
BoxOffice: '$197,171,806',
Production: 'N/A',
Website: 'N/A',
},
tt0076759: {
Title: 'Star Wars: Episode IV - A New Hope',
Year: '1977',
Rated: 'PG',
Released: '25 May 1977',
Runtime: '121 min',
Genre: 'Action, Adventure, Fantasy',
Director: 'George Lucas',
Writer: 'George Lucas',
Actors: 'Mark Hamill, Harrison Ford, Carrie Fisher',
Plot: 'The Imperial Forces, under orders from cruel Darth Vader, hold Princess Leia hostage in their efforts to quell the rebellion against the Galactic Empire. Luke Skywalker and Han Solo, captain of the Millennium Falcon, work together with the companionable droid duo R2-D2 and C-3PO to rescue the beautiful princess, help the Rebel Alliance and restore freedom and justice to the Galaxy.',
Language: 'English',
Country: 'United States',
Awards: 'Won 6 Oscars. 65 wins & 31 nominations total',
Poster: 'https://m.media-amazon.com/images/M/MV5BOTA5NjhiOTAtZWM0ZC00MWNhLThiMzEtZDFkOTk2OTU1ZDJkXkEyXkFqcGdeQXVyMTA4NDI1NTQx._V1_SX300.jpg',
Ratings: [
{ Source: 'Internet Movie Database', Value: '8.6/10' },
{ Source: 'Rotten Tomatoes', Value: '93%' },
{ Source: 'Metacritic', Value: '90/100' },
],
Metascore: '90',
imdbRating: '8.6',
imdbVotes: '1,424,627',
imdbID: 'tt0076759',
Type: 'movie',
DVD: '10 Oct 2016',
BoxOffice: '$460,998,507',
Production: 'N/A',
Website: 'N/A',
},
tt0061852: {
Title: 'The Jungle Book',
Year: '1967',
Rated: 'G',
Released: '18 Oct 1967',
Runtime: '78 min',
Genre: 'Animation, Adventure, Comedy',
Director: 'Wolfgang Reitherman',
Writer: 'Larry Clemmons, Ralph Wright, Ken Anderson',
Actors: 'Phil Harris, Sebastian Cabot, Louis Prima',
Plot: "Abandoned after an accident, baby Mowgli is taken and raised by a family of wolves. As the boy grows older, the wise panther Bagheera realizes he must be returned to his own kind in the nearby man-village. Baloo the bear, however, thinks differently, taking the young Mowgli under his wing and teaching him that living in the jungle is the best life there is. Bagheera realizes that Mowgli is in danger, particularly from Shere Khan the tiger who hates all people. When Baloo finally comes around, Mowgli runs off into the jungle where he survives a second encounter with Kaa the snake and finally, with Shere Khan. It's the sight of a pretty girl, however, that draws Mowgli to the nearby man-village and stay there.",
Language: 'English',
Country: 'United States',
Awards: 'Nominated for 1 Oscar. 6 wins & 4 nominations total',
Poster: 'https://m.media-amazon.com/images/M/MV5BYmY1MTA3NmUtYzJmZC00YTFjLTk2NzktYTJhMWQ0ZTlkNzJjXkEyXkFqcGdeQXVyNjc5NjEzNA@@._V1_SX300.jpg',
Ratings: [
{ Source: 'Internet Movie Database', Value: '7.6/10' },
{ Source: 'Rotten Tomatoes', Value: '88%' },
{ Source: 'Metacritic', Value: '65/100' },
],
Metascore: '65',
imdbRating: '7.6',
imdbVotes: '195,021',
imdbID: 'tt0061852',
Type: 'movie',
DVD: '10 Aug 2016',
BoxOffice: '$141,843,612',
Production: 'N/A',
Website: 'N/A',
},
tt7394674: {
Title: 'Blood Quantum',
Year: '2019',
Rated: 'Not Rated',
Released: '28 Apr 2020',
Runtime: '98 min',
Genre: 'Drama, Horror',
Director: 'Jeff Barnaby',
Writer: 'Jeff Barnaby',
Actors: 'Michael Greyeyes, Elle-Máijá Tailfeathers, Forrest Goodluck',
Plot: 'The term "blood quantum" refers to a colonial blood measurement system that is used to determine an individual\'s Indigenous status, and is criticized as a tool of control and erasure of Indigenous peoples. The words take on even more provocative implications as the title of Jeff Barnaby\'s sophomore feature, which grimly depicts an apocalyptic scenario where in an isolated "Mi\'gmaq" community discover they are the only humans immune to a zombie plague. As the citizens of surrounding cities flee to the "Mi\'gmaq" reserve in search of refuge from the outbreak, the community must reckon with whether to let the outsiders in - and thus risk not just the extinction of their tribe but of humanity, period. The severe and scathing portrait of post-colonial Indigenous life and culture that Barnaby previously captured in the acclaimed Rhymes for Young Ghouls here deftly collides with the iconography and violent hyperbole typical of the zombie genre. The Undead are spectacularly and gruesomely dispatched via samurai swords, chainsaws, shotguns, and makeshift axes, while the living - a terrific ensemble cast led by Michael Greyeyes (Woman Walks Ahead and Fear the Walking Dead) - endure the paranoid pressures that such dire straits foment. In this iteration, however, Barnaby takes full advantage of the canvas zombie films regularly afford for cultural critique, exploring racism, colonialism, and the very real threat of extinction that Indigenous communities have experienced for generations. Further accentuated by arresting animated chapter breaks that instill a cool comic-book aesthetic to its horrific proceedings, Blood Quantum is as powerful an entry into the annals of zombie cinema as the devastating conclusion to George Romero\'s 1968 original Night of the Living Dead, and a meaningful demonstration of how marginalized voices - when given the opportunity - can resurrect a tired genre with incendiary new life.',
Language: 'English, Micmac',
Country: 'Canada',
Awards: '9 wins & 8 nominations',
Poster: 'https://m.media-amazon.com/images/M/MV5BZTc1ODE0ZDAtZWU4YS00OTFmLWJkYWItNmRkMzkzZmRlNTFlXkEyXkFqcGdeQXVyNTM0NTU5Mg@@._V1_SX300.jpg',
Ratings: [
{ Source: 'Internet Movie Database', Value: '5.6/10' },
{ Source: 'Rotten Tomatoes', Value: '90%' },
{ Source: 'Metacritic', Value: '63/100' },
],
Metascore: '63',
imdbRating: '5.6',
imdbVotes: '5,230',
imdbID: 'tt7394674',
Type: 'movie',
DVD: '28 Apr 2020',
BoxOffice: 'N/A',
Production: 'N/A',
Website: 'N/A',
},
};
const omdbApiClient: OmdbApiClient = {
fetchMetadata: (imdbId) => Promise.resolve(omdbResponses[imdbId]),
};
describe('createOmdbEnrichedDataService', () => {
const servicePromise = createOmdbEnrichedDataService(
createInternalProvider(),
createOmdbProviderByApiClient(omdbApiClient),
);
it('returns correct data for 3532674', async () => {
const service = await servicePromise;
const result = service.getMetadataByInternalId(3532674);
expect(result).toEqual({
actors: ['Mickey Rourke', 'Clive Owen', 'Bruce Willis'],
availableLanguages: ['de', 'en'],
awards: '38 wins & 54 nominations',
boxOffice: '$74,103,820',
contentRating: 'R',
description:
"Four tales of crime adapted from Frank Miller's popular comics, focusing around a muscular brute who's looking for the person responsible for the death of his beloved Goldie (Jaime King), a man fed up with Sin City's corrupt law enforcement who takes the law into his own hands after a horrible mistake, a cop who risks his life to protect a girl from a deformed pedophile and a hitman looking to make a little cash.",
directors: [
'Frank Miller',
'Quentin Tarantino',
'Robert Rodriguez',
],
duration: 119,
dvdReleaseDate: '03 Sep 2016',
genres: ['Crime', 'Thriller'],
imdbId: 'tt0401792',
internalId: 3532674,
localDescription:
'Im Sündenpfuhl Sin City werden drei Geschichten parallel erzählt: Der Polizist Hartigan jagt einen Pädophilen, der Outlaw Dwight muss im Rotlichtbezirk untertauchen und dem Schläger Marv wird ein Mord angehängt. ',
localTitle: 'Sin City',
originalLanguage: 'en',
posterUrl:
'https://m.media-amazon.com/images/M/MV5BODZmYjMwNzEtNzVhNC00ZTRmLTk2M2UtNzE1MTQ2ZDAxNjc2XkEyXkFqcGdeQXVyMTQxNzMzNDI@._V1_SX300.jpg',
productionCountries: ['United States'],
productionYear: 2005,
ratings: [
{
source: 'Internet Movie Database',
value: '8.0/10',
},
{
source: 'Rotten Tomatoes',
value: '76%',
},
{
source: 'Metacritic',
value: '74/100',
},
{
source: 'Internal',
value: '3.9/5',
},
],
releaseDate: '01 Apr 2005',
studios: ['Studiocanal', 'Paramount'],
title: 'Sin City',
type: 'movie',
writers: ['Frank Miller', 'Robert Rodriguez'],
});
});
it('returns correct data for 5979300', async () => {
const service = await servicePromise;
const result = service.getMetadataByInternalId(5979300);
expect(result).toEqual({
actors: ['Harrison Ford', 'Sean Connery', 'Alison Doody'],
availableLanguages: ['de', 'en'],
awards: 'Won 1 Oscar. 9 wins & 24 nominations total',
boxOffice: '$197,171,806',
contentRating: 'PG-13',
description:
'An art collector appeals to Indiana Jones to embark on a search for the Holy Grail. He learns that another archaeologist has disappeared while searching for the precious goblet, and the missing man is his own father, Dr. Henry Jones. The artifact is much harder to find than they expected, and its powers are too much for those impure of heart.',
directors: ['Steven Spielberg'],
duration: 127,
dvdReleaseDate: '28 Jan 2014',
genres: ['Action', 'Adventure'],
imdbId: 'tt0097576',
internalId: 5979300,
localDescription:
'1912: Der junge Indiana Jones will Grabräubern das Kreuz von Coronado abluchsen, um es in ein Museum zu bringen. Nach einem Zeitsprung ins Jahr 1938 kämpft Indy wieder um das Kreuz, diesmal erfolgreich. Anschließend soll er den Heiligen Gral suchen.',
localTitle: 'Indiana Jones und der letzte Kreuzzug',
originalLanguage: 'en',
posterUrl:
'https://m.media-amazon.com/images/M/MV5BY2Q0ODg4ZmItNDZiYi00ZWY5LTg2NzctNmYwZjA5OThmNzE1XkEyXkFqcGdeQXVyMjM4MzQ4OTQ@._V1_SX300.jpg',
productionCountries: ['United States'],
productionYear: 1989,
ratings: [
{
source: 'Internet Movie Database',
value: '8.2/10',
},
{
source: 'Rotten Tomatoes',
value: '84%',
},
{
source: 'Metacritic',
value: '65/100',
},
{
source: 'Internal',
value: '4.2/5',
},
],
releaseDate: '24 May 1989',
studios: ['Paramount'],
title: 'Indiana Jones and the Last Crusade',
type: 'movie',
writers: ['Jeffrey Boam', 'George Lucas', 'Menno Meyjes'],
});
});
it('returns correct data for tt0076759', async () => {
const service = await servicePromise;
const result = service.getMetadataByImdbId('tt0076759');
expect(result).toEqual({
actors: ['Mark Hamill', 'Harrison Ford', 'Carrie Fisher'],
availableLanguages: ['de', 'en'],
awards: 'Won 6 Oscars. 65 wins & 31 nominations total',
boxOffice: '$460,998,507',
contentRating: 'PG',
description:
'The Imperial Forces, under orders from cruel Darth Vader, hold Princess Leia hostage in their efforts to quell the rebellion against the Galactic Empire. Luke Skywalker and Han Solo, captain of the Millennium Falcon, work together with the companionable droid duo R2-D2 and C-3PO to rescue the beautiful princess, help the Rebel Alliance and restore freedom and justice to the Galaxy.',
directors: ['George Lucas'],
duration: 120,
dvdReleaseDate: '10 Oct 2016',
genres: ['Action', 'Adventure', 'Fantasy'],
imdbId: 'tt0076759',
internalId: 11043689,
localDescription:
'Der im Exil lebende Jedi-Ritter Obi-Wan Kenobi nimmt sich einen Mann namens Luke Skywalker als Schüler. Zusammen helfen sie der Rebellion, die Pläne des bösen Imperiums und des Sith-Lords Darth Vader zu vereiteln. ',
localTitle: 'Star Wars: Eine neue Hoffnung',
originalLanguage: 'en',
posterUrl:
'https://m.media-amazon.com/images/M/MV5BOTA5NjhiOTAtZWM0ZC00MWNhLThiMzEtZDFkOTk2OTU1ZDJkXkEyXkFqcGdeQXVyMTA4NDI1NTQx._V1_SX300.jpg',
productionCountries: ['United States'],
productionYear: 1977,
ratings: [
{
source: 'Internet Movie Database',
value: '8.6/10',
},
{
source: 'Rotten Tomatoes',
value: '93%',
},
{
source: 'Metacritic',
value: '90/100',
},
{
source: 'Internal',
value: '4.5/5',
},
],
releaseDate: '25 May 1977',
studios: ['FOX', 'Paramount'],
title: 'Star Wars: Episode IV - A New Hope',
type: 'movie',
writers: ['George Lucas'],
});
});
it('returns correct data for tt0061852', async () => {
const service = await servicePromise;
const result = service.getMetadataByImdbId('tt0061852');
expect(result).toEqual({
actors: ['Phil Harris', 'Sebastian Cabot', 'Louis Prima'],
availableLanguages: ['de', 'en'],
awards: 'Nominated for 1 Oscar. 6 wins & 4 nominations total',
boxOffice: '$141,843,612',
contentRating: 'G',
description:
"Abandoned after an accident, baby Mowgli is taken and raised by a family of wolves. As the boy grows older, the wise panther Bagheera realizes he must be returned to his own kind in the nearby man-village. Baloo the bear, however, thinks differently, taking the young Mowgli under his wing and teaching him that living in the jungle is the best life there is. Bagheera realizes that Mowgli is in danger, particularly from Shere Khan the tiger who hates all people. When Baloo finally comes around, Mowgli runs off into the jungle where he survives a second encounter with Kaa the snake and finally, with Shere Khan. It's the sight of a pretty girl, however, that draws Mowgli to the nearby man-village and stay there.",
directors: ['Wolfgang Reitherman'],
duration: 75,
dvdReleaseDate: '10 Aug 2016',
genres: ['Animation', 'Adventure', 'Comedy'],
imdbId: 'tt0061852',
internalId: 11528860,
localDescription:
'Unter der Obhut des Panthers Baghira wächst das Findelkind Mogli bei einer Wolfsfamilie auf. Doch da erschüttert die Rückkehr des menschenfressenden Tigers Shir Khan den Dschungel. Die Sorge um Mogli zwingt Baghira zu der einzig möglichen Entscheidung.',
localTitle: 'Das Dschungelbuch',
originalLanguage: 'en',
posterUrl:
'https://m.media-amazon.com/images/M/MV5BYmY1MTA3NmUtYzJmZC00YTFjLTk2NzktYTJhMWQ0ZTlkNzJjXkEyXkFqcGdeQXVyNjc5NjEzNA@@._V1_SX300.jpg',
productionCountries: ['United States'],
productionYear: 1967,
ratings: [
{
source: 'Internet Movie Database',
value: '7.6/10',
},
{
source: 'Rotten Tomatoes',
value: '88%',
},
{
source: 'Metacritic',
value: '65/100',
},
{
source: 'Internal',
value: '4.4/5',
},
],
releaseDate: '18 Oct 1967',
studios: ['Disney'],
title: 'The Jungle Book',
type: 'movie',
writers: ['Larry Clemmons', 'Ralph Wright', 'Ken Anderson'],
});
});
it('returns undefined for non-existent internal ID', async () => {
const service = await servicePromise;
const result = service.getMetadataByInternalId(999999999);
expect(result).toBeUndefined();
});
it('returns undefined for correct ID for movie not present in internal database', async () => {
const service = await servicePromise;
const result = service.getMetadataByImdbId('tt7394674');
expect(result).toBeUndefined();
});
});

@ -0,0 +1,41 @@
import type {
EnrichedDataService,
InternalProvider,
MovieData,
OmdbProvider,
} from '../types';
export const createOmdbEnrichedDataService = async (
internalProvider: InternalProvider,
omdbProvider: OmdbProvider,
): Promise<EnrichedDataService> => {
const internalMetadataList = await internalProvider.getAllMetadata();
const mergedMetadataList = await Promise.all(
internalMetadataList.map(async (internalData): Promise<MovieData> => {
const omdbData = await omdbProvider.getMetadata(
internalData.imdbId,
);
if (!omdbData) {
throw new Error(
`No OMDB data found for ${internalData.imdbId}`,
);
}
return {
...omdbData,
...internalData,
ratings: [...omdbData.ratings, ...internalData.ratings],
};
}),
);
return {
getMetadataByInternalId: (requestedId) =>
mergedMetadataList.find(
({ internalId }) => internalId === requestedId,
),
getMetadataByImdbId: (requestedId) =>
mergedMetadataList.find(({ imdbId }) => imdbId === requestedId),
};
};

@ -1,5 +1,5 @@
type MovieData = {
internalId?: number;
export type MovieData = {
internalId: number;
imdbId: string;
title: string;
localTitle: string;
@ -45,6 +45,7 @@ type MovieData = {
export type NormalizedOmdbData = Omit<
MovieData,
| 'availableLanguages'
| 'internalId'
| 'localDescription'
| 'localTitle'
| 'originalLanguage'
@ -72,9 +73,7 @@ export type NormalizedInternalData = Omit<
| 'type'
| 'website'
| 'writers'
> & {
internalId: number;
};
>;
export type InternalProvider = {
getMetadataByInternalId(
@ -83,8 +82,14 @@ export type InternalProvider = {
getMetadataByImdbId(
imdbId: string,
): Promise<NormalizedInternalData | undefined>;
getAllMetadata(): Promise<NormalizedInternalData[]>;
};
export type OmdbProvider = {
getMetadata(imdbId: string): Promise<NormalizedOmdbData | undefined>;
};
export type EnrichedDataService = {
getMetadataByInternalId(internalId: number): MovieData | undefined;
getMetadataByImdbId(imdbId: string): MovieData | undefined;
};

@ -1,5 +1,5 @@
import { Test, TestingModule } from '@nestjs/testing';
import { INestApplication } from '@nestjs/common';
import { Test, type TestingModule } from '@nestjs/testing';
import type { INestApplication } from '@nestjs/common';
import request from 'supertest';
import { AppModule } from './../src/app.module';

Loading…
Cancel
Save