Skip to main content

monster_service/
export.rs

1//! A campaign's own monsters, spells and conditions, exported to keep or
2//! to move to another server, and imported there.
3
4use edda_types::{
5    admin::MonstersExport,
6    rules_text::{ConditionText, SpellText},
7};
8use uuid::Uuid;
9
10use crate::{MonsterStore, error::ApiError, store, texts};
11
12impl MonsterStore {
13    /// The campaign's own, as they are.
14    pub async fn export_campaign(&self, campaign: Uuid) -> Result<MonstersExport, ApiError> {
15        Ok(MonstersExport {
16            monsters: self.export_own(campaign).await?,
17            spells: self.export_texts::<SpellText>(campaign).await?,
18            conditions: self.export_texts::<ConditionText>(campaign).await?,
19        })
20    }
21
22    /// Takes in a campaign's own exported elsewhere, as they were: ids,
23    /// versions and dates. All or nothing, and only while it has none here;
24    /// returns how many came.
25    pub async fn import_campaign(
26        &self,
27        campaign: Uuid,
28        export: &MonstersExport,
29    ) -> Result<u64, ApiError> {
30        let ours = Some(campaign);
31        if export.monsters.iter().any(|m| m.campaign != ours)
32            || export.spells.iter().any(|s| s.campaign != ours)
33            || export.conditions.iter().any(|c| c.campaign != ours)
34        {
35            return Err(ApiError::BadRequest(
36                "the export holds what isn't this campaign's own".into(),
37            ));
38        }
39        let mut tx = self.pool().begin().await?;
40        let (kept,): (i64,) = sqlx::query_as(
41            "SELECT (SELECT COUNT(*) FROM monsters WHERE campaign = $1) \
42             + (SELECT COUNT(*) FROM rules_text WHERE campaign = $1)",
43        )
44        .bind(campaign)
45        .fetch_one(&mut *tx)
46        .await?;
47        if kept > 0 {
48            return Err(ApiError::Conflict(format!(
49                "campaign {campaign} has {kept} monster(s), spell(s) or condition(s) here already"
50            )));
51        }
52        for monster in &export.monsters {
53            store::insert_as_is(&mut *tx, monster).await?;
54        }
55        for spell in &export.spells {
56            texts::insert_as_is(&mut *tx, spell).await?;
57        }
58        for condition in &export.conditions {
59            texts::insert_as_is(&mut *tx, condition).await?;
60        }
61        tx.commit().await?;
62        let count = export.monsters.len() + export.spells.len() + export.conditions.len();
63        Ok(u64::try_from(count).unwrap_or(u64::MAX))
64    }
65}