Skip to content

Commit

Permalink
Merge pull request #89 from myaple/dev/diesel-postgis
Browse files Browse the repository at this point in the history
Adds diesel support for Ewkb type for postgis
  • Loading branch information
pka committed Dec 20, 2022
2 parents a2f294f + fa72b16 commit bcc1c3a
Show file tree
Hide file tree
Showing 5 changed files with 137 additions and 1 deletion.
4 changes: 4 additions & 0 deletions geozero/Cargo.toml
Expand Up @@ -25,6 +25,7 @@ with-gpkg = ["with-wkb", "sqlx/sqlite"]
with-gpx = ["gpx"]
with-postgis-sqlx = ["with-wkb", "sqlx/postgres"]
with-postgis-postgres = ["with-wkb", "postgres-types", "bytes"]
with-postgis-diesel = ["with-wkb", "diesel", "byteorder"]
with-mvt = ["prost", "prost-build"]
with-tessellator = ["lyon"]

Expand All @@ -42,6 +43,8 @@ lyon = { version = "1.0", optional = true }
log = "0.4.17"
scroll = { version = "0.11", optional = true }
sqlx = { version = "0.6", default-features = false, optional = true }
diesel = { version = "2.0.2", default-features = false, optional = true }
byteorder = { version = "1.4.3", default-features = false, optional = true }
postgres-types = { version = "0.2", optional = true }
bytes = { version = "1.0", optional = true }
prost = { version = "0.11.0", optional = true }
Expand All @@ -59,6 +62,7 @@ flatgeobuf = "3.24.0"
#flatgeobuf = { git = "https://github.com/pka/flatgeobuf", branch="geozero-0.9" }
postgres = "0.19"
sqlx = { version = "0.6", default-features = false, features = [ "runtime-tokio-native-tls", "macros", "time", "postgres", "sqlite" ] }
diesel = { version = "2.0.2", default-features = false, features = [ "postgres" ] }
tokio = { version = "1.17.0", default-features = false, features = ["macros"] }

[build-dependencies]
Expand Down
6 changes: 5 additions & 1 deletion geozero/src/lib.rs
Expand Up @@ -78,7 +78,11 @@ pub mod gpkg;
#[cfg(feature = "with-gpx")]
pub mod gpx;

#[cfg(any(feature = "with-postgis-postgres", feature = "with-postgis-sqlx"))]
#[cfg(any(
feature = "with-postgis-postgres",
feature = "with-postgis-sqlx",
feature = "with-postgis-diesel"
))]
pub mod postgis;

