movie database | Find cross section of actors and movies | Cell 2 | Search

This code provides a set of functions for interacting with a SQLite database containing movie information, including methods for searching by Levenshtein distance and retrieving actor and title data. The functions use a mix of synchronous and asynchronous programming, with prepared statements and promise chains to improve security, performance, and readability.

Cell 1

var importer = require('../Core');
var levSort = importer.import("sort by levenshtein distance");
var sqlite3 = require('better-sqlite3');
var movies = './movies.sqlite.db';
var db = new sqlite3(movies, {});

function getTitles(t) {
    t = typeof t === 'string' ? [t] : t;
    return db.prepare(`
SELECT *
FROM principals
WHERE tconst IN (${t.map(i => '?').join(',')})`).all(t);
}

function getTitlesByName(n) {
    n = typeof n === 'string' ? [n] : n;
    return db.prepare(`
SELECT *
FROM principals
WHERE nconst IN (${n.map(i => '?').join(',')})`).all(n);
}

function getActorsByTitles(t, n) {
    t = typeof t === 'string' ? [t] : t;
    n = typeof n === 'string' ? [n] : n;
    return db.prepare(`
SELECT *
FROM principals
WHERE nconst IN (${n.map(i => '?').join(',')})
AND tconst IN (${t.map(i => '?').join(',')})`).all(n.concat(t));
}

var assignPromise = r => resolve => getExactName(r.nconst)
    .then(result => Object.assign(r, result))
    .then(resolve)

function getActorTitlesIntersection(n, t) {
    var titles, actors;
    return Promise.resolve()
        .then(() => getTitlesByName(n))
        .then(ts => titles = ts.map(t => t.tconst))
        .then(() => getTitles(t))
        .then(as => getActorsByTitles(titles, as.map(a => a.nconst)))
        .then(r => importer.runAllPromises(r.map(r => assignPromise(r))))
}

function getTitleTitleIntersection(t) {
    var titles = Array.from(arguments);
    return Promise.resolve()
        .then(() => getTitles(t))
        .then(as => getActorsByTitles(titles.slice(1), as.map(a => a.nconst)))
        .then(r => importer.runAllPromises(r.map(r => assignPromise(r))))
}

function getExactName(n) {
    return Promise.resolve()
        .then(() => db.prepare(`SELECT * FROM name WHERE nconst=?`).get(n))
}

function getExactTitle(t) {
    return Promise.resolve()
        .then(() => db.prepare(`SELECT * FROM titles WHERE tconst=?`).get(t))
}

function getTitle(t) {
    var words = t.split(/\s+/ig);
    return Promise.resolve()
        .then(() => db.prepare(`
SELECT * 
FROM titles 
WHERE (${words.map(word => 'primaryTitle LIKE ?').join(' AND ')})
OR (${words.map(word => 'originalTitle LIKE ?').join(' AND ')})
`).all(words.map(w => `%${w}%`).concat(words.map(w => `%${w}%`))))
        .then(results => levSort(results, t, r => r.primaryTitle)[0])
}

// https://v2.sg.media-imdb.com/suggests/w/werner%20herzog.json
$.async();
//getTitle('three colors: white')
getTitleTitleIntersection('tt0111507', 'tt0111495', 'tt0108394')
//getActorTitlesIntersection('nm0001348', 'tt0082694')
    .then(r => $.sendResult(r))
    .catch(e => $.sendError(e))
    // close the database connection
    .then(() => db.close())

What the code could have been:

```javascript
// Import required modules
const { import: levSort } = require('../Core');
const sqlite3 = require('better-sqlite3');
const dbPath = './movies.sqlite.db';

// Initialize the SQLite database
const db = new sqlite3(dbPath, {});

// Define utility functions
const getValues = (t) => t.map((item) => typeof item ==='string'? [item] : item);

// Function to get titles from the database
const getTitles = (t) => {
    const query = `SELECT * FROM principals WHERE tconst IN (${getValues(t).map((i) => '?').join(',')})`;
    return db.prepare(query).all(getValues(t));
};

// Function to get actors by title from the database
const getActorsByTitles = (t, n) => {
    const query = `SELECT * FROM principals WHERE nconst IN (${getValues(n).map((i) => '?').join(',')}) AND tconst IN (${getValues(t).map((i) => '?').join(',')})`;
    return db.prepare(query).all(getValues(n).concat(getValues(t)));
};

// Function to get a single actor's exact name from the database
const getExactName = (n) => {
    const query = `SELECT * FROM name WHERE nconst=?`;
    return db.prepare(query).get(n);
};

// Function to get a single title's exact details from the database
const getExactTitle = (t) => {
    const query = `SELECT * FROM titles WHERE tconst=?`;
    return db.prepare(query).get(t);
};

// Function to get a single title's details from the database using levenshtein distance
const getTitle = (t) => {
    // Find words in the title
    const words = t.split(/\s+/ig);
    const query = `SELECT * FROM titles WHERE (${words.map((word) => 'primaryTitle LIKE?').join(' AND ')}) OR (${words.map((word) => 'originalTitle LIKE?').join(' AND ')})`;
    return db.prepare(query).all(words.map((w) => `%${w}%`).concat(words.map((w) => `%${w}%`)));
};

// Function to get a title's intersection of titles from the database
const getTitleTitleIntersection = (t) => {
    const titles = Array.from(arguments);
    return Promise.resolve()
       .then(() => getTitles(t))
       .then((as) => getActorsByTitles(titles.slice(1), as.map((a) => a.nconst)))
       .then((r) => levSort(r.map((r) => r), t, (r) => r.primaryTitle)[0]);
};

// Function to get an actor's intersection of titles from the database
const getActorTitlesIntersection = (n, t) => {
    const titles = getTitles(n);
    const actors = getTitles(t);
    return Promise.all([titles, actors]).then((results) => {
        const titlesArray = results[0].map((t) => t.tconst);
        const actorsArray = results[1].map((a) => a.nconst);
        return levSort(getActorsByTitles(titlesArray, actorsArray), t, (r) => r.primaryTitle)[0];
    });
};

// Function to assign exact name to an actor
const assignPromise = (r) => {
    return getExactName(r.nconst).then((result) => Object.assign(r, result));
};

// Initialize the database connection
db.close();

// Usage
getTitle('three colors: white')
   .then((result) => console.log(result))
   .catch((error) => console.error(error));
getTitleTitleIntersection('tt0111507', 'tt0111495', 'tt0108394')
   .then((result) => console.log(result))
   .catch((error) => console.error(error));
getActorTitlesIntersection('nm0001348', 'tt0082694')
   .then((result) => console.log(result))
   .catch((error) => console.error(error));
```

Overview

This code is a set of functions for interacting with a SQLite database containing movie information. It provides methods for retrieving actor and title data, including functionality for searching by Levenshtein distance.

Required Modules

The code requires two external modules:

  1. better-sqlite3 for interacting with the SQLite database.
  2. A custom module ../Core containing a function import for importing modules and runAllPromises for running multiple promises concurrently.

Functions

Database Interactions

Intersection Functions

Exact Name and Title Functions

Utility Functions

Notes