184 lines
5.7 KiB
Rust
184 lines
5.7 KiB
Rust
use diesel::prelude::*;
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
use crate::{db::{schema::spells::{self}, classes::AbilityType, conditions::ConditionType}, error_handler::ServiceError};
|
|
|
|
use super::{SchoolType, CastingTime, CastingType, SpellAttackType, SpellDamageType, Range, Area, Components, Duration, Source, Description};
|
|
|
|
#[derive(Queryable, QueryableByName)]
|
|
#[diesel(table_name = spells)]
|
|
pub struct QuerySpell {
|
|
pub id: i32,
|
|
pub name: String,
|
|
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 {
|
|
pub fn get_all(filters: &QueryFilters, 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));
|
|
if let Some(name) = filters.by_name.to_owned() {
|
|
query = query.filter(spells::name.ilike(format!("%{}%", name)));
|
|
}
|
|
|
|
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(filters: &QueryFilters) -> Result<i64, ServiceError> {
|
|
let mut conn = crate::db::connection()?;
|
|
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)
|
|
}
|
|
|
|
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 {
|
|
pub name: String,
|
|
pub data: serde_json::Value
|
|
}
|
|
|
|
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(Debug, Serialize, Deserialize)]
|
|
pub struct Spell {
|
|
pub name: String,
|
|
pub school: SchoolType,
|
|
pub level: i32,
|
|
pub ritual: bool,
|
|
pub casting_time: CastingTime,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub saving_throw: Option<Vec<AbilityType>>,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub attack_type: Option<SpellAttackType>,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub damage_inflict: Option<Vec<SpellDamageType>>,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub damage_resist: Option<Vec<SpellDamageType>>,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub conditions: Option<Vec<ConditionType>>,
|
|
pub range: Range,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub area: Option<Area>,
|
|
pub components: Components,
|
|
pub durations: Vec<Duration>,
|
|
pub classes: Vec<String>,
|
|
pub sources: Vec<Source>,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub tags: Option<Vec<String>>,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub description: Option<Description>
|
|
}
|
|
|
|
impl From<QuerySpell> for Spell {
|
|
fn from(query: QuerySpell) -> Self {
|
|
return match serde_json::from_value(query.data) {
|
|
Ok(data) => data,
|
|
Err(err) => {
|
|
log::error!("Failed to parse spell: {}", err);
|
|
Self {
|
|
name: "".to_string(),
|
|
school: SchoolType::Abjuration,
|
|
level: 0,
|
|
ritual: false,
|
|
casting_time: CastingTime { amount: 0, casting_type: CastingType::Action },
|
|
saving_throw: None,
|
|
attack_type: None,
|
|
damage_inflict: None,
|
|
damage_resist: None,
|
|
conditions: None,
|
|
range: Range { range_type: "".to_string(), amount: None, unit: None },
|
|
area: None,
|
|
components: Components { verbal: false, somatic: false, material: false, materials_needed: None, materials_cost: None, materials_consumed: None },
|
|
durations: vec![],
|
|
classes: vec![],
|
|
sources: vec![],
|
|
tags: None,
|
|
description: None,
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Into<InsertSpell> for Spell {
|
|
fn into(self) -> InsertSpell {
|
|
return InsertSpell {
|
|
name: self.name.to_string(),
|
|
data: match serde_json::to_value(&self) {
|
|
Ok(data) => data,
|
|
Err(err) => {
|
|
log::error!("Failed to serialize spell description: {}", err);
|
|
serde_json::Value::Null
|
|
}
|
|
},
|
|
}
|
|
}
|
|
}
|