diff options
Diffstat (limited to 'migration/src')
| -rw-r--r-- | migration/src/main.rs | 131 | 
1 files changed, 131 insertions, 0 deletions
| diff --git a/migration/src/main.rs b/migration/src/main.rs new file mode 100644 index 0000000..72252a9 --- /dev/null +++ b/migration/src/main.rs @@ -0,0 +1,131 @@ +extern crate clap; +extern crate serde; +extern crate serde_json; +#[macro_use] +extern crate serde_derive; +#[macro_use] +extern crate log; +extern crate env_logger; +extern crate rusqlite; +extern crate regex; + +use std::fs::File; +use std::io::Read; +use clap::{App, Arg}; +use std::collections::HashMap; +use regex::Regex; + +#[derive(Serialize, Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +struct Key { +    id: String, +} + +#[derive(Serialize, Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +struct Quote { +    timestamp: String, +    author: String, +    ip: String, +    content: String, +    quote_date: String, +    #[serde(rename = "__key__")] +    key: Key, +    #[serde(default = "Vec::new")] +    votes: Vec<Vote>, +} + +#[derive(Serialize, Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +struct Vote { +    ip: String, +    rating: String, +    quote_id: String, +    timestamp: String, +} + +fn import<'a, I: Iterator<Item = &'a Quote>>(conn: &rusqlite::Connection, quotes: I) { +    let r = Regex::new(r".*(\d{4})-(\d{2})-(\d{2}).*").unwrap(); +    for quote in quotes { +        let quote_date = r.replace("e.quote_date, "$1-$2-$3").to_string(); +        info!("Inserting: {:?}, quote_date({})", quote, quote_date); +        conn.execute("INSERT INTO quotes (approved, quote_date, author, content, ip, timestamp) VALUES (1, ?1, ?2, ?3, ?4, ?5)", +        &["e_date, "e.author, "e.content, "e.ip, "e.timestamp]).unwrap(); + +        let quote_id = conn.last_insert_rowid(); +        let mut user_id = 1; +        for vote in quote.votes.iter() { +            info!("quote({}): Add vote {:?}", quote_id, vote); +            let score: i32 = vote.rating.parse().unwrap(); +            conn.execute(r"INSERT INTO votes (user_id, quote_id, score, ip, timestamp) VALUES (?1, ?2, ?3, ?4, ?5)", +            &[&user_id, "e_id, &score, &vote.ip, &vote.timestamp]).unwrap(); +            user_id += 1; +        } +    } +} + +fn main() { +    env_logger::init().unwrap(); + +    let matches = App::new("migration") +        .arg(Arg::with_name("db").required(true)) +        .arg(Arg::with_name("quotes_json").required(true)) +        .arg(Arg::with_name("votes_json").required(true)) +        .get_matches(); + +    let mut quotes = "".to_string(); +    File::open(matches.value_of("quotes_json").unwrap()) +        .unwrap() +        .read_to_string(&mut quotes) +        .unwrap(); + +    fn parse_all<'a, T: serde::Deserialize<'a>>(s: &'a str) -> Vec<T> { +        s.lines() +            .filter(|s| !s.is_empty()) +            .map(|s| { +                debug!("deserializing this: {:?}", s); +                serde_json::from_str(s).unwrap() +            }) +            .collect::<Vec<T>>() +    } +    let quotes: Vec<Quote> = parse_all("es); +    let mut quotes: HashMap<String, Quote> = +        quotes.into_iter().map(|q| (q.key.id.clone(), q)).collect(); + +    let mut votes = "".to_string(); +    File::open(matches.value_of("votes_json").unwrap()) +        .unwrap() +        .read_to_string(&mut votes) +        .unwrap(); +    let votes: Vec<Vote> = parse_all(&votes); + +    let mut v1 = 0; +    for vote in votes.into_iter() { +        if let Some(quote) = quotes.get_mut(&vote.quote_id) { +            quote.votes.push(vote); +        } +        v1 += 1; +    } + +    let mut v2 = 0; +    for (_, quote) in quotes.iter() { +        println!( +            "{}/{}: {} votes", +            quote.key.id, +            quote.quote_date, +            quote.votes.len() +        ); +        v2 += quote.votes.len(); +    } +    println!("votes before {} after {}", v1, v2); + +    let mut quotes: Vec<Quote> = quotes.into_iter().map(|(_, v)| v).collect(); +    quotes.sort_by_key(|q| { +        (q.quote_date.clone(), q.timestamp.clone(), q.key.id.clone()) +    }); + +    let mut conn = rusqlite::Connection::open(matches.value_of("db").unwrap()).unwrap(); +    let tx = conn.transaction().unwrap(); +    import(&tx, quotes.iter()); +    tx.commit().unwrap(); +} | 
