Skip to content

Commit

Permalink
Initial postgres ltree support
Browse files Browse the repository at this point in the history
  • Loading branch information
halfmatthalfcat committed Feb 18, 2022
1 parent 0b9aa16 commit be7c91a
Show file tree
Hide file tree
Showing 7 changed files with 806 additions and 1 deletion.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
Cargo.lock
.direnv/
.vscode/
.idea/
2 changes: 1 addition & 1 deletion src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ mod update;
mod values;

pub use column::{Column, DefaultValue, TypeDataLength, TypeFamily};
pub use compare::{Comparable, Compare, JsonCompare, JsonType};
pub use compare::{Comparable, Compare, JsonCompare, JsonType, LtreeCompare};
pub use conditions::ConditionTree;
pub use conjunctive::Conjunctive;
pub use cte::{CommonTableExpression, IntoCommonTableExpression};
Expand Down
278 changes: 278 additions & 0 deletions src/ast/compare.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ pub enum Compare<'a> {
/// (NOT `left` @@ to_tsquery(`value`))
#[cfg(feature = "postgresql")]
NotMatches(Box<Expression<'a>>, Cow<'a, str>),
#[cfg(feature = "postgresql")]
LtreeCompare(LtreeCompare<'a>),
}

#[derive(Debug, Clone, PartialEq)]
Expand All @@ -72,6 +74,26 @@ pub enum JsonType {
Null,
}

#[derive(Debug, Clone, PartialEq)]
pub enum LtreeCompare<'a> {
IsAncestor(Box<Expression<'a>>, Box<Expression<'a>>),
IsNotAncestor(Box<Expression<'a>>, Box<Expression<'a>>),
IsAncestorAny(Box<Expression<'a>>, Vec<Expression<'a>>),
IsNotAncestorAny(Box<Expression<'a>>, Vec<Expression<'a>>),
IsDescendant(Box<Expression<'a>>, Box<Expression<'a>>),
IsNotDescendant(Box<Expression<'a>>, Box<Expression<'a>>),
IsDescendantAny(Box<Expression<'a>>, Vec<Expression<'a>>),
IsNotDescendantAny(Box<Expression<'a>>, Vec<Expression<'a>>),
Matches(Box<Expression<'a>>, Box<Expression<'a>>),
DoesNotMatch(Box<Expression<'a>>, Box<Expression<'a>>),
MatchesAny(Box<Expression<'a>>, Vec<Expression<'a>>),
DoesNotMatchAny(Box<Expression<'a>>, Vec<Expression<'a>>),
MatchesFullText(Box<Expression<'a>>, Box<Expression<'a>>),
DoesNotMatchFullText(Box<Expression<'a>>, Box<Expression<'a>>),
MatchesFullTextAny(Box<Expression<'a>>, Vec<Expression<'a>>),
DoesNotMatchFullTextAny(Box<Expression<'a>>, Vec<Expression<'a>>),
}

impl<'a> Compare<'a> {
/// Finds a possible `(a,y) IN (SELECT x,z FROM B)`, takes the select out and
/// converts the comparison into `a IN (SELECT x FROM cte_n where z = y)`.
Expand Down Expand Up @@ -873,6 +895,86 @@ pub trait Comparable<'a> {
where
T: Into<Cow<'a, str>>,
V: Into<Expression<'a>>;

#[cfg(feature = "postgresql")]
fn ltree_is_ancestor<T>(self, ltree: T) -> Compare<'a>
where
T: Into<Expression<'a>>;

#[cfg(feature = "postgresql")]
fn ltree_is_not_ancestor<T>(self, ltree: T) -> Compare<'a>
where
T: Into<Expression<'a>>;

#[cfg(feature = "postgresql")]
fn ltree_is_ancestor_any<T>(self, ltree: T) -> Compare<'a>
where
T: Into<Vec<Expression<'a>>>;

#[cfg(feature = "postgresql")]
fn ltree_is_not_ancestor_any<T>(self, ltree: T) -> Compare<'a>
where
T: Into<Vec<Expression<'a>>>;

#[cfg(feature = "postgresql")]
fn ltree_is_descendant<T>(self, ltree: T) -> Compare<'a>
where
T: Into<Expression<'a>>;

#[cfg(feature = "postgresql")]
fn ltree_is_not_descendant<T>(self, ltree: T) -> Compare<'a>
where
T: Into<Expression<'a>>;

#[cfg(feature = "postgresql")]
fn ltree_is_descendant_any<T>(self, ltree: T) -> Compare<'a>
where
T: Into<Vec<Expression<'a>>>;

#[cfg(feature = "postgresql")]
fn ltree_is_not_descendant_any<T>(self, ltree: T) -> Compare<'a>
where
T: Into<Vec<Expression<'a>>>;

#[cfg(feature = "postgresql")]
fn ltree_match<T>(self, lquery: T) -> Compare<'a>
where
T: Into<Expression<'a>>;

#[cfg(feature = "postgresql")]
fn ltree_does_not_match<T>(self, lquery: T) -> Compare<'a>
where
T: Into<Expression<'a>>;

#[cfg(feature = "postgresql")]
fn ltree_match_any<T>(self, lqueries: T) -> Compare<'a>
where
T: Into<Vec<Expression<'a>>>;

#[cfg(feature = "postgresql")]
fn ltree_does_not_match_any<T>(self, lqueries: T) -> Compare<'a>
where
T: Into<Vec<Expression<'a>>>;

#[cfg(feature = "postgresql")]
fn ltree_match_fulltext<T>(self, ltxtquery: T) -> Compare<'a>
where
T: Into<Expression<'a>>;

#[cfg(feature = "postgresql")]
fn ltree_does_not_match_fulltext<T>(self, ltxtquery: T) -> Compare<'a>
where
T: Into<Expression<'a>>;

#[cfg(feature = "postgresql")]
fn ltree_match_fulltext_any<T>(self, ltxtqueries: T) -> Compare<'a>
where
T: Into<Vec<Expression<'a>>>;

#[cfg(feature = "postgresql")]
fn ltree_does_not_match_fulltext_any<T>(self, ltxtqueries: T) -> Compare<'a>
where
T: Into<Vec<Expression<'a>>>;
}

