Updated routes to use filters/error handling

This commit is contained in:
Benjamin Sherriff
2023-10-04 10:55:34 -04:00
parent 2b7ec386a0
commit 23d42953f0
7 changed files with 304 additions and 232 deletions

View File

@@ -1,5 +1,4 @@
use std::str::FromStr; // use std::str::FromStr;
use serde::{Serialize, Deserialize}; use serde::{Serialize, Deserialize};
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
@@ -18,30 +17,30 @@ pub enum AbilityType {
Charisma Charisma
} }
impl AbilityType { // impl AbilityType {
pub fn to_string(&self) -> String { // pub fn to_string(&self) -> String {
match self { // match self {
AbilityType::Strength => "Strength".to_string(), // AbilityType::Strength => "Strength".to_string(),
AbilityType::Dexterity => "Dexterity".to_string(), // AbilityType::Dexterity => "Dexterity".to_string(),
AbilityType::Constitution => "Constitution".to_string(), // AbilityType::Constitution => "Constitution".to_string(),
AbilityType::Intelligence => "Intelligence".to_string(), // AbilityType::Intelligence => "Intelligence".to_string(),
AbilityType::Wisdom => "Wisdom".to_string(), // AbilityType::Wisdom => "Wisdom".to_string(),
AbilityType::Charisma => "Charisma".to_string() // AbilityType::Charisma => "Charisma".to_string()
} // }
} // }
} // }
impl FromStr for AbilityType { // impl FromStr for AbilityType {
type Err = (); // type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> { // fn from_str(s: &str) -> Result<Self, Self::Err> {
match s { // match s {
"Strength" => Ok(AbilityType::Strength), // "Strength" => Ok(AbilityType::Strength),
"Dexterity" => Ok(AbilityType::Dexterity), // "Dexterity" => Ok(AbilityType::Dexterity),
"Constitution" => Ok(AbilityType::Constitution), // "Constitution" => Ok(AbilityType::Constitution),
"Intelligence" => Ok(AbilityType::Intelligence), // "Intelligence" => Ok(AbilityType::Intelligence),
"Wisdom" => Ok(AbilityType::Wisdom), // "Wisdom" => Ok(AbilityType::Wisdom),
"Charisma" => Ok(AbilityType::Charisma), // "Charisma" => Ok(AbilityType::Charisma),
_ => Err(()) // _ => Err(())
} // }
} // }
} // }

View File

