2023-07-08 20:16:05 +00:00
|
|
|
use sqlx::{query_scalar, SqlitePool};
|
2023-07-06 15:48:42 +00:00
|
|
|
|
2023-07-08 20:16:05 +00:00
|
|
|
use crate::{db_id::DbId, util::year_to_epoch, ShowKind, User, Watch, WatchQuest};
|
2023-07-01 22:42:01 +00:00
|
|
|
|
2023-07-09 04:21:12 +00:00
|
|
|
const USER_EXISTS_QUERY: &str = "select count(*) from users where id = $1";
|
2023-07-01 22:42:01 +00:00
|
|
|
|
2023-07-06 15:48:42 +00:00
|
|
|
const MOVIE_QUERY: &str = "select * from movies order by random() limit 10000";
|
|
|
|
|
2023-07-05 23:26:20 +00:00
|
|
|
//-************************************************************************
|
|
|
|
// the omega user is the system ID, but has no actual power in the app
|
|
|
|
//-************************************************************************
|
2023-07-01 22:42:01 +00:00
|
|
|
const OMEGA_ID: u128 = u128::MAX;
|
|
|
|
|
2023-07-08 20:16:05 +00:00
|
|
|
const BULK_INSERT: usize = 2_000;
|
|
|
|
|
2023-07-04 23:24:28 +00:00
|
|
|
#[derive(Debug, sqlx::FromRow, Clone)]
|
2023-07-03 22:20:19 +00:00
|
|
|
pub struct ImportMovieOmega {
|
|
|
|
pub title: String,
|
|
|
|
pub year: Option<String>,
|
|
|
|
pub length: Option<String>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<ImportMovieOmega> for Watch {
|
|
|
|
fn from(value: ImportMovieOmega) -> Self {
|
|
|
|
Watch {
|
|
|
|
title: value.title,
|
|
|
|
release_date: year_to_epoch(value.year.as_deref()),
|
|
|
|
length: value.length.and_then(|v| v.parse::<i64>().ok()),
|
|
|
|
id: DbId::new(),
|
|
|
|
kind: ShowKind::Movie,
|
|
|
|
metadata_url: None,
|
|
|
|
added_by: OMEGA_ID.into(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-04 18:30:42 +00:00
|
|
|
impl From<&ImportMovieOmega> for Watch {
|
|
|
|
fn from(value: &ImportMovieOmega) -> Self {
|
|
|
|
Watch {
|
|
|
|
title: value.title.to_string(),
|
|
|
|
release_date: year_to_epoch(value.year.as_deref()),
|
|
|
|
length: value.length.as_ref().and_then(|v| v.parse::<i64>().ok()),
|
|
|
|
id: DbId::new(),
|
|
|
|
kind: ShowKind::Movie,
|
|
|
|
metadata_url: None,
|
|
|
|
added_by: OMEGA_ID.into(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-01 22:42:01 +00:00
|
|
|
//-************************************************************************
|
|
|
|
// utility functions for building CLI tools, currently just for benchmarking
|
|
|
|
//-************************************************************************
|
2023-07-08 20:16:05 +00:00
|
|
|
pub async fn add_watch_quests(pool: &SqlitePool, quests: &[WatchQuest]) -> Result<(), ()> {
|
2023-07-09 05:00:26 +00:00
|
|
|
let mut builder = sqlx::QueryBuilder::new("insert into watch_quests (user, watch) ");
|
2023-07-08 20:16:05 +00:00
|
|
|
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);
|
|
|
|
});
|
2023-07-01 22:42:01 +00:00
|
|
|
|
2023-07-08 20:16:05 +00:00
|
|
|
let q = builder.build();
|
|
|
|
q.execute(pool).await.map_err(|e| {
|
|
|
|
dbg!(e);
|
|
|
|
})?;
|
|
|
|
|
|
|
|
Ok(())
|
2023-07-05 23:26:20 +00:00
|
|
|
}
|
|
|
|
|
2023-07-08 20:16:05 +00:00
|
|
|
pub async fn add_users(db_pool: &SqlitePool, users: &[User]) -> Result<(), ()> {
|
2023-07-06 19:24:25 +00:00
|
|
|
let mut builder =
|
2023-07-09 04:21:12 +00:00
|
|
|
sqlx::QueryBuilder::new("insert into users (id, username, displayname, email, pwhash) ");
|
2023-07-08 20:16:05 +00:00
|
|
|
|
|
|
|
builder.push_values(users.iter(), |mut b, user| {
|
|
|
|
b.push_bind(user.id)
|
|
|
|
.push_bind(&user.username)
|
|
|
|
.push_bind(&user.displayname)
|
|
|
|
.push_bind(&user.email)
|
|
|
|
.push_bind(&user.pwhash);
|
2023-07-06 19:24:25 +00:00
|
|
|
});
|
|
|
|
let q = builder.build();
|
2023-07-08 20:16:05 +00:00
|
|
|
q.execute(db_pool).await.map_err(|_| ())?;
|
2023-07-06 19:24:25 +00:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2023-07-09 05:00:26 +00:00
|
|
|
pub async fn add_omega_watches(
|
|
|
|
w2w_db: &SqlitePool,
|
|
|
|
movie_db: &SqlitePool,
|
|
|
|
) -> Result<Vec<DbId>, ()> {
|
|
|
|
ensure_omega(w2w_db).await;
|
2023-07-05 23:26:20 +00:00
|
|
|
|
2023-07-06 15:48:42 +00:00
|
|
|
let movies: Vec<ImportMovieOmega> = sqlx::query_as(MOVIE_QUERY)
|
|
|
|
.fetch_all(movie_db)
|
|
|
|
.await
|
|
|
|
.unwrap();
|
|
|
|
|
2023-07-08 20:16:05 +00:00
|
|
|
let mut ids = Vec::with_capacity(10_000);
|
|
|
|
let omega: DbId = OMEGA_ID.into();
|
|
|
|
|
|
|
|
for movies in movies.as_slice().chunks(BULK_INSERT) {
|
|
|
|
let mut builder = sqlx::QueryBuilder::new(
|
|
|
|
"insert into watches (id, kind, title, length, release_date, added_by) ",
|
|
|
|
);
|
|
|
|
|
|
|
|
builder.push_values(movies, |mut b, movie| {
|
|
|
|
let id = DbId::new();
|
|
|
|
ids.push(id);
|
|
|
|
let title = &movie.title;
|
|
|
|
|
|
|
|
b.push_bind(id)
|
|
|
|
.push_bind(ShowKind::Movie)
|
|
|
|
.push_bind(title)
|
|
|
|
.push_bind(movie.length.as_ref().and_then(|l| l.parse::<i64>().ok()))
|
|
|
|
.push_bind(year_to_epoch(movie.year.as_deref()))
|
|
|
|
.push_bind(omega);
|
2023-07-05 23:26:20 +00:00
|
|
|
});
|
2023-07-08 20:16:05 +00:00
|
|
|
let q = builder.build();
|
|
|
|
|
2023-07-09 05:00:26 +00:00
|
|
|
q.execute(w2w_db).await.map_err(|_| ())?;
|
2023-07-05 23:26:20 +00:00
|
|
|
}
|
2023-07-08 20:16:05 +00:00
|
|
|
|
|
|
|
Ok(ids)
|
2023-07-05 23:26:20 +00:00
|
|
|
}
|
|
|
|
|
2023-07-01 22:42:01 +00:00
|
|
|
pub async fn ensure_omega(db_pool: &SqlitePool) -> DbId {
|
|
|
|
if !check_omega_exists(db_pool).await {
|
2023-07-08 20:16:05 +00:00
|
|
|
let omega = User {
|
|
|
|
id: OMEGA_ID.into(),
|
|
|
|
username: "The Omega User".to_string(),
|
|
|
|
displayname: Some("I am the end of all watches".to_string()),
|
|
|
|
email: None,
|
|
|
|
last_seen: None,
|
|
|
|
pwhash: "you shall not password".to_string(),
|
|
|
|
};
|
|
|
|
add_users(db_pool, &[omega]).await.unwrap();
|
2023-07-01 22:42:01 +00:00
|
|
|
}
|
|
|
|
OMEGA_ID.into()
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn check_omega_exists(db_pool: &SqlitePool) -> bool {
|
|
|
|
let id: DbId = OMEGA_ID.into();
|
|
|
|
let count = query_scalar(USER_EXISTS_QUERY)
|
|
|
|
.bind(id)
|
|
|
|
.fetch_one(db_pool)
|
|
|
|
.await
|
|
|
|
.unwrap_or(0);
|
|
|
|
count > 0
|
|
|
|
}
|
|
|
|
|
|
|
|
//-************************************************************************
|
|
|
|
//tests
|
|
|
|
//-************************************************************************
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod test {
|
2023-07-21 22:15:47 +00:00
|
|
|
use tokio::runtime::Runtime;
|
|
|
|
|
2023-07-01 22:42:01 +00:00
|
|
|
use super::*;
|
|
|
|
|
2023-07-21 22:15:47 +00:00
|
|
|
#[test]
|
|
|
|
fn ensure_omega_user() {
|
2023-07-19 00:37:24 +00:00
|
|
|
let p = crate::db::get_db_pool();
|
2023-07-21 22:15:47 +00:00
|
|
|
let rt = Runtime::new().unwrap();
|
|
|
|
rt.block_on(async {
|
|
|
|
assert!(!check_omega_exists(&p).await);
|
|
|
|
ensure_omega(&p).await;
|
|
|
|
assert!(check_omega_exists(&p).await);
|
|
|
|
});
|
2023-07-01 22:42:01 +00:00
|
|
|
}
|
|
|
|
}
|