Skip to content

Commit ea3a5a7

Browse files
Add ltree, lquery and ltxtquery support
1 parent 25cabd5 commit ea3a5a7

File tree

6 files changed

+131
-16
lines changed

6 files changed

+131
-16
lines changed

postgres-protocol/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "postgres-protocol"
3-
version = "0.6.3"
3+
version = "0.6.4"
44
authors = ["Steven Fackler <sfackler@gmail.com>"]
55
edition = "2018"
66
description = "Low level Postgres protocol APIs"

postgres-protocol/src/types/mod.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1059,3 +1059,19 @@ impl Inet {
10591059
self.netmask
10601060
}
10611061
}
1062+
1063+
/// Serializes a Postgres l{tree,query,txtquery} string
1064+
#[inline]
1065+
pub fn ltree_to_sql(v: &str, buf: &mut BytesMut) {
1066+
// A version number is prepended to an Ltree string per spec
1067+
buf.put_u8(1);
1068+
// Append the rest of the query
1069+
buf.put_slice(v.as_bytes());
1070+
}
1071+
1072+
/// Deserialize a Postgres l{tree,query,txtquery} string
1073+
#[inline]
1074+
pub fn ltree_from_sql(buf: &[u8]) -> Result<&str, StdBox<dyn Error + Sync + Send>> {
1075+
// Remove the version number from the front of the string per spec
1076+
Ok(str::from_utf8(&buf[1..])?)
1077+
}

postgres-types/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "postgres-types"
3-
version = "0.2.2"
3+
version = "0.2.3"
44
authors = ["Steven Fackler <sfackler@gmail.com>"]
55
edition = "2018"
66
license = "MIT/Apache-2.0"
@@ -27,7 +27,7 @@ with-time-0_3 = ["time-03"]
2727
[dependencies]
2828
bytes = "1.0"
2929
fallible-iterator = "0.2"
30-
postgres-protocol = { version = "0.6.1", path = "../postgres-protocol" }
30+
postgres-protocol = { version = "0.6.4", path = "../postgres-protocol" }
3131
postgres-derive = { version = "0.4.0", optional = true, path = "../postgres-derive" }
3232

3333
array-init = { version = "2", optional = true }

postgres-types/src/lib.rs

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -590,8 +590,8 @@ impl<'a> FromSql<'a> for &'a [u8] {
590590
}
591591

