feos-core 0.9.6

Core traits and functionalities for the `feos` project.
Documentation
use super::{
    BinaryAssociationRecord, BinaryRecord, CombiningRule, IdentifierOption, Parameters, PureRecord,
};
use crate::FeosResult;
use rusqlite::{Connection, ToSql, params_from_iter};
use serde::de::DeserializeOwned;
use std::path::Path;

impl<P: Clone, B: Clone, A: CombiningRule<P> + Clone> Parameters<P, B, A> {
    pub fn from_database<F, S>(
        substances: &[S],
        file: F,
        identifier_option: IdentifierOption,
    ) -> FeosResult<Self>
    where
        F: AsRef<Path>,
        S: ToSql,
        P: DeserializeOwned + Clone,
        B: DeserializeOwned + Clone,
        A: DeserializeOwned + Clone,
    {
        let conn = Connection::open(file)?;
        let pure_records = PureRecord::from_database(substances, &conn, identifier_option)?;
        let binary_records = BinaryRecord::from_database(substances, &conn, identifier_option)?;
        Self::new(pure_records, binary_records)
    }
}

impl<M, A> PureRecord<M, A> {
    pub fn from_database<S>(
        substances: &[S],
        connection: &Connection,
        identifier_option: IdentifierOption,
    ) -> FeosResult<Vec<Self>>
    where
        S: ToSql,
        M: DeserializeOwned,
        A: DeserializeOwned,
    {
        let values = (0..substances.len())
            .map(|i| format!("({i},?)"))
            .collect::<Vec<_>>()
            .join(",");

        let query = format!(
            "
            WITH input(idx, ident) AS (
                VALUES {values}
            )
            SELECT pr.pure_record
            FROM input
            JOIN pure_records pr
              ON pr.{identifier_option} = input.ident
            "
        );
        let mut stmt = connection.prepare(&query)?;
        stmt.query_and_then(params_from_iter(substances), |r| {
            Ok(serde_json::from_str(&r.get::<_, String>("pure_record")?)?)
        })?
        .collect()
    }
}

impl<B, A> BinaryRecord<usize, B, A> {
    pub fn from_database<S>(
        substances: &[S],
        connection: &Connection,
        identifier_option: IdentifierOption,
    ) -> FeosResult<Vec<Self>>
    where
        S: ToSql,
        B: DeserializeOwned,
        A: DeserializeOwned,
    {
        let values = (0..substances.len())
            .map(|i| format!("({i},?)"))
            .collect::<Vec<_>>()
            .join(",");

        let query = format!(
            "
            WITH input(idx, ident) AS (
                VALUES {values}
            )
            SELECT i1.idx AS comp1, i2.idx AS comp2, br.model_record, br.association_sites
            FROM binary_records br
            JOIN pure_records p1 ON br.id1 = p1.id
            JOIN pure_records p2 ON br.id2 = p2.id
            JOIN input i1 ON p1.{identifier_option} = i1.ident
            JOIN input i2 ON p2.{identifier_option} = i2.ident
            "
        );
        let mut stmt = connection.prepare(&query)?;
        stmt.query_and_then(params_from_iter(substances), |r| {
            let mut id1: i32 = r.get("comp1")?;
            let mut id2: i32 = r.get("comp2")?;
            let model_record = serde_json::from_str(&r.get::<_, String>("model_record")?)?;
            let mut association_sites: Vec<BinaryAssociationRecord<_>> =
                serde_json::from_str(&r.get::<_, String>("association_sites")?)?;
            if id1 > id2 {
                association_sites
                    .iter_mut()
                    .for_each(|a| std::mem::swap(&mut a.id1, &mut a.id2));
                std::mem::swap(&mut id1, &mut id2);
            };

            Ok(BinaryRecord::with_association(
                id1 as usize,
                id2 as usize,
                model_record,
                association_sites,
            ))
        })?
        .collect()
    }
}