1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
use crate::xapian_reader::XapianReader;
use std::collections::{HashMap, HashSet};
use std::fmt;
use v_module::module::Module;
use v_module::v_api::app::ResultCode;
use v_module::v_onto::individual::Individual;
use v_module::v_onto::onto::Onto;
use v_module::v_search::common::FTQuery;

#[derive(Debug)]
pub struct IndexerSchema {
    class_property_2_id: HashMap<String, String>,
    class_2_database: HashMap<String, String>,
    id_2_individual: HashMap<String, Individual>,
    database_2_true: HashMap<String, bool>,
}

impl fmt::Display for IndexerSchema {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for (k, v) in self.class_property_2_id.iter() {
            writeln!(f, "{} -> {}", k, v)?
        }
        Ok(())
    }
}

impl IndexerSchema {
    pub fn load(&mut self, force: bool, onto: &Onto, module: &mut Module, xr: &mut XapianReader) {
        if self.class_property_2_id.is_empty() || force {
            if force {
                info!("force reload schema");
            } else {
                info!("reload schema");
            }

            let res = xr.query(FTQuery::new_with_user("cfg:VedaSystem", "'rdf:type' === 'vdi:ClassIndex'"), &mut module.storage);
            if res.result_code == ResultCode::Ok && res.count > 0 {
                for id in res.result.iter() {
                    if let Some(i) = module.get_individual(id, &mut Individual::default()) {
                        i.parse_all();
                        self.add_schema_data(onto, i);
                    }
                }
            }
            info!("SCHEMA \n{}", self);
        }
    }

    pub fn get_dbname_of_class(&self, id: &str) -> &str {
        if let Some(v) = self.class_2_database.get(id) {
            return v;
        }
        "base"
    }

    pub fn get_copy_of_index(&self, id: &str) -> Option<Individual> {
        if let Some(indv) = self.id_2_individual.get(id) {
            Some(Individual::new_from_obj(indv.get_obj()))
        } else {
            None
        }
    }

    pub fn get_index(&self, id: &str) -> Option<&Individual> {
        self.id_2_individual.get(id)
    }

    pub fn get_index_id_of_uri_and_property(&mut self, id: &str, predicate: &str) -> Option<String> {
        if let Some(id) = self.class_property_2_id.get(&format!("{}+{}", id.to_owned(), predicate)) {
            return Some(id.to_owned());
        }
        None
    }

    pub fn get_index_id_of_property(&mut self, predicate: &str) -> Option<String> {
        if let Some(id) = self.class_property_2_id.get(&format!("+{}", predicate)) {
            return Some(id.to_owned());
        }

        None
    }

    pub fn add_schema_data(&mut self, onto: &Onto, indv: &mut Individual) {
        self.id_2_individual.insert(indv.get_id().to_owned(), Individual::new_from_obj(indv.get_obj()));

        let for_classes = indv.get_literals("vdi:forClass").unwrap_or_default();
        let for_properties = indv.get_literals("vdi:forProperty").unwrap_or_default();
        let indexed_to = indv.get_literals("vdi:indexed_to").unwrap_or_default();

        for for_class in for_classes.iter() {
            let mut sub_classes = HashSet::new();
            onto.get_subs(&for_class, &mut sub_classes);

            if let Some(i) = indexed_to.get(0) {
                self.class_2_database.insert(for_class.to_owned(), i.to_owned());
                self.database_2_true.insert(i.to_owned(), true);
            }

            if sub_classes.is_empty() {
                sub_classes.insert("".to_owned());
            }

            for sub_class in sub_classes.iter() {
                if let Some(i) = indexed_to.get(0) {
                    self.class_2_database.insert(sub_class.to_owned(), i.to_owned());
                    self.database_2_true.insert(i.to_owned(), true);
                }

                for for_property in for_properties.iter() {
                    self.class_property_2_id.insert(format!("{}+{}", sub_class, for_property), indv.get_id().to_owned());
                }
            }

            for for_property in for_properties.iter() {
                self.class_property_2_id.insert(format!("{}+{}", for_class, for_property), indv.get_id().to_owned());
            }
        }
    }
}

impl Default for IndexerSchema {
    fn default() -> Self {
        Self {
            class_property_2_id: Default::default(),
            class_2_database: Default::default(),
            id_2_individual: Default::default(),
            database_2_true: Default::default(),
        }
    }
}