mirror of
https://github.com/launchbadge/sqlx.git
synced 2026-03-05 21:29:31 +00:00
Add support for geo::Line<f64> for Postgres
This commit is contained in:
parent
0e25c1c48f
commit
8a1c74bb84
@ -1,60 +1,136 @@
|
||||
use crate::decode::Decode;
|
||||
use crate::encode::Encode;
|
||||
use crate::types::Type;
|
||||
use crate::postgres::protocol::TypeId;
|
||||
use crate::postgres::{ PgData, PgValue, PgRawBuffer, PgTypeInfo, Postgres };
|
||||
use crate::io::Buf;
|
||||
use std::mem;
|
||||
use geo::Coordinate;
|
||||
use byteorder::BigEndian;
|
||||
use crate::{
|
||||
decode::Decode,
|
||||
encode::{Encode, IsNull},
|
||||
error::BoxDynError,
|
||||
postgres::{PgArgumentBuffer, PgTypeInfo, PgValueFormat, PgValueRef, Postgres},
|
||||
types::Type,
|
||||
};
|
||||
use byteorder::{BigEndian, ByteOrder};
|
||||
use geo::{Line, Coordinate};
|
||||
use std::{mem, num::ParseFloatError};
|
||||
|
||||
// <https://www.postgresql.org/docs/12/datatype-geometric.html>
|
||||
|
||||
impl Type<Postgres> for Coordinate<f64> {
|
||||
fn type_info() -> PgTypeInfo {
|
||||
PgTypeInfo::new(TypeId::POINT, "POINT")
|
||||
PgTypeInfo::POINT
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Decode<'de, Postgres> for Coordinate<f64> {
|
||||
fn decode(value: PgValue<'de>) -> crate::Result<Self> {
|
||||
match value.try_get()? {
|
||||
PgData::Binary(mut buf) => {
|
||||
let x = buf.get_f64::<BigEndian>()?;
|
||||
println!("we have what is hopefully x: {}", x);
|
||||
|
||||
let y = buf.get_f64::<BigEndian>()?;
|
||||
println!("is this a y? {}", y);
|
||||
impl Decode<'_, Postgres> for Coordinate<f64> {
|
||||
fn decode(value: PgValueRef<'_>) -> Result<Self, BoxDynError> {
|
||||
match value.format() {
|
||||
PgValueFormat::Binary => {
|
||||
let buf = value.as_bytes()?;
|
||||
|
||||
Ok((x, y).into())
|
||||
decode_coordinate_binary(buf)
|
||||
}
|
||||
|
||||
PgData::Text(s) => {
|
||||
PgValueFormat::Text => {
|
||||
let s = value.as_str()?;
|
||||
|
||||
let parens: &[_] = &['(', ')'];
|
||||
let mut s = s.trim_matches(parens).split(',');
|
||||
|
||||
match (s.next(), s.next()) {
|
||||
(Some(x), Some(y)) => {
|
||||
let x = x.parse().map_err(crate::Error::decode)?;
|
||||
let y = y.parse().map_err(crate::Error::decode)?;
|
||||
let x = x
|
||||
.parse()
|
||||
.map_err(|e: ParseFloatError| crate::error::Error::Decode(e.into()))?;
|
||||
let y = y
|
||||
.parse()
|
||||
.map_err(|e: ParseFloatError| crate::error::Error::Decode(e.into()))?;
|
||||
|
||||
Ok((x, y).into())
|
||||
}
|
||||
|
||||
_ => Err(crate::Error::Decode(format!("expecting a value with the format \"(x,y)\"").into()))
|
||||
_ => Err(Box::new(crate::error::Error::Decode(
|
||||
format!("expecting a value with the format \"(x,y)\"").into(),
|
||||
))),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Encode<Postgres> for Coordinate<f64> {
|
||||
fn encode(&self, buf: &mut PgRawBuffer) {
|
||||
Encode::<Postgres>::encode(&self.x, buf);
|
||||
Encode::<Postgres>::encode(&self.y, buf);
|
||||
fn decode_coordinate_binary(buf: &[u8]) -> Result<Coordinate<f64>, BoxDynError> {
|
||||
let x = BigEndian::read_f64(buf);
|
||||
|
||||
let y = BigEndian::read_f64(buf);
|
||||
|
||||
Ok((x, y).into())
|
||||
}
|
||||
|
||||
impl Encode<'_, Postgres> for Coordinate<f64> {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
|
||||
let _ = Encode::<Postgres>::encode(self.x, buf);
|
||||
let _ = Encode::<Postgres>::encode(self.y, buf);
|
||||
|
||||
IsNull::No
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> usize {
|
||||
2 * mem::size_of::<f64>()
|
||||
}
|
||||
}
|
||||
|
||||
impl Type<Postgres> for Line<f64> {
|
||||
fn type_info() -> PgTypeInfo {
|
||||
PgTypeInfo::LSEG
|
||||
}
|
||||
}
|
||||
|
||||
impl Decode<'_, Postgres> for Line<f64> {
|
||||
fn decode(value: PgValueRef<'_>) -> Result<Self, BoxDynError> {
|
||||
match value.format() {
|
||||
PgValueFormat::Binary => {
|
||||
let buf = value.as_bytes()?;
|
||||
let start = decode_coordinate_binary(buf)?;
|
||||
// buf.advance(Encode::<Postgres>::size_hint(&start));
|
||||
let end = decode_coordinate_binary(buf)?;
|
||||
|
||||
Ok(Line::new(start, end))
|
||||
}
|
||||
|
||||
// TODO: is there no way to make this make use of the Decode for Coordinate?
|
||||
PgValueFormat::Text => {
|
||||
let brackets: &[_] = &['[', ']'];
|
||||
let mut s = value.as_str()?
|
||||
.trim_matches(brackets)
|
||||
.split(|c| c == '(' || c == ')' || c == ',')
|
||||
.filter_map(|part| if part == "" { None } else { Some(part) });
|
||||
|
||||
match (s.next(), s.next(), s.next(), s.next()) {
|
||||
(Some(x1), Some(y1), Some(x2), Some(y2)) => {
|
||||
let x1 = x1.parse().map_err(|e: ParseFloatError| crate::error::Error::Decode(e.into()))?;
|
||||
let y1 = y1.parse().map_err(|e: ParseFloatError| crate::error::Error::Decode(e.into()))?;
|
||||
let x2 = x2.parse().map_err(|e: ParseFloatError| crate::error::Error::Decode(e.into()))?;
|
||||
let y2 = y2.parse().map_err(|e: ParseFloatError| crate::error::Error::Decode(e.into()))?;
|
||||
|
||||
let start = Coordinate::from((x1, y1));
|
||||
let end = Coordinate::from((x2, y2));
|
||||
|
||||
Ok(Line::new(start, end))
|
||||
}
|
||||
|
||||
_ => Err(Box::new(crate::error::Error::Decode(
|
||||
format!("expecting a value with the format \"[(x,y),(x,y)]\"").into(),
|
||||
))),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Encode<'_, Postgres> for Line<f64> {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
|
||||
let _ = Encode::<Postgres>::encode_by_ref(&self.start, buf);
|
||||
let _ = Encode::<Postgres>::encode_by_ref(&self.end, buf);
|
||||
|
||||
IsNull::No
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> usize {
|
||||
2 * Encode::<Postgres>::size_hint(&self.start)
|
||||
}
|
||||
}
|
||||
|
||||
@ -94,7 +94,7 @@
|
||||
//! [`Json<T>`] can be used for structured JSON data with Postgres.
|
||||
//!
|
||||
//! [`Json<T>`]: crate::types::Json
|
||||
//!
|
||||
//!
|
||||
//! ### [`geo`](https://crates.io/crates/geo)
|
||||
//!
|
||||
//! Requires the `geo` Cargo feature flag.
|
||||
@ -102,7 +102,7 @@
|
||||
//! | Rust type | Postgres type(s) |
|
||||
//! |---------------------------------------|------------------------------------------------------|
|
||||
//! | `geo::Coordinate<f64>` | POINT |
|
||||
//! | `geo::Line<f64>` | LINE, LSEG |
|
||||
//! | `geo::Line<f64>` | LSEG |
|
||||
//! | `geo::Rect<f64>` | BOX |
|
||||
//! | `geo::LineString<f64>` | PATH |
|
||||
//! | `geo::Polygon<f64>` | POLYGON |
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user