Skip to content

Commit

Permalink
fix ranges encoding (#155)
Browse files Browse the repository at this point in the history
  • Loading branch information
nsidnev authored Jul 7, 2023
1 parent 59be2df commit b5f5028
Show file tree
Hide file tree
Showing 7 changed files with 147 additions and 33 deletions.
14 changes: 12 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,25 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).


## Unreleased

[Compare with 0.6.0](https://github.com/edgedb/edgedb-elixir/compare/v0.6.0...HEAD)
[Compare with 0.6.1](https://github.com/edgedb/edgedb-elixir/compare/v0.6.1...HEAD)

## [0.6.1] - 2023-07-07

[Compare with 0.6.0](https://github.com/edgedb/edgedb-elixir/compare/v0.6.0...v0.6.1)

### Added

- support for `Elixir v1.15` and `Erlang/OTP 26`.

### Fixed

- encoding of `t:EdgeDB.Range.t/0` values.
- constructing `t:EdgeDB.Range.t/0` from `EdgeDB.Range.new/3` with `nil` as values.
- examples in the documentation and the `Inspect` implementation of
`t:EdgeDB.DateDuration.t/0` and `t:EdgeDB.Range.t/0`.

## [0.6.0] - 2023-06-22

[Compare with 0.5.1](https://github.com/edgedb/edgedb-elixir/compare/v0.5.1...v0.6.0)
Expand Down
23 changes: 17 additions & 6 deletions lib/edgedb/protocol/codecs/range.ex
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,17 @@ defimpl EdgeDB.Protocol.Codec, for: EdgeDB.Protocol.Codecs.Range do
codec = CodecStorage.get(codec_storage, codec)
flags = encode_range_flags(range)

data = [
Codec.encode(codec, range.lower, codec_storage),
Codec.encode(codec, range.upper, codec_storage)
]

[<<IO.iodata_length(data)::uint32(), flags::uint8()>> | data]
data =
Enum.reject(
[
<<flags::uint8()>>,
range.lower && Codec.encode(codec, range.lower, codec_storage),
range.upper && Codec.encode(codec, range.upper, codec_storage)
],
&is_nil/1
)

[<<IO.iodata_length(data)::uint32()>> | data]
end

@impl Codec
Expand Down Expand Up @@ -115,6 +120,9 @@ defimpl EdgeDB.Protocol.Codec, for: EdgeDB.Protocol.Codecs.Range do

range.inc_lower ->
Bitwise.bor(flags, @lb_inc)

true ->
flags
end

cond do
Expand All @@ -123,6 +131,9 @@ defimpl EdgeDB.Protocol.Codec, for: EdgeDB.Protocol.Codecs.Range do

range.inc_upper ->
Bitwise.bor(flags, @ub_inc)

true ->
flags
end
end
end
6 changes: 3 additions & 3 deletions lib/edgedb/types/date_duration.ex
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ defmodule EdgeDB.DateDuration do
```elixir
iex(1)> {:ok, client} = EdgeDB.start_link()
iex(2)> EdgeDB.query_required_single!(client, "select <cal::date_duration>'1 year 2 days'")
#EdgeDB.Duration<"P1Y20D">
#EdgeDB.DateDuration<"P1Y2D">
```
"""

Expand All @@ -33,12 +33,12 @@ defimpl Inspect, for: EdgeDB.DateDuration do

@impl Inspect
def inspect(%EdgeDB.DateDuration{days: 0, months: 0}, _opts) do
concat(["#EdgeDB.RelativeDuration<\"", "P0D", "\">"])
concat(["#EdgeDB.DateDuration<\"", "P0D", "\">"])
end

@impl Inspect
def inspect(%EdgeDB.DateDuration{} = duration, _opts) do
concat(["#EdgeDB.RelativeDuration<\"", format_date("P", duration), "\">"])
concat(["#EdgeDB.DateDuration<\"", format_date("P", duration), "\">"])
end

defp format_date(formatted_repr, %EdgeDB.DateDuration{} = duration) do
Expand Down
59 changes: 45 additions & 14 deletions lib/edgedb/types/range.ex
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,20 @@ defmodule EdgeDB.Range do
is_empty: false
]

@typedoc since: "0.6.1"
@typedoc """
A value representing some interval of values.
A type that is acceptable by EdgeDB ranges.
"""
@type value() ::
integer()
| float()
| Decimal.t()
| DateTime.t()
| NaiveDateTime.t()
| Date.t()

@typedoc """
A value of `t:value/0` type representing some interval of values.
Fields:
Expand All @@ -38,9 +50,9 @@ defmodule EdgeDB.Range do
}

@typedoc """
A value representing some interval of values.
A value of `t:value/0` type representing some interval of values.
"""
@type t() :: t(term())
@type t() :: t(value())

@typedoc """
Options for `EdgeDB.Range.new/3` function.
Expand All @@ -66,7 +78,7 @@ defmodule EdgeDB.Range do
"""
@spec empty() :: t()
def empty do
new(nil, nil, empty: true, inc_lower: false)
new(nil, nil, empty: true)
end

@doc """
Expand All @@ -77,19 +89,38 @@ defmodule EdgeDB.Range do
#EdgeDB.Range<[1.1, 3.3]>
```
"""
@spec new(value, value, list(creation_option())) :: t(value) when value: term()
@spec new(value | nil, value | nil, list(creation_option())) :: t(value) when value: value()
def new(lower, upper, opts \\ []) do
empty? = Keyword.get(opts, :empty, false)
inc_lower? = Keyword.get(opts, :inc_lower, true)
inc_upper? = Keyword.get(opts, :inc_upper, false)
empty? = Keyword.get(opts, :empty, false)

%__MODULE__{
lower: lower,
upper: upper,
inc_lower: inc_lower?,
inc_upper: inc_upper?,
is_empty: empty?
}
cond do
empty? and (not is_nil(lower) or not is_nil(upper)) ->
raise EdgeDB.InvalidArgumentError.new(
"conflicting arguments to construct range: " <>
":empty is `true` while the specified bounds " <>
"suggest otherwise"
)

empty? ->
%__MODULE__{
lower: nil,
upper: nil,
inc_lower: false,
inc_upper: false,
is_empty: true
}

true ->
%__MODULE__{
lower: lower,
upper: upper,
inc_lower: not is_nil(lower) and inc_lower?,
inc_upper: not is_nil(upper) and inc_upper?,
is_empty: false
}
end
end
end

Expand All @@ -107,7 +138,7 @@ defimpl Inspect, for: EdgeDB.Range do
"#EdgeDB.Range<",
if(range.inc_lower, do: "[", else: "("),
if(range.lower, do: Inspect.inspect(range.lower, opts), else: empty()),
",",
", ",
if(range.upper, do: Inspect.inspect(range.upper, opts), else: empty()),
if(range.inc_upper, do: "]", else: ")"),
">"
Expand Down
2 changes: 1 addition & 1 deletion mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ defmodule EdgeDB.MixProject do
use Mix.Project

@app :edgedb
@version "0.6.0"
@version "0.6.1"
@source_url "https://github.com/edgedb/edgedb-elixir"
@description "EdgeDB client for Elixir"

Expand Down
6 changes: 6 additions & 0 deletions test/docs/docs_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ defmodule Tests.DocsTest do
doctest EdgeDB.RelativeDuration
doctest EdgeDB.Set

skip_before(version: 2)
doctest EdgeDB.DateDuration

skip_before(version: 2)
doctest EdgeDB.Range

defp drop_tickets(client) do
EdgeDB.query!(client, "delete Ticket")

Expand Down
70 changes: 63 additions & 7 deletions test/edgedb/protocol/codecs/range_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,66 @@ defmodule Tests.EdgeDB.Protocol.Codecs.RangeTest do
skip_before(version: 2, scope: :module)

@input_ranges %{
"range<int32>" => [
EdgeDB.Range.new(1, 2),
{EdgeDB.Range.new(1, 2, inc_upper: true), EdgeDB.Range.new(1, 3)},
EdgeDB.Range.empty(),
{EdgeDB.Range.new(1, 1), EdgeDB.Range.empty()},
EdgeDB.Range.new(nil, nil)
],
"range<int64>" => [
EdgeDB.Range.new(1, 2, inc_lower: true, inc_upper: false),
{EdgeDB.Range.new(1, 2, inc_lower: true, inc_upper: true),
EdgeDB.Range.new(1, 3, inc_lower: true, inc_upper: false)},
EdgeDB.Range.new(1, 2),
{EdgeDB.Range.new(1, 2, inc_upper: true), EdgeDB.Range.new(1, 3)},
EdgeDB.Range.empty(),
{EdgeDB.Range.new(1, 1), EdgeDB.Range.empty()},
EdgeDB.Range.new(nil, nil)
],
"range<float32>" => [
EdgeDB.Range.new(1.5, 2.5),
{EdgeDB.Range.new(1.5, 2.5, inc_upper: true), EdgeDB.Range.new(1.5, 2.5, inc_upper: true)},
EdgeDB.Range.empty(),
{EdgeDB.Range.new(1.5, 1.5), EdgeDB.Range.empty()},
EdgeDB.Range.new(nil, nil)
],
"range<float64>" => [
EdgeDB.Range.new(1.5, 2.5),
{EdgeDB.Range.new(1.5, 2.5, inc_upper: true), EdgeDB.Range.new(1.5, 2.5, inc_upper: true)},
EdgeDB.Range.empty(),
{EdgeDB.Range.new(1.5, 1.5), EdgeDB.Range.empty()},
EdgeDB.Range.new(nil, nil)
],
"range<decimal>" => [
EdgeDB.Range.new(Decimal.new(1), Decimal.new(2)),
{EdgeDB.Range.new(Decimal.new(1), Decimal.new(2), inc_upper: true),
EdgeDB.Range.new(Decimal.new(1), Decimal.new(2), inc_upper: true)},
EdgeDB.Range.empty(),
{EdgeDB.Range.new(Decimal.new(1), Decimal.new(1)), EdgeDB.Range.empty()},
EdgeDB.Range.new(nil, nil)
],
"range<datetime>" => [
EdgeDB.Range.new(~U[2022-07-01 00:00:00Z], ~U[2022-12-01 00:00:00Z]),
{EdgeDB.Range.new(~U[2022-07-01 00:00:00Z], ~U[2022-12-01 00:00:00Z], inc_upper: true),
EdgeDB.Range.new(~U[2022-07-01 00:00:00Z], ~U[2022-12-01 00:00:00Z], inc_upper: true)},
EdgeDB.Range.empty(),
{EdgeDB.Range.new(~U[2022-07-01 00:00:00Z], ~U[2022-07-01 00:00:00Z]),
EdgeDB.Range.empty()},
EdgeDB.Range.new(nil, nil)
],
"range<cal::local_datetime>" => [
EdgeDB.Range.new(~N[2022-07-01 00:00:00Z], ~N[2022-12-01 00:00:00Z]),
{EdgeDB.Range.new(~N[2022-07-01 00:00:00Z], ~N[2022-12-01 00:00:00Z], inc_upper: true),
EdgeDB.Range.new(~N[2022-07-01 00:00:00Z], ~N[2022-12-01 00:00:00Z], inc_upper: true)},
EdgeDB.Range.empty(),
{EdgeDB.Range.new(~N[2022-07-01 00:00:00Z], ~N[2022-07-01 00:00:00Z]),
EdgeDB.Range.empty()},
EdgeDB.Range.new(nil, nil)
],
"range<cal::local_date>" => [
EdgeDB.Range.new(~D[2022-07-01], ~D[2022-12-01]),
{EdgeDB.Range.new(~D[2022-07-01], ~D[2022-12-01], inc_upper: true),
EdgeDB.Range.new(~D[2022-07-01], ~D[2022-12-02])},
EdgeDB.Range.empty(),
{EdgeDB.Range.new(1, 1, inc_lower: true, inc_upper: false), EdgeDB.Range.empty()},
{EdgeDB.Range.new(~D[2022-07-01], ~D[2022-07-01]), EdgeDB.Range.empty()},
EdgeDB.Range.new(nil, nil)
]
}
Expand Down Expand Up @@ -73,10 +127,12 @@ defmodule Tests.EdgeDB.Protocol.Codecs.RangeTest do
{value, value}
end

test "encoding #{inspect(input)} as #{inspect(type)} with expecting #{inspect(output)} in the end",
test "encoding #{inspect(input)} as #{inspect(type)} with expecting #{inspect(output)} as the result",
%{client: client} do
value = "value"
assert ^value = EdgeDB.query_single!(client, "select <short_str>$0", [value])
type = unquote(type)
input = unquote(Macro.escape(input))
output = unquote(Macro.escape(output))
assert ^output = EdgeDB.query_single!(client, "select <#{type}>$0", [input])
end
end
end
Expand Down

0 comments on commit b5f5028

Please sign in to comment.