|
2 | 2 | //// |
3 | 3 | //// Gleam wrapper around pgo library |
4 | 4 |
|
| 5 | +// TODO: add time and timestamp with zone once PGO supports them |
| 6 | + |
5 | 7 | import gleam/dynamic.{type DecodeErrors, type Decoder, type Dynamic} |
| 8 | +import gleam/float |
| 9 | +import gleam/int |
6 | 10 | import gleam/list |
7 | 11 | import gleam/option.{type Option, None, Some} |
8 | 12 | import gleam/result |
@@ -272,13 +276,22 @@ pub fn bytea(a: BitArray) -> Value |
272 | 276 | @external(erlang, "pog_ffi", "coerce") |
273 | 277 | pub fn array(a: List(a)) -> Value |
274 | 278 |
|
275 | | -/// Coerce a timestamp represented as `#(#(year, month, day), #(hour, minute, second))` into a `Value`. |
276 | | -@external(erlang, "pog_ffi", "coerce") |
277 | | -pub fn timestamp(a: #(#(Int, Int, Int), #(Int, Int, Int))) -> Value |
| 279 | +pub fn timestamp(timestamp: Timestamp) -> Value { |
| 280 | + coerce_value(#(date(timestamp.date), time(timestamp.time))) |
| 281 | +} |
| 282 | + |
| 283 | +pub fn date(date: Date) -> Value { |
| 284 | + coerce_value(#(date.year, date.month, date.day)) |
| 285 | +} |
| 286 | + |
| 287 | +pub fn time(time: Time) -> Value { |
| 288 | + let seconds = int.to_float(time.seconds) |
| 289 | + let seconds = seconds +. int.to_float(time.microseconds) /. 1_000_000.0 |
| 290 | + coerce_value(#(time.hours, time.minutes, seconds)) |
| 291 | +} |
278 | 292 |
|
279 | | -/// Coerce a date represented as `#(year, month, day)` into a `Value`. |
280 | 293 | @external(erlang, "pog_ffi", "coerce") |
281 | | -pub fn date(a: #(Int, Int, Int)) -> Value |
| 294 | +fn coerce_value(a: anything) -> Value |
282 | 295 |
|
283 | 296 | pub type TransactionError { |
284 | 297 | TransactionQueryError(QueryError) |
@@ -656,18 +669,57 @@ pub fn error_code_name(error_code: String) -> Result(String, Nil) { |
656 | 669 | } |
657 | 670 | } |
658 | 671 |
|
659 | | -/// Checks to see if the value is formatted as `#(#(Int, Int, Int), #(Int, Int, Int))` |
660 | | -/// to represent `#(#(year, month, day), #(hour, minute, second))`, and returns the |
661 | | -/// value if it is. |
662 | | -pub fn decode_timestamp(value: dynamic.Dynamic) { |
663 | | - dynamic.tuple2( |
664 | | - dynamic.tuple3(dynamic.int, dynamic.int, dynamic.int), |
665 | | - dynamic.tuple3(dynamic.int, dynamic.int, dynamic.int), |
| 672 | +pub fn decode_timestamp( |
| 673 | + value: dynamic.Dynamic, |
| 674 | +) -> Result(Timestamp, DecodeErrors) { |
| 675 | + dynamic.decode2( |
| 676 | + Timestamp, |
| 677 | + dynamic.element(0, decode_date), |
| 678 | + dynamic.element(1, decode_time), |
666 | 679 | )(value) |
667 | 680 | } |
668 | 681 |
|
669 | | -/// Checks to see if the value is formatted as `#(Int, Int, Int)` to represent a date |
670 | | -/// as `#(year, month, day)`, and returns the value if it is. |
671 | | -pub fn decode_date(value: dynamic.Dynamic) { |
672 | | - dynamic.tuple3(dynamic.int, dynamic.int, dynamic.int)(value) |
| 682 | +pub fn decode_date(value: dynamic.Dynamic) -> Result(Date, DecodeErrors) { |
| 683 | + dynamic.decode3( |
| 684 | + Date, |
| 685 | + dynamic.element(0, dynamic.int), |
| 686 | + dynamic.element(1, dynamic.int), |
| 687 | + dynamic.element(2, dynamic.int), |
| 688 | + )(value) |
| 689 | +} |
| 690 | + |
| 691 | +pub fn decode_time(value: dynamic.Dynamic) -> Result(Time, DecodeErrors) { |
| 692 | + case dynamic.tuple3(dynamic.int, dynamic.int, decode_seconds)(value) { |
| 693 | + Error(e) -> Error(e) |
| 694 | + Ok(#(hours, minutes, #(seconds, microseconds))) -> |
| 695 | + Ok(Time(hours:, minutes:, seconds:, microseconds:)) |
| 696 | + } |
| 697 | +} |
| 698 | + |
| 699 | +fn decode_seconds(value: dynamic.Dynamic) -> Result(#(Int, Int), DecodeErrors) { |
| 700 | + case dynamic.int(value) { |
| 701 | + Ok(i) -> Ok(#(i, 0)) |
| 702 | + Error(_) -> |
| 703 | + case dynamic.float(value) { |
| 704 | + Error(e) -> Error(e) |
| 705 | + Ok(i) -> { |
| 706 | + let floored = float.floor(i) |
| 707 | + let seconds = float.round(floored) |
| 708 | + let microseconds = float.round({ i -. floored } *. 1_000_000.0) |
| 709 | + Ok(#(seconds, microseconds)) |
| 710 | + } |
| 711 | + } |
| 712 | + } |
| 713 | +} |
| 714 | + |
| 715 | +pub type Date { |
| 716 | + Date(year: Int, month: Int, day: Int) |
| 717 | +} |
| 718 | + |
| 719 | +pub type Time { |
| 720 | + Time(hours: Int, minutes: Int, seconds: Int, microseconds: Int) |
| 721 | +} |
| 722 | + |
| 723 | +pub type Timestamp { |
| 724 | + Timestamp(date: Date, time: Time) |
673 | 725 | } |
0 commit comments