-module(pg_value@interval). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/pg_value/interval.gleam"). -export([months/1, days/1, seconds/1, microseconds/1, add/2, to_iso8601_string/1, decoder/0]). -export_type([interval/0]). -if(?OTP_RELEASE >= 27). -define(MODULEDOC(Str), -moduledoc(Str)). -define(DOC(Str), -doc(Str)). -else. -define(MODULEDOC(Str), -compile([])). -define(DOC(Str), -compile([])). -endif. -type interval() :: {interval, integer(), integer(), integer(), integer()}. -file("src/pg_value/interval.gleam", 12). ?DOC(" Returns an Interval with the provided number of months\n"). -spec months(integer()) -> interval(). months(Months) -> {interval, Months, 0, 0, 0}. -file("src/pg_value/interval.gleam", 17). ?DOC(" Returns an Interval with the provided number of days\n"). -spec days(integer()) -> interval(). days(Days) -> {interval, 0, Days, 0, 0}. -file("src/pg_value/interval.gleam", 22). ?DOC(" Returns an Interval with the provided number of seconds\n"). -spec seconds(integer()) -> interval(). seconds(Seconds) -> {interval, 0, 0, Seconds, 0}. -file("src/pg_value/interval.gleam", 27). ?DOC(" Returns an Interval with the provided number of microseconds\n"). -spec microseconds(integer()) -> interval(). microseconds(Microseconds) -> {interval, 0, 0, 0, Microseconds}. -file("src/pg_value/interval.gleam", 32). ?DOC(" Returns an Interval with the summed values of each provided Interval\n"). -spec add(interval(), interval()) -> interval(). add(Left, Right) -> {interval, L_months, L_days, L_secs, L_usecs} = Left, {interval, R_months, R_days, R_secs, R_usecs} = Right, {interval, L_months + R_months, L_days + R_days, L_secs + R_secs, L_usecs + R_usecs}. -file("src/pg_value/interval.gleam", 99). -spec append_to_iso8601_string(binary(), integer(), binary()) -> binary(). append_to_iso8601_string(Iso8601, Count, Unit) -> gleam@bool:guard( Count =:= 0, Iso8601, fun() -> <<<>/binary, Unit/binary>> end ). -file("src/pg_value/interval.gleam", 105). -spec to_seconds_and_microseconds(integer()) -> {integer(), integer()}. to_seconds_and_microseconds(Usecs) -> Seconds = Usecs div 1000000, Usecs@1 = Usecs - (Seconds * 1000000), {Seconds, Usecs@1}. -file("src/pg_value/interval.gleam", 112). -spec microsecond_digits(integer(), integer(), binary()) -> binary(). microsecond_digits(N, Position, Acc) -> case Position of 6 -> Acc; _ when (Acc =:= <<""/utf8>>) andalso ((N rem 10) =:= 0) -> microsecond_digits(N div 10, Position + 1, Acc); _ -> Acc@1 = <<(erlang:integer_to_binary(N rem 10))/binary, Acc/binary>>, microsecond_digits(N div 10, Position + 1, Acc@1) end. -file("src/pg_value/interval.gleam", 67). ?DOC( " Converts an interval to an [ISO8601](https://en.wikipedia.org/wiki/ISO_8601#Durations)\n" " formatted string. This function avoids converting the Interval's units, except for\n" " when the number of microseconds includes whole seconds. If more than `1_000_000`\n" " microseconds are provided, whole seconds will be derived from the microseconds value.\n" " The remaining microseconds will be appended as a decimal in the formatted string.\n" "\n" " `Interval(months: 14, days: 0, seconds: 86430, microseconds: 0)`\n" " will be formatted as \"P14MT86430S\" rather than subdividing months into years\n" " or seconds into days and formatting the string as e.g. \"P1Y2M1DT30S\".\n" "\n" " `Interval(months: 0, days: 0, seconds: 10, microseconds: 1_200_000)` will be\n" " formatted as \"PT11.2S\"\n" ). -spec to_iso8601_string(interval()) -> binary(). to_iso8601_string(Interval) -> case Interval of {interval, 0, 0, 0, 0} -> <<"PT0S"/utf8>>; {interval, Months, Days, Secs, Usecs} -> Iso8601 = begin _pipe = <<"P"/utf8>>, _pipe@1 = append_to_iso8601_string(_pipe, Months, <<"M"/utf8>>), append_to_iso8601_string(_pipe@1, Days, <<"D"/utf8>>) end, {Seconds, Usecs@1} = to_seconds_and_microseconds(Usecs), Seconds@1 = Seconds + Secs, case {Seconds@1, Usecs@1} of {0, 0} -> Iso8601; {_, 0} -> _pipe@2 = Iso8601, _pipe@3 = gleam@string:append(_pipe@2, <<"T"/utf8>>), append_to_iso8601_string(_pipe@3, Seconds@1, <<"S"/utf8>>); {_, _} -> _pipe@4 = Iso8601, _pipe@5 = gleam@string:append(_pipe@4, <<"T"/utf8>>), _pipe@6 = gleam@string:append( _pipe@5, erlang:integer_to_binary(Seconds@1) ), _pipe@7 = gleam@string:append(_pipe@6, <<"."/utf8>>), _pipe@8 = gleam@string:append( _pipe@7, microsecond_digits(Usecs@1, 0, <<""/utf8>>) ), gleam@string:append(_pipe@8, <<"S"/utf8>>) end end. -file("src/pg_value/interval.gleam", 127). ?DOC( " Returns a decoder that decodes the dynamic value returned by\n" " `pg_value.decode` when decoding an PostgresSQL Interval.\n" ). -spec decoder() -> gleam@dynamic@decode:decoder(interval()). decoder() -> gleam@dynamic@decode:field( 0, {decoder, fun gleam@dynamic@decode:decode_int/1}, fun(Months) -> gleam@dynamic@decode:field( 1, {decoder, fun gleam@dynamic@decode:decode_int/1}, fun(Days) -> gleam@dynamic@decode:field( 2, {decoder, fun gleam@dynamic@decode:decode_int/1}, fun(Microseconds) -> {Seconds, Microseconds@1} = to_seconds_and_microseconds( Microseconds ), _pipe = {interval, Months, Days, Seconds, Microseconds@1}, gleam@dynamic@decode:success(_pipe) end ) end ) end ).