diff --git a/Cargo.toml b/Cargo.toml index 8d6634b..cf4a946 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,7 +26,7 @@ serde_json = "1.0.57" [build-dependencies] bindgen = "0.68.1" -cmake = "0.1.45" +cmake = "0.1.51" [dev-dependencies.cargo-husky] version = "1" diff --git a/src/main.rs b/src/main.rs index 85c5199..2afd9c8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,6 @@ -use rsmgclient::{ConnectParams, Connection, MgError, Value}; +use std::collections::HashMap; + +use rsmgclient::{ConnectParams, Connection, MgError, Point2D, QueryParam, Value}; fn execute_query() -> Result<(), MgError> { // Connect to Memgraph. @@ -29,6 +31,22 @@ fn execute_query() -> Result<(), MgError> { } connection.commit()?; + let mut query_params: HashMap = HashMap::new(); + query_params.insert( + "point2d".to_string(), + QueryParam::Point2D(Point2D { + srid: 7203, + x_longitude: 0.0, + y_latitude: 1.0, + }), + ); + connection.execute("RETURN $point2d;", Some(&query_params))?; + for record in connection.fetchall()? { + for value in record.values { + println!("{}", value); + } + } + Ok(()) } diff --git a/src/value/mod.rs b/src/value/mod.rs index d016822..2c54bb4 100644 --- a/src/value/mod.rs +++ b/src/value/mod.rs @@ -23,6 +23,43 @@ use std::num::TryFromIntError; use std::os::raw::c_char; use std::slice; +/// Representation of Point2D spatial data type. +#[derive(Debug, PartialEq, Clone)] +pub struct Point2D { + pub srid: u16, + pub x_longitude: f64, + pub y_latitude: f64, +} + +impl fmt::Display for Point2D { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "Point2D({{ srid:{}, x:{}, y:{} }})", + self.srid, self.x_longitude, self.y_latitude + ) + } +} + +/// Representation of Point3D spatial data type. +#[derive(Debug, PartialEq, Clone)] +pub struct Point3D { + pub srid: u16, + pub x_longitude: f64, + pub y_latitude: f64, + pub z_height: f64, +} + +impl fmt::Display for Point3D { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "Point2D({{ srid:{}, x:{}, y:{}, z:{} }})", + self.srid, self.x_longitude, self.y_latitude, self.z_height + ) + } +} + /// Representation of parameter value used in query. pub enum QueryParam { Null, @@ -34,6 +71,8 @@ pub enum QueryParam { LocalTime(NaiveTime), LocalDateTime(NaiveDateTime), Duration(Duration), + Point2D(Point2D), + Point3D(Point3D), List(Vec), Map(HashMap), } @@ -60,6 +99,12 @@ impl QueryParam { QueryParam::Duration(x) => { bindings::mg_value_make_duration(duration_to_mg_duration(x)) } + QueryParam::Point2D(x) => { + bindings::mg_value_make_point_2d(point2d_to_mg_point_2d(x)) + } + QueryParam::Point3D(x) => { + bindings::mg_value_make_point_3d(point3d_to_mg_point_3d(x)) + } QueryParam::List(x) => bindings::mg_value_make_list(vector_to_mg_list(x)), QueryParam::Map(x) => bindings::mg_value_make_map(hash_map_to_mg_map(x)), } @@ -152,6 +197,8 @@ pub enum Value { LocalDateTime(NaiveDateTime), DateTime(DateTime), Duration(Duration), + Point2D(Point2D), + Point3D(Point3D), Map(HashMap), Node(Node), Relationship(Relationship), @@ -300,6 +347,32 @@ pub(crate) fn mg_value_duration(mg_value: *const bindings::mg_value) -> Duration Duration::days(days) + Duration::seconds(seconds) + Duration::nanoseconds(nanoseconds) } +pub(crate) fn mg_value_point2d(mg_value: *const bindings::mg_value) -> Point2D { + let c_point2d = unsafe { bindings::mg_value_point_2d(mg_value) }; + let srid = unsafe { bindings::mg_point_2d_srid(c_point2d) } as u16; + let x_longitude = unsafe { bindings::mg_point_2d_x(c_point2d) }; + let y_latitude = unsafe { bindings::mg_point_2d_y(c_point2d) }; + Point2D { + srid, + x_longitude, + y_latitude, + } +} + +pub(crate) fn mg_value_point3d(mg_value: *const bindings::mg_value) -> Point3D { + let c_point3d = unsafe { bindings::mg_value_point_3d(mg_value) }; + let srid = unsafe { bindings::mg_point_3d_srid(c_point3d) } as u16; + let x_longitude = unsafe { bindings::mg_point_3d_x(c_point3d) }; + let y_latitude = unsafe { bindings::mg_point_3d_y(c_point3d) }; + let z_height = unsafe { bindings::mg_point_3d_z(c_point3d) }; + Point3D { + srid, + x_longitude, + y_latitude, + z_height, + } +} + pub(crate) fn mg_map_to_hash_map(mg_map: *const bindings::mg_map) -> HashMap { unsafe { let size = bindings::mg_map_size(mg_map); @@ -492,6 +565,21 @@ pub(crate) fn duration_to_mg_duration(input: &Duration) -> *mut bindings::mg_dur unsafe { bindings::mg_duration_make(0, days, seconds, nanoseconds) } } +pub(crate) fn point2d_to_mg_point_2d(input: &Point2D) -> *mut bindings::mg_point_2d { + unsafe { bindings::mg_point_2d_make(input.srid, input.x_longitude, input.y_latitude) } +} + +pub(crate) fn point3d_to_mg_point_3d(input: &Point3D) -> *mut bindings::mg_point_3d { + unsafe { + bindings::mg_point_3d_make( + input.srid, + input.x_longitude, + input.y_latitude, + input.z_height, + ) + } +} + pub(crate) fn vector_to_mg_list(vector: &[QueryParam]) -> *mut bindings::mg_list { let size = vector.len() as u32; let mg_list = unsafe { bindings::mg_list_make_empty(size) }; @@ -530,6 +618,12 @@ impl Value { bindings::mg_value_type_MG_VALUE_TYPE_DURATION => { Value::Duration(mg_value_duration(c_mg_value)) } + bindings::mg_value_type_MG_VALUE_TYPE_POINT_2D => { + Value::Point2D(mg_value_point2d(c_mg_value)) + } + bindings::mg_value_type_MG_VALUE_TYPE_POINT_3D => { + Value::Point3D(mg_value_point3d(c_mg_value)) + } bindings::mg_value_type_MG_VALUE_TYPE_LIST => { Value::List(mg_value_list_to_vec(c_mg_value)) } @@ -581,6 +675,8 @@ impl fmt::Display for Value { ) ), Value::Duration(x) => write!(f, "'{}'", x), + Value::Point2D(x) => write!(f, "'{}'", x), + Value::Point3D(x) => write!(f, "'{}'", x), Value::List(x) => write!( f, "{}", diff --git a/src/value/tests.rs b/src/value/tests.rs index a90b7ae..a93827e 100644 --- a/src/value/tests.rs +++ b/src/value/tests.rs @@ -74,6 +74,8 @@ fn mg_value_to_c_mg_value(mg_value: &Value) -> *mut bindings::mg_value { bindings::mg_value_make_null() } Value::Duration(x) => bindings::mg_value_make_duration(duration_to_mg_duration(x)), + Value::Point2D(x) => bindings::mg_value_make_point_2d(point2d_to_mg_point_2d(x)), + Value::Point3D(x) => bindings::mg_value_make_point_3d(point3d_to_mg_point_3d(x)), Value::List(x) => { bindings::mg_value_make_list(bindings::mg_list_copy(vector_to_mg_list(x))) } @@ -364,6 +366,53 @@ fn from_c_mg_value_duration() { assert_eq!(format!("{}", mg_value), "'PT864100.000001S'"); } +#[test] +fn from_c_mg_value_point_2d() { + let c_point2d = bindings::mg_point_2d { + srid: 0, + x: 1.0, + y: 2.0, + }; + let c_mg_value = + unsafe { bindings::mg_value_make_point_2d(bindings::mg_point_2d_copy(&c_point2d)) }; + let mg_value = unsafe { Value::from_mg_value(c_mg_value) }; + assert_eq!( + Value::Point2D(Point2D { + srid: 0, + x_longitude: 1.0, + y_latitude: 2.0 + }), + mg_value + ); + assert_eq!(format!("{}", mg_value), "'Point2D({ srid:0, x:1, y:2 })'"); +} + +#[test] +fn from_c_mg_value_point_3d() { + let c_point3d = bindings::mg_point_3d { + srid: 0, + x: 1.0, + y: 2.0, + z: 3.0, + }; + let c_mg_value = + unsafe { bindings::mg_value_make_point_3d(bindings::mg_point_3d_copy(&c_point3d)) }; + let mg_value = unsafe { Value::from_mg_value(c_mg_value) }; + assert_eq!( + Value::Point3D(Point3D { + srid: 0, + x_longitude: 1.0, + y_latitude: 2.0, + z_height: 3.0 + }), + mg_value + ); + assert_eq!( + format!("{}", mg_value), + "'Point2D({ srid:0, x:1, y:2, z:3 })'" + ); +} + #[test] fn from_c_mg_value_list() { let mg_values = vec![ @@ -866,6 +915,35 @@ fn from_duration_to_mg_value_2() { } } +#[test] +fn from_point2d_to_mg_point_2d() { + let query_param = QueryParam::Point2D(Point2D { + srid: 0, + x_longitude: 1.0, + y_latitude: 2.0, + }); + let c_mg_value = unsafe { *(query_param.to_c_mg_value()) }; + assert_eq!( + c_mg_value.type_, + bindings::mg_value_type_MG_VALUE_TYPE_POINT_2D + ); +} + +#[test] +fn from_point3d_to_mg_point_3d() { + let query_param = QueryParam::Point3D(Point3D { + srid: 0, + x_longitude: 1.0, + y_latitude: 2.0, + z_height: 3.0, + }); + let c_mg_value = unsafe { *(query_param.to_c_mg_value()) }; + assert_eq!( + c_mg_value.type_, + bindings::mg_value_type_MG_VALUE_TYPE_POINT_3D + ); +} + #[test] fn from_to_c_mg_value_list() { let vec: Vec = vec![