postgrest-parser 0.2.0

PostgREST URL-to-SQL parser for Rust and WASM
Documentation
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum ItemType {
    Field,
    Relation,
    Spread,
}

#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(untagged)]
pub enum ItemHint {
    Inner(String),
    JsonPathCast(Vec<String>, String),
    JsonPath(Vec<String>),
    Cast(String),
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SelectItem {
    pub item_type: ItemType,
    pub name: String,
    pub alias: Option<String>,
    pub children: Option<Vec<SelectItem>>,
    pub hint: Option<ItemHint>,
}

impl SelectItem {
    pub fn field(name: impl Into<String>) -> Self {
        Self {
            item_type: ItemType::Field,
            name: name.into(),
            alias: None,
            children: None,
            hint: None,
        }
    }

    pub fn with_alias(mut self, alias: impl Into<String>) -> Self {
        self.alias = Some(alias.into());
        self
    }

    pub fn with_children(mut self, children: Vec<SelectItem>) -> Self {
        self.children = Some(children);
        self
    }

    pub fn with_hint(mut self, hint: ItemHint) -> Self {
        self.hint = Some(hint);
        self
    }

    pub fn relation(name: impl Into<String>) -> Self {
        Self {
            item_type: ItemType::Relation,
            name: name.into(),
            alias: None,
            children: None,
            hint: None,
        }
    }

    pub fn spread(name: impl Into<String>) -> Self {
        Self {
            item_type: ItemType::Spread,
            name: name.into(),
            alias: None,
            children: None,
            hint: None,
        }
    }

    pub fn wildcard() -> Self {
        Self::field("*".to_string())
    }
}

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

    #[test]
    fn test_select_item_field() {
        let item = SelectItem::field("id");
        assert_eq!(item.item_type, ItemType::Field);
        assert_eq!(item.name, "id");
        assert!(item.alias.is_none());
    }

    #[test]
    fn test_select_item_with_alias() {
        let item = SelectItem::field("name").with_alias("user_name");
        assert_eq!(item.alias, Some("user_name".to_string()));
    }

    #[test]
    fn test_select_item_with_children() {
        let item = SelectItem::relation("client")
            .with_children(vec![SelectItem::field("id"), SelectItem::field("name")]);
        assert_eq!(item.item_type, ItemType::Relation);
        assert_eq!(item.children.as_ref().unwrap().len(), 2);
    }

    #[test]
    fn test_select_item_wildcard() {
        let item = SelectItem::wildcard();
        assert_eq!(item.name, "*");
        assert_eq!(item.item_type, ItemType::Field);
    }

    #[test]
    fn test_select_item_spread() {
        let item = SelectItem::spread("profile");
        assert_eq!(item.item_type, ItemType::Spread);
        assert_eq!(item.name, "profile");
    }

    #[test]
    fn test_select_item_serialization() {
        let item = SelectItem::field("id").with_alias("user_id");
        let json = serde_json::to_string(&item).unwrap();
        assert!(json.contains("id"));
        assert!(json.contains("user_id"));
    }
}