Spells endpoints
This commit is contained in:
@@ -1,3 +1,43 @@
|
||||
mod model;
|
||||
mod routes;
|
||||
|
||||
pub use model::*;
|
||||
pub use routes::init_routes;
|
||||
|
||||
pub fn load_data() {
|
||||
let root_path = std::env::current_dir().unwrap();
|
||||
let mut data_path = std::path::PathBuf::from(root_path);
|
||||
data_path.push("data/spells.json");
|
||||
match data_path.to_str() {
|
||||
Some(path) => {
|
||||
log::debug!("Loading spells from {}", path);
|
||||
match std::fs::read_to_string(data_path) {
|
||||
Ok(data) => {
|
||||
match serde_json::from_str::<serde_json::Value>(&data) {
|
||||
Ok(json) => {
|
||||
match serde_json::from_value::<Vec<Spell>>(json) {
|
||||
Ok(spells) => {
|
||||
let count = QuerySpell::get_count().unwrap();
|
||||
if count >= spells.len() as i64 {
|
||||
log::warn!("Spell data is already loaded");
|
||||
return;
|
||||
}
|
||||
for spell in spells {
|
||||
match InsertSpell::insert(spell.into()) {
|
||||
Ok(_) => {},
|
||||
Err(err) => log::error!("Failed to insert spell: {}", err)
|
||||
}
|
||||
}
|
||||
},
|
||||
Err(err) => log::error!("Failed to parse spells data: {}", err)
|
||||
}
|
||||
},
|
||||
Err(err) => log::error!("Failed to parse spells data to value: {}", err)
|
||||
};
|
||||
},
|
||||
Err(err) => log::error!("Failed to read spells data: {}", err)
|
||||
};
|
||||
},
|
||||
None => log::error!("Failed to find spells data directory")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use diesel::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::db::schema::spells;
|
||||
use crate::{db::schema::spells, error_handler::ServiceError};
|
||||
|
||||
#[derive(Queryable, QueryableByName)]
|
||||
#[diesel(table_name = spells)]
|
||||
@@ -24,6 +24,38 @@ pub struct QuerySpell {
|
||||
pub description: String
|
||||
}
|
||||
|
||||
impl QuerySpell {
|
||||
pub fn get_all(limit: i32, page: i32) -> Result<Vec<Self>, ServiceError> {
|
||||
let mut conn = crate::db::connection()?;
|
||||
let mut query = spells::table
|
||||
.limit(limit as i64)
|
||||
.into_boxed();
|
||||
query = query.filter(spells::id.gt(std::cmp::max(0, page - 1) * limit));
|
||||
let spells = query.load::<QuerySpell>(&mut conn)?;
|
||||
Ok(spells)
|
||||
}
|
||||
|
||||
pub fn get_by_id(id: i32) -> Result<Self, ServiceError> {
|
||||
let mut conn = crate::db::connection()?;
|
||||
let spell = spells::table
|
||||
.filter(spells::id.eq(id))
|
||||
.first::<QuerySpell>(&mut conn)?;
|
||||
Ok(spell)
|
||||
}
|
||||
|
||||
pub fn get_count() -> Result<i64, ServiceError> {
|
||||
let mut conn = crate::db::connection()?;
|
||||
let count = spells::table.count().get_result(&mut conn)?;
|
||||
Ok(count)
|
||||
}
|
||||
|
||||
pub fn delete(id: i32) -> Result<Self, ServiceError> {
|
||||
let mut conn = crate::db::connection()?;
|
||||
let spell = diesel::delete(spells::table.filter(spells::id.eq(id))).get_result(&mut conn)?;
|
||||
Ok(spell)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Insertable, AsChangeset)]
|
||||
#[diesel(table_name = spells)]
|
||||
pub struct InsertSpell {
|
||||
@@ -44,6 +76,20 @@ pub struct InsertSpell {
|
||||
pub description: String
|
||||
}
|
||||
|
||||
impl InsertSpell {
|
||||
pub fn insert(spell: Self) -> Result<QuerySpell, ServiceError> {
|
||||
let mut conn = crate::db::connection()?;
|
||||
let spell = diesel::insert_into(spells::table).values(spell).get_result(&mut conn)?;
|
||||
Ok(spell)
|
||||
}
|
||||
|
||||
pub fn update(id: i32, spell: Self) -> Result<QuerySpell, ServiceError> {
|
||||
let mut conn = crate::db::connection()?;
|
||||
let spell = diesel::update(spells::table.filter(spells::id.eq(id))).set(spell).get_result(&mut conn)?;
|
||||
Ok(spell)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct Spell {
|
||||
pub name: String,
|
||||
@@ -56,6 +102,7 @@ pub struct Spell {
|
||||
pub duration: String,
|
||||
pub classes: Vec<String>,
|
||||
pub sources: Vec<String>,
|
||||
pub tags: Vec<String>,
|
||||
pub description: String
|
||||
}
|
||||
|
||||
@@ -67,30 +114,8 @@ pub struct Components {
|
||||
pub materials_needed: Option<String>
|
||||
}
|
||||
|
||||
impl Spell {
|
||||
/// Convert spell to insertable struct
|
||||
pub fn to_insert(self) -> InsertSpell {
|
||||
return InsertSpell {
|
||||
name: self.name,
|
||||
school: self.school,
|
||||
level: self.level,
|
||||
ritual: self.ritual,
|
||||
casting_time: self.casting_time,
|
||||
range: self.range,
|
||||
components_verbal: self.components.verbal,
|
||||
components_somatic: self.components.somatic,
|
||||
components_material: self.components.material,
|
||||
components_materials_needed: self.components.materials_needed,
|
||||
duration: self.duration,
|
||||
classes: self.classes,
|
||||
sources: self.sources,
|
||||
tags: vec![],
|
||||
description: self.description
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert query struct to spell
|
||||
pub fn from_query(query: QuerySpell) -> Self {
|
||||
impl From<QuerySpell> for Spell {
|
||||
fn from(query: QuerySpell) -> Self {
|
||||
return Self {
|
||||
name: query.name,
|
||||
school: query.school,
|
||||
@@ -107,14 +132,30 @@ impl Spell {
|
||||
duration: query.duration,
|
||||
classes: query.classes,
|
||||
sources: query.sources,
|
||||
tags: query.tags,
|
||||
description: query.description
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert file to spell
|
||||
pub fn from_file(file: String) -> Self {
|
||||
let data = std::fs::read_to_string(file).unwrap();
|
||||
let spell: Spell = serde_json::from_str(&data).unwrap();
|
||||
return spell;
|
||||
impl Into<InsertSpell> for Spell {
|
||||
fn into(self) -> InsertSpell {
|
||||
return InsertSpell {
|
||||
name: self.name,
|
||||
school: self.school,
|
||||
level: self.level,
|
||||
ritual: self.ritual,
|
||||
casting_time: self.casting_time,
|
||||
range: self.range,
|
||||
components_verbal: self.components.verbal,
|
||||
components_somatic: self.components.somatic,
|
||||
components_material: self.components.material,
|
||||
components_materials_needed: self.components.materials_needed,
|
||||
duration: self.duration,
|
||||
classes: self.classes,
|
||||
sources: self.sources,
|
||||
tags: self.tags,
|
||||
description: self.description
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
79
src/db/spells/routes.rs
Normal file
79
src/db/spells/routes.rs
Normal file
@@ -0,0 +1,79 @@
|
||||
use actix_web::{get, post, put, delete, web, HttpResponse, HttpRequest, ResponseError};
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
use crate::db::{spells::QuerySpell, GetResponse, Metadata};
|
||||
|
||||
use super::{Spell, InsertSpell};
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct GetAllParams {
|
||||
limit: Option<i32>,
|
||||
page: Option<i32>,
|
||||
}
|
||||
|
||||
#[get("/spells")]
|
||||
async fn get_all(req: HttpRequest) -> HttpResponse {
|
||||
let params = web::Query::<GetAllParams>::from_query(req.query_string()).unwrap();
|
||||
let limit = params.limit.unwrap_or(20);
|
||||
let page = params.page.unwrap_or(1);
|
||||
match web::block(move || QuerySpell::get_all(limit, page)).await.unwrap() {
|
||||
Ok(spells) => {
|
||||
let mut response: Vec<Spell> = Vec::new();
|
||||
for spell in spells {
|
||||
response.push(Spell::from(spell));
|
||||
}
|
||||
let total_count = QuerySpell::get_count().unwrap();
|
||||
HttpResponse::Ok().json(GetResponse {
|
||||
data: response,
|
||||
metadata: Some(Metadata {
|
||||
total: total_count as i32,
|
||||
limit,
|
||||
page
|
||||
})
|
||||
})
|
||||
},
|
||||
Err(err) => ResponseError::error_response(&err)
|
||||
}
|
||||
}
|
||||
|
||||
#[get("/spells/{id}")]
|
||||
async fn get_by_id(id: web::Path<i32>) -> HttpResponse {
|
||||
match web::block(move || QuerySpell::get_by_id(id.into_inner())).await.unwrap() {
|
||||
Ok(spell) => HttpResponse::Ok().json(GetResponse {
|
||||
data: Spell::from(spell),
|
||||
metadata: None
|
||||
}),
|
||||
Err(err) => ResponseError::error_response(&err)
|
||||
}
|
||||
}
|
||||
|
||||
#[post("/spells")]
|
||||
async fn create(spell: web::Json<Spell>) -> HttpResponse {
|
||||
match InsertSpell::insert(spell.into_inner().into()) {
|
||||
Ok(spell) => HttpResponse::Created().json(Spell::from(spell)),
|
||||
Err(err) => ResponseError::error_response(&err)
|
||||
}
|
||||
}
|
||||
|
||||
#[put("/spells/{id}")]
|
||||
async fn update(id: web::Path<i32>, spell: web::Json<Spell>) -> HttpResponse {
|
||||
match web::block(move || InsertSpell::update(id.into_inner(), spell.into_inner().into())).await.unwrap() {
|
||||
Ok(spell) => HttpResponse::Ok().json(Spell::from(spell)),
|
||||
Err(err) => ResponseError::error_response(&err)
|
||||
}
|
||||
}
|
||||
|
||||
#[delete("/spells/{id}")]
|
||||
async fn delete(id: web::Path<i32>) -> HttpResponse {
|
||||
match web::block(move || QuerySpell::delete(id.into_inner())).await.unwrap() {
|
||||
Ok(spell) => HttpResponse::Ok().json(Spell::from(spell)),
|
||||
Err(err) => ResponseError::error_response(&err)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init_routes(config: &mut web::ServiceConfig) {
|
||||
config.service(get_all);
|
||||
config.service(get_by_id);
|
||||
config.service(create);
|
||||
config.service(delete);
|
||||
}
|
||||
Reference in New Issue
Block a user