@@ -1,5 +1,4 @@
use std::str::FromStr; // use std::str::FromStr;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@@ -37,48 +36,48 @@ pub enum ConditionType {
Unconscious Unconscious
} }
impl ConditionType { // impl ConditionType {
pub fn to_string(&self) -> String { // pub fn to_string(&self) -> String {
match self { // match self {
ConditionType::Blinded => "Blinded".to_string(), // ConditionType::Blinded => "Blinded".to_string(),
ConditionType::Charmed => "Charmed".to_string(), // ConditionType::Charmed => "Charmed".to_string(),
ConditionType::Deafened => "Deafened".to_string(), // ConditionType::Deafened => "Deafened".to_string(),
ConditionType::Exhaustion => "Exhaustion".to_string(), // ConditionType::Exhaustion => "Exhaustion".to_string(),
ConditionType::Frightened => "Frightened".to_string(), // ConditionType::Frightened => "Frightened".to_string(),
ConditionType::Grappled => "Grappled".to_string(), // ConditionType::Grappled => "Grappled".to_string(),
ConditionType::Incapacitated => "Incapacitated".to_string(), // ConditionType::Incapacitated => "Incapacitated".to_string(),
ConditionType::Invisible => "Invisible".to_string(), // ConditionType::Invisible => "Invisible".to_string(),
ConditionType::Paralyzed => "Paralyzed".to_string(), // ConditionType::Paralyzed => "Paralyzed".to_string(),
ConditionType::Petrified => "Petrified".to_string(), // ConditionType::Petrified => "Petrified".to_string(),
ConditionType::Poisoned => "Poisoned".to_string(), // ConditionType::Poisoned => "Poisoned".to_string(),
ConditionType::Prone => "Prone".to_string(), // ConditionType::Prone => "Prone".to_string(),
ConditionType::Restrained => "Restrained".to_string(), // ConditionType::Restrained => "Restrained".to_string(),
ConditionType::Stunned => "Stunned".to_string(), // ConditionType::Stunned => "Stunned".to_string(),
ConditionType::Unconscious => "Unconscious".to_string() // ConditionType::Unconscious => "Unconscious".to_string()
} // }
} // }
} // }
impl FromStr for ConditionType { // impl FromStr for ConditionType {
type Err = (); // type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> { // fn from_str(s: &str) -> Result<Self, Self::Err> {
match s { // match s {
"Blinded" => Ok(ConditionType::Blinded), // "Blinded" => Ok(ConditionType::Blinded),
"Charmed" => Ok(ConditionType::Charmed), // "Charmed" => Ok(ConditionType::Charmed),
"Deafened" => Ok(ConditionType::Deafened), // "Deafened" => Ok(ConditionType::Deafened),
"Exhaustion" => Ok(ConditionType::Exhaustion), // "Exhaustion" => Ok(ConditionType::Exhaustion),
"Frightened" => Ok(ConditionType::Frightened), // "Frightened" => Ok(ConditionType::Frightened),
"Grappled" => Ok(ConditionType::Grappled), // "Grappled" => Ok(ConditionType::Grappled),
"Incapacitated" => Ok(ConditionType::Incapacitated), // "Incapacitated" => Ok(ConditionType::Incapacitated),
"Invisible" => Ok(ConditionType::Invisible), // "Invisible" => Ok(ConditionType::Invisible),
"Paralyzed" => Ok(ConditionType::Paralyzed), // "Paralyzed" => Ok(ConditionType::Paralyzed),
"Petrified" => Ok(ConditionType::Petrified), // "Petrified" => Ok(ConditionType::Petrified),
"Poisoned" => Ok(ConditionType::Poisoned), // "Poisoned" => Ok(ConditionType::Poisoned),
"Prone" => Ok(ConditionType::Prone), // "Prone" => Ok(ConditionType::Prone),
"Restrained" => Ok(ConditionType::Restrained), // "Restrained" => Ok(ConditionType::Restrained),
"Stunned" => Ok(ConditionType::Stunned), // "Stunned" => Ok(ConditionType::Stunned),
"Unconscious" => Ok(ConditionType::Unconscious), // "Unconscious" => Ok(ConditionType::Unconscious),
_ => Err(()) // _ => Err(())
} // }
} // }
} // }

View File

@@ -32,7 +32,7 @@ pub fn load_data() {
Err(err) => log::error!("Failed to read from {}: {}", file, err) Err(err) => log::error!("Failed to read from {}: {}", file, err)
}; };
} }
let count = QuerySpell::get_count().unwrap(); let count = QuerySpell::get_count(&QueryFilters::default()).unwrap();
if count >= spells.len() as i64 { if count >= spells.len() as i64 {
log::warn!("Spell data is already loaded"); log::warn!("Spell data is already loaded");
return; return;

View File

@@ -13,13 +13,48 @@ pub struct QuerySpell {
pub data: serde_json::Value, pub data: serde_json::Value,
} }
#[derive(Debug)]
pub struct QueryFilters {
pub by_name: Option<String>,
pub by_schools: Option<Vec<SchoolType>>,
pub by_levels: Option<Vec<i32>>,
pub by_ritual: Option<bool>,
pub by_concentration: Option<bool>,
pub by_classes: Option<Vec<String>>,
pub by_damage_inflict: Option<Vec<SpellDamageType>>,
pub by_damage_resist: Option<Vec<SpellDamageType>>,
pub by_conditions: Option<Vec<ConditionType>>,
pub by_saving_throw: Option<Vec<AbilityType>>,
pub by_attack_type: Option<SpellAttackType>,
}
impl Default for QueryFilters {
fn default() -> Self {
Self {
by_name: None,
by_schools: None,
by_levels: None,
by_ritual: None,
by_concentration: None,
by_classes: None,
by_damage_inflict: None,
by_damage_resist: None,
by_conditions: None,
by_saving_throw: None,
by_attack_type: None,
}
}
}
impl QuerySpell { impl QuerySpell {
pub fn get_all(limit: i32, page: i32) -> Result<Vec<Self>, ServiceError> { pub fn get_all(filters: &QueryFilters, limit: i32, page: i32) -> Result<Vec<Self>, ServiceError> {
let mut conn = crate::db::connection()?; let mut conn = crate::db::connection()?;
let mut query = spells::table let mut query = spells::table.limit(limit as i64).into_boxed();
.limit(limit as i64)
.into_boxed();
query = query.filter(spells::id.gt(std::cmp::max(0, page - 1) * limit)); query = query.filter(spells::id.gt(std::cmp::max(0, page - 1) * limit));
if let Some(name) = filters.by_name.to_owned() {
query = query.filter(spells::name.ilike(format!("%{}%", name)));
}
let spells = query.load::<QuerySpell>(&mut conn)?; let spells = query.load::<QuerySpell>(&mut conn)?;
Ok(spells) Ok(spells)
} }
@@ -32,9 +67,14 @@ impl QuerySpell {
Ok(spell) Ok(spell)
} }
pub fn get_count() -> Result<i64, ServiceError> { pub fn get_count(filters: &QueryFilters) -> Result<i64, ServiceError> {
let mut conn = crate::db::connection()?; let mut conn = crate::db::connection()?;
let count = spells::table.count().get_result(&mut conn)?; let mut query = spells::table.count().into_boxed();
if let Some(name) = filters.by_name.to_owned() {
query = query.filter(spells::name.ilike(format!("%{}%", name)));
}
let count = query.get_result(&mut conn)?;
Ok(count) Ok(count)
} }

View File

@@ -1,28 +1,41 @@
use actix_web::{get, post, put, delete, web, HttpResponse, HttpRequest, ResponseError}; use actix_web::{get, post, put, delete, web, HttpResponse, HttpRequest, ResponseError};
use serde::{Serialize, Deserialize}; use serde::{Serialize, Deserialize};
use crate::db::{spells::QuerySpell, GetResponse, Metadata}; use crate::{db::{spells::{QuerySpell, QueryFilters}, GetResponse, Metadata}, error_handler::ServiceError};
use super::{Spell, InsertSpell}; use super::{Spell, InsertSpell};
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
struct GetAllParams { struct GetAllParams {
name: Option<String>,
limit: Option<i32>, limit: Option<i32>,
page: Option<i32>, page: Option<i32>,
} }
#[get("/spells")] #[get("/spells")]
async fn get_all(req: HttpRequest) -> HttpResponse { async fn get_all(req: HttpRequest) -> HttpResponse {
let params = web::Query::<GetAllParams>::from_query(req.query_string()).unwrap(); let params = match web::Query::<GetAllParams>::from_query(req.query_string()) {
let limit = params.limit.unwrap_or(20); Ok(params) => params,
let page = params.page.unwrap_or(1); Err(err) => return ResponseError::error_response(&ServiceError {
match web::block(move || QuerySpell::get_all(limit, page)).await.unwrap() { status: 422,
message: err.to_string()
})
};
let mut filters = QueryFilters::default();
filters.by_name = params.name.clone();
// Limit must be between 1 and 100
let limit = std::cmp::min(std::cmp::max(params.limit.unwrap_or(20), 1), 100);
let total_count = QuerySpell::get_count(&filters).unwrap();
let max_page = std::cmp::max(1, (total_count as f64 / limit as f64).ceil() as i32);
// Page must be between 1 and max_page
let page = std::cmp::min(std::cmp::max(params.page.unwrap_or(1), 1), max_page);
match web::block(move || QuerySpell::get_all(&filters, limit, page)).await.unwrap() {
Ok(spells) => { Ok(spells) => {
let mut response: Vec<Spell> = Vec::new(); let mut response: Vec<Spell> = Vec::new();
for spell in spells { for spell in spells {
response.push(Spell::from(spell)); response.push(Spell::from(spell));
} }
let total_count = QuerySpell::get_count().unwrap();
HttpResponse::Ok().json(GetResponse { HttpResponse::Ok().json(GetResponse {
data: response, data: response,
metadata: Some(Metadata { metadata: Some(Metadata {
@@ -37,8 +50,15 @@ async fn get_all(req: HttpRequest) -> HttpResponse {
} }
#[get("/spells/{id}")] #[get("/spells/{id}")]
async fn get_by_id(id: web::Path<i32>) -> HttpResponse { async fn get_by_id(id: web::Path<String>) -> HttpResponse {
match web::block(move || QuerySpell::get_by_id(id.into_inner())).await.unwrap() { let id = match id.parse::<i32>() {
Ok(id) => id,
Err(err) => return ResponseError::error_response(&ServiceError {
status: 422,
message: err.to_string()
})
};
match web::block(move || QuerySpell::get_by_id(id)).await.unwrap() {
Ok(spell) => HttpResponse::Ok().json(GetResponse { Ok(spell) => HttpResponse::Ok().json(GetResponse {
data: Spell::from(spell), data: Spell::from(spell),
metadata: None metadata: None
@@ -56,16 +76,30 @@ async fn create(spell: web::Json<Spell>) -> HttpResponse {
} }
#[put("/spells/{id}")] #[put("/spells/{id}")]
async fn update(id: web::Path<i32>, spell: web::Json<Spell>) -> HttpResponse { async fn update(id: web::Path<String>, spell: web::Json<Spell>) -> HttpResponse {
match web::block(move || InsertSpell::update(id.into_inner(), spell.into_inner().into())).await.unwrap() { let id = match id.parse::<i32>() {
Ok(id) => id,
Err(err) => return ResponseError::error_response(&ServiceError {
status: 422,
message: err.to_string()
})
};
match web::block(move || InsertSpell::update(id, spell.into_inner().into())).await.unwrap() {
Ok(spell) => HttpResponse::Ok().json(Spell::from(spell)), Ok(spell) => HttpResponse::Ok().json(Spell::from(spell)),
Err(err) => ResponseError::error_response(&err) Err(err) => ResponseError::error_response(&err)
} }
} }
#[delete("/spells/{id}")] #[delete("/spells/{id}")]
async fn delete(id: web::Path<i32>) -> HttpResponse { async fn delete(id: web::Path<String>) -> HttpResponse {
match web::block(move || QuerySpell::delete(id.into_inner())).await.unwrap() { let id = match id.parse::<i32>() {
Ok(id) => id,
Err(err) => return ResponseError::error_response(&ServiceError {
status: 422,
message: err.to_string()
})
};
match web::block(move || QuerySpell::delete(id)).await.unwrap() {
Ok(spell) => HttpResponse::Ok().json(Spell::from(spell)), Ok(spell) => HttpResponse::Ok().json(Spell::from(spell)),
Err(err) => ResponseError::error_response(&err) Err(err) => ResponseError::error_response(&err)
} }

View File

@@ -1,4 +1,4 @@
use std::str::FromStr; // use std::str::FromStr;
use serde::{Deserialize, Serialize, ser::SerializeMap}; use serde::{Deserialize, Serialize, ser::SerializeMap};
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
@@ -21,38 +21,38 @@ pub enum SchoolType {
Transmutation Transmutation
} }
impl SchoolType { // impl SchoolType {
pub fn to_string(&self) -> String { // pub fn to_string(&self) -> String {
match self { // match self {
SchoolType::Abjuration => "abjuration".to_string(), // SchoolType::Abjuration => "abjuration".to_string(),
SchoolType::Conjuration => "conjuration".to_string(), // SchoolType::Conjuration => "conjuration".to_string(),
SchoolType::Divination => "divination".to_string(), // SchoolType::Divination => "divination".to_string(),
SchoolType::Enchantment => "enchantment".to_string(), // SchoolType::Enchantment => "enchantment".to_string(),
SchoolType::Evocation => "evocation".to_string(), // SchoolType::Evocation => "evocation".to_string(),
SchoolType::Illusion => "illusion".to_string(), // SchoolType::Illusion => "illusion".to_string(),
SchoolType::Necromancy => "necromancy".to_string(), // SchoolType::Necromancy => "necromancy".to_string(),
SchoolType::Transmutation => "transmutation".to_string() // SchoolType::Transmutation => "transmutation".to_string()
} // }
} // }
} // }
impl FromStr for SchoolType { // impl FromStr for SchoolType {
type Err = (); // type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> { // fn from_str(s: &str) -> Result<Self, Self::Err> {
match s { // match s {
"abjuration" => Ok(SchoolType::Abjuration), // "abjuration" => Ok(SchoolType::Abjuration),
"conjuration" => Ok(SchoolType::Conjuration), // "conjuration" => Ok(SchoolType::Conjuration),
"divination" => Ok(SchoolType::Divination), // "divination" => Ok(SchoolType::Divination),
"enchantment" => Ok(SchoolType::Enchantment), // "enchantment" => Ok(SchoolType::Enchantment),
"evocation" => Ok(SchoolType::Evocation), // "evocation" => Ok(SchoolType::Evocation),
"illusion" => Ok(SchoolType::Illusion), // "illusion" => Ok(SchoolType::Illusion),
"necromancy" => Ok(SchoolType::Necromancy), // "necromancy" => Ok(SchoolType::Necromancy),
"transmutation" => Ok(SchoolType::Transmutation), // "transmutation" => Ok(SchoolType::Transmutation),
_ => Err(()) // _ => Err(())
} // }
} // }
} // }
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct CastingTime { pub struct CastingTime {
@@ -75,32 +75,32 @@ pub enum CastingType {
Hours Hours
} }
impl CastingType { // impl CastingType {
pub fn to_string(&self) -> String { // pub fn to_string(&self) -> String {
match self { // match self {
CastingType::Action => "action".to_string(), // CastingType::Action => "action".to_string(),
CastingType::BonusAction => "bonus".to_string(), // CastingType::BonusAction => "bonus".to_string(),
CastingType::Reaction => "reaction".to_string(), // CastingType::Reaction => "reaction".to_string(),
CastingType::Minutes => "minutes".to_string(), // CastingType::Minutes => "minutes".to_string(),
CastingType::Hours => "hours".to_string() // CastingType::Hours => "hours".to_string()
} // }
} // }
} // }
impl FromStr for CastingType { // impl FromStr for CastingType {
type Err = (); // type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> { // fn from_str(s: &str) -> Result<Self, Self::Err> {
match s { // match s {
"action" => Ok(CastingType::Action), // "action" => Ok(CastingType::Action),
"bonus" => Ok(CastingType::BonusAction), // "bonus" => Ok(CastingType::BonusAction),
"reaction" => Ok(CastingType::Reaction), // "reaction" => Ok(CastingType::Reaction),
"minutes" => Ok(CastingType::Minutes), // "minutes" => Ok(CastingType::Minutes),
"hours" => Ok(CastingType::Hours), // "hours" => Ok(CastingType::Hours),
_ => Err(()) // _ => Err(())
} // }
} // }
} // }
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub enum SpellAttackType { pub enum SpellAttackType {
@@ -110,26 +110,26 @@ pub enum SpellAttackType {
Ranged, Ranged,
} }
impl SpellAttackType { // impl SpellAttackType {
pub fn to_string(&self) -> String { // pub fn to_string(&self) -> String {
match self { // match self {
SpellAttackType::Melee => "melee".to_string(), // SpellAttackType::Melee => "melee".to_string(),
SpellAttackType::Ranged => "ranged".to_string() // SpellAttackType::Ranged => "ranged".to_string()
} // }
} // }
} // }
impl FromStr for SpellAttackType { // impl FromStr for SpellAttackType {
type Err = (); // type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> { // fn from_str(s: &str) -> Result<Self, Self::Err> {
match s { // match s {
"melee" => Ok(SpellAttackType::Melee), // "melee" => Ok(SpellAttackType::Melee),
"ranged" => Ok(SpellAttackType::Ranged), // "ranged" => Ok(SpellAttackType::Ranged),
_ => Err(()) // _ => Err(())
} // }
} // }
} // }
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub enum SpellDamageType { pub enum SpellDamageType {
@@ -161,48 +161,48 @@ pub enum SpellDamageType {
Thunder Thunder
} }
impl SpellDamageType { // impl SpellDamageType {
pub fn to_string(&self) -> String { // pub fn to_string(&self) -> String {
match self { // match self {
SpellDamageType::Acid => "acid".to_string(), // SpellDamageType::Acid => "acid".to_string(),
SpellDamageType::Bludgeoning => "bludgeoning".to_string(), // SpellDamageType::Bludgeoning => "bludgeoning".to_string(),
SpellDamageType::Cold => "cold".to_string(), // SpellDamageType::Cold => "cold".to_string(),
SpellDamageType::Fire => "fire".to_string(), // SpellDamageType::Fire => "fire".to_string(),
SpellDamageType::Force => "force".to_string(), // SpellDamageType::Force => "force".to_string(),
SpellDamageType::Lightning => "lightning".to_string(), // SpellDamageType::Lightning => "lightning".to_string(),
SpellDamageType::Necrotic => "necrotic".to_string(), // SpellDamageType::Necrotic => "necrotic".to_string(),
SpellDamageType::Piercing => "piercing".to_string(), // SpellDamageType::Piercing => "piercing".to_string(),
SpellDamageType::Poison => "poison".to_string(), // SpellDamageType::Poison => "poison".to_string(),
SpellDamageType::Psychic => "psychic".to_string(), // SpellDamageType::Psychic => "psychic".to_string(),
SpellDamageType::Radiant => "radiant".to_string(), // SpellDamageType::Radiant => "radiant".to_string(),
SpellDamageType::Slashing => "slashing".to_string(), // SpellDamageType::Slashing => "slashing".to_string(),
SpellDamageType::Thunder => "thunder".to_string() // SpellDamageType::Thunder => "thunder".to_string()
} // }
} // }
} // }
impl FromStr for SpellDamageType { // impl FromStr for SpellDamageType {
type Err = (); // type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> { // fn from_str(s: &str) -> Result<Self, Self::Err> {
match s { // match s {
"acid" => Ok(SpellDamageType::Acid), // "acid" => Ok(SpellDamageType::Acid),
"bludgeoning" => Ok(SpellDamageType::Bludgeoning), // "bludgeoning" => Ok(SpellDamageType::Bludgeoning),
"cold" => Ok(SpellDamageType::Cold), // "cold" => Ok(SpellDamageType::Cold),
"fire" => Ok(SpellDamageType::Fire), // "fire" => Ok(SpellDamageType::Fire),
"force" => Ok(SpellDamageType::Force), // "force" => Ok(SpellDamageType::Force),
"lightning" => Ok(SpellDamageType::Lightning), // "lightning" => Ok(SpellDamageType::Lightning),
"necrotic" => Ok(SpellDamageType::Necrotic), // "necrotic" => Ok(SpellDamageType::Necrotic),
"piercing" => Ok(SpellDamageType::Piercing), // "piercing" => Ok(SpellDamageType::Piercing),
"poison" => Ok(SpellDamageType::Poison), // "poison" => Ok(SpellDamageType::Poison),
"psychic" => Ok(SpellDamageType::Psychic), // "psychic" => Ok(SpellDamageType::Psychic),
"radiant" => Ok(SpellDamageType::Radiant), // "radiant" => Ok(SpellDamageType::Radiant),
"slashing" => Ok(SpellDamageType::Slashing), // "slashing" => Ok(SpellDamageType::Slashing),
"thunder" => Ok(SpellDamageType::Thunder), // "thunder" => Ok(SpellDamageType::Thunder),
_ => Err(()) // _ => Err(())
} // }
} // }
} // }
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct Range { pub struct Range {
@@ -238,32 +238,32 @@ pub enum AreaType {
Sphere Sphere
} }
impl AreaType { // impl AreaType {
pub fn to_string(&self) -> String { // pub fn to_string(&self) -> String {
match self { // match self {
AreaType::Cone => "cone".to_string(), // AreaType::Cone => "cone".to_string(),
AreaType::Cube => "cube".to_string(), // AreaType::Cube => "cube".to_string(),
AreaType::Cylinder => "cylinder".to_string(), // AreaType::Cylinder => "cylinder".to_string(),
AreaType::Line => "line".to_string(), // AreaType::Line => "line".to_string(),
AreaType::Sphere => "sphere".to_string() // AreaType::Sphere => "sphere".to_string()
} // }
} // }
} // }
impl FromStr for AreaType { // impl FromStr for AreaType {
type Err = (); // type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> { // fn from_str(s: &str) -> Result<Self, Self::Err> {
match s { // match s {
"cone" => Ok(AreaType::Cone), // "cone" => Ok(AreaType::Cone),
"cube" => Ok(AreaType::Cube), // "cube" => Ok(AreaType::Cube),
"cylinder" => Ok(AreaType::Cylinder), // "cylinder" => Ok(AreaType::Cylinder),
"line" => Ok(AreaType::Line), // "line" => Ok(AreaType::Line),
"sphere" => Ok(AreaType::Sphere), // "sphere" => Ok(AreaType::Sphere),
_ => Err(()) // _ => Err(())
} // }
} // }
} // }
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct Duration { pub struct Duration {

View File

@@ -35,7 +35,7 @@ impl From<DieselError> for ServiceError {
DieselError::SerializationError(err) => { DieselError::SerializationError(err) => {
ServiceError::new(422, err.to_string()) ServiceError::new(422, err.to_string())
}, },
err => ServiceError::new(500, format!("Unknown Diesel error: {}", err)), err => ServiceError::new(500, format!("Unknown database error: {}", err)),
} }
} }
} }
@@ -52,6 +52,6 @@ impl ResponseError for ServiceError {
false => "Internal server error".to_string(), false => "Internal server error".to_string(),
}; };
HttpResponse::build(status_code).json(serde_json::json!({ "message": error_message })) HttpResponse::build(status_code).json(serde_json::json!({ "status": status_code.as_u16(), "message": error_message }))
} }
} }