1use v_individual_model::onto::onto_index::OntoIndex;
2use crate::storage::async_storage::get_individual_from_db;
3use crate::storage::async_storage::AStorage;
4use crate::v_api::common_type::ResultCode;
5use futures::lock::Mutex;
6use serde::{Deserialize, Serialize};
7use std::sync::Arc;
8use strum_macros::EnumString;
9
10#[derive(Serialize, Deserialize, Debug)]
11pub struct QueryResult {
12 pub result: Vec<String>,
13 pub count: i64,
14 pub estimated: i64,
15 pub processed: i64,
16 pub cursor: i64,
17 pub total_time: i64,
18 pub query_time: i64,
19 pub authorize_time: i64,
20 pub result_code: ResultCode,
21}
22
23impl Default for QueryResult {
24 fn default() -> Self {
25 QueryResult {
26 result: vec![],
27 count: 0,
28 estimated: 0,
29 processed: 0,
30 cursor: 0,
31 total_time: 0,
32 query_time: 0,
33 authorize_time: 0,
34 result_code: ResultCode::NotReady,
35 }
36 }
37}
38
39#[derive(Debug, PartialEq, EnumString)]
40pub enum ResultFormat {
41 #[strum(ascii_case_insensitive)]
42 Rows,
43 #[strum(ascii_case_insensitive)]
44 Cols,
45 #[strum(ascii_case_insensitive)]
46 Full,
47}
48
49#[derive(Debug, PartialEq, EnumString)]
50pub enum AuthorizationLevel {
51 #[strum(ascii_case_insensitive)]
52 Query,
53 #[strum(ascii_case_insensitive)]
54 Cell,
55 #[strum(ascii_case_insensitive, serialize = "row-column")]
56 RowColumn,
57}
58
59#[derive(Serialize, Deserialize, Debug)]
60pub struct FTQuery {
61 pub ticket: String,
62 pub user: String,
63 pub query: String,
64 pub sort: String,
65 pub databases: String,
66 pub reopen: bool,
67 pub top: i32,
68 pub limit: i32,
69 pub from: i32,
70}
71
72impl FTQuery {
73 pub fn new_with_user(user: &str, query: &str) -> FTQuery {
74 FTQuery {
75 ticket: "".to_owned(),
76 user: user.to_owned(),
77 query: query.to_owned(),
78 sort: "".to_owned(),
79 databases: "".to_owned(),
80 reopen: false,
81 top: 10000,
82 limit: 10000,
83 from: 0,
84 }
85 }
86
87 pub fn new_with_ticket(ticket: &str, query: &str) -> FTQuery {
88 FTQuery {
89 ticket: ticket.to_owned(),
90 user: "".to_owned(),
91 query: query.to_owned(),
92 sort: "".to_owned(),
93 databases: "".to_owned(),
94 reopen: false,
95 top: 10000,
96 limit: 10000,
97 from: 0,
98 }
99 }
100
101 pub fn as_string(&self) -> String {
102 let mut s = String::new();
103
104 s.push_str("[\"");
105 if self.ticket.is_empty() {
106 if !self.user.is_empty() {
107 s.push_str("\"UU=");
108 s.push_str(&self.user);
109 }
110 } else {
111 s.push_str(&self.ticket);
112 }
113
114 s.push_str("\",\"");
115 s.push_str(&self.query.replace('"', "\\\""));
116 s.push_str("\",\"");
117 s.push_str(&self.sort);
118 s.push_str("\",\"");
119 s.push_str(&self.databases);
120 s.push_str("\",");
121 s.push_str(&self.reopen.to_string());
122 s.push(',');
123 s.push_str(&self.top.to_string());
124 s.push(',');
125 s.push_str(&self.limit.to_string());
126 s.push(',');
127 s.push_str(&self.from.to_string());
128 s.push(']');
129
130 s
131 }
132}
133
134pub struct PrefixesCache {
137 pub full2short_r: evmap::ReadHandle<String, String>,
138 pub full2short_w: Arc<Mutex<evmap::WriteHandle<String, String>>>,
139 pub short2full_r: evmap::ReadHandle<String, String>,
140 pub short2full_w: Arc<Mutex<evmap::WriteHandle<String, String>>>,
141}
142
143pub fn split_full_prefix(v: &str) -> (&str, &str) {
144 let pos = if let Some(n) = v.rfind('/') {
145 n
146 } else {
147 v.rfind('#').unwrap_or_default()
148 };
149
150 v.split_at(pos + 1)
151}
152
153pub fn split_short_prefix(v: &str) -> Option<(&str, &str)> {
154 if let Some(pos) = v.rfind(':') {
155 let lr = v.split_at(pos);
156 if let Some(l) = lr.1.strip_prefix(':') {
157 return Some((lr.0, l));
158 }
159 }
160 None
161}
162
163pub fn get_short_prefix(full_prefix: &str, prefixes_cache: &PrefixesCache) -> String {
164 if let Some(v) = prefixes_cache.full2short_r.get(full_prefix) {
165 if let Some(t) = v.get_one() {
166 return t.to_string();
167 }
168 }
169
170 full_prefix.to_owned()
171}
172
173pub fn get_full_prefix(short_prefix: &str, prefixes_cache: &PrefixesCache) -> String {
174 if let Some(v) = prefixes_cache.short2full_r.get(short_prefix) {
175 if let Some(t) = v.get_one() {
176 return t.to_string();
177 }
178 }
179
180 short_prefix.to_owned()
181}
182
183pub async fn load_prefixes(storage: &AStorage, prefixes_cache: &PrefixesCache) {
184 let onto_index = OntoIndex::load();
185
186 let mut f2s = prefixes_cache.full2short_w.lock().await;
187 let mut s2f = prefixes_cache.short2full_w.lock().await;
188
189 for id in onto_index.data.keys() {
190 if let Ok((mut rindv, _res)) = get_individual_from_db(id, "", storage, None).await {
191 rindv.parse_all();
192
193 if rindv.any_exists("rdf:type", &["owl:Ontology"]) {
194 if let Some(full_url) = rindv.get_first_literal("v-s:fullUrl") {
195 debug!("prefix : {} -> {}", rindv.get_id(), full_url);
196 let short_prefix = rindv.get_id().trim_end_matches(':');
197
198 f2s.insert(full_url.to_owned(), short_prefix.to_owned());
199 s2f.insert(short_prefix.to_owned(), full_url.to_owned());
200 }
201 }
202 } else {
203 error!("failed to read individual {}", id);
204 }
205 f2s.refresh();
206 s2f.refresh();
207 }
208}
209
210use regex::Regex;
211
212lazy_static! {
213 static ref REG_URI: Regex = Regex::new(r"^[a-z][a-z0-9]*:([a-zA-Z0-9-_])*$").expect("Invalid regex pattern");
214}
215
216pub fn is_identifier(str: &str) -> bool {
217 REG_URI.is_match(str)
218}
219
220pub fn replace_word(text: &str, a: &str, b: &str) -> String {
221 let a_lower = a.to_lowercase();
222 let re = Regex::new(r"[\w']+").unwrap();
223 let mut replaced_text = String::new();
224 let mut last_end = 0;
225
226 for word_match in re.find_iter(text) {
227 let (start, end) = (word_match.start(), word_match.end());
228 let word = &text[start..end];
229 let word_lower = word.to_lowercase();
230
231 if word_lower == a_lower {
232 replaced_text.push_str(&text[last_end..start]);
233 replaced_text.push_str(b);
234 } else {
235 replaced_text.push_str(&text[last_end..end]);
236 }
237
238 last_end = end;
239 }
240
241 replaced_text.push_str(&text[last_end..]);
242
243 replaced_text
244}