Skip to content

Commit 6415660

Browse files
committed
Tighten marina error types to documented sum
Three correctness sweeps in one commit, no behaviour changes: 1. error/0 was {error, term()}, which gave dialyzer nothing. Replace with {error, error_reason()} where error_reason/0 enumerates: - marina_pool_not_started, timeout (marina-level) - cql_error() = {pos_integer(), binary()} (server-side CQL error) - no_server, pool_not_started, shackle_not_started (shackle) cql_error/0 exported so callers can match against it cleanly. 2. marina_body:decode/1 said it returned {error, atom()} but the actual return is {error, {Code, Msg}}. Spec was wrong; dialyzer silently accepted it because no caller destructured. Fixed to {error, cql_error()}. 3. Four marina_types specs were wrong about null handling: - decode_short_bytes/1 and decode_string/1 can return {null, binary()} on the 0xFFFF sentinel. - encode_bytes/1 and encode_short_bytes/1 accept null as input. The functions handled null correctly already -- the specs just lied about the contract. Existing callers continue to work; dialyzer now catches {error, typo} at call sites.
1 parent 147d061 commit 6415660

5 files changed

Lines changed: 53 additions & 7 deletions

File tree

CHANGELOG.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,43 @@
11
# Changelog
22

3+
## 0.4.5
4+
5+
### Changed
6+
7+
- `error/0` is now `{error, error_reason()}` where `error_reason/0`
8+
is a documented sum type — was `{error, term()}`, which gave
9+
dialyzer nothing to check at call sites. The sum covers:
10+
11+
- `marina_pool_not_started` and `timeout` (marina-level)
12+
- `cql_error()``{Code :: pos_integer(), Msg :: binary()}`, the
13+
Cassandra/Scylla server-side error tuple
14+
- `no_server`, `pool_not_started`, `shackle_not_started` (shackle
15+
errors that propagate through marina)
16+
17+
`cql_error/0` is exported as a public type so callers can pattern-
18+
match against it cleanly.
19+
20+
- `marina_body:decode/1` spec corrected: was `{error, atom()}`,
21+
is actually `{error, cql_error()}` — the `{Code, Msg}` shape was
22+
documented but the spec contradicted it. Real bug; dialyzer
23+
was silently accepting `atom()` because no caller was destructuring.
24+
25+
- Four `marina_types` spec corrections (real correctness bugs, not
26+
just imprecision):
27+
28+
- `decode_short_bytes/1` and `decode_string/1` can return
29+
`{null, binary()}` on the 0xFFFF sentinel; specs claimed
30+
`{binary(), binary()}`.
31+
- `encode_bytes/1` and `encode_short_bytes/1` accept `null` as
32+
input (encoded as the sentinel); specs claimed `binary()` only.
33+
34+
No behavioural change — the functions handled `null` correctly
35+
already, the specs just lied about it.
36+
37+
No source changes beyond the type tightening; existing callers
38+
continue to work unchanged. Dialyzer now flags `{error, typo}`
39+
at call sites that don't match the sum.
40+
341
## 0.4.4
442

543
### Added

include/marina.hrl

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,15 @@
6464
-type batch_query() ::
6565
{query, query(), values()} |
6666
{prepared, statement_id(), values()}.
67-
-type error() :: {error, term()}.
67+
-type cql_error() :: {pos_integer(), binary()}.
68+
-type error_reason() ::
69+
%% marina-level
70+
marina_pool_not_started | timeout |
71+
%% Cassandra/Scylla server-side error: {Code, Msg}
72+
cql_error() |
73+
%% shackle errors that propagate through marina
74+
no_server | pool_not_started | shackle_not_started.
75+
-type error() :: {error, error_reason()}.
6876
-type frame() :: #frame {}.
6977
-type frame_flag() :: 0..1.
7078
-type query() :: binary().

src/marina.app.src

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{application, marina, [
22
{description, "High-Performance Erlang Cassandra / Scylla CQL Client"},
3-
{vsn, "0.4.4"},
3+
{vsn, "0.4.5"},
44
{registered, []},
55
{applications, [
66
kernel,

src/marina_body.erl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
]).
1010

1111
%% public
12-
-spec decode(frame()) -> {ok, term()} | {error, atom()}.
12+
-spec decode(frame()) -> {ok, term()} | {error, cql_error()}.
1313

1414
decode(#frame {flags = Flags, body = Body, opcode = Opcode}) ->
1515
Body1 = maybe_decompress(Flags, Body),

src/marina_types.erl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,14 +86,14 @@ decode_number_list(<<Length:32, Rest/binary>>) ->
8686
decode_short(<<Value:16/signed, Rest/binary>>) ->
8787
{Value, Rest}.
8888

89-
-spec decode_short_bytes(binary()) -> {binary(), binary()}.
89+
-spec decode_short_bytes(binary()) -> {null | binary(), binary()}.
9090

9191
decode_short_bytes(<<255, 255, Rest/binary>>) ->
9292
{null, Rest};
9393
decode_short_bytes(<<Pos:16, Value:Pos/binary, Rest/binary>>) ->
9494
{Value, Rest}.
9595

96-
-spec decode_string(binary()) -> {binary(), binary()}.
96+
-spec decode_string(binary()) -> {null | binary(), binary()}.
9797

9898
decode_string(Bin) ->
9999
decode_short_bytes(Bin).
@@ -128,7 +128,7 @@ decode_uuid(<<Value:16/binary, Rest/binary>>) ->
128128
encode_boolean(false) -> <<0>>;
129129
encode_boolean(true) -> <<1>>.
130130

131-
-spec encode_bytes(binary()) -> binary().
131+
-spec encode_bytes(null | binary()) -> binary().
132132

133133
encode_bytes(null) ->
134134
<<255, 255, 255, 255>>;
@@ -169,7 +169,7 @@ encode_long_string(Value) ->
169169
encode_short(Value) ->
170170
<<Value:16/signed>>.
171171

172-
-spec encode_short_bytes(binary()) -> binary().
172+
-spec encode_short_bytes(null | binary()) -> binary().
173173

174174
encode_short_bytes(null) ->
175175
<<255, 255>>;

0 commit comments

Comments
 (0)