Skip to content

Commit

Permalink
Add wrappers for postgres geometric types.
Browse files Browse the repository at this point in the history
For simple `Copy` types, just alias them and add impls for
FromDatum and ToDatum.

For more complex variable length types, create owned structs with
impls for FromDatum and ToDatum as well as SqlTranslatable.
  • Loading branch information
hamiltop committed Oct 13, 2023
1 parent 6bbe8ff commit b510864
Show file tree
Hide file tree
Showing 4 changed files with 402 additions and 22 deletions.
9 changes: 7 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -185,8 +185,13 @@ cargo pgrx init
| `timestamp with time zone` | `pgrx::TimestampWithTimeZone` |
| `anyarray` | `pgrx::AnyArray` |
| `anyelement` | `pgrx::AnyElement` |
| `box` | `pgrx::pg_sys::BOX` |
| `point` | `pgrx::pg_sys::Point` |
| `box` | `pgrx::geo::Box` |
| `circle` | `pgrx::geo::Circle` |
| `line` | `pgrx::geo::Line` |
| `lseg` | `pgrx::geo::LineSegment` |
| `path` | `pgrx::geo::Path` |
| `point` | `pgrx::geo::Point` |
| `polygon` | `pgrx::geo::Polygon` |
| `tid` | `pgrx::pg_sys::ItemPointerData` |
| `cstring` | `&core::ffi::CStr` |
| `inet` | `pgrx::Inet(String)` -- TODO: needs better support |
Expand Down
95 changes: 84 additions & 11 deletions pgrx-tests/src/tests/geo_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,24 +13,97 @@ mod tests {
#[allow(unused_imports)]
use crate as pgrx_tests;

use pgrx::datum::geo::*;
use pgrx::prelude::*;

#[pg_test]
fn test_point_into_datum() -> spi::Result<()> {
let p =
Spi::get_one::<pg_sys::Point>("SELECT '42, 99'::point")?.expect("SPI result was null");
assert_eq!(p.x, 42.0);
assert_eq!(p.y, 99.0);
fn test_point_datum() -> spi::Result<()> {
let p = Spi::get_one::<Point>("SELECT '42, 99'::point")?.expect("SPI result was null");
assert_eq!(p, Point { x: 42.0, y: 99.0 });
let p2 = Spi::get_one_with_args::<Point>(
"SELECT $1",
vec![(Point::type_oid().into(), p.into_datum())],
)?
.expect("SPI result was null");
assert_eq!(p, p2);
Ok(())
}

#[pg_test]
fn test_box_into_datum() -> spi::Result<()> {
let b = Spi::get_one::<pg_sys::BOX>("SELECT '1,2,3,4'::box")?.expect("SPI result was null");
assert_eq!(b.high.x, 3.0);
assert_eq!(b.high.y, 4.0);
assert_eq!(b.low.x, 1.0);
assert_eq!(b.low.y, 2.0);
fn test_box_datum() -> spi::Result<()> {
let b = Spi::get_one::<Box>("SELECT '1,2,3,4'::box")?.expect("SPI result was null");
assert_eq!(b, Box { high: Point { x: 3.0, y: 4.0 }, low: Point { x: 1.0, y: 2.0 } });
let b2 = Spi::get_one_with_args::<Box>(
"SELECT $1",
vec![(Box::type_oid().into(), b.into_datum())],
)?
.expect("SPI result was null");
assert_eq!(b, b2);
Ok(())
}

#[pg_test]
fn test_lseg_datum() -> spi::Result<()> {
let l = Spi::get_one::<LineSegment>("SELECT '(1,2),(3,4)'::lseg")?
.expect("SPI result was null");
assert_eq!(l.p, [Point { x: 1.0, y: 2.0 }, Point { x: 3.0, y: 4.0 }]);
let l2 = Spi::get_one_with_args::<LineSegment>(
"SELECT $1",
vec![(LineSegment::type_oid().into(), l.into_datum())],
)?
.expect("SPI result was null");
assert_eq!(l.p, l2.p);
Ok(())
}

#[pg_test]
fn test_path_datum() -> spi::Result<()> {
// Closed path
let p = Spi::get_one::<Path>("SELECT '((1,2),(3,4))'::path")?.expect("SPI result was null");
assert_eq!(p.points(), [Point { x: 1.0, y: 2.0 }, Point { x: 3.0, y: 4.0 }]);
assert_eq!(p.closed(), true);
let p2 = Spi::get_one_with_args::<Path>(
"SELECT $1",
vec![(Path::type_oid().into(), p.clone().into_datum())],
)?
.expect("SPI result was null");
assert_eq!(p.points(), p2.points());
assert_eq!(p.closed(), p2.closed());

// Open path
let p = Spi::get_one::<Path>("SELECT '[(1,2),(3,4)]'::path")?.expect("SPI result was null");
assert_eq!(p.points(), [Point { x: 1.0, y: 2.0 }, Point { x: 3.0, y: 4.0 }]);
assert_eq!(p.closed(), false);
let p2 = Spi::get_one_with_args::<Path>(
"SELECT $1",
vec![(Path::type_oid().into(), p.clone().into_datum())],
)?
.expect("SPI result was null");
assert_eq!(p.points(), p2.points());
assert_eq!(p.closed(), p2.closed());

Ok(())
}

#[pg_test]
fn test_polygon_datum() -> spi::Result<()> {
let p = Spi::get_one::<Polygon>("SELECT '((1,2),(3,4),(0,5))'::polygon")?
.expect("SPI result was null");
assert_eq!(
p.points(),
[Point { x: 1.0, y: 2.0 }, Point { x: 3.0, y: 4.0 }, Point { x: 0.0, y: 5.0 }]
);
assert_eq!(
p.boundbox(),
Box { high: Point { x: 3.0, y: 5.0 }, low: Point { x: 0.0, y: 2.0 } }
);
let p2 = Spi::get_one_with_args::<Polygon>(
"SELECT $1",
vec![(Polygon::type_oid().into(), p.clone().into_datum())],
)?
.expect("SPI result was null");
assert_eq!(p.points(), p2.points());
assert_eq!(p.boundbox(), p2.boundbox());
Ok(())
}
}
Loading

0 comments on commit b510864

Please sign in to comment.