range.ex (3019B)
1 defmodule Postgrex.Extensions.Range do 2 @moduledoc false 3 import Postgrex.BinaryUtils, warn: false 4 import Bitwise 5 @behaviour Postgrex.SuperExtension 6 7 @range_empty 0x01 8 @range_lb_inc 0x02 9 @range_ub_inc 0x04 10 @range_lb_inf 0x08 11 @range_ub_inf 0x10 12 13 def init(_), do: nil 14 15 def matching(_), do: [send: "range_send"] 16 17 def format(_), do: :super_binary 18 19 def oids(%Postgrex.TypeInfo{base_type: base_oid}, _) do 20 [base_oid] 21 end 22 23 def encode(_) do 24 quote location: :keep do 25 %Postgrex.Range{lower: lower, upper: upper} = range, [oid], [type] -> 26 # encode_value/2 defined by TypeModule 27 lower = if is_atom(lower), do: lower, else: encode_value(lower, type) 28 upper = if is_atom(upper), do: upper, else: encode_value(upper, type) 29 unquote(__MODULE__).encode(range, oid, lower, upper) 30 31 other, _, _ -> 32 raise DBConnection.EncodeError, Postgrex.Utils.encode_msg(other, Postgrex.Range) 33 end 34 end 35 36 def decode(_) do 37 quote location: :keep do 38 <<len::int32(), binary::binary-size(len)>>, [oid], [type] -> 39 <<flags, data::binary>> = binary 40 # decode_list/2 defined by TypeModule 41 case decode_list(data, type) do 42 [upper, lower] -> 43 unquote(__MODULE__).decode(flags, oid, [lower, upper]) 44 45 empty_or_one -> 46 unquote(__MODULE__).decode(flags, oid, empty_or_one) 47 end 48 end 49 end 50 51 ## Helpers 52 53 def encode(_range, _oid, :empty, :empty) do 54 [<<1::int32(), @range_empty>>] 55 end 56 57 def encode(%{lower_inclusive: lower_inc, upper_inclusive: upper_inc}, _oid, lower, upper) do 58 flags = 0 59 60 {flags, data} = 61 if is_atom(lower) do 62 {flags ||| @range_lb_inf, []} 63 else 64 {flags, lower} 65 end 66 67 {flags, data} = 68 if is_atom(upper) do 69 {flags ||| @range_ub_inf, data} 70 else 71 {flags, [data | upper]} 72 end 73 74 flags = 75 case lower_inc do 76 true -> flags ||| @range_lb_inc 77 false -> flags 78 end 79 80 flags = 81 case upper_inc do 82 true -> flags ||| @range_ub_inc 83 false -> flags 84 end 85 86 [<<IO.iodata_length(data) + 1::int32()>>, flags | data] 87 end 88 89 def decode(flags, _oid, []) when (flags &&& @range_empty) != 0 do 90 %Postgrex.Range{ 91 lower: :empty, 92 upper: :empty, 93 lower_inclusive: false, 94 upper_inclusive: false 95 } 96 end 97 98 def decode(flags, _oid, elems) do 99 {lower, elems} = 100 if (flags &&& @range_lb_inf) != 0 do 101 {:unbound, elems} 102 else 103 [lower | rest] = elems 104 {lower, rest} 105 end 106 107 {upper, []} = 108 if (flags &&& @range_ub_inf) != 0 do 109 {:unbound, elems} 110 else 111 [upper | rest] = elems 112 {upper, rest} 113 end 114 115 lower_inclusive? = (flags &&& @range_lb_inc) != 0 116 upper_inclusive? = (flags &&& @range_ub_inc) != 0 117 118 %Postgrex.Range{ 119 lower: lower, 120 upper: upper, 121 lower_inclusive: lower_inclusive?, 122 upper_inclusive: upper_inclusive? 123 } 124 end 125 end