sz_rust_sdk/
traits.rs

1//! Core traits defining the Senzing SDK interface
2//!
3//! This module contains the main trait definitions that mirror the C# SDK interfaces.
4//! These traits define the contract for interacting with the Senzing engine.
5
6use crate::{error::SzResult, flags::SzFlags, types::*};
7use std::collections::HashSet;
8
9/// Main entry point and factory for Senzing SDK components.
10///
11/// The `SzEnvironment` trait provides the primary interface for initializing
12/// the Senzing SDK and obtaining instances of other SDK components. This is
13/// the first interface you interact with when using the SDK.
14///
15/// # Example
16///
17/// ```
18/// # use sz_rust_sdk::helpers::ExampleEnvironment;
19/// # let env = ExampleEnvironment::initialize("doctest_sz_environment")?;
20/// use sz_rust_sdk::prelude::*;
21///
22/// // Get component interfaces
23/// let engine = env.get_engine()?;
24/// let product = env.get_product()?;
25/// # Ok::<(), SzError>(())
26/// ```
27///
28/// # Singleton Pattern
29///
30/// `SzEnvironmentCore` implements a singleton pattern. Multiple calls to
31/// `get_instance` with the same parameters return the same instance.
32pub trait SzEnvironment: Send + Sync {
33    /// Checks if the environment has been destroyed.
34    ///
35    /// # Returns
36    ///
37    /// `true` if `destroy()` has been called, `false` otherwise.
38    ///
39    /// # Examples
40    ///
41    /// ```
42    /// # use sz_rust_sdk::helpers::ExampleEnvironment;
43    /// use sz_rust_sdk::prelude::*;
44    ///
45    /// # let env = ExampleEnvironment::initialize("doctest_is_destroyed")?;
46    /// let destroyed = env.is_destroyed();
47    /// assert!(!destroyed);
48    /// # Ok::<(), SzError>(())
49    /// ```
50    fn is_destroyed(&self) -> bool;
51
52    /// Reinitializes the environment with a different configuration.
53    ///
54    /// Switches to a different registered configuration without destroying
55    /// the environment. This is thread-safe and can be called while other
56    /// operations are in progress.
57    ///
58    /// # Arguments
59    ///
60    /// * `config_id` - ID of a registered configuration to activate
61    ///
62    /// # Examples
63    ///
64    /// ```
65    /// # use sz_rust_sdk::helpers::ExampleEnvironment;
66    /// use sz_rust_sdk::prelude::*;
67    ///
68    /// # let env = ExampleEnvironment::initialize("doctest_reinitialize")?;
69    /// let config_id = env.get_active_config_id()?;
70    /// env.reinitialize(config_id)?;
71    /// # Ok::<(), SzError>(())
72    /// ```
73    ///
74    /// # Errors
75    ///
76    /// * `SzError::NotFound` - Configuration ID does not exist
77    /// * `SzError::EnvironmentDestroyed` - Environment was destroyed
78    fn reinitialize(&self, config_id: ConfigId) -> SzResult<()>;
79
80    /// Gets the currently active configuration ID.
81    ///
82    /// # Returns
83    ///
84    /// The configuration ID currently in use by the engine.
85    ///
86    /// # Examples
87    ///
88    /// ```
89    /// # use sz_rust_sdk::helpers::ExampleEnvironment;
90    /// use sz_rust_sdk::prelude::*;
91    ///
92    /// # let env = ExampleEnvironment::initialize("doctest_get_active_config_id")?;
93    /// let config_id = env.get_active_config_id()?;
94    /// println!("Active config ID: {}", config_id);
95    /// # Ok::<(), SzError>(())
96    /// ```
97    ///
98    /// # Errors
99    ///
100    /// * `SzError::EnvironmentDestroyed` - Environment was destroyed
101    fn get_active_config_id(&self) -> SzResult<ConfigId>;
102
103    /// Gets the product interface for version and license information.
104    ///
105    /// # Returns
106    ///
107    /// An [`SzProduct`] instance for querying product information.
108    ///
109    /// # Examples
110    ///
111    /// ```
112    /// # use sz_rust_sdk::helpers::ExampleEnvironment;
113    /// use sz_rust_sdk::prelude::*;
114    ///
115    /// # let env = ExampleEnvironment::initialize("doctest_get_product")?;
116    /// let product = env.get_product()?;
117    /// let version = product.get_version()?;
118    /// println!("Senzing version: {}", version);
119    /// # Ok::<(), SzError>(())
120    /// ```
121    ///
122    /// # Errors
123    ///
124    /// * `SzError::EnvironmentDestroyed` - Environment was destroyed
125    fn get_product(&self) -> SzResult<Box<dyn SzProduct>>;
126
127    /// Gets the engine interface for entity resolution operations.
128    ///
129    /// # Returns
130    ///
131    /// An [`SzEngine`] instance for adding records, searching, and analysis.
132    ///
133    /// # Examples
134    ///
135    /// ```
136    /// # use sz_rust_sdk::helpers::ExampleEnvironment;
137    /// use sz_rust_sdk::prelude::*;
138    ///
139    /// # let env = ExampleEnvironment::initialize("doctest_get_engine")?;
140    /// let engine = env.get_engine()?;
141    /// # Ok::<(), SzError>(())
142    /// ```
143    ///
144    /// # Errors
145    ///
146    /// * `SzError::EnvironmentDestroyed` - Environment was destroyed
147    fn get_engine(&self) -> SzResult<Box<dyn SzEngine>>;
148
149    /// Gets the configuration manager interface.
150    ///
151    /// # Returns
152    ///
153    /// An [`SzConfigManager`] instance for managing configuration versions.
154    ///
155    /// # Examples
156    ///
157    /// ```
158    /// # use sz_rust_sdk::helpers::ExampleEnvironment;
159    /// use sz_rust_sdk::prelude::*;
160    ///
161    /// # let env = ExampleEnvironment::initialize("doctest_get_config_manager")?;
162    /// let config_mgr = env.get_config_manager()?;
163    /// # Ok::<(), SzError>(())
164    /// ```
165    ///
166    /// # Errors
167    ///
168    /// * `SzError::EnvironmentDestroyed` - Environment was destroyed
169    fn get_config_manager(&self) -> SzResult<Box<dyn SzConfigManager>>;
170
171    /// Gets the diagnostic interface for system monitoring.
172    ///
173    /// # Returns
174    ///
175    /// An [`SzDiagnostic`] instance for performance testing and repository info.
176    ///
177    /// # Examples
178    ///
179    /// ```
180    /// # use sz_rust_sdk::helpers::ExampleEnvironment;
181    /// use sz_rust_sdk::prelude::*;
182    ///
183    /// # let env = ExampleEnvironment::initialize("doctest_get_diagnostic")?;
184    /// let diagnostic = env.get_diagnostic()?;
185    /// # Ok::<(), SzError>(())
186    /// ```
187    ///
188    /// # Errors
189    ///
190    /// * `SzError::EnvironmentDestroyed` - Environment was destroyed
191    fn get_diagnostic(&self) -> SzResult<Box<dyn SzDiagnostic>>;
192}
193
194/// Core entity resolution engine operations.
195///
196/// The `SzEngine` trait provides methods for adding records, retrieving entities,
197/// performing searches, and conducting various types of analysis. This is the
198/// primary interface for entity resolution operations.
199///
200/// # Obtaining an Instance
201///
202/// ```
203/// # use sz_rust_sdk::helpers::ExampleEnvironment;
204/// # let env = ExampleEnvironment::initialize("doctest_sz_engine")?;
205/// use sz_rust_sdk::prelude::*;
206///
207/// let engine = env.get_engine()?;
208/// # Ok::<(), SzError>(())
209/// ```
210pub trait SzEngine: Send + Sync {
211    /// Primes the engine for optimal performance.
212    ///
213    /// Loads internal caches and prepares the engine for high-throughput operations.
214    /// Call this once after initialization when processing large batches of records.
215    ///
216    /// # Examples
217    ///
218    /// ```
219    /// # use sz_rust_sdk::helpers::ExampleEnvironment;
220    /// use sz_rust_sdk::prelude::*;
221    ///
222    /// # let env = ExampleEnvironment::initialize("doctest_prime_engine")?;
223    /// let engine = env.get_engine()?;
224    ///
225    /// engine.prime_engine()?;
226    /// # Ok::<(), SzError>(())
227    /// ```
228    ///
229    /// # Errors
230    ///
231    /// Returns `SzError::NotInitialized` if the environment is not initialized.
232    fn prime_engine(&self) -> SzResult<()>;
233
234    /// Gets engine performance statistics.
235    ///
236    /// Returns a JSON object containing internal performance metrics useful for
237    /// monitoring and debugging.
238    ///
239    /// # Returns
240    ///
241    /// JSON string with engine statistics including cache hit rates and timing data.
242    ///
243    /// # Examples
244    ///
245    /// ```
246    /// # use sz_rust_sdk::helpers::ExampleEnvironment;
247    /// use sz_rust_sdk::prelude::*;
248    ///
249    /// # let env = ExampleEnvironment::initialize("doctest_get_stats")?;
250    /// let engine = env.get_engine()?;
251    ///
252    /// let stats = engine.get_stats()?;
253    /// assert!(!stats.is_empty());
254    /// # Ok::<(), SzError>(())
255    /// ```
256    fn get_stats(&self) -> SzResult<JsonString>;
257
258    /// Adds a record for entity resolution.
259    ///
260    /// Inserts or updates a record in the entity repository. The record will be
261    /// matched and potentially merged with existing entities based on configured rules.
262    ///
263    /// # Arguments
264    ///
265    /// * `data_source_code` - The data source identifier (must be registered)
266    /// * `record_id` - Unique identifier for the record within the data source
267    /// * `record_definition` - JSON object containing the record attributes
268    /// * `flags` - Optional flags controlling what information is returned
269    ///
270    /// # Returns
271    ///
272    /// JSON string with information about affected entities (when flags request it).
273    ///
274    /// # Examples
275    ///
276    /// ```
277    /// # use sz_rust_sdk::helpers::ExampleEnvironment;
278    /// use sz_rust_sdk::prelude::*;
279    ///
280    /// # let env = ExampleEnvironment::initialize("doctest_add_record")?;
281    /// let engine = env.get_engine()?;
282    ///
283    /// let record = r#"{"NAME_FULL": "John Smith", "ADDR_FULL": "123 Main St"}"#;
284    /// let result = engine.add_record("TEST", "ADD_1001", record, None)?;
285    /// # Ok::<(), SzError>(())
286    /// ```
287    ///
288    /// With flags to get entity info back:
289    ///
290    /// ```
291    /// # use sz_rust_sdk::helpers::ExampleEnvironment;
292    /// use sz_rust_sdk::prelude::*;
293    ///
294    /// # let env = ExampleEnvironment::initialize("doctest_add_record_flags")?;
295    /// let engine = env.get_engine()?;
296    ///
297    /// let record = r#"{"NAME_FULL": "Jane Doe", "EMAIL": "jane@example.com"}"#;
298    /// let result = engine.add_record(
299    ///     "TEST",
300    ///     "ADD_1002",
301    ///     record,
302    ///     Some(SzFlags::WITH_INFO),
303    /// )?;
304    /// // result contains affected entity info when WITH_INFO is set
305    /// # Ok::<(), SzError>(())
306    /// ```
307    ///
308    /// # Errors
309    ///
310    /// * `SzError::UnknownDataSource` - Data source is not registered
311    /// * `SzError::BadInput` - Invalid JSON or missing required fields
312    fn add_record(
313        &self,
314        data_source_code: &str,
315        record_id: &str,
316        record_definition: &str,
317        flags: Option<SzFlags>,
318    ) -> SzResult<JsonString>;
319
320    /// Gets a preview of how a record would be processed without persisting it.
321    ///
322    /// Useful for testing record mappings and seeing how features would be extracted
323    /// before committing the record to the repository.
324    ///
325    /// # Arguments
326    ///
327    /// * `record_definition` - JSON object containing the record attributes
328    /// * `flags` - Optional flags controlling what information is returned
329    ///
330    /// # Returns
331    ///
332    /// JSON string showing extracted features and potential matches.
333    ///
334    /// # Examples
335    ///
336    /// ```
337    /// # use sz_rust_sdk::helpers::ExampleEnvironment;
338    /// use sz_rust_sdk::prelude::*;
339    ///
340    /// # let env = ExampleEnvironment::initialize("doctest_get_record_preview")?;
341    /// let engine = env.get_engine()?;
342    ///
343    /// let record = r#"{"NAME_FULL": "John Smith", "ADDR_FULL": "123 Main St"}"#;
344    /// let preview = engine.get_record_preview(record, None)?;
345    /// # Ok::<(), SzError>(())
346    /// ```
347    fn get_record_preview(
348        &self,
349        record_definition: &str,
350        flags: Option<SzFlags>,
351    ) -> SzResult<JsonString>;
352
353    /// Deletes a record from the entity repository.
354    ///
355    /// Removes the record and re-resolves any affected entities. If the record
356    /// was the only record in an entity, the entity is also removed.
357    ///
358    /// # Arguments
359    ///
360    /// * `data_source_code` - The data source identifier
361    /// * `record_id` - The record identifier to delete
362    /// * `flags` - Optional flags controlling what information is returned
363    ///
364    /// # Returns
365    ///
366    /// JSON string with information about affected entities.
367    ///
368    /// # Examples
369    ///
370    /// ```
371    /// # use sz_rust_sdk::helpers::ExampleEnvironment;
372    /// use sz_rust_sdk::prelude::*;
373    ///
374    /// # let env = ExampleEnvironment::initialize("doctest_delete_record")?;
375    /// let engine = env.get_engine()?;
376    ///
377    /// // First add a record, then delete it
378    /// # engine.add_record("TEST", "DEL_1001",
379    /// #     r#"{"NAME_FULL": "Delete Me"}"#, None)?;
380    /// let result = engine.delete_record("TEST", "DEL_1001", None)?;
381    /// # Ok::<(), SzError>(())
382    /// ```
383    ///
384    /// # Errors
385    ///
386    /// * `SzError::UnknownDataSource` - Data source is not registered
387    /// * `SzError::NotFound` - Record does not exist
388    fn delete_record(
389        &self,
390        data_source_code: &str,
391        record_id: &str,
392        flags: Option<SzFlags>,
393    ) -> SzResult<JsonString>;
394
395    /// Reevaluates a specific record against current rules.
396    ///
397    /// Forces re-resolution of a record using the current configuration. Useful
398    /// after configuration changes to update entity assignments.
399    ///
400    /// # Arguments
401    ///
402    /// * `data_source_code` - The data source identifier
403    /// * `record_id` - The record identifier to reevaluate
404    /// * `flags` - Optional flags controlling what information is returned
405    ///
406    /// # Returns
407    ///
408    /// JSON string with reevaluation results.
409    ///
410    /// # Examples
411    ///
412    /// ```
413    /// # use sz_rust_sdk::helpers::ExampleEnvironment;
414    /// use sz_rust_sdk::prelude::*;
415    ///
416    /// # let env = ExampleEnvironment::initialize("doctest_reevaluate_record")?;
417    /// let engine = env.get_engine()?;
418    /// # engine.add_record("TEST", "REEV_REC_1001",
419    /// #     r#"{"NAME_FULL": "John Smith"}"#, None)?;
420    ///
421    /// let result = engine.reevaluate_record("TEST", "REEV_REC_1001", None)?;
422    /// # Ok::<(), SzError>(())
423    /// ```
424    ///
425    /// # Errors
426    ///
427    /// * `SzError::NotFound` - Record does not exist
428    fn reevaluate_record(
429        &self,
430        data_source_code: &str,
431        record_id: &str,
432        flags: Option<SzFlags>,
433    ) -> SzResult<JsonString>;
434
435    /// Reevaluates all records for a specific entity.
436    ///
437    /// Forces re-resolution of all records in an entity. The entity may split
438    /// into multiple entities or merge with others based on current rules.
439    ///
440    /// # Arguments
441    ///
442    /// * `entity_id` - The entity identifier to reevaluate
443    /// * `flags` - Optional flags controlling what information is returned
444    ///
445    /// # Returns
446    ///
447    /// JSON string with reevaluation results.
448    ///
449    /// # Examples
450    ///
451    /// ```
452    /// # use sz_rust_sdk::helpers::ExampleEnvironment;
453    /// use sz_rust_sdk::prelude::*;
454    ///
455    /// # let env = ExampleEnvironment::initialize("doctest_reevaluate_entity")?;
456    /// let engine = env.get_engine()?;
457    /// # engine.add_record("TEST", "REEV_ENT_1001",
458    /// #     r#"{"NAME_FULL": "John Smith"}"#, None)?;
459    /// # let result = engine.get_entity(
460    /// #     EntityRef::Record { data_source: "TEST", record_id: "REEV_ENT_1001" },
461    /// #     None,
462    /// # )?;
463    /// # let entity_json: serde_json::Value = serde_json::from_str(&result).unwrap();
464    /// # let entity_id = entity_json["RESOLVED_ENTITY"]["ENTITY_ID"].as_i64().unwrap();
465    ///
466    /// let result = engine.reevaluate_entity(entity_id, None)?;
467    /// # Ok::<(), SzError>(())
468    /// ```
469    ///
470    /// # Errors
471    ///
472    /// * `SzError::NotFound` - Entity does not exist
473    fn reevaluate_entity(
474        &self,
475        entity_id: EntityId,
476        flags: Option<SzFlags>,
477    ) -> SzResult<JsonString>;
478
479    /// Searches for entities by attributes.
480    ///
481    /// Finds entities that match the provided attributes. Returns scored results
482    /// based on match quality.
483    ///
484    /// # Arguments
485    ///
486    /// * `attributes` - JSON object with search attributes (e.g., name, address)
487    /// * `search_profile` - Optional search profile name for customized matching
488    /// * `flags` - Optional flags controlling result detail level
489    ///
490    /// # Returns
491    ///
492    /// JSON string with matching entities and match scores.
493    ///
494    /// # Examples
495    ///
496    /// ```
497    /// # use sz_rust_sdk::helpers::ExampleEnvironment;
498    /// use sz_rust_sdk::prelude::*;
499    ///
500    /// # let env = ExampleEnvironment::initialize("doctest_search")?;
501    /// let engine = env.get_engine()?;
502    ///
503    /// let attrs = r#"{"NAME_FULL": "John Smith"}"#;
504    /// let results = engine.search_by_attributes(attrs, None, None)?;
505    /// # Ok::<(), SzError>(())
506    /// ```
507    ///
508    /// # Errors
509    ///
510    /// * `SzError::BadInput` - Invalid JSON attributes
511    fn search_by_attributes(
512        &self,
513        attributes: &str,
514        search_profile: Option<&str>,
515        flags: Option<SzFlags>,
516    ) -> SzResult<JsonString>;
517
518    /// Analyzes why a search result was returned for an entity.
519    ///
520    /// Provides detailed explanation of why a particular entity matched the
521    /// search criteria, including feature comparisons and match scores.
522    ///
523    /// # Arguments
524    ///
525    /// * `attributes` - JSON object with search attributes
526    /// * `entity_id` - The entity to analyze
527    /// * `search_profile` - Optional search profile name
528    /// * `flags` - Optional flags controlling detail level
529    ///
530    /// # Returns
531    ///
532    /// JSON string with detailed match analysis.
533    ///
534    /// # Examples
535    ///
536    /// ```
537    /// # use sz_rust_sdk::helpers::ExampleEnvironment;
538    /// use sz_rust_sdk::prelude::*;
539    ///
540    /// # let env = ExampleEnvironment::initialize("doctest_why_search")?;
541    /// let engine = env.get_engine()?;
542    /// # engine.add_record("TEST", "WHYS_1001",
543    /// #     r#"{"NAME_FULL": "John Smith", "ADDR_FULL": "123 Main St"}"#, None)?;
544    /// # let result = engine.get_entity(
545    /// #     EntityRef::Record { data_source: "TEST", record_id: "WHYS_1001" },
546    /// #     None,
547    /// # )?;
548    /// # let entity_json: serde_json::Value = serde_json::from_str(&result).unwrap();
549    /// # let entity_id = entity_json["RESOLVED_ENTITY"]["ENTITY_ID"].as_i64().unwrap();
550    ///
551    /// let attrs = r#"{"NAME_FULL": "John Smith"}"#;
552    /// let result = engine.why_search(attrs, entity_id, None, None)?;
553    /// # Ok::<(), SzError>(())
554    /// ```
555    fn why_search(
556        &self,
557        attributes: &str,
558        entity_id: EntityId,
559        search_profile: Option<&str>,
560        flags: Option<SzFlags>,
561    ) -> SzResult<JsonString>;
562
563    /// Gets entity information by entity ID or record key.
564    ///
565    /// Retrieves complete entity data including all constituent records and
566    /// relationships. The entity can be specified either by its entity ID
567    /// or by a record key (data source + record ID).
568    ///
569    /// # Arguments
570    ///
571    /// * `entity_ref` - Reference to the entity (entity ID or record key)
572    /// * `flags` - Optional flags controlling what data is included
573    ///
574    /// # Returns
575    ///
576    /// JSON string with entity details.
577    ///
578    /// # Errors
579    ///
580    /// * `SzError::NotFound` - Entity or record does not exist
581    ///
582    /// # Examples
583    ///
584    /// By record key:
585    ///
586    /// ```
587    /// # use sz_rust_sdk::helpers::ExampleEnvironment;
588    /// use sz_rust_sdk::prelude::*;
589    ///
590    /// # let env = ExampleEnvironment::initialize("doctest_get_entity")?;
591    /// let engine = env.get_engine()?;
592    /// # engine.add_record("TEST", "ENT_1001",
593    /// #     r#"{"NAME_FULL": "John Smith"}"#, None)?;
594    ///
595    /// let entity = engine.get_entity(
596    ///     EntityRef::Record { data_source: "TEST", record_id: "ENT_1001" },
597    ///     None,
598    /// )?;
599    /// # Ok::<(), SzError>(())
600    /// ```
601    fn get_entity(&self, entity_ref: EntityRef, flags: Option<SzFlags>) -> SzResult<JsonString>;
602
603    /// Gets record information.
604    ///
605    /// Retrieves the original record data as stored in the repository.
606    ///
607    /// # Arguments
608    ///
609    /// * `data_source_code` - The data source identifier
610    /// * `record_id` - The record identifier
611    /// * `flags` - Optional flags controlling what data is included
612    ///
613    /// # Returns
614    ///
615    /// JSON string with record details.
616    ///
617    /// # Examples
618    ///
619    /// ```
620    /// # use sz_rust_sdk::helpers::ExampleEnvironment;
621    /// use sz_rust_sdk::prelude::*;
622    ///
623    /// # let env = ExampleEnvironment::initialize("doctest_get_record")?;
624    /// let engine = env.get_engine()?;
625    /// # engine.add_record("TEST", "REC_1001",
626    /// #     r#"{"NAME_FULL": "John Smith"}"#, None)?;
627    ///
628    /// let record = engine.get_record("TEST", "REC_1001", None)?;
629    /// # Ok::<(), SzError>(())
630    /// ```
631    ///
632    /// # Errors
633    ///
634    /// * `SzError::NotFound` - Record does not exist
635    fn get_record(
636        &self,
637        data_source_code: &str,
638        record_id: &str,
639        flags: Option<SzFlags>,
640    ) -> SzResult<JsonString>;
641
642    /// Finds interesting entities related to a given entity or record.
643    ///
644    /// Identifies entities with notable relationships to the specified entity,
645    /// such as disclosed relationships or possible matches. The entity can be
646    /// specified either by its entity ID or by a record key.
647    ///
648    /// # Arguments
649    ///
650    /// * `entity_ref` - Reference to the entity (entity ID or record key)
651    /// * `flags` - Optional flags controlling result detail
652    ///
653    /// # Returns
654    ///
655    /// JSON string with interesting entity relationships.
656    ///
657    /// # Examples
658    ///
659    /// ```
660    /// # use sz_rust_sdk::helpers::ExampleEnvironment;
661    /// use sz_rust_sdk::prelude::*;
662    ///
663    /// # let env = ExampleEnvironment::initialize("doctest_find_interesting")?;
664    /// let engine = env.get_engine()?;
665    /// # engine.add_record("TEST", "INT_1001",
666    /// #     r#"{"NAME_FULL": "John Smith"}"#, None)?;
667    ///
668    /// let entity = engine.get_entity(
669    ///     EntityRef::Record { data_source: "TEST", record_id: "INT_1001" },
670    ///     None,
671    /// )?;
672    /// // Parse entity_id from the result, then find interesting entities
673    /// # Ok::<(), SzError>(())
674    /// ```
675    fn find_interesting_entities(
676        &self,
677        entity_ref: EntityRef,
678        flags: Option<SzFlags>,
679    ) -> SzResult<JsonString>;
680
681    /// Finds a relationship path between two entities.
682    ///
683    /// Discovers the shortest path connecting two entities through their
684    /// relationships, useful for understanding indirect connections.
685    ///
686    /// # Arguments
687    ///
688    /// * `start_entity_id` - Starting entity
689    /// * `end_entity_id` - Target entity
690    /// * `max_degrees` - Maximum relationship hops to traverse
691    /// * `avoid_entity_ids` - Optional entities to exclude from the path
692    /// * `required_data_sources` - Optional data sources that must appear in path
693    /// * `flags` - Optional flags controlling result detail
694    ///
695    /// # Returns
696    ///
697    /// JSON string with path details and intermediate entities.
698    ///
699    /// # Examples
700    ///
701    /// ```
702    /// # use sz_rust_sdk::helpers::ExampleEnvironment;
703    /// use sz_rust_sdk::prelude::*;
704    ///
705    /// # let env = ExampleEnvironment::initialize("doctest_find_path")?;
706    /// let engine = env.get_engine()?;
707    /// # engine.add_record("TEST", "PATH_1001",
708    /// #     r#"{"NAME_FULL": "John Smith"}"#, None)?;
709    /// # engine.add_record("TEST", "PATH_1002",
710    /// #     r#"{"NAME_FULL": "Jane Doe"}"#, None)?;
711    /// # let r1 = engine.get_entity(
712    /// #     EntityRef::Record { data_source: "TEST", record_id: "PATH_1001" },
713    /// #     None,
714    /// # )?;
715    /// # let j1: serde_json::Value = serde_json::from_str(&r1).unwrap();
716    /// # let entity_id1 = j1["RESOLVED_ENTITY"]["ENTITY_ID"].as_i64().unwrap();
717    /// # let r2 = engine.get_entity(
718    /// #     EntityRef::Record { data_source: "TEST", record_id: "PATH_1002" },
719    /// #     None,
720    /// # )?;
721    /// # let j2: serde_json::Value = serde_json::from_str(&r2).unwrap();
722    /// # let entity_id2 = j2["RESOLVED_ENTITY"]["ENTITY_ID"].as_i64().unwrap();
723    ///
724    /// let path = engine.find_path(entity_id1, entity_id2, 3, None, None, None)?;
725    /// # Ok::<(), SzError>(())
726    /// ```
727    fn find_path(
728        &self,
729        start_entity_id: EntityId,
730        end_entity_id: EntityId,
731        max_degrees: i64,
732        avoid_entity_ids: Option<&HashSet<EntityId>>,
733        required_data_sources: Option<&HashSet<String>>,
734        flags: Option<SzFlags>,
735    ) -> SzResult<JsonString>;
736
737    /// Finds a network of related entities.
738    ///
739    /// Builds a network graph starting from one or more seed entities,
740    /// expanding outward through relationships.
741    ///
742    /// # Arguments
743    ///
744    /// * `entity_list` - Seed entity IDs to start from
745    /// * `max_degrees` - Maximum relationship hops from seed entities
746    /// * `build_out_degree` - Degrees to expand for building connections
747    /// * `max_entities` - Maximum entities to include in the network
748    /// * `flags` - Optional flags controlling result detail
749    ///
750    /// # Returns
751    ///
752    /// JSON string with network graph data.
753    ///
754    /// # Examples
755    ///
756    /// ```
757    /// # use sz_rust_sdk::helpers::ExampleEnvironment;
758    /// use sz_rust_sdk::prelude::*;
759    ///
760    /// # let env = ExampleEnvironment::initialize("doctest_find_network")?;
761    /// let engine = env.get_engine()?;
762    /// # engine.add_record("TEST", "NET_1001",
763    /// #     r#"{"NAME_FULL": "John Smith"}"#, None)?;
764    /// # let r1 = engine.get_entity(
765    /// #     EntityRef::Record { data_source: "TEST", record_id: "NET_1001" },
766    /// #     None,
767    /// # )?;
768    /// # let j1: serde_json::Value = serde_json::from_str(&r1).unwrap();
769    /// # let entity_id = j1["RESOLVED_ENTITY"]["ENTITY_ID"].as_i64().unwrap();
770    ///
771    /// let network = engine.find_network(&[entity_id], 3, 1, 100, None)?;
772    /// # Ok::<(), SzError>(())
773    /// ```
774    fn find_network(
775        &self,
776        entity_list: &[EntityId],
777        max_degrees: i64,
778        build_out_degree: i64,
779        max_entities: i64,
780        flags: Option<SzFlags>,
781    ) -> SzResult<JsonString>;
782
783    /// Analyzes why two entities are related.
784    ///
785    /// Provides detailed explanation of the relationship between two entities,
786    /// including shared features and match scores.
787    ///
788    /// # Arguments
789    ///
790    /// * `entity_id1` - First entity
791    /// * `entity_id2` - Second entity
792    /// * `flags` - Optional flags controlling detail level
793    ///
794    /// # Returns
795    ///
796    /// JSON string with relationship analysis.
797    ///
798    /// # Examples
799    ///
800    /// ```
801    /// # use sz_rust_sdk::helpers::ExampleEnvironment;
802    /// use sz_rust_sdk::prelude::*;
803    ///
804    /// # let env = ExampleEnvironment::initialize("doctest_why_entities")?;
805    /// let engine = env.get_engine()?;
806    /// # engine.add_record("TEST", "WHYE_1001",
807    /// #     r#"{"NAME_FULL": "John Smith"}"#, None)?;
808    /// # engine.add_record("TEST", "WHYE_1002",
809    /// #     r#"{"NAME_FULL": "Jane Doe"}"#, None)?;
810    /// # let r1 = engine.get_entity(
811    /// #     EntityRef::Record { data_source: "TEST", record_id: "WHYE_1001" },
812    /// #     None,
813    /// # )?;
814    /// # let j1: serde_json::Value = serde_json::from_str(&r1).unwrap();
815    /// # let entity_id1 = j1["RESOLVED_ENTITY"]["ENTITY_ID"].as_i64().unwrap();
816    /// # let r2 = engine.get_entity(
817    /// #     EntityRef::Record { data_source: "TEST", record_id: "WHYE_1002" },
818    /// #     None,
819    /// # )?;
820    /// # let j2: serde_json::Value = serde_json::from_str(&r2).unwrap();
821    /// # let entity_id2 = j2["RESOLVED_ENTITY"]["ENTITY_ID"].as_i64().unwrap();
822    ///
823    /// let result = engine.why_entities(entity_id1, entity_id2, None)?;
824    /// # Ok::<(), SzError>(())
825    /// ```
826    fn why_entities(
827        &self,
828        entity_id1: EntityId,
829        entity_id2: EntityId,
830        flags: Option<SzFlags>,
831    ) -> SzResult<JsonString>;
832
833    /// Analyzes why two records resolved together.
834    ///
835    /// Explains why two specific records were merged into the same entity,
836    /// showing the matching features and rules that caused the merge.
837    ///
838    /// # Arguments
839    ///
840    /// * `data_source_code1` - First record's data source
841    /// * `record_id1` - First record's identifier
842    /// * `data_source_code2` - Second record's data source
843    /// * `record_id2` - Second record's identifier
844    /// * `flags` - Optional flags controlling detail level
845    ///
846    /// # Returns
847    ///
848    /// JSON string with merge analysis.
849    ///
850    /// # Examples
851    ///
852    /// ```
853    /// # use sz_rust_sdk::helpers::ExampleEnvironment;
854    /// use sz_rust_sdk::prelude::*;
855    ///
856    /// # let env = ExampleEnvironment::initialize("doctest_why_records")?;
857    /// let engine = env.get_engine()?;
858    /// # engine.add_record("TEST", "WHYR_1001",
859    /// #     r#"{"NAME_FULL": "John Smith", "ADDR_FULL": "123 Main St"}"#, None)?;
860    /// # engine.add_record("TEST", "WHYR_1002",
861    /// #     r#"{"NAME_FULL": "John Smith", "EMAIL": "john@example.com"}"#, None)?;
862    ///
863    /// let result = engine.why_records("TEST", "WHYR_1001", "TEST", "WHYR_1002", None)?;
864    /// # Ok::<(), SzError>(())
865    /// ```
866    fn why_records(
867        &self,
868        data_source_code1: &str,
869        record_id1: &str,
870        data_source_code2: &str,
871        record_id2: &str,
872        flags: Option<SzFlags>,
873    ) -> SzResult<JsonString>;
874
875    /// Analyzes why a record belongs to its entity.
876    ///
877    /// Explains the chain of matches that connected a record to its current
878    /// entity assignment.
879    ///
880    /// # Arguments
881    ///
882    /// * `data_source_code` - The record's data source
883    /// * `record_id` - The record identifier
884    /// * `flags` - Optional flags controlling detail level
885    ///
886    /// # Returns
887    ///
888    /// JSON string with entity membership analysis.
889    ///
890    /// # Examples
891    ///
892    /// ```
893    /// # use sz_rust_sdk::helpers::ExampleEnvironment;
894    /// use sz_rust_sdk::prelude::*;
895    ///
896    /// # let env = ExampleEnvironment::initialize("doctest_why_record_in_entity")?;
897    /// let engine = env.get_engine()?;
898    /// # engine.add_record("TEST", "WRIE_1001",
899    /// #     r#"{"NAME_FULL": "John Smith"}"#, None)?;
900    ///
901    /// let result = engine.why_record_in_entity("TEST", "WRIE_1001", None)?;
902    /// # Ok::<(), SzError>(())
903    /// ```
904    fn why_record_in_entity(
905        &self,
906        data_source_code: &str,
907        record_id: &str,
908        flags: Option<SzFlags>,
909    ) -> SzResult<JsonString>;
910
911    /// Analyzes how an entity was constructed.
912    ///
913    /// Provides a step-by-step explanation of how records were merged to form
914    /// the current entity, useful for understanding complex resolution paths.
915    ///
916    /// # Arguments
917    ///
918    /// * `entity_id` - The entity to analyze
919    /// * `flags` - Optional flags controlling detail level
920    ///
921    /// # Returns
922    ///
923    /// JSON string with entity construction history.
924    ///
925    /// # Examples
926    ///
927    /// ```
928    /// # use sz_rust_sdk::helpers::ExampleEnvironment;
929    /// use sz_rust_sdk::prelude::*;
930    ///
931    /// # let env = ExampleEnvironment::initialize("doctest_how_entity")?;
932    /// let engine = env.get_engine()?;
933    /// # engine.add_record("TEST", "HOW_1001",
934    /// #     r#"{"NAME_FULL": "John Smith"}"#, None)?;
935    /// # let result = engine.get_entity(
936    /// #     EntityRef::Record { data_source: "TEST", record_id: "HOW_1001" },
937    /// #     None,
938    /// # )?;
939    /// # let entity_json: serde_json::Value = serde_json::from_str(&result).unwrap();
940    /// # let entity_id = entity_json["RESOLVED_ENTITY"]["ENTITY_ID"].as_i64().unwrap();
941    ///
942    /// let result = engine.how_entity(entity_id, None)?;
943    /// # Ok::<(), SzError>(())
944    /// ```
945    fn how_entity(&self, entity_id: EntityId, flags: Option<SzFlags>) -> SzResult<JsonString>;
946
947    /// Creates a virtual entity from record keys without persisting.
948    ///
949    /// Simulates what an entity would look like if the specified records were
950    /// merged, without affecting the actual repository.
951    ///
952    /// # Arguments
953    ///
954    /// * `record_keys` - Pairs of (data_source_code, record_id)
955    /// * `flags` - Optional flags controlling result detail
956    ///
957    /// # Returns
958    ///
959    /// JSON string with virtual entity data.
960    ///
961    /// # Examples
962    ///
963    /// ```
964    /// # use sz_rust_sdk::helpers::ExampleEnvironment;
965    /// use sz_rust_sdk::prelude::*;
966    ///
967    /// # let env = ExampleEnvironment::initialize("doctest_get_virtual_entity")?;
968    /// let engine = env.get_engine()?;
969    /// # engine.add_record("TEST", "VIRT_1001",
970    /// #     r#"{"NAME_FULL": "John Smith"}"#, None)?;
971    /// # engine.add_record("TEST", "VIRT_1002",
972    /// #     r#"{"NAME_FULL": "Jane Doe"}"#, None)?;
973    ///
974    /// let record_keys = vec![
975    ///     ("TEST".to_string(), "VIRT_1001".to_string()),
976    ///     ("TEST".to_string(), "VIRT_1002".to_string()),
977    /// ];
978    /// let result = engine.get_virtual_entity(&record_keys, None)?;
979    /// # Ok::<(), SzError>(())
980    /// ```
981    fn get_virtual_entity(
982        &self,
983        record_keys: &[(String, String)],
984        flags: Option<SzFlags>,
985    ) -> SzResult<JsonString>;
986
987    /// Processes a redo record for deferred resolution.
988    ///
989    /// Handles records that were queued for later processing due to conflicts
990    /// or resource constraints.
991    ///
992    /// # Arguments
993    ///
994    /// * `redo_record` - The redo record JSON from `get_redo_record`
995    /// * `flags` - Optional flags controlling result detail
996    ///
997    /// # Returns
998    ///
999    /// JSON string with processing results.
1000    ///
1001    /// # Examples
1002    ///
1003    /// ```
1004    /// # use sz_rust_sdk::helpers::ExampleEnvironment;
1005    /// use sz_rust_sdk::prelude::*;
1006    ///
1007    /// # let env = ExampleEnvironment::initialize("doctest_process_redo_record")?;
1008    /// let engine = env.get_engine()?;
1009    ///
1010    /// let redo = engine.get_redo_record()?;
1011    /// if !redo.is_empty() {
1012    ///     let result = engine.process_redo_record(&redo, None)?;
1013    /// }
1014    /// # Ok::<(), SzError>(())
1015    /// ```
1016    fn process_redo_record(
1017        &self,
1018        redo_record: &str,
1019        flags: Option<SzFlags>,
1020    ) -> SzResult<JsonString>;
1021
1022    /// Gets the next pending redo record.
1023    ///
1024    /// Retrieves one record from the redo queue for processing.
1025    ///
1026    /// # Returns
1027    ///
1028    /// JSON string with redo record data, or empty string if queue is empty.
1029    ///
1030    /// # Examples
1031    ///
1032    /// ```
1033    /// # use sz_rust_sdk::helpers::ExampleEnvironment;
1034    /// use sz_rust_sdk::prelude::*;
1035    ///
1036    /// # let env = ExampleEnvironment::initialize("doctest_get_redo_record")?;
1037    /// let engine = env.get_engine()?;
1038    ///
1039    /// let redo = engine.get_redo_record()?;
1040    /// if redo.is_empty() {
1041    ///     println!("No redo records pending");
1042    /// }
1043    /// # Ok::<(), SzError>(())
1044    /// ```
1045    fn get_redo_record(&self) -> SzResult<JsonString>;
1046
1047    /// Counts pending redo records.
1048    ///
1049    /// # Returns
1050    ///
1051    /// Number of records waiting in the redo queue.
1052    ///
1053    /// # Examples
1054    ///
1055    /// ```
1056    /// # use sz_rust_sdk::helpers::ExampleEnvironment;
1057    /// use sz_rust_sdk::prelude::*;
1058    ///
1059    /// # let env = ExampleEnvironment::initialize("doctest_count_redo_records")?;
1060    /// let engine = env.get_engine()?;
1061    ///
1062    /// let count = engine.count_redo_records()?;
1063    /// println!("Pending redo records: {}", count);
1064    /// # Ok::<(), SzError>(())
1065    /// ```
1066    fn count_redo_records(&self) -> SzResult<i64>;
1067
1068    /// Starts a JSON entity export.
1069    ///
1070    /// Initiates an export operation returning a handle for fetching results.
1071    /// Use `fetch_next` to retrieve data and `close_export` when done.
1072    ///
1073    /// # Arguments
1074    ///
1075    /// * `flags` - Optional flags controlling what data is exported
1076    ///
1077    /// # Returns
1078    ///
1079    /// Handle for fetching export data.
1080    ///
1081    /// # Examples
1082    ///
1083    /// Export all entities as JSON (full export loop):
1084    ///
1085    /// ```
1086    /// # use sz_rust_sdk::helpers::ExampleEnvironment;
1087    /// use sz_rust_sdk::prelude::*;
1088    ///
1089    /// # let env = ExampleEnvironment::initialize("doctest_export")?;
1090    /// let engine = env.get_engine()?;
1091    ///
1092    /// let handle = engine.export_json_entity_report(None)?;
1093    /// loop {
1094    ///     let chunk = engine.fetch_next(handle)?;
1095    ///     if chunk.is_empty() {
1096    ///         break;
1097    ///     }
1098    ///     print!("{}", chunk);
1099    /// }
1100    /// engine.close_export(handle)?;
1101    /// # Ok::<(), SzError>(())
1102    /// ```
1103    fn export_json_entity_report(&self, flags: Option<SzFlags>) -> SzResult<ExportHandle>;
1104
1105    /// Starts a CSV entity export.
1106    ///
1107    /// Initiates a CSV export with specified columns.
1108    ///
1109    /// # Arguments
1110    ///
1111    /// * `csv_column_list` - Comma-separated list of columns to include
1112    /// * `flags` - Optional flags controlling what data is exported
1113    ///
1114    /// # Returns
1115    ///
1116    /// Handle for fetching export data.
1117    ///
1118    /// # Examples
1119    ///
1120    /// ```
1121    /// # use sz_rust_sdk::helpers::ExampleEnvironment;
1122    /// use sz_rust_sdk::prelude::*;
1123    ///
1124    /// # let env = ExampleEnvironment::initialize("doctest_export_csv")?;
1125    /// let engine = env.get_engine()?;
1126    ///
1127    /// let handle = engine.export_csv_entity_report(
1128    ///     "RESOLVED_ENTITY_ID,RELATED_ENTITY_ID,MATCH_LEVEL_CODE",
1129    ///     None,
1130    /// )?;
1131    /// loop {
1132    ///     let chunk = engine.fetch_next(handle)?;
1133    ///     if chunk.is_empty() {
1134    ///         break;
1135    ///     }
1136    ///     print!("{}", chunk);
1137    /// }
1138    /// engine.close_export(handle)?;
1139    /// # Ok::<(), SzError>(())
1140    /// ```
1141    fn export_csv_entity_report(
1142        &self,
1143        csv_column_list: &str,
1144        flags: Option<SzFlags>,
1145    ) -> SzResult<ExportHandle>;
1146
1147    /// Fetches the next batch of export data.
1148    ///
1149    /// Call repeatedly until empty string is returned to get all export data.
1150    ///
1151    /// # Arguments
1152    ///
1153    /// * `export_handle` - Handle from `export_json_entity_report` or `export_csv_entity_report`
1154    ///
1155    /// # Returns
1156    ///
1157    /// Next batch of export data, or empty string when complete.
1158    ///
1159    /// # Examples
1160    ///
1161    /// ```
1162    /// # use sz_rust_sdk::helpers::ExampleEnvironment;
1163    /// use sz_rust_sdk::prelude::*;
1164    ///
1165    /// # let env = ExampleEnvironment::initialize("doctest_fetch_next")?;
1166    /// let engine = env.get_engine()?;
1167    ///
1168    /// let handle = engine.export_json_entity_report(None)?;
1169    /// let chunk = engine.fetch_next(handle)?;
1170    /// // Empty string means no more data
1171    /// engine.close_export(handle)?;
1172    /// # Ok::<(), SzError>(())
1173    /// ```
1174    fn fetch_next(&self, export_handle: ExportHandle) -> SzResult<JsonString>;
1175
1176    /// Closes an export operation and releases resources.
1177    ///
1178    /// Must be called when finished with an export to free the handle.
1179    ///
1180    /// # Arguments
1181    ///
1182    /// * `export_handle` - Handle to close
1183    ///
1184    /// # Examples
1185    ///
1186    /// ```
1187    /// # use sz_rust_sdk::helpers::ExampleEnvironment;
1188    /// use sz_rust_sdk::prelude::*;
1189    ///
1190    /// # let env = ExampleEnvironment::initialize("doctest_close_export")?;
1191    /// let engine = env.get_engine()?;
1192    ///
1193    /// let handle = engine.export_json_entity_report(None)?;
1194    /// // ... fetch data ...
1195    /// engine.close_export(handle)?;
1196    /// # Ok::<(), SzError>(())
1197    /// ```
1198    fn close_export(&self, export_handle: ExportHandle) -> SzResult<()>;
1199}
1200
1201/// Configuration management operations.
1202///
1203/// The `SzConfig` trait provides methods for managing Senzing configuration data,
1204/// including data source registration and configuration export.
1205///
1206/// # Obtaining an Instance
1207///
1208/// Configuration instances are obtained through [`SzConfigManager`]:
1209///
1210/// ```
1211/// # use sz_rust_sdk::helpers::ExampleEnvironment;
1212/// # let env = ExampleEnvironment::initialize("doctest_sz_config")?;
1213/// use sz_rust_sdk::prelude::*;
1214///
1215/// let config_mgr = env.get_config_manager()?;
1216/// let config = config_mgr.create_config()?;
1217/// # Ok::<(), SzError>(())
1218/// ```
1219pub trait SzConfig {
1220    /// Exports the complete configuration as JSON.
1221    ///
1222    /// Returns the full configuration definition that can be saved, modified,
1223    /// or registered as a new configuration version.
1224    ///
1225    /// # Returns
1226    ///
1227    /// JSON string containing the complete configuration.
1228    ///
1229    /// # Examples
1230    ///
1231    /// ```
1232    /// # use sz_rust_sdk::helpers::ExampleEnvironment;
1233    /// use sz_rust_sdk::prelude::*;
1234    ///
1235    /// # let env = ExampleEnvironment::initialize("doctest_config_export")?;
1236    /// let config_mgr = env.get_config_manager()?;
1237    /// let config = config_mgr.create_config()?;
1238    /// let json = config.export()?;
1239    /// assert!(!json.is_empty());
1240    /// # Ok::<(), SzError>(())
1241    /// ```
1242    fn export(&self) -> SzResult<JsonString>;
1243
1244    /// Gets the data source registry.
1245    ///
1246    /// Returns information about all registered data sources in this configuration.
1247    ///
1248    /// # Returns
1249    ///
1250    /// JSON string with array of data source definitions including codes and IDs.
1251    ///
1252    /// # Examples
1253    ///
1254    /// ```
1255    /// # use sz_rust_sdk::helpers::ExampleEnvironment;
1256    /// use sz_rust_sdk::prelude::*;
1257    ///
1258    /// # let env = ExampleEnvironment::initialize("doctest_get_data_source_registry")?;
1259    /// let config_mgr = env.get_config_manager()?;
1260    /// let config = config_mgr.create_config()?;
1261    /// let registry = config.get_data_source_registry()?;
1262    /// println!("Data sources: {}", registry);
1263    /// # Ok::<(), SzError>(())
1264    /// ```
1265    fn get_data_source_registry(&self) -> SzResult<JsonString>;
1266
1267    /// Registers a new data source.
1268    ///
1269    /// Adds a data source to the configuration. Data sources must be registered
1270    /// before records can be added from that source.
1271    ///
1272    /// # Arguments
1273    ///
1274    /// * `data_source_code` - Unique identifier for the data source (e.g., "CUSTOMERS", "WATCHLIST")
1275    ///
1276    /// # Returns
1277    ///
1278    /// JSON string with the registered data source details including assigned ID.
1279    ///
1280    /// # Examples
1281    ///
1282    /// ```
1283    /// # use sz_rust_sdk::helpers::ExampleEnvironment;
1284    /// use sz_rust_sdk::prelude::*;
1285    ///
1286    /// # let env = ExampleEnvironment::initialize("doctest_register_data_source")?;
1287    /// let config_mgr = env.get_config_manager()?;
1288    /// let config = config_mgr.create_config()?;
1289    /// let result = config.register_data_source("VENDORS")?;
1290    /// println!("Registered: {}", result);
1291    /// // Clean up by unregistering
1292    /// config.unregister_data_source("VENDORS")?;
1293    /// # Ok::<(), SzError>(())
1294    /// ```
1295    ///
1296    /// # Errors
1297    ///
1298    /// * `SzError::BadInput` - Data source code is invalid or already exists
1299    fn register_data_source(&self, data_source_code: &str) -> SzResult<JsonString>;
1300
1301    /// Removes a data source from the configuration.
1302    ///
1303    /// Unregisters a data source. This should only be done if no records exist
1304    /// from that data source.
1305    ///
1306    /// # Arguments
1307    ///
1308    /// * `data_source_code` - The data source identifier to remove
1309    ///
1310    /// # Examples
1311    ///
1312    /// ```
1313    /// # use sz_rust_sdk::helpers::ExampleEnvironment;
1314    /// use sz_rust_sdk::prelude::*;
1315    ///
1316    /// # let env = ExampleEnvironment::initialize("doctest_unregister_data_source")?;
1317    /// let config_mgr = env.get_config_manager()?;
1318    /// let config = config_mgr.create_config()?;
1319    /// # config.register_data_source("TEMP_SOURCE")?;
1320    /// config.unregister_data_source("TEMP_SOURCE")?;
1321    /// # Ok::<(), SzError>(())
1322    /// ```
1323    ///
1324    /// # Errors
1325    ///
1326    /// * `SzError::BadInput` - Data source does not exist
1327    fn unregister_data_source(&self, data_source_code: &str) -> SzResult<()>;
1328}
1329
1330/// Configuration lifecycle management.
1331///
1332/// The `SzConfigManager` trait provides methods for managing configuration
1333/// versions, registration, and deployment. Use this to create, modify, and
1334/// activate configuration versions.
1335///
1336/// # Obtaining an Instance
1337///
1338/// ```
1339/// # use sz_rust_sdk::helpers::ExampleEnvironment;
1340/// # let env = ExampleEnvironment::initialize("doctest_sz_config_manager")?;
1341/// use sz_rust_sdk::prelude::*;
1342///
1343/// let config_mgr = env.get_config_manager()?;
1344/// # Ok::<(), SzError>(())
1345/// ```
1346pub trait SzConfigManager {
1347    /// Creates a new configuration instance from the default template.
1348    ///
1349    /// Returns a configuration object that can be modified (e.g., adding data sources)
1350    /// before being registered and activated.
1351    ///
1352    /// # Returns
1353    ///
1354    /// A new [`SzConfig`] instance based on the default configuration template.
1355    ///
1356    /// # Examples
1357    ///
1358    /// ```
1359    /// # use sz_rust_sdk::helpers::ExampleEnvironment;
1360    /// use sz_rust_sdk::prelude::*;
1361    ///
1362    /// # let env = ExampleEnvironment::initialize("doctest_create_config")?;
1363    /// let config_mgr = env.get_config_manager()?;
1364    /// let config = config_mgr.create_config()?;
1365    /// let json = config.export()?;
1366    /// assert!(!json.is_empty());
1367    /// # Ok::<(), SzError>(())
1368    /// ```
1369    fn create_config(&self) -> SzResult<Box<dyn SzConfig>>;
1370
1371    /// Creates a configuration from an existing registered configuration.
1372    ///
1373    /// Loads a previously registered configuration for viewing or modification.
1374    ///
1375    /// # Arguments
1376    ///
1377    /// * `config_id` - ID of a registered configuration
1378    ///
1379    /// # Returns
1380    ///
1381    /// An [`SzConfig`] instance with the specified configuration loaded.
1382    ///
1383    /// # Examples
1384    ///
1385    /// ```
1386    /// # use sz_rust_sdk::helpers::ExampleEnvironment;
1387    /// use sz_rust_sdk::prelude::*;
1388    ///
1389    /// # let env = ExampleEnvironment::initialize("doctest_create_config_from_id")?;
1390    /// let config_mgr = env.get_config_manager()?;
1391    /// let config_id = config_mgr.get_default_config_id()?;
1392    /// let config = config_mgr.create_config_from_id(config_id)?;
1393    /// let json = config.export()?;
1394    /// assert!(!json.is_empty());
1395    /// # Ok::<(), SzError>(())
1396    /// ```
1397    ///
1398    /// # Errors
1399    ///
1400    /// * `SzError::NotFound` - Configuration ID does not exist
1401    fn create_config_from_id(&self, config_id: ConfigId) -> SzResult<Box<dyn SzConfig>>;
1402
1403    /// Creates a configuration from a JSON definition string.
1404    ///
1405    /// Parses a configuration JSON (e.g., from a file or `SzConfig::export()`)
1406    /// into a configuration object.
1407    ///
1408    /// # Arguments
1409    ///
1410    /// * `config_definition` - JSON string containing the configuration
1411    ///
1412    /// # Returns
1413    ///
1414    /// An [`SzConfig`] instance with the parsed configuration.
1415    ///
1416    /// # Examples
1417    ///
1418    /// ```
1419    /// # use sz_rust_sdk::helpers::ExampleEnvironment;
1420    /// use sz_rust_sdk::prelude::*;
1421    ///
1422    /// # let env = ExampleEnvironment::initialize("doctest_create_config_from_def")?;
1423    /// let config_mgr = env.get_config_manager()?;
1424    /// let config = config_mgr.create_config()?;
1425    /// let json = config.export()?;
1426    /// let config2 = config_mgr.create_config_from_definition(&json)?;
1427    /// # Ok::<(), SzError>(())
1428    /// ```
1429    ///
1430    /// # Errors
1431    ///
1432    /// * `SzError::BadInput` - Invalid JSON or configuration format
1433    fn create_config_from_definition(&self, config_definition: &str)
1434    -> SzResult<Box<dyn SzConfig>>;
1435
1436    /// Gets the configuration registry.
1437    ///
1438    /// Returns information about all registered configuration versions.
1439    ///
1440    /// # Returns
1441    ///
1442    /// JSON string with array of configuration metadata including IDs, comments, and timestamps.
1443    ///
1444    /// # Examples
1445    ///
1446    /// ```
1447    /// # use sz_rust_sdk::helpers::ExampleEnvironment;
1448    /// use sz_rust_sdk::prelude::*;
1449    ///
1450    /// # let env = ExampleEnvironment::initialize("doctest_get_config_registry")?;
1451    /// let config_mgr = env.get_config_manager()?;
1452    /// let registry = config_mgr.get_config_registry()?;
1453    /// println!("Registered configs: {}", registry);
1454    /// # Ok::<(), SzError>(())
1455    /// ```
1456    fn get_config_registry(&self) -> SzResult<JsonString>;
1457
1458    /// Gets the currently active default configuration ID.
1459    ///
1460    /// # Returns
1461    ///
1462    /// The configuration ID that is currently active for entity resolution.
1463    ///
1464    /// # Examples
1465    ///
1466    /// ```
1467    /// # use sz_rust_sdk::helpers::ExampleEnvironment;
1468    /// use sz_rust_sdk::prelude::*;
1469    ///
1470    /// # let env = ExampleEnvironment::initialize("doctest_get_default_config_id")?;
1471    /// let config_mgr = env.get_config_manager()?;
1472    /// let config_id = config_mgr.get_default_config_id()?;
1473    /// println!("Default config ID: {}", config_id);
1474    /// # Ok::<(), SzError>(())
1475    /// ```
1476    fn get_default_config_id(&self) -> SzResult<ConfigId>;
1477
1478    /// Registers a new configuration version.
1479    ///
1480    /// Saves a configuration to the repository, making it available for activation.
1481    /// Does not activate the configuration - use `set_default_config_id` for that.
1482    ///
1483    /// # Arguments
1484    ///
1485    /// * `config_definition` - JSON string from `SzConfig::export()`
1486    /// * `config_comment` - Optional description for this configuration version
1487    ///
1488    /// # Returns
1489    ///
1490    /// The assigned configuration ID for the newly registered configuration.
1491    ///
1492    /// # Examples
1493    ///
1494    /// ```
1495    /// # use sz_rust_sdk::helpers::ExampleEnvironment;
1496    /// use sz_rust_sdk::prelude::*;
1497    ///
1498    /// # let env = ExampleEnvironment::initialize("doctest_register_config")?;
1499    /// let config_mgr = env.get_config_manager()?;
1500    /// let config = config_mgr.create_config()?;
1501    /// let config_json = config.export()?;
1502    /// let config_id = config_mgr.register_config(&config_json, Some("Test config"))?;
1503    /// println!("Registered config ID: {}", config_id);
1504    /// # Ok::<(), SzError>(())
1505    /// ```
1506    fn register_config(
1507        &self,
1508        config_definition: &str,
1509        config_comment: Option<&str>,
1510    ) -> SzResult<ConfigId>;
1511
1512    /// Atomically replaces the default configuration ID.
1513    ///
1514    /// Updates the active configuration only if the current default matches
1515    /// the expected value. This prevents race conditions when multiple processes
1516    /// may be updating the configuration.
1517    ///
1518    /// # Arguments
1519    ///
1520    /// * `current_default_config_id` - Expected current default (for optimistic locking)
1521    /// * `new_default_config_id` - New configuration to activate
1522    ///
1523    /// # Examples
1524    ///
1525    /// ```
1526    /// # use sz_rust_sdk::helpers::ExampleEnvironment;
1527    /// use sz_rust_sdk::prelude::*;
1528    ///
1529    /// # let env = ExampleEnvironment::initialize("doctest_replace_default_config_id")?;
1530    /// let config_mgr = env.get_config_manager()?;
1531    /// let current_id = config_mgr.get_default_config_id()?;
1532    /// let config = config_mgr.create_config()?;
1533    /// let config_json = config.export()?;
1534    /// let new_id = config_mgr.register_config(&config_json, Some("Replacement config"))?;
1535    /// config_mgr.replace_default_config_id(current_id, new_id)?;
1536    /// # Ok::<(), SzError>(())
1537    /// ```
1538    ///
1539    /// # Errors
1540    ///
1541    /// * `SzError::ReplaceConflict` - Current default doesn't match expected value
1542    /// * `SzError::NotFound` - New configuration ID does not exist
1543    fn replace_default_config_id(
1544        &self,
1545        current_default_config_id: ConfigId,
1546        new_default_config_id: ConfigId,
1547    ) -> SzResult<()>;
1548
1549    /// Registers and activates a configuration in one operation.
1550    ///
1551    /// Convenience method that combines `register_config` and `set_default_config_id`.
1552    ///
1553    /// # Arguments
1554    ///
1555    /// * `config_definition` - JSON string from `SzConfig::export()`
1556    /// * `config_comment` - Optional description for this configuration version
1557    ///
1558    /// # Returns
1559    ///
1560    /// The assigned configuration ID.
1561    ///
1562    /// # Examples
1563    ///
1564    /// ```
1565    /// # use sz_rust_sdk::helpers::ExampleEnvironment;
1566    /// use sz_rust_sdk::prelude::*;
1567    ///
1568    /// # let env = ExampleEnvironment::initialize("doctest_set_default_config")?;
1569    /// let config_mgr = env.get_config_manager()?;
1570    /// let config = config_mgr.create_config()?;
1571    /// let config_json = config.export()?;
1572    /// let config_id = config_mgr.set_default_config(&config_json, Some("New default"))?;
1573    /// println!("New default config ID: {}", config_id);
1574    /// # Ok::<(), SzError>(())
1575    /// ```
1576    fn set_default_config(
1577        &self,
1578        config_definition: &str,
1579        config_comment: Option<&str>,
1580    ) -> SzResult<ConfigId>;
1581
1582    /// Sets the active configuration by ID.
1583    ///
1584    /// Activates a previously registered configuration. The engine will use
1585    /// this configuration for all subsequent operations.
1586    ///
1587    /// # Arguments
1588    ///
1589    /// * `config_id` - ID of a registered configuration to activate
1590    ///
1591    /// # Examples
1592    ///
1593    /// ```
1594    /// # use sz_rust_sdk::helpers::ExampleEnvironment;
1595    /// use sz_rust_sdk::prelude::*;
1596    ///
1597    /// # let env = ExampleEnvironment::initialize("doctest_set_default_config_id")?;
1598    /// let config_mgr = env.get_config_manager()?;
1599    /// let config_id = config_mgr.get_default_config_id()?;
1600    /// config_mgr.set_default_config_id(config_id)?;
1601    /// # Ok::<(), SzError>(())
1602    /// ```
1603    ///
1604    /// # Errors
1605    ///
1606    /// * `SzError::NotFound` - Configuration ID does not exist
1607    fn set_default_config_id(&self, config_id: ConfigId) -> SzResult<()>;
1608}
1609
1610/// System diagnostics and monitoring.
1611///
1612/// The `SzDiagnostic` trait provides methods for system health monitoring,
1613/// performance analysis, and repository maintenance.
1614///
1615/// # Obtaining an Instance
1616///
1617/// ```
1618/// # use sz_rust_sdk::helpers::ExampleEnvironment;
1619/// # let env = ExampleEnvironment::initialize("doctest_sz_diagnostic")?;
1620/// use sz_rust_sdk::prelude::*;
1621///
1622/// let diagnostic = env.get_diagnostic()?;
1623/// # Ok::<(), SzError>(())
1624/// ```
1625pub trait SzDiagnostic: Send + Sync {
1626    /// Runs a performance benchmark on the repository.
1627    ///
1628    /// Executes read operations against the repository to measure performance
1629    /// characteristics. Useful for baseline testing and capacity planning.
1630    ///
1631    /// # Arguments
1632    ///
1633    /// * `seconds_to_run` - Duration of the benchmark in seconds
1634    ///
1635    /// # Returns
1636    ///
1637    /// JSON string with performance metrics including operations per second.
1638    ///
1639    /// # Examples
1640    ///
1641    /// ```
1642    /// # use sz_rust_sdk::helpers::ExampleEnvironment;
1643    /// use sz_rust_sdk::prelude::*;
1644    ///
1645    /// # let env = ExampleEnvironment::initialize("doctest_check_repo_perf")?;
1646    /// let diagnostic = env.get_diagnostic()?;
1647    /// let result = diagnostic.check_repository_performance(1)?;
1648    /// println!("Performance: {}", result);
1649    /// # Ok::<(), SzError>(())
1650    /// ```
1651    ///
1652    /// # Errors
1653    ///
1654    /// * `SzError::BadInput` - Invalid duration (must be positive)
1655    fn check_repository_performance(&self, seconds_to_run: i64) -> SzResult<JsonString>;
1656
1657    /// Gets detailed information about a specific feature.
1658    ///
1659    /// Retrieves internal feature data useful for debugging entity resolution
1660    /// decisions. Features are the normalized attributes extracted from records.
1661    ///
1662    /// # Arguments
1663    ///
1664    /// * `feature_id` - Internal feature identifier
1665    ///
1666    /// # Returns
1667    ///
1668    /// JSON string with feature details including type, value, and usage statistics.
1669    ///
1670    /// # Examples
1671    ///
1672    /// ```no_run
1673    /// # use sz_rust_sdk::helpers::ExampleEnvironment;
1674    /// use sz_rust_sdk::prelude::*;
1675    ///
1676    /// # let env = ExampleEnvironment::initialize("doctest_get_feature")?;
1677    /// let diagnostic = env.get_diagnostic()?;
1678    /// let feature_id = 1; // obtained from entity resolution results
1679    /// let result = diagnostic.get_feature(feature_id)?;
1680    /// println!("Feature: {}", result);
1681    /// # Ok::<(), SzError>(())
1682    /// ```
1683    ///
1684    /// # Errors
1685    ///
1686    /// * `SzError::NotFound` - Feature ID does not exist
1687    fn get_feature(&self, feature_id: FeatureId) -> SzResult<JsonString>;
1688
1689    /// Gets repository statistics and information.
1690    ///
1691    /// Returns aggregate information about the entity repository including
1692    /// record counts, entity counts, and data source statistics.
1693    ///
1694    /// # Returns
1695    ///
1696    /// JSON string with repository statistics.
1697    ///
1698    /// # Examples
1699    ///
1700    /// ```
1701    /// # use sz_rust_sdk::helpers::ExampleEnvironment;
1702    /// use sz_rust_sdk::prelude::*;
1703    ///
1704    /// # let env = ExampleEnvironment::initialize("doctest_get_repository_info")?;
1705    /// let diagnostic = env.get_diagnostic()?;
1706    /// let info = diagnostic.get_repository_info()?;
1707    /// println!("Repository info: {}", info);
1708    /// # Ok::<(), SzError>(())
1709    /// ```
1710    fn get_repository_info(&self) -> SzResult<JsonString>;
1711
1712    /// Purges all entity data from the repository.
1713    ///
1714    /// Removes all records and entities while preserving configuration.
1715    /// Use with caution - this operation is irreversible.
1716    ///
1717    /// # Warning
1718    ///
1719    /// This permanently deletes all entity resolution data. Configuration
1720    /// and data source definitions are preserved.
1721    ///
1722    /// # Examples
1723    ///
1724    /// ```
1725    /// # use sz_rust_sdk::helpers::ExampleEnvironment;
1726    /// use sz_rust_sdk::prelude::*;
1727    ///
1728    /// # let env = ExampleEnvironment::initialize("doctest_purge_repository")?;
1729    /// let diagnostic = env.get_diagnostic()?;
1730    /// diagnostic.purge_repository()?;
1731    /// # Ok::<(), SzError>(())
1732    /// ```
1733    fn purge_repository(&self) -> SzResult<()>;
1734}
1735
1736/// Product version and license information.
1737///
1738/// The `SzProduct` trait provides methods for retrieving product version
1739/// and licensing information.
1740///
1741/// # Obtaining an Instance
1742///
1743/// ```
1744/// # use sz_rust_sdk::helpers::ExampleEnvironment;
1745/// # let env = ExampleEnvironment::initialize("doctest_sz_product")?;
1746/// use sz_rust_sdk::prelude::*;
1747///
1748/// let product = env.get_product()?;
1749/// # Ok::<(), SzError>(())
1750/// ```
1751pub trait SzProduct: Send + Sync {
1752    /// Gets the product license details.
1753    ///
1754    /// Returns information about the Senzing license including type,
1755    /// expiration, and feature entitlements.
1756    ///
1757    /// # Returns
1758    ///
1759    /// JSON string with license information.
1760    ///
1761    /// # Examples
1762    ///
1763    /// ```
1764    /// # use sz_rust_sdk::helpers::ExampleEnvironment;
1765    /// use sz_rust_sdk::prelude::*;
1766    ///
1767    /// # let env = ExampleEnvironment::initialize("doctest_get_license")?;
1768    /// let product = env.get_product()?;
1769    /// let license = product.get_license()?;
1770    /// println!("License: {}", license);
1771    /// # Ok::<(), SzError>(())
1772    /// ```
1773    fn get_license(&self) -> SzResult<JsonString>;
1774
1775    /// Gets the product version information.
1776    ///
1777    /// Returns version details for the Senzing engine and its components.
1778    ///
1779    /// # Returns
1780    ///
1781    /// JSON string with version information including build date and component versions.
1782    ///
1783    /// # Examples
1784    ///
1785    /// ```
1786    /// # use sz_rust_sdk::helpers::ExampleEnvironment;
1787    /// use sz_rust_sdk::prelude::*;
1788    ///
1789    /// # let env = ExampleEnvironment::initialize("doctest_get_version")?;
1790    /// let product = env.get_product()?;
1791    /// let version = product.get_version()?;
1792    /// println!("Version: {}", version);
1793    /// # Ok::<(), SzError>(())
1794    /// ```
1795    fn get_version(&self) -> SzResult<JsonString>;
1796}