Initial public Omnigraph repository

This commit is contained in:
andrew 2026-04-10 20:49:41 +03:00
commit 338289656a
110 changed files with 60747 additions and 0 deletions

View file

@ -0,0 +1,111 @@
use crate::types::PropType;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct SchemaFile {
pub declarations: Vec<SchemaDecl>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum SchemaDecl {
Interface(InterfaceDecl),
Node(NodeDecl),
Edge(EdgeDecl),
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct InterfaceDecl {
pub name: String,
pub properties: Vec<PropDecl>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct NodeDecl {
pub name: String,
pub annotations: Vec<Annotation>,
pub implements: Vec<String>,
pub properties: Vec<PropDecl>,
pub constraints: Vec<Constraint>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct EdgeDecl {
pub name: String,
pub from_type: String,
pub to_type: String,
pub cardinality: Cardinality,
pub annotations: Vec<Annotation>,
pub properties: Vec<PropDecl>,
pub constraints: Vec<Constraint>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct PropDecl {
pub name: String,
pub prop_type: PropType,
pub annotations: Vec<Annotation>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Annotation {
pub name: String,
pub value: Option<String>,
}
/// A typed constraint declared in a node or edge body.
///
/// Property-level annotations (`@key`, `@unique`, `@index`) are desugared
/// into these during parsing, so both syntactic positions produce the same
/// representation.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum Constraint {
Key(Vec<String>),
Unique(Vec<String>),
Index(Vec<String>),
Range {
property: String,
min: Option<ConstraintBound>,
max: Option<ConstraintBound>,
},
Check {
property: String,
pattern: String,
},
}
/// A numeric bound used in `@range` constraints.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum ConstraintBound {
Integer(i64),
Float(f64),
}
/// Edge cardinality: `@card(min..max)`. Default is `0..*`.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Cardinality {
pub min: u32,
pub max: Option<u32>,
}
impl Default for Cardinality {
fn default() -> Self {
Self { min: 0, max: None }
}
}
impl Cardinality {
pub fn is_default(&self) -> bool {
self.min == 0 && self.max.is_none()
}
}
pub fn has_annotation(annotations: &[Annotation], name: &str) -> bool {
annotations.iter().any(|ann| ann.name == name)
}
pub fn annotation_value<'a>(annotations: &'a [Annotation], name: &str) -> Option<&'a str> {
annotations
.iter()
.find(|ann| ann.name == name)
.and_then(|ann| ann.value.as_deref())
}

View file

@ -0,0 +1,2 @@
pub mod ast;
pub mod parser;

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,60 @@
// Omnigraph Schema Grammar (.pg files)
WHITESPACE = _{ " " | "\t" | "\r" | "\n" }
COMMENT = _{ LINE_COMMENT | BLOCK_COMMENT }
LINE_COMMENT = _{ "//" ~ (!"\n" ~ ANY)* }
BLOCK_COMMENT = _{ "/*" ~ (!"*/" ~ ANY)* ~ "*/" }
schema_file = { SOI ~ schema_decl* ~ EOI }
schema_decl = { interface_decl | node_decl | edge_decl }
// interface Named { name: String @key }
interface_decl = { "interface" ~ type_name ~ "{" ~ prop_decl* ~ "}" }
// node Person implements Named, Described { ... }
node_decl = { "node" ~ type_name ~ annotation* ~ implements_clause? ~ "{" ~ (prop_decl | body_constraint)* ~ "}" }
implements_clause = { "implements" ~ type_name ~ ("," ~ type_name)* }
// edge Knows: Person -> Person @card(0..1) { ... }
// edge Knows: Person -> Person
edge_decl = { "edge" ~ type_name ~ ":" ~ type_name ~ "->" ~ type_name ~ cardinality? ~ annotation* ~ ("{" ~ (prop_decl | body_constraint)* ~ "}")? }
// @card(0..1), @card(1..), @card(0..)
cardinality = { "@card" ~ "(" ~ integer ~ ".." ~ integer? ~ ")" }
prop_decl = { ident ~ ":" ~ type_ref ~ annotation* }
// Body-level constraints: @key(name), @unique(a, b), @index(a, b), @range(age, 0..200), @check(code, "regex")
body_constraint = { "@" ~ constraint_name ~ "(" ~ constraint_args ~ ")" }
constraint_name = { "key" | "unique" | "index" | "range" | "check" }
constraint_args = { constraint_arg ~ ("," ~ constraint_arg)* }
constraint_arg = { range_bound | literal | ident }
range_bound = { (signed_float | signed_integer) ~ ".." ~ (signed_float | signed_integer)? | ".." ~ (signed_float | signed_integer) }
type_ref = { core_type ~ "?"? }
core_type = { list_type | enum_type | vector_type | base_type }
list_type = { "[" ~ base_type ~ "]" }
enum_type = { "enum" ~ "(" ~ enum_value ~ ("," ~ enum_value)* ~ ")" }
vector_type = { "Vector" ~ "(" ~ integer ~ ")" }
enum_value = @{ (ASCII_ALPHANUMERIC | "_" | "-")+ }
base_type = { "String" | "Blob" | "Bool" | "I32" | "I64" | "U32" | "U64" | "F32" | "F64" | "DateTime" | "Date" }
// Annotation rule excludes constraint keywords followed by "(" — those are body_constraints
annotation = { "@" ~ !(constraint_name ~ "(") ~ ident ~ ("(" ~ annotation_arg ~ ")")? }
annotation_arg = { literal | ident }
literal = { string_lit | float_lit | integer | bool_lit }
string_lit = @{ "\"" ~ string_char* ~ "\"" }
string_char = @{ !("\"" | "\\") ~ ANY | "\\" ~ ANY }
float_lit = @{ ASCII_DIGIT+ ~ "." ~ ASCII_DIGIT+ }
integer = @{ ASCII_DIGIT+ }
signed_float = @{ "-"? ~ ASCII_DIGIT+ ~ "." ~ ASCII_DIGIT+ }
signed_integer = @{ "-"? ~ ASCII_DIGIT+ }
bool_lit = { "true" | "false" }
type_name = @{ ASCII_ALPHA_UPPER ~ (ASCII_ALPHANUMERIC | "_")* }
ident = @{ (ASCII_ALPHA_LOWER | "_") ~ (ASCII_ALPHANUMERIC | "_")* }