From 210c6ca6aef4dc8699fd01649bb530be212b0a62 Mon Sep 17 00:00:00 2001 From: dnwpark Date: Tue, 10 Dec 2024 21:53:16 -0500 Subject: [PATCH] Support printing postgis data. --- Cargo.lock | 75 +++++++++++++++++- Cargo.toml | 1 + src/outputs/tab_separated.rs | 4 + src/print/native.rs | 17 ++++ src/print/tests.rs | 147 +++++++++++++++++++++++++++++++++++ 5 files changed, 240 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fa5840f11..fd81389ff 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -149,6 +149,15 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7992085ec035cfe96992dd31bfd495a2ebd31969bb95f624471cb6c0b349e571" +[[package]] +name = "approx" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6" +dependencies = [ + "num-traits", +] + [[package]] name = "arbitrary" version = "1.4.1" @@ -1161,6 +1170,7 @@ dependencies = [ "fs-err", "fs_extra", "futures-util", + "geozero", "gethostname", "hex", "humantime", @@ -1259,7 +1269,7 @@ dependencies = [ [[package]] name = "edgedb-derive" version = "0.5.2" -source = "git+https://github.com/edgedb/edgedb-rust/#afdbaaca2518adb4041460b13181fc860e36add9" +source = "git+https://github.com/edgedb/edgedb-rust/#0929ef146c32037dc6ad4ac8e1cbdaa091640066" dependencies = [ "proc-macro2", "quote", @@ -1270,7 +1280,7 @@ dependencies = [ [[package]] name = "edgedb-errors" version = "0.4.2" -source = "git+https://github.com/edgedb/edgedb-rust/#afdbaaca2518adb4041460b13181fc860e36add9" +source = "git+https://github.com/edgedb/edgedb-rust/#0929ef146c32037dc6ad4ac8e1cbdaa091640066" dependencies = [ "bytes", ] @@ -1278,7 +1288,7 @@ dependencies = [ [[package]] name = "edgedb-protocol" version = "0.6.1" -source = "git+https://github.com/edgedb/edgedb-rust/#afdbaaca2518adb4041460b13181fc860e36add9" +source = "git+https://github.com/edgedb/edgedb-rust/#0929ef146c32037dc6ad4ac8e1cbdaa091640066" dependencies = [ "bigdecimal", "bitflags 2.6.0", @@ -1296,7 +1306,7 @@ dependencies = [ [[package]] name = "edgedb-tokio" version = "0.5.1" -source = "git+https://github.com/edgedb/edgedb-rust/#afdbaaca2518adb4041460b13181fc860e36add9" +source = "git+https://github.com/edgedb/edgedb-rust/#0929ef146c32037dc6ad4ac8e1cbdaa091640066" dependencies = [ "anyhow", "arc-swap", @@ -1686,6 +1696,44 @@ dependencies = [ "version_check", ] +[[package]] +name = "geo-types" +version = "0.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6f47c611187777bbca61ea7aba780213f5f3441fd36294ab333e96cfa791b65" +dependencies = [ + "approx", + "num-traits", + "serde", +] + +[[package]] +name = "geojson" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5d728c1df1fbf328d74151efe6cb0586f79ee813346ea981add69bd22c9241b" +dependencies = [ + "log", + "serde", + "serde_json", + "thiserror 1.0.69", +] + +[[package]] +name = "geozero" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5f28f34864745eb2f123c990c6ffd92c1584bd39439b3f27ff2a0f4ea5b309b" +dependencies = [ + "geo-types", + "geojson", + "log", + "scroll", + "serde_json", + "thiserror 1.0.69", + "wkt", +] + [[package]] name = "gethostname" version = "0.5.0" @@ -2663,6 +2711,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", + "libm", ] [[package]] @@ -3569,6 +3618,12 @@ dependencies = [ "ring", ] +[[package]] +name = "scroll" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04c565b551bafbef4157586fa379538366e4385d42082f255bfd96e4fe8519da" + [[package]] name = "security-framework" version = "3.0.1" @@ -5004,6 +5059,18 @@ version = "0.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" +[[package]] +name = "wkt" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54f7f1ff4ea4c18936d6cd26a6fd24f0003af37e951a8e0e8b9e9a2d0bd0a46d" +dependencies = [ + "geo-types", + "log", + "num-traits", + "thiserror 1.0.69", +] + [[package]] name = "write16" version = "1.0.0" diff --git a/Cargo.toml b/Cargo.toml index e58615a12..4dde665f6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -138,6 +138,7 @@ nom = "7.1.3" bitflags = "2.6" renamore = "0.3.2" anes = "0.2.0" +geozero = {version="0.14.0",features=["with-wkb"]} [dependencies.bzip2] version = "*" diff --git a/src/outputs/tab_separated.rs b/src/outputs/tab_separated.rs index be3bd18b7..ed89ff0f1 100644 --- a/src/outputs/tab_separated.rs +++ b/src/outputs/tab_separated.rs @@ -50,6 +50,10 @@ fn value_to_string(v: &Value) -> Result { | Set(_) | Tuple(_) | Range {..} + | PostGisGeometry {..} + | PostGisGeography {..} + | PostGisBox2d {..} + | PostGisBox3d {..} => { Err(anyhow::anyhow!( "Complex objects like {:?} cannot be printed tab-separated", diff --git a/src/print/native.rs b/src/print/native.rs index 321fc2619..4d01516ef 100644 --- a/src/print/native.rs +++ b/src/print/native.rs @@ -7,6 +7,7 @@ use crate::print::buffer::Result; use crate::print::formatter::Formatter; use crate::repl::VectorLimit; use edgedb_protocol::value::Value; +use geozero::{wkb::Ewkb, ToWkt}; pub trait FormatExt { fn format(&self, prn: &mut F) -> Result; @@ -270,6 +271,22 @@ impl FormatExt for Value { Ok(()) }) } + V::PostGisGeometry(v) => { + let wkb = Ewkb(v); + prn.const_string(wkb.to_ewkt(None).unwrap()) + } + V::PostGisGeography(v) => { + let wkb = Ewkb(v); + prn.const_string(wkb.to_ewkt(None).unwrap()) + } + V::PostGisBox2d(v) => { + let wkb = Ewkb(v); + prn.const_string(wkb.to_ewkt(None).unwrap()) + } + V::PostGisBox3d(v) => { + let wkb = Ewkb(v); + prn.const_string(wkb.to_ewkt(None).unwrap()) + } } } } diff --git a/src/print/tests.rs b/src/print/tests.rs index be7799224..15c7fbd84 100644 --- a/src/print/tests.rs +++ b/src/print/tests.rs @@ -6,6 +6,7 @@ use std::task; use bigdecimal::BigDecimal; use bytes::Bytes; +use nom::AsBytes; use tokio_stream::Stream; use crate::print::native::FormatExt; @@ -579,3 +580,149 @@ fn json() { ]"### ); } + +#[test] +fn postgis_geometry() { + assert_eq!( + test_format(&[Value::PostGisGeometry( + /* + * Point + * 01 - byteOrder, Little Endian + * 01000000 - wkbType, WKBPoint + * 0000000000000040 - x, 2.0 + * 000000000000F03F - y, 1.0 + */ + b"\ + \x01\ + \x01\x00\x00\x00\ + \x00\x00\x00\x00\x00\x00\x00\x40\ + \x00\x00\x00\x00\x00\x00\xF0\x3F\ + "[..] + .into() + ),],) + .unwrap(), + r###"{POINT(2 1)}"### + ); +} + +#[test] +fn postgis_geography() { + assert_eq!( + test_format(&[Value::PostGisGeography( + /* + * Point + * 01 - byteOrder, Little Endian + * 01000000 - wkbType, WKBPoint + * 0000000000000040 - x, 2.0 + * 000000000000F03F - y, 1.0 + */ + b"\ + \x01\ + \x01\x00\x00\x00\ + \x00\x00\x00\x00\x00\x00\x00\x40\ + \x00\x00\x00\x00\x00\x00\xF0\x3F\ + "[..] + .into(), + ),],) + .unwrap(), + r###"{POINT(2 1)}"### + ); +} + +#[test] +fn postgis_box_2d() { + assert_eq!( + test_format(&[Value::PostGisBox2d( + /* + * Polygon + * 01 - byteOrder, Little Endian + * 03000000 - wkbType, wkbPolygon + * 01000000 - numRings, 1 + * 05000000 - numPoints, 5 + * 000000000000F03F - x, 1.0 + * 000000000000F03F - y, 1.0 + * 0000000000000040 - x, 2.0 + * 000000000000F03F - y, 1.0 + * 0000000000000040 - x, 2.0 + * 0000000000000040 - y, 2.0 + * 000000000000F03F - x, 1.0 + * 0000000000000040 - y, 2.0 + * 000000000000F03F - x, 1.0 + * 000000000000F03F - y, 1.0 + */ + b"\ + \x01\ + \x03\x00\x00\x00\ + \x01\x00\x00\x00\ + \x05\x00\x00\x00\ + \x00\x00\x00\x00\x00\x00\xF0\x3F\ + \x00\x00\x00\x00\x00\x00\xF0\x3F\ + \x00\x00\x00\x00\x00\x00\x00\x40\ + \x00\x00\x00\x00\x00\x00\xF0\x3F\ + \x00\x00\x00\x00\x00\x00\x00\x40\ + \x00\x00\x00\x00\x00\x00\x00\x40\ + \x00\x00\x00\x00\x00\x00\xF0\x3F\ + \x00\x00\x00\x00\x00\x00\x00\x40\ + \x00\x00\x00\x00\x00\x00\xF0\x3F\ + \x00\x00\x00\x00\x00\x00\xF0\x3F\ + "[..] + .into(), + ),],) + .unwrap(), + r###"{POLYGON((1 1,2 1,2 2,1 2,1 1))}"### + ); +} + +#[test] +fn postgis_box_3d() { + assert_eq!( + test_format(&[Value::PostGisBox2d( + /* + * Polygon + * 01 - byteOrder, Little Endian + * 03000080 - wkbType, wkbPolygonZ + * 01000000 - numRings, 1 + * 05000000 - numPoints, 5 + * 000000000000F03F - x, 1.0 + * 000000000000F03F - y, 1.0 + * 0000000000000000 - z, 0.0 + * 0000000000000040 - x, 2.0 + * 000000000000F03F - y, 1.0 + * 0000000000000000 - z, 0.0 + * 0000000000000040 - x, 2.0 + * 0000000000000040 - y, 2.0 + * 0000000000000000 - z, 0.0 + * 000000000000F03F - x, 1.0 + * 0000000000000040 - y, 2.0 + * 0000000000000000 - z, 0.0 + * 000000000000F03F - x, 1.0 + * 000000000000F03F - y, 1.0 + * 0000000000000000 - z, 0.0 + */ + b"\ + \x01\ + \x03\x00\x00\x80\ + \x01\x00\x00\x00\ + \x05\x00\x00\x00\ + \x00\x00\x00\x00\x00\x00\xF0\x3F\ + \x00\x00\x00\x00\x00\x00\xF0\x3F\ + \x00\x00\x00\x00\x00\x00\x08\x40\ + \x00\x00\x00\x00\x00\x00\x00\x40\ + \x00\x00\x00\x00\x00\x00\xF0\x3F\ + \x00\x00\x00\x00\x00\x00\x08\x40\ + \x00\x00\x00\x00\x00\x00\x00\x40\ + \x00\x00\x00\x00\x00\x00\x00\x40\ + \x00\x00\x00\x00\x00\x00\x08\x40\ + \x00\x00\x00\x00\x00\x00\xF0\x3F\ + \x00\x00\x00\x00\x00\x00\x00\x40\ + \x00\x00\x00\x00\x00\x00\x08\x40\ + \x00\x00\x00\x00\x00\x00\xF0\x3F\ + \x00\x00\x00\x00\x00\x00\xF0\x3F\ + \x00\x00\x00\x00\x00\x00\x08\x40\ + "[..] + .into(), + ),],) + .unwrap(), + r###"{POLYGON((1 1 3,2 1 3,2 2 3,1 2 3,1 1 3))}"### + ); +}