592592
impl<'a> FromSql<'a> for String {
593-
fn from_sql(_: &Type, raw: &'a [u8]) -> Result<String, Box<dyn Error + Sync + Send>> {
594-
types::text_from_sql(raw).map(ToString::to_string)
593+
fn from_sql(ty: &Type, raw: &'a [u8]) -> Result<String, Box<dyn Error + Sync + Send>> {
594+
<&str as FromSql>::from_sql(ty, raw).map(ToString::to_string)
595595
}
596596

597597
fn accepts(ty: &Type) -> bool {
@@ -600,8 +600,8 @@ impl<'a> FromSql<'a> for String {
600600
}
601601

602602
impl<'a> FromSql<'a> for Box<str> {
603-
fn from_sql(_: &Type, raw: &'a [u8]) -> Result<Box<str>, Box<dyn Error + Sync + Send>> {
604-
types::text_from_sql(raw)
603+
fn from_sql(ty: &Type, raw: &'a [u8]) -> Result<Box<str>, Box<dyn Error + Sync + Send>> {
604+
<&str as FromSql>::from_sql(ty, raw)
605605
.map(ToString::to_string)
606606
.map(String::into_boxed_str)
607607
}
@@ -612,14 +612,26 @@ impl<'a> FromSql<'a> for Box<str> {
612612
}
613613

614614
impl<'a> FromSql<'a> for &'a str {
615-
fn from_sql(_: &Type, raw: &'a [u8]) -> Result<&'a str, Box<dyn Error + Sync + Send>> {
616-
types::text_from_sql(raw)
615+
fn from_sql(ty: &Type, raw: &'a [u8]) -> Result<&'a str, Box<dyn Error + Sync + Send>> {
616+
match *ty {
617+
ref ty if (
618+
ty.name() == "ltree" ||
619+
ty.name() == "lquery" ||
620+
ty.name() == "ltxtquery"
621+
) => types::ltree_from_sql(raw),
622+
_ => types::text_from_sql(raw)
623+
}
617624
}
618625

619626
fn accepts(ty: &Type) -> bool {
620627
match *ty {
621628
Type::VARCHAR | Type::TEXT | Type::BPCHAR | Type::NAME | Type::UNKNOWN => true,
622-
ref ty if ty.name() == "citext" => true,
629+
ref ty if (
630+
ty.name() == "citext" ||
631+
ty.name() == "ltree" ||
632+
ty.name() == "lquery" ||
633+
ty.name() == "ltxtquery"
634+
) => true,
623635
_ => false,
624636
}
625637
}
@@ -920,15 +932,27 @@ impl ToSql for Vec<u8> {
920932
}
921933

922934
impl<'a> ToSql for &'a str {
923-
fn to_sql(&self, _: &Type, w: &mut BytesMut) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
924-
types::text_to_sql(*self, w);
935+
fn to_sql(&self, ty: &Type, w: &mut BytesMut) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
936+
match ty {
937+
ref ty if (
938+
ty.name() == "ltree" ||
939+
ty.name() == "lquery" ||
940+
ty.name() == "ltxtquery"
941+
) => types::ltree_to_sql(*self, w),
942+
_ => types::text_to_sql(*self, w)
943+
}
925944
Ok(IsNull::No)
926945
}
927946

928947
fn accepts(ty: &Type) -> bool {
929948
match *ty {
930949
Type::VARCHAR | Type::TEXT | Type::BPCHAR | Type::NAME | Type::UNKNOWN => true,
931-
ref ty if ty.name() == "citext" => true,
950+
ref ty if (
951+
ty.name() == "citext" ||
952+
ty.name() == "ltree" ||
953+
ty.name() == "lquery" ||
954+
ty.name() == "ltxtquery"
955+
) => true,
932956
_ => false,
933957
}
934958
}

tokio-postgres/Cargo.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "tokio-postgres"
3-
version = "0.7.5"
3+
version = "0.7.6"
44
authors = ["Steven Fackler <sfackler@gmail.com>"]
55
edition = "2018"
66
license = "MIT/Apache-2.0"
@@ -50,8 +50,8 @@ parking_lot = "0.12"
5050
percent-encoding = "2.0"
5151
pin-project-lite = "0.2"
5252
phf = "0.10"
53-
postgres-protocol = { version = "0.6.1", path = "../postgres-protocol" }
54-
postgres-types = { version = "0.2.2", path = "../postgres-types" }
53+
postgres-protocol = { version = "0.6.4", path = "../postgres-protocol" }
54+
postgres-types = { version = "0.2.3", path = "../postgres-types" }
5555
socket2 = "0.4"
5656
tokio = { version = "1.0", features = ["io-util"] }
5757
tokio-util = { version = "0.7", features = ["codec"] }

tokio-postgres/tests/test/types/mod.rs

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -648,3 +648,78 @@ async fn inet() {
648648
)
649649
.await;
650650
}
651+
652+
#[tokio::test]
653+
async fn ltree() {
654+
let client = connect("user=postgres").await;
655+
client.execute("CREATE EXTENSION IF NOT EXISTS ltree;", &[]).await.unwrap();
656+
657+
test_type("ltree", &[
658+
(Some("b.c.d".to_owned()), "'b.c.d'"),
659+
(None, "NULL"),
660+
]).await;
661+
}
662+
663+
#[tokio::test]
664+
async fn ltree_any() {
665+
let client = connect("user=postgres").await;
666+
client.execute("CREATE EXTENSION IF NOT EXISTS ltree;", &[]).await.unwrap();
667+
668+
test_type("ltree[]", &[
669+
(Some(vec![]), "ARRAY[]"),
670+
(Some(vec!["a.b.c".to_string()]), "ARRAY['a.b.c']"),
671+
(Some(vec!["a.b.c".to_string(), "e.f.g".to_string()]), "ARRAY['a.b.c','e.f.g']"),
672+
(None, "NULL"),
673+
]).await;
674+
}
675+
676+
#[tokio::test]
677+
async fn lquery() {
678+
let client = connect("user=postgres").await;
679+
client.execute("CREATE EXTENSION IF NOT EXISTS ltree;", &[]).await.unwrap();
680+
681+
test_type("lquery", &[
682+
(Some("b.c.d".to_owned()), "'b.c.d'"),
683+
(Some("b.c.*".to_owned()), "'b.c.*'"),
684+
(Some("b.*{1,2}.d|e".to_owned()), "'b.*{1,2}.d|e'"),
685+
(None, "NULL"),
686+
]).await;
687+
}
688+
689+
#[tokio::test]
690+
async fn lquery_any() {
691+
let client = connect("user=postgres").await;
692+
client.execute("CREATE EXTENSION IF NOT EXISTS ltree;", &[]).await.unwrap();
693+
694+
test_type("lquery[]", &[
695+
(Some(vec![]), "ARRAY[]"),
696+
(Some(vec!["b.c.*".to_string()]), "ARRAY['b.c.*']"),
697+
(Some(vec!["b.c.*".to_string(), "b.*{1,2}.d|e".to_string()]), "ARRAY['b.c.*','b.*{1,2}.d|e']"),
698+
(None, "NULL"),
699+
]).await;
700+
}
701+
702+
#[tokio::test]
703+
async fn ltxtquery() {
704+
let client = connect("user=postgres").await;
705+
client.execute("CREATE EXTENSION IF NOT EXISTS ltree;", &[]).await.unwrap();
706+
707+
test_type("ltxtquery", &[
708+
(Some("b & c & d".to_owned()), "'b & c & d'"),
709+
(Some("b@* & !c".to_owned()), "'b@* & !c'"),
710+
(None, "NULL"),
711+
]).await;
712+
}
713+
714+
#[tokio::test]
715+
async fn ltxtquery_any() {
716+
let client = connect("user=postgres").await;
717+
client.execute("CREATE EXTENSION IF NOT EXISTS ltree;", &[]).await.unwrap();
718+
719+
test_type("ltxtquery[]", &[
720+
(Some(vec![]), "ARRAY[]"),
721+
(Some(vec!["b & c & d".to_string()]), "ARRAY['b & c & d']"),
722+
(Some(vec!["b & c & d".to_string(), "b@* & !c".to_string()]), "ARRAY['b & c & d','b@* & !c']"),
723+
(None, "NULL"),
724+
]).await;
725+
}

0 commit comments

Comments
 (0)