hamelin_lib 0.21.7

Core library for Hamelin query language
Documentation
//! Identifier builder for constructing simple and compound identifiers
//!
//! This module provides a fluent API for building identifiers with dots.

use crate::tree::ast::identifier::{CompoundIdentifier, Identifier, SimpleIdentifier};

/// Builder for identifiers
#[derive(Debug)]
pub struct IdentifierBuilder {
    parts: Vec<SimpleIdentifier>,
}

impl IdentifierBuilder {
    pub fn new(name: impl Into<String>) -> Self {
        Self {
            parts: vec![SimpleIdentifier::new(name)],
        }
    }

    /// Add another part to create a compound identifier
    /// Example: `ident("schema").dot("table").dot("column")`
    pub fn dot(mut self, name: impl Into<String>) -> Self {
        self.parts.push(SimpleIdentifier::new(name));
        self
    }

    pub fn build(&self) -> Identifier {
        match self.parts.as_slice() {
            [] => unreachable!("IdentifierBuilder always has at least one part"),
            [single] => single.clone().into(),
            [first, second, rest @ ..] => {
                CompoundIdentifier::new(first.clone(), second.clone(), rest.to_vec()).into()
            }
        }
    }
}

// Allow IdentifierBuilder to be converted into Identifier
impl From<IdentifierBuilder> for Identifier {
    fn from(builder: IdentifierBuilder) -> Self {
        builder.build()
    }
}

/// Create an identifier builder
pub fn ident(name: impl Into<String>) -> IdentifierBuilder {
    IdentifierBuilder::new(name)
}

// Convenience conversions for builder API
impl From<String> for Identifier {
    fn from(name: String) -> Self {
        SimpleIdentifier::new(name).into()
    }
}

impl From<&str> for Identifier {
    fn from(name: &str) -> Self {
        SimpleIdentifier::new(name).into()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use pretty_assertions::assert_eq;

    #[test]
    fn test_simple_identifier() {
        let id = ident("column").build();
        match id {
            Identifier::Simple(s) => assert!(s == "column"),
            _ => panic!("Expected simple identifier"),
        }
    }

    #[test]
    fn test_compound_identifier_two_parts() {
        let id = ident("table").dot("column").build();
        match id {
            Identifier::Compound(c) => {
                assert_eq!(c.parts().len(), 2);
                assert!(c.parts()[0] == "table");
                assert!(c.parts()[1] == "column");
            }
            _ => panic!("Expected compound identifier"),
        }
    }

    #[test]
    fn test_compound_identifier_three_parts() {
        let id = ident("schema").dot("table").dot("column").build();
        match id {
            Identifier::Compound(c) => {
                assert_eq!(c.parts().len(), 3);
                assert!(c.parts()[0] == "schema");
                assert!(c.parts()[1] == "table");
                assert!(c.parts()[2] == "column");
            }
            _ => panic!("Expected compound identifier"),
        }
    }

    #[test]
    fn test_identifier_from_string() {
        let id: Identifier = "column".into();
        match id {
            Identifier::Simple(s) => assert!(s == "column"),
            _ => panic!("Expected simple identifier"),
        }
    }
}