use crate::{Error, Result};
use meshdb_core::{Edge, EdgeId, Node, NodeId, Property};
use std::path::Path;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct PropertyIndexSpec {
pub label: String,
pub properties: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct EdgePropertyIndexSpec {
pub edge_type: String,
pub properties: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct PointIndexSpec {
pub label: String,
pub property: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct EdgePointIndexSpec {
pub edge_type: String,
pub property: String,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum PropertyConstraintKind {
Unique,
NotNull,
PropertyType(PropertyType),
NodeKey,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum PropertyType {
String,
Integer,
Float,
Boolean,
}
impl PropertyType {
pub fn as_str(&self) -> &'static str {
match self {
PropertyType::String => "STRING",
PropertyType::Integer => "INTEGER",
PropertyType::Float => "FLOAT",
PropertyType::Boolean => "BOOLEAN",
}
}
pub fn name_tag(&self) -> &'static str {
match self {
PropertyType::String => "string",
PropertyType::Integer => "integer",
PropertyType::Float => "float",
PropertyType::Boolean => "boolean",
}
}
}
impl PropertyConstraintKind {
pub fn as_string(&self) -> String {
match self {
PropertyConstraintKind::Unique => "UNIQUE".into(),
PropertyConstraintKind::NotNull => "NOT NULL".into(),
PropertyConstraintKind::PropertyType(t) => format!("IS :: {}", t.as_str()),
PropertyConstraintKind::NodeKey => "NODE KEY".into(),
}
}
pub fn name_tag(&self) -> String {
match self {
PropertyConstraintKind::Unique => "unique".into(),
PropertyConstraintKind::NotNull => "not_null".into(),
PropertyConstraintKind::PropertyType(t) => format!("type_{}", t.name_tag()),
PropertyConstraintKind::NodeKey => "node_key".into(),
}
}
pub fn allows_multi_property(&self) -> bool {
matches!(self, PropertyConstraintKind::NodeKey)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum ConstraintScope {
Node(String),
Relationship(String),
}
impl ConstraintScope {
pub fn target(&self) -> &str {
match self {
ConstraintScope::Node(l) => l,
ConstraintScope::Relationship(t) => t,
}
}
pub fn name_tag(&self) -> &'static str {
match self {
ConstraintScope::Node(_) => "node",
ConstraintScope::Relationship(_) => "rel",
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct PropertyConstraintSpec {
pub name: String,
pub scope: ConstraintScope,
pub properties: Vec<String>,
pub kind: PropertyConstraintKind,
}
impl PropertyConstraintSpec {
pub fn primary_property(&self) -> &str {
self.properties.first().map(String::as_str).unwrap_or("")
}
}
#[derive(Debug, Clone)]
pub enum GraphMutation {
PutNode(Node),
PutEdge(Edge),
DeleteEdge(EdgeId),
DetachDeleteNode(NodeId),
}
pub trait StorageEngine: Send + Sync {
fn put_node(&self, node: &Node) -> Result<()>;
fn get_node(&self, id: NodeId) -> Result<Option<Node>>;
fn detach_delete_node(&self, id: NodeId) -> Result<()>;
fn put_edge(&self, edge: &Edge) -> Result<()>;
fn get_edge(&self, id: EdgeId) -> Result<Option<Edge>>;
fn delete_edge(&self, id: EdgeId) -> Result<()>;
fn apply_batch(&self, mutations: &[GraphMutation]) -> Result<()>;
fn all_nodes(&self) -> Result<Vec<Node>>;
fn all_edges(&self) -> Result<Vec<Edge>>;
fn all_node_ids(&self) -> Result<Vec<NodeId>>;
fn outgoing(&self, source: NodeId) -> Result<Vec<(EdgeId, NodeId)>>;
fn incoming(&self, target: NodeId) -> Result<Vec<(EdgeId, NodeId)>>;
fn nodes_by_label(&self, label: &str) -> Result<Vec<NodeId>>;
fn edges_by_type(&self, edge_type: &str) -> Result<Vec<EdgeId>>;
fn nodes_by_property(
&self,
label: &str,
property: &str,
value: &Property,
) -> Result<Vec<NodeId>>;
fn nodes_by_properties(
&self,
label: &str,
properties: &[String],
values: &[Property],
) -> Result<Vec<NodeId>>;
fn edges_by_property(
&self,
edge_type: &str,
property: &str,
value: &Property,
) -> Result<Vec<EdgeId>>;
fn create_property_index(&self, label: &str, property: &str) -> Result<()>;
fn drop_property_index(&self, label: &str, property: &str) -> Result<()>;
fn create_property_index_composite(&self, label: &str, properties: &[String]) -> Result<()>;
fn drop_property_index_composite(&self, label: &str, properties: &[String]) -> Result<()>;
fn list_property_indexes(&self) -> Vec<PropertyIndexSpec>;
fn create_edge_property_index(&self, edge_type: &str, property: &str) -> Result<()>;
fn drop_edge_property_index(&self, edge_type: &str, property: &str) -> Result<()>;
fn create_edge_property_index_composite(
&self,
edge_type: &str,
properties: &[String],
) -> Result<()>;
fn drop_edge_property_index_composite(
&self,
edge_type: &str,
properties: &[String],
) -> Result<()>;
fn list_edge_property_indexes(&self) -> Vec<EdgePropertyIndexSpec>;
fn create_point_index(&self, label: &str, property: &str) -> Result<()>;
fn drop_point_index(&self, label: &str, property: &str) -> Result<()>;
fn list_point_indexes(&self) -> Vec<PointIndexSpec>;
fn nodes_in_bbox(
&self,
label: &str,
property: &str,
srid: i32,
xlo: f64,
ylo: f64,
xhi: f64,
yhi: f64,
) -> Result<Vec<NodeId>>;
fn create_edge_point_index(&self, edge_type: &str, property: &str) -> Result<()>;
fn drop_edge_point_index(&self, edge_type: &str, property: &str) -> Result<()>;
fn list_edge_point_indexes(&self) -> Vec<EdgePointIndexSpec>;
fn edges_in_bbox(
&self,
edge_type: &str,
property: &str,
srid: i32,
xlo: f64,
ylo: f64,
xhi: f64,
yhi: f64,
) -> Result<Vec<EdgeId>>;
fn create_property_constraint(
&self,
name: Option<&str>,
scope: &ConstraintScope,
properties: &[String],
kind: PropertyConstraintKind,
if_not_exists: bool,
) -> Result<PropertyConstraintSpec>;
fn drop_property_constraint(&self, name: &str, if_exists: bool) -> Result<()>;
fn list_property_constraints(&self) -> Vec<PropertyConstraintSpec>;
fn put_trigger(&self, _name: &str, _value: &[u8]) -> Result<()> {
Err(Error::Unsupported(
"trigger registry is not supported by this backend".into(),
))
}
fn delete_trigger(&self, _name: &str) -> Result<()> {
Err(Error::Unsupported(
"trigger registry is not supported by this backend".into(),
))
}
fn list_triggers(&self) -> Result<Vec<(String, Vec<u8>)>> {
Ok(Vec::new())
}
fn put_pending_tx(&self, _key: &[u8], _value: &[u8]) -> Result<()> {
Err(Error::Unsupported(
"pending-tx metadata is not supported by this backend".into(),
))
}
fn delete_pending_tx(&self, _key: &[u8]) -> Result<()> {
Err(Error::Unsupported(
"pending-tx metadata is not supported by this backend".into(),
))
}
fn list_pending_txs(&self) -> Result<Vec<(Vec<u8>, Vec<u8>)>> {
Ok(Vec::new())
}
fn create_checkpoint(&self, path: &Path) -> Result<()>;
fn clear_all(&self) -> Result<()>;
}