1#![allow(unused_variables)]
3
4use crate::{
5 error::{SzError, SzResult},
6 ffi_call,
7 flags::SzFlags,
8 traits::SzEngine,
9 types::*,
10};
11use std::collections::HashSet;
12
13pub struct SzEngineCore;
15
16impl SzEngineCore {
17 pub fn new() -> SzResult<Self> {
18 Ok(Self)
19 }
20}
21
22impl SzEngine for SzEngineCore {
23 fn prime_engine(&self) -> SzResult<()> {
24 ffi_call!(crate::ffi::bindings::Sz_primeEngine());
25 Ok(())
26 }
27
28 fn get_stats(&self) -> SzResult<JsonString> {
29 unsafe {
30 let result = crate::ffi::bindings::Sz_stats_helper();
31 crate::ffi::helpers::process_pointer_result(result)
32 }
33 }
34
35 fn add_record(
36 &self,
37 data_source_code: &str,
38 record_id: &str,
39 record_definition: &str,
40 flags: Option<SzFlags>,
41 ) -> SzResult<JsonString> {
42 let data_source_c = crate::ffi::helpers::str_to_c_string(data_source_code)?;
43 let record_id_c = crate::ffi::helpers::str_to_c_string(record_id)?;
44 let record_def_c = crate::ffi::helpers::str_to_c_string(record_definition)?;
45 let flags_bits = flags.unwrap_or(SzFlags::ADD_RECORD_DEFAULT).bits() as i64;
46
47 let result = unsafe {
48 crate::ffi::bindings::Sz_addRecordWithInfo_helper(
49 data_source_c.as_ptr(),
50 record_id_c.as_ptr(),
51 record_def_c.as_ptr(),
52 flags_bits,
53 )
54 };
55
56 unsafe { crate::ffi::helpers::process_engine_pointer_result(result) }
57 }
58
59 fn get_record_preview(
60 &self,
61 record_definition: &str,
62 flags: Option<SzFlags>,
63 ) -> SzResult<JsonString> {
64 let record_def_c = crate::ffi::helpers::str_to_c_string(record_definition)?;
65 let flags_bits = flags.unwrap_or(SzFlags::GET_RECORD_DEFAULT).bits() as i64;
66
67 let result = unsafe {
68 crate::ffi::bindings::Sz_getRecordPreview_helper(record_def_c.as_ptr(), flags_bits)
69 };
70
71 unsafe { crate::ffi::helpers::process_pointer_result(result) }
72 }
73
74 fn delete_record(
75 &self,
76 data_source_code: &str,
77 record_id: &str,
78 flags: Option<SzFlags>,
79 ) -> SzResult<JsonString> {
80 let data_source_c = crate::ffi::helpers::str_to_c_string(data_source_code)?;
81 let record_id_c = crate::ffi::helpers::str_to_c_string(record_id)?;
82 let flags_bits = flags.unwrap_or(SzFlags::DELETE_RECORD_DEFAULT).bits() as i64;
83
84 let result = unsafe {
85 crate::ffi::bindings::Sz_deleteRecordWithInfo_helper(
86 data_source_c.as_ptr(),
87 record_id_c.as_ptr(),
88 flags_bits,
89 )
90 };
91
92 unsafe { crate::ffi::helpers::process_engine_pointer_result(result) }
93 }
94
95 fn reevaluate_record(
96 &self,
97 data_source_code: &str,
98 record_id: &str,
99 flags: Option<SzFlags>,
100 ) -> SzResult<JsonString> {
101 let data_source_c = crate::ffi::helpers::str_to_c_string(data_source_code)?;
102 let record_id_c = crate::ffi::helpers::str_to_c_string(record_id)?;
103 let flags_bits = flags.unwrap_or(SzFlags::REEVALUATE_RECORD_DEFAULT).bits() as i64;
104
105 let result = unsafe {
106 crate::ffi::bindings::Sz_reevaluateRecordWithInfo_helper(
107 data_source_c.as_ptr(),
108 record_id_c.as_ptr(),
109 flags_bits,
110 )
111 };
112
113 unsafe { crate::ffi::helpers::process_pointer_result(result) }
114 }
115
116 fn reevaluate_entity(
117 &self,
118 entity_id: EntityId,
119 flags: Option<SzFlags>,
120 ) -> SzResult<JsonString> {
121 let flags_value =
122 flags.unwrap_or(SzFlags::REEVALUATE_ENTITY_DEFAULT).bits() as libc::c_longlong;
123
124 let result = unsafe {
125 crate::ffi::bindings::Sz_reevaluateEntityWithInfo_helper(entity_id, flags_value)
126 };
127
128 unsafe { crate::ffi::helpers::process_pointer_result(result) }
129 }
130
131 fn search_by_attributes(
132 &self,
133 attributes: &str,
134 search_profile: Option<&str>,
135 flags: Option<SzFlags>,
136 ) -> SzResult<JsonString> {
137 let attributes_c = crate::ffi::helpers::str_to_c_string(attributes)?;
138 let flags_bits = flags
139 .unwrap_or(SzFlags::SEARCH_BY_ATTRIBUTES_DEFAULT)
140 .bits() as i64;
141
142 let result = if let Some(profile) = search_profile {
143 let search_profile_c = crate::ffi::helpers::str_to_c_string(profile)?;
144 unsafe {
145 crate::ffi::bindings::Sz_searchByAttributes_V3_helper(
146 attributes_c.as_ptr(),
147 search_profile_c.as_ptr(),
148 flags_bits,
149 )
150 }
151 } else {
152 unsafe { crate::ffi::bindings::Sz_searchByAttributes_helper(attributes_c.as_ptr()) }
153 };
154
155 unsafe { crate::ffi::helpers::process_engine_pointer_result(result) }
156 }
157
158 fn why_search(
159 &self,
160 attributes: &str,
161 entity_id: EntityId,
162 search_profile: Option<&str>,
163 flags: Option<SzFlags>,
164 ) -> SzResult<JsonString> {
165 let attributes_c = crate::ffi::helpers::str_to_c_string(attributes)?;
166 let search_profile_c = search_profile
167 .map(crate::ffi::helpers::str_to_c_string)
168 .transpose()?;
169 let search_profile_ptr = search_profile_c
170 .as_ref()
171 .map(|c_str| c_str.as_ptr())
172 .unwrap_or(std::ptr::null());
173 let flags_bits = flags.unwrap_or(SzFlags::WHY_SEARCH_DEFAULT).bits() as i64;
174
175 let result = unsafe {
176 crate::ffi::bindings::Sz_whySearch_helper(
177 attributes_c.as_ptr(),
178 entity_id,
179 search_profile_ptr,
180 flags_bits,
181 )
182 };
183
184 unsafe { crate::ffi::helpers::process_pointer_result(result) }
185 }
186
187 fn get_entity(&self, entity_id: EntityId, flags: Option<SzFlags>) -> SzResult<JsonString> {
188 let result = unsafe { crate::ffi::bindings::Sz_getEntityByEntityID_helper(entity_id) };
189
190 unsafe { crate::ffi::helpers::process_engine_pointer_result(result) }
191 }
192
193 fn get_entity_by_record(
194 &self,
195 data_source_code: &str,
196 record_id: &str,
197 flags: Option<SzFlags>,
198 ) -> SzResult<JsonString> {
199 let data_source_c = crate::ffi::helpers::str_to_c_string(data_source_code)?;
200 let record_id_c = crate::ffi::helpers::str_to_c_string(record_id)?;
201 let flags_bits = flags.unwrap_or(SzFlags::GET_ENTITY_DEFAULT).bits() as i64;
202
203 let result = unsafe {
204 crate::ffi::bindings::Sz_getEntityByRecordID_helper(
205 data_source_c.as_ptr(),
206 record_id_c.as_ptr(),
207 )
208 };
209
210 unsafe { crate::ffi::helpers::process_engine_pointer_result(result) }
211 }
212
213 fn get_record(
214 &self,
215 data_source_code: &str,
216 record_id: &str,
217 flags: Option<SzFlags>,
218 ) -> SzResult<JsonString> {
219 let data_source_c = crate::ffi::helpers::str_to_c_string(data_source_code)?;
220 let record_id_c = crate::ffi::helpers::str_to_c_string(record_id)?;
221 let flags_value = flags.map(|f| f.bits() as i64).unwrap_or(0);
222
223 let result = unsafe {
224 crate::ffi::bindings::Sz_getRecord_helper(
225 data_source_c.as_ptr(),
226 record_id_c.as_ptr(),
227 flags_value,
228 )
229 };
230
231 if result.return_code != 0 {
232 crate::ffi::helpers::check_return_code(result.return_code)?;
233 }
234
235 unsafe { crate::ffi::helpers::c_str_to_string(result.response) }
236 }
237
238 fn find_interesting_entities_by_entity_id(
239 &self,
240 entity_id: EntityId,
241 flags: Option<SzFlags>,
242 ) -> SzResult<JsonString> {
243 let flags_bits = flags
244 .unwrap_or(SzFlags::FIND_INTERESTING_ENTITIES_DEFAULT)
245 .bits() as i64;
246
247 let result = unsafe {
248 crate::ffi::bindings::Sz_findInterestingEntitiesByEntityID_helper(entity_id, flags_bits)
249 };
250
251 unsafe { crate::ffi::helpers::process_pointer_result(result) }
252 }
253
254 fn find_interesting_entities_by_record(
255 &self,
256 data_source_code: &str,
257 record_id: &str,
258 flags: Option<SzFlags>,
259 ) -> SzResult<JsonString> {
260 let data_source_c = crate::ffi::helpers::str_to_c_string(data_source_code)?;
261 let record_id_c = crate::ffi::helpers::str_to_c_string(record_id)?;
262 let flags_bits = flags
263 .unwrap_or(SzFlags::FIND_INTERESTING_ENTITIES_DEFAULT)
264 .bits() as i64;
265
266 let result = unsafe {
267 crate::ffi::bindings::Sz_findInterestingEntitiesByRecordID_helper(
268 data_source_c.as_ptr(),
269 record_id_c.as_ptr(),
270 flags_bits,
271 )
272 };
273
274 unsafe { crate::ffi::helpers::process_pointer_result(result) }
275 }
276
277 fn find_path(
278 &self,
279 start_entity_id: EntityId,
280 end_entity_id: EntityId,
281 max_degrees: i64,
282 avoid_entity_ids: Option<&HashSet<EntityId>>,
283 required_data_sources: Option<&HashSet<String>>,
284 flags: Option<SzFlags>,
285 ) -> SzResult<JsonString> {
286 let flags_bits = flags.unwrap_or(SzFlags::FIND_PATH_DEFAULT).bits() as i64;
287
288 let result_ptr = unsafe {
289 crate::ffi::bindings::Sz_findPathByEntityID_helper(
290 start_entity_id,
291 end_entity_id,
292 max_degrees,
293 flags_bits,
294 )
295 };
296
297 if result_ptr.is_null() {
298 return Err(SzError::unknown("Failed to find path"));
299 }
300
301 unsafe { crate::ffi::helpers::c_str_to_string(result_ptr) }
302 }
303
304 fn find_network(
305 &self,
306 entity_list: &[EntityId],
307 max_degrees: i64,
308 build_out_degree: i64,
309 max_entities: i64,
310 flags: Option<SzFlags>,
311 ) -> SzResult<JsonString> {
312 let entity_objects: Vec<serde_json::Value> = entity_list
314 .iter()
315 .map(|&id| serde_json::json!({"ENTITY_ID": id}))
316 .collect();
317
318 let entity_list_json = serde_json::json!({
319 "ENTITIES": entity_objects
320 })
321 .to_string();
322
323 let entity_list_c = crate::ffi::helpers::str_to_c_string(&entity_list_json)?;
324 let flags_bits = flags.unwrap_or(SzFlags::FIND_NETWORK_DEFAULT).bits() as i64;
325
326 let result = unsafe {
327 crate::ffi::bindings::Sz_findNetworkByEntityID_V2_helper(
328 entity_list_c.as_ptr(),
329 max_degrees,
330 build_out_degree,
331 max_entities,
332 flags_bits,
333 )
334 };
335
336 if result.return_code != 0 {
338 crate::ffi::helpers::check_return_code(result.return_code)?;
339 }
340
341 unsafe { crate::ffi::helpers::c_str_to_string(result.response) }
342 }
343
344 fn why_entity(
345 &self,
346 entity_id1: EntityId,
347 entity_id2: EntityId,
348 flags: Option<SzFlags>,
349 ) -> SzResult<JsonString> {
350 let flags_value = flags.unwrap_or(SzFlags::WHY_ENTITY_DEFAULT).bits() as libc::c_longlong;
351
352 let result = unsafe {
353 crate::ffi::bindings::Sz_whyEntities_helper(entity_id1, entity_id2, flags_value)
354 };
355
356 unsafe { crate::ffi::helpers::process_pointer_result(result) }
357 }
358
359 fn why_records(
360 &self,
361 data_source_code1: &str,
362 record_id1: &str,
363 data_source_code2: &str,
364 record_id2: &str,
365 flags: Option<SzFlags>,
366 ) -> SzResult<JsonString> {
367 let data_source1_c = crate::ffi::helpers::str_to_c_string(data_source_code1)?;
368 let record_id1_c = crate::ffi::helpers::str_to_c_string(record_id1)?;
369 let data_source2_c = crate::ffi::helpers::str_to_c_string(data_source_code2)?;
370 let record_id2_c = crate::ffi::helpers::str_to_c_string(record_id2)?;
371 let flags_bits = flags.unwrap_or(SzFlags::WHY_RECORD_DEFAULT).bits() as i64;
372
373 let result = unsafe {
374 crate::ffi::bindings::Sz_whyRecords_helper(
375 data_source1_c.as_ptr(),
376 record_id1_c.as_ptr(),
377 data_source2_c.as_ptr(),
378 record_id2_c.as_ptr(),
379 flags_bits,
380 )
381 };
382
383 unsafe { crate::ffi::helpers::process_pointer_result(result) }
384 }
385
386 fn why_record_in_entity(
387 &self,
388 data_source_code: &str,
389 record_id: &str,
390 flags: Option<SzFlags>,
391 ) -> SzResult<JsonString> {
392 let data_source_c = crate::ffi::helpers::str_to_c_string(data_source_code)?;
393 let record_id_c = crate::ffi::helpers::str_to_c_string(record_id)?;
394 let flags_bits = flags.unwrap_or(SzFlags::WHY_RECORD_DEFAULT).bits() as i64;
395
396 let result = unsafe {
397 crate::ffi::bindings::Sz_whyRecordInEntity_helper(
398 data_source_c.as_ptr(),
399 record_id_c.as_ptr(),
400 flags_bits,
401 )
402 };
403
404 unsafe { crate::ffi::helpers::process_pointer_result(result) }
405 }
406
407 fn how_entity(&self, entity_id: EntityId, flags: Option<SzFlags>) -> SzResult<JsonString> {
408 let flags_bits = flags.unwrap_or(SzFlags::HOW_ENTITY_DEFAULT).bits() as i64;
409
410 let result =
411 unsafe { crate::ffi::bindings::Sz_howEntityByEntityID_helper(entity_id, flags_bits) };
412
413 unsafe { crate::ffi::helpers::process_pointer_result(result) }
414 }
415
416 fn get_virtual_entity(
417 &self,
418 record_keys: &[(String, String)],
419 flags: Option<SzFlags>,
420 ) -> SzResult<JsonString> {
421 if record_keys.is_empty() {
426 return Err(SzError::configuration("No record keys provided"));
427 }
428
429 if record_keys.len() == 1 {
431 let (data_source, record_id) = &record_keys[0];
432 let data_source_c = crate::ffi::helpers::str_to_c_string(data_source)?;
433 let record_id_c = crate::ffi::helpers::str_to_c_string(record_id)?;
434
435 let result = unsafe {
436 crate::ffi::bindings::Sz_getVirtualEntityByRecordID_helper(
437 data_source_c.as_ptr(),
438 record_id_c.as_ptr(),
439 )
440 };
441
442 unsafe { crate::ffi::helpers::process_pointer_result(result) }
443 } else {
444 Err(SzError::configuration(
446 "Multiple record keys for get_virtual_entity not yet supported. Native library only supports single record.",
447 ))
448 }
449 }
450
451 fn process_redo_record(
452 &self,
453 redo_record: &str,
454 flags: Option<SzFlags>,
455 ) -> SzResult<JsonString> {
456 let redo_record_c = crate::ffi::helpers::str_to_c_string(redo_record)?;
457 let flags_bits = flags.unwrap_or_default().bits() as i64;
458
459 let result = unsafe {
460 crate::ffi::bindings::Sz_processRedoRecordWithInfo_helper(
461 redo_record_c.as_ptr(),
462 flags_bits,
463 )
464 };
465
466 unsafe { crate::ffi::helpers::process_pointer_result(result) }
467 }
468
469 fn get_redo_record(&self) -> SzResult<JsonString> {
470 let result = unsafe { crate::ffi::bindings::Sz_getRedoRecord_helper() };
471 unsafe { crate::ffi::helpers::process_pointer_result(result) }
472 }
473
474 fn count_redo_records(&self) -> SzResult<i64> {
475 let count = unsafe { crate::ffi::bindings::Sz_countRedoRecords() };
476 Ok(count)
477 }
478
479 fn export_json_entity_report(&self, flags: Option<SzFlags>) -> SzResult<ExportHandle> {
480 let flags_bits = flags.unwrap_or_default().bits() as i64;
481
482 let result = unsafe { crate::ffi::bindings::Sz_exportJSONEntityReport_helper(flags_bits) };
483
484 let export_handle_str =
485 unsafe { crate::ffi::helpers::process_engine_pointer_result(result) }?;
486
487 export_handle_str
489 .parse()
490 .map_err(|_| SzError::ffi("Invalid export handle"))
491 }
492
493 fn export_csv_entity_report(
494 &self,
495 csv_column_list: &str,
496 flags: Option<SzFlags>,
497 ) -> SzResult<ExportHandle> {
498 let csv_columns_c = crate::ffi::helpers::str_to_c_string(csv_column_list)?;
499 let flags_bits = flags.unwrap_or_default().bits() as i64;
500
501 let result = unsafe {
502 crate::ffi::bindings::Sz_exportCSVEntityReport_helper(
503 csv_columns_c.as_ptr(),
504 flags_bits,
505 )
506 };
507
508 let export_handle_str =
509 unsafe { crate::ffi::helpers::process_engine_pointer_result(result) }?;
510
511 export_handle_str
513 .parse()
514 .map_err(|_| SzError::ffi("Invalid export handle"))
515 }
516
517 fn fetch_next(&self, export_handle: ExportHandle) -> SzResult<JsonString> {
518 let handle_str = export_handle.to_string();
519 let handle_c = crate::ffi::helpers::str_to_c_string(&handle_str)?;
520
521 let result = unsafe { crate::ffi::bindings::Sz_fetchNext_helper(handle_c.as_ptr()) };
522
523 unsafe { crate::ffi::helpers::process_engine_pointer_result(result) }
524 }
525
526 fn close_export(&self, export_handle: ExportHandle) -> SzResult<()> {
527 let handle_str = export_handle.to_string();
528 let handle_c = crate::ffi::helpers::str_to_c_string(&handle_str)?;
529
530 ffi_call!(crate::ffi::bindings::Sz_closeExportReport_helper(
531 handle_c.as_ptr()
532 ));
533 Ok(())
534 }
535}
536
537