#[cfg(feature = "with-svg")]
Expand Down
66 changes: 66 additions & 0 deletions geozero/src/postgis/mod.rs
Expand Up @@ -3,6 +3,8 @@
//! All geometry types implementing [GeozeroGeometry](crate::GeozeroGeometry) can be encoded as PostGIS EWKB geometry using [wkb::Encode](crate::wkb::Encode).
//!
//! Geometry types implementing [FromWkb](crate::wkb::FromWkb) can be decoded from PostGIS geometries using [wkb::Decode](crate::wkb::Decode).
#[cfg(feature = "with-postgis-diesel")]
mod postgis_diesel;
#[cfg(feature = "with-postgis-postgres")]
mod postgis_postgres;
#[cfg(feature = "with-postgis-sqlx")]
Expand Down Expand Up @@ -89,3 +91,67 @@ pub mod postgres {
pub mod sqlx {
pub use super::postgis_sqlx::*;
}

/// Postgis geometry type encoding for Diesel.
///
/// # PostGIS usage example with Diesel
///
/// Declare model and select Ewkb types directly with GeoZero and Diesel
///
/// ```
/// use diesel::pg::PgConnection;
/// use diesel::{Connection, QueryDsl, RunQueryDsl};
/// use diesel::prelude::*;
///
/// use geozero::wkb::Ewkb;
///
/// diesel::table! {
/// use diesel::sql_types::*;
/// use geozero::postgis::diesel::sql_types::*;
///
/// geometries (name) {
/// name -> Varchar,
/// geom -> Nullable<Geometry>,
/// }
/// }
///
/// #[derive(Queryable, Debug, Insertable)]
/// #[diesel(table_name = geometries)]
/// pub struct Geom {
/// pub name: String,
/// pub geom: Option<Ewkb>,
/// }
///
/// pub fn establish_connection() -> PgConnection {
/// let database_url = std::env::var("DATABASE_URL").expect("Unable to find database url.");
/// PgConnection::establish(&database_url).unwrap()
/// }
///
/// # async fn rust_geo_query() -> Result<(), diesel::result::Error> {
/// let conn = &mut establish_connection();
///
/// let wkb = Ewkb(vec![
/// 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 64, 0, 0, 0, 0, 0, 0, 52, 192,
/// ]);
///
/// let insert_geometry = Geom {
/// name: "GeoZeroTest".to_string(),
/// geom: Some(wkb),
/// };
///
/// let inserted: Geom = diesel::insert_into(geometries::table)
/// .values(&insert_geometry)
/// .get_result(conn)
/// .expect("Unable to insert into postgis");
///
/// let geometry_vec: Vec<Geom> = geometries::dsl::geometries
/// .limit(10)
/// .load::<Geom>(conn)
/// .expect("Error loading geometries");
/// # Ok(())
/// # }
/// ```
#[cfg(feature = "with-postgis-diesel")]
pub mod diesel {
pub use super::postgis_diesel::*;
}
51 changes: 51 additions & 0 deletions geozero/src/postgis/postgis_diesel.rs
@@ -0,0 +1,51 @@
use crate::postgis::postgis_diesel::sql_types::*;
use crate::wkb::Ewkb;

use byteorder::WriteBytesExt;

use diesel::deserialize::{self, FromSql};
use diesel::pg::{self, Pg};
use diesel::serialize::{self, IsNull, Output, ToSql};

pub mod sql_types {
use diesel::query_builder::QueryId;
use diesel::sql_types::SqlType;

#[derive(SqlType, QueryId)]
#[diesel(postgres_type(name = "geometry"))]
pub struct Geometry;

#[derive(SqlType, QueryId)]
#[diesel(postgres_type(name = "geography"))]
pub struct Geography;
}

impl ToSql<Geometry, Pg> for Ewkb {
fn to_sql(&self, out: &mut Output<Pg>) -> serialize::Result {
for ewkb_byte in &self.0 {
out.write_u8(*ewkb_byte)?;
}
Ok(IsNull::No)
}
}

impl ToSql<Geography, Pg> for Ewkb {
fn to_sql(&self, out: &mut Output<Pg>) -> serialize::Result {
for ewkb_byte in &self.0 {
out.write_u8(*ewkb_byte)?;
}
Ok(IsNull::No)
}
}

impl FromSql<Geometry, Pg> for Ewkb {
fn from_sql(bytes: pg::PgValue) -> deserialize::Result<Self> {
Ok(Self(bytes.as_bytes().to_vec()))
}
}

impl FromSql<Geography, Pg> for Ewkb {
fn from_sql(bytes: pg::PgValue) -> deserialize::Result<Self> {
Ok(Self(bytes.as_bytes().to_vec()))
}
}
11 changes: 11 additions & 0 deletions geozero/src/wkb/wkb_reader.rs
Expand Up @@ -4,6 +4,11 @@ use crate::{GeomProcessor, GeozeroGeometry};
use scroll::IOread;
use std::io::Read;

#[cfg(feature = "with-postgis-diesel")]
use crate::postgis::diesel::sql_types::{Geography, Geometry};
#[cfg(feature = "with-postgis-diesel")]
use diesel::expression::AsExpression;

/// WKB reader.
pub struct Wkb(pub Vec<u8>);

Expand All @@ -14,6 +19,12 @@ impl GeozeroGeometry for Wkb {
}

/// EWKB reader.
#[cfg_attr(
feature = "with-postgis-diesel",
derive(Debug, AsExpression, PartialEq)
)]
#[cfg_attr(feature = "with-postgis-diesel", diesel(sql_type = Geometry))]
#[cfg_attr(feature = "with-postgis-diesel", diesel(sql_type = Geography))]
pub struct Ewkb(pub Vec<u8>);

impl GeozeroGeometry for Ewkb {
Expand Down

0 comments on commit bcc1c3a

Please sign in to comment.