oxirs_shacl/custom_components/
mod.rs1#![allow(dead_code)]
8
9pub mod constraints;
10pub mod dsl;
11pub mod js_wasm;
12pub mod library;
13pub mod marketplace;
14pub mod metadata;
15pub mod performance;
16pub mod registry;
17pub mod security;
18pub mod standard;
19
20pub use constraints::{
22 ComponentExecutionResult, CompositeConstraint, CompositionType, CustomConstraint,
23};
24pub use dsl::{
25 namespaces, patterns, xsd, ConstraintSpec, ConstraintTemplate, ParameterDef, ParameterType,
26 ShapeDSL, TemplateLibrary,
27};
28pub use js_wasm::{
29 interop, ExternalValidatorBuilder, JavaScriptValidator, RuntimeConfig, WasmValidator,
30};
31pub use library::{
32 AgeRangeValidator,
33 BicValidator,
34 BoundingBoxValidator,
35 BusinessHoursValidator,
36 ChemicalFormulaValidator,
37 ClassHierarchyValidator,
39 ConstraintLibrary,
40 CoordinatesValidator,
42 CountryCodeValidator,
43 CreditCardValidator,
44 CurrencyValidator,
46 DateRangeValidator,
48 DoiValidator,
49 DurationValidator,
50 GeoJsonValidator,
51 IbanValidator,
52 IriValidator,
53 IsbnValidator,
54 LibraryMetadata,
55 NamePatternValidator,
56 OntologyConsistencyValidator,
57 OrcidValidator,
58 PhoneNumberValidator,
60 PostalCodeValidator,
61 PropertyDomainRangeValidator,
62 ScientificNotationValidator,
63 TimezoneValidator,
64 UnitValidator,
66 UuidValidator,
68};
69pub use marketplace::{
70 AccessLevel, Author, Category, ComponentStats, ComponentVersion, ConstraintMarketplace,
71 Dependency, InstallOptions, InstallResult, MarketplaceCache, MarketplaceComponent,
72 MarketplaceConfig, MarketplaceIndex, MarketplaceStatistics, Permission, PublishOptions,
73 PublishResult, Review, SearchQuery, SearchQueryBuilder, SearchResults, SortBy, SortOrder,
74 UpdateInfo, UserSession,
75};
76pub use metadata::{
77 ComponentLibrary, ComponentMetadata, ParameterConstraint, ParameterDefinition,
78 ValidationCondition, ValidationRule, ValidationRuleType,
79};
80pub use performance::{
81 ComponentExecutionContext, ComponentPerformanceStats, ErrorStats, ErrorTrend, ExecutionMetrics,
82 MemoryUsageStats,
83};
84pub use registry::CustomConstraintRegistry;
85pub use security::{
86 ResourceQuotas, SandboxingLevel, SecurityPolicy, SecurityViolation, SecurityViolationType,
87 SparqlOperation,
88};
89pub use standard::{
90 EmailValidationComponent, RangeConstraintComponent, RegexConstraintComponent,
91 SparqlConstraintComponent, UrlValidationComponent,
92};
93
94use crate::{ConstraintComponentId, Result};
95use oxirs_core::model::Term;
96use std::collections::HashMap;
97
98pub trait CustomConstraintComponent: Send + Sync + std::fmt::Debug {
100 fn component_id(&self) -> &ConstraintComponentId;
102
103 fn metadata(&self) -> &ComponentMetadata;
105
106 fn validate_configuration(&self, parameters: &HashMap<String, Term>) -> Result<()>;
108
109 fn create_constraint(&self, parameters: HashMap<String, Term>) -> Result<CustomConstraint>;
111
112 fn sparql_template(&self) -> Option<&str> {
114 None
115 }
116
117 fn sparql_prefixes(&self) -> Option<&str> {
119 None
120 }
121}
122
123#[cfg(test)]
124mod tests {
125 use super::*;
126 use oxirs_core::model::Literal;
127
128 #[test]
129 fn test_registry_registration() {
130 let mut registry = CustomConstraintRegistry::new();
131 let component = std::sync::Arc::new(RegexConstraintComponent::new());
132 let component_id = component.component_id().clone();
133
134 assert!(registry.register_component(component).is_ok());
135 assert!(registry.get_component(&component_id).is_some());
136 assert!(registry.get_metadata(&component_id).is_some());
137 }
138
139 #[test]
140 fn test_regex_constraint_creation() {
141 let component = RegexConstraintComponent::new();
142 let mut parameters = HashMap::new();
143 parameters.insert(
144 "pattern".to_string(),
145 Term::Literal(Literal::new(r"^test\d+$")),
146 );
147
148 let constraint = component
149 .create_constraint(parameters)
150 .expect("training should succeed");
151 assert_eq!(
152 constraint.component_id.as_str(),
153 "ex:RegexConstraintComponent"
154 );
155 assert!(constraint.parameters.contains_key("pattern"));
156 }
157
158 #[test]
159 fn test_range_constraint_validation() {
160 let component = RangeConstraintComponent::new();
161
162 let empty_params = HashMap::new();
164 assert!(component.validate_configuration(&empty_params).is_err());
165
166 let mut params = HashMap::new();
168 params.insert("minValue".to_string(), Term::Literal(Literal::new("0")));
169 assert!(component.validate_configuration(¶ms).is_ok());
170 }
171
172 #[test]
173 fn test_standard_extensions_registration() {
174 let mut registry = CustomConstraintRegistry::new();
175 assert!(registry.register_standard_extensions().is_ok());
176
177 assert!(registry
179 .get_component(&ConstraintComponentId(
180 "ex:RegexConstraintComponent".to_string()
181 ))
182 .is_some());
183 assert!(registry
184 .get_component(&ConstraintComponentId(
185 "ex:RangeConstraintComponent".to_string()
186 ))
187 .is_some());
188 assert!(registry
189 .get_component(&ConstraintComponentId(
190 "ex:UrlValidationComponent".to_string()
191 ))
192 .is_some());
193 assert!(registry
194 .get_component(&ConstraintComponentId(
195 "ex:EmailValidationComponent".to_string()
196 ))
197 .is_some());
198 assert!(registry
199 .get_component(&ConstraintComponentId(
200 "ex:SparqlConstraintComponent".to_string()
201 ))
202 .is_some());
203 }
204
205 #[test]
206 fn test_composite_constraint_creation() {
207 let mut registry = CustomConstraintRegistry::new();
208 registry
209 .register_standard_extensions()
210 .expect("training should succeed");
211
212 let regex_id = ConstraintComponentId("ex:RegexConstraintComponent".to_string());
213 let range_id = ConstraintComponentId("ex:RangeConstraintComponent".to_string());
214
215 let mut parameters = HashMap::new();
216 parameters.insert("pattern".to_string(), Term::Literal(Literal::new(r"^\d+$")));
217 parameters.insert("minValue".to_string(), Term::Literal(Literal::new("0")));
218
219 let composite = registry
220 .create_composite_constraint(&[regex_id, range_id], parameters)
221 .expect("training should succeed");
222
223 assert_eq!(composite.component_ids.len(), 2);
224 assert_eq!(composite.constraints.len(), 2);
225 assert!(matches!(composite.composition_type, CompositionType::And));
226 }
227}