Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(psql): introduce column type ltree #604

Merged
merged 2 commits into from
Oct 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/backend/mysql/table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ impl TableBuilder for MysqlQueryBuilder {
ColumnType::Cidr => unimplemented!("Cidr is not available in MySQL."),
ColumnType::Inet => unimplemented!("Inet is not available in MySQL."),
ColumnType::MacAddr => unimplemented!("MacAddr is not available in MySQL."),
ColumnType::LTree => unimplemented!("LTree is not available in MySQL."),
}
)
.unwrap();
Expand Down
1 change: 1 addition & 0 deletions src/backend/postgres/table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ impl TableBuilder for PostgresQueryBuilder {
ColumnType::Inet => "inet".into(),
ColumnType::MacAddr => "macaddr".into(),
ColumnType::Year(_) => unimplemented!("Year is not available in Postgres."),
ColumnType::LTree => "ltree".into(),
}
)
.unwrap()
Expand Down
1 change: 1 addition & 0 deletions src/backend/sqlite/table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ impl TableBuilder for SqliteQueryBuilder {
ColumnType::Year(_) => unimplemented!("Year is not available in Sqlite."),
ColumnType::Bit(_) => unimplemented!("Bit is not available in Sqlite."),
ColumnType::VarBit(_) => unimplemented!("VarBit is not available in Sqlite."),
ColumnType::LTree => unimplemented!("LTree is not available in Sqlite."),
}
)
.unwrap()
Expand Down
57 changes: 57 additions & 0 deletions src/extension/postgres/ltree.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
use std::fmt;

/// PostgreSQL `ltree` extension type.
///
/// `ltree` stores a raber path which in this struct is represented as the
/// tuple's first value.
///
/// # PostcreSQL Reference
///
/// The following set of SQL statements can be used to create a table with
/// a `ltree` column. Here the `ltree` column is called `path`.
///
/// The `path` column is then populated to generate the tree.
///
/// ```ignore
/// CREATE TABLE test (path ltree);
/// INSERT INTO test VALUES ('Top');
/// INSERT INTO test VALUES ('Top.Science');
/// INSERT INTO test VALUES ('Top.Science.Astronomy');
/// INSERT INTO test VALUES ('Top.Science.Astronomy.Astrophysics');
/// INSERT INTO test VALUES ('Top.Science.Astronomy.Cosmology');
/// INSERT INTO test VALUES ('Top.Hobbies');
/// INSERT INTO test VALUES ('Top.Hobbies.Amateurs_Astronomy');
/// INSERT INTO test VALUES ('Top.Collections');
/// INSERT INTO test VALUES ('Top.Collections.Pictures');
/// INSERT INTO test VALUES ('Top.Collections.Pictures.Astronomy');
/// INSERT INTO test VALUES ('Top.Collections.Pictures.Astronomy.Stars');
/// INSERT INTO test VALUES ('Top.Collections.Pictures.Astronomy.Galaxies');
/// INSERT INTO test VALUES ('Top.Collections.Pictures.Astronomy.Astronauts');
/// CREATE INDEX path_gist_idx ON test USING GIST (path);
/// CREATE INDEX path_idx ON test USING BTREE (path);
/// ```
///
/// The set of queries above will generate the following tree:
///
/// ```ignore
/// Top
/// / | \
/// Science Hobbies Collections
/// / | \
/// Astronomy Amateurs_Astronomy Pictures
/// / \ |
/// Astrophysics Cosmology Astronomy
/// / | \
/// Galaxies Stars Astronauts
/// ```
/// [Source][1]
///
/// [1]: https://www.postgresql.org/docs/current/ltree.html
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct PgLTree;

impl fmt::Display for PgLTree {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "ltree")
}
}
2 changes: 2 additions & 0 deletions src/extension/postgres/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ pub use expr::*;
pub use extension::*;
pub use func::*;
pub use interval::*;
pub use ltree::*;
pub use types::*;

use crate::types::BinOper;
Expand All @@ -10,6 +11,7 @@ pub(crate) mod expr;
pub(crate) mod extension;
pub(crate) mod func;
pub(crate) mod interval;
pub(crate) mod ltree;
pub(crate) mod types;

/// Binary operator
Expand Down
8 changes: 8 additions & 0 deletions src/table/column.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ pub enum ColumnType {
Cidr,
Inet,
MacAddr,
LTree,
}

impl PartialEq for ColumnType {
Expand Down Expand Up @@ -580,6 +581,13 @@ impl ColumnDef {
self
}

/// Set column type as `ltree`
/// This is only supported on Postgres.
pub fn ltree(&mut self) -> &mut Self {
self.types = Some(ColumnType::LTree);
self
}

/// Set constraints as SimpleExpr
pub fn check<T>(&mut self, value: T) -> &mut Self
where
Expand Down
3 changes: 1 addition & 2 deletions tests/mysql/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -998,8 +998,7 @@ fn select_58() {
.and_where(Expr::col(Char::Character).like(LikeExpr::new("A").escape('\\')))
.build(MysqlQueryBuilder),
(
r#"SELECT `character` FROM `character` WHERE `character` LIKE ? ESCAPE '\\'"#
.to_owned(),
r"SELECT `character` FROM `character` WHERE `character` LIKE ? ESCAPE '\\'".to_owned(),
Values(vec!["A".into()])
)
);
Expand Down
24 changes: 24 additions & 0 deletions tests/postgres/table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -597,3 +597,27 @@ fn alter_with_check_constraint() {
r#"ALTER TABLE "glyph" ADD COLUMN "aspect" integer NOT NULL DEFAULT 101 CHECK ("aspect" > 100)"#,
);
}

#[test]
fn create_16() {
assert_eq!(
Table::create()
.table(Glyph::Table)
.col(
ColumnDef::new(Glyph::Id)
.integer()
.not_null()
.auto_increment()
.primary_key()
)
.col(ColumnDef::new(Glyph::Tokens).ltree())
.to_string(PostgresQueryBuilder),
[
r#"CREATE TABLE "glyph" ("#,
r#""id" serial NOT NULL PRIMARY KEY,"#,
r#""tokens" ltree"#,
r#")"#,
]
.join(" ")
);
}