Austin Bonander a2eceec33b
chore: replace dotenv with dotenvy (#2003)
* chore: replace `dotenv` with `dotenvy`

The former appears to be unmaintained and the latter is a drop-in replacement.

* chore: fix all warnings
2022-07-28 14:33:44 -07:00

98 lines
1.9 KiB
Rust

use serde::{Deserialize, Serialize};
use serde_json::{Map, Value};
use sqlx::postgres::PgPool;
use sqlx::types::Json;
use std::io::{self, Read};
use std::num::NonZeroU8;
use structopt::StructOpt;
#[derive(StructOpt)]
struct Args {
#[structopt(subcommand)]
cmd: Option<Command>,
}
#[derive(StructOpt)]
enum Command {
Add,
}
#[derive(Deserialize, Serialize)]
struct Person {
name: String,
age: NonZeroU8,
#[serde(flatten)]
extra: Map<String, Value>,
}
struct Row {
id: i64,
person: Json<Person>,
}
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let args = Args::from_args_safe()?;
let pool = PgPool::connect(&dotenvy::var("DATABASE_URL")?).await?;
match args.cmd {
Some(Command::Add) => {
let mut json = String::new();
io::stdin().read_to_string(&mut json)?;
let person: Person = serde_json::from_str(&json)?;
println!(
"Adding new person: {}",
&serde_json::to_string_pretty(&person)?
);
let person_id = add_person(&pool, person).await?;
println!("Added new person with ID {}", person_id);
}
None => {
println!("Printing all people");
list_people(&pool).await?;
}
}
Ok(())
}
async fn add_person(pool: &PgPool, person: Person) -> anyhow::Result<i64> {
let rec = sqlx::query!(
r#"
INSERT INTO people ( person )
VALUES ( $1 )
RETURNING id
"#,
Json(person) as _
)
.fetch_one(pool)
.await?;
Ok(rec.id)
}
async fn list_people(pool: &PgPool) -> anyhow::Result<()> {
let rows = sqlx::query_as!(
Row,
r#"
SELECT id, person as "person: Json<Person>"
FROM people
ORDER BY id
"#
)
.fetch_all(pool)
.await?;
for row in rows {
println!(
"{}: {}",
row.id,
&serde_json::to_string_pretty(&row.person)?
);
}
Ok(())
}