linkrs_server/graph_service/
error.rs1use linkrs_core::types::Position;
2
3#[derive(Debug, Clone)]
6pub struct GraphServiceError {
7 pub message: String,
8 pub position: Option<Position>,
9}
10
11impl std::fmt::Display for GraphServiceError {
12 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13 write!(f, "{}", self.message)
14 }
15}
16
17impl std::error::Error for GraphServiceError {}
18
19impl GraphServiceError {
20 pub fn new(message: impl Into<String>) -> Self {
21 Self {
22 message: message.into(),
23 position: None,
24 }
25 }
26
27 pub fn with_position(message: impl Into<String>, position: Option<Position>) -> Self {
28 Self {
29 message: message.into(),
30 position: position.filter(|p| p.is_valid()),
31 }
32 }
33
34 pub fn message(&self) -> &str {
35 &self.message
36 }
37
38 pub fn position(&self) -> Option<Position> {
39 self.position
40 }
41
42 pub fn from_core_error(e: linkrs_api::api_core::CoreError) -> Self {
43 let message = e.to_string();
44 let position = e.error_position().filter(|p| p.is_valid());
45 let position = match (position, e.error_offset()) {
46 (Some(pos), _) => Some(pos),
47 (None, _) => None,
48 };
49 Self { message, position }
50 }
51
52 pub fn from_core_error_with_query(e: linkrs_api::api_core::CoreError, query: &str) -> Self {
53 let message = e.to_string();
54 if let Some(pos) = e.error_position().filter(|p| p.is_valid()) {
55 return Self {
56 message,
57 position: Some(pos),
58 };
59 }
60 if let Some(offset) = e.error_offset() {
61 return Self {
62 message,
63 position: offset_to_position(query, offset),
64 };
65 }
66 Self {
67 message,
68 position: None,
69 }
70 }
71}
72
73impl From<String> for GraphServiceError {
74 fn from(message: String) -> Self {
75 Self::new(message)
76 }
77}
78
79impl From<&str> for GraphServiceError {
80 fn from(message: &str) -> Self {
81 Self::new(message)
82 }
83}
84
85pub(crate) fn offset_to_position(query: &str, offset: usize) -> Option<Position> {
87 let offset = offset.min(query.len());
88 let prefix = &query[..offset];
89 let line = prefix.bytes().filter(|b| *b == b'\n').count() + 1;
90 let column = prefix
91 .rsplit('\n')
92 .next()
93 .map(|s| s.chars().count() + 1)
94 .unwrap_or(1);
95 let position = Position::new(line, column);
96 position.is_valid().then_some(position)
97}