_site/cover/pgsqlp_scalar.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(pgsqlp_scalar).
17 -feature(maybe_expr, enable).
18
19
20 -export([column_references/0]).
21 -export([expression/0]).
22 -export([function_call/0]).
23 -import(scran_branch, [alt/1]).
24 -import(scran_character_complete, [digit1/0]).
25 -import(scran_character_complete, [multispace0/0]).
26 -import(scran_character_complete, [multispace1/0]).
27 -import(scran_character_complete, [re/1]).
28 -import(scran_character_complete, [tag/1]).
29 -import(scran_character_complete, [tag_no_case/1]).
30 -import(scran_combinator, [is_not/1]).
31 -import(scran_combinator, [map_parser/2]).
32 -import(scran_combinator, [map_result/2]).
33 -import(scran_combinator, [opt/1]).
34 -import(scran_multi, [many1/1]).
35 -import(scran_multi, [separated_list0/2]).
36 -import(scran_multi, [separated_list1/2]).
37 -import(scran_result, [kv/2]).
38 -import(scran_sequence, [delimited/3]).
39 -import(scran_sequence, [pair/2]).
40 -import(scran_sequence, [preceded/2]).
41 -import(scran_sequence, [separated_pair/3]).
42 -import(scran_sequence, [sequence/1]).
43 -import(scran_sequence, [terminated/2]).
44 -include_lib("kernel/include/logger.hrl").
45
46
47 expression() ->
48 1010 fun
49 (Input) ->
50 177 (alt([in_expression(),
51 operator_invocation(),
52 function_call(),
53 column_reference(),
54 conditional(),
55 type_cast(),
56 group_subexpression(),
57 literal_value()]))(Input)
58 end.
59
60 group_subexpression() ->
61 346 fun
62 (Input) ->
63 159 (kv(?FUNCTION_NAME,
64 delimited(
65 sequence([multispace0(),
66 tag("("),
67 multispace0()]),
68 expression(),
69 sequence([multispace0(),
70 tag(")")]))))(Input)
71
72 end.
73
74 conditional() ->
75 177 fun
76 (Input) ->
77 70 (alt([case_expression()]))(Input)
78 end.
79
80 case_expression() ->
81 70 fun
82 (Input) ->
83 70 (kv(?FUNCTION_NAME,
84 terminated(
85 preceded(
86 sequence(
87 [multispace0(),
88 tag_no_case("CASE")]),
89
90 sequence(
91 [kv(clauses,
92 many1(
93 sequence(
94 [kv(condition,
95 preceded(
96 sequence(
97 [multispace1(),
98 tag_no_case("WHEN"),
99 multispace1()]),
100 expression())),
101
102 kv(then,
103 preceded(
104 sequence(
105 [multispace1(),
106 tag_no_case("THEN"),
107 multispace1()]),
108 expression()))]))),
109
110 opt(kv(otherwise,
111 preceded(
112 sequence(
113 [multispace1(),
114 tag_no_case("ELSE"),
115 multispace1()]),
116 expression())))])),
117 sequence(
118 [multispace1(),
119 tag_no_case("END"),
120 multispace0()]))))(Input)
121 end.
122
123 type_cast() ->
124 346 fun
125 (Input) ->
126 273 (kv(?FUNCTION_NAME,
127 sequence(
128 [alt([literal_value()]),
129 preceded(
130 tag_no_case("::"),
131 type_name())])))(Input)
132 end.
133
134
135 function_call() ->
136 367 fun
137 (Input) ->
138 365 (kv(?FUNCTION_NAME,
139 sequence([function_name(), function_args()])))(Input)
140 end.
141
142
143 function_name() ->
144 365 fun
145 (Input) ->
146 365 (kv(?FUNCTION_NAME,
147 alt([map_result(
148 separated_pair(schema_name(), tag("."), name()),
149 fun erlang:list_to_tuple/1),
150
151 tag_no_case("ANY"),
152
153 name()])))(Input)
154 end.
155
156
157 function_args() ->
158 365 fun
159 (Input) ->
160 194 (kv(?FUNCTION_NAME,
161 delimited(
162 tag("("),
163 separated_list0(
164 sequence([tag(","), multispace0()]),
165 expression()),
166 tag(")"))))(Input)
167 end.
168
169
170 operator_invocation() ->
171 177 fun
172 (Input) ->
173 169 (kv(?FUNCTION_NAME, infix_operator()))(Input)
174 end.
175
176
177 infix_operator() ->
178 169 fun
179 (Input) ->
180 169 (infix_operator(
181 preceded(
182 multispace0(),
183 operator()),
184
185 preceded(
186 multispace0(),
187 alt([function_call(),
188 in_expression(),
189 type_cast(),
190 column_reference(),
191 group_subexpression(),
192 literal_value()]))))(Input)
193 end.
194
195
196 infix_operator(OperatorParser, ExpressionParser) ->
197 169 fun
198 (Input) ->
199 169 ?LOG_DEBUG(
200 #{input => Input,
201 operator_parser => scran_debug:pp(OperatorParser),
202 169 expression_parser => scran_debug:pp(ExpressionParser)}),
203
204 169 maybe
205 169 {OperatorInput, LHS} ?= ExpressionParser(Input),
206 162 {RHSInput, Operator} ?= OperatorParser(OperatorInput),
207 40 {NextIterationInput, RHS} ?= ExpressionParser(RHSInput),
208
209
210 40 (kv(?FUNCTION_NAME,
211 ?FUNCTION_NAME(
212 OperatorParser,
213 ExpressionParser,
214 [RHS, {operator, Operator}, LHS])))(NextIterationInput)
215 end
216 end.
217
218 infix_operator(OperatorParser, ExpressionParser, A) ->
219 62 fun
220 (Input) ->
221 62 ?LOG_DEBUG(
222 #{input => Input,
223 operator_parser => scran_debug:pp(OperatorParser),
224 expression_parser => scran_debug:pp(ExpressionParser),
225 62 a => A}),
226
227 62 maybe
228 62 {ExpressionInput, Operator} ?= OperatorParser(Input),
229 25 {NextIterationInput, Expression} ?= ExpressionParser(ExpressionInput),
230
231 22 ?LOG_DEBUG(#{operator => Operator, expression => Expression}),
232
233 22 (?FUNCTION_NAME(
234 OperatorParser,
235 ExpressionParser,
236 [Expression, {operator, Operator} | A]))(NextIterationInput)
237
238 else
239 nomatch ->
240 40 {Input, lists:reverse(A)}
241 end
242 end.
243
244 operator() ->
245 169 fun
246 (Input) ->
247 224 (alt(
248 [re("[\\+\\-\\*\\/\\<\\>\\=\\~\\!\\@\\#\\%\\^\\&\\|\\`\\?]{1,63}"),
249 tag_no_case("AND NOT"),
250 tag_no_case("AND"),
251 tag_no_case("OR"),
252 tag_no_case("NOT")]))(Input)
253 end.
254
255
256 column_references() ->
257 399 fun
258 (Input) ->
259 391 (kv(?FUNCTION_NAME,
260 separated_list1(
261 sequence([tag(","), multispace0()]),
262 column_reference())))(Input)
263 end.
264
265
266 column_reference() ->
267 737 fun
268 (Input) ->
269 804 (kv(?FUNCTION_NAME,
270 map_result(
271 separated_list1(
272 tag("."),
273 name()),
274 fun erlang:list_to_tuple/1)))(Input)
275 end.
276
277
278 in_expression() ->
279 346 fun
280 (Input) ->
281 389 (kv(in,
282 pair(
283 column_references(),
284 preceded(
285 sequence(
286 [multispace1(),
287 tag_no_case("IN"),
288 multispace1()]),
289 delimited(
290 sequence([tag("("), multispace0()]),
291 separated_list0(
292 sequence([tag(","), multispace0()]),
293 expression()),
294 sequence([multispace0(), tag(")")]))))))(Input)
295 end.
296
297
298 literal_value() ->
299 619 fun
300 (Input) ->
301 421 (alt([null_literal(),
302 string_literal(),
303 numeric_literal(),
304 boolean_literal()]))(Input)
305 end.
306
307
308 null_literal() ->
309 421 fun
310 (Input) ->
311 421 (kv(?FUNCTION_NAME, tag_no_case("null")))(Input)
312 end.
313
314 string_literal() ->
315 421 fun
316 (Input) ->
317 401 (kv(?FUNCTION_NAME,
318 delimited(
319 tag("'"),
320 re("[a-z_]*"),
321 tag("'"))))(Input)
322 end.
323
324 numeric_literal() ->
325 421 fun
326 (Input) ->
327 271 (kv(?FUNCTION_NAME,
328 map_result(
329 digit1(),
330 fun erlang:binary_to_integer/1)))(Input)
331 end.
332
333 boolean_literal() ->
334 421 fun
335 (Input) ->
336 172 (kv(?FUNCTION_NAME,
337 map_result(
338 alt([tag_no_case("true"), tag_no_case("false")]),
339 fun
340 (Term) ->
341 32 binary_to_existing_atom(string:lowercase(Term))
342 end)))(Input)
343 end.
344
345 type_name() ->
346 273 fun
347 (Input) ->
348 5 (kv(?FUNCTION_NAME,
349 separated_list0(
350 tag("."),
351 re("[a-z_][a-z0-9_]*"))))(Input)
352 end.
353
354
355 schema_name() ->
356 365 fun
357 (Input) ->
358 365 (name())(Input)
359 end.
360
361
362 name() ->
363 1899 fun
364 (Input) ->
365 1940 (map_parser(
366 re("[a-z_]+"),
367 is_not(pgsqlp:reserved())))(Input)
368 end.
Line Hits Source