aboutsummaryrefslogtreecommitdiffstats
path: root/rust/src/bin/fatcat-doctor.rs
blob: 7255a22f9cb4fe16d5ee1d77ab24927272d7f1bd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
//! Database cleanup tool

use clap::{value_t_or_exit, App, SubCommand};

use fatcat::database_models::*;
use fatcat::database_schema::*;
use fatcat::errors::Result;
use fatcat::identifiers::FatcatId;
use fatcat::server;
use fatcat::server::DbConn;
use std::process;
use std::str::FromStr;

use diesel::prelude::*;

fn backfill_changelog_gap(conn: &DbConn, last_good: i64, max_index: i64) -> Result<()> {
    // sanity check arguments against database
    assert!(last_good > 0);
    assert!(max_index > 0);
    assert!(last_good < max_index);
    let highest_row: ChangelogRow = changelog::table.order(changelog::id.desc()).first(conn)?;
    assert!(highest_row.id >= max_index);

    // default values
    // 'root' editor_id is aaaaaaaaaaaabkvkaaaaaaaaae
    // 'admin' editor_id is aaaaaaaaaaaabkvkaaaaaaaaai
    let editor_id = FatcatId::from_str("aaaaaaaaaaaabkvkaaaaaaaaai").unwrap();
    let description = "Backfill of missing changelog entries due to database id gap";

    // fetch the last entry before the gap, to re-use the timestamp
    let existing_row: ChangelogRow = changelog::table.find(last_good).first(conn)?;

    for index in last_good + 1..max_index + 1 {
        // ensure this index is actually a gap
        let count: i64 = changelog::table
            .filter(changelog::id.eq(index))
            .count()
            .get_result(conn)?;
        if count != 0 {
            println!("Found existing changelog: {}", index);
            return Ok(());
        }

        // create dummy empty editgroup, then add a changelog entry
        let eg_row: EditgroupRow = diesel::insert_into(editgroup::table)
            .values((
                editgroup::editor_id.eq(editor_id.to_uuid()),
                editgroup::created.eq(existing_row.timestamp),
                editgroup::is_accepted.eq(true),
                editgroup::description.eq(Some(description)),
            ))
            .get_result(conn)?;
        let _entry_row: ChangelogRow = diesel::insert_into(changelog::table)
            .values((
                changelog::id.eq(index),
                changelog::editgroup_id.eq(eg_row.id),
                changelog::timestamp.eq(existing_row.timestamp),
            ))
            .get_result(conn)?;
        println!("Inserted changelog: {}", index);
    }
    Ok(())
}

fn main() -> Result<()> {
    let m = App::new("fatcat-doctor")
        .version(env!("CARGO_PKG_VERSION"))
        .author("Bryan Newbold <bnewbold@archive.org>")
        .about("Database cleanup / fixup tool")
        .subcommand(
            SubCommand::with_name("backfill-changelog-gap")
                .about("Inserts dummy changelog entries and editgroups for gap")
                .args_from_usage(
                    "<start> 'changelog index of entry just before gap'
                    <end> 'highest changelog index to backfill'",
                ),
        )
        .get_matches();

    let db_conn = server::database_worker_pool()?
        .get()
        .expect("database pool");
    match m.subcommand() {
        ("backfill-changelog-gap", Some(subm)) => {
            let last_good: i64 = value_t_or_exit!(subm.value_of("start"), i64);
            let max_index: i64 = value_t_or_exit!(subm.value_of("end"), i64);
            backfill_changelog_gap(&db_conn, last_good, max_index)?;
        }
        _ => {
            println!("Missing or unimplemented command!");
            println!("{}", m.usage());
            process::exit(-1);
        }
    }
    Ok(())
}