Skip to content

Commit

Permalink
issues-336 Third try impl postgres-array
Browse files Browse the repository at this point in the history
  • Loading branch information
ikrivosheev committed Oct 9, 2022
1 parent 847c602 commit 835707e
Show file tree
Hide file tree
Showing 8 changed files with 80 additions and 30 deletions.
2 changes: 1 addition & 1 deletion sea-query-binder/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ rust-version = "1.60"
[lib]

[dependencies]
sea-query = { version = "^0", path = ".." }
sea-query = { version = "^0", path = "..", features = ["thread-safe"] }
sqlx = { version = "^0.6", optional = true }

[features]
Expand Down
41 changes: 36 additions & 5 deletions sea-query-binder/src/sqlx_postgres.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,23 @@
use sea_query::{ColumnType, Value, ValueType};

use crate::SqlxValues;
use sea_query::Value;

fn convert_to_vector<T: ValueType>(
ty: ColumnType,
source: Option<Box<Vec<Value>>>,
) -> Option<Vec<T>> {
if ty == T::column_type() {
Some(
source
.as_ref()?
.iter()
.map(|v| T::try_from(v.clone()).unwrap())
.collect(),
)
} else {
panic!()
}
}

impl<'q> sqlx::IntoArguments<'q, sqlx::postgres::Postgres> for SqlxValues {
fn into_arguments(self) -> sqlx::postgres::PgArguments {
Expand Down Expand Up @@ -32,7 +50,7 @@ impl<'q> sqlx::IntoArguments<'q, sqlx::postgres::Postgres> for SqlxValues {
args.add(i.map(|i| i as i64));
}
Value::BigUnsigned(i) => {
args.add(i.map(|i| <i64 as std::convert::TryFrom<u64>>::try_from(i).unwrap()));
args.add(i.map(|i| <i64 as TryFrom<u64>>::try_from(i).unwrap()));
}
Value::Float(f) => {
args.add(f);
Expand Down Expand Up @@ -106,9 +124,22 @@ impl<'q> sqlx::IntoArguments<'q, sqlx::postgres::Postgres> for SqlxValues {
args.add(j.as_deref());
}
#[cfg(feature = "postgres-array")]
Value::Array(_) => {
panic!("SeaQuery doesn't support array arguments for Postgresql");
}
Value::Array(t, v) => match t {
ColumnType::Char(_) => args.add(convert_to_vector::<String>(t, v)),
ColumnType::String(_) => args.add(convert_to_vector::<String>(t, v)),
ColumnType::Text => args.add(convert_to_vector::<String>(t, v)),
ColumnType::TinyInteger(_) => args.add(convert_to_vector::<i8>(t, v)),
ColumnType::SmallInteger(_) => args.add(convert_to_vector::<i16>(t, v)),
ColumnType::Integer(_) => args.add(convert_to_vector::<i32>(t, v)),
ColumnType::BigInteger(_) => args.add(convert_to_vector::<i64>(t, v)),
ColumnType::TinyUnsigned(_) => args.add(convert_to_vector::<i16>(t, v)),
ColumnType::SmallUnsigned(_) => args.add(convert_to_vector::<i32>(t, v)),
ColumnType::Unsigned(_) => args.add(convert_to_vector::<i64>(t, v)),
ColumnType::BigUnsigned(_) => args.add(convert_to_vector::<i64>(t, v)),
ColumnType::Float(_) => args.add(convert_to_vector::<f32>(t, v)),
ColumnType::Double(_) => args.add(convert_to_vector::<f64>(t, v)),
_ => {}
},
#[cfg(feature = "with-ipnetwork")]
Value::IpNetwork(ip) => {
args.add(ip.as_deref());
Expand Down
2 changes: 1 addition & 1 deletion sea-query-postgres/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ rust-version = "1.60"
[lib]

[dependencies]
sea-query = { version = "^0", path = ".." }
sea-query = { version = "^0", path = "..", feature = ["thread-safe"] }
postgres-types = { version = "^0.2" }
bytes = { version = "^1" }
rust_decimal = { version = "^1", optional = true }
Expand Down
6 changes: 5 additions & 1 deletion src/backend/postgres/table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,11 @@ impl TableBuilder for PostgresQueryBuilder {
ColumnType::Json => "json".into(),
ColumnType::JsonBinary => "jsonb".into(),
ColumnType::Uuid => "uuid".into(),
ColumnType::Array(elem_type) => format!("{}[]", elem_type.as_ref().unwrap()),
ColumnType::Array(elem_type) => {
let mut sql = String::new();
self.prepare_column_type(elem_type, &mut sql);
format!("{}[]", sql)
}
ColumnType::Custom(iden) => iden.to_string(),
ColumnType::Enum { name, .. } => name.to_string(),
ColumnType::Cidr => "cidr".into(),
Expand Down
4 changes: 2 additions & 2 deletions src/backend/query_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -966,7 +966,7 @@ pub trait QueryBuilder: QuotedBuilder + EscapeBuilder + TableRefBuilder {
#[cfg(feature = "with-mac_address")]
Value::MacAddress(None) => write!(s, "NULL").unwrap(),
#[cfg(feature = "postgres-array")]
Value::Array(None) => write!(s, "NULL").unwrap(),
Value::Array(_, None) => write!(s, "NULL").unwrap(),
Value::Bool(Some(b)) => write!(s, "{}", if *b { "TRUE" } else { "FALSE" }).unwrap(),
Value::TinyInt(Some(v)) => write!(s, "{}", v).unwrap(),
Value::SmallInt(Some(v)) => write!(s, "{}", v).unwrap(),
Expand Down Expand Up @@ -1036,7 +1036,7 @@ pub trait QueryBuilder: QuotedBuilder + EscapeBuilder + TableRefBuilder {
#[cfg(feature = "with-uuid")]
Value::Uuid(Some(v)) => write!(s, "'{}'", v).unwrap(),
#[cfg(feature = "postgres-array")]
Value::Array(Some(v)) => write!(
Value::Array(_, Some(v)) => write!(
s,
"'{{{}}}'",
v.iter()
Expand Down
16 changes: 11 additions & 5 deletions src/table/column.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,18 @@ pub enum ColumnType {
name: DynIden,
variants: Vec<DynIden>,
},
Array(Option<String>),
Array(SeaRc<Box<ColumnType>>),
Cidr,
Inet,
MacAddr,
}

impl PartialEq for ColumnType {
fn eq(&self, other: &Self) -> bool {
true
}
}

/// All column specification keywords
#[derive(Debug, Clone)]
pub enum ColumnSpec {
Expand All @@ -64,7 +70,7 @@ pub enum ColumnSpec {
}

// All interval fields
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum PgInterval {
Year,
Month,
Expand All @@ -81,7 +87,7 @@ pub enum PgInterval {
MinuteToSecond,
}

#[derive(Debug, Clone)]
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum BlobSize {
Tiny,
/// MySQL & SQLite support `binary(length)` column type
Expand Down Expand Up @@ -524,8 +530,8 @@ impl ColumnDef {

/// Set column type as an array with a specified element type.
/// This is only supported on Postgres.
pub fn array(&mut self, elem_type: String) -> &mut Self {
self.types = Some(ColumnType::Array(Some(elem_type)));
pub fn array(&mut self, elem_type: ColumnType) -> &mut Self {
self.types = Some(ColumnType::Array(SeaRc::new(Box::new(elem_type))));
self
}

Expand Down
12 changes: 9 additions & 3 deletions src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ macro_rules! iden_trait {
}

fn to_string(&self) -> String {
let s = &mut String::new();
self.unquoted(s);
s.to_owned()
let mut s = String::new();
self.unquoted(&mut s);
s
}

fn unquoted(&self, s: &mut dyn fmt::Write);
Expand Down Expand Up @@ -57,6 +57,12 @@ impl fmt::Debug for dyn Iden {
}
}

impl PartialEq for dyn Iden {
fn eq(&self, other: &Self) -> bool {
self.to_string() == other.to_string()
}
}

/// Column references
#[derive(Debug, Clone)]
pub enum ColumnRef {
Expand Down
27 changes: 15 additions & 12 deletions src/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ use std::net::IpAddr;
#[cfg(feature = "with-mac_address")]
use mac_address::MacAddress;

use crate::{BlobSize, ColumnType, CommonSqlQueryBuilder, QueryBuilder};
use crate::{BlobSize, ColumnType, CommonSqlQueryBuilder, QueryBuilder, SeaRc};

/// Value variants
///
Expand Down Expand Up @@ -111,7 +111,7 @@ pub enum Value {

#[cfg(feature = "postgres-array")]
#[cfg_attr(docsrs, doc(cfg(feature = "postgres-array")))]
Array(Option<Box<Vec<Value>>>),
Array(ColumnType, Option<Box<Vec<Value>>>),

#[cfg(feature = "with-ipnetwork")]
#[cfg_attr(docsrs, doc(cfg(feature = "with-ipnetwork")))]
Expand Down Expand Up @@ -585,19 +585,22 @@ mod with_array {

impl<T> From<Vec<T>> for Value
where
T: Into<Value> + NotU8,
T: Into<Value> + NotU8 + ValueType,
{
fn from(x: Vec<T>) -> Value {
Value::Array(Some(Box::new(x.into_iter().map(|e| e.into()).collect())))
Value::Array(
T::column_type(),
Some(Box::new(x.into_iter().map(|e| e.into()).collect())),
)
}
}

impl<T> Nullable for Vec<T>
where
T: Into<Value> + NotU8,
T: Into<Value> + NotU8 + ValueType,
{
fn null() -> Value {
Value::Array(None)
Value::Array(T::column_type(), None)
}
}

Expand All @@ -607,7 +610,7 @@ mod with_array {
{
fn try_from(v: Value) -> Result<Self, ValueTypeErr> {
match v {
Value::Array(Some(v)) => Ok(v.into_iter().map(|e| e.unwrap()).collect()),
Value::Array(_, Some(v)) => Ok(v.into_iter().map(|e| e.unwrap()).collect()),
_ => Err(ValueTypeErr),
}
}
Expand All @@ -618,7 +621,7 @@ mod with_array {

fn column_type() -> ColumnType {
use ColumnType::*;
Array(None)
Array(SeaRc::new(Box::new(T::column_type())))
}
}
}
Expand Down Expand Up @@ -880,12 +883,12 @@ impl Value {
#[cfg(feature = "postgres-array")]
impl Value {
pub fn is_array(&self) -> bool {
matches!(self, Self::Array(_))
matches!(self, Self::Array(_, _))
}

pub fn as_ref_array(&self) -> Option<&Vec<Value>> {
match self {
Self::Array(v) => box_to_opt_ref!(v),
Self::Array(_, v) => box_to_opt_ref!(v),
_ => panic!("not Value::Array"),
}
}
Expand Down Expand Up @@ -1172,7 +1175,7 @@ pub fn sea_value_to_json_value(value: &Value) -> Json {
#[cfg(feature = "with-uuid")]
Value::Uuid(None) => Json::Null,
#[cfg(feature = "postgres-array")]
Value::Array(None) => Json::Null,
Value::Array(_, None) => Json::Null,
#[cfg(feature = "with-ipnetwork")]
Value::IpNetwork(None) => Json::Null,
#[cfg(feature = "with-mac_address")]
Expand Down Expand Up @@ -1225,7 +1228,7 @@ pub fn sea_value_to_json_value(value: &Value) -> Json {
#[cfg(feature = "with-uuid")]
Value::Uuid(Some(v)) => Json::String(v.to_string()),
#[cfg(feature = "postgres-array")]
Value::Array(Some(v)) => {
Value::Array(_, Some(v)) => {
Json::Array(v.as_ref().iter().map(sea_value_to_json_value).collect())
}
#[cfg(feature = "with-ipnetwork")]
Expand Down

0 comments on commit 835707e

Please sign in to comment.