/
codec_storage.ex
126 lines (105 loc) · 2.6 KB
/
codec_storage.ex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
defmodule EdgeDB.Protocol.CodecStorage do
@moduledoc since: "0.2.0"
@moduledoc """
A storage for each codec that the connection knows how to decode.
"""
import EdgeDB.Protocol.Converters
alias EdgeDB.Protocol.{
Codec,
Codecs
}
@typedoc """
A storage for each codec that the connection knows how to decode.
"""
@type t() :: :ets.tab()
@known_base_codecs [
Codecs.UUID,
Codecs.Str,
Codecs.Bytes,
Codecs.Int16,
Codecs.Int32,
Codecs.Int64,
Codecs.Float32,
Codecs.Float64,
Codecs.Decimal,
Codecs.Bool,
Codecs.DateTime,
Codecs.Duration,
Codecs.LocalDateTime,
Codecs.LocalDate,
Codecs.LocalTime,
Codecs.JSON,
Codecs.BigInt,
Codecs.RelativeDuration,
Codecs.ConfigMemory,
Codecs.DateDuration,
Codecs.Vector,
# special case
Codecs.Null
]
@null_codec_id <<0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0>>
@doc false
@spec new() :: t()
def new do
storage = :ets.new(:codec_storage, [:set, :public, {:read_concurrency, true}])
register_base_scalar_codecs(storage)
storage
end
@doc false
@spec null_codec_id() :: binary()
def null_codec_id do
@null_codec_id
end
@doc """
Find a codec in the storage by ID.
"""
@spec get(t(), binary()) :: Codec.t() | nil
def get(storage, id) do
case :ets.lookup(storage, id) do
[{^id, codec}] ->
codec
[] ->
nil
end
end
@doc """
Find a codec in the storage by type name.
"""
@spec get_by_name(t(), binary()) :: Codec.t() | nil
def get_by_name(storage, name) do
# created with Ex2ms
# fun do {idx, %{name: name}} = result when name == ^name -> result end
match_spec = [{{:"$1", %{name: :"$2"}}, [{:==, :"$2", name}], [:"$_"]}]
case :ets.select(storage, match_spec) do
[{_id, %{name: ^name} = codec}] ->
codec
[] ->
nil
end
end
@doc false
@spec add(t(), bitstring() | binary(), Codec.t()) :: :ok
def add(storage, <<id::uuid()>>, codec) do
add_codec(storage, id, codec)
end
def add(storage, id, codec) do
add_codec(storage, UUID.string_to_binary!(id), codec)
end
@doc false
@spec update(t(), binary(), map()) :: :ok
def update(storage, id, updates) do
if codec = get(storage, id) do
add_codec(storage, id, Map.merge(codec, updates))
end
:ok
end
defp add_codec(storage, id, codec) do
:ets.insert(storage, {id, codec})
:ok
end
defp register_base_scalar_codecs(storage) do
Enum.each(@known_base_codecs, fn codec_mod ->
add_codec(storage, codec_mod.id(), codec_mod.new())
end)
end
end