Packages

Gleam library providing Postgres data types, encoders, and decoders

Current section

Files

Jump to
pg_value src pg_value@interval.erl
Raw

src/pg_value@interval.erl

-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() ->
<<<<Iso8601/binary, (erlang:integer_to_binary(Count))/binary>>/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
).