mirror of
https://github.com/diesel-rs/diesel.git
synced 2024-10-04 01:28:13 +03:00
Allow arrays containing null to be serialized
Deserialization already worked, so there's no reason we shouldn't just allow this. It's worth noting that there is no way to represent whether an array is allowed to contain nulls or not within postgres's type system. As such, the type `Array<Nullable<ST>>` will never be generated by `infer_schema!` (I do want to make `FromSql<Array<ST>> for `Vec<Option<T>>` just work though). Since we never provide a `ToSql<Array<ST>> for Vec<Option<T>>`, Diesel will prevent you from accidentally inserting nulls at compile time. Ultimately the user does just have to make sure they represent whether the array could contain null in the output type, however. One alternative would be to represent the fact that all arrays can contain null within the type system, and only provide `impl FromSql<Array<ST>> for Vec<Option<T>>`. I suspect this would hinder ergonomics pretty heavily, but we should consider it before 1.0. One note about the implementation -- Technically we should be setting `flags` to `1` if the array contains any nulls, as that's what happens on the data sent to us. However, setting it would require us to perform an additional level of intermediate buffering on all the values to determine whether the flag should be set, and that flag is currently ignored by PG. "But Sean, that's just relying on an implementation detail!" this is true, but our entire usage of the binary format is relying on an implementation detail (See #695).
This commit is contained in:
parent
ea6c55c51a
commit
a571e417e6
@ -14,6 +14,10 @@ for Rust libraries in [RFC #1105](https://github.com/rust-lang/rfcs/blob/master/
|
||||
[select-0.11.0]: http://docs.diesel.rs/diesel/fn.select.html
|
||||
[boxed-0.11.0]: http://docs.diesel.rs/diesel/prelude/trait.BoxedDsl.html
|
||||
|
||||
* Arrays containing null are now supported. `infer_schema!` will never infer an
|
||||
array that contains null, but a `table!` definition which specifies a type of
|
||||
`Array<Nullable<X>>` can now be deserialized to `Vec<Option<T>>`
|
||||
|
||||
### Changed
|
||||
|
||||
* It is no longer possible to exhaustively match against
|
||||
|
@ -134,10 +134,14 @@ impl<'a, ST, T> ToSql<Array<ST>, Pg> for &'a [T] where
|
||||
let mut buffer = Vec::new();
|
||||
for elem in self.iter() {
|
||||
let is_null = try!(elem.to_sql(&mut buffer));
|
||||
assert!(is_null == IsNull::No, "Arrays containing null are not supported");
|
||||
try!(out.write_i32::<NetworkEndian>(buffer.len() as i32));
|
||||
try!(out.write_all(&buffer));
|
||||
buffer.clear();
|
||||
if let IsNull::No = is_null {
|
||||
try!(out.write_i32::<NetworkEndian>(buffer.len() as i32));
|
||||
try!(out.write_all(&buffer));
|
||||
buffer.clear();
|
||||
} else {
|
||||
// https://github.com/postgres/postgres/blob/82f8107b92c9104ec9d9465f3f6a4c6dab4c124a/src/backend/utils/adt/arrayfuncs.c#L1461
|
||||
try!(out.write_i32::<NetworkEndian>(-1));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(IsNull::No)
|
||||
|
@ -102,6 +102,7 @@ mod pg_types {
|
||||
test_round_trip!(array_of_int_roundtrips, Array<Integer>, Vec<i32>);
|
||||
test_round_trip!(array_of_bigint_roundtrips, Array<BigInt>, Vec<i64>);
|
||||
test_round_trip!(array_of_dynamic_size_roundtrips, Array<Text>, Vec<String>);
|
||||
test_round_trip!(array_of_nullable_roundtrips, Array<Nullable<Text>>, Vec<Option<String>>);
|
||||
|
||||
fn mk_uuid(data: (u32, u16, u16, (u8, u8, u8, u8, u8, u8, u8, u8))) -> self::uuid::Uuid {
|
||||
let a = data.3;
|
||||
@ -131,7 +132,7 @@ pub fn mk_naive_date(days: u32) -> NaiveDate {
|
||||
|
||||
#[cfg(feature = "postgres")]
|
||||
mod unstable_types {
|
||||
use super::{quickcheck, types, test_type_round_trips};
|
||||
use super::{quickcheck, test_type_round_trips};
|
||||
use std::time::*;
|
||||
|
||||
fn strip_nanosecond_precision(time: SystemTime) -> SystemTime {
|
||||
|
Loading…
Reference in New Issue
Block a user