1use serde::{Deserialize, Serialize};
38use std::collections::HashMap;
39
40#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
79#[serde(rename_all = "camelCase")]
80pub struct AstPattern {
81 pub subject: AstSubject,
83
84 pub elements: Vec<AstPattern>,
86}
87
88#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
112#[serde(rename_all = "camelCase")]
113pub struct AstSubject {
114 pub identity: String,
116
117 pub labels: Vec<String>,
119
120 pub properties: HashMap<String, serde_json::Value>,
126}
127
128impl AstPattern {
129 pub fn empty() -> Self {
133 AstPattern {
134 subject: AstSubject {
135 identity: String::new(),
136 labels: Vec::new(),
137 properties: HashMap::new(),
138 },
139 elements: Vec::new(),
140 }
141 }
142}
143
144#[derive(Debug, Clone, Serialize, Deserialize)]
150pub struct ParseWithHeaderResult {
151 pub header: Option<HashMap<String, serde_json::Value>>,
152 pub patterns: Vec<AstPattern>,
153}
154
155impl ParseWithHeaderResult {
156 pub fn from_parts(
158 header: Option<pattern_core::PropertyRecord>,
159 patterns: Vec<pattern_core::Pattern<pattern_core::Subject>>,
160 ) -> Self {
161 ParseWithHeaderResult {
162 header: header.map(|h| {
163 h.iter()
164 .map(|(k, v)| (k.clone(), value_to_json(v)))
165 .collect()
166 }),
167 patterns: patterns.iter().map(AstPattern::from_pattern).collect(),
168 }
169 }
170
171 pub fn header_to_record(&self) -> Result<Option<pattern_core::PropertyRecord>, String> {
173 match &self.header {
174 None => Ok(None),
175 Some(map) => {
176 let record: pattern_core::PropertyRecord = map
177 .iter()
178 .map(|(k, v)| json_to_value(v).map(|val| (k.clone(), val)))
179 .collect::<Result<_, _>>()?;
180 Ok(Some(record))
181 }
182 }
183 }
184}
185
186use pattern_core::{Pattern, Subject, Value};
188
189impl AstPattern {
190 pub fn to_pattern(&self) -> Result<Pattern<Subject>, String> {
213 crate::json::ast_to_pattern(self)
214 }
215
216 pub fn from_pattern(pattern: &Pattern<Subject>) -> Self {
217 let subject = pattern.value();
218
219 AstPattern {
220 subject: AstSubject {
221 identity: subject.identity.0.clone(),
222 labels: subject.labels.iter().cloned().collect(),
223 properties: subject
224 .properties
225 .iter()
226 .map(|(k, v)| (k.clone(), value_to_json(v)))
227 .collect(),
228 },
229 elements: pattern
230 .elements()
231 .iter()
232 .map(AstPattern::from_pattern)
233 .collect(),
234 }
235 }
236}
237
238fn value_to_json(value: &Value) -> serde_json::Value {
252 match value {
253 Value::VInteger(i) => serde_json::Value::Number((*i).into()),
255
256 Value::VDecimal(d) => {
257 serde_json::Number::from_f64(*d)
259 .map(serde_json::Value::Number)
260 .unwrap_or_else(|| serde_json::Value::Null)
261 }
262
263 Value::VBoolean(b) => serde_json::Value::Bool(*b),
264
265 Value::VString(s) => serde_json::Value::String(s.clone()),
266
267 Value::VArray(arr) => serde_json::Value::Array(arr.iter().map(value_to_json).collect()),
268
269 Value::VMap(map) => serde_json::Value::Object(
270 map.iter()
271 .map(|(k, v)| (k.clone(), value_to_json(v)))
272 .collect(),
273 ),
274
275 Value::VSymbol(sym) => serde_json::json!({
278 "type": "symbol",
279 "value": sym.clone()
280 }),
281
282 Value::VRange(range) => serde_json::json!({
283 "type": "range",
284 "lower": range.lower,
285 "upper": range.upper
286 }),
287
288 Value::VMeasurement { unit, value } => serde_json::json!({
289 "type": "measurement",
290 "unit": unit,
291 "value": value
292 }),
293
294 Value::VTaggedString { tag, content } => serde_json::json!({
295 "type": "tagged",
296 "tag": tag,
297 "content": content
298 }),
299 }
300}
301
302pub(crate) fn json_to_value(v: &serde_json::Value) -> Result<Value, String> {
304 use pattern_core::RangeValue;
305 match v {
306 serde_json::Value::String(s) => Ok(Value::VString(s.clone())),
307 serde_json::Value::Bool(b) => Ok(Value::VBoolean(*b)),
308 serde_json::Value::Null => {
309 Err("JSON null is not representable as a gram value".to_string())
310 }
311 serde_json::Value::Number(n) => {
312 if let Some(i) = n.as_i64() {
313 Ok(Value::VInteger(i))
314 } else if let Some(f) = n.as_f64() {
315 Ok(Value::VDecimal(f))
316 } else {
317 Err(format!(
318 "JSON number is not representable as a gram decimal value: {}",
319 n
320 ))
321 }
322 }
323 serde_json::Value::Array(arr) => {
324 let items: Vec<Value> = arr
325 .iter()
326 .map(json_to_value)
327 .collect::<Result<Vec<_>, _>>()?;
328 Ok(Value::VArray(items))
329 }
330 serde_json::Value::Object(obj) => {
331 if let Some(type_tag) = obj.get("type").and_then(|t| t.as_str()) {
332 match type_tag {
333 "symbol" => {
334 let val = obj
335 .get("value")
336 .and_then(|v| v.as_str())
337 .ok_or_else(|| "symbol value must be a string".to_string())?
338 .to_string();
339 Ok(Value::VSymbol(val))
340 }
341 "range" => {
342 let lower = obj.get("lower").and_then(|v| v.as_f64());
343 let upper = obj.get("upper").and_then(|v| v.as_f64());
344 Ok(Value::VRange(RangeValue { lower, upper }))
345 }
346 "measurement" => {
347 let unit = obj
348 .get("unit")
349 .and_then(|v| v.as_str())
350 .ok_or_else(|| "measurement unit must be a string".to_string())?
351 .to_string();
352 let value = obj
353 .get("value")
354 .and_then(|v| v.as_f64())
355 .ok_or_else(|| "measurement value must be a number".to_string())?;
356 Ok(Value::VMeasurement { unit, value })
357 }
358 "tagged" => {
359 let tag = obj
360 .get("tag")
361 .and_then(|v| v.as_str())
362 .ok_or_else(|| "tagged value tag must be a string".to_string())?
363 .to_string();
364 let content = obj
365 .get("content")
366 .and_then(|v| v.as_str())
367 .ok_or_else(|| "tagged value content must be a string".to_string())?
368 .to_string();
369 Ok(Value::VTaggedString { tag, content })
370 }
371 _ => Err(format!("unknown tagged value type: {}", type_tag)),
372 }
373 } else {
374 let map: std::collections::HashMap<String, Value> = obj
375 .iter()
376 .map(|(k, v)| json_to_value(v).map(|val| (k.clone(), val)))
377 .collect::<Result<std::collections::HashMap<_, _>, _>>()?;
378 Ok(Value::VMap(map))
379 }
380 }
381 }
382}
383
384#[cfg(test)]
385mod tests {
386 use super::*;
387 use pattern_core::{Pattern, Subject, Symbol};
388 use std::collections::{HashMap, HashSet};
389
390 #[test]
391 fn test_empty_pattern() {
392 let pattern = AstPattern::empty();
393 assert_eq!(pattern.subject.identity, "");
394 assert_eq!(pattern.subject.labels.len(), 0);
395 assert_eq!(pattern.subject.properties.len(), 0);
396 assert_eq!(pattern.elements.len(), 0);
397 }
398
399 #[test]
400 fn test_json_serialization() {
401 let pattern = AstPattern {
402 subject: AstSubject {
403 identity: "alice".to_string(),
404 labels: vec!["Person".to_string()],
405 properties: {
406 let mut props = HashMap::new();
407 props.insert("name".to_string(), serde_json::json!("Alice"));
408 props
409 },
410 },
411 elements: vec![],
412 };
413
414 let json = serde_json::to_string(&pattern).unwrap();
416 assert!(json.contains("alice"));
417 assert!(json.contains("Person"));
418
419 let deserialized: AstPattern = serde_json::from_str(&json).unwrap();
421 assert_eq!(deserialized, pattern);
422 }
423
424 #[test]
425 fn test_nested_patterns() {
426 let child1 = AstPattern {
427 subject: AstSubject {
428 identity: "child1".to_string(),
429 labels: vec![],
430 properties: HashMap::new(),
431 },
432 elements: vec![],
433 };
434
435 let child2 = AstPattern {
436 subject: AstSubject {
437 identity: "child2".to_string(),
438 labels: vec![],
439 properties: HashMap::new(),
440 },
441 elements: vec![],
442 };
443
444 let parent = AstPattern {
445 subject: AstSubject {
446 identity: "parent".to_string(),
447 labels: vec![],
448 properties: HashMap::new(),
449 },
450 elements: vec![child1, child2],
451 };
452
453 assert_eq!(parent.elements.len(), 2);
454 assert_eq!(parent.elements[0].subject.identity, "child1");
455 assert_eq!(parent.elements[1].subject.identity, "child2");
456
457 let json = serde_json::to_string(&parent).unwrap();
459 let deserialized: AstPattern = serde_json::from_str(&json).unwrap();
460 assert_eq!(deserialized.elements.len(), 2);
461 }
462
463 #[test]
464 fn test_from_pattern_simple() {
465 let subject = Subject {
466 identity: Symbol("alice".to_string()),
467 labels: {
468 let mut labels = HashSet::new();
469 labels.insert("Person".to_string());
470 labels
471 },
472 properties: HashMap::new(),
473 };
474 let pattern = Pattern::point(subject);
475
476 let ast = AstPattern::from_pattern(&pattern);
477
478 assert_eq!(ast.subject.identity, "alice");
479 assert_eq!(ast.subject.labels, vec!["Person"]);
480 assert_eq!(ast.elements.len(), 0);
481 }
482
483 #[test]
484 fn test_from_pattern_with_properties() {
485 let subject = Subject {
486 identity: Symbol("alice".to_string()),
487 labels: HashSet::new(),
488 properties: {
489 let mut props = HashMap::new();
490 props.insert("name".to_string(), Value::VString("Alice".to_string()));
491 props.insert("age".to_string(), Value::VInteger(30));
492 props
493 },
494 };
495 let pattern = Pattern::point(subject);
496
497 let ast = AstPattern::from_pattern(&pattern);
498
499 assert_eq!(ast.subject.identity, "alice");
500 assert_eq!(ast.subject.properties.len(), 2);
501
502 assert_eq!(ast.subject.properties.get("name").unwrap(), "Alice");
504
505 let age_value = ast.subject.properties.get("age").unwrap();
507 assert_eq!(age_value, 30); }
509
510 #[test]
511 fn test_value_serialization_simple_types() {
512 let v = value_to_json(&Value::VInteger(42));
514 assert_eq!(v, serde_json::json!(42));
515 assert!(v.is_number());
516
517 let v = value_to_json(&Value::VDecimal(3.14));
519 assert_eq!(v, serde_json::json!(3.14));
520 assert!(v.is_number());
521
522 let v = value_to_json(&Value::VBoolean(true));
524 assert_eq!(v, serde_json::Value::Bool(true));
525
526 let v = value_to_json(&Value::VString("hello".to_string()));
528 assert_eq!(v, serde_json::Value::String("hello".to_string()));
529
530 let v = value_to_json(&Value::VArray(vec![Value::VInteger(1), Value::VInteger(2)]));
532 assert!(v.is_array());
533 assert_eq!(v.as_array().unwrap().len(), 2);
534 assert_eq!(v.as_array().unwrap()[0], serde_json::json!(1));
535 assert_eq!(v.as_array().unwrap()[1], serde_json::json!(2));
536 }
537
538 #[test]
539 fn test_value_serialization_tagged_types() {
540 let v = value_to_json(&Value::VSymbol("user123".to_string()));
542 assert_eq!(v["type"], "symbol");
543 assert_eq!(v["value"], "user123");
544
545 let v = value_to_json(&Value::VRange(pattern_core::RangeValue {
547 lower: Some(1.0),
548 upper: Some(10.0),
549 }));
550 assert_eq!(v["type"], "range");
551 assert_eq!(v["lower"], 1.0);
552 assert_eq!(v["upper"], 10.0);
553
554 let v = value_to_json(&Value::VMeasurement {
556 unit: "cm".to_string(),
557 value: 168.0,
558 });
559 assert_eq!(v["type"], "measurement");
560 assert_eq!(v["value"], 168.0);
561 assert_eq!(v["unit"], "cm");
562
563 let v = value_to_json(&Value::VTaggedString {
565 tag: "date".to_string(),
566 content: "2024-01-09".to_string(),
567 });
568 assert_eq!(v["type"], "tagged");
569 assert_eq!(v["tag"], "date");
570 assert_eq!(v["content"], "2024-01-09");
571 }
572
573 #[test]
574 fn test_value_serialization_map() {
575 let mut map = HashMap::new();
576 map.insert("key1".to_string(), Value::VString("value1".to_string()));
577 map.insert("key2".to_string(), Value::VInteger(42));
578
579 let v = value_to_json(&Value::VMap(map));
580
581 assert!(v.is_object());
582 assert_eq!(v["key1"], "value1");
583 assert_eq!(v["key2"], 42);
585 }
586}