From 0603c3f460a90ac2194219c4d189e17c724c4d5f Mon Sep 17 00:00:00 2001 From: "Christoph J. Scherr" Date: Thu, 27 Jun 2024 09:58:50 +0200 Subject: [PATCH] a lot of things happened and my id is now null --- members/diesel-demo/Cargo.toml | 2 +- members/diesel-demo/data/dieseldemo.db | Bin 12288 -> 20480 bytes members/diesel-demo/src/lib.rs | 45 +++++++++++++++++- members/diesel-demo/src/main.rs | 43 +++++++++++++++-- members/diesel-demo/src/models.rs | 61 +++++++++++++++++++++++++ members/diesel-demo/src/schema.rs | 8 ++-- 6 files changed, 148 insertions(+), 11 deletions(-) create mode 100644 members/diesel-demo/src/models.rs diff --git a/members/diesel-demo/Cargo.toml b/members/diesel-demo/Cargo.toml index 98f0385..5424625 100644 --- a/members/diesel-demo/Cargo.toml +++ b/members/diesel-demo/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" [dependencies] anyhow.workspace = true -diesel = { version = "2.2.1", features = ["serde_json", "sqlite", "uuid"] } +diesel = { version = "2.2.1", features = ["serde_json", "sqlite", "uuid", "returning_clauses_for_sqlite_3_35"] } dotenvy = "0.15.7" libpt.workspace = true serde = { workspace = true, features = ["serde_derive"] } diff --git a/members/diesel-demo/data/dieseldemo.db b/members/diesel-demo/data/dieseldemo.db index 85e66ea95a89564f1f2df04bf8f2e3bb6b0244d6..8ee4e2248e968019b859cb45eeaf172df0dfec68 100644 GIT binary patch delta 351 zcmZojXjs5FL0XWBfq{V)h+%+fqK>gB6N6q^2QU8*1{U6b416c}7xVt(o4c{Fi?_Z} zhM8SlT%55~I)=C^gg83+xGE%o#S%2QI1@5c5)?fBLQE9= z{6iG{LVbJ`0)jk!9fKkjyj>%8fC@@7OL9^Z6v7;XoIM3S8hfP+?@&G&V9YGBGeSGBY$bwJAX8-^I diff --git a/members/diesel-demo/src/lib.rs b/members/diesel-demo/src/lib.rs index 6310f34..9bedbe5 100644 --- a/members/diesel-demo/src/lib.rs +++ b/members/diesel-demo/src/lib.rs @@ -1,13 +1,19 @@ +pub mod models; pub mod schema; -use std::env; +use std::io::Write; +use std::{env, io}; use diesel::prelude::*; use diesel::sqlite::SqliteConnection; use dotenvy::dotenv; -use libpt::log::error; // load envars from a `.env` file +use libpt::log::{error, info, warn}; + +use self::models::*; +use self::schema::posts::dsl::*; +use diesel::prelude::*; pub fn establish_connection() -> anyhow::Result { dotenv()?; @@ -16,3 +22,38 @@ pub fn establish_connection() -> anyhow::Result { Ok(SqliteConnection::establish(&database_url) .inspect_err(|e| error!("Error connecting to {}:\n{e:#?}", database_url))?) } + +pub fn load_posts(conn: &mut SqliteConnection) -> anyhow::Result> { + Ok(posts + .filter(published.eq(true)) + .limit(5) + .select(Post::as_select()) + .load(conn)?) +} + +pub fn print_posts(posts_to_print: &Vec) { + if !posts_to_print.is_empty() { + info!("Displaying {} posts", posts_to_print.len()); + for post in posts_to_print { + println!("{}", post.title); + println!("-----------\n"); + println!("{}", post.body); + } + } else { + warn!("Tried to display posts, but there are no posts stored in the database"); + } +} + +// NOTE: this can't handle unicode stuff like 春 and I don't really care +pub fn read_buf_interactive(buf: &mut String) -> anyhow::Result<()> { + buf.clear(); + let stdin = io::stdin(); + let mut stdout = io::stdout(); + + print!("> "); + stdout.flush()?; + stdin.read_line(buf)?; + *buf = buf.trim().to_string(); + + Ok(()) +} diff --git a/members/diesel-demo/src/main.rs b/members/diesel-demo/src/main.rs index 508a06c..4208b85 100644 --- a/members/diesel-demo/src/main.rs +++ b/members/diesel-demo/src/main.rs @@ -1,16 +1,53 @@ -use libpt::log::{self, debug}; +use diesel::SqliteConnection; +use diesel_demo::models::PostDraft; +use libpt::log::{self, debug, info, trace, warn}; use diesel_demo as lib; fn main() -> anyhow::Result<()> { let _logger = log::Logger::builder() .max_level(log::Level::TRACE) - .uptime(true) + .show_time(false) .build(); debug!("logger initialized"); - let conn = lib::establish_connection()?; + let mut conn = lib::establish_connection()?; debug!("db connection established"); + let posts = lib::load_posts(&mut conn)?; + + lib::print_posts(&posts); + + trace!("entering the repl"); + repl(&mut conn)?; + trace!("leaving the repl"); + + Ok(()) +} + +fn repl(conn: &mut SqliteConnection) -> anyhow::Result<()> { + let mut buf = String::new(); + + loop { + lib::read_buf_interactive(&mut buf)?; + buf = buf.to_uppercase(); + if buf.starts_with("HELP") { + println!("\ + help - show this menu\n\ + exit - exit the application\n\ + new - create a new post") + } + else if buf.starts_with("EXIT") { + break; + } + else if buf.starts_with("NEW") { + let post = PostDraft::interactive_create()?; + post.post(conn)?; + } + else { + println!("Bad input: try 'help'"); + } + } + Ok(()) } diff --git a/members/diesel-demo/src/models.rs b/members/diesel-demo/src/models.rs new file mode 100644 index 0000000..f0c268a --- /dev/null +++ b/members/diesel-demo/src/models.rs @@ -0,0 +1,61 @@ +use std::io::{self, Read, Write}; + +use diesel::prelude::*; + +use crate::schema::posts; + +#[cfg(not(windows))] +const EOF: &str = "CTRL+D"; + +#[cfg(windows)] +const EOF: &str = "CTRL+Z"; + +#[derive(Queryable, Selectable)] +#[diesel(table_name = crate::schema::posts)] +#[diesel(check_for_backend(diesel::sqlite::Sqlite))] // optional but improves generated compiler + // errors +pub struct Post { + pub id: i32, + pub title: String, + pub body: String, + pub published: bool, +} + +#[derive(Insertable)] +#[diesel(table_name = crate::schema::posts)] +pub struct PostDraft { + pub title: String, + pub body: String, +} + +impl PostDraft { + pub fn new(title: T, body: T) -> Self { + Self { + title: title.to_string(), + body: body.to_string(), + } + } + pub fn post(self, conn: &mut SqliteConnection) -> anyhow::Result { + Ok(diesel::insert_into(posts::table) + .values(&self) + .returning(Post::as_returning()) + .get_result(conn)?) + } + + pub fn interactive_create() -> anyhow::Result { + let mut title = String::new(); + let mut body = String::new(); + let mut stdin = io::stdin(); + + print!("Title: "); + io::stdout().flush()?; + stdin.read_line(&mut title)?; + title = title.trim().to_string(); + + println!("(End with {} when finished) Body:\n", EOF); + stdin.read_to_string(&mut body)?; + body = body.trim().to_string(); + + Ok(Self::new(&title, &body)) + } +} diff --git a/members/diesel-demo/src/schema.rs b/members/diesel-demo/src/schema.rs index 5115db3..af8680b 100644 --- a/members/diesel-demo/src/schema.rs +++ b/members/diesel-demo/src/schema.rs @@ -2,11 +2,9 @@ diesel::table! { posts (id) { - id -> Int4, // what the hell is an Int4???? I guess it must - // be a 4 byte integer (u32?), no way it would be a nibble. - title -> Varchar, - body -> Text, // What is the difference between Text and Varchar? I know Varchar - // from various DB stuff but idk Text + id -> Integer, + title -> Text, + body -> Text, published -> Bool, } }