Moved more code from hotel_service to lib
Some checks failed
Build & test / build (push) Failing after 6s
Some checks failed
Build & test / build (push) Failing after 6s
This commit is contained in:
parent
7e2df67fee
commit
80f4af9087
60
Cargo.lock
generated
60
Cargo.lock
generated
@ -509,6 +509,19 @@ dependencies = [
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "diesel_async_migrations"
|
||||
version = "0.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b99915cbb9455e8fd56f12edc58f92bbdf8161e4363cb2000cf4308aa6358ff4"
|
||||
dependencies = [
|
||||
"diesel",
|
||||
"diesel-async",
|
||||
"diesel_async_migrations_macros",
|
||||
"scoped-futures",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "diesel_async_migrations_macros"
|
||||
version = "0.12.0"
|
||||
@ -1061,6 +1074,7 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||
name = "lib"
|
||||
version = "1.4.3"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"axum",
|
||||
"chrono",
|
||||
"deadpool-diesel",
|
||||
@ -1069,11 +1083,14 @@ dependencies = [
|
||||
"diesel-async",
|
||||
"diesel-crud-derive",
|
||||
"diesel-crud-trait",
|
||||
"diesel_async_migrations 0.15.0",
|
||||
"into-response-derive",
|
||||
"mime",
|
||||
"nom",
|
||||
"read-files",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"testcontainers-modules 0.10.0",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
@ -1954,13 +1971,50 @@ dependencies = [
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "testcontainers"
|
||||
version = "0.22.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2ef8374cea2c164699681ecc39316c3e1d953831a7a5721e36c7736d974e15fa"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"bollard",
|
||||
"bollard-stubs",
|
||||
"bytes",
|
||||
"dirs",
|
||||
"docker_credential",
|
||||
"either",
|
||||
"futures",
|
||||
"log",
|
||||
"memchr",
|
||||
"parse-display",
|
||||
"pin-project-lite",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_with",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"tokio-util",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "testcontainers-modules"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "868e8e818fe37b8ed4c21ac72185206b48e8767b5ad3836d7ec0e5c9386e19a2"
|
||||
dependencies = [
|
||||
"testcontainers",
|
||||
"testcontainers 0.21.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "testcontainers-modules"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "359d9a225791e1b9f60aab01f9ae9471898b9b9904b5db192104a71e96785079"
|
||||
dependencies = [
|
||||
"testcontainers 0.22.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1970,10 +2024,10 @@ dependencies = [
|
||||
"derive_more",
|
||||
"diesel",
|
||||
"diesel-async",
|
||||
"diesel_async_migrations",
|
||||
"diesel_async_migrations 0.14.0",
|
||||
"dotenvy_macro",
|
||||
"lib",
|
||||
"testcontainers-modules",
|
||||
"testcontainers-modules 0.9.0",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
]
|
||||
|
11
Cargo.toml
11
Cargo.toml
@ -26,6 +26,7 @@ tower = { version = "0.5", optional = true }
|
||||
tower-http = { version = "0.5", optional = true, features = ["trace", "cors", "normalize-path"] }
|
||||
mime = { version = "0.3", optional = true }
|
||||
# Async
|
||||
async-trait = { workspace = true }
|
||||
tokio = { workspace = true, optional = true, features = ["fs", "rt-multi-thread"] }
|
||||
tokio-util = { version = "0.7", optional = true, features = ["io"] }
|
||||
# Database
|
||||
@ -33,6 +34,7 @@ diesel = { workspace = true, optional = true, features = ["postgres"] }
|
||||
diesel-async = { workspace = true, optional = true, features = ["postgres", "deadpool"] }
|
||||
diesel-crud-derive = { path = "crates/diesel_crud_derive", optional = true }
|
||||
diesel-crud-trait = { path = "crates/diesel_crud_trait", optional = true }
|
||||
diesel_async_migrations = { version = "0.15", optional = true }
|
||||
deadpool-diesel = { workspace = true, optional = true, features = ["postgres"] }
|
||||
# Error handling
|
||||
thiserror = { workspace = true, optional = true }
|
||||
@ -46,6 +48,9 @@ into-response-derive = { path = "crates/into_response_derive", optional = true }
|
||||
read-files = { path = "crates/read_files", optional = true }
|
||||
# Serialization / Deserialization
|
||||
serde = { version = "1.0", optional = true, features = ["derive"] }
|
||||
serde_json = { version = "1.0", optional = true }
|
||||
# Test
|
||||
testcontainers-modules = { version = "0.10", features = ["postgres"], optional = true }
|
||||
# Time
|
||||
chrono = { version = "0.4", optional = true, features = ["serde"] }
|
||||
# Utils
|
||||
@ -54,6 +59,7 @@ derive_more = { workspace = true, features = ["from", "constructor"] }
|
||||
[workspace.dependencies]
|
||||
# Async
|
||||
tokio = "1.40"
|
||||
async-trait = "0.1"
|
||||
# Database
|
||||
diesel = "2.2"
|
||||
diesel-async = "0.5"
|
||||
@ -70,11 +76,12 @@ derive_more = "1.0"
|
||||
|
||||
[features]
|
||||
axum = ["dep:axum", "dep:tower", "dep:tower-http", "dep:thiserror", "dep:tracing", "dep:tracing-subscriber", "dep:tokio", "dep:mime"]
|
||||
diesel = ["dep:diesel-crud-trait", "dep:diesel", "dep:diesel-async", "dep:deadpool-diesel"]
|
||||
diesel = ["dep:diesel-crud-trait", "dep:diesel", "dep:diesel-async", "dep:deadpool-diesel", "dep:diesel_async_migrations"]
|
||||
io = ["dep:tokio", "dep:tokio-util"]
|
||||
iter = []
|
||||
nom = ["dep:nom"]
|
||||
serde = ["dep:serde"]
|
||||
serde = ["dep:serde", "dep:serde_json"]
|
||||
derive = ["dep:into-response-derive", "dep:diesel-crud-derive"]
|
||||
read-files = ["dep:read-files"]
|
||||
time = ["dep:chrono"]
|
||||
test = ["dep:testcontainers-modules"]
|
||||
|
1
examples/multipart_file/Cargo.lock
generated
1
examples/multipart_file/Cargo.lock
generated
@ -308,6 +308,7 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||
name = "lib"
|
||||
version = "1.4.3"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"axum",
|
||||
"derive_more",
|
||||
"mime",
|
||||
|
@ -152,11 +152,13 @@ impl AppBuilder {
|
||||
let _ = fmt_trace(); // Allowed to fail
|
||||
let listener = self.listener().await?;
|
||||
|
||||
if self.normalize_path.unwrap_or(true) {
|
||||
let app = NormalizePathLayer::trim_trailing_slash().layer(self.build());
|
||||
let should_normalize = self.normalize_path.unwrap_or(true);
|
||||
let app = self.build();
|
||||
|
||||
if should_normalize {
|
||||
let app = NormalizePathLayer::trim_trailing_slash().layer(app);
|
||||
axum::serve(listener, ServiceExt::<Request>::into_make_service(app)).await?;
|
||||
} else {
|
||||
let app = self.build();
|
||||
axum::serve(listener, app.into_make_service()).await?;
|
||||
};
|
||||
Ok(())
|
||||
|
14
src/axum/builder.rs
Normal file
14
src/axum/builder.rs
Normal file
@ -0,0 +1,14 @@
|
||||
use crate::axum::traits::BuildJson;
|
||||
use axum::body::Body;
|
||||
use axum::http::header::CONTENT_TYPE;
|
||||
use axum::http::Request;
|
||||
use mime::APPLICATION_JSON;
|
||||
use serde::Serialize;
|
||||
use serde_json::json;
|
||||
|
||||
impl BuildJson for axum::http::request::Builder {
|
||||
fn json<T: Serialize>(self, body: T) -> Result<Request<Body>, axum::http::Error> {
|
||||
self.header(CONTENT_TYPE, APPLICATION_JSON.as_ref())
|
||||
.body(Body::new(json!(body).to_string()))
|
||||
}
|
||||
}
|
@ -1,8 +1,11 @@
|
||||
pub mod app;
|
||||
#[cfg(feature = "serde")]
|
||||
pub mod builder;
|
||||
pub mod extractor;
|
||||
pub mod load;
|
||||
#[cfg(feature = "serde")]
|
||||
pub mod response;
|
||||
pub mod router;
|
||||
pub mod traits;
|
||||
#[cfg(feature = "serde")]
|
||||
pub mod wrappers;
|
||||
|
@ -1,10 +1,15 @@
|
||||
use {
|
||||
crate::serde::response::BaseResponse,
|
||||
crate::{serde::response::BaseResponse, serde::traits::DeserializeInto},
|
||||
async_trait::async_trait,
|
||||
axum::{
|
||||
body::to_bytes,
|
||||
response::{IntoResponse, Response},
|
||||
Json,
|
||||
},
|
||||
serde::Serialize,
|
||||
serde::{
|
||||
de::{DeserializeOwned, Error},
|
||||
Serialize,
|
||||
},
|
||||
};
|
||||
|
||||
impl<T: Serialize> IntoResponse for BaseResponse<T> {
|
||||
@ -13,6 +18,16 @@ impl<T: Serialize> IntoResponse for BaseResponse<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl DeserializeInto for Response {
|
||||
async fn deserialize_into<T: DeserializeOwned>(self) -> Result<T, serde_json::Error> {
|
||||
let body = to_bytes(self.into_body(), usize::MAX).await.map_err(|e| {
|
||||
serde_json::Error::custom(format!("Failed to read response body: {}", e))
|
||||
})?;
|
||||
serde_json::from_slice(&body)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use axum::http::header::CONTENT_TYPE;
|
||||
|
7
src/axum/traits.rs
Normal file
7
src/axum/traits.rs
Normal file
@ -0,0 +1,7 @@
|
||||
use axum::body::Body;
|
||||
use axum::http::Request;
|
||||
use serde::Serialize;
|
||||
|
||||
pub trait BuildJson {
|
||||
fn json<T: Serialize>(self, body: T) -> Result<Request<Body>, axum::http::Error>;
|
||||
}
|
29
src/diesel/get_connection.rs
Normal file
29
src/diesel/get_connection.rs
Normal file
@ -0,0 +1,29 @@
|
||||
use axum::async_trait;
|
||||
use deadpool_diesel::Status;
|
||||
use derive_more::From;
|
||||
use diesel_async::pooled_connection::deadpool::{Object, PoolError};
|
||||
use diesel_async::AsyncPgConnection;
|
||||
use lib::diesel::pool::PgPool;
|
||||
|
||||
#[async_trait]
|
||||
pub trait GetConnection: Clone + Send + Sync {
|
||||
async fn get(&self) -> Result<Object<AsyncPgConnection>, GetConnectionError>;
|
||||
fn status(&self) -> Status;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl GetConnection for PgPool {
|
||||
async fn get(&self) -> Result<Object<AsyncPgConnection>, GetConnectionError> {
|
||||
self.get().await.map_err(Into::into)
|
||||
}
|
||||
#[inline]
|
||||
fn status(&self) -> Status {
|
||||
self.status()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, From)]
|
||||
pub enum GetConnectionError {
|
||||
PoolError(PoolError),
|
||||
DieselError(diesel::result::Error),
|
||||
}
|
9
src/diesel/migration.rs
Normal file
9
src/diesel/migration.rs
Normal file
@ -0,0 +1,9 @@
|
||||
use diesel_async::AsyncPgConnection;
|
||||
use diesel_async_migrations::EmbeddedMigrations;
|
||||
|
||||
pub async fn run_migrations(
|
||||
migrations: &EmbeddedMigrations,
|
||||
conn: &mut AsyncPgConnection,
|
||||
) -> Result<(), diesel::result::Error> {
|
||||
migrations.run_pending_migrations(conn).await
|
||||
}
|
@ -1,3 +1,5 @@
|
||||
pub mod get_connection;
|
||||
pub mod migration;
|
||||
pub mod pool;
|
||||
|
||||
/// Re-export diesel::result::Error as DieselError
|
||||
|
@ -19,6 +19,8 @@ pub mod io;
|
||||
pub mod nom;
|
||||
#[cfg(feature = "serde")]
|
||||
pub mod serde;
|
||||
#[cfg(feature = "test")]
|
||||
pub mod test;
|
||||
#[cfg(feature = "time")]
|
||||
pub mod time;
|
||||
pub mod traits;
|
||||
|
@ -1 +1,2 @@
|
||||
pub mod response;
|
||||
pub mod traits;
|
||||
|
7
src/serde/traits.rs
Normal file
7
src/serde/traits.rs
Normal file
@ -0,0 +1,7 @@
|
||||
use async_trait::async_trait;
|
||||
use serde::de::DeserializeOwned;
|
||||
|
||||
#[async_trait]
|
||||
pub trait DeserializeInto {
|
||||
async fn deserialize_into<T: DeserializeOwned>(self) -> Result<T, serde_json::Error>;
|
||||
}
|
45
src/test/diesel_pool.rs
Normal file
45
src/test/diesel_pool.rs
Normal file
@ -0,0 +1,45 @@
|
||||
use crate::diesel::get_connection::{GetConnection, GetConnectionError};
|
||||
use crate::diesel::pool::PgPool;
|
||||
use crate::diesel::DieselError;
|
||||
use axum::async_trait;
|
||||
use deadpool_diesel::postgres::BuildError;
|
||||
use deadpool_diesel::Status;
|
||||
use derive_more::From;
|
||||
use diesel_async::pooled_connection::deadpool::Object;
|
||||
use diesel_async::{AsyncConnection, AsyncPgConnection};
|
||||
use lib::diesel::pool::create_pool_from_url_with_size;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct PoolStub(PgPool);
|
||||
|
||||
#[derive(Debug, PartialEq, From)]
|
||||
pub enum Error {
|
||||
Connection(diesel::ConnectionError),
|
||||
Database(DieselError),
|
||||
}
|
||||
|
||||
pub async fn setup_test_transaction(url: impl AsRef<str>) -> Result<AsyncPgConnection, Error> {
|
||||
let mut conn = AsyncPgConnection::establish(url.as_ref()).await?;
|
||||
conn.begin_test_transaction().await?;
|
||||
Ok(conn)
|
||||
}
|
||||
|
||||
pub async fn create_test_pool_url_with_size(
|
||||
url: impl Into<String>,
|
||||
size: usize,
|
||||
) -> Result<PoolStub, BuildError> {
|
||||
let pool = create_pool_from_url_with_size(url, size)?;
|
||||
Ok(PoolStub(pool))
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl GetConnection for PoolStub {
|
||||
async fn get(&self) -> Result<Object<AsyncPgConnection>, GetConnectionError> {
|
||||
let mut conn = self.0.get().await?;
|
||||
conn.begin_test_transaction().await?;
|
||||
Ok(conn)
|
||||
}
|
||||
fn status(&self) -> Status {
|
||||
unimplemented!("PoolStub does not support status")
|
||||
}
|
||||
}
|
3
src/test/mod.rs
Normal file
3
src/test/mod.rs
Normal file
@ -0,0 +1,3 @@
|
||||
#[cfg(feature = "diesel")]
|
||||
pub mod diesel_pool;
|
||||
pub mod test_containers;
|
39
src/test/test_containers.rs
Normal file
39
src/test/test_containers.rs
Normal file
@ -0,0 +1,39 @@
|
||||
use crate::diesel::pool::{create_pool_from_url, PgPool};
|
||||
use deadpool_diesel::postgres::BuildError;
|
||||
use derive_more::{Constructor, From};
|
||||
use diesel_async::pooled_connection::deadpool::PoolError;
|
||||
use lib::diesel::DieselError;
|
||||
use testcontainers_modules::postgres::Postgres;
|
||||
use testcontainers_modules::testcontainers::runners::AsyncRunner;
|
||||
use testcontainers_modules::testcontainers::{ContainerAsync, TestcontainersError};
|
||||
|
||||
/// When the TestContainer is dropped, the container will be removed.
|
||||
/// # Errors
|
||||
/// If destructed and the container field is dropped, the container will be dropped, and using the pool will cause an error.
|
||||
#[derive(Constructor)]
|
||||
pub struct TestContainer {
|
||||
pub container: ContainerAsync<Postgres>,
|
||||
pub pool: PgPool,
|
||||
}
|
||||
|
||||
pub async fn create_test_containers_pool<'a>() -> Result<TestContainer, ContainerError> {
|
||||
let container = create_postgres_container().await?;
|
||||
let connection_string = format!(
|
||||
"postgres://postgres:postgres@127.0.0.1:{}/postgres",
|
||||
container.get_host_port_ipv4(5432).await?
|
||||
);
|
||||
let pool = create_pool_from_url(connection_string)?;
|
||||
Ok(TestContainer::new(container, pool))
|
||||
}
|
||||
|
||||
pub async fn create_postgres_container() -> Result<ContainerAsync<Postgres>, TestcontainersError> {
|
||||
Postgres::default().start().await
|
||||
}
|
||||
|
||||
#[derive(Debug, From)]
|
||||
pub enum ContainerError {
|
||||
TestContainers(TestcontainersError),
|
||||
BuildError(BuildError),
|
||||
PoolError(PoolError),
|
||||
DieselError(DieselError),
|
||||
}
|
@ -23,9 +23,8 @@
|
||||
#[macro_export]
|
||||
macro_rules! map {
|
||||
() => { std::collections::HashMap::new() };
|
||||
($default:ty; $($key:expr),* $(,)?) => {
|
||||
($default:ty; $($key:expr),+ $(,)?) => {
|
||||
{
|
||||
#[allow(unused_mut)]
|
||||
let mut temp_map = std::collections::HashMap::new();
|
||||
$(
|
||||
temp_map.insert($key, <$default>::default());
|
||||
@ -76,8 +75,8 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_map_only_keys_0_keys() {
|
||||
let map: HashMap<usize, usize> = map!(usize;);
|
||||
assert_eq!(map.len(), 0);
|
||||
fn test_map_only_keys_1_key() {
|
||||
let map: HashMap<usize, usize> = map!(usize; 1);
|
||||
assert_eq!(map.len(), 1);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user