Packages
postgrex
0.13.0
1.0.0-rc.1
retired
1.0.0-rc.0
retired
0.22.3
0.22.2
0.22.1
0.22.0
0.21.1
0.21.0
0.20.0
0.19.3
0.19.2
0.19.1
0.19.0
0.18.0
0.17.5
0.17.4
0.17.3
0.17.2
0.17.1
0.17.0
0.16.5
0.16.4
0.16.3
0.16.2
0.16.1
0.16.0
0.15.13
0.15.12
0.15.11
0.15.10
0.15.9
0.15.8
0.15.7
0.15.6
0.15.5
0.15.4
0.15.3
0.15.2
0.15.1
0.15.0
0.14.3
0.14.2
0.14.1
0.14.0
0.14.0-rc.1
0.14.0-rc.0
0.13.5
0.13.4
0.13.3
0.13.2
0.13.1
0.13.0
0.13.0-rc.0
0.12.2
0.12.1
0.12.0
0.11.2
0.11.1
0.11.0
0.10.0
0.9.1
0.9.0
0.8.4
0.8.3
0.8.2
0.8.1
0.8.0
0.7.0
0.6.0
0.5.5
0.5.4
0.5.3
0.5.2
0.5.1
0.5.0
0.4.2
PostgreSQL driver for Elixir
Current section
Files
Jump to
Current section
Files
lib/postgrex/extensions/hstore.ex
defmodule Postgrex.Extensions.HStore do
@moduledoc false
import Postgrex.BinaryUtils, warn: false
use Postgrex.BinaryExtension, type: "hstore"
def init(opts), do: Keyword.fetch!(opts, :decode_binary)
def encode(_) do
quote location: :keep do
%{} = map ->
data = unquote(__MODULE__).encode_hstore(map)
[<<IO.iodata_length(data) :: int32>> | data]
other ->
raise ArgumentError, Postgrex.Utils.encode_msg(other, "a map")
end
end
def decode(mode) do
quote do
<<len :: int32, data :: binary-size(len)>> ->
unquote(__MODULE__).decode_hstore(data, unquote(mode))
end
end
## Helpers
def encode_hstore(hstore_map) do
keys_and_values = Enum.reduce hstore_map, "", fn ({key, value}, acc) ->
[acc, encode_hstore_key(key), encode_hstore_value(value)]
end
[<<Map.size(hstore_map)::int32>> | keys_and_values]
end
defp encode_hstore_key(key) when is_binary(key) do
encode_hstore_value key
end
defp encode_hstore_key(key) when is_nil(key) do
raise ArgumentError, "hstore keys cannot be nil!"
end
defp encode_hstore_value(nil) do
<<-1::int32>>
end
defp encode_hstore_value(value) when is_binary(value) do
value_byte_size = byte_size(value)
<<value_byte_size::int32>> <> value
end
def decode_hstore(<<_length::int32, pairs::binary>>, :reference) do
decode_hstore_ref(pairs, %{})
end
def decode_hstore(<<_length::int32, pairs::binary>>, :copy) do
decode_hstore_copy(pairs, %{})
end
defp decode_hstore_ref(<<>>, acc) do
acc
end
# in the case of a NULL value, there won't be a length
defp decode_hstore_ref(<<key_length::int32, key::binary(key_length),
-1::int32, rest::binary>>, acc) do
decode_hstore_ref(rest, Map.put(acc, key, nil))
end
defp decode_hstore_ref(<<key_length::int32, key::binary(key_length),
value_length::int32, value::binary(value_length), rest::binary>>, acc) do
decode_hstore_ref(rest, Map.put(acc, key, value))
end
defp decode_hstore_copy(<<>>, acc) do
acc
end
# in the case of a NULL value, there won't be a length
defp decode_hstore_copy(<<key_length::int32, key::binary(key_length),
-1::int32, rest::binary>>, acc) do
decode_hstore_copy(rest, Map.put(acc, :binary.copy(key), nil))
end
defp decode_hstore_copy(<<key_length::int32, key::binary(key_length),
value_length::int32, value::binary(value_length), rest::binary>>, acc) do
decode_hstore_copy(rest, Map.put(acc, :binary.copy(key), :binary.copy(value)))
end
end