mirror of
https://github.com/launchbadge/sqlx.git
synced 2025-12-27 02:58:55 +00:00
Add example with external query files (#1967)
* feat(examples): add files example for postgres * fix(examples): add missing deps
This commit is contained in:
parent
7d8ded9a1a
commit
d6c4eff81a
10
Cargo.lock
generated
10
Cargo.lock
generated
@ -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"
|
||||
|
||||
@ -8,6 +8,7 @@ members = [
|
||||
"sqlx-cli",
|
||||
"sqlx-bench",
|
||||
"examples/mysql/todos",
|
||||
"examples/postgres/files",
|
||||
"examples/postgres/json",
|
||||
"examples/postgres/listen",
|
||||
"examples/postgres/todos",
|
||||
|
||||
12
examples/postgres/files/Cargo.toml
Normal file
12
examples/postgres/files/Cargo.toml
Normal 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"
|
||||
36
examples/postgres/files/README.md
Normal file
36
examples/postgres/files/README.md
Normal 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
|
||||
```
|
||||
14
examples/postgres/files/migrations/20220712221654_files.sql
Normal file
14
examples/postgres/files/migrations/20220712221654_files.sql
Normal 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
|
||||
);
|
||||
11
examples/postgres/files/queries/insert_seed_data.sql
Normal file
11
examples/postgres/files/queries/insert_seed_data.sql
Normal 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));
|
||||
7
examples/postgres/files/queries/list_all_posts.sql
Normal file
7
examples/postgres/files/queries/list_all_posts.sql
Normal 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;
|
||||
48
examples/postgres/files/src/main.rs
Normal file
48
examples/postgres/files/src/main.rs
Normal 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(())
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user