From 04f68632b4582229bceda5483a184f4ed8ede450 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Th=C3=A9riault?= Date: Mon, 24 Aug 2020 15:44:55 -0400 Subject: [PATCH] JSON+macros example using overrides --- Cargo.lock | 15 +++ Cargo.toml | 1 + examples/postgres/json/Cargo.toml | 16 +++ examples/postgres/json/README.md | 41 ++++++++ .../json/migrations/20200824190010_json.sql | 5 + examples/postgres/json/src/main.rs | 97 +++++++++++++++++++ 6 files changed, 175 insertions(+) create mode 100644 examples/postgres/json/Cargo.toml create mode 100644 examples/postgres/json/README.md create mode 100644 examples/postgres/json/migrations/20200824190010_json.sql create mode 100644 examples/postgres/json/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index e1027e792..158fa0d47 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1026,6 +1026,21 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "json" +version = "0.1.0" +dependencies = [ + "anyhow", + "async-std", + "dotenv", + "futures", + "paw", + "serde", + "serde_json", + "sqlx", + "structopt", +] + [[package]] name = "kernel32-sys" version = "0.2.2" diff --git a/Cargo.toml b/Cargo.toml index 11729527f..edfdbd53b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,7 @@ members = [ "sqlx-cli", "sqlx-bench", "examples/mysql/todos", + "examples/postgres/json", "examples/postgres/listen", "examples/postgres/todos", "examples/sqlite/todos", diff --git a/examples/postgres/json/Cargo.toml b/examples/postgres/json/Cargo.toml new file mode 100644 index 000000000..07c0e3b96 --- /dev/null +++ b/examples/postgres/json/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "json" +version = "0.1.0" +edition = "2018" +workspace = "../../../" + +[dependencies] +anyhow = "1.0" +async-std = { version = "1.6.0", features = [ "attributes" ] } +dotenv = "0.15.0" +futures = "0.3" +paw = "1.0" +serde = { version = "1", features = ["derive"] } +serde_json = "1" +sqlx = { path = "../../../", features = ["postgres", "json"] } +structopt = { version = "0.3", features = ["paw"] } diff --git a/examples/postgres/json/README.md b/examples/postgres/json/README.md new file mode 100644 index 000000000..0813ad876 --- /dev/null +++ b/examples/postgres/json/README.md @@ -0,0 +1,41 @@ +# JSON Example + +## Setup + +1. Declare the database URL + + ``` + export DATABASE_URL="postgres://postgres:password@localhost/json" + ``` + +2. Create the database. + + ``` + $ sqlx db create + ``` + +3. Run sql migrations + + ``` + $ sqlx migrate run + ``` + +## Usage + +Add a person + +``` +echo '{ "name": "John Doe", "age": 30 }' | cargo run -- add +``` + +or with extra keys + +``` +echo '{ "name": "Jane Doe", "age": 25, "array": ["string", true, 0] }' | cargo run -- add +``` + +List all people + +``` +cargo run +``` diff --git a/examples/postgres/json/migrations/20200824190010_json.sql b/examples/postgres/json/migrations/20200824190010_json.sql new file mode 100644 index 000000000..02458ff72 --- /dev/null +++ b/examples/postgres/json/migrations/20200824190010_json.sql @@ -0,0 +1,5 @@ +CREATE TABLE IF NOT EXISTS people +( + id BIGSERIAL PRIMARY KEY, + person JSONB NOT NULL +); diff --git a/examples/postgres/json/src/main.rs b/examples/postgres/json/src/main.rs new file mode 100644 index 000000000..6a0e31087 --- /dev/null +++ b/examples/postgres/json/src/main.rs @@ -0,0 +1,97 @@ +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, +} + +#[derive(StructOpt)] +enum Command { + Add, +} + +#[derive(Deserialize, Serialize)] +struct Person { + name: String, + age: NonZeroU8, + #[serde(flatten)] + extra: Map, +} + +struct Row { + id: i64, + person: Json, +} + +#[async_std::main] +#[paw::main] +async fn main(args: Args) -> anyhow::Result<()> { + let pool = PgPool::connect(&dotenv::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 { + 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" +FROM people +ORDER BY id + "# + ) + .fetch_all(pool) + .await?; + + for row in rows { + println!( + "{}: {}", + row.id, + &serde_json::to_string_pretty(&row.person)? + ); + } + + Ok(()) +}