Skip to content

Commit 7b5ff07

Browse files
authored
Fix for #122 - bug with type casting when using "in" operator (#124)
* fix for in and wrapper * add neq operator * add tests to fix for 122
1 parent 4fd02b4 commit 7b5ff07

File tree

9 files changed

+3045
-14
lines changed

9 files changed

+3045
-14
lines changed

CHANGELOG.md

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
# Changelog
2-
3-
## [Unreleased]
4-
2+
## [v0.6.5]
53
### Fixed
6-
4+
- Fix for type casting when using the "in" operator [#122](https://github.com/stac-utils/pgstac/issues/122)
75
- Fix failure of pypgstac load for large items [#121](https://github.com/stac-utils/pgstac/pull/121)
86

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

0 commit comments

Comments
 (0)