fosk 0.2.0

In-memory SQL-like query engine and lightweight data store for testing and prototyping.
Documentation
use std::fmt::Display;

use crate::parser::QueryParser;

#[derive(Debug, Clone)]
pub struct ParseError {
    pub message: String,
    pub text: String,
    pub start: usize,
    pub end: usize,
}

impl ParseError {
    pub fn new(message: &str, pivot: usize, parser: &QueryParser) -> Self {
        Self {
            message: message.to_string(),
            text: parser.text_from_range(pivot, parser.position + 1),
            start: pivot,
            end: parser.position,
        }
    }

    pub fn err<T>(self) -> Result<T, ParseError> {
        Err(self)
    }
}

impl Display for ParseError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "ParseError: {}\n  at [{}:{}] -> '{}'",
            self.message, self.start, self.end, self.text
        )
    }
}

#[cfg(test)]
mod tests {
    use super::ParseError;
    use crate::parser::QueryParser;

    #[test]
    fn new_captures_parser_range_at_pivot() {
        let mut parser = QueryParser::new("select *");
        parser.jump(3);

        let error = ParseError::new("bad token", 1, &parser);

        assert_eq!(error.message, "bad token");
        assert_eq!(error.text, "ele");
        assert_eq!(error.start, 1);
        assert_eq!(error.end, 3);
    }

    #[test]
    fn err_wraps_error_in_result() {
        let parser = QueryParser::new("x");
        let error = ParseError::new("bad token", 0, &parser);
        let result: Result<(), ParseError> = error.err();

        assert!(result.is_err());
    }

    #[test]
    fn display_includes_message_location_and_text() {
        let parser = QueryParser::new("x");
        let error = ParseError::new("bad token", 0, &parser);

        assert_eq!(
            error.to_string(),
            "ParseError: bad token\n  at [0:0] -> 'x'"
        );
    }
}