1use byteorder::{NetworkEndian, ReadBytesExt, WriteBytesExt};
2use std::fmt;
3use std::io::Write;
4
5use deserialize::{self, FromSql};
6use pg::{Pg, PgMetadataLookup, PgTypeMetadata};
7use serialize::{self, IsNull, Output, ToSql};
8use sql_types::{Array, HasSqlType, Nullable};
9
10impl<T> HasSqlType<Array<T>> for Pg
11where
12 Pg: HasSqlType<T>,
13{
14 fn metadata(lookup: &PgMetadataLookup) -> PgTypeMetadata {
15 PgTypeMetadata {
16 oid: <Pg as HasSqlType<T>>::metadata(lookup).array_oid,
17 array_oid: 0,
18 }
19 }
20}
21
22impl<T, ST> FromSql<Array<ST>, Pg> for Vec<T>
23where
24 T: FromSql<ST, Pg>,
25{
26 fn from_sql(bytes: Option<&[u8]>) -> deserialize::Result<Self> {
27 let mut bytes = not_none!(bytes);
28 let num_dimensions = bytes.read_i32::<NetworkEndian>()?;
29 let has_null = bytes.read_i32::<NetworkEndian>()? != 0;
30 let _oid = bytes.read_i32::<NetworkEndian>()?;
31
32 if num_dimensions == 0 {
33 return Ok(Vec::new());
34 }
35
36 let num_elements = bytes.read_i32::<NetworkEndian>()?;
37 let _lower_bound = bytes.read_i32::<NetworkEndian>()?;
38
39 if num_dimensions != 1 {
40 return Err("multi-dimensional arrays are not supported".into());
41 }
42
43 (0..num_elements)
44 .map(|_| {
45 let elem_size = bytes.read_i32::<NetworkEndian>()?;
46 if has_null && elem_size == -1 {
47 T::from_sql(None)
48 } else {
49 let (elem_bytes, new_bytes) = bytes.split_at(elem_size as usize);
50 bytes = new_bytes;
51 T::from_sql(Some(elem_bytes))
52 }
53 })
54 .collect()
55 }
56}
57
58use expression::bound::Bound;
59use expression::AsExpression;
60
61macro_rules! array_as_expression {
62 ($ty:ty, $sql_type:ty) => {
63 impl<'a, 'b, ST, T> AsExpression<$sql_type> for $ty {
64 type Expression = Bound<$sql_type, Self>;
65
66 fn as_expression(self) -> Self::Expression {
67 Bound::new(self)
68 }
69 }
70 };
71}
72
73array_as_expression!(&'a [T], Array<ST>);
74array_as_expression!(&'a [T], Nullable<Array<ST>>);
75array_as_expression!(&'a &'b [T], Array<ST>);
76array_as_expression!(&'a &'b [T], Nullable<Array<ST>>);
77array_as_expression!(Vec<T>, Array<ST>);
78array_as_expression!(Vec<T>, Nullable<Array<ST>>);
79array_as_expression!(&'a Vec<T>, Array<ST>);
80array_as_expression!(&'a Vec<T>, Nullable<Array<ST>>);
81array_as_expression!(&'a &'b Vec<T>, Array<ST>);
82array_as_expression!(&'a &'b Vec<T>, Nullable<Array<ST>>);
83
84impl<ST, T> ToSql<Array<ST>, Pg> for [T]
85where
86 Pg: HasSqlType<ST>,
87 T: ToSql<ST, Pg>,
88{
89 fn to_sql<W: Write>(&self, out: &mut Output<W, Pg>) -> serialize::Result {
90 let num_dimensions = 1;
91 out.write_i32::<NetworkEndian>(num_dimensions)?;
92 let flags = 0;
93 out.write_i32::<NetworkEndian>(flags)?;
94 let element_oid = Pg::metadata(out.metadata_lookup()).oid;
95 out.write_u32::<NetworkEndian>(element_oid)?;
96 out.write_i32::<NetworkEndian>(self.len() as i32)?;
97 let lower_bound = 1;
98 out.write_i32::<NetworkEndian>(lower_bound)?;
99
100 let mut buffer = out.with_buffer(Vec::new());
101 for elem in self.iter() {
102 let is_null = elem.to_sql(&mut buffer)?;
103 if let IsNull::No = is_null {
104 out.write_i32::<NetworkEndian>(buffer.len() as i32)?;
105 out.write_all(&buffer)?;
106 buffer.clear();
107 } else {
108 out.write_i32::<NetworkEndian>(-1)?;
110 }
111 }
112
113 Ok(IsNull::No)
114 }
115}
116
117impl<ST, T> ToSql<Nullable<Array<ST>>, Pg> for [T]
118where
119 [T]: ToSql<Array<ST>, Pg>,
120{
121 fn to_sql<W: Write>(&self, out: &mut Output<W, Pg>) -> serialize::Result {
122 ToSql::<Array<ST>, Pg>::to_sql(self, out)
123 }
124}
125
126impl<ST, T> ToSql<Array<ST>, Pg> for Vec<T>
127where
128 [T]: ToSql<Array<ST>, Pg>,
129 T: fmt::Debug,
130{
131 fn to_sql<W: Write>(&self, out: &mut Output<W, Pg>) -> serialize::Result {
132 (self as &[T]).to_sql(out)
133 }
134}
135
136impl<ST, T> ToSql<Nullable<Array<ST>>, Pg> for Vec<T>
137where
138 Vec<T>: ToSql<Array<ST>, Pg>,
139{
140 fn to_sql<W: Write>(&self, out: &mut Output<W, Pg>) -> serialize::Result {
141 ToSql::<Array<ST>, Pg>::to_sql(self, out)
142 }
143}