1use crate::{
4 error::{SzError, SzResult},
5 ffi_call,
6 flags::SzFlags,
7 process_engine_result,
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::Sz_primeEngine());
25 Ok(())
26 }
27
28 fn get_stats(&self) -> SzResult<JsonString> {
29 let result = unsafe { crate::ffi::Sz_stats_helper() };
30 process_engine_result!(result)
31 }
32
33 fn add_record(
34 &self,
35 data_source_code: &str,
36 record_id: &str,
37 record_definition: &str,
38 flags: Option<SzFlags>,
39 ) -> SzResult<JsonString> {
40 let data_source_c = crate::ffi::helpers::str_to_c_string(data_source_code)?;
41 let record_id_c = crate::ffi::helpers::str_to_c_string(record_id)?;
42 let record_def_c = crate::ffi::helpers::str_to_c_string(record_definition)?;
43 let flags_bits = flags.unwrap_or(SzFlags::ADD_RECORD_DEFAULT_FLAGS).bits() as i64;
44
45 let result = unsafe {
46 crate::ffi::Sz_addRecordWithInfo_helper(
47 data_source_c.as_ptr(),
48 record_id_c.as_ptr(),
49 record_def_c.as_ptr(),
50 flags_bits,
51 )
52 };
53
54 process_engine_result!(result)
55 }
56
57 fn get_record_preview(
58 &self,
59 record_definition: &str,
60 flags: Option<SzFlags>,
61 ) -> SzResult<JsonString> {
62 let record_def_c = crate::ffi::helpers::str_to_c_string(record_definition)?;
63 let flags_bits = flags.unwrap_or(SzFlags::RECORD_DEFAULT_FLAGS).bits() as i64;
64
65 let result =
66 unsafe { crate::ffi::Sz_getRecordPreview_helper(record_def_c.as_ptr(), flags_bits) };
67
68 process_engine_result!(result)
69 }
70
71 fn delete_record(
72 &self,
73 data_source_code: &str,
74 record_id: &str,
75 flags: Option<SzFlags>,
76 ) -> SzResult<JsonString> {
77 let data_source_c = crate::ffi::helpers::str_to_c_string(data_source_code)?;
78 let record_id_c = crate::ffi::helpers::str_to_c_string(record_id)?;
79 let flags_bits = flags.unwrap_or(SzFlags::DELETE_RECORD_DEFAULT_FLAGS).bits() as i64;
80
81 let result = unsafe {
82 crate::ffi::Sz_deleteRecordWithInfo_helper(
83 data_source_c.as_ptr(),
84 record_id_c.as_ptr(),
85 flags_bits,
86 )
87 };
88
89 process_engine_result!(result)
90 }
91
92 fn reevaluate_record(
93 &self,
94 data_source_code: &str,
95 record_id: &str,
96 flags: Option<SzFlags>,
97 ) -> SzResult<JsonString> {
98 let data_source_c = crate::ffi::helpers::str_to_c_string(data_source_code)?;
99 let record_id_c = crate::ffi::helpers::str_to_c_string(record_id)?;
100 let flags_bits = flags
101 .unwrap_or(SzFlags::REEVALUATE_RECORD_DEFAULT_FLAGS)
102 .bits() as i64;
103
104 let result = unsafe {
105 crate::ffi::Sz_reevaluateRecordWithInfo_helper(
106 data_source_c.as_ptr(),
107 record_id_c.as_ptr(),
108 flags_bits,
109 )
110 };
111
112 process_engine_result!(result)
113 }
114
115 fn reevaluate_entity(
116 &self,
117 entity_id: EntityId,
118 flags: Option<SzFlags>,
119 ) -> SzResult<JsonString> {
120 let flags_bits = flags
121 .unwrap_or(SzFlags::REEVALUATE_ENTITY_DEFAULT_FLAGS)
122 .bits() as i64;
123
124 let result =
125 unsafe { crate::ffi::Sz_reevaluateEntityWithInfo_helper(entity_id, flags_bits) };
126
127 process_engine_result!(result)
128 }
129
130 fn search_by_attributes(
131 &self,
132 attributes: &str,
133 search_profile: Option<&str>,
134 flags: Option<SzFlags>,
135 ) -> SzResult<JsonString> {
136 let attributes_c = crate::ffi::helpers::str_to_c_string(attributes)?;
137 let flags_bits = flags
138 .unwrap_or(SzFlags::SEARCH_BY_ATTRIBUTES_DEFAULT_FLAGS)
139 .bits() as i64;
140
141 if let Some(profile) = search_profile {
143 let search_profile_c = crate::ffi::helpers::str_to_c_string(profile)?;
144 let result = unsafe {
145 crate::ffi::Sz_searchByAttributes_V3_helper(
146 attributes_c.as_ptr(),
147 search_profile_c.as_ptr(),
148 flags_bits,
149 )
150 };
151 process_engine_result!(result)
152 } else {
153 let result = unsafe {
154 crate::ffi::Sz_searchByAttributes_V2_helper(attributes_c.as_ptr(), flags_bits)
155 };
156 process_engine_result!(result)
157 }
158 }
159
160 fn why_search(
161 &self,
162 attributes: &str,
163 entity_id: EntityId,
164 search_profile: Option<&str>,
165 flags: Option<SzFlags>,
166 ) -> SzResult<JsonString> {
167 let attributes_c = crate::ffi::helpers::str_to_c_string(attributes)?;
168 let search_profile_c = search_profile
169 .map(crate::ffi::helpers::str_to_c_string)
170 .transpose()?;
171 let search_profile_ptr = search_profile_c
172 .as_ref()
173 .map(|c_str| c_str.as_ptr())
174 .unwrap_or(std::ptr::null());
175 let flags_bits = flags.unwrap_or(SzFlags::WHY_SEARCH_DEFAULT_FLAGS).bits() as i64;
176
177 let result = unsafe {
178 crate::ffi::Sz_whySearch_V2_helper(
179 attributes_c.as_ptr(),
180 entity_id,
181 search_profile_ptr,
182 flags_bits,
183 )
184 };
185
186 process_engine_result!(result)
187 }
188
189 fn get_entity(&self, entity_ref: EntityRef, flags: Option<SzFlags>) -> SzResult<JsonString> {
190 let flags_bits = flags.unwrap_or(SzFlags::ENTITY_DEFAULT_FLAGS).bits() as i64;
191
192 match entity_ref {
193 EntityRef::Id(entity_id) => {
194 let result =
195 unsafe { crate::ffi::Sz_getEntityByEntityID_V2_helper(entity_id, flags_bits) };
196 process_engine_result!(result)
197 }
198 EntityRef::Record {
199 data_source,
200 record_id,
201 } => {
202 let data_source_c = crate::ffi::helpers::str_to_c_string(data_source)?;
203 let record_id_c = crate::ffi::helpers::str_to_c_string(record_id)?;
204 let result = unsafe {
205 crate::ffi::Sz_getEntityByRecordID_V2_helper(
206 data_source_c.as_ptr(),
207 record_id_c.as_ptr(),
208 flags_bits,
209 )
210 };
211 process_engine_result!(result)
212 }
213 }
214 }
215
216 fn get_record(
217 &self,
218 data_source_code: &str,
219 record_id: &str,
220 flags: Option<SzFlags>,
221 ) -> SzResult<JsonString> {
222 let data_source_c = crate::ffi::helpers::str_to_c_string(data_source_code)?;
223 let record_id_c = crate::ffi::helpers::str_to_c_string(record_id)?;
224 let flags_bits = flags.unwrap_or(SzFlags::RECORD_DEFAULT_FLAGS).bits() as i64;
225
226 let result = unsafe {
228 crate::ffi::Sz_getRecord_V2_helper(
229 data_source_c.as_ptr(),
230 record_id_c.as_ptr(),
231 flags_bits,
232 )
233 };
234
235 process_engine_result!(result)
236 }
237
238 fn find_interesting_entities(
239 &self,
240 entity_ref: EntityRef,
241 flags: Option<SzFlags>,
242 ) -> SzResult<JsonString> {
243 let flags_bits = flags
244 .unwrap_or(SzFlags::FIND_INTERESTING_ENTITIES_DEFAULT_FLAGS)
245 .bits() as i64;
246
247 match entity_ref {
248 EntityRef::Id(entity_id) => {
249 let result = unsafe {
250 crate::ffi::Sz_findInterestingEntitiesByEntityID_helper(entity_id, flags_bits)
251 };
252 process_engine_result!(result)
253 }
254 EntityRef::Record {
255 data_source,
256 record_id,
257 } => {
258 let data_source_c = crate::ffi::helpers::str_to_c_string(data_source)?;
259 let record_id_c = crate::ffi::helpers::str_to_c_string(record_id)?;
260 let result = unsafe {
261 crate::ffi::Sz_findInterestingEntitiesByRecordID_helper(
262 data_source_c.as_ptr(),
263 record_id_c.as_ptr(),
264 flags_bits,
265 )
266 };
267 process_engine_result!(result)
268 }
269 }
270 }
271
272 fn find_path(
273 &self,
274 start_entity_id: EntityId,
275 end_entity_id: EntityId,
276 max_degrees: i64,
277 _avoid_entity_ids: Option<&HashSet<EntityId>>,
278 _required_data_sources: Option<&HashSet<String>>,
279 flags: Option<SzFlags>,
280 ) -> SzResult<JsonString> {
281 let flags_bits = flags.unwrap_or(SzFlags::FIND_PATH_DEFAULT_FLAGS).bits() as i64;
282
283 let result = unsafe {
285 crate::ffi::Sz_findPathByEntityID_V2_helper(
286 start_entity_id,
287 end_entity_id,
288 max_degrees,
289 flags_bits,
290 )
291 };
292
293 process_engine_result!(result)
294 }
295
296 fn find_network(
297 &self,
298 entity_list: &[EntityId],
299 max_degrees: i64,
300 build_out_degree: i64,
301 max_entities: i64,
302 flags: Option<SzFlags>,
303 ) -> SzResult<JsonString> {
304 let entity_objects: Vec<serde_json::Value> = entity_list
305 .iter()
306 .map(|&id| serde_json::json!({"ENTITY_ID": id}))
307 .collect();
308
309 let entity_list_json = serde_json::json!({
310 "ENTITIES": entity_objects
311 })
312 .to_string();
313
314 let entity_list_c = crate::ffi::helpers::str_to_c_string(&entity_list_json)?;
315 let flags_bits = flags.unwrap_or(SzFlags::FIND_NETWORK_DEFAULT_FLAGS).bits() as i64;
316
317 let result = unsafe {
318 crate::ffi::Sz_findNetworkByEntityID_V2_helper(
319 entity_list_c.as_ptr(),
320 max_degrees,
321 build_out_degree,
322 max_entities,
323 flags_bits,
324 )
325 };
326
327 process_engine_result!(result)
328 }
329
330 fn why_entities(
331 &self,
332 entity_id1: EntityId,
333 entity_id2: EntityId,
334 flags: Option<SzFlags>,
335 ) -> SzResult<JsonString> {
336 let flags_bits = flags.unwrap_or(SzFlags::WHY_ENTITIES_DEFAULT_FLAGS).bits() as i64;
337
338 let result =
340 unsafe { crate::ffi::Sz_whyEntities_V2_helper(entity_id1, entity_id2, flags_bits) };
341
342 process_engine_result!(result)
343 }
344
345 fn why_records(
346 &self,
347 data_source_code1: &str,
348 record_id1: &str,
349 data_source_code2: &str,
350 record_id2: &str,
351 flags: Option<SzFlags>,
352 ) -> SzResult<JsonString> {
353 let data_source1_c = crate::ffi::helpers::str_to_c_string(data_source_code1)?;
354 let record_id1_c = crate::ffi::helpers::str_to_c_string(record_id1)?;
355 let data_source2_c = crate::ffi::helpers::str_to_c_string(data_source_code2)?;
356 let record_id2_c = crate::ffi::helpers::str_to_c_string(record_id2)?;
357 let flags_bits = flags.unwrap_or(SzFlags::WHY_RECORDS_DEFAULT_FLAGS).bits() as i64;
358
359 let result = unsafe {
361 crate::ffi::Sz_whyRecords_V2_helper(
362 data_source1_c.as_ptr(),
363 record_id1_c.as_ptr(),
364 data_source2_c.as_ptr(),
365 record_id2_c.as_ptr(),
366 flags_bits,
367 )
368 };
369
370 process_engine_result!(result)
371 }
372
373 fn why_record_in_entity(
374 &self,
375 data_source_code: &str,
376 record_id: &str,
377 flags: Option<SzFlags>,
378 ) -> SzResult<JsonString> {
379 let data_source_c = crate::ffi::helpers::str_to_c_string(data_source_code)?;
380 let record_id_c = crate::ffi::helpers::str_to_c_string(record_id)?;
381 let flags_bits = flags.unwrap_or(SzFlags::WHY_RECORDS_DEFAULT_FLAGS).bits() as i64;
382
383 let result = unsafe {
385 crate::ffi::Sz_whyRecordInEntity_V2_helper(
386 data_source_c.as_ptr(),
387 record_id_c.as_ptr(),
388 flags_bits,
389 )
390 };
391
392 process_engine_result!(result)
393 }
394
395 fn how_entity(&self, entity_id: EntityId, flags: Option<SzFlags>) -> SzResult<JsonString> {
396 let flags_bits = flags.unwrap_or(SzFlags::HOW_ENTITY_DEFAULT_FLAGS).bits() as i64;
397
398 let result = unsafe { crate::ffi::Sz_howEntityByEntityID_V2_helper(entity_id, flags_bits) };
400
401 process_engine_result!(result)
402 }
403
404 fn get_virtual_entity(
405 &self,
406 record_keys: &[(String, String)],
407 flags: Option<SzFlags>,
408 ) -> SzResult<JsonString> {
409 if record_keys.is_empty() {
410 return Err(SzError::configuration("No record keys provided"));
411 }
412
413 let record_objects: Vec<serde_json::Value> = record_keys
414 .iter()
415 .map(|(data_source, record_id)| {
416 serde_json::json!({
417 "DATA_SOURCE": data_source,
418 "RECORD_ID": record_id
419 })
420 })
421 .collect();
422
423 let record_list_json = serde_json::json!({
424 "RECORDS": record_objects
425 })
426 .to_string();
427
428 let record_list_c = crate::ffi::helpers::str_to_c_string(&record_list_json)?;
429 let flags_bits = flags
430 .unwrap_or(SzFlags::VIRTUAL_ENTITY_DEFAULT_FLAGS)
431 .bits() as i64;
432
433 let result = unsafe {
434 crate::ffi::Sz_getVirtualEntityByRecordID_V2_helper(record_list_c.as_ptr(), flags_bits)
435 };
436
437 process_engine_result!(result)
438 }
439
440 fn process_redo_record(
441 &self,
442 redo_record: &str,
443 _flags: Option<SzFlags>,
444 ) -> SzResult<JsonString> {
445 let redo_record_c = crate::ffi::helpers::str_to_c_string(redo_record)?;
446 let result =
448 unsafe { crate::ffi::Sz_processRedoRecordWithInfo_helper(redo_record_c.as_ptr()) };
449
450 process_engine_result!(result)
451 }
452
453 fn get_redo_record(&self) -> SzResult<JsonString> {
454 let result = unsafe { crate::ffi::Sz_getRedoRecord_helper() };
455 process_engine_result!(result)
456 }
457
458 fn count_redo_records(&self) -> SzResult<i64> {
459 let count = unsafe { crate::ffi::Sz_countRedoRecords() };
460 Ok(count)
461 }
462
463 fn export_json_entity_report(&self, flags: Option<SzFlags>) -> SzResult<ExportHandle> {
464 let flags_bits = flags.unwrap_or_default().bits() as i64;
465
466 let result = unsafe { crate::ffi::Sz_exportJSONEntityReport_helper(flags_bits) };
467
468 crate::ffi::helpers::check_return_code(result.returnCode)?;
469 Ok(result.exportHandle as ExportHandle)
470 }
471
472 fn export_csv_entity_report(
473 &self,
474 csv_column_list: &str,
475 flags: Option<SzFlags>,
476 ) -> SzResult<ExportHandle> {
477 let csv_columns_c = crate::ffi::helpers::str_to_c_string(csv_column_list)?;
478 let flags_bits = flags.unwrap_or_default().bits() as i64;
479
480 let result = unsafe {
481 crate::ffi::Sz_exportCSVEntityReport_helper(csv_columns_c.as_ptr(), flags_bits)
482 };
483
484 crate::ffi::helpers::check_return_code(result.returnCode)?;
485 Ok(result.exportHandle as ExportHandle)
486 }
487
488 fn fetch_next(&self, export_handle: ExportHandle) -> SzResult<JsonString> {
489 let result = unsafe { crate::ffi::Sz_fetchNext_helper(export_handle as usize) };
490
491 process_engine_result!(result)
492 }
493
494 fn close_export(&self, export_handle: ExportHandle) -> SzResult<()> {
495 ffi_call!(crate::ffi::Sz_closeExportReport_helper(
496 export_handle as usize
497 ));
498 Ok(())
499 }
500}