diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 3de70e9..0000000 --- a/.travis.yml +++ /dev/null @@ -1,9 +0,0 @@ -language: rust -rust: -- nightly -- beta -- stable -addons: - postgresql: 9.4 -script: -- cargo test diff --git a/Cargo.toml b/Cargo.toml index 91e44c3..5fa0f65 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,13 +1,17 @@ [package] name = "postgres_array" -version = "0.7.1" +version = "0.11.1" authors = ["Steven Fackler "] +edition = "2018" license = "MIT" description = "Array support for rust-postgres" repository = "https://github.com/sfackler/rust-postgres-array" -documentation = "https://sfackler.github.io/rust-postgres-array/doc/v0.7.1/postgres_array" [dependencies] -fallible-iterator = "0.1" -postgres = ">= 0.12, < 0.14" -postgres-protocol = "0.1" +bytes = "1.0" +fallible-iterator = "0.2" +postgres-types = "0.2" +postgres-protocol = "0.6" + +[dev-dependencies] +postgres = "0.19" diff --git a/README.md b/README.md index 1ae0889..0008029 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # rust-postgres-array -[![Build Status](https://travis-ci.org/sfackler/rust-postgres-array.svg?branch=master)](https://travis-ci.org/sfackler/rust-postgres-array) +[![CircleCI](https://circleci.com/gh/sfackler/rust-postgres-array.svg?style=shield)](https://circleci.com/gh/sfackler/rust-postgres-array) -[Documentation](https://sfackler.github.io/rust-postgres-array/doc/v0.7.1/postgres_array) +[Documentation](https://docs.rs/postgres_array) Support for PostgreSQL arrays in [rust-postgres](https://github.com/sfackler/rust-postgres). diff --git a/circle.yml b/circle.yml new file mode 100644 index 0000000..8e1b563 --- /dev/null +++ b/circle.yml @@ -0,0 +1,25 @@ +version: 2 +jobs: + build: + docker: + - image: rust:1.64.0 + - image: postgres:12 + environment: + POSTGRES_PASSWORD: password + steps: + - checkout + - restore_cache: + key: registry + - run: cargo generate-lockfile + - save_cache: + key: registry-{{ epoch }} + paths: + - /usr/local/cargo/registry/index + - restore_cache: + key: dependencies-1.40-{{ checksum "Cargo.lock" }} + - run: cargo test + - save_cache: + key: dependencies-1.40-{{ checksum "Cargo.lock" }} + paths: + - target + - /usr/local/cargo/registry/cache diff --git a/src/array.rs b/src/array.rs index 4a091ff..9886d8d 100644 --- a/src/array.rs +++ b/src/array.rs @@ -1,9 +1,9 @@ +use std::fmt; use std::ops::{Index, IndexMut}; use std::slice; use std::vec; -use std::fmt; -use Dimension; +use crate::Dimension; /// A multi-dimensional array. #[derive(Debug, PartialEq, Eq, Clone)] @@ -13,38 +13,46 @@ pub struct Array { } impl fmt::Display for Array { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { if self.dims.iter().any(|dim| dim.lower_bound != 1) { for dim in &self.dims { - try!(write!(fmt, - "[{}:{}]", - dim.lower_bound, - dim.lower_bound + dim.len - 1)); + write!( + fmt, + "[{}:{}]", + dim.lower_bound, + dim.lower_bound + dim.len - 1 + )?; } - try!(write!(fmt, "=")); + write!(fmt, "=")?; } fmt_helper(0, &self.dims, &mut self.data.iter(), fmt) } } -fn fmt_helper<'a, T, I>(depth: usize, - dims: &[Dimension], - mut data: &mut I, - fmt: &mut fmt::Formatter) - -> fmt::Result - where I: Iterator, - T: 'a + fmt::Display +fn fmt_helper<'a, T, I>( + depth: usize, + dims: &[Dimension], + data: &mut I, + fmt: &mut fmt::Formatter<'_>, +) -> fmt::Result +where + I: Iterator, + T: 'a + fmt::Display, { + if dims.len() == 0 { + return write!(fmt, "{{}}"); + } + if depth == dims.len() { return write!(fmt, "{}", data.next().unwrap()); } - try!(write!(fmt, "{{")); + write!(fmt, "{{")?; for i in 0..dims[depth].len { if i != 0 { - try!(write!(fmt, ",")); + write!(fmt, ",")?; } - try!(fmt_helper(depth + 1, dims, data, fmt)); + fmt_helper(depth + 1, dims, data, fmt)?; } write!(fmt, "}}") } @@ -60,12 +68,14 @@ impl Array { /// Panics if the number of elements provided does not match the number of /// elements specified by the dimensions. pub fn from_parts(data: Vec, dimensions: Vec) -> Array { - assert!((data.is_empty() && dimensions.is_empty()) || - data.len() as i32 == dimensions.iter().fold(1, |acc, i| acc * i.len), - "size mismatch"); + assert!( + (data.is_empty() && dimensions.is_empty()) + || data.len() as i32 == dimensions.iter().fold(1, |acc, i| acc * i.len), + "size mismatch" + ); Array { dims: dimensions, - data: data, + data, } } @@ -73,10 +83,10 @@ impl Array { pub fn from_vec(data: Vec, lower_bound: i32) -> Array { Array { dims: vec![Dimension { - len: data.len() as i32, - lower_bound: lower_bound, - }], - data: data, + len: data.len() as i32, + lower_bound, + }], + data, } } @@ -85,11 +95,13 @@ impl Array { /// For example, the one dimensional array `[1, 2]` would turn into the /// two-dimensional array `[[1, 2]]`. pub fn wrap(&mut self, lower_bound: i32) { - self.dims.insert(0, - Dimension { - len: 1, - lower_bound: lower_bound, - }); + self.dims.insert( + 0, + Dimension { + len: 1, + lower_bound, + }, + ); } /// Consumes another array, appending it to the top level dimension of this @@ -106,8 +118,10 @@ impl Array { /// /// Panics if the dimensions of the two arrays do not match. pub fn push(&mut self, other: Array) { - assert!(self.dims.len() - 1 == other.dims.len(), - "cannot append differently shaped arrays"); + assert!( + self.dims.len() - 1 == other.dims.len(), + "cannot append differently shaped arrays" + ); for (dim1, dim2) in self.dims.iter().skip(1).zip(other.dims.iter()) { assert!(dim1 == dim2, "cannot append differently shaped arrays"); } @@ -135,14 +149,18 @@ impl Array { /// Returns an iterator over references to the elements of the array in the /// higher-dimensional equivalent of row-major order. - pub fn iter<'a>(&'a self) -> Iter<'a, T> { - Iter { inner: self.data.iter() } + pub fn iter(&self) -> Iter<'_, T> { + Iter { + inner: self.data.iter(), + } } /// Returns an iterator over mutable references to the elements of the /// array in the higher-dimensional equivalent of row-major order. - pub fn iter_mut<'a>(&'a mut self) -> IterMut<'a, T> { - IterMut { inner: self.data.iter_mut() } + pub fn iter_mut(&mut self) -> IterMut<'_, T> { + IterMut { + inner: self.data.iter_mut(), + } } /// Returns the underlying data vector for this Array in the @@ -196,8 +214,27 @@ tuple_impl!(a: i32, b: i32, c: i32, d: i32); tuple_impl!(a: i32, b: i32, c: i32, d: i32, e: i32); tuple_impl!(a: i32, b: i32, c: i32, d: i32, e: i32, f: i32); tuple_impl!(a: i32, b: i32, c: i32, d: i32, e: i32, f: i32, g: i32); -tuple_impl!(a: i32, b: i32, c: i32, d: i32, e: i32, f: i32, g: i32, h: i32); -tuple_impl!(a: i32, b: i32, c: i32, d: i32, e: i32, f: i32, g: i32, h: i32, i: i32); +tuple_impl!( + a: i32, + b: i32, + c: i32, + d: i32, + e: i32, + f: i32, + g: i32, + h: i32 +); +tuple_impl!( + a: i32, + b: i32, + c: i32, + d: i32, + e: i32, + f: i32, + g: i32, + h: i32, + i: i32 +); /// Indexes into the `Array`, retrieving a reference to the contained /// value. @@ -262,13 +299,15 @@ impl IntoIterator for Array { type IntoIter = IntoIter; fn into_iter(self) -> IntoIter { - IntoIter { inner: self.data.into_iter() } + IntoIter { + inner: self.data.into_iter(), + } } } /// An iterator over references to values of an `Array` in the /// higher-dimensional equivalent of row-major order. -pub struct Iter<'a, T: 'a> { +pub struct Iter<'a, T> { inner: slice::Iter<'a, T>, } @@ -298,7 +337,7 @@ impl<'a, T: 'a> ExactSizeIterator for Iter<'a, T> { /// An iterator over mutable references to values of an `Array` in the /// higher-dimensional equivalent of row-major order. -pub struct IterMut<'a, T: 'a> { +pub struct IterMut<'a, T> { inner: slice::IterMut<'a, T>, } diff --git a/src/impls.rs b/src/impls.rs index 6eda63a..399a36e 100644 --- a/src/impls.rs +++ b/src/impls.rs @@ -1,31 +1,38 @@ use fallible_iterator::FallibleIterator; -use postgres::types::{Type, Kind, ToSql, FromSql, IsNull, SessionInfo}; -use postgres_protocol::types; use postgres_protocol; +use postgres_protocol::types; +use postgres_types::{to_sql_checked, FromSql, IsNull, Kind, ToSql, Type}; use std::error::Error; -use {Array, Dimension}; +use crate::{Array, Dimension}; +use postgres_types::private::BytesMut; -impl FromSql for Array - where T: FromSql +impl<'de, T> FromSql<'de> for Array +where + T: FromSql<'de>, { - fn from_sql(ty: &Type, raw: &[u8], info: &SessionInfo) -> Result, Box> { + fn from_sql(ty: &Type, raw: &'de [u8]) -> Result, Box> { let element_type = match *ty.kind() { Kind::Array(ref ty) => ty, _ => unreachable!(), }; - let array = try!(types::array_from_sql(raw)); + let array = types::array_from_sql(raw)?; - let dimensions = try!(array.dimensions() + let dimensions = array + .dimensions() .map(|d| { - Dimension { len: d.len, lower_bound: d.lower_bound } + Ok(Dimension { + len: d.len, + lower_bound: d.lower_bound, + }) }) - .collect()); + .collect()?; - let elements = try!(array.values() - .and_then(|v| FromSql::from_sql_nullable(element_type, v, info)) - .collect()); + let elements = array + .values() + .map(|v| FromSql::from_sql_nullable(element_type, v)) + .collect()?; Ok(Array::from_parts(elements, dimensions)) } @@ -39,36 +46,32 @@ impl FromSql for Array } impl ToSql for Array - where T: ToSql +where + T: ToSql, { - fn to_sql(&self, ty: &Type, w: &mut Vec, info: &SessionInfo) -> Result> { + fn to_sql(&self, ty: &Type, w: &mut BytesMut) -> Result> { let element_type = match ty.kind() { &Kind::Array(ref ty) => ty, _ => unreachable!(), }; - let dimensions = self.dimensions() - .iter() - .map(|d| { - types::ArrayDimension { - len: d.len, - lower_bound: d.lower_bound, - } - }); + let dimensions = self.dimensions().iter().map(|d| types::ArrayDimension { + len: d.len, + lower_bound: d.lower_bound, + }); let elements = self.iter(); - try!(types::array_to_sql(dimensions, - true, - element_type.oid(), - elements, - |v, w| { - match v.to_sql(element_type, w, info) { - Ok(IsNull::Yes) => Ok(postgres_protocol::IsNull::Yes), - Ok(IsNull::No) => Ok(postgres_protocol::IsNull::No), - Err(e) => Err(e), - } - }, - w)); + types::array_to_sql( + dimensions, + element_type.oid(), + elements, + |v, w| match v.to_sql(element_type, w) { + Ok(IsNull::Yes) => Ok(postgres_protocol::IsNull::Yes), + Ok(IsNull::No) => Ok(postgres_protocol::IsNull::No), + Err(e) => Err(e), + }, + w, + )?; Ok(IsNull::No) } @@ -87,38 +90,49 @@ impl ToSql for Array mod test { use std::fmt; - use postgres::{Connection, TlsMode}; - use postgres::types::{FromSql, ToSql}; - use Array; + use crate::Array; + use postgres::types::{FromSqlOwned, ToSql}; + use postgres::{Client, NoTls}; - fn test_type(sql_type: &str, - checks: &[(T, S)]) { - let conn = Connection::connect("postgres://postgres@localhost", TlsMode::None).unwrap(); + fn test_type( + sql_type: &str, + checks: &[(T, S)], + ) { + let mut conn = Client::connect("postgres://postgres:password@localhost", NoTls).unwrap(); for &(ref val, ref repr) in checks.iter() { - let stmt = conn.prepare(&format!("SELECT {}::{}", *repr, sql_type)).unwrap(); - let result = stmt.query(&[]).unwrap().iter().next().unwrap().get(0); + let result = conn + .query(&*format!("SELECT {}::{}", *repr, sql_type), &[]) + .unwrap()[0] + .get(0); assert!(val == &result); - let stmt = conn.prepare(&format!("SELECT $1::{}", sql_type)).unwrap(); - let result = stmt.query(&[val]).unwrap().iter().next().unwrap().get(0); + let result = conn + .query(&*format!("SELECT $1::{}", sql_type), &[val]) + .unwrap()[0] + .get(0); assert!(val == &result); } } macro_rules! test_array_params { - ($name:expr, $v1:expr, $s1:expr, $v2:expr, $s2:expr, $v3:expr, $s3:expr) => ({ - - let tests = &[(Some(Array::from_vec(vec!(Some($v1), Some($v2), None), 1)), - format!("'{{{},{},NULL}}'", $s1, $s2)), - (None, "NULL".to_string())]; + ($name:expr, $v1:expr, $s1:expr, $v2:expr, $s2:expr, $v3:expr, $s3:expr) => {{ + let tests = &[ + ( + Some(Array::from_vec(vec![Some($v1), Some($v2), None], 1)), + format!("'{{{},{},NULL}}'", $s1, $s2), + ), + (None, "NULL".to_string()), + ]; test_type(&format!("{}[]", $name), tests); - let mut a = Array::from_vec(vec!(Some($v1), Some($v2)), 0); + let mut a = Array::from_vec(vec![Some($v1), Some($v2)], 0); a.wrap(-1); - a.push(Array::from_vec(vec!(None, Some($v3)), 0)); - let tests = &[(Some(a), format!("'[-1:0][0:1]={{{{{},{}}},{{NULL,{}}}}}'", - $s1, $s2, $s3))]; + a.push(Array::from_vec(vec![None, Some($v3)], 0)); + let tests = &[( + Some(a), + format!("'[-1:0][0:1]={{{{{},{}}},{{NULL,{}}}}}'", $s1, $s2, $s3), + )]; test_type(&format!("{}[][]", $name), tests); - }) + }}; } #[test] @@ -128,13 +142,15 @@ mod test { #[test] fn test_byteaarray_params() { - test_array_params!("BYTEA", - vec![0u8, 1], - r#""\\x0001""#, - vec![254u8, 255u8], - r#""\\xfeff""#, - vec![10u8, 11u8], - r#""\\x0a0b""#); + test_array_params!( + "BYTEA", + vec![0u8, 1], + r#""\\x0001""#, + vec![254u8, 255u8], + r#""\\xfeff""#, + vec![10u8, 11u8], + r#""\\x0a0b""# + ); } #[test] @@ -144,13 +160,15 @@ mod test { #[test] fn test_namearray_params() { - test_array_params!("NAME", - "hello".to_string(), - "hello", - "world".to_string(), - "world", - "!".to_string(), - "!"); + test_array_params!( + "NAME", + "hello".to_string(), + "hello", + "world".to_string(), + "world", + "!".to_string(), + "!" + ); } #[test] @@ -165,35 +183,41 @@ mod test { #[test] fn test_textarray_params() { - test_array_params!("TEXT", - "hello".to_string(), - "hello", - "world".to_string(), - "world", - "!".to_string(), - "!"); + test_array_params!( + "TEXT", + "hello".to_string(), + "hello", + "world".to_string(), + "world", + "!".to_string(), + "!" + ); } #[test] fn test_charnarray_params() { - test_array_params!("CHAR(5)", - "hello".to_string(), - "hello", - "world".to_string(), - "world", - "! ".to_string(), - "!"); + test_array_params!( + "CHAR(5)", + "hello".to_string(), + "hello", + "world".to_string(), + "world", + "! ".to_string(), + "!" + ); } #[test] fn test_varchararray_params() { - test_array_params!("VARCHAR", - "hello".to_string(), - "hello", - "world".to_string(), - "world", - "!".to_string(), - "!"); + test_array_params!( + "VARCHAR", + "hello".to_string(), + "hello", + "world".to_string(), + "world", + "!".to_string(), + "!" + ); } #[test] @@ -213,8 +237,7 @@ mod test { #[test] fn test_empty_array() { - let conn = Connection::connect("postgres://postgres@localhost", TlsMode::None).unwrap(); - let stmt = conn.prepare("SELECT '{}'::INT4[]").unwrap(); - stmt.query(&[]).unwrap().iter().next().unwrap().get::<_, Array>(0); + let mut conn = Client::connect("postgres://postgres@localhost", NoTls).unwrap(); + conn.query("SELECT '{}'::INT4[]", &[]).unwrap()[0].get::<_, Array>(0); } } diff --git a/src/lib.rs b/src/lib.rs index e29dbdb..21240da 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,13 +1,8 @@ //! Multi-dimensional arrays with per-dimension specifiable lower bounds -#![doc(html_root_url="https://sfackler.github.io/rust-postgres-array/doc/v0.7.1")] - -extern crate fallible_iterator; -#[macro_use] -extern crate postgres; -extern crate postgres_protocol; +#![doc(html_root_url = "https://docs.rs/postgres_array/0.10")] #[doc(inline)] -pub use array::Array; +pub use crate::array::Array; pub mod array; mod impls; @@ -25,8 +20,10 @@ impl Dimension { fn shift(&self, idx: i32) -> i32 { let offset = self.lower_bound; assert!(idx >= offset, "out of bounds array access"); - assert!(offset >= 0 || idx <= 0 || i32::max_value() - (-offset) >= idx, - "out of bounds array access"); + assert!( + offset >= 0 || idx <= 0 || i32::max_value() - (-offset) >= idx, + "out of bounds array access" + ); match idx.checked_sub(offset) { Some(shifted) => shifted, None => panic!("out of bounds array access"), @@ -41,10 +38,13 @@ mod tests { #[test] fn test_from_vec() { let a = Array::from_vec(vec![0i32, 1, 2], -1); - assert!(&[Dimension { - len: 3, - lower_bound: -1, - }][..] == a.dimensions()); + assert!( + &[Dimension { + len: 3, + lower_bound: -1, + },][..] + == a.dimensions() + ); assert_eq!(0, a[-1]); assert_eq!(1, a[0]); assert_eq!(2, a[1]); @@ -146,5 +146,8 @@ mod tests { a.push(Array::from_vec(vec![4, 5, 6], 3)); a.wrap(1); assert_eq!("[1:1][-2:-1][3:5]={{{1,2,3},{4,5,6}}}", &format!("{}", a)); + + let a: Array = Array::from_parts(vec![], vec![]); + assert_eq!("{}", &format!("{}", a)); } } pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy