deleting colors(+cats) works
This commit is contained in:
parent
22fa06e2b6
commit
29ebb7b31a
|
@ -0,0 +1,174 @@
|
|||
use std::path::PathBuf;
|
||||
use std::{env, fs};
|
||||
|
||||
use rusqlite::Connection;
|
||||
pub const DBNAME: &str = "cats.db";
|
||||
pub const TABLE_CAT_COLOR: &str = "cat_colors";
|
||||
pub const TABLE_CAT: &str = "cats";
|
||||
|
||||
|
||||
pub fn connect() -> anyhow::Result<Connection> {
|
||||
let mut wd = env::current_dir()?;
|
||||
let mut dbpath: Option<PathBuf> = None;
|
||||
|
||||
// does the current directory have a data/cats.db ? (the file need not exist, we can create it
|
||||
// if data exists)
|
||||
{
|
||||
let mut wddata = wd.clone();
|
||||
wddata.push("data");
|
||||
if wddata.exists() {
|
||||
println!("found {DBNAME} in {:?}", &wddata);
|
||||
wddata.push(DBNAME);
|
||||
dbpath = Some(wddata);
|
||||
}
|
||||
}
|
||||
|
||||
// otherwise, does the current or any higher directories contain a cats.db ?
|
||||
'search_dir: while dbpath.is_none() {
|
||||
for entry in fs::read_dir(&wd)? {
|
||||
let entry = entry?;
|
||||
if entry.file_name() == DBNAME {
|
||||
println!("found {DBNAME} in {:?}", wd);
|
||||
dbpath = Some(entry.path());
|
||||
break 'search_dir;
|
||||
}
|
||||
}
|
||||
if !wd.pop() {
|
||||
// we are at the root!
|
||||
break 'search_dir;
|
||||
}
|
||||
}
|
||||
|
||||
// if all fails, use $PWD/data/cats.db
|
||||
if dbpath.is_none() {
|
||||
println!(
|
||||
"No {DBNAME} found, using {:?}/data/{DBNAME}",
|
||||
env::current_dir()?
|
||||
);
|
||||
fs::create_dir("data")?;
|
||||
let mut path = env::current_dir()?;
|
||||
path.push("data");
|
||||
path.push(DBNAME);
|
||||
dbpath = Some(path);
|
||||
}
|
||||
|
||||
let conn = Connection::open(dbpath.unwrap())?;
|
||||
|
||||
Ok(conn)
|
||||
}
|
||||
|
||||
pub fn setup(conn: &Connection) -> anyhow::Result<()> {
|
||||
conn.execute(
|
||||
&format!(
|
||||
"CREATE TABLE IF NOT EXISTS {TABLE_CAT_COLOR} (
|
||||
id INTEGER PRIMARY KEY,
|
||||
name TEXT NOT NULL UNIQUE COLLATE NOCASE
|
||||
)"
|
||||
),
|
||||
(),
|
||||
)?;
|
||||
conn.execute(
|
||||
&format!(
|
||||
"CREATE TABLE IF NOT EXISTS {TABLE_CAT} (
|
||||
id INTEGER PRIMARY KEY,
|
||||
name TEXT NOT NULL COLLATE NOCASE,
|
||||
color_id INTEGER NOT NULL REFERENCES CAT_COLORS(ID)
|
||||
)"
|
||||
),
|
||||
(),
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// color names are unique, so we use the color name instead of the id because it's easier
|
||||
pub fn check_if_color_exists(conn: &Connection, color: &str) -> anyhow::Result<bool> {
|
||||
let mut stmt = conn.prepare(&format!(
|
||||
"SELECT EXISTS( SELECT 1 FROM {TABLE_CAT_COLOR} WHERE name = (LOWER(?1)))"
|
||||
))?;
|
||||
|
||||
// we need the return or the temporary result is dropped somehow
|
||||
#[allow(clippy::needless_return)]
|
||||
return Ok(stmt
|
||||
.query([color.to_string()])?
|
||||
.next()?
|
||||
.unwrap()
|
||||
.get::<usize, usize>(0)?
|
||||
== 1);
|
||||
}
|
||||
|
||||
// note that cat names are not UNIQUE, so we need to use the id instead
|
||||
pub fn check_if_cat_exists(conn: &Connection, id: usize) -> anyhow::Result<bool> {
|
||||
let mut stmt = conn.prepare(&format!(
|
||||
"SELECT EXISTS( SELECT 1 FROM {TABLE_CAT} WHERE id = (?1))"
|
||||
))?;
|
||||
|
||||
// we need the return or the temporary result is dropped somehow
|
||||
#[allow(clippy::needless_return)]
|
||||
return Ok(stmt.query([id])?.next()?.unwrap().get::<usize, usize>(0)? == 1);
|
||||
}
|
||||
|
||||
/// Add a new color to the cat_colors table
|
||||
///
|
||||
/// Will fail if the sql fails
|
||||
///
|
||||
/// If the color already exists, will return Ok(id)
|
||||
///
|
||||
/// The table stores the name in lowercase
|
||||
///
|
||||
/// Returns the id of the color
|
||||
pub fn new_color(conn: &Connection, color: &str) -> anyhow::Result<usize> {
|
||||
if check_if_color_exists(conn, color)? {
|
||||
return get_color_id(conn, color);
|
||||
}
|
||||
|
||||
conn.execute(
|
||||
&format!("INSERT INTO {TABLE_CAT_COLOR} (name) VALUES (LOWER(?1))"),
|
||||
[color.to_string()],
|
||||
)?;
|
||||
|
||||
get_color_id(conn, color)
|
||||
}
|
||||
|
||||
pub fn get_color_id(conn: &Connection, color: &str) -> anyhow::Result<usize> {
|
||||
Ok(conn.query_row(
|
||||
&format!("SELECT id FROM {TABLE_CAT_COLOR} WHERE name = (LOWER(?1))"),
|
||||
[color.to_string()],
|
||||
|row| row.get::<usize, usize>(0),
|
||||
)?)
|
||||
}
|
||||
|
||||
pub fn get_color_by_id(conn: &Connection, id: usize) -> anyhow::Result<Option<String>> {
|
||||
let maybe = conn.query_row(
|
||||
&format!("SELECT name FROM {TABLE_CAT_COLOR} WHERE id = (?1)"),
|
||||
[id.to_string()],
|
||||
|row| row.get::<usize, String>(0),
|
||||
);
|
||||
if let Result::Ok(color) = maybe {
|
||||
Ok(Some(color))
|
||||
} else {
|
||||
let err: rusqlite::Error = maybe.unwrap_err();
|
||||
if matches!(err, rusqlite::Error::QueryReturnedNoRows) {
|
||||
Ok(None)
|
||||
} else {
|
||||
Err(err.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_cat(conn: &Connection, name: &str, color_id: usize) -> anyhow::Result<usize> {
|
||||
conn.execute(
|
||||
&format!("INSERT INTO {TABLE_CAT} (name, color_id) VALUES (LOWER(?1), ?2)"),
|
||||
[name.to_string(), color_id.to_string()],
|
||||
)?;
|
||||
|
||||
Ok(conn.last_insert_rowid() as usize)
|
||||
}
|
||||
|
||||
pub fn get_cat_color(conn: &Connection, id: usize) -> anyhow::Result<String> {
|
||||
Ok(conn.query_row(
|
||||
&format!("SELECT cc.name FROM {TABLE_CAT_COLOR} cc, {TABLE_CAT} c WHERE c.id = (?1) AND c.color_id = cc.id"),
|
||||
[id.to_string()],
|
||||
|row| row.get::<usize, String>(0),
|
||||
)?)
|
||||
}
|
|
@ -1,189 +1,21 @@
|
|||
use std::io;
|
||||
/// This demo application uses a sqlite file to store some data. It does *not* use ORM (that would
|
||||
/// be done with the `diesel` crate.)!
|
||||
///
|
||||
/// A very useful ressource is the
|
||||
/// [rust-cookbook](https://rust-lang-nursery.github.io/rust-cookbook/database/sqlite.html).
|
||||
use std::io::{BufRead, Write};
|
||||
use std::path::PathBuf;
|
||||
use std::{env, fs, io};
|
||||
|
||||
use rusqlite::{Connection, Rows};
|
||||
|
||||
const DBNAME: &str = "cats.db";
|
||||
const TABLE_CAT_COLOR: &str = "cat_colors";
|
||||
const TABLE_CAT: &str = "cats";
|
||||
mod db;
|
||||
use db::*;
|
||||
|
||||
const USAGE_DELETE: &str = "Usage:
|
||||
> D cat 15 (to delete cat with id 15)
|
||||
> D cat 15 16 (to delete cat with id 15 and 16)
|
||||
> D color 5 (to delete color with id 5)";
|
||||
|
||||
fn connect() -> anyhow::Result<Connection> {
|
||||
let mut wd = env::current_dir()?;
|
||||
let mut dbpath: Option<PathBuf> = None;
|
||||
|
||||
// does the current directory have a data/cats.db ? (the file need not exist, we can create it
|
||||
// if data exists)
|
||||
{
|
||||
let mut wddata = wd.clone();
|
||||
wddata.push("data");
|
||||
if wddata.exists() {
|
||||
println!("found {DBNAME} in {:?}", &wddata);
|
||||
wddata.push(DBNAME);
|
||||
dbpath = Some(wddata);
|
||||
}
|
||||
}
|
||||
|
||||
// otherwise, does the current or any higher directories contain a cats.db ?
|
||||
'search_dir: while dbpath.is_none() {
|
||||
for entry in fs::read_dir(&wd)? {
|
||||
let entry = entry?;
|
||||
if entry.file_name() == DBNAME {
|
||||
println!("found {DBNAME} in {:?}", wd);
|
||||
dbpath = Some(entry.path());
|
||||
break 'search_dir;
|
||||
}
|
||||
}
|
||||
if !wd.pop() {
|
||||
// we are at the root!
|
||||
break 'search_dir;
|
||||
}
|
||||
}
|
||||
|
||||
// if all fails, use $PWD/data/cats.db
|
||||
if dbpath.is_none() {
|
||||
println!(
|
||||
"No {DBNAME} found, using {:?}/data/{DBNAME}",
|
||||
env::current_dir()?
|
||||
);
|
||||
fs::create_dir("data")?;
|
||||
let mut path = env::current_dir()?;
|
||||
path.push("data");
|
||||
path.push(DBNAME);
|
||||
dbpath = Some(path);
|
||||
}
|
||||
|
||||
let conn = Connection::open(dbpath.unwrap())?;
|
||||
|
||||
Ok(conn)
|
||||
}
|
||||
|
||||
fn setup(conn: &Connection) -> anyhow::Result<()> {
|
||||
conn.execute(
|
||||
&format!(
|
||||
"CREATE TABLE IF NOT EXISTS {TABLE_CAT_COLOR} (
|
||||
id INTEGER PRIMARY KEY,
|
||||
name TEXT NOT NULL UNIQUE COLLATE NOCASE
|
||||
)"
|
||||
),
|
||||
(),
|
||||
)?;
|
||||
conn.execute(
|
||||
&format!(
|
||||
"CREATE TABLE IF NOT EXISTS {TABLE_CAT} (
|
||||
id INTEGER PRIMARY KEY,
|
||||
name TEXT NOT NULL COLLATE NOCASE,
|
||||
color_id INTEGER NOT NULL REFERENCES CAT_COLORS(ID)
|
||||
)"
|
||||
),
|
||||
(),
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// color names are unique, so we use the color name instead of the id because it's easier
|
||||
fn check_if_color_exists(conn: &Connection, color: &str) -> anyhow::Result<bool> {
|
||||
let mut stmt = conn.prepare(&format!(
|
||||
"SELECT EXISTS( SELECT 1 FROM {TABLE_CAT_COLOR} WHERE name = (LOWER(?1)))"
|
||||
))?;
|
||||
|
||||
// we need the return or the temporary result is dropped somehow
|
||||
#[allow(clippy::needless_return)]
|
||||
return Ok(stmt
|
||||
.query([color.to_string()])?
|
||||
.next()?
|
||||
.unwrap()
|
||||
.get::<usize, usize>(0)?
|
||||
== 1);
|
||||
}
|
||||
|
||||
// note that cat names are not UNIQUE, so we need to use the id instead
|
||||
fn check_if_cat_exists(conn: &Connection, id: usize) -> anyhow::Result<bool> {
|
||||
let mut stmt = conn.prepare(&format!(
|
||||
"SELECT EXISTS( SELECT 1 FROM {TABLE_CAT} WHERE id = (?1))"
|
||||
))?;
|
||||
|
||||
// we need the return or the temporary result is dropped somehow
|
||||
#[allow(clippy::needless_return)]
|
||||
return Ok(stmt.query([id])?.next()?.unwrap().get::<usize, usize>(0)? == 1);
|
||||
}
|
||||
|
||||
/// Add a new color to the cat_colors table
|
||||
///
|
||||
/// Will fail if the sql fails
|
||||
///
|
||||
/// If the color already exists, will return Ok(id)
|
||||
///
|
||||
/// The table stores the name in lowercase
|
||||
///
|
||||
/// Returns the id of the color
|
||||
fn new_color(conn: &Connection, color: &str) -> anyhow::Result<usize> {
|
||||
if check_if_color_exists(conn, color)? {
|
||||
return get_color_id(conn, color);
|
||||
}
|
||||
|
||||
conn.execute(
|
||||
&format!("INSERT INTO {TABLE_CAT_COLOR} (name) VALUES (LOWER(?1))"),
|
||||
[color.to_string()],
|
||||
)?;
|
||||
|
||||
get_color_id(conn, color)
|
||||
}
|
||||
|
||||
fn get_color_id(conn: &Connection, color: &str) -> anyhow::Result<usize> {
|
||||
Ok(conn.query_row(
|
||||
&format!("SELECT id FROM {TABLE_CAT_COLOR} WHERE name = (LOWER(?1))"),
|
||||
[color.to_string()],
|
||||
|row| row.get::<usize, usize>(0),
|
||||
)?)
|
||||
}
|
||||
|
||||
fn get_color_by_id(conn: &Connection, id: usize) -> anyhow::Result<Option<String>> {
|
||||
let maybe = conn.query_row(
|
||||
&format!("SELECT name FROM {TABLE_CAT_COLOR} WHERE id = (?1)"),
|
||||
[id.to_string()],
|
||||
|row| row.get::<usize, String>(0),
|
||||
);
|
||||
if let Result::Ok(color) = maybe {
|
||||
Ok(Some(color))
|
||||
} else {
|
||||
let err: rusqlite::Error = maybe.unwrap_err();
|
||||
if matches!(err, rusqlite::Error::QueryReturnedNoRows) {
|
||||
Ok(None)
|
||||
} else {
|
||||
Err(err.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn new_cat(conn: &Connection, name: &str, color_id: usize) -> anyhow::Result<usize> {
|
||||
conn.execute(
|
||||
&format!("INSERT INTO {TABLE_CAT} (name, color_id) VALUES (LOWER(?1), ?2)"),
|
||||
[name.to_string(), color_id.to_string()],
|
||||
)?;
|
||||
|
||||
Ok(conn.last_insert_rowid() as usize)
|
||||
}
|
||||
|
||||
fn get_cat_color(conn: &Connection, id: usize) -> anyhow::Result<String> {
|
||||
Ok(conn.query_row(
|
||||
&format!("SELECT cc.name FROM {TABLE_CAT_COLOR} cc, {TABLE_CAT} c WHERE c.id = (?1) AND c.color_id = cc.id"),
|
||||
[id.to_string()],
|
||||
|row| row.get::<usize, String>(0),
|
||||
)?)
|
||||
}
|
||||
|
||||
fn interactive_add_cat(conn: &Connection) -> anyhow::Result<usize> {
|
||||
let stdin = io::stdin();
|
||||
print!("the name of your cat?\n> ");
|
||||
|
@ -234,6 +66,97 @@ fn interactive_find_cat(conn: &Connection) -> anyhow::Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn interactive_delete(conn: &Connection, buf: &mut String) -> anyhow::Result<()> {
|
||||
let words: Vec<&str> = buf.split(' ').collect();
|
||||
if words.len() < 2 {
|
||||
println!("{USAGE_DELETE}");
|
||||
} else {
|
||||
let stdin = io::stdin();
|
||||
let mode = words[1];
|
||||
let mut nums: Vec<usize> = Vec::new();
|
||||
for word in words[2..].iter() {
|
||||
nums.push(match word.parse() {
|
||||
Ok(n) => n,
|
||||
Err(e) => {
|
||||
eprintln!("Could not parse '{word}' to id: {e}");
|
||||
continue;
|
||||
}
|
||||
})
|
||||
}
|
||||
match mode {
|
||||
"CAT" => {
|
||||
let mut stmt = conn.prepare(&format!("DELETE FROM {TABLE_CAT} WHERE id = (?1)"))?;
|
||||
for n in nums {
|
||||
stmt.execute([n])?;
|
||||
}
|
||||
}
|
||||
"COLOR" => {
|
||||
// Cats have colors, so if we delete a color, we need to delete cats with
|
||||
// that color too.
|
||||
let mut stmt_how_many_cats_with_color = conn.prepare(&format!(
|
||||
"SELECT COUNT(1) FROM {TABLE_CAT} c, {TABLE_CAT_COLOR}
|
||||
cc WHERE c.color_id = (?1) AND cc.id = (?1)"
|
||||
))?;
|
||||
// FIXME: this must still be wrong?
|
||||
let mut stmt_cats_with_color = conn.prepare(&format!(
|
||||
"SELECT c.* FROM {TABLE_CAT} c, {TABLE_CAT_COLOR} cc
|
||||
WHERE c.color_id = (?1) AND cc.id = (?1)"
|
||||
))?;
|
||||
// works: `SELECT cats.* FROM cats, cat_colors WHERE cats.color_id = 2 AND cat_colors.id = 2;`
|
||||
|
||||
for color_id in &nums {
|
||||
let cats_amount: usize = stmt_how_many_cats_with_color
|
||||
.query_row([color_id], |row| row.get::<_, usize>(0))?;
|
||||
|
||||
if cats_amount > 0 {
|
||||
let mut cats = stmt_cats_with_color.query([color_id])?; // Get the cats
|
||||
// that would be deleted
|
||||
println!(
|
||||
"\nYou are about to also delete these cats,\n\
|
||||
as they have the color id {color_id}. Type 'YES' to confirm."
|
||||
);
|
||||
print_cats(conn, &mut cats)?;
|
||||
drop(cats); // we need to renew this, because Rows is not Clone and we have
|
||||
// consumed the Rows in print_cats. The Rows index can not be reset,
|
||||
// probably because of a sqlite API limitation.
|
||||
|
||||
let mut cats = stmt_cats_with_color.query([color_id])?;
|
||||
let mut cat_ids: Vec<usize> = Vec::new();
|
||||
|
||||
while let Some(cat) = cats.next()? {
|
||||
cat_ids.push(cat.get::<_, usize>(0)?);
|
||||
}
|
||||
buf.clear();
|
||||
let _ = stdin.lock().read_line(buf); // wait for enter as confirmation
|
||||
*buf = buf.trim().to_string();
|
||||
*buf = buf.to_uppercase().to_string();
|
||||
dbg!(&buf);
|
||||
if buf.as_str() != "YES" {
|
||||
continue;
|
||||
}
|
||||
let mut stmt =
|
||||
conn.prepare(&format!("DELETE FROM {TABLE_CAT} WHERE id = (?1)"))?;
|
||||
for cat_id in cat_ids {
|
||||
stmt.execute([cat_id])?;
|
||||
}
|
||||
}
|
||||
|
||||
let mut stmt =
|
||||
conn.prepare(&format!("DELETE FROM {TABLE_CAT_COLOR} WHERE id = (?1)"))?;
|
||||
for n in &nums {
|
||||
stmt.execute([n])?;
|
||||
}
|
||||
}
|
||||
println!("deleted ids {nums:?}");
|
||||
}
|
||||
_ => {
|
||||
println!("{USAGE_DELETE}");
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn print_colors(_conn: &Connection, colors: &mut Rows) -> anyhow::Result<()> {
|
||||
println!("{: <14}| {: <19}", "id", "name");
|
||||
println!("{:=^80}", "");
|
||||
|
@ -247,6 +170,9 @@ fn print_colors(_conn: &Connection, colors: &mut Rows) -> anyhow::Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Print [Rows] of cats.
|
||||
///
|
||||
/// This needs all columns of the [TABLE_CAT], otherwise it will error.
|
||||
fn print_cats(conn: &Connection, cats: &mut Rows) -> anyhow::Result<()> {
|
||||
println!(
|
||||
"{: <14}| {: <19}| {: <19} -> {: <19}",
|
||||
|
@ -289,7 +215,7 @@ fn main() -> anyhow::Result<()> {
|
|||
|
||||
loop {
|
||||
buf.clear();
|
||||
print!("{}[2J", 27 as char); // clear terminal
|
||||
// print!("{}[2J", 27 as char); // clear terminal
|
||||
io::stdout().flush()?;
|
||||
print!("(A)dd a cat, (F)ind a cat, (P)rint out all data, (D)elete data, or (E)xit?\n> ");
|
||||
io::stdout().flush()?;
|
||||
|
@ -303,87 +229,12 @@ fn main() -> anyhow::Result<()> {
|
|||
} else if buf.starts_with('P') {
|
||||
print_all_data(&conn)?;
|
||||
} else if buf.starts_with('D') {
|
||||
let words: Vec<&str> = buf.split(' ').collect();
|
||||
dbg!(&words);
|
||||
if words.len() < 2 {
|
||||
println!("{USAGE_DELETE}");
|
||||
} else {
|
||||
let mode = words[1];
|
||||
let nums: Vec<usize> = words[2..]
|
||||
.iter()
|
||||
.map(|word| {
|
||||
word.parse::<usize>()
|
||||
.expect("could not parse db integer to rust integer")
|
||||
})
|
||||
.collect();
|
||||
dbg!(&nums);
|
||||
match mode {
|
||||
"CAT" => {
|
||||
let mut stmt =
|
||||
conn.prepare(&format!("DELETE FROM {TABLE_CAT} WHERE id = (?1)"))?;
|
||||
for n in nums {
|
||||
stmt.execute([n])?;
|
||||
}
|
||||
}
|
||||
"COLOR" => {
|
||||
// Cats have colors, so if we delete a color, we need to delete cats with
|
||||
// that color too.
|
||||
let mut stmt_how_many_cats_with_color = conn.prepare(&format!(
|
||||
"SELECT cc.id FROM {TABLE_CAT} c, {TABLE_CAT_COLOR}
|
||||
cc WHERE c.color_id = (?1)"
|
||||
))?;
|
||||
let mut stmt_cats_with_color = conn.prepare(&format!(
|
||||
"SELECT cc.id FROM {TABLE_CAT} c, {TABLE_CAT_COLOR}
|
||||
cc WHERE c.color_id = (?1)"
|
||||
))?;
|
||||
|
||||
for color_id in &nums {
|
||||
let cats_amount: usize = stmt_how_many_cats_with_color
|
||||
.query_row([color_id], |row| row.get::<_, usize>(0))?;
|
||||
|
||||
if cats_amount > 0 {
|
||||
// FIXME: cats is empty?
|
||||
let mut cats = stmt_cats_with_color.query([color_id])?;
|
||||
let mut cat_ids: Vec<usize> = Vec::new();
|
||||
|
||||
while let Some(cat) = cats.next()? {
|
||||
cat_ids.push(cat.get::<_, usize>(0)?);
|
||||
}
|
||||
|
||||
println!("You are about to also delete these cats, as they have the color id {color_id}. Type 'YES' to confirm");
|
||||
print_cats(&conn, &mut cats)?;
|
||||
buf.clear();
|
||||
let _ = stdin.lock().read_line(&mut buf); // wait for enter as confirmation
|
||||
buf = buf.trim().to_string();
|
||||
buf = buf.to_uppercase().to_string();
|
||||
if buf.as_str() != "YES" {
|
||||
continue;
|
||||
}
|
||||
// FIXME: I DELETED ALL THE CATS OH NO
|
||||
let mut stmt = conn
|
||||
.prepare(&format!("DELETE FROM {TABLE_CAT} WHERE id = (?1)"))?;
|
||||
for cat_id in cat_ids {
|
||||
stmt.execute([cat_id])?;
|
||||
}
|
||||
}
|
||||
|
||||
let mut stmt = conn.prepare(&format!(
|
||||
"DELETE FROM {TABLE_CAT_COLOR} WHERE id = (?1)"
|
||||
))?;
|
||||
let _ = nums.iter().map(|n| stmt.execute([n]));
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
println!("{USAGE_DELETE}");
|
||||
}
|
||||
}
|
||||
}
|
||||
interactive_delete(&conn, &mut buf)?;
|
||||
} else if buf.starts_with('E') {
|
||||
println!("Goodbye");
|
||||
break;
|
||||
}
|
||||
println!("\n(Enter to continue)");
|
||||
let _ = stdin.lock().read_line(&mut buf); // wait for enter as confirmation
|
||||
println!("\n");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
Loading…
Reference in New Issue