Skip to content

Commit d3997cd

Browse files
bitnerUbuntu
andauthored
add fixes for casting items in filters to floats (#117)
* add fixes for casting items in filters to floats * fix for between case * update cql2_ops table * merge 116, update changelog Co-authored-by: Ubuntu <planetarycomputer@pct-bitner-vm.kko0dpzi4g3udak2ovyb5nsdte.ax.internal.cloudapp.net>
1 parent 3baae42 commit d3997cd

File tree

8 files changed

+3073
-38
lines changed

8 files changed

+3073
-38
lines changed

CHANGELOG.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Changelog
2-
3-
## Unreleased
4-
2+
## [v0.6.4]
3+
### Fixed
4+
- Fixed casts for numeric data when a property is not in the queryables table to use the type from the incoming json filter
55
- Fixed issue loader grouping an unordered iterable by partition, speeding up loads of items with mixed partitions [#116](https://github.com/stac-utils/pgstac/pull/116)
66

77
## [v0.6.3]
Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
SET SEARCH_PATH to pgstac, public;
2+
set check_function_bodies = off;
3+
4+
INSERT INTO cql2_ops (op, template, types) VALUES
5+
('eq', '%s = %s', NULL),
6+
('lt', '%s < %s', NULL),
7+
('lte', '%s <= %s', NULL),
8+
('gt', '%s > %s', NULL),
9+
('gte', '%s >= %s', NULL),
10+
('le', '%s <= %s', NULL),
11+
('ge', '%s >= %s', NULL),
12+
('=', '%s = %s', NULL),
13+
('<', '%s < %s', NULL),
14+
('<=', '%s <= %s', NULL),
15+
('>', '%s > %s', NULL),
16+
('>=', '%s >= %s', NULL),
17+
('like', '%s LIKE %s', NULL),
18+
('ilike', '%s ILIKE %s', NULL),
19+
('+', '%s + %s', NULL),
20+
('-', '%s - %s', NULL),
21+
('*', '%s * %s', NULL),
22+
('/', '%s / %s', NULL),
23+
('in', '%s = ANY (%s)', NULL),
24+
('not', 'NOT (%s)', NULL),
25+
('between', '%s BETWEEN %s AND %s', NULL),
26+
('isnull', '%s IS NULL', NULL),
27+
('upper', 'upper(%s)', NULL),
28+
('lower', 'lower(%s)', NULL)
29+
ON CONFLICT (op) DO UPDATE
30+
SET
31+
template = EXCLUDED.template
32+
;
33+
34+
35+
CREATE OR REPLACE FUNCTION pgstac.cql2_query(j jsonb, wrapper text DEFAULT NULL::text)
36+
RETURNS text
37+
LANGUAGE plpgsql
38+
STABLE
39+
AS $function$
40+
#variable_conflict use_variable
41+
DECLARE
42+
args jsonb := j->'args';
43+
arg jsonb;
44+
op text := lower(j->>'op');
45+
cql2op RECORD;
46+
literal text;
47+
_wrapper text;
48+
BEGIN
49+
IF j IS NULL OR (op IS NOT NULL AND args IS NULL) THEN
50+
RETURN NULL;
51+
END IF;
52+
RAISE NOTICE 'CQL2_QUERY: %', j;
53+
IF j ? 'filter' THEN
54+
RETURN cql2_query(j->'filter');
55+
END IF;
56+
57+
IF j ? 'upper' THEN
58+
RETURN cql2_query(jsonb_build_object('op', 'upper', 'args', j->'upper'));
59+
END IF;
60+
61+
IF j ? 'lower' THEN
62+
RETURN cql2_query(jsonb_build_object('op', 'lower', 'args', j->'lower'));
63+
END IF;
64+
65+
-- Temporal Query
66+
IF op ilike 't_%' or op = 'anyinteracts' THEN
67+
RETURN temporal_op_query(op, args);
68+
END IF;
69+
70+
-- If property is a timestamp convert it to text to use with
71+
-- general operators
72+
IF j ? 'timestamp' THEN
73+
RETURN format('%L::timestamptz', to_tstz(j->'timestamp'));
74+
END IF;
75+
IF j ? 'interval' THEN
76+
RAISE EXCEPTION 'Please use temporal operators when using intervals.';
77+
RETURN NONE;
78+
END IF;
79+
80+
-- Spatial Query
81+
IF op ilike 's_%' or op = 'intersects' THEN
82+
RETURN spatial_op_query(op, args);
83+
END IF;
84+
85+
86+
IF op = 'in' THEN
87+
RETURN format(
88+
'%s = ANY (%L)',
89+
cql2_query(args->0),
90+
to_text_array(args->1)
91+
);
92+
END IF;
93+
94+
95+
96+
IF op = 'between' THEN
97+
args = jsonb_build_array(
98+
args->0,
99+
args->1->0,
100+
args->1->1
101+
);
102+
END IF;
103+
104+
-- Make sure that args is an array and run cql2_query on
105+
-- each element of the array
106+
RAISE NOTICE 'ARGS PRE: %', args;
107+
IF j ? 'args' THEN
108+
IF jsonb_typeof(args) != 'array' THEN
109+
args := jsonb_build_array(args);
110+
END IF;
111+
112+
IF jsonb_path_exists(args, '$[*] ? (@.property == "id" || @.property == "datetime" || @.property == "end_datetime" || @.property == "collection")') THEN
113+
wrapper := NULL;
114+
ELSE
115+
-- if any of the arguments are a property, try to get the property_wrapper
116+
FOR arg IN SELECT jsonb_path_query(args, '$[*] ? (@.property != null)') LOOP
117+
RAISE NOTICE 'Arg: %', arg;
118+
SELECT property_wrapper INTO wrapper
119+
FROM queryables
120+
WHERE name=(arg->>'property')
121+
LIMIT 1;
122+
RAISE NOTICE 'Property: %, Wrapper: %', arg, wrapper;
123+
IF wrapper IS NOT NULL THEN
124+
EXIT;
125+
END IF;
126+
END LOOP;
127+
128+
-- if the property was not in queryables, see if any args were numbers
129+
IF
130+
wrapper IS NULL
131+
AND jsonb_path_exists(args, '$[*] ? (@.type()=="number")')
132+
THEN
133+
wrapper := 'to_float';
134+
END IF;
135+
wrapper := coalesce(wrapper, 'to_text');
136+
END IF;
137+
138+
SELECT jsonb_agg(cql2_query(a, wrapper))
139+
INTO args
140+
FROM jsonb_array_elements(args) a;
141+
END IF;
142+
RAISE NOTICE 'ARGS: %', args;
143+
144+
IF op IN ('and', 'or') THEN
145+
RETURN
146+
format(
147+
'(%s)',
148+
array_to_string(to_text_array(args), format(' %s ', upper(op)))
149+
);
150+
END IF;
151+
152+
-- Look up template from cql2_ops
153+
IF j ? 'op' THEN
154+
SELECT * INTO cql2op FROM cql2_ops WHERE cql2_ops.op ilike op;
155+
IF FOUND THEN
156+
-- If specific index set in queryables for a property cast other arguments to that type
157+
RETURN format(
158+
cql2op.template,
159+
VARIADIC (to_text_array(args))
160+
);
161+
ELSE
162+
RAISE EXCEPTION 'Operator % Not Supported.', op;
163+
END IF;
164+
END IF;
165+
166+
167+
IF wrapper IS NOT NULL THEN
168+
RAISE NOTICE 'Wrapping % with %', j, wrapper;
169+
IF j ? 'property' THEN
170+
RETURN format('%I(%s)', wrapper, (queryable(j->>'property')).path);
171+
ELSE
172+
RETURN format('%I(%L)', wrapper, j);
173+
END IF;
174+
ELSIF j ? 'property' THEN
175+
RETURN quote_ident(j->>'property');
176+
END IF;
177+
178+
RETURN quote_literal(to_text(j));
179+
END;
180+
$function$
181+
;
182+
183+
184+
185+
SELECT set_version('0.6.4');

0 commit comments

Comments
 (0)