use core::fmt;
use oxgraph_csc::CscSnapshotError;
use oxgraph_csr::CsrSnapshotError;
use oxgraph_snapshot::{PlanError, SnapshotError};
use crate::{catalog::CatalogError, role::GraphRole};
#[derive(Debug)]
pub enum BuildError {
Plan(PlanError),
Graph(oxgraph_csr::build::GraphBuildError<u32, u32>),
MissingSnapshotBytes,
EmptyEdges,
NodeCountOverflow,
EdgeCountOverflow,
EdgeCountMismatch,
MissingNodeKey,
MissingCsrSection {
kind: u32,
},
MissingMetadataSection,
MalformedMetadata(alloc::string::String),
MissingReverseIndex,
TopologyNodeCountMismatch,
TopologyEdgeCountMismatch,
MetadataNodeCountMismatch,
MetadataEdgeCountMismatch,
Spi(alloc::string::String),
}
impl fmt::Display for BuildError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Plan(error) => write!(f, "plan error: {error}"),
Self::Graph(error) => write!(f, "graph build error: {error}"),
Self::MissingSnapshotBytes => f.write_str("snapshot bytes required"),
Self::EmptyEdges => f.write_str("build requires at least one edge row"),
Self::NodeCountOverflow => f.write_str("node count does not fit in u32 metadata"),
Self::EdgeCountOverflow => f.write_str("edge count does not fit in u32 metadata"),
Self::EdgeCountMismatch | Self::TopologyEdgeCountMismatch => {
f.write_str("forward and inbound edge counts diverged")
}
Self::MissingNodeKey => f.write_str("edge row references missing node key"),
Self::MissingCsrSection { kind } => {
write!(f, "missing CSR section {kind:#06x}")
}
Self::MissingMetadataSection => f.write_str("postgres metadata section missing"),
Self::MalformedMetadata(message) => write!(f, "postgres metadata layout: {message}"),
Self::MissingReverseIndex => {
f.write_str("artifact missing HAS_REVERSE_INDEX metadata flag")
}
Self::TopologyNodeCountMismatch => {
f.write_str("forward and inbound node counts diverged")
}
Self::MetadataNodeCountMismatch => {
f.write_str("forward node count disagrees with metadata")
}
Self::MetadataEdgeCountMismatch => {
f.write_str("forward edge count disagrees with metadata")
}
Self::Spi(message) => write!(f, "spi: {message}"),
}
}
}
impl core::error::Error for BuildError {}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum QueryError {
SeedOutOfBounds {
seed: u32,
node_count: u32,
},
LimitZero,
NodeIndexOverflow,
InternalInvariant(&'static str),
}
impl fmt::Display for QueryError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::SeedOutOfBounds { seed, node_count } => {
write!(f, "seed {seed} out of bounds (node_count {node_count})")
}
Self::LimitZero => f.write_str("limit must be > 0"),
Self::NodeIndexOverflow => f.write_str("node index does not fit in u32"),
Self::InternalInvariant(message) => write!(f, "internal query invariant: {message}"),
}
}
}
impl core::error::Error for QueryError {}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SyncError {
NonMonotonicSequence {
sequence: u64,
previous: u64,
},
InvalidActionType {
action_type: i16,
},
InvalidActionArgs {
action_type: i16,
},
UnknownNodeKey {
key: crate::catalog::NodeKey,
},
}
impl fmt::Display for SyncError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::NonMonotonicSequence { sequence, previous } => {
write!(f, "non-monotonic sync sequence {sequence} after {previous}")
}
Self::InvalidActionType { action_type } => {
write!(f, "invalid sync action type {action_type}")
}
Self::InvalidActionArgs { action_type } => {
write!(f, "invalid sync action arguments for type {action_type}")
}
Self::UnknownNodeKey { key } => write!(f, "unknown sync node key {key}"),
}
}
}
impl core::error::Error for SyncError {}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ConfigError {
ZeroTraverseLimit,
ZeroSearchLimit,
MaintenanceDisabled,
}
impl fmt::Display for ConfigError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::ZeroTraverseLimit => f.write_str("traverse_limit must be > 0"),
Self::ZeroSearchLimit => f.write_str("search_limit must be > 0"),
Self::MaintenanceDisabled => f.write_str("maintenance rebuild disabled by config"),
}
}
}
impl core::error::Error for ConfigError {}
#[derive(Debug)]
pub enum PostgresGraphError {
Snapshot(SnapshotError),
ForwardSnapshot(CsrSnapshotError<u32, u32>),
InboundSnapshot(CscSnapshotError),
NotLoaded,
Build(BuildError),
Catalog(CatalogError),
Query(QueryError),
Sync(SyncError),
Config(ConfigError),
AccessDenied {
required: GraphRole,
actual: GraphRole,
},
}
impl fmt::Display for PostgresGraphError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Snapshot(error) => write!(f, "snapshot error: {error}"),
Self::ForwardSnapshot(error) => write!(f, "forward snapshot error: {error}"),
Self::InboundSnapshot(error) => write!(f, "inbound snapshot error: {error}"),
Self::NotLoaded => f.write_str("graph engine not loaded"),
Self::Build(error) => write!(f, "build error: {error}"),
Self::Catalog(error) => write!(f, "catalog error: {error}"),
Self::Query(error) => write!(f, "query error: {error}"),
Self::Sync(error) => write!(f, "sync error: {error}"),
Self::Config(error) => write!(f, "config error: {error}"),
Self::AccessDenied { required, actual } => {
write!(f, "access denied: {actual:?} cannot satisfy {required:?}")
}
}
}
}
impl core::error::Error for PostgresGraphError {}
impl From<SnapshotError> for PostgresGraphError {
fn from(error: SnapshotError) -> Self {
Self::Snapshot(error)
}
}
impl From<CsrSnapshotError<u32, u32>> for PostgresGraphError {
fn from(error: CsrSnapshotError<u32, u32>) -> Self {
Self::ForwardSnapshot(error)
}
}
impl From<CscSnapshotError> for PostgresGraphError {
fn from(error: CscSnapshotError) -> Self {
Self::InboundSnapshot(error)
}
}
impl From<PlanError> for PostgresGraphError {
fn from(error: PlanError) -> Self {
Self::Build(BuildError::Plan(error))
}
}
impl From<oxgraph_csr::build::GraphBuildError<u32, u32>> for PostgresGraphError {
fn from(error: oxgraph_csr::build::GraphBuildError<u32, u32>) -> Self {
Self::Build(BuildError::Graph(error))
}
}
impl From<CatalogError> for PostgresGraphError {
fn from(error: CatalogError) -> Self {
Self::Catalog(error)
}
}
impl From<BuildError> for PostgresGraphError {
fn from(error: BuildError) -> Self {
Self::Build(error)
}
}
impl From<QueryError> for PostgresGraphError {
fn from(error: QueryError) -> Self {
Self::Query(error)
}
}
impl From<SyncError> for PostgresGraphError {
fn from(error: SyncError) -> Self {
Self::Sync(error)
}
}
impl From<ConfigError> for PostgresGraphError {
fn from(error: ConfigError) -> Self {
Self::Config(error)
}
}