• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

supabase / supavisor / 16470769502

23 Jul 2025 12:34PM UTC coverage: 57.067% (+1.7%) from 55.355%
16470769502

Pull #694

github

web-flow
Merge 78a9c0b2c into deaa48192
Pull Request #694: feat: improved named prepared statements support

175 of 217 new or added lines in 11 files covered. (80.65%)

16 existing lines in 4 files now uncovered.

1292 of 2264 relevant lines covered (57.07%)

1126.08 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/lib/supavisor/protocol/client.ex
1
defmodule Supavisor.Protocol.Client do
2
  @moduledoc false
3

4
  require Logger
5

6
  @pkt_header_size 5
7

8
  defmodule Pkt do
9
    @moduledoc false
10
    defstruct([:tag, :len, :payload, :bin])
11

12
    @type t :: %Pkt{
13
            tag: atom,
14
            len: integer,
15
            payload: any,
16
            bin: binary
17
          }
18
  end
19

20
  def pkt_header_size, do: @pkt_header_size
×
21

22
  def header(<<char::8, pkt_len::32>>) do
×
23
    {tag(char), pkt_len}
24
  end
25

26
  @spec decode(binary) :: {:ok, [Pkt.t()], binary} | {:error, any}
27
  def decode(data) do
28
    decode(data, [])
×
29
  end
30

31
  @spec decode(binary, [Pkt.t()]) :: {:ok, [Pkt.t()], binary} | {:error, any}
32
  def decode("", acc), do: {:ok, Enum.reverse(acc), ""}
×
33

34
  def decode(data, acc) do
35
    case decode_pkt(data) do
×
36
      {:ok, pkt, rest} -> decode(rest, [pkt | acc])
×
37
      {:error, :payload_too_small} -> {:ok, Enum.reverse(acc), data}
×
38
    end
39
  end
40

41
  @spec decode_pkt(binary) ::
42
          {:ok, Pkt.t(), binary}
43
          | {:acc, nil, binary}
44
          | {:error, :payload_too_small}
45
  def decode_pkt(<<_::8, pkt_len::32, payload::binary>>)
×
46
      when byte_size(payload) < pkt_len - 4 do
47
    {:error, :payload_too_small}
48
  end
49

50
  def decode_pkt(<<char::8, pkt_len::32, rest::binary>>) do
51
    case tag(char) do
×
52
      nil ->
×
53
        {:error, {:undefined_tag, <<char>>}}
54

55
      tag ->
56
        payload_len = pkt_len - 4
×
57
        <<bin_payload::binary-size(payload_len), rest2::binary>> = rest
×
58

59
        {:ok,
×
60
         %Pkt{
61
           tag: tag,
62
           len: pkt_len + 1,
63
           payload: decode_payload(tag, bin_payload),
64
           bin: <<char, pkt_len::32, bin_payload::binary>>
65
         }, rest2}
66
    end
67
  end
68

69
  def decode_pkt(_), do: {:error, :header_mismatch}
×
70

71
  @spec get_payload(binary | any()) :: {:ok, String.t()} | {:error, any}
72
  def get_payload(<<char::8, pkt_len::32, rest::binary>>) do
UNCOV
73
    case tag(char) do
×
UNCOV
74
      nil ->
×
75
        {:error, {:undefined_tag, <<char>>}}
76

77
      tag ->
UNCOV
78
        try do
×
UNCOV
79
          payload_len = pkt_len - 4
×
UNCOV
80
          <<bin_payload::binary-size(payload_len), _::binary>> = rest
×
81

82
          {:ok, decode_payload(tag, bin_payload)}
83
        rescue
UNCOV
84
          reason ->
×
85
            {:error, {:decode_payload_error, reason}}
86
        end
87
    end
88
  end
89

90
  def get_payload(msg), do: {:error, {:invalid_msg, msg}}
×
91

92
  @spec tag(byte) :: atom | nil
93
  def tag(char) do
UNCOV
94
    case char do
×
UNCOV
95
      ?Q -> :simple_query
×
96
      ?H -> :flush_message
×
UNCOV
97
      ?P -> :parse_message
×
98
      ?B -> :bind_message
×
99
      ?D -> :describe_message
×
100
      ?E -> :execute_message
×
101
      ?S -> :sync_message
×
102
      ?X -> :termination_message
×
103
      ?C -> :close_message
×
NEW
104
      ?d -> :copy_data
×
NEW
105
      ?c -> :copy_done
×
NEW
106
      ?f -> :copy_fail
×
UNCOV
107
      _ -> nil
×
108
    end
109
  end
110

111
  def decode_payload(:simple_query, payload) do
UNCOV
112
    case :binary.split(payload, <<0>>) do
×
UNCOV
113
      [query, ""] -> query
×
114
      _ -> :undefined
×
115
    end
116
  end
117

118
  def decode_payload(:parse_message, <<0>>), do: :undefined
×
119

120
  def decode_payload(:parse_message, payload) do
NEW
121
    [str_name, sql | _] = :binary.split(payload, <<0>>, [:global])
×
NEW
122
    %{str_name: str_name, sql: sql}
×
123
  end
124

125
  def decode_payload(:describe_message, <<char::binary-size(1), str_name::binary>>) do
126
    str_name = String.trim_trailing(str_name, <<0>>)
×
127
    %{char: char, str_name: str_name}
×
128
  end
129

130
  def decode_payload(:close_message, <<char::binary-size(1), str_name::binary>>) do
131
    str_name = String.trim_trailing(str_name, <<0>>)
×
132
    %{char: char, str_name: str_name}
×
133
  end
134

135
  def decode_payload(:flush_message, <<4::32>>), do: nil
×
136

137
  def decode_payload(:termination_message, _payload), do: nil
×
138

139
  def decode_payload(:bind_message, payload) do
NEW
140
    [_portal_name, rest] = :binary.split(payload, <<0>>)
×
NEW
141
    [statement_name, _rest] = :binary.split(rest, <<0>>)
×
142

NEW
143
    %{str_name: statement_name}
×
144
  end
145

NEW
146
  def decode_payload(:execute_message, _payload) do
×
147
    nil
148
  end
149

150
  def decode_payload(_tag, ""), do: nil
×
151

152
  def decode_payload(_tag, payload) do
153
    Logger.error("undefined payload: #{inspect(payload)}")
×
154
    :undefined
155
  end
156

157
  def decode_startup_packet(<<len::32, _protocol::binary-4, rest::binary>>) do
158
    # <<major::16, minor::16>> = protocol
159

160
    %Pkt{
×
161
      len: len,
162
      payload:
163
        String.split(rest, <<0>>, trim: true)
164
        |> Enum.chunk_every(2)
165
        |> Enum.into(%{}, fn [k, v] -> {k, v} end),
×
166
      tag: :startup
167
    }
168
  end
169

170
  def decode_startup_packet(_) do
×
171
    :undef
172
  end
173

174
  def parse_msg_sel_1 do
175
    <<80, 0, 0, 0, 16, 0, 115, 101, 108, 101, 99, 116, 32, 49, 0, 0, 0, 66, 0, 0, 0, 12, 0, 0, 0,
×
176
      0, 0, 0, 0, 0, 68, 0, 0, 0, 6, 80, 0, 69, 0, 0, 0, 9, 0, 0, 0, 0, 200, 83, 0, 0, 0, 4>>
177
  end
178
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc