tsvector.ex (2075B)
1 defmodule Postgrex.Extensions.TSVector do 2 @moduledoc false 3 4 import Postgrex.BinaryUtils, warn: false 5 use Postgrex.BinaryExtension, send: "tsvectorsend" 6 7 def encode(_) do 8 quote location: :keep do 9 values when is_list(values) -> 10 encoded_tsvectors = unquote(__MODULE__).encode_tsvector(values) 11 <<byte_size(encoded_tsvectors)::int32(), encoded_tsvectors::binary>> 12 13 other -> 14 raise DBConnection.EncodeError, Postgrex.Utils.encode_msg(other, "a list of tsvectors") 15 end 16 end 17 18 def decode(_) do 19 quote do 20 <<len::int32(), value::binary-size(len)>> -> 21 <<nb_lexemes::int32(), words::binary>> = value 22 unquote(__MODULE__).decode_tsvector_values(words) 23 end 24 end 25 26 ## Helpers 27 28 def encode_tsvector(values) do 29 <<length(values)::int32(), encode_lexemes(values)::binary>> 30 end 31 32 defp encode_lexemes(values) do 33 values |> Enum.map(fn x -> encode_positions(x) end) |> IO.iodata_to_binary() 34 end 35 36 defp encode_positions(%Postgrex.Lexeme{word: word, positions: positions}) do 37 positions = 38 Enum.map(positions, fn {position, weight} -> 39 <<encode_weight_binary(weight)::2, position::14>> 40 end) 41 42 [word, 0, <<length(positions)::16>> | positions] 43 end 44 45 def decode_tsvector_values("") do 46 [] 47 end 48 49 def decode_tsvector_values(words) do 50 [word, <<positions_count::16, rest::binary>>] = :binary.split(words, <<0>>) 51 positions_bytes = positions_count * 2 52 <<positions::binary-size(positions_bytes), remaining_data::binary>> = rest 53 54 positions = 55 for <<weight::2, position::14 <- positions>>, do: {position, decode_weight(weight)} 56 57 [%Postgrex.Lexeme{word: word, positions: positions} | decode_tsvector_values(remaining_data)] 58 end 59 60 defp encode_weight_binary(:A) do 61 3 62 end 63 64 defp encode_weight_binary(:B) do 65 2 66 end 67 68 defp encode_weight_binary(:C) do 69 1 70 end 71 72 defp encode_weight_binary(nil) do 73 0 74 end 75 76 defp decode_weight(0), do: nil 77 defp decode_weight(1), do: :C 78 defp decode_weight(2), do: :B 79 defp decode_weight(3), do: :A 80 end