166 lines
5.0 KiB
Rust
166 lines
5.0 KiB
Rust
use std::time::{Duration, Instant};
|
|
|
|
use julid::Julid;
|
|
use sqlx::{query_scalar, SqlitePool};
|
|
|
|
use crate::{util::year_to_epoch, ShowKind, User, Watch, WatchQuest};
|
|
|
|
const USER_EXISTS_QUERY: &str = "select count(*) from users where id = $1";
|
|
|
|
const MOVIE_QUERY: &str = "select * from movie_titles order by year, title asc limit ?";
|
|
|
|
//-************************************************************************
|
|
// the omega user is the system ID, but has no actual power in the app
|
|
//-************************************************************************
|
|
const OMEGA_ID: Julid = Julid::omega();
|
|
const BULK_INSERT: usize = 2_000;
|
|
|
|
#[derive(Debug, sqlx::FromRow, Clone)]
|
|
pub struct ImportMovieOmega {
|
|
pub title: String,
|
|
pub year: Option<String>,
|
|
pub runtime: Option<String>,
|
|
}
|
|
|
|
impl From<ImportMovieOmega> for Watch {
|
|
fn from(value: ImportMovieOmega) -> Self {
|
|
Watch {
|
|
id: OMEGA_ID, // this is ignored by the inserter
|
|
title: value.title,
|
|
release_date: year_to_epoch(value.year.as_deref()),
|
|
length: value.runtime.and_then(|v| v.parse::<i64>().ok()),
|
|
kind: ShowKind::Movie,
|
|
metadata_url: None,
|
|
added_by: OMEGA_ID,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<&ImportMovieOmega> for Watch {
|
|
fn from(value: &ImportMovieOmega) -> Self {
|
|
Watch {
|
|
id: OMEGA_ID,
|
|
title: value.title.to_string(),
|
|
release_date: year_to_epoch(value.year.as_deref()),
|
|
length: value.runtime.as_ref().and_then(|v| v.parse::<i64>().ok()),
|
|
kind: ShowKind::Movie,
|
|
metadata_url: None,
|
|
added_by: OMEGA_ID,
|
|
}
|
|
}
|
|
}
|
|
|
|
//-************************************************************************
|
|
// utility functions for building CLI tools, currently just for benchmarking
|
|
//-************************************************************************
|
|
pub async fn add_watch_quests(pool: &SqlitePool, quests: &[WatchQuest]) -> Result<(), ()> {
|
|
let mut builder = sqlx::QueryBuilder::new("insert into watch_quests (user, watch) ");
|
|
builder.push_values(quests, |mut b, quest| {
|
|
let user = quest.user;
|
|
let watch = quest.watch;
|
|
//eprintln!("{user}, {watch}");
|
|
b.push_bind(user).push_bind(watch);
|
|
});
|
|
|
|
let q = builder.build();
|
|
q.execute(pool).await.map_err(|e| {
|
|
dbg!(e);
|
|
})?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
pub async fn add_users(db_pool: &SqlitePool, users: &[User]) -> Result<Duration, ()> {
|
|
let mut builder =
|
|
sqlx::QueryBuilder::new("insert into users (username, displayname, email, pwhash)");
|
|
|
|
let start = Instant::now();
|
|
builder.push_values(users.iter(), |mut b, user| {
|
|
b.push_bind(&user.username)
|
|
.push_bind(&user.displayname)
|
|
.push_bind(&user.email)
|
|
.push_bind(&user.pwhash);
|
|
});
|
|
let q = builder.build();
|
|
q.execute(db_pool).await.map_err(|_| ())?;
|
|
let end = Instant::now();
|
|
let dur = end - start;
|
|
|
|
Ok(dur)
|
|
}
|
|
|
|
pub async fn add_omega_watches(
|
|
w2w_db: &SqlitePool,
|
|
movie_db: &SqlitePool,
|
|
num: u32,
|
|
) -> Result<Duration, ()> {
|
|
let omega = ensure_omega(w2w_db).await;
|
|
|
|
let movies: Vec<ImportMovieOmega> = sqlx::query_as(MOVIE_QUERY)
|
|
.bind(num)
|
|
.fetch_all(movie_db)
|
|
.await
|
|
.unwrap();
|
|
|
|
let start = Instant::now();
|
|
for movies in movies.as_slice().chunks(BULK_INSERT) {
|
|
let mut builder = sqlx::QueryBuilder::new(
|
|
"insert into watches (kind, title, length, release_date, added_by) ",
|
|
);
|
|
|
|
builder.push_values(movies, |mut b, movie| {
|
|
let title = &movie.title;
|
|
b.push_bind(ShowKind::Movie)
|
|
.push_bind(title)
|
|
.push_bind(movie.runtime.as_ref().and_then(|l| l.parse::<i64>().ok()))
|
|
.push_bind(year_to_epoch(movie.year.as_deref()))
|
|
.push_bind(omega);
|
|
});
|
|
let q = builder.build();
|
|
q.execute(w2w_db).await.map_err(|_| ())?;
|
|
}
|
|
let end = Instant::now();
|
|
let dur = end - start;
|
|
|
|
Ok(dur)
|
|
}
|
|
|
|
pub async fn ensure_omega(db_pool: &SqlitePool) -> Julid {
|
|
if !check_omega_exists(db_pool).await {
|
|
sqlx::query("insert into users (id, username, pwhash) values (?, 'the omega user', 'you shall not password')").bind(OMEGA_ID).execute(db_pool).await.unwrap();
|
|
}
|
|
OMEGA_ID
|
|
}
|
|
|
|
async fn check_omega_exists(db_pool: &SqlitePool) -> bool {
|
|
let count = query_scalar(USER_EXISTS_QUERY)
|
|
.bind(OMEGA_ID)
|
|
.fetch_one(db_pool)
|
|
.await
|
|
.unwrap_or(0);
|
|
count > 0
|
|
}
|
|
|
|
//-************************************************************************
|
|
//tests
|
|
//-************************************************************************
|
|
|
|
#[cfg(test)]
|
|
mod test {
|
|
use tokio::runtime::Runtime;
|
|
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn ensure_omega_user() {
|
|
let p = crate::db::get_db_pool();
|
|
let rt = Runtime::new().unwrap();
|
|
rt.block_on(async {
|
|
assert!(!check_omega_exists(&p).await);
|
|
ensure_omega(&p).await;
|
|
});
|
|
|
|
assert!(rt.block_on(check_omega_exists(&p)));
|
|
}
|
|
}
|