summaryrefslogtreecommitdiff
path: root/src/database.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/database.rs')
-rw-r--r--src/database.rs164
1 files changed, 164 insertions, 0 deletions
diff --git a/src/database.rs b/src/database.rs
new file mode 100644
index 0000000..326c1e0
--- /dev/null
+++ b/src/database.rs
@@ -0,0 +1,164 @@
+use crate::errors::Error;
+use postgres::{Client, NoTls};
+use std::sync::{Arc, Mutex};
+
+lazy_static! {
+ static ref CLIENT: Arc<Mutex<Client>> = Arc::new(Mutex::new(Client::connect(
+ "host=track_db user=postgres password=example",
+ NoTls
+ )?));
+}
+
+fn initialize_db() -> Result<(), Error> {
+ let mut client = CLIENT.lock()?;
+ client.batch_execute(
+ r#"
+ CREATE TABLE IF NOT EXISTS track (
+ track_id SERIAL PRIMARY KEY,
+ track_code TEXT NOT NULL UNIQUE,
+ name TEXT NOT NULL,
+ artist TEXT NOT NULL,
+ popularity int DEFAULT 50
+ );
+ CREATE TABLE IF NOT EXISTS suser (
+ user_id SERIAL PRIMARY KEY,
+ user_name TEXT NOT NULL UNIQUE
+ );
+ CREATE TABLE IF NOT EXISTS user_track_raw (
+ track_id int REFERENCES track (track_id) ON UPDATE CASCADE ON DELETE CASCADE,
+ user_id int REFERENCES suser (user_id) ON UPDATE CASCADE ON DELETE CASCADE,
+ count int NOT NULL DEFAULT 1,
+ CONSTRAINT track_user_pkey PRIMARY KEY (track_id, user_id)
+ );
+
+ CREATE OR REPLACE VIEW user_track AS (
+ SELECT *, "count" / (
+ SELECT SUM("count")
+ FROM user_track ut
+ WHERE ut.user_id = user_id
+ )::decimal AS score
+ FROM user_track
+ );
+ "#,
+ )?;
+ Ok(())
+}
+
+use rspotify::spotify::model::track::FullTrack;
+fn insert_track(user_id: i32, track: FullTrack) -> Result<(), Error> {
+ let mut client = crate::CLIENT.lock()?;
+
+ if track.id.is_none() {
+ println!("{:#?}", track);
+ return Err("failed to load get track information".into());
+ }
+ print!(" {} ", track.id.clone()?);
+ client.execute(
+ "INSERT INTO track (track_code, name, artist, popularity)
+ VALUES ($1, $2, $3, $4)
+ ON CONFLICT DO NOTHING
+ ",
+ &[
+ &(track.id.clone()?),
+ &track.name,
+ &track.artists[0].name,
+ &(track.popularity as i32),
+ ],
+ )?;
+ let track_id: i32 = client.query(
+ "SELECT track_id FROM track where track_code = $1;",
+ &[&(track.id?)],
+ )?[0]
+ .get(0);
+ println!("uid: {} tid: {}", user_id, track_id);
+ client.batch_execute(
+ "
+ INSERT INTO user_track_raw (track_id, user_id, count)
+ VALUES ($1, $2, $3)
+ ON CONFLICT
+ ON CONSTRAINT track_user_pkey
+ DO NOTHING;
+ UPDATE user_track SET count = count + 1 WHERE track_id = $1 AND user_id = $2;
+ ",
+ &[&track_id, &user_id, &0],
+ )?;
+ Ok(())
+}
+
+fn insert_user(name: &str) -> Result<(i32, String), Error> {
+ let mut client = crate::CLIENT.lock()?;
+ client.batch_execute(
+ "
+ INSERT INTO suser (user_name) VALUES ($1) ON CONFLICT (user_name) DO NOTHING;
+ DELETE FROM user_track WHERE user_name = $1;
+ ",
+ &[&user_id],
+ )?;
+ let user_id: i32 = client
+ .query_one(
+ "SELECT user_id FROM suser WHERE user_name = $1;",
+ &[&user_id],
+ )?
+ .get(0);
+ //reset user_track relation
+ Ok((user_id, name))
+}
+
+fn get_uid(name: &str, client: &mut postgres::Client) -> Result<i32, Error> {
+ let x: i32 = client
+ .query_one("SELECT user_id FROM suser where user_name = $1;", &[&name])?
+ .get(0);
+ Ok(x)
+}
+
+lazy_static! {
+ static ref CACHE: Arc<Mutex<HashMap<String, SpotifyOAuth>>> =
+ Arc::new(Mutex::new(HashMap::new()));
+}
+
+pub fn match_users(name1: String, name2: String) -> Result<String, Error> {
+ let mut client = crate::CLIENT.lock()?;
+ let mut songs = String::new();
+ for row in client.query(
+ "
+ WITH users AS (
+ SELECT *
+ FROM ( VALUES
+
+ ($1), ($2)
+
+ ) AS _ (user_id)
+ )
+ SELECT track_id, name, artist
+ FROM track
+ JOIN (
+ SELECT track_id
+ FROM user_track
+ JOIN suser USING (user_id)
+ JOIN track USING (track_id)
+ WHERE suser.user_name IN (SELECT * FROM users)
+ GROUP BY track_id
+ HAVING COUNT(track_id) = (SELECT COUNT(*) FROM users)
+ ORDER BY SUM(score) DESC
+ ) AS _ USING (track_id)
+ ;
+ ",
+ &[&name1.as_str(), &name2.as_str()],
+ )? {
+ let name: String = row.get(1);
+ let artist: String = row.get(2);
+ songs = format!("{}{} by {}\n", songs, name, artist);
+ }
+ Ok(songs)
+}
+
+#[get("/user")]
+pub fn get_users() -> Result<String, Error> {
+ let mut client = crate::CLIENT.lock()?;
+ let mut users = String::new();
+ for row in client.query("SELECT user_name FROM suser", &[])? {
+ let user: String = row.get(0);
+ users = format!("{}{}\n", users, user);
+ }
+ Ok(users)
+}