ggen_core/ontology_pack.rs
1//! Ontology Pack Metadata and Core Data Structures
2//!
3//! Extension of GpackMetadata for ontology-specific packs. Ontology packs are
4//! specialized template packs that focus on code generation from RDF/OWL ontologies.
5//!
6//! # Example
7//!
8//! ```rust,no_run
9//! use ggen_core::ontology_pack::{OntologyPackMetadata, OntologyConfig, OntologyDefinition};
10//!
11//! let pack_metadata = OntologyPackMetadata {
12//! base: Default::default(),
13//! ontology: OntologyConfig {
14//! ontologies: vec![
15//! OntologyDefinition {
16//! id: "schema.org".to_string(),
17//! name: "Schema.org".to_string(),
18//! version: "15.0".to_string(),
19//! namespace: "https://schema.org/".to_string(),
20//! file_path: "ontologies/schema-org.ttl".to_string(),
21//! format: OntologyFormat::Turtle,
22//! description: "Schema.org vocabulary".to_string(),
23//! spec_url: Some("https://schema.org".to_string()),
24//! classes_count: 792,
25//! properties_count: 1453,
26//! }
27//! ],
28//! ..Default::default()
29//! },
30//! };
31//! ```
32
33use serde::{Deserialize, Serialize};
34use std::collections::BTreeMap;
35
36/// Ontology pack metadata - extends GpackMetadata with ontology-specific fields
37#[derive(Debug, Clone, Serialize, Deserialize)]
38pub struct OntologyPackMetadata {
39 /// Base gpack metadata (id, name, version, description, etc.)
40 #[serde(flatten)]
41 pub base: crate::gpack::GpackMetadata,
42
43 /// Ontology-specific configuration
44 #[serde(default)]
45 pub ontology: OntologyConfig,
46}
47
48/// Ontology-specific configuration
49#[derive(Debug, Clone, Serialize, Deserialize, Default)]
50pub struct OntologyConfig {
51 /// Ontologies included in this pack
52 #[serde(default)]
53 pub ontologies: Vec<OntologyDefinition>,
54
55 /// Default namespace for generated code
56 pub default_namespace: Option<String>,
57
58 /// Code generation targets supported by this pack
59 #[serde(default)]
60 pub targets: Vec<CodeGenTarget>,
61
62 /// Template organization (language-specific paths)
63 #[serde(default)]
64 pub template_paths: BTreeMap<String, String>,
65
66 /// Ontology-specific prefixes
67 #[serde(default)]
68 pub prefixes: BTreeMap<String, String>,
69}
70
71/// An ontology definition (SCHEMA.ORG, FOAF, etc.)
72#[derive(Debug, Clone, Serialize, Deserialize)]
73pub struct OntologyDefinition {
74 /// Ontology identifier (e.g., "schema.org", "foaf", "dublincore")
75 pub id: String,
76
77 /// Human-readable name
78 pub name: String,
79
80 /// Ontology version
81 pub version: String,
82
83 /// Namespace URI
84 pub namespace: String,
85
86 /// Path to ontology file within pack (TTL, RDF/XML, etc.)
87 pub file_path: String,
88
89 /// Format (turtle, rdfxml, ntriples, jsonld)
90 pub format: OntologyFormat,
91
92 /// Description
93 pub description: String,
94
95 /// Official specification URL
96 pub spec_url: Option<String>,
97
98 /// Classes count (populated after extraction)
99 #[serde(default)]
100 pub classes_count: usize,
101
102 /// Properties count (populated after extraction)
103 #[serde(default)]
104 pub properties_count: usize,
105}
106
107/// Ontology file format
108#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
109#[serde(rename_all = "lowercase")]
110pub enum OntologyFormat {
111 /// Turtle format (.ttl)
112 Turtle,
113 /// RDF/XML format (.rdf, .xml)
114 RdfXml,
115 /// N-Triples format (.nt)
116 NTriples,
117 /// JSON-LD format (.jsonld)
118 JsonLd,
119}
120
121impl OntologyFormat {
122 /// Get file extension for this format
123 pub fn extension(&self) -> &str {
124 match self {
125 OntologyFormat::Turtle => "ttl",
126 OntologyFormat::RdfXml => "rdf",
127 OntologyFormat::NTriples => "nt",
128 OntologyFormat::JsonLd => "jsonld",
129 }
130 }
131}
132
133/// Code generation target (language + features)
134#[derive(Debug, Clone, Serialize, Deserialize)]
135pub struct CodeGenTarget {
136 /// Target language (typescript, rust, python, etc.)
137 pub language: String,
138
139 /// Features enabled for this target
140 #[serde(default)]
141 pub features: Vec<String>, // ["zod", "utilities", "graphql", etc.]
142
143 /// Template path for this target (relative to pack root)
144 pub template_path: String,
145
146 /// Output file pattern (e.g., "{class_name}.ts", "types.ts")
147 pub output_pattern: String,
148}
149
150/// Extracted ontology schema (intermediate representation)
151#[derive(Debug, Clone, Serialize, Deserialize, Default)]
152pub struct OntologySchema {
153 /// Schema namespace
154 pub namespace: String,
155
156 /// Classes extracted from ontology
157 #[serde(default)]
158 pub classes: Vec<OntologyClass>,
159
160 /// Properties extracted from ontology
161 #[serde(default)]
162 pub properties: Vec<OntologyProperty>,
163
164 /// Relationships between classes
165 #[serde(default)]
166 pub relationships: Vec<OntologyRelationship>,
167
168 /// Prefixes used in ontology
169 #[serde(default)]
170 pub prefixes: BTreeMap<String, String>,
171}
172
173/// Ontology class
174#[derive(Debug, Clone, Serialize, Deserialize)]
175pub struct OntologyClass {
176 /// Class URI
177 pub uri: String,
178
179 /// Class name (extracted from URI)
180 pub name: String,
181
182 /// Label (rdfs:label)
183 pub label: Option<String>,
184
185 /// Comment (rdfs:comment)
186 pub comment: Option<String>,
187
188 /// Properties belonging to this class
189 #[serde(default)]
190 pub properties: Vec<String>, // URIs
191
192 /// Superclasses
193 #[serde(default)]
194 pub super_classes: Vec<String>,
195
196 /// Subclasses
197 #[serde(default)]
198 pub sub_classes: Vec<String>,
199}
200
201/// Ontology property
202#[derive(Debug, Clone, Serialize, Deserialize)]
203pub struct OntologyProperty {
204 /// Property URI
205 pub uri: String,
206
207 /// Property name
208 pub name: String,
209
210 /// Label
211 pub label: Option<String>,
212
213 /// Comment
214 pub comment: Option<String>,
215
216 /// Domain (class this property applies to)
217 pub domain: String,
218
219 /// Range (value type or target class)
220 pub range: PropertyRange,
221
222 /// Cardinality constraints
223 pub cardinality: Option<Cardinality>,
224
225 /// Is this a functional property (single value)?
226 #[serde(default)]
227 pub is_functional: bool,
228}
229
230/// Property range (value type)
231#[derive(Debug, Clone, Serialize, Deserialize)]
232#[serde(tag = "type", rename_all = "lowercase")]
233pub enum PropertyRange {
234 /// Primitive type (string, integer, boolean, etc.)
235 Datatype {
236 /// XSD datatype (xsd:string, xsd:integer, etc.)
237 datatype: String,
238 },
239
240 /// Reference to another class
241 Reference {
242 /// Class URI
243 class_uri: String,
244 },
245
246 /// Array of values
247 Array {
248 /// Item type
249 item_type: Box<PropertyRange>,
250 },
251}
252
253/// Cardinality constraint
254#[derive(Debug, Clone, Serialize, Deserialize)]
255pub struct Cardinality {
256 /// Minimum occurrences (0 = optional, 1 = required)
257 pub min: Option<usize>,
258
259 /// Maximum occurrences (None = unbounded)
260 pub max: Option<usize>,
261}
262
263/// Relationship between classes
264#[derive(Debug, Clone, Serialize, Deserialize)]
265pub struct OntologyRelationship {
266 /// Source class URI
267 pub from: String,
268
269 /// Target class URI
270 pub to: String,
271
272 /// Property URI that defines this relationship
273 pub via_property: String,
274
275 /// Relationship type
276 pub relationship_type: RelationshipType,
277}
278
279/// Type of relationship between classes
280#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
281#[serde(rename_all = "lowercase")]
282pub enum RelationshipType {
283 /// rdfs:subClassOf inheritance
284 Inheritance,
285 /// Composition (part-of relationship)
286 Composition,
287 /// General association
288 Association,
289}
290
291#[cfg(test)]
292mod tests {
293 use super::*;
294
295 #[test]
296 fn test_ontology_format_extension() {
297 assert_eq!(OntologyFormat::Turtle.extension(), "ttl");
298 assert_eq!(OntologyFormat::RdfXml.extension(), "rdf");
299 assert_eq!(OntologyFormat::NTriples.extension(), "nt");
300 assert_eq!(OntologyFormat::JsonLd.extension(), "jsonld");
301 }
302
303 #[test]
304 fn test_ontology_class_serialization() {
305 let class = OntologyClass {
306 uri: "https://schema.org/Product".to_string(),
307 name: "Product".to_string(),
308 label: Some("Product".to_string()),
309 comment: Some("A manufactured product".to_string()),
310 properties: vec!["https://schema.org/name".to_string()],
311 super_classes: vec![],
312 sub_classes: vec![],
313 };
314
315 let json = serde_json::to_string(&class).unwrap();
316 let deserialized: OntologyClass = serde_json::from_str(&json).unwrap();
317
318 assert_eq!(deserialized.name, "Product");
319 assert_eq!(deserialized.properties.len(), 1);
320 }
321}