_site/cover/pgec_kv.COVER.html

1 %% Copyright (c) 2023 Peter Morgan <peter.james.morgan@gmail.com>
2 %%
3 %% Licensed under the Apache License, Version 2.0 (the "License");
4 %% you may not use this file except in compliance with the License.
5 %% You may obtain a copy of the License at
6 %%
7 %% http://www.apache.org/licenses/LICENSE-2.0
8 %%
9 %% Unless required by applicable law or agreed to in writing, software
10 %% distributed under the License is distributed on an "AS IS" BASIS,
11 %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 %% See the License for the specific language governing permissions and
13 %% limitations under the License.
14
15
16 -module(pgec_kv).
17
18
19 -export([key/2]).
20 -export([keys/2]).
21 -export([row/2]).
22 -export([row/3]).
23 -export([row/4]).
24 -export([value/3]).
25 -include_lib("kernel/include/logger.hrl").
26
27
28 keys(#{keys := Positions, oids := Types}, Keys) ->
29 59 pgmp_data_row:decode(
30 #{<<"client_encoding">> => <<"UTF8">>},
31 lists:map(
32 fun
33 ({Encoded, KeyOID}) ->
34 59 {#{format => text, type_oid => KeyOID}, Encoded}
35 end,
36 lists:zip(
37 Keys,
38 lists:map(
39 fun
40 (Position) ->
41 59 lists:nth(Position, Types)
42 end,
43 Positions))),
44 pgmp_types:cache(pgec_util:db())).
45
46
47 key(#{keys := Positions} = Metadata, Keys)
48 when length(Positions) == length(Keys) ->
49 47 ?LOG_DEBUG(#{keys => Keys, metadata => Metadata}),
50
51 47 case keys(Metadata, Keys) of
52 [Primary] ->
53 47 Primary;
54
55 Composite ->
56
:-(
list_to_tuple(Composite)
57 end;
58
59 key(Metadata, Keys) ->
60
:-(
error(badarg, [Metadata, Keys]).
61
62
63 row(Metadata, ContentType) ->
64 2 ?LOG_DEBUG(
65 #{content_type => ContentType,
66 2 metadata => Metadata}),
67
68 2 fun
69 (Values, A) ->
70 2 ?LOG_DEBUG(#{values => Values, a => A}),
71 2 [?FUNCTION_NAME(Metadata, ContentType, Values) | A]
72 end.
73
74 row(Metadata, ContentType, Values) ->
75 27 ?FUNCTION_NAME(Metadata,
76 ContentType,
77 Values,
78 pgmp_types:cache(pgec_util:db())).
79
80
81 row(#{columns := Columns, oids := OIDS} = Metadata, ContentType, Values, Types) ->
82 33 ?LOG_DEBUG(#{metadata => Metadata,
83 content_type => ContentType,
84 33 values => Values}),
85 33 maps:from_list(
86 lists:zipwith3(
87 combine(ContentType, Types),
88 Columns,
89 OIDS,
90 tuple_to_list(Values))).
91
92
93 %% values(#{keys := [_]}, Values) ->
94 %% tuple_to_list(Values);
95
96 %% values(#{keys := KeyPositions}, CompositeWithValues) when is_tuple(CompositeWithValues) ->
97 %% [Composite | Values] = tuple_to_list(CompositeWithValues),
98 %% values(1, KeyPositions, tuple_to_list(Composite), Values).
99
100
101 %% values(_, [], [], Values) ->
102 %% Values;
103 %% values(_, _, Keys, []) ->
104 %% Keys;
105 %% values(Pos, [Pos | KeyPositions], [Key | Keys], Values) ->
106 %% [Key | ?FUNCTION_NAME(Pos + 1, KeyPositions, Keys, Values)];
107 %% values(Pos, KeyPositions, Keys, [Value | Values]) ->
108 %% [Value | ?FUNCTION_NAME(Pos + 1, KeyPositions, Keys, Values)].
109
110
111 combine(ContentType, Types) ->
112 33 fun
113 (Column, OID, Value) when is_map_key(OID, Types) ->
114 97 #{OID := ColumnType} = Types,
115 97 {Column, value(ContentType, ColumnType, Value)}
116 end.
117
118
119 value(<<"text/plain">> = ContentType,
120 ColumnType,
121 null = Value) ->
122 16 ?LOG_DEBUG(#{content_type => ContentType,
123 column_type => ColumnType,
124 16 value => Value}),
125 16 Value;
126
127 value(<<"text/plain">> = ContentType,
128 #{<<"typname">> := Name} = ColumnType,
129 Value) when Name == <<"int2">>;
130 Name == <<"int4">>;
131 Name == <<"int8">>;
132 Name == <<"money">> ->
133 22 ?LOG_DEBUG(#{content_type => ContentType,
134 column_type => ColumnType,
135 22 value => Value}),
136 22 integer_to_list(Value);
137
138 value(<<"text/plain">> = ContentType,
139 #{<<"typname">> := Name} = ColumnType,
140 Value) when Name == <<"numeric">>,
141 is_integer(Value) ->
142 1 ?LOG_DEBUG(#{content_type => ContentType,
143 column_type => ColumnType,
144 1 value => Value}),
145 1 integer_to_list(Value);
146
147 value(<<"text/plain">> = ContentType,
148 #{<<"typname">> := Name} = ColumnType,
149 Value) when Name == <<"numeric">>,
150 is_float(Value) ->
151 1 ?LOG_DEBUG(#{content_type => ContentType,
152 column_type => ColumnType,
153 1 value => Value}),
154 1 float_to_list(Value, [short]);
155
156 value(ContentType,
157 #{<<"typname">> := <<"float", _/bytes>>} = ColumnType,
158 Value) when Value == 'NaN';
159 Value == 'Infinity';
160 Value == '-Infinity' ->
161 3 ?LOG_DEBUG(#{content_type => ContentType,
162 column_type => ColumnType,
163 3 value => Value}),
164 3 atom_to_binary(Value);
165
166 value(<<"text/plain">> = ContentType,
167 #{<<"typname">> := <<"float", _/bytes>>} = ColumnType,
168 Value) when is_float(Value) ->
169 1 ?LOG_DEBUG(#{content_type => ContentType,
170 column_type => ColumnType,
171 1 value => Value}),
172 1 float_to_list(Value, [short]);
173
174 value(<<"text/plain">> = ContentType,
175 #{<<"typname">> := <<"float", _/bytes>>} = ColumnType,
176 Value) when is_integer(Value) ->
177
:-(
?LOG_DEBUG(#{content_type => ContentType,
178 column_type => ColumnType,
179
:-(
value => Value}),
180
:-(
integer_to_list(Value);
181
182 value(<<"text/plain">> = ContentType,
183 #{<<"typname">> := <<"bool">>} = ColumnType,
184 Value) ->
185 4 ?LOG_DEBUG(#{content_type => ContentType,
186 column_type => ColumnType,
187 4 value => Value}),
188 4 atom_to_list(Value);
189
190 value(<<"text/plain">> = ContentType,
191 #{<<"typname">> := Name} = ColumnType,
192 Value) when Name == <<"jsonb">>;
193 Name == <<"json">>,
194 is_map(Value) ->
195 6 ?LOG_DEBUG(#{content_type => ContentType,
196 column_type => ColumnType,
197 6 value => Value}),
198 6 jsx:encode(Value);
199
200 value(ContentType,
201 #{<<"typname">> := Type} = ColumnType,
202 {{Ye, Mo, Da}, {Ho, Mi, Se}} = Value)
203 when Type == <<"timestamp">>; Type == <<"timestampz">>->
204 2 ?LOG_DEBUG(#{content_type => ContentType,
205 column_type => ColumnType,
206 2 value => Value}),
207
208 2 iolist_to_binary(
209 io_lib:format(
210 "~4..0b-~2..0b-~2..0bT~2..0b:~2..0b:~2..0bZ",
211 [Ye, Mo, Da, Ho, Mi, Se]));
212
213 value(ContentType,
214 #{<<"typname">> := <<"date">>} = ColumnType,
215 {Ye, Mo, Da} = Value) ->
216 2 ?LOG_DEBUG(#{content_type => ContentType,
217 column_type => ColumnType,
218 2 value => Value}),
219
220 2 iolist_to_binary(
221 io_lib:format(
222 "~4..0b-~2..0b-~2..0b",
223 [Ye, Mo, Da]));
224
225 value(ContentType,
226 #{<<"typname">> := <<"time">>} = ColumnType,
227 {Ho, Mi, Se} = Value) ->
228 2 ?LOG_DEBUG(#{content_type => ContentType,
229 column_type => ColumnType,
230 2 value => Value}),
231 2 iolist_to_binary(
232 io_lib:format(
233 "~2..0b:~2..0b:~2..0b",
234 [Ho, Mi, Se]));
235
236 value(<<"text/plain">> = ContentType,
237 #{<<"typname">> := Type} = ColumnType,
238 {From, To} = Value) when Type == <<"lseg">>;
239 Type == <<"box">> ->
240 2 ?LOG_DEBUG(#{content_type => ContentType,
241 column_type => ColumnType,
242 2 value => Value}),
243 2 jsx:encode(#{from => From, to => To});
244
245 value(<<"text/plain">> = ContentType,
246 #{<<"typname">> := Type} = ColumnType,
247 Value) when Type == <<"point">>;
248 Type == <<"line">>;
249 Type == <<"path">>;
250 Type == <<"polygon">>;
251 Type == <<"circle">> ->
252 5 ?LOG_DEBUG(#{content_type => ContentType,
253 column_type => ColumnType,
254 5 value => Value}),
255 5 jsx:encode(Value);
256
257
258 value(ContentType,
259 #{<<"typname">> := Type} = ColumnType,
260 {From, To} = Value) when Type == <<"lseg">>;
261 Type == <<"box">> ->
262 2 ?LOG_DEBUG(#{content_type => ContentType,
263 column_type => ColumnType,
264 2 value => Value}),
265 2 #{from => From, to => To};
266
267 value(ContentType,
268 #{<<"typname">> := Name} = ColumnType,
269 Value) when (Name == <<"timestamp">> orelse
270 Name == <<"timestampz">>) andalso
271 is_integer(Value) ->
272 3 ?LOG_DEBUG(#{content_type => ContentType,
273 column_type => ColumnType,
274 3 value => Value}),
275 3 iolist_to_binary(
276 calendar:system_time_to_rfc3339(
277 Value,
278 [{unit, microsecond}, {offset, "Z"}]));
279
280 value(ContentType, ColumnType, Value) ->
281 53 ?LOG_DEBUG(#{content_type => ContentType,
282 column_type => ColumnType,
283 53 value => Value}),
284 53 Value.
Line Hits Source