Add example with external query files (#1967)

* feat(examples): add files example for postgres

* fix(examples): add missing deps
This commit is contained in:
Joey McKenzie 2022-07-13 14:45:34 -07:00 committed by GitHub
parent 7d8ded9a1a
commit d6c4eff81a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 139 additions and 0 deletions

10
Cargo.lock generated
View File

@ -879,6 +879,16 @@ dependencies = [
"windows-sys",
]
[[package]]
name = "files"
version = "0.1.0"
dependencies = [
"anyhow",
"async-std",
"dotenv",
"sqlx",
]
[[package]]
name = "filetime"
version = "0.2.17"

View File

@ -8,6 +8,7 @@ members = [
"sqlx-cli",
"sqlx-bench",
"examples/mysql/todos",
"examples/postgres/files",
"examples/postgres/json",
"examples/postgres/listen",
"examples/postgres/todos",

View File

@ -0,0 +1,12 @@
[package]
name = "files"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
anyhow = "1.0"
async-std = { version = "1.8.0", features = [ "attributes" ] }
sqlx = { path = "../../../", features = ["postgres", "offline", "runtime-async-std-native-tls"] }
dotenv = "0.15.0"

View File

@ -0,0 +1,36 @@
# Query files Example
## Description
This example demonstrates storing external files to use for querying data.
Encapsulating your SQL queries can be helpful in several ways, assisting with intellisense,
etc.
## Setup
1. Declare the database URL
```
export DATABASE_URL="postgres://postgres:password@localhost/files"
```
2. Create the database.
```
$ sqlx db create
```
3. Run sql migrations
```
$ sqlx migrate run
```
## Usage
Run the project
```
cargo run files
```

View File

@ -0,0 +1,14 @@
CREATE TABLE IF NOT EXISTS users
(
id BIGSERIAL PRIMARY KEY,
username TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS posts
(
id BIGSERIAL PRIMARY KEY,
title TEXT NOT NULL,
body TEXT NOT NULL,
user_id BIGINT NOT NULL
REFERENCES users (id) ON DELETE CASCADE
);

View File

@ -0,0 +1,11 @@
-- seed some data to work with
WITH inserted_users_cte AS (
INSERT INTO users (username)
VALUES ('user1'),
('user2')
RETURNING id as "user_id"
)
INSERT INTO posts (title, body, user_id)
VALUES ('user1 post1 title', 'user1 post1 body', (SELECT user_id FROM inserted_users_cte FETCH FIRST ROW ONLY)),
('user1 post2 title', 'user1 post2 body', (SELECT user_id FROM inserted_users_cte FETCH FIRST ROW ONLY)),
('user2 post1 title', 'user2 post2 body', (SELECT user_id FROM inserted_users_cte OFFSET 1 LIMIT 1));

View File

@ -0,0 +1,7 @@
SELECT p.id as "post_id",
p.title,
p.body,
u.id as "author_id",
u.username as "author_username"
FROM users u
JOIN posts p on u.id = p.user_id;

View File

@ -0,0 +1,48 @@
use sqlx::{query_file, query_file_as, query_file_unchecked, FromRow, PgPool};
use std::fmt::{Display, Formatter};
#[derive(FromRow)]
struct PostWithAuthorQuery {
pub post_id: i64,
pub title: String,
pub body: String,
pub author_id: i64,
pub author_username: String,
}
impl Display for PostWithAuthorQuery {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(
f,
r#"
post_id: {},
title: {},
body: {},
author_id: {},
author_username: {}
"#,
self.post_id, self.title, self.body, self.author_id, self.author_username
)
}
}
#[async_std::main]
async fn main() -> anyhow::Result<()> {
let pool = PgPool::connect(&dotenv::var("DATABASE_URL")?).await?;
// we can use a tranditional wrapper around the `query!()` macro using files
query_file!("queries/insert_seed_data.sql")
.execute(&pool)
.await?;
// we can also use `query_file_as!()` similarly to `query_as!()` to map our database models
let posts_with_authors = query_file_as!(PostWithAuthorQuery, "queries/list_all_posts.sql")
.fetch_all(&pool)
.await?;
for post_with_author in posts_with_authors {
println!("{}", post_with_author);
}
Ok(())
}