Skip to content

Commit

Permalink
add interactive flag
Browse files Browse the repository at this point in the history
  • Loading branch information
lmcmicu committed Dec 17, 2023
1 parent f4a8ddc commit 289213f
Show file tree
Hide file tree
Showing 3 changed files with 118 additions and 22 deletions.
2 changes: 1 addition & 1 deletion src/api_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -468,7 +468,7 @@ async fn test_undo_redo(valve: &Valve) -> Result<(), sqlx::Error> {
}

pub async fn run_api_tests(table: &str, database: &str) -> Result<(), sqlx::Error> {
let valve = Valve::build(table, "table", database, false, false).await?;
let valve = Valve::build(table, "table", database, false, false, false).await?;
// NOTE that you must use an external script to fetch the data from the database and run a diff
// against a known good sample to verify that these tests yield the expected results:
test_matching(&valve).await?;
Expand Down
68 changes: 62 additions & 6 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,13 +155,23 @@ impl std::fmt::Debug for ColumnRule {

#[derive(Debug)]
pub struct Valve {
/// TODO: Add docstring here.
pub global_config: SerdeMap,
/// TODO: Add docstring here.
pub compiled_datatype_conditions: HashMap<String, CompiledCondition>,
/// TODO: Add docstring here.
pub compiled_rule_conditions: HashMap<String, HashMap<String, Vec<ColumnRule>>>,
/// TODO: Add docstring here.
pub parsed_structure_conditions: HashMap<String, ParsedStructure>,
/// TODO: Add docstring here.
pub pool: AnyPool,
/// TODO: Add docstring here.
pub user: String,
/// TODO: Add docstring here.
pub verbose: bool,
/// TODO: Add docstring here. Note that this field is CLI only.
pub interactive: bool,
/// TODO: Add docstring here.
pub initial_load: bool,
}

Expand All @@ -182,6 +192,7 @@ impl Valve {
config_table: &str,
database: &str,
verbose: bool,
interactive: bool,
initial_load: bool,
) -> Result<Self, sqlx::Error> {
// TODO: Error type should be ConfigError
Expand Down Expand Up @@ -264,6 +275,7 @@ impl Valve {
pool: pool,
user: String::from("VALVE"),
verbose: verbose,
interactive: interactive,
initial_load: initial_load,
})
}
Expand Down Expand Up @@ -909,8 +921,10 @@ impl Valve {
let mut once_dropped = false;
for (i, table) in sorted_table_list.iter().enumerate() {
if self.table_has_changed(*table).await? {
// TODO: Prompt the user to confirm whether she wants to automatically drop any
// flagged tables.
if self.verbose {
// TODO: Prompt the user to confirm whether she wants to automatically drop any
// flagged tables.
}
if !once_dropped {
let mut tables_to_drop = vec![""; sorted_table_list.len() - i];
tables_to_drop.clone_from_slice(&sorted_table_list[i..]);
Expand All @@ -931,6 +945,32 @@ impl Valve {
Ok(self)
}

/// TODO: Add docstring here.
pub async fn table_exists(&self, table: &str) -> Result<bool, sqlx::Error> {
let sql = {
if self.pool.any_kind() == AnyKind::Sqlite {
format!(
r#"SELECT 1
FROM "sqlite_master"
WHERE "type" = 'table' AND name = '{}'
LIMIT 1"#,
table
)
} else {
format!(
r#"SELECT 1
FROM "information_schema"."tables"
WHERE "table_schema" = 'public'
AND "table_name" = '{}'"#,
table
)
}
};
let query = sqlx_query(&sql);
let rows = query.fetch_all(&self.pool).await?;
return Ok(rows.len() > 0);
}

/// Drop all configured tables, in reverse dependency order.
pub async fn drop_all_tables(&self) -> Result<&Self, sqlx::Error> {
// DatabaseError
Expand Down Expand Up @@ -962,8 +1002,16 @@ impl Valve {
drop_list
};

// TODO: If the drop_list does not match tables, prompt the user to confirm whether
// she wants to automatically truncate those dependent tables.
if self.verbose {
let auto_drops = drop_list
.iter()
.filter(|t| !tables.contains(t) && !block_on(self.table_exists(t)).unwrap())
.collect::<Vec<_>>();
if auto_drops.len() > 0 {
// TODO: prompt the user to confirm whether she wants to automatically drop
// the dependent tables.
}
}

for table in &drop_list {
if *table != "message" && *table != "history" {
Expand Down Expand Up @@ -1013,8 +1061,16 @@ impl Valve {
truncate_list
};

// TODO: If the truncate_list does not match tables, prompt the user to confirm whether
// she wants to automatically truncate those dependent tables.
if self.verbose {
let auto_truncates = truncate_list
.iter()
.filter(|t| !tables.contains(t) && !block_on(self.table_exists(t)).unwrap())
.collect::<Vec<_>>();
if auto_truncates.len() > 0 {
// TODO: prompt the user to confirm whether she wants to automatically truncate
// the dependent tables.
}
}

// We must use CASCADE in the case of PostgreSQL since we cannot truncate a table, T, that
// depends on another table, T', even in the case where we have previously truncated T'.
Expand Down
70 changes: 55 additions & 15 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,14 @@ fn cli_args_valid(source: &str, destination: &str, dump_config: bool) -> bool {

#[async_std::main]
async fn main() -> Result<(), sqlx::Error> {
let mut verbose = false;
let mut yes = false;
let mut api_test = false;
let mut dump_config = false;
let mut dump_schema = false;
let mut drop_all = false;
let mut create_only = false;
let mut config_table = String::new();
let mut verbose = false;
let mut initial_load = false;
let mut source = String::new();
let mut destination = String::new();
Expand All @@ -39,6 +41,16 @@ async fn main() -> Result<(), sqlx::Error> {
to by SOURCE will be read and a new database will be created and loaded
with the indicated data."#,
);
ap.refer(&mut verbose).add_option(
&["--verbose"],
StoreTrue,
r#"While loading the database, write progress messages to stderr."#,
);
ap.refer(&mut yes).add_option(
&["--yes"],
StoreTrue,
r#"Do not prompt the user to confirm dropping/truncating tables."#,
);
ap.refer(&mut api_test).add_option(
&["--api_test"],
StoreTrue,
Expand All @@ -52,6 +64,11 @@ async fn main() -> Result<(), sqlx::Error> {
r#"Read the configuration referred to by SOURCE and send it to stdout as a
JSON-formatted string."#,
);
ap.refer(&mut dump_schema).add_option(
&["--dump_schema"],
StoreTrue,
r#"Write the SQL used to create the database to stdout."#,
);
ap.refer(&mut drop_all).add_option(
&["--drop_all"],
StoreTrue,
Expand All @@ -63,18 +80,13 @@ async fn main() -> Result<(), sqlx::Error> {
r#"Read the configuration referred to by SOURCE, and create a corresponding database in
DESTINATION but do not load it."#,
);
// TODO: Remove this option:
ap.refer(&mut config_table).add_option(
&["--config_table"],
Store,
r#"When reading configuration from a database, the name to use to refer to the main
configuration table (defaults to "table")"#,
);
ap.refer(&mut verbose).add_option(
&["--verbose"],
StoreTrue,
r#"Write the SQL used to create the database to stdout after configuring it, and then
while loading the database, write progress messages to stderr."#,
);
ap.refer(&mut initial_load).add_option(
&["--initial_load"],
StoreTrue,
Expand Down Expand Up @@ -122,8 +134,15 @@ async fn main() -> Result<(), sqlx::Error> {
if api_test {
run_api_tests(&source, &destination).await?;
} else if dump_config {
let valve =
Valve::build(&source, &config_table, &destination, verbose, initial_load).await?;
let valve = Valve::build(
&source,
&config_table,
&destination,
verbose,
initial_load,
yes,
)
.await?;
let mut config = valve.global_config.clone();
let datatype_conditions =
format!("{:?}", valve.compiled_datatype_conditions).replace(r"\", r"\\");
Expand All @@ -142,16 +161,37 @@ async fn main() -> Result<(), sqlx::Error> {
let config = serde_json::to_string(&config).unwrap();
println!("{}", config);
} else if drop_all {
let valve =
Valve::build(&source, &config_table, &destination, verbose, initial_load).await?;
let valve = Valve::build(
&source,
&config_table,
&destination,
verbose,
initial_load,
yes,
)
.await?;
valve.drop_all_tables().await?;
} else if create_only {
let valve =
Valve::build(&source, &config_table, &destination, verbose, initial_load).await?;
let valve = Valve::build(
&source,
&config_table,
&destination,
verbose,
initial_load,
yes,
)
.await?;
valve.create_all_tables().await?;
} else {
let valve =
Valve::build(&source, &config_table, &destination, verbose, initial_load).await?;
let valve = Valve::build(
&source,
&config_table,
&destination,
verbose,
initial_load,
yes,
)
.await?;
valve.load_all_tables(true).await?;
}

Expand Down

0 comments on commit 289213f

Please sign in to comment.