/
types.ex
113 lines (94 loc) · 2.93 KB
/
types.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
defmodule WalEx.Types do
@moduledoc """
Cast from Postgres to Elixir types
"""
def cast_record("t", "bool"), do: true
def cast_record("f", "bool"), do: false
def cast_record(record, <<"int", _::binary>>) when is_binary(record) do
case Integer.parse(record) do
{int, _} ->
int
:error ->
record
end
end
def cast_record(record, <<"float", _::binary>>) when is_binary(record) do
case Float.parse(record) do
{float, _} ->
float
:error ->
record
end
end
def cast_record(record, "numeric") when is_binary(record), do: Decimal.new(record)
def cast_record(record, "decimal"), do: cast_record(record, "numeric")
def cast_record(record, "timestamp") when is_binary(record) do
with {:ok, %NaiveDateTime{} = naive_date_time} <- Timex.parse(record, "{RFC3339}"),
%DateTime{} = date_time <- Timex.to_datetime(naive_date_time) do
date_time
else
_ -> record
end
end
def cast_record(record, "timestamptz") when is_binary(record) do
case Timex.parse(record, "{RFC3339}") do
{:ok, %DateTime{} = date_time} ->
date_time
_ ->
record
end
end
def cast_record(record, "jsonb") when is_binary(record) do
case Jason.decode(record) do
{:ok, json} ->
json
_ ->
record
end
end
# TODO: Add additional type castings and ability to load external types
def cast_record(record, _column_type) do
record
end
# defp cast_record(record, "int2") when is_binary(record), do: String.to_integer(record)
# defp cast_record(record, "int4") when is_binary(record), do: String.to_integer(record)
# defp cast_record(record, "int8") when is_binary(record), do: String.to_integer(record)
# defp cast_record(record, "numeric") when is_binary(record) do
# if String.contains?(record, ".") do
# String.to_float(record)
# else
# String.to_integer(record)
# end
# end
# defp cast_record(record, "json") when is_binary(record) do
# case Jason.decode(record) do
# {:ok, json} ->
# Jason.decode!(json)
# _ ->
# record
# end
# end
# # Integer Array - this assumes a single non-nested array
# # This is brittle, I imagine there's a safer way to handle arrays..
# defp cast_record(<<123>> <> record, "_int4") when is_binary(record) do
# record
# |> String.replace(["{", "}"], "")
# |> String.split(",")
# |> Enum.map(&String.to_integer/1)
# end
# # Text Array - this assumes a single non-nested array
# defp cast_record(<<123>> <> record, "_text") when is_binary(record) do
# record
# |> String.replace(["{", "}"], "")
# |> String.split(",")
# end
# # TODO: Create a dynamic function that can take custom decoders
# defp cast_record(record, "geography") when is_binary(record) do
# case Geo.WKB.decode(record) do
# {:ok, geo} ->
# geo
# _ ->
# record
# end
# end
end