Estendere il programma film-library.js collegandolo al database locale films.db. La FilmLibrary dovrà offrire sei metodi asincroni che recuperano insiemi di film secondo diversi criteri, restituendo sempre una Promise risolta con un array di oggetti Film.
Import di SQLite3
const sqlite = require('sqlite3'); e creare un’unica connessione:
const db = new sqlite.Database('films.db', (err) => { if (err) throw err; });Definizione dei metodi di lettura
?.db.all(sql, params, callback) per ottenere risultati.dayjs() (coerente con il costruttore di Film).Implementazioni richieste
| # | Metodo | Query SQL (semplificata) | Parametri |
|---|---|---|---|
| 1 | getAll() |
SELECT * FROM films |
- |
| 2 | getFavorites() |
SELECT * FROM films WHERE favorite = 1 |
- |
| 3 | getWatchedToday() |
SELECT * FROM films WHERE watchDate = DATE('now') |
- |
| 4 | getWatchedBefore(date) |
SELECT * FROM films WHERE watchDate < ? |
date (ISO yyyy-mm-dd) |
| 5 | getRatedAtLeast(rating) |
SELECT * FROM films WHERE rating >= ? |
rating (int) |
| 6 | getFilmsByTitle(substr) |
`SELECT * FROM films WHERE title LIKE '%' |
Verifica del funzionamento
async function demo() che invoca in sequenza i sei metodi e stampa i risultati con console.log.demo() a fine file per un rapido smoke-test."use strict";
const dayjs = require("dayjs");
const sqlite = require ("sqlite3");
// Connessione condivisa
const db = new sqlite.Database('films.db', (err) => {
if (err)
throw err;
});
/* ===== Model ===== */
function Film(id, title, favorite = false, watchDate = null, rating = null, user = 1) {
this.id = id;
this.title = title;
this.favorite = favorite;
this.watchDate = watchDate ? dayjs(watchDate) : null;
this.rating = rating;
this.user = user;
this.toString = () => {
const dateStr = this.watchDate ? this.watchDate.format("MMMM D, YYYY") : "-";
const scoreStr = this.rating ?? "-";
return `Id: ${this.id}, Title: ${this.title}, Favorite: ${this.favorite}, Watch date: ${dateStr}, Score: ${scoreStr}, User: ${this.user}`;
};
}
/* ===== Collection ===== */
function FilmLibrary() {
this.list = [];
/* Inserimento */
this.addNewFilm = film => {
this.list.push(film);
}
/* 1. Ordinamento per data */
this.sortByDate = () => {
return [...this.list].sort((a, b) => {
if (a.watchDate === null && b.watchDate === null)
return 0;
if (a.watchDate === null)
return 1; // a non visto -> dopo
if (b.watchDate === null)
return -1; // b non visto -> dopo
return a.watchDate.isAfter(b.watchDate) ? 1 : -1;
});
};
/* 2. Cancellazione per id */
this.deleteFilm = id => {
this.list = this.list.filter(f => f.id !== id);
};
/* 3. Reset di tutte le date di visione */
this.resetWatchedFilms = () => {
this.list.forEach(f => {
f.watchDate = null
});
};
/* 4. Selezione dei film valutati */
this.getRated = () => {
return this.list
.filter(f => f.rating != null && f.rating > 0)
.sort((a, b) => b.rating - a.rating);
};
/* Utility: stampa completa della libreria */
this.print = () => {
this.list.forEach(f => console.log(f.toString()));
};
// 1. Tutti i film
this.getAll = () => {
return new Promise((resolve, reject) => {
const sql = "SELECT * FROM films";
db.all(sql, [], (err, rows) => {
if (err)
reject(err);
else
resolve(rows.map(r => new Film(r.id, r.title, !!r.favorite, r.watchDate, r.rating, r.user)));
});
});
};
// 2. Preferiti
this.getFavorites = () => {
return new Promise((resolve, reject) => {
const sql = "SELECT * FROM films WHERE isFavorite = 1";
db.all(sql, [], (err, rows) => {
if (err)
reject(err);
else
resolve(rows.map(r => new Film(r.id, r.title, true, r.watchDate, r.rating, r.user)));
});
});
};
// 3. Visti oggi
this.getWatchedToday = () => {
return new Promise((resolve, reject) => {
const sql = "SELECT * FROM films WHERE DATE(watchDate) = DATE('now')";
db.all(sql, [], (err, rows) => {
if (err)
reject(err);
else
resolve(rows.map(r => new Film(r.id, r.title, !!r.favorite, r.watchDate, r.rating, r.user)));
});
});
};
// 4. Visti prima di una data
this.getWatchedBefore = (date) => {
return new Promise((resolve, reject) => {
const sql = "SELECT * FROM films WHERE watchDate < ?";
db.all(sql, [date], (err, rows) => {
if (err)
reject(err);
else
resolve(rows.map(r => new Film(r.id, r.title, !!r.favorite, r.watchDate, r.rating, r.user)));
});
});
};
// 5. Valutazione minima
this.getRatedAtLeast = (rating) => {
return new Promise((resolve, reject) => {
const sql = "SELECT * FROM films WHERE rating >= ?";
db.all(sql, [rating], (err, rows) => {
if (err)
reject(err);
else
resolve(rows.map(r => new Film(r.id, r.title, !!r.favorite, r.watchDate, r.rating, r.user)));
});
});
};
// 6. Titolo contenente stringa
this.getFilmsByTitle = (substr) => {
return new Promise((resolve, reject) => {
const sql = "SELECT * FROM films WHERE title LIKE '%' || ? || '%'";
db.all(sql, [substr], (err, rows) => {
if (err)
reject(err);
else
resolve(rows.map(r => new Film(r.id, r.title, !!r.favorite, r.watchDate, r.rating, r.user)));
});
});
};
}
/* ===== Demo ===== */
async function demo() {
const libary = new FilmLibrary();
libary.addNewFilm(new Film(1, "Pulp Fiction", true, "2024-03-10", 5));
libary.addNewFilm(new Film(2, "21 Grams", true, "2024-03-17", 4));
libary.addNewFilm(new Film(3, "Star Wars", false, null, null));
libary.addNewFilm(new Film(4, "Matrix", false, null, null));
libary.addNewFilm(new Film(5, "Shrek", false, "2024-03-21", 3));
console.log("***** List sorted by date *****");
libary.print(libary.sortByDate());
console.log("\\n>>> Delete film id=3");
libary.deleteFilm(3);
libary.print(libary.list);
console.log("\\n>>> Reset watch dates");
libary.resetWatchedFilms();
libary.print(libary.list);
console.log("\\n***** Films filtered - rated only *****");
libary.print(libary.getRated());
console.log(">> Tutti");
(await libary.getAll()).forEach(f => console.log(f.toString()));
console.log("\\n>> Preferiti");
(await libary.getFavorites()).forEach(f => console.log(f.toString()));
console.log("\\n>> Visti oggi");
(await libary.getWatchedToday()).forEach(f => console.log(f.toString()));
console.log("\\n>> Visti prima del 2024");
(await libary.getWatchedBefore("2024-01-01")).forEach(f => console.log(f.toString()));
console.log("\\n>> Rating >= 4");
(await libary.getRatedAtLeast(4)).forEach(f => console.log(f.toString()));
console.log("\\n>> Titolo contenente 'war'");
(await libary.getFilmsByTitle('war')).forEach(f => console.log(f.toString()));
db.close(); // chiusura esplicita della connessione
}
demo().catch(console.error);
? per evitare SQL-injection.demo() lo cattura con .catch.db evita overhead; in un’app reale si valuterebbe un pool o richieste in parallelo.Estendere la FilmLibrary per inserire, cancellare e aggiornare record nella tabella films di films.db, restituendo sempre una Promise e visualizzando un messaggio di conferma o errore al termine di ciascuna operazione.
Richiamo a db.run per query di scrittura
Le query che non restituiscono righe (INSERT, DELETE, UPDATE) si eseguono con db.run(sql, [params], function(err) {...}).
Nota: la callback non può essere una arrow-function, perché occorrono le proprietà
this.lastIDethis.changesfornite da sqlite3.