sqlite select and inserts with guards
cargo devel CI / cargo CI (push) Failing after 1m42s
Details
cargo devel CI / cargo CI (push) Failing after 1m42s
Details
This commit is contained in:
parent
5dc524bef7
commit
c3b9b68af8
|
@ -4,3 +4,4 @@ members/c-bindings/lib/cmake_install.cmake
|
||||||
members/c-bindings/lib/libtest.so
|
members/c-bindings/lib/libtest.so
|
||||||
members/c-bindings/lib/libtest.so.1
|
members/c-bindings/lib/libtest.so.1
|
||||||
members/c-bindings/lib/libtest.so.1.0.1
|
members/c-bindings/lib/libtest.so.1.0.1
|
||||||
|
members/sqlite-demo/data/cats.db
|
||||||
|
|
Binary file not shown.
|
@ -1,34 +1,116 @@
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::{env, fs};
|
||||||
|
|
||||||
use anyhow::Ok;
|
use anyhow::Ok;
|
||||||
/// This demo application uses a sqlite file to store some data. It does *not* use ORM (that would
|
/// This demo application uses a sqlite file to store some data. It does *not* use ORM (that would
|
||||||
/// be done with the `diesel` crate.)!
|
/// be done with the `diesel` crate.)!
|
||||||
///
|
///
|
||||||
/// A very useful ressource is the
|
/// A very useful ressource is the
|
||||||
/// [rust-cookbook](https://rust-lang-nursery.github.io/rust-cookbook/database/sqlite.html).
|
/// [rust-cookbook](https://rust-lang-nursery.github.io/rust-cookbook/database/sqlite.html).
|
||||||
use rusqlite::{Connection, Result};
|
use rusqlite::Connection;
|
||||||
|
|
||||||
|
const DBNAME: &str = "cats.db";
|
||||||
|
const TABLE_CAT_COLOR: &str = "cat_colors";
|
||||||
|
const TABLE_CAT: &str = "cats";
|
||||||
|
|
||||||
|
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<()> {
|
fn setup(conn: &Connection) -> anyhow::Result<()> {
|
||||||
conn.execute(
|
conn.execute(
|
||||||
"create table if not exists cat_colors (
|
&format!(
|
||||||
id integer primary key,
|
"CREATE TABLE IF NOT EXISTS {TABLE_CAT_COLOR} (
|
||||||
name text not null unique
|
id INTEGER PRIMARY KEY,
|
||||||
)",
|
name TEXT NOT NULL UNIQUE COLLATE NOCASE
|
||||||
|
)"
|
||||||
|
),
|
||||||
(),
|
(),
|
||||||
)?;
|
)?;
|
||||||
conn.execute(
|
conn.execute(
|
||||||
"create table if not exists cats (
|
&format!(
|
||||||
id integer primary key,
|
"CREATE TABLE IF NOT EXISTS {TABLE_CAT} (
|
||||||
name text not null,
|
id INTEGER PRIMARY KEY,
|
||||||
color_id integer not null references cat_colors(id)
|
name TEXT NOT NULL COLLATE NOCASE,
|
||||||
)",
|
COLOR_ID INTEGER NOT NULL REFERENCES CAT_COLORS(ID)
|
||||||
|
)"
|
||||||
|
),
|
||||||
(),
|
(),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Add a new color to the cat_colors table
|
||||||
|
///
|
||||||
|
/// Will fail if the sql fails
|
||||||
|
///
|
||||||
|
/// If the color already exists, will return Ok(())
|
||||||
|
///
|
||||||
|
/// The table stores the name in lowercase
|
||||||
fn new_color(conn: &Connection, color: &str) -> anyhow::Result<()> {
|
fn new_color(conn: &Connection, color: &str) -> anyhow::Result<()> {
|
||||||
|
// check if the color already exists, so we can just try adding a color and not worry if it
|
||||||
|
// already exists
|
||||||
|
|
||||||
|
let mut stmt = conn.prepare(&format!(
|
||||||
|
"SELECT EXISTS( SELECT 1 FROM {TABLE_CAT_COLOR} WHERE name = (?1))"
|
||||||
|
))?;
|
||||||
|
if let Some(row) = stmt.query([color.to_string()])?.next()? {
|
||||||
|
if row.get::<usize, usize>(0)? == 1 {
|
||||||
|
// the color already exists
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// do the inserting
|
||||||
conn.execute(
|
conn.execute(
|
||||||
"INSERT INTO cat_colors (name) values (?1)",
|
"INSERT INTO cat_colors (name) VALUES (?1)",
|
||||||
[color.to_string()],
|
[color.to_string()],
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
@ -36,11 +118,12 @@ fn new_color(conn: &Connection, color: &str) -> anyhow::Result<()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> anyhow::Result<()> {
|
fn main() -> anyhow::Result<()> {
|
||||||
let conn = Connection::open("cats.db")?;
|
let conn = connect()?;
|
||||||
|
|
||||||
setup(&conn)?;
|
setup(&conn)?;
|
||||||
new_color(&conn, "black")?;
|
new_color(&conn, "black")?;
|
||||||
new_color(&conn, "red")?;
|
new_color(&conn, "red")?;
|
||||||
|
new_color(&conn, "white")?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue