1313// limitations under the License.
1414
1515use super :: bindings;
16+ use chrono:: { Datelike , Duration , NaiveDate , NaiveDateTime , NaiveTime , Timelike } ;
1617use std:: collections:: HashMap ;
18+ use std:: convert:: TryFrom ;
1719use std:: ffi:: { CStr , CString } ;
1820use std:: fmt;
1921use std:: fmt:: Formatter ;
20-
22+ use std :: num :: TryFromIntError ;
2123use std:: slice;
2224
2325/// Representation of parameter value used in query.
@@ -27,6 +29,10 @@ pub enum QueryParam {
2729 Int ( i64 ) ,
2830 Float ( f64 ) ,
2931 String ( String ) ,
32+ Date ( NaiveDate ) ,
33+ LocalTime ( NaiveTime ) ,
34+ LocalDateTime ( NaiveDateTime ) ,
35+ Duration ( Duration ) ,
3036 List ( Vec < QueryParam > ) ,
3137 Map ( HashMap < String , QueryParam > ) ,
3238}
@@ -43,6 +49,16 @@ impl QueryParam {
4349 QueryParam :: Int ( x) => bindings:: mg_value_make_integer ( * x) ,
4450 QueryParam :: Float ( x) => bindings:: mg_value_make_float ( * x) ,
4551 QueryParam :: String ( x) => bindings:: mg_value_make_string ( str_to_c_str ( x. as_str ( ) ) ) ,
52+ QueryParam :: Date ( x) => bindings:: mg_value_make_date ( naive_date_to_mg_date ( x) ) ,
53+ QueryParam :: LocalTime ( x) => {
54+ bindings:: mg_value_make_local_time ( naive_local_time_to_mg_local_time ( x) )
55+ }
56+ QueryParam :: LocalDateTime ( x) => bindings:: mg_value_make_local_date_time (
57+ naive_local_date_time_to_mg_local_date_time ( x) ,
58+ ) ,
59+ QueryParam :: Duration ( x) => {
60+ bindings:: mg_value_make_duration ( duration_to_mg_duration ( x) )
61+ }
4662 QueryParam :: List ( x) => bindings:: mg_value_make_list ( vector_to_mg_list ( x) ) ,
4763 QueryParam :: Map ( x) => bindings:: mg_value_make_map ( hash_map_to_mg_map ( x) ) ,
4864 }
@@ -114,6 +130,10 @@ pub enum Value {
114130 Float ( f64 ) ,
115131 String ( String ) ,
116132 List ( Vec < Value > ) ,
133+ Date ( NaiveDate ) ,
134+ LocalTime ( NaiveTime ) ,
135+ LocalDateTime ( NaiveDateTime ) ,
136+ Duration ( Duration ) ,
117137 Map ( HashMap < String , Value > ) ,
118138 Node ( Node ) ,
119139 Relationship ( Relationship ) ,
@@ -167,6 +187,59 @@ pub(crate) fn mg_value_string(mg_value: *const bindings::mg_value) -> String {
167187 mg_string_to_string ( c_str)
168188}
169189
190+ fn days_as_seconds ( days : i64 ) -> i64 {
191+ hours_as_seconds ( days * 24 )
192+ }
193+
194+ fn hours_as_seconds ( hours : i64 ) -> i64 {
195+ minutes_as_seconds ( hours * 60 )
196+ }
197+
198+ fn minutes_as_seconds ( minutes : i64 ) -> i64 {
199+ minutes * 60
200+ }
201+
202+ const NSEC_IN_SEC : i64 = 1_000_000_000 ;
203+
204+ pub ( crate ) fn mg_value_naive_date ( mg_value : * const bindings:: mg_value ) -> Result < NaiveDate , ( ) > {
205+ let c_date = unsafe { bindings:: mg_value_date ( mg_value) } ;
206+ let c_delta_days = unsafe { bindings:: mg_date_days ( c_date) } ;
207+ let epoch_date = NaiveDate :: from_ymd ( 1970 , 1 , 1 ) ;
208+ let delta_days = Duration :: days ( c_delta_days) ;
209+ Ok ( epoch_date. checked_add_signed ( delta_days) . unwrap ( ) )
210+ }
211+
212+ pub ( crate ) fn mg_value_naive_local_time (
213+ mg_value : * const bindings:: mg_value ,
214+ ) -> Result < NaiveTime , TryFromIntError > {
215+ let c_local_time = unsafe { bindings:: mg_value_local_time ( mg_value) } ;
216+ let c_nanoseconds = unsafe { bindings:: mg_local_time_nanoseconds ( c_local_time) } ;
217+ let seconds = u32:: try_from ( c_nanoseconds / NSEC_IN_SEC ) ?;
218+ let nanoseconds = u32:: try_from ( c_nanoseconds % NSEC_IN_SEC ) ?;
219+ Ok ( NaiveTime :: from_num_seconds_from_midnight (
220+ seconds,
221+ nanoseconds,
222+ ) )
223+ }
224+
225+ pub ( crate ) fn mg_value_naive_local_date_time (
226+ mg_value : * const bindings:: mg_value ,
227+ ) -> Result < NaiveDateTime , TryFromIntError > {
228+ let c_local_date_time = unsafe { bindings:: mg_value_local_date_time ( mg_value) } ;
229+ let c_seconds = unsafe { bindings:: mg_local_date_time_seconds ( c_local_date_time) } ;
230+ let c_nanoseconds = unsafe { bindings:: mg_local_date_time_nanoseconds ( c_local_date_time) } ;
231+ let nanoseconds = u32:: try_from ( c_nanoseconds) ?;
232+ Ok ( NaiveDateTime :: from_timestamp ( c_seconds, nanoseconds) )
233+ }
234+
235+ pub ( crate ) fn mg_value_duration ( mg_value : * const bindings:: mg_value ) -> Duration {
236+ let c_duration = unsafe { bindings:: mg_value_duration ( mg_value) } ;
237+ let days = unsafe { bindings:: mg_duration_days ( c_duration) } ;
238+ let seconds = unsafe { bindings:: mg_duration_seconds ( c_duration) } ;
239+ let nanoseconds = unsafe { bindings:: mg_duration_nanoseconds ( c_duration) } ;
240+ Duration :: days ( days) + Duration :: seconds ( seconds) + Duration :: nanoseconds ( nanoseconds)
241+ }
242+
170243pub ( crate ) fn mg_map_to_hash_map ( mg_map : * const bindings:: mg_map ) -> HashMap < String , Value > {
171244 unsafe {
172245 let size = bindings:: mg_map_size ( mg_map) ;
@@ -318,6 +391,47 @@ pub(crate) fn str_to_c_str(string: &str) -> *const std::os::raw::c_char {
318391 unsafe { ( * c_str) . as_ptr ( ) }
319392}
320393
394+ pub ( crate ) fn naive_date_to_mg_date ( input : & NaiveDate ) -> * mut bindings:: mg_date {
395+ let unix_epoch = NaiveDate :: from_ymd ( 1970 , 1 , 1 ) . num_days_from_ce ( ) ;
396+ unsafe { bindings:: mg_date_make ( ( input. num_days_from_ce ( ) - unix_epoch) as i64 ) }
397+ }
398+
399+ pub ( crate ) fn naive_local_time_to_mg_local_time ( input : & NaiveTime ) -> * mut bindings:: mg_local_time {
400+ let hours_ns = hours_as_seconds ( input. hour ( ) as i64 ) * NSEC_IN_SEC ;
401+ let minutes_ns = minutes_as_seconds ( input. minute ( ) as i64 ) * NSEC_IN_SEC ;
402+ let seconds_ns = ( input. second ( ) as i64 ) * NSEC_IN_SEC ;
403+ let nanoseconds = input. nanosecond ( ) as i64 ;
404+ unsafe { bindings:: mg_local_time_make ( hours_ns + minutes_ns + seconds_ns + nanoseconds) }
405+ }
406+
407+ pub ( crate ) fn naive_local_date_time_to_mg_local_date_time (
408+ input : & NaiveDateTime ,
409+ ) -> * mut bindings:: mg_local_date_time {
410+ let unix_epoch = NaiveDate :: from_ymd ( 1970 , 1 , 1 ) . num_days_from_ce ( ) ;
411+ let days_s = days_as_seconds ( ( input. num_days_from_ce ( ) - unix_epoch) as i64 ) ;
412+ let hours_s = hours_as_seconds ( input. hour ( ) as i64 ) ;
413+ let minutes_s = minutes_as_seconds ( input. minute ( ) as i64 ) ;
414+ let seconds_s = input. second ( ) as i64 ;
415+ let nanoseconds = input. nanosecond ( ) as i64 ;
416+ unsafe {
417+ bindings:: mg_local_date_time_make ( days_s + hours_s + minutes_s + seconds_s, nanoseconds)
418+ }
419+ }
420+
421+ pub ( crate ) fn duration_to_mg_duration ( input : & Duration ) -> * mut bindings:: mg_duration {
422+ // Duration returns total number of nanoseconds, in order to create a valid mg_duration object,
423+ // days and seconds have to be reducted from the total duration. In addition, one can get numer
424+ // of nanoseconds and then substract days and seconds, but since nanoseconds can overflow quite
425+ // quicky (with 292 years), it's better to use Duration and first reduce days and seconds.
426+ let mut duration = * input;
427+ let days = input. num_days ( ) ;
428+ duration = duration - Duration :: days ( days) ;
429+ let seconds = input. num_seconds ( ) ;
430+ duration = duration - Duration :: seconds ( seconds) ;
431+ let nanoseconds = duration. num_nanoseconds ( ) . unwrap ( ) ;
432+ unsafe { bindings:: mg_duration_make ( 0 , days, seconds, nanoseconds) }
433+ }
434+
321435pub ( crate ) fn vector_to_mg_list ( vector : & [ QueryParam ] ) -> * mut bindings:: mg_list {
322436 let size = vector. len ( ) as u32 ;
323437 let mg_list = unsafe { bindings:: mg_list_make_empty ( size) } ;
@@ -339,6 +453,18 @@ impl Value {
339453 bindings:: mg_value_type_MG_VALUE_TYPE_STRING => {
340454 Value :: String ( mg_value_string ( c_mg_value) )
341455 }
456+ bindings:: mg_value_type_MG_VALUE_TYPE_DATE => {
457+ Value :: Date ( mg_value_naive_date ( c_mg_value) . unwrap ( ) )
458+ }
459+ bindings:: mg_value_type_MG_VALUE_TYPE_LOCAL_TIME => {
460+ Value :: LocalTime ( mg_value_naive_local_time ( c_mg_value) . unwrap ( ) )
461+ }
462+ bindings:: mg_value_type_MG_VALUE_TYPE_LOCAL_DATE_TIME => {
463+ Value :: LocalDateTime ( mg_value_naive_local_date_time ( c_mg_value) . unwrap ( ) )
464+ }
465+ bindings:: mg_value_type_MG_VALUE_TYPE_DURATION => {
466+ Value :: Duration ( mg_value_duration ( c_mg_value) )
467+ }
342468 bindings:: mg_value_type_MG_VALUE_TYPE_LIST => {
343469 Value :: List ( mg_value_list_to_vec ( c_mg_value) )
344470 }
@@ -365,6 +491,10 @@ impl fmt::Display for Value {
365491 Value :: Int ( x) => write ! ( f, "{}" , x) ,
366492 Value :: Float ( x) => write ! ( f, "{}" , x) ,
367493 Value :: String ( x) => write ! ( f, "'{}'" , x) ,
494+ Value :: Date ( x) => write ! ( f, "'{}'" , x) ,
495+ Value :: LocalTime ( x) => write ! ( f, "'{}'" , x) ,
496+ Value :: LocalDateTime ( x) => write ! ( f, "'{}'" , x) ,
497+ Value :: Duration ( x) => write ! ( f, "'{}'" , x) ,
368498 Value :: List ( x) => write ! (
369499 f,
370500 "{}" ,
0 commit comments