Skip to main content

omnigraph_compiler/schema/
ast.rs

1use crate::types::PropType;
2use serde::{Deserialize, Serialize};
3
4#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
5pub struct SchemaFile {
6    pub declarations: Vec<SchemaDecl>,
7}
8
9#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
10pub enum SchemaDecl {
11    Interface(InterfaceDecl),
12    Node(NodeDecl),
13    Edge(EdgeDecl),
14}
15
16#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
17pub struct InterfaceDecl {
18    pub name: String,
19    pub properties: Vec<PropDecl>,
20}
21
22#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
23pub struct NodeDecl {
24    pub name: String,
25    pub annotations: Vec<Annotation>,
26    pub implements: Vec<String>,
27    pub properties: Vec<PropDecl>,
28    pub constraints: Vec<Constraint>,
29}
30
31#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
32pub struct EdgeDecl {
33    pub name: String,
34    pub from_type: String,
35    pub to_type: String,
36    pub cardinality: Cardinality,
37    pub annotations: Vec<Annotation>,
38    pub properties: Vec<PropDecl>,
39    pub constraints: Vec<Constraint>,
40}
41
42#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
43pub struct PropDecl {
44    pub name: String,
45    pub prop_type: PropType,
46    pub annotations: Vec<Annotation>,
47}
48
49#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
50pub struct Annotation {
51    pub name: String,
52    pub value: Option<String>,
53}
54
55/// A typed constraint declared in a node or edge body.
56///
57/// Property-level annotations (`@key`, `@unique`, `@index`) are desugared
58/// into these during parsing, so both syntactic positions produce the same
59/// representation.
60#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
61pub enum Constraint {
62    Key(Vec<String>),
63    Unique(Vec<String>),
64    Index(Vec<String>),
65    Range {
66        property: String,
67        min: Option<ConstraintBound>,
68        max: Option<ConstraintBound>,
69    },
70    Check {
71        property: String,
72        pattern: String,
73    },
74}
75
76/// A numeric bound used in `@range` constraints.
77#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
78pub enum ConstraintBound {
79    Integer(i64),
80    Float(f64),
81}
82
83/// Edge cardinality: `@card(min..max)`. Default is `0..*`.
84#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
85pub struct Cardinality {
86    pub min: u32,
87    pub max: Option<u32>,
88}
89
90impl Default for Cardinality {
91    fn default() -> Self {
92        Self { min: 0, max: None }
93    }
94}
95
96impl Cardinality {
97    pub fn is_default(&self) -> bool {
98        self.min == 0 && self.max.is_none()
99    }
100}
101
102pub fn has_annotation(annotations: &[Annotation], name: &str) -> bool {
103    annotations.iter().any(|ann| ann.name == name)
104}
105
106pub fn annotation_value<'a>(annotations: &'a [Annotation], name: &str) -> Option<&'a str> {
107    annotations
108        .iter()
109        .find(|ann| ann.name == name)
110        .and_then(|ann| ann.value.as_deref())
111}