defmodule Postgrex.Extensions.Range do @moduledoc false alias Postgrex.TypeInfo alias Postgrex.Types import Postgrex.BinaryUtils use Postgrex.BinaryExtension, [] # send: "range_send" hard coded in types use Bitwise, only_operators: true @range_empty 0x01 @range_lb_inc 0x02 @range_ub_inc 0x04 @range_lb_inf 0x08 @range_ub_inf 0x10 def encode(%TypeInfo{base_type: oid}, %Postgrex.Range{} = range, types, _), do: encode_range(range, oid, types) def encode(type_info, value, _, _) do raise ArgumentError, Postgrex.Utils.encode_msg(type_info, value, Postgrex.Range) end def decode(%TypeInfo{base_type: oid}, bin, types, _), do: decode_range(bin, oid, types) ## Helpers defp encode_range(%Postgrex.Range{lower: nil, upper: nil}, _oid, _types) do <<@range_empty>> end defp encode_range(range, oid, types) do flags = 0 {flags, bin} = if range.lower == nil do {flags ||| @range_lb_inf, ""} else data = Types.encode(oid, range.lower, types) {flags, [<>, data]} end {flags, bin} = if range.upper == nil do {flags ||| @range_ub_inf, bin} else data = Types.encode(oid, range.upper, types) {flags, [bin, <>, data]} end flags = if range.lower_inclusive do flags ||| @range_lb_inc else flags end flags = if range.upper_inclusive do flags ||| @range_ub_inc else flags end [flags|bin] end defp decode_range(<>, _oid, _types) when (flags &&& @range_empty) != 0 do %Postgrex.Range{} end defp decode_range(<>, oid, types) do {lower, rest} = if (flags &&& @range_lb_inf) != 0 do {nil, rest} else <> = rest {Types.decode(oid, lower, types), rest} end {upper, rest} = if (flags &&& @range_ub_inf) != 0 do {nil, rest} else <> = rest {Types.decode(oid, upper, types), rest} end "" = rest lower_inclusive = (flags &&& @range_lb_inc) != 0 upper_inclusive = (flags &&& @range_ub_inc) != 0 %Postgrex.Range{lower: lower, upper: upper, lower_inclusive: lower_inclusive, upper_inclusive: upper_inclusive} end end