v-common-onto 0.1.13

common part of the veda platform
Documentation
use crate::datatype::*;
use crate::individual::*;
use crate::resource::*;
use crate::turtle_formatters_with_prefixes::TurtleFormatterWithPrefixes;
use chrono::{TimeZone, Utc};
use rio_api::formatter::TriplesFormatter;
use rio_api::model::*;
use rust_decimal::Decimal;
use std::collections::HashMap;
use std::io;

fn from_boolean<'a>(id: &'a str, in_predicate: &'a str, v: &'a str) -> Triple<'a> {
    let subject = NamedNode {
        iri: id,
    };

    let predicate = NamedNode {
        iri: in_predicate,
    };

    let obj = Literal::Typed {
        value: v,
        datatype: NamedNode {
            iri: "xsd:boolean",
        },
    };

    Triple {
        subject: subject.into(),
        predicate,
        object: obj.into(),
    }
}

fn from_integer<'a>(id: &'a str, in_predicate: &'a str, v: &'a str) -> Triple<'a> {
    let subject = NamedNode {
        iri: id,
    };

    let predicate = NamedNode {
        iri: in_predicate,
    };

    let obj = Literal::Typed {
        value: v,
        datatype: NamedNode {
            iri: "xsd:integer",
        },
    };

    Triple {
        subject: subject.into(),
        predicate,
        object: obj.into(),
    }
}

fn from_decimal<'a>(id: &'a str, in_predicate: &'a str, v: &'a str) -> Triple<'a> {
    let subject = NamedNode {
        iri: id,
    };

    let predicate = NamedNode {
        iri: in_predicate,
    };

    let obj = Literal::Typed {
        value: v,
        datatype: NamedNode {
            iri: "xsd:decimal",
        },
    };

    Triple {
        subject: subject.into(),
        predicate,
        object: obj.into(),
    }
}

fn from_datetime<'a>(id: &'a str, in_predicate: &'a str, v: &'a str) -> Triple<'a> {
    let subject = NamedNode {
        iri: id,
    };

    let predicate = NamedNode {
        iri: in_predicate,
    };

    let obj = Literal::Typed {
        value: v,
        datatype: NamedNode {
            iri: "xsd:dateTime",
        },
    };

    Triple {
        subject: subject.into(),
        predicate,
        object: obj.into(),
    }
}

fn from_uri<'a>(id: &'a str, in_predicate: &'a str, v: &'a str) -> Triple<'a> {
    let subject = NamedNode {
        iri: id,
    };

    let predicate = NamedNode {
        iri: in_predicate,
    };

    let obj = NamedNode {
        iri: v,
    };

    Triple {
        subject: subject.into(),
        predicate,
        object: obj.into(),
    }
}

fn from_string<'a>(id: &'a str, in_predicate: &'a str, s: &'a str, l: Lang) -> Triple<'a> {
    let subject = NamedNode {
        iri: id,
    };

    let predicate = NamedNode {
        iri: in_predicate,
    };

    let obj = match l {
        Lang::NONE => Literal::Simple {
            value: s,
        },
        Lang::RU => Literal::LanguageTaggedString {
            value: s,
            language: "ru",
        },
        Lang::EN => Literal::LanguageTaggedString {
            value: s,
            language: "en",
        },
    };

    Triple {
        subject: subject.into(),
        predicate,
        object: obj.into(),
    }
}

fn format_resources(subject: &str, predicate: &str, resources: &[Resource], formatter: &mut TurtleFormatterWithPrefixes<Vec<u8>>) -> Result<(), io::Error> {
    for r in resources {
        match r.rtype {
            DataType::Boolean => {
                formatter.format(&from_boolean(subject, &predicate, &r.get_bool().to_string()))?;
            }
            DataType::Integer => {
                formatter.format(&from_integer(subject, &predicate, &r.get_int().to_string()))?;
            }
            DataType::Uri => {
                formatter.format(&from_uri(subject, &predicate, &r.get_uri()))?;
            }
            DataType::String => {
                formatter.format(&from_string(subject, &predicate, r.get_str(), r.get_lang()))?;
            }
            DataType::Datetime => {
                formatter.format(&from_datetime(subject, &predicate, &format!("{:?}", &Utc.timestamp(r.get_datetime(), 0))))?;
            }
            DataType::Decimal => {
                let (m, e) = r.get_num();
                let c = exponent_to_scale(&m, &e);
                let d = Decimal::new(c.0, c.1);
                formatter.format(&from_decimal(subject, &predicate, &format!("{:?}", d.to_string())))?;
            }
            _ => {}
        }
    }
    Ok(())
}

pub fn get_prefix(v: &str) -> Option<&str> {
    if let Some(el) = v.split(':').next() {
        return Some(el);
    }
    None
}

fn collect_prefix(v: &str, all_prefixes: &HashMap<String, String>, used_prefixes: &mut HashMap<String, String>) {
    if let Some(p) = get_prefix(v) {
        if !used_prefixes.contains_key(p) {
            if let Some(up) = all_prefixes.get(&(p.to_owned() + ":")) {
                used_prefixes.insert(p.to_owned(), up.to_owned());
            }
        }
    }
}

fn extract_prefixes(indvs: &[Individual], all_prefixes: &HashMap<String, String>) -> HashMap<String, String> {
    let mut used_prefixes = HashMap::new();

    collect_prefix("xsd:", &all_prefixes, &mut used_prefixes);

    for indv in indvs.iter() {
        collect_prefix(indv.get_id(), &all_prefixes, &mut used_prefixes);
        for (predicate, resources) in &indv.obj.resources {
            collect_prefix(predicate, &all_prefixes, &mut used_prefixes);
            for r in resources {
                if let DataType::Uri = r.rtype {
                    collect_prefix(&r.get_uri(), &all_prefixes, &mut used_prefixes);
                }
            }
        }
    }

    used_prefixes
}

pub fn to_turtle(indvs: &[Individual], all_prefixes: &mut HashMap<String, String>) -> Result<Vec<u8>, io::Error> {
    let used_prefixes = extract_prefixes(&indvs, all_prefixes);
    let mut formatter = TurtleFormatterWithPrefixes::new(Vec::default(), &used_prefixes);

    for indv in indvs.iter() {
        for (predicate, resources) in &indv.obj.resources {
            if predicate == "rdf:type" {
                format_resources(&indv.get_id(), predicate, resources, &mut formatter)?;
                break;
            }
        }
        for (predicate, resources) in &indv.obj.resources {
            if predicate == "rdf:type" || predicate == "v-s:updateCounter" {
                continue;
            }
            format_resources(&indv.get_id(), predicate, resources, &mut formatter)?;
        }
    }

    formatter.finish()
}