mirror of
https://github.com/LukeMathWalker/zero-to-production.git
synced 2024-12-18 05:56:35 +00:00
Use TryInto.
This commit is contained in:
parent
f6d62fb7a1
commit
9dd9aaffd6
6 changed files with 89 additions and 12 deletions
45
Cargo.lock
generated
45
Cargo.lock
generated
|
@ -701,6 +701,25 @@ dependencies = [
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "env_logger"
|
||||||
|
version = "0.7.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36"
|
||||||
|
dependencies = [
|
||||||
|
"log",
|
||||||
|
"regex",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fake"
|
||||||
|
version = "2.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6479fa2c7e83ddf8be7d435421e093b072ca891b99a49bc84eba098f4044f818"
|
||||||
|
dependencies = [
|
||||||
|
"rand",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "flate2"
|
name = "flate2"
|
||||||
version = "1.0.19"
|
version = "1.0.19"
|
||||||
|
@ -1609,6 +1628,29 @@ version = "1.2.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
|
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quickcheck"
|
||||||
|
version = "0.9.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a44883e74aa97ad63db83c4bf8ca490f02b2fc02f92575e720c8551e843c945f"
|
||||||
|
dependencies = [
|
||||||
|
"env_logger",
|
||||||
|
"log",
|
||||||
|
"rand",
|
||||||
|
"rand_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quickcheck_macros"
|
||||||
|
version = "0.9.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "608c156fd8e97febc07dc9c2e2c80bf74cfc6ef26893eae3daf8bc2bc94a4b7f"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quote"
|
name = "quote"
|
||||||
version = "1.0.7"
|
version = "1.0.7"
|
||||||
|
@ -2921,7 +2963,10 @@ dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"claim",
|
"claim",
|
||||||
"config",
|
"config",
|
||||||
|
"fake",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
|
"quickcheck",
|
||||||
|
"quickcheck_macros",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"serde",
|
"serde",
|
||||||
"serde-aux",
|
"serde-aux",
|
||||||
|
|
|
@ -30,8 +30,11 @@ tracing-actix-web = "0.2.0"
|
||||||
serde-aux = "1.0.1"
|
serde-aux = "1.0.1"
|
||||||
unicode-segmentation = "1.7.1"
|
unicode-segmentation = "1.7.1"
|
||||||
validator = "0.12.0"
|
validator = "0.12.0"
|
||||||
|
quickcheck_macros = "0.9.1"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
reqwest = { version = "0.10.7", features = ["json"] }
|
reqwest = { version = "0.10.7", features = ["json"] }
|
||||||
lazy_static = "1.4.0"
|
lazy_static = "1.4.0"
|
||||||
claim = "0.4.0"
|
claim = "0.4.0"
|
||||||
|
quickcheck = "0.9.2"
|
||||||
|
fake = "2.3.0"
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
mod subscriber_name;
|
|
||||||
mod subscriber_email;
|
|
||||||
mod new_subscriber;
|
mod new_subscriber;
|
||||||
|
mod subscriber_email;
|
||||||
|
mod subscriber_name;
|
||||||
|
|
||||||
pub use subscriber_name::SubscriberName;
|
|
||||||
pub use new_subscriber::NewSubscriber;
|
pub use new_subscriber::NewSubscriber;
|
||||||
|
pub use subscriber_email::SubscriberEmail;
|
||||||
|
pub use subscriber_name::SubscriberName;
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
use crate::domain::subscriber_name::SubscriberName;
|
use crate::domain::subscriber_name::SubscriberName;
|
||||||
|
use crate::domain::subscriber_email::SubscriberEmail;
|
||||||
|
|
||||||
pub struct NewSubscriber {
|
pub struct NewSubscriber {
|
||||||
pub email: String,
|
// We are not using `String` anymore!
|
||||||
|
pub email: SubscriberEmail,
|
||||||
pub name: SubscriberName,
|
pub name: SubscriberName,
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,8 @@ impl AsRef<str> for SubscriberEmail {
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::SubscriberEmail;
|
use super::SubscriberEmail;
|
||||||
use claim::assert_err;
|
use claim::assert_err;
|
||||||
|
use fake::Fake;
|
||||||
|
use fake::faker::internet::en::SafeEmail;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn empty_string_is_rejected() {
|
fn empty_string_is_rejected() {
|
||||||
|
@ -41,4 +43,19 @@ mod tests {
|
||||||
let email = "@domain.com".to_string();
|
let email = "@domain.com".to_string();
|
||||||
assert_err!(SubscriberEmail::parse(email));
|
assert_err!(SubscriberEmail::parse(email));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
struct ValidEmailFixture(pub String);
|
||||||
|
|
||||||
|
impl quickcheck::Arbitrary for ValidEmailFixture {
|
||||||
|
fn arbitrary<G: quickcheck::Gen>(g: &mut G) -> Self {
|
||||||
|
let email = SafeEmail().fake_with_rng(g);
|
||||||
|
Self(email)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[quickcheck_macros::quickcheck]
|
||||||
|
fn valid_emails_are_parsed_successfully(valid_email: ValidEmailFixture) -> bool {
|
||||||
|
SubscriberEmail::parse(valid_email.0).is_ok()
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,7 +1,8 @@
|
||||||
use crate::domain::{NewSubscriber, SubscriberName};
|
use crate::domain::{NewSubscriber, SubscriberEmail, SubscriberName};
|
||||||
use actix_web::{web, HttpResponse};
|
use actix_web::{web, HttpResponse};
|
||||||
use chrono::Utc;
|
use chrono::Utc;
|
||||||
use sqlx::PgPool;
|
use sqlx::PgPool;
|
||||||
|
use std::convert::TryInto;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
#[derive(serde::Deserialize)]
|
#[derive(serde::Deserialize)]
|
||||||
|
@ -10,6 +11,16 @@ pub struct FormData {
|
||||||
name: String,
|
name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TryInto<NewSubscriber> for FormData {
|
||||||
|
type Error = String;
|
||||||
|
|
||||||
|
fn try_into(self) -> Result<NewSubscriber, Self::Error> {
|
||||||
|
let name = SubscriberName::parse(self.name)?;
|
||||||
|
let email = SubscriberEmail::parse(self.email)?;
|
||||||
|
Ok(NewSubscriber { email, name })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[tracing::instrument(
|
#[tracing::instrument(
|
||||||
name = "Adding a new subscriber",
|
name = "Adding a new subscriber",
|
||||||
skip(form, pool),
|
skip(form, pool),
|
||||||
|
@ -22,12 +33,10 @@ pub async fn subscribe(
|
||||||
form: web::Form<FormData>,
|
form: web::Form<FormData>,
|
||||||
pool: web::Data<PgPool>,
|
pool: web::Data<PgPool>,
|
||||||
) -> Result<HttpResponse, HttpResponse> {
|
) -> Result<HttpResponse, HttpResponse> {
|
||||||
let name =
|
let new_subscriber = form
|
||||||
SubscriberName::parse(form.0.name).map_err(|_| HttpResponse::BadRequest().finish())?;
|
.0
|
||||||
let new_subscriber = NewSubscriber {
|
.try_into()
|
||||||
email: form.0.email,
|
.map_err(|_| HttpResponse::BadRequest().finish())?;
|
||||||
name,
|
|
||||||
};
|
|
||||||
insert_subscriber(&pool, &new_subscriber)
|
insert_subscriber(&pool, &new_subscriber)
|
||||||
.await
|
.await
|
||||||
.map_err(|_| HttpResponse::InternalServerError().finish())?;
|
.map_err(|_| HttpResponse::InternalServerError().finish())?;
|
||||||
|
@ -48,7 +57,7 @@ pub async fn insert_subscriber(
|
||||||
VALUES ($1, $2, $3, $4)
|
VALUES ($1, $2, $3, $4)
|
||||||
"#,
|
"#,
|
||||||
Uuid::new_v4(),
|
Uuid::new_v4(),
|
||||||
new_subscriber.email,
|
new_subscriber.email.as_ref(),
|
||||||
new_subscriber.name.as_ref(),
|
new_subscriber.name.as_ref(),
|
||||||
Utc::now()
|
Utc::now()
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in a new issue