impl<'a, U> Comparable<'a> for U
Expand Down Expand Up @@ -1150,4 +1252,180 @@ where

val.not_matches(query)
}

#[cfg(feature = "postgresql")]
fn ltree_is_ancestor<T>(self, ltree: T) -> Compare<'a>
where
T: Into<Expression<'a>>
{
let col: Column<'a> = self.into();
let val: Expression<'a> = col.into();

val.ltree_is_ancestor(ltree)
}

#[cfg(feature = "postgresql")]
fn ltree_is_not_ancestor<T>(self, ltree: T) -> Compare<'a>
where
T: Into<Expression<'a>>
{
let col: Column<'a> = self.into();
let val: Expression<'a> = col.into();

val.ltree_is_not_ancestor(ltree)
}

#[cfg(feature = "postgresql")]
fn ltree_is_ancestor_any<T>(self, ltree: T) -> Compare<'a>
where
T: Into<Vec<Expression<'a>>>
{
let col: Column<'a> = self.into();
let val: Expression<'a> = col.into();

val.ltree_is_ancestor_any(ltree)
}

#[cfg(feature = "postgresql")]
fn ltree_is_not_ancestor_any<T>(self, ltree: T) -> Compare<'a>
where
T: Into<Vec<Expression<'a>>>
{
let col: Column<'a> = self.into();
let val: Expression<'a> = col.into();

val.ltree_is_not_ancestor_any(ltree)
}

#[cfg(feature = "postgresql")]
fn ltree_is_descendant<T>(self, ltree: T) -> Compare<'a>
where
T: Into<Expression<'a>>
{
let col: Column<'a> = self.into();
let val: Expression<'a> = col.into();

val.ltree_is_descendant(ltree)
}

#[cfg(feature = "postgresql")]
fn ltree_is_not_descendant<T>(self, ltree: T) -> Compare<'a>
where
T: Into<Expression<'a>>
{
let col: Column<'a> = self.into();
let val: Expression<'a> = col.into();

val.ltree_is_not_descendant(ltree)
}

#[cfg(feature = "postgresql")]
fn ltree_is_descendant_any<T>(self, ltree: T) -> Compare<'a>
where
T: Into<Vec<Expression<'a>>>
{
let col: Column<'a> = self.into();
let val: Expression<'a> = col.into();

val.ltree_is_descendant_any(ltree)
}

#[cfg(feature = "postgresql")]
fn ltree_is_not_descendant_any<T>(self, ltree: T) -> Compare<'a>
where
T: Into<Vec<Expression<'a>>>
{
let col: Column<'a> = self.into();
let val: Expression<'a> = col.into();

val.ltree_is_not_descendant_any(ltree)
}

#[cfg(feature = "postgresql")]
fn ltree_match<T>(self, lquery: T) -> Compare<'a>
where
T: Into<Expression<'a>>
{
let col: Column<'a> = self.into();
let val: Expression<'a> = col.into();

val.ltree_match(lquery)
}

#[cfg(feature = "postgresql")]
fn ltree_does_not_match<T>(self, lquery: T) -> Compare<'a>
where
T: Into<Expression<'a>>
{
let col: Column<'a> = self.into();
let val: Expression<'a> = col.into();

val.ltree_does_not_match(lquery)
}

#[cfg(feature = "postgresql")]
fn ltree_match_any<T>(self, lqueries: T) -> Compare<'a>
where
T: Into<Vec<Expression<'a>>>
{
let col: Column<'a> = self.into();
let val: Expression<'a> = col.into();

val.ltree_match_any(lqueries)
}

#[cfg(feature = "postgresql")]
fn ltree_does_not_match_any<T>(self, lqueries: T) -> Compare<'a>
where
T: Into<Vec<Expression<'a>>>
{
let col: Column<'a> = self.into();
let val: Expression<'a> = col.into();

val.ltree_does_not_match_any(lqueries)
}

#[cfg(feature = "postgresql")]
fn ltree_match_fulltext<T>(self, ltxtquery: T) -> Compare<'a>
where
T: Into<Expression<'a>>
{
let col: Column<'a> = self.into();
let val: Expression<'a> = col.into();

val.ltree_match_fulltext(ltxtquery)
}

#[cfg(feature = "postgresql")]
fn ltree_does_not_match_fulltext<T>(self, ltxtquery: T) -> Compare<'a>
where
T: Into<Expression<'a>>
{
let col: Column<'a> = self.into();
let val: Expression<'a> = col.into();

val.ltree_does_not_match_fulltext(ltxtquery)
}

#[cfg(feature = "postgresql")]
fn ltree_match_fulltext_any<T>(self, ltxtqueries: T) -> Compare<'a>
where
T: Into<Vec<Expression<'a>>>
{
let col: Column<'a> = self.into();
let val: Expression<'a> = col.into();

val.ltree_match_fulltext_any(ltxtqueries)
}

#[cfg(feature = "postgresql")]
fn ltree_does_not_match_fulltext_any<T>(self, ltxtqueries: T) -> Compare<'a>
where
T: Into<Vec<Expression<'a>>>
{
let col: Column<'a> = self.into();
let val: Expression<'a> = col.into();

val.ltree_does_not_match_fulltext_any(ltxtqueries)
}
}
Loading

0 comments on commit be7c91a

Please sign in to comment.