Skip to main content

uni_common/api/
error.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2024-2026 Dragonscale Team
3
4use std::path::PathBuf;
5use thiserror::Error;
6
7#[derive(Debug, Error)]
8#[non_exhaustive]
9pub enum UniError {
10    #[error("Database not found: {path}")]
11    NotFound { path: PathBuf },
12
13    #[error("Schema error: {message}")]
14    Schema { message: String },
15
16    #[error("Parse error: {message}")]
17    Parse {
18        message: String,
19        position: Option<usize>,
20        line: Option<usize>,
21        column: Option<usize>,
22        context: Option<String>,
23    },
24
25    #[error("Query error: {message}")]
26    Query {
27        message: String,
28        query: Option<String>,
29    },
30
31    #[error("Transaction error: {message}")]
32    Transaction { message: String },
33
34    #[error("Transaction conflict: {message}")]
35    TransactionConflict { message: String },
36
37    #[error("Transaction already completed")]
38    TransactionAlreadyCompleted,
39
40    /// Operation not supported on read-only database
41    #[error("Operation '{operation}' not supported on read-only database")]
42    ReadOnly { operation: String },
43
44    /// Label not found in schema
45    #[error("Label '{label}' not found in schema")]
46    LabelNotFound { label: String },
47
48    /// Edge type not found in schema
49    #[error("Edge type '{edge_type}' not found in schema")]
50    EdgeTypeNotFound { edge_type: String },
51
52    /// Property not found on node/edge
53    #[error("Property '{property}' not found on {entity_type} with label '{label}'")]
54    PropertyNotFound {
55        property: String,
56        entity_type: String, // "node" or "edge"
57        label: String,
58    },
59
60    /// Index not found
61    #[error("Index '{index}' not found")]
62    IndexNotFound { index: String },
63
64    /// Snapshot not found
65    #[error("Snapshot '{snapshot_id}' not found")]
66    SnapshotNotFound { snapshot_id: String },
67
68    /// Query memory limit exceeded
69    #[error("Query exceeded memory limit of {limit_bytes} bytes")]
70    MemoryLimitExceeded { limit_bytes: usize },
71
72    #[error("Database is locked by another process")]
73    DatabaseLocked,
74
75    #[error("Operation timed out after {timeout_ms}ms")]
76    Timeout { timeout_ms: u64 },
77
78    #[error("Type error: expected {expected}, got {actual}")]
79    Type { expected: String, actual: String },
80
81    #[error("Constraint violation: {message}")]
82    Constraint { message: String },
83
84    #[error("Storage error: {message}")]
85    Storage {
86        message: String,
87        #[source]
88        source: Option<Box<dyn std::error::Error + Send + Sync>>,
89    },
90
91    #[error("IO error: {0}")]
92    Io(#[from] std::io::Error),
93
94    #[error("Internal error: {0}")]
95    Internal(#[from] anyhow::Error),
96
97    #[error("Invalid identifier '{name}': {reason}")]
98    InvalidIdentifier { name: String, reason: String },
99
100    #[error("Label '{label}' already exists")]
101    LabelAlreadyExists { label: String },
102
103    #[error("Edge type '{edge_type}' already exists")]
104    EdgeTypeAlreadyExists { edge_type: String },
105
106    #[error("Permission denied: {action}")]
107    PermissionDenied { action: String },
108
109    #[error("Argument '{arg}' is invalid: {message}")]
110    InvalidArgument { arg: String, message: String },
111
112    /// Write context (transaction, bulk writer, or appender) is already active on session.
113    #[error("A write context is already active on session '{session_id}'")]
114    WriteContextAlreadyActive {
115        session_id: String,
116        hint: &'static str,
117    },
118
119    /// Transaction commit timed out waiting for the global writer lock.
120    #[error("Transaction '{tx_id}' commit timed out")]
121    CommitTimeout { tx_id: String, hint: &'static str },
122
123    /// Transaction exceeded its deadline.
124    #[error("Transaction '{tx_id}' expired")]
125    TransactionExpired { tx_id: String, hint: &'static str },
126
127    /// Operation was cancelled via a cancellation token.
128    #[error("Operation cancelled")]
129    Cancelled,
130
131    /// Derived facts are stale relative to the current database version.
132    #[error("Derived facts are stale: version gap is {version_gap}")]
133    StaleDerivedFacts { version_gap: u64 },
134
135    /// A Locy rule conflict was detected during transaction commit rule promotion.
136    #[error("Rule conflict: rule '{rule_name}' conflicts during promotion")]
137    RuleConflict { rule_name: String },
138
139    /// A session hook rejected the operation.
140    #[error("Hook rejected: {message}")]
141    HookRejected { message: String },
142}
143
144pub type Result<T> = std::result::Result<T, UniError>;