Split out ltree,query,txtquery protocol parsers, add tests, rust fmt
This commit is contained in:
parent
6ae60d6d09
commit
d9d283e131
@ -1060,18 +1060,59 @@ impl Inet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Serializes a Postgres l{tree,query,txtquery} string
|
/// Serializes a Postgres ltree string
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn ltree_to_sql(v: &str, buf: &mut BytesMut) {
|
pub fn ltree_to_sql(v: &str, buf: &mut BytesMut) {
|
||||||
// A version number is prepended to an Ltree string per spec
|
// A version number is prepended to an ltree string per spec
|
||||||
buf.put_u8(1);
|
buf.put_u8(1);
|
||||||
// Append the rest of the query
|
// Append the rest of the query
|
||||||
buf.put_slice(v.as_bytes());
|
buf.put_slice(v.as_bytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Deserialize a Postgres l{tree,query,txtquery} string
|
/// Deserialize a Postgres ltree string
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn ltree_from_sql(buf: &[u8]) -> Result<&str, StdBox<dyn Error + Sync + Send>> {
|
pub fn ltree_from_sql(buf: &[u8]) -> Result<&str, StdBox<dyn Error + Sync + Send>> {
|
||||||
// Remove the version number from the front of the string per spec
|
match buf {
|
||||||
Ok(str::from_utf8(&buf[1..])?)
|
// Remove the version number from the front of the ltree per spec
|
||||||
|
[1u8, rest @ ..] => Ok(str::from_utf8(rest)?),
|
||||||
|
_ => Err("ltree version 1 only supported".into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Serializes a Postgres lquery string
|
||||||
|
#[inline]
|
||||||
|
pub fn lquery_to_sql(v: &str, buf: &mut BytesMut) {
|
||||||
|
// A version number is prepended to an lquery string per spec
|
||||||
|
buf.put_u8(1);
|
||||||
|
// Append the rest of the query
|
||||||
|
buf.put_slice(v.as_bytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Deserialize a Postgres lquery string
|
||||||
|
#[inline]
|
||||||
|
pub fn lquery_from_sql(buf: &[u8]) -> Result<&str, StdBox<dyn Error + Sync + Send>> {
|
||||||
|
match buf {
|
||||||
|
// Remove the version number from the front of the lquery per spec
|
||||||
|
[1u8, rest @ ..] => Ok(str::from_utf8(rest)?),
|
||||||
|
_ => Err("lquery version 1 only supported".into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Serializes a Postgres ltxtquery string
|
||||||
|
#[inline]
|
||||||
|
pub fn ltxtquery_to_sql(v: &str, buf: &mut BytesMut) {
|
||||||
|
// A version number is prepended to an ltxtquery string per spec
|
||||||
|
buf.put_u8(1);
|
||||||
|
// Append the rest of the query
|
||||||
|
buf.put_slice(v.as_bytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Deserialize a Postgres ltxtquery string
|
||||||
|
#[inline]
|
||||||
|
pub fn ltxtquery_from_sql(buf: &[u8]) -> Result<&str, StdBox<dyn Error + Sync + Send>> {
|
||||||
|
match buf {
|
||||||
|
// Remove the version number from the front of the ltxtquery per spec
|
||||||
|
[1u8, rest @ ..] => Ok(str::from_utf8(rest)?),
|
||||||
|
_ => Err("ltxtquery version 1 only supported".into()),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use bytes::BytesMut;
|
use bytes::{Buf, BytesMut};
|
||||||
use fallible_iterator::FallibleIterator;
|
use fallible_iterator::FallibleIterator;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
@ -156,3 +156,117 @@ fn non_null_array() {
|
|||||||
assert_eq!(array.dimensions().collect::<Vec<_>>().unwrap(), dimensions);
|
assert_eq!(array.dimensions().collect::<Vec<_>>().unwrap(), dimensions);
|
||||||
assert_eq!(array.values().collect::<Vec<_>>().unwrap(), values);
|
assert_eq!(array.values().collect::<Vec<_>>().unwrap(), values);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn ltree_sql() {
|
||||||
|
let mut query = vec![1u8];
|
||||||
|
query.extend_from_slice("A.B.C".as_bytes());
|
||||||
|
|
||||||
|
let mut buf = BytesMut::new();
|
||||||
|
|
||||||
|
ltree_to_sql("A.B.C", &mut buf);
|
||||||
|
|
||||||
|
assert_eq!(query.as_slice(), buf.chunk());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn ltree_str() {
|
||||||
|
let mut query = vec![1u8];
|
||||||
|
query.extend_from_slice("A.B.C".as_bytes());
|
||||||
|
|
||||||
|
let success = match ltree_from_sql(query.as_slice()) {
|
||||||
|
Ok(_) => true,
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
|
||||||
|
assert!(success)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn ltree_wrong_version() {
|
||||||
|
let mut query = vec![2u8];
|
||||||
|
query.extend_from_slice("A.B.C".as_bytes());
|
||||||
|
|
||||||
|
let success = match ltree_from_sql(query.as_slice()) {
|
||||||
|
Err(_) => true,
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
|
||||||
|
assert!(success)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn lquery_sql() {
|
||||||
|
let mut query = vec![1u8];
|
||||||
|
query.extend_from_slice("A.B.C".as_bytes());
|
||||||
|
|
||||||
|
let mut buf = BytesMut::new();
|
||||||
|
|
||||||
|
lquery_to_sql("A.B.C", &mut buf);
|
||||||
|
|
||||||
|
assert_eq!(query.as_slice(), buf.chunk());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn lquery_str() {
|
||||||
|
let mut query = vec![1u8];
|
||||||
|
query.extend_from_slice("A.B.C".as_bytes());
|
||||||
|
|
||||||
|
let success = match lquery_from_sql(query.as_slice()) {
|
||||||
|
Ok(_) => true,
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
|
||||||
|
assert!(success)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn lquery_wrong_version() {
|
||||||
|
let mut query = vec![2u8];
|
||||||
|
query.extend_from_slice("A.B.C".as_bytes());
|
||||||
|
|
||||||
|
let success = match lquery_from_sql(query.as_slice()) {
|
||||||
|
Err(_) => true,
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
|
||||||
|
assert!(success)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn ltxtquery_sql() {
|
||||||
|
let mut query = vec![1u8];
|
||||||
|
query.extend_from_slice("a & b*".as_bytes());
|
||||||
|
|
||||||
|
let mut buf = BytesMut::new();
|
||||||
|
|
||||||
|
ltree_to_sql("a & b*", &mut buf);
|
||||||
|
|
||||||
|
assert_eq!(query.as_slice(), buf.chunk());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn ltxtquery_str() {
|
||||||
|
let mut query = vec![1u8];
|
||||||
|
query.extend_from_slice("a & b*".as_bytes());
|
||||||
|
|
||||||
|
let success = match ltree_from_sql(query.as_slice()) {
|
||||||
|
Ok(_) => true,
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
|
||||||
|
assert!(success)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn ltxtquery_wrong_version() {
|
||||||
|
let mut query = vec![2u8];
|
||||||
|
query.extend_from_slice("a & b*".as_bytes());
|
||||||
|
|
||||||
|
let success = match ltree_from_sql(query.as_slice()) {
|
||||||
|
Err(_) => true,
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
|
||||||
|
assert!(success)
|
||||||
|
}
|
||||||
|
@ -619,24 +619,24 @@ impl<'a> FromSql<'a> for Box<str> {
|
|||||||
impl<'a> FromSql<'a> for &'a str {
|
impl<'a> FromSql<'a> for &'a str {
|
||||||
fn from_sql(ty: &Type, raw: &'a [u8]) -> Result<&'a str, Box<dyn Error + Sync + Send>> {
|
fn from_sql(ty: &Type, raw: &'a [u8]) -> Result<&'a str, Box<dyn Error + Sync + Send>> {
|
||||||
match *ty {
|
match *ty {
|
||||||
ref ty if (
|
ref ty if ty.name() == "ltree" => types::ltree_from_sql(raw),
|
||||||
ty.name() == "ltree" ||
|
ref ty if ty.name() == "lquery" => types::lquery_from_sql(raw),
|
||||||
ty.name() == "lquery" ||
|
ref ty if ty.name() == "ltxtquery" => types::ltxtquery_from_sql(raw),
|
||||||
ty.name() == "ltxtquery"
|
_ => types::text_from_sql(raw),
|
||||||
) => types::ltree_from_sql(raw),
|
|
||||||
_ => types::text_from_sql(raw)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn accepts(ty: &Type) -> bool {
|
fn accepts(ty: &Type) -> bool {
|
||||||
match *ty {
|
match *ty {
|
||||||
Type::VARCHAR | Type::TEXT | Type::BPCHAR | Type::NAME | Type::UNKNOWN => true,
|
Type::VARCHAR | Type::TEXT | Type::BPCHAR | Type::NAME | Type::UNKNOWN => true,
|
||||||
ref ty if (
|
ref ty
|
||||||
ty.name() == "citext" ||
|
if (ty.name() == "citext"
|
||||||
ty.name() == "ltree" ||
|
|| ty.name() == "ltree"
|
||||||
ty.name() == "lquery" ||
|
|| ty.name() == "lquery"
|
||||||
ty.name() == "ltxtquery"
|
|| ty.name() == "ltxtquery") =>
|
||||||
) => true,
|
{
|
||||||
|
true
|
||||||
|
}
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -939,13 +939,11 @@ impl ToSql for Vec<u8> {
|
|||||||
|
|
||||||
impl<'a> ToSql for &'a str {
|
impl<'a> ToSql for &'a str {
|
||||||
fn to_sql(&self, ty: &Type, w: &mut BytesMut) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
|
fn to_sql(&self, ty: &Type, w: &mut BytesMut) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
|
||||||
match ty {
|
match *ty {
|
||||||
ref ty if (
|
ref ty if ty.name() == "ltree" => types::ltree_to_sql(*self, w),
|
||||||
ty.name() == "ltree" ||
|
ref ty if ty.name() == "lquery" => types::lquery_to_sql(*self, w),
|
||||||
ty.name() == "lquery" ||
|
ref ty if ty.name() == "ltxtquery" => types::ltxtquery_to_sql(*self, w),
|
||||||
ty.name() == "ltxtquery"
|
_ => types::text_to_sql(*self, w),
|
||||||
) => types::ltree_to_sql(*self, w),
|
|
||||||
_ => types::text_to_sql(*self, w)
|
|
||||||
}
|
}
|
||||||
Ok(IsNull::No)
|
Ok(IsNull::No)
|
||||||
}
|
}
|
||||||
@ -953,12 +951,14 @@ impl<'a> ToSql for &'a str {
|
|||||||
fn accepts(ty: &Type) -> bool {
|
fn accepts(ty: &Type) -> bool {
|
||||||
match *ty {
|
match *ty {
|
||||||
Type::VARCHAR | Type::TEXT | Type::BPCHAR | Type::NAME | Type::UNKNOWN => true,
|
Type::VARCHAR | Type::TEXT | Type::BPCHAR | Type::NAME | Type::UNKNOWN => true,
|
||||||
ref ty if (
|
ref ty
|
||||||
ty.name() == "citext" ||
|
if (ty.name() == "citext"
|
||||||
ty.name() == "ltree" ||
|
|| ty.name() == "ltree"
|
||||||
ty.name() == "lquery" ||
|
|| ty.name() == "lquery"
|
||||||
ty.name() == "ltxtquery"
|
|| ty.name() == "ltxtquery") =>
|
||||||
) => true,
|
{
|
||||||
|
true
|
||||||
|
}
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -652,74 +652,122 @@ async fn inet() {
|
|||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn ltree() {
|
async fn ltree() {
|
||||||
let client = connect("user=postgres").await;
|
let client = connect("user=postgres").await;
|
||||||
client.execute("CREATE EXTENSION IF NOT EXISTS ltree;", &[]).await.unwrap();
|
client
|
||||||
|
.execute("CREATE EXTENSION IF NOT EXISTS ltree;", &[])
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
test_type("ltree", &[
|
test_type(
|
||||||
(Some("b.c.d".to_owned()), "'b.c.d'"),
|
"ltree",
|
||||||
(None, "NULL"),
|
&[(Some("b.c.d".to_owned()), "'b.c.d'"), (None, "NULL")],
|
||||||
]).await;
|
)
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn ltree_any() {
|
async fn ltree_any() {
|
||||||
let client = connect("user=postgres").await;
|
let client = connect("user=postgres").await;
|
||||||
client.execute("CREATE EXTENSION IF NOT EXISTS ltree;", &[]).await.unwrap();
|
client
|
||||||
|
.execute("CREATE EXTENSION IF NOT EXISTS ltree;", &[])
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
test_type("ltree[]", &[
|
test_type(
|
||||||
(Some(vec![]), "ARRAY[]"),
|
"ltree[]",
|
||||||
(Some(vec!["a.b.c".to_string()]), "ARRAY['a.b.c']"),
|
&[
|
||||||
(Some(vec!["a.b.c".to_string(), "e.f.g".to_string()]), "ARRAY['a.b.c','e.f.g']"),
|
(Some(vec![]), "ARRAY[]"),
|
||||||
(None, "NULL"),
|
(Some(vec!["a.b.c".to_string()]), "ARRAY['a.b.c']"),
|
||||||
]).await;
|
(
|
||||||
|
Some(vec!["a.b.c".to_string(), "e.f.g".to_string()]),
|
||||||
|
"ARRAY['a.b.c','e.f.g']",
|
||||||
|
),
|
||||||
|
(None, "NULL"),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn lquery() {
|
async fn lquery() {
|
||||||
let client = connect("user=postgres").await;
|
let client = connect("user=postgres").await;
|
||||||
client.execute("CREATE EXTENSION IF NOT EXISTS ltree;", &[]).await.unwrap();
|
client
|
||||||
|
.execute("CREATE EXTENSION IF NOT EXISTS ltree;", &[])
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
test_type("lquery", &[
|
test_type(
|
||||||
(Some("b.c.d".to_owned()), "'b.c.d'"),
|
"lquery",
|
||||||
(Some("b.c.*".to_owned()), "'b.c.*'"),
|
&[
|
||||||
(Some("b.*{1,2}.d|e".to_owned()), "'b.*{1,2}.d|e'"),
|
(Some("b.c.d".to_owned()), "'b.c.d'"),
|
||||||
(None, "NULL"),
|
(Some("b.c.*".to_owned()), "'b.c.*'"),
|
||||||
]).await;
|
(Some("b.*{1,2}.d|e".to_owned()), "'b.*{1,2}.d|e'"),
|
||||||
|
(None, "NULL"),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn lquery_any() {
|
async fn lquery_any() {
|
||||||
let client = connect("user=postgres").await;
|
let client = connect("user=postgres").await;
|
||||||
client.execute("CREATE EXTENSION IF NOT EXISTS ltree;", &[]).await.unwrap();
|
client
|
||||||
|
.execute("CREATE EXTENSION IF NOT EXISTS ltree;", &[])
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
test_type("lquery[]", &[
|
test_type(
|
||||||
(Some(vec![]), "ARRAY[]"),
|
"lquery[]",
|
||||||
(Some(vec!["b.c.*".to_string()]), "ARRAY['b.c.*']"),
|
&[
|
||||||
(Some(vec!["b.c.*".to_string(), "b.*{1,2}.d|e".to_string()]), "ARRAY['b.c.*','b.*{1,2}.d|e']"),
|
(Some(vec![]), "ARRAY[]"),
|
||||||
(None, "NULL"),
|
(Some(vec!["b.c.*".to_string()]), "ARRAY['b.c.*']"),
|
||||||
]).await;
|
(
|
||||||
|
Some(vec!["b.c.*".to_string(), "b.*{1,2}.d|e".to_string()]),
|
||||||
|
"ARRAY['b.c.*','b.*{1,2}.d|e']",
|
||||||
|
),
|
||||||
|
(None, "NULL"),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn ltxtquery() {
|
async fn ltxtquery() {
|
||||||
let client = connect("user=postgres").await;
|
let client = connect("user=postgres").await;
|
||||||
client.execute("CREATE EXTENSION IF NOT EXISTS ltree;", &[]).await.unwrap();
|
client
|
||||||
|
.execute("CREATE EXTENSION IF NOT EXISTS ltree;", &[])
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
test_type("ltxtquery", &[
|
test_type(
|
||||||
(Some("b & c & d".to_owned()), "'b & c & d'"),
|
"ltxtquery",
|
||||||
(Some("b@* & !c".to_owned()), "'b@* & !c'"),
|
&[
|
||||||
(None, "NULL"),
|
(Some("b & c & d".to_owned()), "'b & c & d'"),
|
||||||
]).await;
|
(Some("b@* & !c".to_owned()), "'b@* & !c'"),
|
||||||
|
(None, "NULL"),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn ltxtquery_any() {
|
async fn ltxtquery_any() {
|
||||||
let client = connect("user=postgres").await;
|
let client = connect("user=postgres").await;
|
||||||
client.execute("CREATE EXTENSION IF NOT EXISTS ltree;", &[]).await.unwrap();
|
client
|
||||||
|
.execute("CREATE EXTENSION IF NOT EXISTS ltree;", &[])
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
test_type("ltxtquery[]", &[
|
test_type(
|
||||||
(Some(vec![]), "ARRAY[]"),
|
"ltxtquery[]",
|
||||||
(Some(vec!["b & c & d".to_string()]), "ARRAY['b & c & d']"),
|
&[
|
||||||
(Some(vec!["b & c & d".to_string(), "b@* & !c".to_string()]), "ARRAY['b & c & d','b@* & !c']"),
|
(Some(vec![]), "ARRAY[]"),
|
||||||
(None, "NULL"),
|
(Some(vec!["b & c & d".to_string()]), "ARRAY['b & c & d']"),
|
||||||
]).await;
|
(
|
||||||
|
Some(vec!["b & c & d".to_string(), "b@* & !c".to_string()]),
|
||||||
|
"ARRAY['b & c & d','b@* & !c']",
|
||||||
|
),
|
||||||
|
(None, "NULL"),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user