-
Notifications
You must be signed in to change notification settings - Fork 142
/
parser.ex
158 lines (123 loc) · 3.63 KB
/
parser.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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
defmodule EventStore.Config.Parser do
@moduledoc false
@config_defaults [
column_data_type: "bytea",
enable_hard_deletes: false,
schema: "public",
timeout: 15_000
]
def parse(config) do
config
|> Enum.reduce(@config_defaults, fn
{:port, value}, config ->
Keyword.put(config, :port, get_config_integer(value))
{:session_mode_url, value}, config ->
parsed_value = get_config_value(value) |> parse_url()
Keyword.put(config, :session_mode_pool, parsed_value)
{:timeout, value}, config ->
Keyword.put(config, :timeout, get_config_timeout(value))
{:url, value}, config ->
parsed_value = get_config_value(value) |> parse_url()
Keyword.merge(config, parsed_value)
{key, value}, config ->
Keyword.put(config, key, get_config_value(value))
end)
|> Keyword.put(:pool, EventStore.Config.get_pool())
end
# Converts a database url into a Keyword list
defp parse_url(url)
defp parse_url(""), do: []
defp parse_url(url) do
info = URI.parse(url)
if is_nil(info.host) do
raise ArgumentError, message: "host is not present"
end
if is_nil(info.path) or not (info.path =~ ~r"^/([^/])+$") do
raise ArgumentError, message: "path should be a database name"
end
destructure [username, password], info.userinfo && String.split(info.userinfo, ":")
"/" <> database = info.path
opts =
Enum.reject(
[
username: username,
password: password,
database: database,
hostname: info.host,
port: info.port
],
fn {_k, v} -> is_nil(v) end
)
query_opts = parse_uri_query(info)
for {k, v} <- opts ++ query_opts,
not is_nil(v),
do: {k, if(is_binary(v), do: URI.decode(v), else: v)}
end
defp parse_uri_query(%URI{query: nil}), do: []
defp parse_uri_query(%URI{query: query}) do
query
|> URI.query_decoder()
|> Enum.reduce([], fn
{"ssl", "true"}, acc ->
[{:ssl, true} | acc]
{"ssl", "false"}, acc ->
[{:ssl, false} | acc]
{key, value}, acc when key in ["pool_size", "queue_target", "queue_interval", "timeout"] ->
[{String.to_atom(key), parse_integer!(key, value)} | acc]
{key, _value}, _acc ->
raise ArgumentError, message: "unsupported query parameter `#{key}`"
end)
end
defp parse_integer!(key, value) do
case Integer.parse(value) do
{int, ""} ->
int
_ ->
raise ArgumentError,
message: "can not parse value `#{value}` for parameter `#{key}` as an integer"
end
end
defp get_config_value(value, default \\ nil)
defp get_config_value({:system, env_var}, default) do
case System.get_env(env_var) do
nil -> default
val -> val
end
end
defp get_config_value({:system, env_var, default}, _default) do
case System.get_env(env_var) do
nil -> default
val -> val
end
end
defp get_config_value(nil, default), do: default
defp get_config_value(value, _default), do: value
defp get_config_integer(value, default \\ nil) do
case get_config_value(value) do
nil ->
default
n when is_integer(n) ->
n
n ->
case Integer.parse(n) do
{i, _} -> i
:error -> default
end
end
end
defp get_config_timeout(value, default \\ nil) do
case get_config_value(value) do
nil ->
default
:infinity ->
:infinity
n when is_integer(n) ->
n
n ->
case Integer.parse(n) do
{i, _} -> i
:error -> default
end
end
end
end