tsubakuro_rust_core/service/sql/prepare/
parameter.rs

1use std::sync::atomic::AtomicI64;
2
3#[cfg(feature = "with_chrono")]
4use {chrono::Datelike, chrono::Offset};
5
6#[cfg(any(feature = "with_bigdecimal", feature = "with_rust_decimal"))]
7use crate::jogasaki::proto::sql::common::Decimal as ProtoDecimal;
8#[cfg(any(feature = "with_chrono", feature = "with_time"))]
9use crate::jogasaki::proto::sql::common::{
10    TimeOfDayWithTimeZone as ProtoTimeOfDayWithTimeZone, TimePoint as ProtoTimePoint,
11    TimePointWithTimeZone as ProtoTimePointWithTimeZone,
12};
13use crate::jogasaki::proto::sql::request::parameter::{Placement, Value};
14use crate::prelude::{
15    r#type::large_object::LargeObjectSendPathMapping, TgBlob, TgClob, TgDate, TgDecimal,
16    TgDecimalI128, TgTimeOfDay, TgTimeOfDayWithTimeZone, TgTimePoint, TgTimePointWithTimeZone,
17};
18use crate::tateyama::proto::framework::common::BlobInfo;
19use crate::{error::TgError, jogasaki::proto::sql::request::Parameter as SqlParameter};
20
21impl SqlParameter {
22    fn new(name: &str, value: Option<Value>) -> SqlParameter {
23        let placement = Placement::Name(name.to_string());
24
25        SqlParameter {
26            placement: Some(placement),
27            value,
28        }
29    }
30
31    /// Creates a null parameter.
32    pub fn null(name: &str) -> SqlParameter {
33        SqlParameter::new(name, None)
34    }
35
36    /// Get name.
37    pub fn name(&self) -> Option<&String> {
38        match self.placement {
39            Some(Placement::Name(ref name)) => Some(name),
40            _ => None,
41        }
42    }
43
44    /// Get value.
45    pub fn value(&self) -> Option<&Value> {
46        self.value.as_ref()
47    }
48}
49
50/// `of` method for [SqlParameter].
51pub trait SqlParameterOf<T> {
52    /// Creates a new instance.
53    fn of(name: &str, value: T) -> SqlParameter;
54}
55
56impl SqlParameterOf<bool> for SqlParameter {
57    fn of(name: &str, value: bool) -> SqlParameter {
58        let value = Value::BooleanValue(value);
59        SqlParameter::new(name, Some(value))
60    }
61}
62
63impl SqlParameterOf<i32> for SqlParameter {
64    fn of(name: &str, value: i32) -> SqlParameter {
65        let value = Value::Int4Value(value);
66        SqlParameter::new(name, Some(value))
67    }
68}
69
70impl SqlParameterOf<i64> for SqlParameter {
71    fn of(name: &str, value: i64) -> SqlParameter {
72        let value = Value::Int8Value(value);
73        SqlParameter::new(name, Some(value))
74    }
75}
76
77impl SqlParameterOf<f32> for SqlParameter {
78    fn of(name: &str, value: f32) -> SqlParameter {
79        let value = Value::Float4Value(value);
80        SqlParameter::new(name, Some(value))
81    }
82}
83
84impl SqlParameterOf<f64> for SqlParameter {
85    fn of(name: &str, value: f64) -> SqlParameter {
86        let value = Value::Float8Value(value);
87        SqlParameter::new(name, Some(value))
88    }
89}
90
91impl SqlParameterOf<TgDecimal> for SqlParameter {
92    fn of(name: &str, value: TgDecimal) -> SqlParameter {
93        let value = Value::DecimalValue(value);
94        SqlParameter::new(name, Some(value))
95    }
96}
97
98impl SqlParameterOf<TgDecimalI128> for SqlParameter {
99    fn of(name: &str, value: TgDecimalI128) -> SqlParameter {
100        let value = TgDecimal::from(value);
101        Self::of(name, value)
102    }
103}
104
105#[cfg(feature = "with_bigdecimal")]
106impl SqlParameterOf<bigdecimal::BigDecimal> for SqlParameter {
107    fn of(name: &str, value: bigdecimal::BigDecimal) -> SqlParameter {
108        Self::of(name, &value)
109    }
110}
111
112#[cfg(feature = "with_bigdecimal")]
113impl SqlParameterOf<&bigdecimal::BigDecimal> for SqlParameter {
114    fn of(name: &str, value: &bigdecimal::BigDecimal) -> SqlParameter {
115        let (value, scale) = value.as_bigint_and_exponent();
116        let value = ProtoDecimal {
117            unscaled_value: value.to_signed_bytes_be(),
118            exponent: -scale as i32,
119        };
120        let value = Value::DecimalValue(value);
121        SqlParameter::new(name, Some(value))
122    }
123}
124
125#[cfg(feature = "with_rust_decimal")]
126impl SqlParameterOf<rust_decimal::Decimal> for SqlParameter {
127    fn of(name: &str, value: rust_decimal::Decimal) -> SqlParameter {
128        Self::of(name, &value)
129    }
130}
131
132#[cfg(feature = "with_rust_decimal")]
133impl SqlParameterOf<&rust_decimal::Decimal> for SqlParameter {
134    fn of(name: &str, value: &rust_decimal::Decimal) -> SqlParameter {
135        let value = ProtoDecimal {
136            unscaled_value: value.mantissa().to_be_bytes().to_vec(),
137            exponent: -(value.scale() as i32),
138        };
139        let value = Value::DecimalValue(value);
140        SqlParameter::new(name, Some(value))
141    }
142}
143
144impl SqlParameterOf<&str> for SqlParameter {
145    fn of(name: &str, value: &str) -> SqlParameter {
146        let value = Value::CharacterValue(value.to_string());
147        SqlParameter::new(name, Some(value))
148    }
149}
150
151impl SqlParameterOf<String> for SqlParameter {
152    fn of(name: &str, value: String) -> SqlParameter {
153        let value = Value::CharacterValue(value);
154        SqlParameter::new(name, Some(value))
155    }
156}
157
158impl SqlParameterOf<&String> for SqlParameter {
159    fn of(name: &str, value: &String) -> SqlParameter {
160        let value = Value::CharacterValue(value.clone());
161        SqlParameter::new(name, Some(value))
162    }
163}
164
165impl SqlParameterOf<&[u8]> for SqlParameter {
166    fn of(name: &str, value: &[u8]) -> SqlParameter {
167        let value = Value::OctetValue(value.to_vec());
168        SqlParameter::new(name, Some(value))
169    }
170}
171
172impl SqlParameterOf<Vec<u8>> for SqlParameter {
173    fn of(name: &str, value: Vec<u8>) -> SqlParameter {
174        let value = Value::OctetValue(value);
175        SqlParameter::new(name, Some(value))
176    }
177}
178
179impl SqlParameterOf<&Vec<u8>> for SqlParameter {
180    fn of(name: &str, value: &Vec<u8>) -> SqlParameter {
181        let value = Value::OctetValue(value.clone());
182        SqlParameter::new(name, Some(value))
183    }
184}
185
186impl SqlParameterOf<TgDate> for SqlParameter {
187    fn of(name: &str, value: TgDate) -> SqlParameter {
188        let value = Value::DateValue(value.epoch_days);
189        SqlParameter::new(name, Some(value))
190    }
191}
192
193impl SqlParameterOf<TgTimeOfDay> for SqlParameter {
194    fn of(name: &str, value: TgTimeOfDay) -> SqlParameter {
195        let value = Value::TimeOfDayValue(value.offset_nanoseconds);
196        SqlParameter::new(name, Some(value))
197    }
198}
199
200impl SqlParameterOf<TgTimePoint> for SqlParameter {
201    fn of(name: &str, value: TgTimePoint) -> SqlParameter {
202        let value = Value::TimePointValue(value);
203        SqlParameter::new(name, Some(value))
204    }
205}
206
207impl SqlParameterOf<TgTimeOfDayWithTimeZone> for SqlParameter {
208    fn of(name: &str, value: TgTimeOfDayWithTimeZone) -> SqlParameter {
209        let value = Value::TimeOfDayWithTimeZoneValue(value);
210        SqlParameter::new(name, Some(value))
211    }
212}
213
214impl SqlParameterOf<TgTimePointWithTimeZone> for SqlParameter {
215    fn of(name: &str, value: TgTimePointWithTimeZone) -> SqlParameter {
216        let value = Value::TimePointWithTimeZoneValue(value);
217        SqlParameter::new(name, Some(value))
218    }
219}
220
221#[cfg(feature = "with_chrono")]
222impl SqlParameterOf<chrono::NaiveDate> for SqlParameter {
223    fn of(name: &str, value: chrono::NaiveDate) -> SqlParameter {
224        Self::of(name, &value)
225    }
226}
227
228#[cfg(feature = "with_chrono")]
229impl SqlParameterOf<&chrono::NaiveDate> for SqlParameter {
230    fn of(name: &str, value: &chrono::NaiveDate) -> SqlParameter {
231        let days = chrono_naive_date_to_days(value);
232
233        let value = Value::DateValue(days);
234        SqlParameter::new(name, Some(value))
235    }
236}
237
238#[cfg(feature = "with_chrono")]
239fn chrono_naive_date_to_days(value: &chrono::NaiveDate) -> i64 {
240    value.num_days_from_ce() as i64 - /* NaiveDate(1970-01-01).num_days_from_ce() */ 719_163
241}
242
243#[cfg(feature = "with_chrono")]
244impl SqlParameterOf<chrono::NaiveTime> for SqlParameter {
245    fn of(name: &str, value: chrono::NaiveTime) -> SqlParameter {
246        Self::of(name, &value)
247    }
248}
249
250#[cfg(feature = "with_chrono")]
251impl SqlParameterOf<&chrono::NaiveTime> for SqlParameter {
252    fn of(name: &str, value: &chrono::NaiveTime) -> SqlParameter {
253        let (seconds, nanos) = chrono_naive_time_to_seconds(value);
254        let value = seconds * 1_000_000_000 + nanos as u64;
255
256        let value = Value::TimeOfDayValue(value);
257        SqlParameter::new(name, Some(value))
258    }
259}
260
261#[cfg(feature = "with_chrono")]
262fn chrono_naive_time_to_seconds(value: &chrono::NaiveTime) -> (u64, u32) {
263    use chrono::Timelike;
264
265    let seconds = value.num_seconds_from_midnight() as u64;
266    let nanos = value.nanosecond();
267
268    (seconds, nanos)
269}
270
271#[cfg(feature = "with_chrono")]
272impl SqlParameterOf<chrono::NaiveDateTime> for SqlParameter {
273    fn of(name: &str, value: chrono::NaiveDateTime) -> SqlParameter {
274        Self::of(name, &value)
275    }
276}
277
278#[cfg(feature = "with_chrono")]
279impl SqlParameterOf<&chrono::NaiveDateTime> for SqlParameter {
280    fn of(name: &str, value: &chrono::NaiveDateTime) -> SqlParameter {
281        let (seconds, nanos) = chrono_naive_date_time_to_seconds(value);
282
283        let value = ProtoTimePoint {
284            offset_seconds: seconds,
285            nano_adjustment: nanos,
286        };
287        let value = Value::TimePointValue(value);
288        SqlParameter::new(name, Some(value))
289    }
290}
291
292#[cfg(feature = "with_chrono")]
293fn chrono_naive_date_time_to_seconds(value: &chrono::NaiveDateTime) -> (i64, u32) {
294    let days = chrono_naive_date_to_days(&value.date());
295    let (seconds, nanos) = chrono_naive_time_to_seconds(&value.time());
296    let seconds = days * 24 * 60 * 60 + seconds as i64;
297
298    (seconds, nanos)
299}
300
301#[cfg(feature = "with_chrono")]
302impl SqlParameterOf<(chrono::NaiveTime, chrono::FixedOffset)> for SqlParameter {
303    fn of(name: &str, value: (chrono::NaiveTime, chrono::FixedOffset)) -> SqlParameter {
304        Self::of(name, &value)
305    }
306}
307
308#[cfg(feature = "with_chrono")]
309impl SqlParameterOf<&(chrono::NaiveTime, chrono::FixedOffset)> for SqlParameter {
310    fn of(name: &str, value: &(chrono::NaiveTime, chrono::FixedOffset)) -> SqlParameter {
311        let (time, offset) = value;
312
313        let (seconds, nanos) = chrono_naive_time_to_seconds(time);
314        let offset_minutes = chrono_fixed_offset_to_minutes(offset);
315
316        let value = ProtoTimeOfDayWithTimeZone {
317            offset_nanoseconds: seconds * 1_000_000_000 + nanos as u64,
318            time_zone_offset: offset_minutes,
319        };
320        let value = Value::TimeOfDayWithTimeZoneValue(value);
321        SqlParameter::new(name, Some(value))
322    }
323}
324
325#[cfg(feature = "with_chrono")]
326fn chrono_fixed_offset_to_minutes(value: &chrono::FixedOffset) -> i32 {
327    value.local_minus_utc() / 60
328}
329
330#[cfg(feature = "with_chrono")]
331impl<Tz: chrono::TimeZone> SqlParameterOf<chrono::DateTime<Tz>> for SqlParameter {
332    fn of(name: &str, value: chrono::DateTime<Tz>) -> SqlParameter {
333        Self::of(name, &value)
334    }
335}
336
337#[cfg(feature = "with_chrono")]
338impl<Tz: chrono::TimeZone> SqlParameterOf<&chrono::DateTime<Tz>> for SqlParameter {
339    fn of(name: &str, value: &chrono::DateTime<Tz>) -> SqlParameter {
340        let (seconds, nanos) = chrono_naive_date_time_to_seconds(&value.naive_local());
341        let offset_minutes = chrono_fixed_offset_to_minutes(&value.offset().fix());
342
343        let value = ProtoTimePointWithTimeZone {
344            offset_seconds: seconds,
345            nano_adjustment: nanos,
346            time_zone_offset: offset_minutes,
347        };
348        let value = Value::TimePointWithTimeZoneValue(value);
349        SqlParameter::new(name, Some(value))
350    }
351}
352
353#[cfg(feature = "with_time")]
354impl SqlParameterOf<time::Date> for SqlParameter {
355    fn of(name: &str, value: time::Date) -> SqlParameter {
356        Self::of(name, &value)
357    }
358}
359
360#[cfg(feature = "with_time")]
361impl SqlParameterOf<&time::Date> for SqlParameter {
362    fn of(name: &str, value: &time::Date) -> SqlParameter {
363        let days = time_date_to_days(value);
364
365        let value = Value::DateValue(days);
366        SqlParameter::new(name, Some(value))
367    }
368}
369
370// #[cfg(feature = "with_time")]
371// const TIME_EPOCH_START_DATE: Result<time::Date, time::error::ComponentRange> =
372//     time::Date::from_ordinal_date(1970, 1);
373
374#[cfg(feature = "with_time")]
375fn time_date_to_days(value: &time::Date) -> i64 {
376    // let days = *value - TIME_EPOCH_START_DATE.unwrap();
377    // let days = days.whole_days();
378    value.to_julian_day() as i64 - /* Date(1970-01-01).to_julian_day() */ 2440588
379}
380
381#[cfg(feature = "with_time")]
382impl SqlParameterOf<time::Time> for SqlParameter {
383    fn of(name: &str, value: time::Time) -> SqlParameter {
384        Self::of(name, &value)
385    }
386}
387
388#[cfg(feature = "with_time")]
389impl SqlParameterOf<&time::Time> for SqlParameter {
390    fn of(name: &str, value: &time::Time) -> SqlParameter {
391        let (seconds, nanos) = time_time_to_seconds(value);
392        let value = seconds * 1_000_000_000 + nanos as u64;
393
394        let value = Value::TimeOfDayValue(value);
395        SqlParameter::new(name, Some(value))
396    }
397}
398
399#[cfg(feature = "with_time")]
400fn time_time_to_seconds(value: &time::Time) -> (u64, u32) {
401    let (hour, min, sec, nanos) = value.as_hms_nano();
402    let seconds = ((hour as u64) * 60 + min as u64) * 60 + sec as u64;
403
404    (seconds, nanos)
405}
406
407#[cfg(feature = "with_time")]
408impl SqlParameterOf<time::PrimitiveDateTime> for SqlParameter {
409    fn of(name: &str, value: time::PrimitiveDateTime) -> SqlParameter {
410        Self::of(name, &value)
411    }
412}
413
414#[cfg(feature = "with_time")]
415impl SqlParameterOf<&time::PrimitiveDateTime> for SqlParameter {
416    fn of(name: &str, value: &time::PrimitiveDateTime) -> SqlParameter {
417        let (seconds, nanos) = time_date_time_to_seconds(&value.date(), &value.time());
418
419        let value = ProtoTimePoint {
420            offset_seconds: seconds,
421            nano_adjustment: nanos,
422        };
423        let value = Value::TimePointValue(value);
424        SqlParameter::new(name, Some(value))
425    }
426}
427
428#[cfg(feature = "with_time")]
429fn time_date_time_to_seconds(date: &time::Date, time: &time::Time) -> (i64, u32) {
430    let days = time_date_to_days(date);
431    let (seconds, nanos) = time_time_to_seconds(time);
432    let seconds = days * 24 * 60 * 60 + seconds as i64;
433
434    (seconds, nanos)
435}
436
437#[cfg(feature = "with_time")]
438impl SqlParameterOf<(time::Time, time::UtcOffset)> for SqlParameter {
439    fn of(name: &str, value: (time::Time, time::UtcOffset)) -> SqlParameter {
440        Self::of(name, &value)
441    }
442}
443
444#[cfg(feature = "with_time")]
445impl SqlParameterOf<&(time::Time, time::UtcOffset)> for SqlParameter {
446    fn of(name: &str, value: &(time::Time, time::UtcOffset)) -> SqlParameter {
447        let (time, offset) = value;
448
449        let (seconds, nanos) = time_time_to_seconds(time);
450        let offset_minutes = time_utc_offset_to_minutes(offset);
451
452        let value = ProtoTimeOfDayWithTimeZone {
453            offset_nanoseconds: seconds * 1_000_000_000 + nanos as u64,
454            time_zone_offset: offset_minutes,
455        };
456        let value = Value::TimeOfDayWithTimeZoneValue(value);
457        SqlParameter::new(name, Some(value))
458    }
459}
460
461#[cfg(feature = "with_time")]
462fn time_utc_offset_to_minutes(offset: &time::UtcOffset) -> i32 {
463    let (hour, min, _sec) = offset.as_hms();
464    hour as i32 * 60 + min as i32
465}
466
467#[cfg(feature = "with_time")]
468impl SqlParameterOf<time::OffsetDateTime> for SqlParameter {
469    fn of(name: &str, value: time::OffsetDateTime) -> SqlParameter {
470        Self::of(name, &value)
471    }
472}
473
474#[cfg(feature = "with_time")]
475impl SqlParameterOf<&time::OffsetDateTime> for SqlParameter {
476    fn of(name: &str, value: &time::OffsetDateTime) -> SqlParameter {
477        let (seconds, nanos) = time_date_time_to_seconds(&value.date(), &value.time());
478        let offset_minutes = time_utc_offset_to_minutes(&value.offset());
479
480        let value = ProtoTimePointWithTimeZone {
481            offset_seconds: seconds,
482            nano_adjustment: nanos,
483            time_zone_offset: offset_minutes,
484        };
485        let value = Value::TimePointWithTimeZoneValue(value);
486        SqlParameter::new(name, Some(value))
487    }
488}
489
490impl SqlParameterOf<TgBlob> for SqlParameter {
491    fn of(name: &str, value: TgBlob) -> SqlParameter {
492        use crate::jogasaki::proto::sql::common::blob::Data;
493        let data = match value {
494            TgBlob::Path(path) => Data::LocalPath(path),
495            TgBlob::Contents(value) => Data::Contents(value),
496        };
497        let value = crate::jogasaki::proto::sql::common::Blob { data: Some(data) };
498        let value = Value::Blob(value);
499        SqlParameter::new(name, Some(value))
500    }
501}
502
503impl SqlParameterOf<TgClob> for SqlParameter {
504    fn of(name: &str, value: TgClob) -> SqlParameter {
505        use crate::jogasaki::proto::sql::common::clob::Data;
506        let data = match value {
507            TgClob::Path(path) => Data::LocalPath(path),
508            TgClob::Contents(value) => Data::Contents(value),
509        };
510        let value = crate::jogasaki::proto::sql::common::Clob { data: Some(data) };
511        let value = Value::Clob(value);
512        SqlParameter::new(name, Some(value))
513    }
514}
515
516impl<T> SqlParameterOf<Option<T>> for SqlParameter
517where
518    SqlParameter: SqlParameterOf<T>,
519{
520    fn of(name: &str, value: Option<T>) -> SqlParameter {
521        match value {
522            Some(value) => SqlParameter::of(name, value),
523            _ => SqlParameter::null(name),
524        }
525    }
526}
527
528/// `parameter` method for [SqlParameter].
529pub trait SqlParameterBind<T> {
530    /// Creates a new instance.
531    fn parameter(&self, value: T) -> SqlParameter;
532}
533
534impl<T> SqlParameterBind<T> for &str
535where
536    SqlParameter: SqlParameterOf<T>,
537{
538    fn parameter(&self, value: T) -> SqlParameter {
539        SqlParameter::of(self, value)
540    }
541}
542
543impl<T> SqlParameterBind<T> for String
544where
545    SqlParameter: SqlParameterOf<T>,
546{
547    fn parameter(&self, value: T) -> SqlParameter {
548        SqlParameter::of(self, value)
549    }
550}
551
552/// `parameter_null` method for [SqlParameter].
553pub trait SqlParameterBindNull {
554    /// Creates a null parameter.
555    fn parameter_null(&self) -> SqlParameter;
556}
557
558impl SqlParameterBindNull for &str {
559    fn parameter_null(&self) -> SqlParameter {
560        SqlParameter::null(self)
561    }
562}
563
564impl SqlParameterBindNull for String {
565    fn parameter_null(&self) -> SqlParameter {
566        SqlParameter::null(self)
567    }
568}
569
570static BLOB_NUMBER: AtomicI64 = AtomicI64::new(0);
571static CLOB_NUMBER: AtomicI64 = AtomicI64::new(0);
572
573pub(crate) fn convert_lob_parameters(
574    parameters: Vec<SqlParameter>,
575    lob_send_path_mapping: &LargeObjectSendPathMapping,
576) -> Result<(Vec<SqlParameter>, Option<Vec<BlobInfo>>), TgError> {
577    use crate::jogasaki::proto::sql::common::blob::Data as BlobData;
578    use crate::jogasaki::proto::sql::common::clob::Data as ClobData;
579    use crate::jogasaki::proto::sql::common::Blob;
580    use crate::jogasaki::proto::sql::common::Clob;
581
582    let mut parameters_result = Vec::with_capacity(parameters.len());
583    let mut lobs = Vec::new();
584    for parameter in parameters {
585        let parameter = match parameter {
586            SqlParameter {
587                placement,
588                value:
589                    Some(Value::Blob(Blob {
590                        data: Some(BlobData::LocalPath(path)),
591                    })),
592            } => {
593                let path = lob_send_path_mapping.contert_to_server_path(&path)?;
594                let channel_name = create_channel_name("Blob", &BLOB_NUMBER);
595                let lob_info = BlobInfo {
596                    channel_name: channel_name.clone(),
597                    path,
598                    temporary: false,
599                };
600                lobs.push(lob_info);
601
602                let data = BlobData::ChannelName(channel_name);
603                let value = Blob { data: Some(data) };
604                let value = Value::Blob(value);
605                SqlParameter {
606                    placement,
607                    value: Some(value),
608                }
609            }
610            SqlParameter {
611                placement,
612                value:
613                    Some(Value::Clob(Clob {
614                        data: Some(ClobData::LocalPath(path)),
615                    })),
616            } => {
617                let path = lob_send_path_mapping.contert_to_server_path(&path)?;
618                let channel_name = create_channel_name("Clob", &CLOB_NUMBER);
619                // not ClobInfo
620                let lob_info = BlobInfo {
621                    channel_name: channel_name.clone(),
622                    path,
623                    temporary: false,
624                };
625                lobs.push(lob_info);
626
627                let data = ClobData::ChannelName(channel_name);
628                let value = Clob { data: Some(data) };
629                let value = Value::Clob(value);
630                SqlParameter {
631                    placement,
632                    value: Some(value),
633                }
634            }
635            parameter => parameter,
636        };
637        parameters_result.push(parameter);
638    }
639
640    if lobs.is_empty() {
641        Ok((parameters_result, None))
642    } else {
643        Ok((parameters_result, Some(lobs)))
644    }
645}
646
647fn create_channel_name(prefix: &str, number: &AtomicI64) -> String {
648    let pid = std::process::id();
649    let n = number.fetch_add(1, std::sync::atomic::Ordering::SeqCst) + 1;
650    format!("Rust{prefix}Channel-{pid}-{n}")
651}
652
653#[cfg(test)]
654mod test {
655    use super::*;
656
657    #[test]
658    fn null() {
659        let target0 = SqlParameter::null("test");
660        assert_eq!("test", target0.name().unwrap());
661        assert_eq!(None, target0.value);
662
663        let target = SqlParameter::of("test", None::<i32>);
664        assert_eq!(target0, target);
665
666        let target = "test".parameter_null();
667        assert_eq!(target0, target);
668
669        let target = "test".to_string().parameter_null();
670        assert_eq!(target0, target);
671    }
672
673    #[test]
674    fn bool() {
675        bool_test(true);
676        bool_test(false);
677    }
678
679    fn bool_test(value: bool) {
680        let target0 = SqlParameter::of("test", value);
681        assert_eq!("test", target0.name().unwrap());
682        assert_eq!(&Value::BooleanValue(value), target0.value().unwrap());
683
684        let target = SqlParameter::of("test", Some(value));
685        assert_eq!(target0, target);
686
687        let target = "test".parameter(value);
688        assert_eq!(target0, target);
689
690        let target = "test".to_string().parameter(value);
691        assert_eq!(target0, target);
692    }
693
694    #[test]
695    fn i32() {
696        let target0 = SqlParameter::of("test", 123);
697        assert_eq!("test", target0.name().unwrap());
698        assert_eq!(&Value::Int4Value(123), target0.value().unwrap());
699
700        let target = SqlParameter::of("test", Some(123));
701        assert_eq!(target0, target);
702
703        let target = "test".parameter(123);
704        assert_eq!(target0, target);
705
706        let target = "test".to_string().parameter(123);
707        assert_eq!(target0, target);
708    }
709
710    #[test]
711    fn i64() {
712        let target0 = SqlParameter::of("test", 123_i64);
713        assert_eq!("test", target0.name().unwrap());
714        assert_eq!(&Value::Int8Value(123), target0.value().unwrap());
715
716        let target = SqlParameter::of("test", Some(123_i64));
717        assert_eq!(target0, target);
718
719        let target = "test".parameter(123_i64);
720        assert_eq!(target0, target);
721
722        let target = "test".to_string().parameter(123_i64);
723        assert_eq!(target0, target);
724    }
725
726    #[test]
727    fn f32() {
728        let target0 = SqlParameter::of("test", 123_f32);
729        assert_eq!("test", target0.name().unwrap());
730        assert_eq!(&Value::Float4Value(123.0), target0.value().unwrap());
731
732        let target = SqlParameter::of("test", Some(123_f32));
733        assert_eq!(target0, target);
734
735        let target = "test".parameter(123_f32);
736        assert_eq!(target0, target);
737
738        let target = "test".to_string().parameter(123_f32);
739        assert_eq!(target0, target);
740    }
741
742    #[test]
743    fn f64() {
744        let target0 = SqlParameter::of("test", 123_f64);
745        assert_eq!("test", target0.name().unwrap());
746        assert_eq!(&Value::Float8Value(123.0), target0.value().unwrap());
747
748        let target = SqlParameter::of("test", Some(123_f64));
749        assert_eq!(target0, target);
750
751        let target = "test".parameter(123_f64);
752        assert_eq!(target0, target);
753
754        let target = "test".to_string().parameter(123_f64);
755        assert_eq!(target0, target);
756    }
757
758    #[test]
759    fn decimal() {
760        let value = TgDecimal::new(vec![4, 0xd2], -1);
761        let target0 = SqlParameter::of("test", value.clone());
762        assert_eq!("test", target0.name().unwrap());
763        assert_eq!(
764            &Value::DecimalValue(ProtoDecimal {
765                unscaled_value: vec![4, 0xd2],
766                exponent: -1
767            }),
768            target0.value().unwrap()
769        );
770
771        let target = SqlParameter::of("test", Some(value.clone()));
772        assert_eq!(target0, target);
773
774        let value = TgDecimalI128::new(1234, -1);
775        let target = SqlParameter::of("test", value.clone());
776        assert_eq!(target0.name(), target.name());
777        assert_eq!(
778            &Value::DecimalValue(ProtoDecimal {
779                unscaled_value: vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0xd2],
780                exponent: -1
781            }),
782            target.value().unwrap()
783        );
784
785        let target1 = SqlParameter::of("test", Some(value.clone()));
786        assert_eq!(target1, target);
787    }
788
789    #[cfg(feature = "with_bigdecimal")]
790    #[test]
791    fn bigdecimal() {
792        use std::str::FromStr;
793
794        let value = bigdecimal::BigDecimal::from_str("123.4").unwrap();
795        let expected = value.as_bigint_and_exponent();
796
797        let target0 = SqlParameter::of("test", value.clone());
798        assert_eq!("test", target0.name().unwrap());
799        assert_eq!(
800            &Value::DecimalValue(ProtoDecimal {
801                unscaled_value: expected.0.to_signed_bytes_be(),
802                exponent: -expected.1 as i32
803            }),
804            target0.value().unwrap()
805        );
806
807        let target = SqlParameter::of("test", Some(value.clone()));
808        assert_eq!(target0, target);
809
810        let target = "test".parameter(value.clone());
811        assert_eq!(target0, target);
812
813        let target = "test".to_string().parameter(value.clone());
814        assert_eq!(target0, target);
815    }
816
817    #[cfg(feature = "with_bigdecimal")]
818    #[test]
819    fn bigdecimal_ref() {
820        use std::str::FromStr;
821
822        let value = bigdecimal::BigDecimal::from_str("123.4").unwrap();
823        let expected = value.as_bigint_and_exponent();
824
825        let target0 = SqlParameter::of("test", &value);
826        assert_eq!("test", target0.name().unwrap());
827        assert_eq!(
828            &Value::DecimalValue(ProtoDecimal {
829                unscaled_value: expected.0.to_signed_bytes_be(),
830                exponent: -expected.1 as i32
831            }),
832            target0.value().unwrap()
833        );
834
835        let target = SqlParameter::of("test", Some(&value));
836        assert_eq!(target0, target);
837
838        let target = "test".parameter(&value);
839        assert_eq!(target0, target);
840
841        let target = "test".to_string().parameter(&value);
842        assert_eq!(target0, target);
843    }
844
845    #[cfg(feature = "with_rust_decimal")]
846    #[test]
847    fn rust_decimal() {
848        use std::str::FromStr;
849
850        let value = rust_decimal::Decimal::from_str("123.4").unwrap();
851
852        let target0 = SqlParameter::of("test", value.clone());
853        assert_eq!("test", target0.name().unwrap());
854        assert_eq!(
855            &Value::DecimalValue(ProtoDecimal {
856                unscaled_value: value.mantissa().to_be_bytes().to_vec(),
857                exponent: -(value.scale() as i32)
858            }),
859            target0.value().unwrap()
860        );
861
862        let target = SqlParameter::of("test", Some(value.clone()));
863        assert_eq!(target0, target);
864
865        let target = "test".parameter(value.clone());
866        assert_eq!(target0, target);
867
868        let target = "test".to_string().parameter(value.clone());
869        assert_eq!(target0, target);
870    }
871
872    #[cfg(feature = "with_rust_decimal")]
873    #[test]
874    fn rust_decimal_ref() {
875        use std::str::FromStr;
876
877        let value = rust_decimal::Decimal::from_str("123.4").unwrap();
878
879        let target0 = SqlParameter::of("test", &value);
880        assert_eq!("test", target0.name().unwrap());
881        assert_eq!(
882            &Value::DecimalValue(ProtoDecimal {
883                unscaled_value: value.mantissa().to_be_bytes().to_vec(),
884                exponent: -(value.scale() as i32)
885            }),
886            target0.value().unwrap()
887        );
888
889        let target = SqlParameter::of("test", Some(&value));
890        assert_eq!(target0, target);
891
892        let target = "test".parameter(&value);
893        assert_eq!(target0, target);
894
895        let target = "test".to_string().parameter(&value);
896        assert_eq!(target0, target);
897    }
898
899    #[test]
900    fn str() {
901        let target0 = SqlParameter::of("test", "abc");
902        assert_eq!("test", target0.name().unwrap());
903        assert_eq!(
904            &Value::CharacterValue("abc".to_string()),
905            target0.value().unwrap()
906        );
907
908        let target = SqlParameter::of("test", Some("abc"));
909        assert_eq!(target0, target);
910
911        let target = "test".parameter("abc");
912        assert_eq!(target0, target);
913
914        let target = "test".to_string().parameter("abc");
915        assert_eq!(target0, target);
916    }
917
918    #[test]
919    fn string() {
920        let target0 = SqlParameter::of("test", "abc".to_string());
921        assert_eq!("test", target0.name().unwrap());
922        assert_eq!(
923            &Value::CharacterValue("abc".to_string()),
924            target0.value().unwrap()
925        );
926
927        let target = SqlParameter::of("test", Some("abc".to_string()));
928        assert_eq!(target0, target);
929
930        let target = "test".parameter("abc".to_string());
931        assert_eq!(target0, target);
932
933        let target = "test".to_string().parameter("abc".to_string());
934        assert_eq!(target0, target);
935    }
936
937    #[test]
938    fn string_ref() {
939        let target0 = SqlParameter::of("test", &"abc".to_string());
940        assert_eq!("test", target0.name().unwrap());
941        assert_eq!(
942            &Value::CharacterValue("abc".to_string()),
943            target0.value().unwrap()
944        );
945
946        let target = SqlParameter::of("test", Some(&"abc".to_string()));
947        assert_eq!(target0, target);
948
949        let target = "test".parameter(&"abc".to_string());
950        assert_eq!(target0, target);
951
952        let target = "test".to_string().parameter(&"abc".to_string());
953        assert_eq!(target0, target);
954    }
955
956    #[test]
957    fn array_u8() {
958        let value = [0x12_u8, 0x34, 0xef].as_slice();
959        let target0 = SqlParameter::of("test", value);
960        assert_eq!("test", target0.name().unwrap());
961        assert_eq!(&Value::OctetValue(value.to_vec()), target0.value().unwrap());
962
963        let target = SqlParameter::of("test", Some(value));
964        assert_eq!(target0, target);
965
966        let target = "test".parameter(value);
967        assert_eq!(target0, target);
968
969        let target = "test".to_string().parameter(value);
970        assert_eq!(target0, target);
971    }
972
973    #[test]
974    fn vec_u8() {
975        let value = vec![0x12_u8, 0x34, 0xef];
976        let target0 = SqlParameter::of("test", value.clone());
977        assert_eq!("test", target0.name().unwrap());
978        assert_eq!(&Value::OctetValue(value.clone()), target0.value().unwrap());
979
980        let target = SqlParameter::of("test", Some(value.clone()));
981        assert_eq!(target0, target);
982
983        let target = "test".parameter(value.clone());
984        assert_eq!(target0, target);
985
986        let target = "test".to_string().parameter(value.clone());
987        assert_eq!(target0, target);
988    }
989
990    #[test]
991    fn vec_u8_ref() {
992        let value = vec![0x12_u8, 0x34, 0xef];
993        let target0 = SqlParameter::of("test", &value);
994        assert_eq!("test", target0.name().unwrap());
995        assert_eq!(&Value::OctetValue(value.clone()), target0.value().unwrap());
996
997        let target = SqlParameter::of("test", Some(&value));
998        assert_eq!(target0, target);
999
1000        let target = "test".parameter(&value);
1001        assert_eq!(target0, target);
1002
1003        let target = "test".to_string().parameter(&value);
1004        assert_eq!(target0, target);
1005    }
1006
1007    #[test]
1008    fn date() {
1009        let value = TgDate::new(20126);
1010        let target0 = SqlParameter::of("test", value);
1011        assert_eq!("test", target0.name().unwrap());
1012        assert_eq!(
1013            &Value::DateValue(value.epoch_days),
1014            target0.value().unwrap()
1015        );
1016
1017        let target = SqlParameter::of("test", Some(value));
1018        assert_eq!(target0, target);
1019    }
1020
1021    #[test]
1022    fn time_of_day() {
1023        let value = TgTimeOfDay::new(30551971944200);
1024        let target0 = SqlParameter::of("test", value);
1025        assert_eq!("test", target0.name().unwrap());
1026        assert_eq!(
1027            &Value::TimeOfDayValue(value.offset_nanoseconds),
1028            target0.value().unwrap()
1029        );
1030
1031        let target = SqlParameter::of("test", Some(value));
1032        assert_eq!(target0, target);
1033    }
1034
1035    #[test]
1036    fn time_point() {
1037        let value = TgTimePoint::new(1738917213, 123456789);
1038        let target0 = SqlParameter::of("test", value.clone());
1039        assert_eq!("test", target0.name().unwrap());
1040        assert_eq!(
1041            &Value::TimePointValue(value.clone()),
1042            target0.value().unwrap()
1043        );
1044
1045        let target = SqlParameter::of("test", Some(value.clone()));
1046        assert_eq!(target0, target);
1047    }
1048
1049    #[test]
1050    fn time_of_day_with_time_zone() {
1051        let value = TgTimeOfDayWithTimeZone::new(30551971944200, 9 * 60);
1052        let target0 = SqlParameter::of("test", value.clone());
1053        assert_eq!("test", target0.name().unwrap());
1054        assert_eq!(
1055            &Value::TimeOfDayWithTimeZoneValue(value.clone()),
1056            target0.value().unwrap()
1057        );
1058
1059        let target = SqlParameter::of("test", Some(value.clone()));
1060        assert_eq!(target0, target);
1061    }
1062
1063    #[test]
1064    fn time_point_with_time_zone() {
1065        let value = TgTimePointWithTimeZone::new(1738917213, 123456789, 9 * 60);
1066        let target0 = SqlParameter::of("test", value.clone());
1067        assert_eq!("test", target0.name().unwrap());
1068        assert_eq!(
1069            &Value::TimePointWithTimeZoneValue(value.clone()),
1070            target0.value().unwrap()
1071        );
1072
1073        let target = SqlParameter::of("test", Some(value.clone()));
1074        assert_eq!(target0, target);
1075    }
1076
1077    #[cfg(feature = "with_chrono")]
1078    #[test]
1079    fn chrono_naive_date() {
1080        let value = chrono::NaiveDate::from_ymd_opt(2025, 1, 16).unwrap();
1081        let target0 = SqlParameter::of("test", value.clone());
1082        assert_eq!("test", target0.name().unwrap());
1083        assert_eq!(&Value::DateValue(20104), target0.value().unwrap());
1084
1085        let target = SqlParameter::of("test", Some(value.clone()));
1086        assert_eq!(target0, target);
1087
1088        let target = "test".parameter(value.clone());
1089        assert_eq!(target0, target);
1090
1091        let target = "test".to_string().parameter(value.clone());
1092        assert_eq!(target0, target);
1093    }
1094
1095    #[cfg(feature = "with_chrono")]
1096    #[test]
1097    fn chrono_naive_date_ref() {
1098        let value = chrono::NaiveDate::from_ymd_opt(2025, 1, 16).unwrap();
1099
1100        let target0 = SqlParameter::of("test", &value);
1101        assert_eq!("test", target0.name().unwrap());
1102        assert_eq!(&Value::DateValue(20104), target0.value().unwrap());
1103
1104        let target = SqlParameter::of("test", Some(&value));
1105        assert_eq!(target0, target);
1106
1107        let target = "test".parameter(&value);
1108        assert_eq!(target0, target);
1109
1110        let target = "test".to_string().parameter(&value);
1111        assert_eq!(target0, target);
1112    }
1113
1114    #[cfg(feature = "with_chrono")]
1115    #[test]
1116    fn chrono_naive_time() {
1117        let value = chrono::NaiveTime::from_hms_milli_opt(16, 24, 30, 456).unwrap();
1118        let target0 = SqlParameter::of("test", value.clone());
1119        assert_eq!("test", target0.name().unwrap());
1120        assert_eq!(
1121            &Value::TimeOfDayValue(59070456000000),
1122            target0.value().unwrap()
1123        );
1124
1125        let target = SqlParameter::of("test", Some(value.clone()));
1126        assert_eq!(target0, target);
1127
1128        let target = "test".parameter(value.clone());
1129        assert_eq!(target0, target);
1130
1131        let target = "test".to_string().parameter(value.clone());
1132        assert_eq!(target0, target);
1133    }
1134
1135    #[cfg(feature = "with_chrono")]
1136    #[test]
1137    fn chrono_naive_time_ref() {
1138        chrono_naive_time_ref_test(chrono::NaiveTime::from_hms_opt(0, 0, 0).unwrap(), 0);
1139        chrono_naive_time_ref_test(
1140            chrono::NaiveTime::from_hms_opt(23, 59, 59).unwrap(),
1141            86399000000000,
1142        );
1143        chrono_naive_time_ref_test(
1144            chrono::NaiveTime::from_hms_nano_opt(0, 0, 0, 123456789).unwrap(),
1145            123456789,
1146        );
1147        chrono_naive_time_ref_test(
1148            chrono::NaiveTime::from_hms_nano_opt(23, 59, 59, 999999999).unwrap(),
1149            86399999999999,
1150        );
1151    }
1152
1153    #[cfg(feature = "with_chrono")]
1154    fn chrono_naive_time_ref_test(value: chrono::NaiveTime, expected: u64) {
1155        let target0 = SqlParameter::of("test", &value);
1156        assert_eq!("test", target0.name().unwrap());
1157        assert_eq!(&Value::TimeOfDayValue(expected), target0.value().unwrap());
1158
1159        let target = SqlParameter::of("test", Some(&value));
1160        assert_eq!(target0, target);
1161
1162        let target = "test".parameter(&value);
1163        assert_eq!(target0, target);
1164
1165        let target = "test".to_string().parameter(&value);
1166        assert_eq!(target0, target);
1167    }
1168
1169    #[cfg(feature = "with_chrono")]
1170    #[test]
1171    fn chrono_naive_date_time() {
1172        let value = chrono::NaiveDateTime::new(
1173            chrono::NaiveDate::from_ymd_opt(2025, 1, 16).unwrap(),
1174            chrono::NaiveTime::from_hms_nano_opt(17, 42, 30, 123456789).unwrap(),
1175        );
1176
1177        let target0 = SqlParameter::of("test", value.clone());
1178        assert_eq!("test", target0.name().unwrap());
1179        assert_eq!(
1180            &Value::TimePointValue(ProtoTimePoint {
1181                offset_seconds: 1737049350,
1182                nano_adjustment: 123456789
1183            }),
1184            target0.value().unwrap()
1185        );
1186
1187        let target = SqlParameter::of("test", Some(value.clone()));
1188        assert_eq!(target0, target);
1189
1190        let target = "test".parameter(value.clone());
1191        assert_eq!(target0, target);
1192
1193        let target = "test".to_string().parameter(value.clone());
1194        assert_eq!(target0, target);
1195    }
1196
1197    #[cfg(feature = "with_chrono")]
1198    #[test]
1199    fn chrono_naive_date_time_ref() {
1200        chrono_naive_date_time_ref_test(2025, 1, 16, 17, 42, 30, 123456789, 1737049350);
1201        chrono_naive_date_time_ref_test(1970, 1, 1, 0, 0, 0, 0, 0);
1202        chrono_naive_date_time_ref_test(1969, 12, 31, 23, 59, 59, 999999999, -1);
1203    }
1204
1205    #[cfg(feature = "with_chrono")]
1206    fn chrono_naive_date_time_ref_test(
1207        year: i32,
1208        month: u32,
1209        day: u32,
1210        hour: u32,
1211        min: u32,
1212        sec: u32,
1213        nanos: u32,
1214        expected_sec: i64,
1215    ) {
1216        let value = chrono::NaiveDateTime::new(
1217            chrono::NaiveDate::from_ymd_opt(year, month, day).unwrap(),
1218            chrono::NaiveTime::from_hms_nano_opt(hour, min, sec, nanos).unwrap(),
1219        );
1220
1221        let target0 = SqlParameter::of("test", &value);
1222        assert_eq!("test", target0.name().unwrap());
1223        assert_eq!(
1224            &Value::TimePointValue(ProtoTimePoint {
1225                offset_seconds: expected_sec,
1226                nano_adjustment: nanos
1227            }),
1228            target0.value().unwrap()
1229        );
1230
1231        let target = SqlParameter::of("test", Some(&value));
1232        assert_eq!(target0, target);
1233
1234        let target = "test".parameter(&value);
1235        assert_eq!(target0, target);
1236
1237        let target = "test".to_string().parameter(&value);
1238        assert_eq!(target0, target);
1239    }
1240
1241    #[cfg(feature = "with_chrono")]
1242    #[test]
1243    fn chrono_naive_time_with_offset() {
1244        use std::str::FromStr;
1245
1246        let time = chrono::NaiveTime::from_hms_nano_opt(17, 42, 30, 123456789).unwrap();
1247        let offset = chrono::FixedOffset::from_str("+09:00").unwrap();
1248        let value = (time, offset);
1249
1250        let target0 = SqlParameter::of("test", value.clone());
1251        assert_eq!("test", target0.name().unwrap());
1252        assert_eq!(
1253            &Value::TimeOfDayWithTimeZoneValue(ProtoTimeOfDayWithTimeZone {
1254                offset_nanoseconds: (((17 * 60) + 42) * 60 + 30) * 1_000_000_000 + 123456789,
1255                time_zone_offset: 9 * 60
1256            }),
1257            target0.value().unwrap()
1258        );
1259
1260        let target = SqlParameter::of("test", Some(value.clone()));
1261        assert_eq!(target0, target);
1262
1263        let target = "test".parameter(value.clone());
1264        assert_eq!(target0, target);
1265
1266        let target = "test".to_string().parameter(value.clone());
1267        assert_eq!(target0, target);
1268    }
1269
1270    #[cfg(feature = "with_chrono")]
1271    #[test]
1272    fn chrono_naive_time_with_offset_ref() {
1273        chrono_naive_time_with_offset_ref_test(17, 42, 30, 123456789, 9);
1274        chrono_naive_time_with_offset_ref_test(0, 0, 0, 0, 9);
1275        chrono_naive_time_with_offset_ref_test(23, 59, 59, 999999999, 9);
1276        chrono_naive_time_with_offset_ref_test(17, 42, 30, 123456789, -9);
1277    }
1278
1279    #[cfg(feature = "with_chrono")]
1280    fn chrono_naive_time_with_offset_ref_test(
1281        hour: u32,
1282        min: u32,
1283        sec: u32,
1284        nanos: u32,
1285        offset_hour: i32,
1286    ) {
1287        use std::str::FromStr;
1288
1289        let time = chrono::NaiveTime::from_hms_nano_opt(hour, min, sec, nanos).unwrap();
1290        let offset = if offset_hour >= 0 {
1291            format!("+{:02}:00", offset_hour)
1292        } else {
1293            format!("-{:02}:00", offset_hour.abs())
1294        };
1295        let offset = chrono::FixedOffset::from_str(&offset).unwrap();
1296        let value = (time, offset);
1297
1298        let target0 = SqlParameter::of("test", &value);
1299        assert_eq!("test", target0.name().unwrap());
1300        assert_eq!(
1301            &Value::TimeOfDayWithTimeZoneValue(ProtoTimeOfDayWithTimeZone {
1302                offset_nanoseconds: (((hour as u64 * 60) + min as u64) * 60 + sec as u64)
1303                    * 1_000_000_000
1304                    + nanos as u64,
1305                time_zone_offset: offset_hour * 60
1306            }),
1307            target0.value().unwrap()
1308        );
1309
1310        let target = SqlParameter::of("test", Some(&value));
1311        assert_eq!(target0, target);
1312
1313        let target = "test".parameter(&value);
1314        assert_eq!(target0, target);
1315
1316        let target = "test".to_string().parameter(&value);
1317        assert_eq!(target0, target);
1318    }
1319
1320    #[cfg(feature = "with_chrono")]
1321    #[test]
1322    fn chrono_date_time() {
1323        let value = date_time(2025, 1, 16, 17, 42, 30, 123456789, 9);
1324
1325        let target0 = SqlParameter::of("test", value.clone());
1326        assert_eq!("test", target0.name().unwrap());
1327        assert_eq!(
1328            &Value::TimePointWithTimeZoneValue(ProtoTimePointWithTimeZone {
1329                offset_seconds: 1737049350,
1330                nano_adjustment: 123456789,
1331                time_zone_offset: 9 * 60
1332            }),
1333            target0.value().unwrap()
1334        );
1335
1336        let target = SqlParameter::of("test", Some(value.clone()));
1337        assert_eq!(target0, target);
1338
1339        let target = "test".parameter(value.clone());
1340        assert_eq!(target0, target);
1341
1342        let target = "test".to_string().parameter(value.clone());
1343        assert_eq!(target0, target);
1344    }
1345
1346    #[cfg(feature = "with_chrono")]
1347    #[test]
1348    fn chrono_date_time_ref() {
1349        let value = date_time(2025, 1, 16, 17, 42, 30, 123456789, 9);
1350
1351        let target0 = SqlParameter::of("test", &value);
1352        assert_eq!("test", target0.name().unwrap());
1353        assert_eq!(
1354            &Value::TimePointWithTimeZoneValue(ProtoTimePointWithTimeZone {
1355                offset_seconds: 1737049350,
1356                nano_adjustment: 123456789,
1357                time_zone_offset: 9 * 60
1358            }),
1359            target0.value().unwrap()
1360        );
1361
1362        let target = SqlParameter::of("test", Some(&value));
1363        assert_eq!(target0, target);
1364
1365        let target = "test".parameter(&value);
1366        assert_eq!(target0, target);
1367
1368        let target = "test".to_string().parameter(&value);
1369        assert_eq!(target0, target);
1370    }
1371
1372    #[cfg(feature = "with_chrono")]
1373    fn date_time(
1374        year: i32,
1375        month: u32,
1376        day: u32,
1377        hour: u32,
1378        min: u32,
1379        sec: u32,
1380        nanos: u32,
1381        offset_hour: i32,
1382    ) -> chrono::DateTime<chrono::FixedOffset> {
1383        use std::str::FromStr;
1384
1385        let s = format!("{year:04}-{month:02}-{day:02} {hour:02}:{min:02}:{sec:02}.{nanos:09} +{offset_hour:02}:00");
1386        chrono::DateTime::from_str(&s).unwrap()
1387    }
1388
1389    #[cfg(feature = "with_time")]
1390    #[test]
1391    fn time_date() {
1392        let value = time::Date::from_calendar_date(2025, time::Month::January, 16).unwrap();
1393        let target0 = SqlParameter::of("test", value.clone());
1394        assert_eq!("test", target0.name().unwrap());
1395        assert_eq!(&Value::DateValue(20104), target0.value().unwrap());
1396
1397        let target = SqlParameter::of("test", Some(value.clone()));
1398        assert_eq!(target0, target);
1399
1400        let target = "test".parameter(value.clone());
1401        assert_eq!(target0, target);
1402
1403        let target = "test".to_string().parameter(value.clone());
1404        assert_eq!(target0, target);
1405    }
1406
1407    #[cfg(feature = "with_time")]
1408    #[test]
1409    fn time_date_ref() {
1410        time_date_ref_test(2025, 1, 16, 20104);
1411        time_date_ref_test(1970, 1, 1, 0);
1412        time_date_ref_test(1969, 12, 31, -1);
1413        time_date_ref_test(0, 1, 1, -719528);
1414        time_date_ref_test(9999, 12, 31, 2932896);
1415        time_date_ref_test(-9999, 1, 1, -4371587);
1416    }
1417
1418    #[cfg(feature = "with_time")]
1419    fn time_date_ref_test(year: i32, month: u8, day: u8, expected: i64) {
1420        let value =
1421            time::Date::from_calendar_date(year, time::Month::try_from(month).unwrap(), day)
1422                .unwrap();
1423        let target0 = SqlParameter::of("test", &value);
1424        assert_eq!("test", target0.name().unwrap());
1425        assert_eq!(&Value::DateValue(expected), target0.value().unwrap());
1426
1427        let target = SqlParameter::of("test", Some(&value));
1428        assert_eq!(target0, target);
1429
1430        let target = "test".parameter(&value);
1431        assert_eq!(target0, target);
1432
1433        let target = "test".to_string().parameter(&value);
1434        assert_eq!(target0, target);
1435    }
1436
1437    #[cfg(feature = "with_time")]
1438    #[test]
1439    fn time_time() {
1440        let value = time::Time::from_hms_milli(16, 24, 30, 456).unwrap();
1441        let target0 = SqlParameter::of("test", value.clone());
1442        assert_eq!("test", target0.name().unwrap());
1443        assert_eq!(
1444            &Value::TimeOfDayValue(59070456000000),
1445            target0.value().unwrap()
1446        );
1447
1448        let target = SqlParameter::of("test", Some(value.clone()));
1449        assert_eq!(target0, target);
1450
1451        let target = "test".parameter(value.clone());
1452        assert_eq!(target0, target);
1453
1454        let target = "test".to_string().parameter(value.clone());
1455        assert_eq!(target0, target);
1456    }
1457
1458    #[cfg(feature = "with_time")]
1459    #[test]
1460    fn time_time_ref() {
1461        time_time_ref_test(time::Time::from_hms(0, 0, 0).unwrap(), 0);
1462        time_time_ref_test(time::Time::from_hms(23, 59, 59).unwrap(), 86399000000000);
1463        time_time_ref_test(
1464            time::Time::from_hms_nano(0, 0, 0, 123456789).unwrap(),
1465            123456789,
1466        );
1467        time_time_ref_test(
1468            time::Time::from_hms_nano(23, 59, 59, 999999999).unwrap(),
1469            86399999999999,
1470        );
1471    }
1472
1473    #[cfg(feature = "with_time")]
1474    fn time_time_ref_test(value: time::Time, expected: u64) {
1475        let target0 = SqlParameter::of("test", &value);
1476        assert_eq!("test", target0.name().unwrap());
1477        assert_eq!(&Value::TimeOfDayValue(expected), target0.value().unwrap());
1478
1479        let target = SqlParameter::of("test", Some(&value));
1480        assert_eq!(target0, target);
1481
1482        let target = "test".parameter(&value);
1483        assert_eq!(target0, target);
1484
1485        let target = "test".to_string().parameter(&value);
1486        assert_eq!(target0, target);
1487    }
1488
1489    #[cfg(feature = "with_time")]
1490    #[test]
1491    fn time_primitive_date_time() {
1492        let value = time::PrimitiveDateTime::new(
1493            time::Date::from_calendar_date(2025, time::Month::January, 16).unwrap(),
1494            time::Time::from_hms_nano(17, 42, 30, 123456789).unwrap(),
1495        );
1496        let target0 = SqlParameter::of("test", value.clone());
1497        assert_eq!("test", target0.name().unwrap());
1498        assert_eq!(
1499            &Value::TimePointValue(ProtoTimePoint {
1500                offset_seconds: 1737049350,
1501                nano_adjustment: 123456789
1502            }),
1503            target0.value().unwrap()
1504        );
1505
1506        let target = SqlParameter::of("test", Some(value.clone()));
1507        assert_eq!(target0, target);
1508
1509        let target = "test".parameter(value.clone());
1510        assert_eq!(target0, target);
1511
1512        let target = "test".to_string().parameter(value.clone());
1513        assert_eq!(target0, target);
1514    }
1515
1516    #[cfg(feature = "with_time")]
1517    #[test]
1518    fn time_primitive_date_time_ref() {
1519        time_primitive_date_time_ref_test(2025, 1, 16, 17, 42, 30, 123456789, 1737049350);
1520        time_primitive_date_time_ref_test(1970, 1, 1, 0, 0, 0, 0, 0);
1521        time_primitive_date_time_ref_test(1969, 12, 31, 23, 59, 59, 999999999, -1);
1522    }
1523
1524    #[cfg(feature = "with_time")]
1525    fn time_primitive_date_time_ref_test(
1526        year: i32,
1527        month: u8,
1528        day: u8,
1529        hour: u8,
1530        min: u8,
1531        sec: u8,
1532        nanos: u32,
1533        expected: i64,
1534    ) {
1535        let value = time::PrimitiveDateTime::new(
1536            time::Date::from_calendar_date(year, time::Month::try_from(month).unwrap(), day)
1537                .unwrap(),
1538            time::Time::from_hms_nano(hour, min, sec, nanos).unwrap(),
1539        );
1540        let target0 = SqlParameter::of("test", &value);
1541        assert_eq!("test", target0.name().unwrap());
1542        assert_eq!(
1543            &Value::TimePointValue(ProtoTimePoint {
1544                offset_seconds: expected,
1545                nano_adjustment: nanos
1546            }),
1547            target0.value().unwrap()
1548        );
1549
1550        let target = SqlParameter::of("test", Some(&value));
1551        assert_eq!(target0, target);
1552
1553        let target = "test".parameter(&value);
1554        assert_eq!(target0, target);
1555
1556        let target = "test".to_string().parameter(&value);
1557        assert_eq!(target0, target);
1558    }
1559
1560    #[cfg(feature = "with_time")]
1561    #[test]
1562    fn time_time_with_offset() {
1563        let time = time::Time::from_hms_nano(17, 42, 30, 123456789).unwrap();
1564        let offset = time::UtcOffset::from_hms(9, 0, 0).unwrap();
1565        let value = (time, offset);
1566
1567        let target0 = SqlParameter::of("test", value.clone());
1568        assert_eq!("test", target0.name().unwrap());
1569        assert_eq!(
1570            &Value::TimeOfDayWithTimeZoneValue(ProtoTimeOfDayWithTimeZone {
1571                offset_nanoseconds: (((17 * 60) + 42) * 60 + 30) * 1_000_000_000 + 123456789,
1572                time_zone_offset: 9 * 60
1573            }),
1574            target0.value().unwrap()
1575        );
1576
1577        let target = SqlParameter::of("test", Some(value.clone()));
1578        assert_eq!(target0, target);
1579
1580        let target = "test".parameter(value.clone());
1581        assert_eq!(target0, target);
1582
1583        let target = "test".to_string().parameter(value.clone());
1584        assert_eq!(target0, target);
1585    }
1586
1587    #[cfg(feature = "with_time")]
1588    #[test]
1589    fn time_naive_time_with_offset_ref() {
1590        time_time_with_offset_ref_test(17, 42, 30, 123456789, 9);
1591        time_time_with_offset_ref_test(0, 0, 0, 0, 9);
1592        time_time_with_offset_ref_test(23, 59, 59, 999999999, 9);
1593        time_time_with_offset_ref_test(17, 42, 30, 123456789, -9);
1594    }
1595
1596    #[cfg(feature = "with_time")]
1597    fn time_time_with_offset_ref_test(hour: u8, min: u8, sec: u8, nanos: u32, offset_hour: i8) {
1598        let time = time::Time::from_hms_nano(hour, min, sec, nanos).unwrap();
1599        let offset = time::UtcOffset::from_hms(offset_hour, 0, 0).unwrap();
1600        let value = (time, offset);
1601
1602        let target0 = SqlParameter::of("test", &value);
1603        assert_eq!("test", target0.name().unwrap());
1604        assert_eq!(
1605            &Value::TimeOfDayWithTimeZoneValue(ProtoTimeOfDayWithTimeZone {
1606                offset_nanoseconds: (((hour as u64 * 60) + min as u64) * 60 + sec as u64)
1607                    * 1_000_000_000
1608                    + nanos as u64,
1609                time_zone_offset: offset_hour as i32 * 60
1610            }),
1611            target0.value().unwrap()
1612        );
1613
1614        let target = SqlParameter::of("test", Some(&value));
1615        assert_eq!(target0, target);
1616
1617        let target = "test".parameter(&value);
1618        assert_eq!(target0, target);
1619
1620        let target = "test".to_string().parameter(&value);
1621        assert_eq!(target0, target);
1622    }
1623
1624    #[cfg(feature = "with_time")]
1625    #[test]
1626    fn time_offset_date_time() {
1627        let value = offset_date_time(2025, 1, 16, 17, 42, 30, 123456789, 9);
1628
1629        let target0 = SqlParameter::of("test", value.clone());
1630        assert_eq!("test", target0.name().unwrap());
1631        assert_eq!(
1632            &Value::TimePointWithTimeZoneValue(ProtoTimePointWithTimeZone {
1633                offset_seconds: 1737049350,
1634                nano_adjustment: 123456789,
1635                time_zone_offset: 9 * 60
1636            }),
1637            target0.value().unwrap()
1638        );
1639
1640        let target = SqlParameter::of("test", Some(value.clone()));
1641        assert_eq!(target0, target);
1642
1643        let target = "test".parameter(value.clone());
1644        assert_eq!(target0, target);
1645
1646        let target = "test".to_string().parameter(value.clone());
1647        assert_eq!(target0, target);
1648    }
1649
1650    #[cfg(feature = "with_time")]
1651    #[test]
1652    fn time_offset_date_time_ref() {
1653        let value = offset_date_time(2025, 1, 16, 17, 42, 30, 123456789, 9);
1654
1655        let target0 = SqlParameter::of("test", &value);
1656        assert_eq!("test", target0.name().unwrap());
1657        assert_eq!(
1658            &Value::TimePointWithTimeZoneValue(ProtoTimePointWithTimeZone {
1659                offset_seconds: 1737049350,
1660                nano_adjustment: 123456789,
1661                time_zone_offset: 9 * 60
1662            }),
1663            target0.value().unwrap()
1664        );
1665
1666        let target = SqlParameter::of("test", Some(&value));
1667        assert_eq!(target0, target);
1668
1669        let target = "test".parameter(&value);
1670        assert_eq!(target0, target);
1671
1672        let target = "test".to_string().parameter(&value);
1673        assert_eq!(target0, target);
1674    }
1675
1676    #[cfg(feature = "with_time")]
1677    fn offset_date_time(
1678        year: i32,
1679        month: u8,
1680        day: u8,
1681        hour: u8,
1682        min: u8,
1683        sec: u8,
1684        nanos: u32,
1685        offset_hour: i32,
1686    ) -> time::OffsetDateTime {
1687        time::OffsetDateTime::new_in_offset(
1688            time::Date::from_calendar_date(year, time::Month::try_from(month).unwrap(), day)
1689                .unwrap(),
1690            time::Time::from_hms_nano(hour, min, sec, nanos).unwrap(),
1691            time::UtcOffset::from_whole_seconds(offset_hour * 60 * 60).unwrap(),
1692        )
1693    }
1694
1695    #[test]
1696    fn blob_path() {
1697        let value = TgBlob::new("/path/to/file");
1698        let target0 = SqlParameter::of("test", value.clone());
1699        assert_eq!("test", target0.name().unwrap());
1700        let data =
1701            crate::jogasaki::proto::sql::common::blob::Data::LocalPath("/path/to/file".to_string());
1702        assert_eq!(
1703            &Value::Blob(crate::jogasaki::proto::sql::common::Blob { data: Some(data) }),
1704            target0.value().unwrap()
1705        );
1706
1707        let target = SqlParameter::of("test", Some(value.clone()));
1708        assert_eq!(target0, target);
1709    }
1710
1711    #[test]
1712    fn blob_contents() {
1713        let contents = vec![1, 2, 3];
1714        let value = TgBlob::from(contents.clone());
1715        let target0 = SqlParameter::of("test", value.clone());
1716        assert_eq!("test", target0.name().unwrap());
1717        let data = crate::jogasaki::proto::sql::common::blob::Data::Contents(contents);
1718        assert_eq!(
1719            &Value::Blob(crate::jogasaki::proto::sql::common::Blob { data: Some(data) }),
1720            target0.value().unwrap()
1721        );
1722
1723        let target = SqlParameter::of("test", Some(value.clone()));
1724        assert_eq!(target0, target);
1725    }
1726
1727    #[test]
1728    fn clob_path() {
1729        let value = TgClob::new("/path/to/file");
1730        let target0 = SqlParameter::of("test", value.clone());
1731        assert_eq!("test", target0.name().unwrap());
1732        let data =
1733            crate::jogasaki::proto::sql::common::clob::Data::LocalPath("/path/to/file".to_string());
1734        assert_eq!(
1735            &Value::Clob(crate::jogasaki::proto::sql::common::Clob { data: Some(data) }),
1736            target0.value().unwrap()
1737        );
1738
1739        let target = SqlParameter::of("test", Some(value.clone()));
1740        assert_eq!(target0, target);
1741    }
1742
1743    #[test]
1744    fn clob_contents() {
1745        let contents = "abc";
1746        let value = TgClob::from(contents);
1747        let target0 = SqlParameter::of("test", value.clone());
1748        assert_eq!("test", target0.name().unwrap());
1749        let data =
1750            crate::jogasaki::proto::sql::common::clob::Data::Contents(contents.as_bytes().to_vec());
1751        assert_eq!(
1752            &Value::Clob(crate::jogasaki::proto::sql::common::Clob { data: Some(data) }),
1753            target0.value().unwrap()
1754        );
1755
1756        let target = SqlParameter::of("test", Some(value.clone()));
1757        assert_eq!(target0, target);
1758
1759        let value = TgClob::from(contents.to_string());
1760        let target = SqlParameter::of("test", value);
1761        assert_eq!(target0, target);
1762    }
1763}