Skip to content

Commit 98d3e04

Browse files
Breaking migration into 2 parts
1 parent 030acfa commit 98d3e04

File tree

1 file changed

+0
-271
lines changed

1 file changed

+0
-271
lines changed

packages/api/migrations/current.sql

-271
Original file line numberDiff line numberDiff line change
@@ -4,274 +4,3 @@ alter table sketch_classes add column if not exists filter_api_server_location t
44

55
alter type sketch_geometry_type add value if not exists 'FILTERED_PLANNING_UNITS';
66

7-
set role seasketch_superuser;
8-
delete from sketch_classes where project_id = (select id from projects where slug = 'superuser') and name = 'Filtered Planning Units';
9-
10-
insert into sketch_classes(
11-
project_id,
12-
name,
13-
geometry_type,
14-
mapbox_gl_style,
15-
is_template,
16-
template_description
17-
) values (
18-
(select id from projects where slug = 'superuser'),
19-
'Filtered Planning Units',
20-
'FILTERED_PLANNING_UNITS'::sketch_geometry_type,
21-
'{}'::jsonb,
22-
true,
23-
'Filter polygons by criteria. Requires an API server.'
24-
) on conflict do nothing;
25-
26-
select initialize_sketch_class_form_from_template((select id from sketch_classes where name = 'Filtered Planning Units' and is_template = true), (select id from forms where is_template = true and template_type = 'SKETCHES' and template_name = 'Basic Template'));
27-
set role postgres;
28-
29-
GRANT update (filter_api_server_location) on sketch_classes to seasketch_user;
30-
GRANT update (filter_api_version) on sketch_classes to seasketch_user;
31-
32-
delete from form_element_types where component_name = 'FilterInput';
33-
insert into form_element_types (
34-
component_name,
35-
label,
36-
is_input,
37-
is_surveys_only
38-
) values (
39-
'FilterInput',
40-
'Filter Input',
41-
true,
42-
false
43-
);
44-
45-
CREATE OR REPLACE FUNCTION public.before_sketch_insert_or_update() RETURNS trigger
46-
LANGUAGE plpgsql SECURITY DEFINER
47-
AS $$
48-
declare
49-
class_geometry_type sketch_geometry_type;
50-
allow_multi boolean;
51-
incoming_geometry_type text;
52-
new_geometry_type text;
53-
parent_collection_id int;
54-
begin
55-
select
56-
geometry_type,
57-
sketch_classes.allow_multi
58-
into
59-
class_geometry_type,
60-
allow_multi,
61-
incoming_geometry_type
62-
from
63-
sketch_classes
64-
where
65-
id = NEW.sketch_class_id;
66-
if NEW.folder_id is not null and NEW.collection_id is not null then
67-
raise exception 'Parent cannot be to both folder and collection';
68-
end if;
69-
if class_geometry_type = 'COLLECTION' then
70-
-- Also check for parent collection of parent folder (recursively)
71-
if NEW.collection_id is not null then
72-
if (select get_parent_collection_id('sketch', NEW.collection_id)) is not null then
73-
raise exception 'Nested collections are not allowed';
74-
end if;
75-
elsif NEW.folder_id is not null then
76-
if (select get_parent_collection_id('sketch_folder', NEW.folder_id)) is not null then
77-
raise exception 'Nested collections are not allowed';
78-
end if;
79-
end if;
80-
-- geom must be present unless a collection
81-
if NEW.geom is not null or NEW.user_geom is not null then
82-
raise exception 'Collections should not have geometry';
83-
else
84-
-- no nested collections
85-
if NEW.collection_id is not null then
86-
raise exception 'Nested collections are not allowed';
87-
else
88-
return NEW;
89-
end if;
90-
end if;
91-
elsif class_geometry_type = 'FILTERED_PLANNING_UNITS' then
92-
-- Also check for parent collection of parent folder (recursively)
93-
if NEW.collection_id is not null then
94-
raise exception 'Filtered planning units cannot be part of a collection';
95-
elsif NEW.folder_id is not null then
96-
if (select get_parent_collection_id('sketch_folder', NEW.folder_id)) is not null then
97-
raise exception 'Filtered planning units cannot be part of a collection';
98-
end if;
99-
end if;
100-
-- geom must be present unless a collection
101-
if NEW.geom is not null or NEW.user_geom is not null then
102-
raise exception 'Filtered planning units should not have geometry';
103-
else
104-
-- no nested collections
105-
if NEW.collection_id is not null then
106-
raise exception 'Filtered planning units cannot be part of a collection';
107-
else
108-
return NEW;
109-
end if;
110-
end if;
111-
else
112-
select geometrytype(NEW.user_geom) into new_geometry_type;
113-
-- geometry type must match sketch_class.geometry_type and sketch_class.allow_multi
114-
if (new_geometry_type = class_geometry_type::text) or (allow_multi and new_geometry_type like '%' || class_geometry_type::text) then
115-
-- if specifying a collection_id, must be in it's valid_children
116-
if NEW.collection_id is null or not exists(select 1 from sketch_classes_valid_children where parent_id in (select sketch_class_id from sketches where id = NEW.collection_id)) or exists(select 1 from sketch_classes_valid_children where parent_id in (select sketch_class_id from sketches where id = NEW.collection_id) and child_id = NEW.sketch_class_id) then
117-
return NEW;
118-
else
119-
raise exception 'Sketch is not a valid child of collection';
120-
end if;
121-
else
122-
raise exception 'Geometry type does not match sketch class';
123-
end if;
124-
end if;
125-
end;
126-
$$;
127-
128-
129-
CREATE OR REPLACE FUNCTION url_encode(input text)
130-
RETURNS text AS $$
131-
DECLARE
132-
cleaned_input text;
133-
output text := '';
134-
ch text;
135-
ch_code int;
136-
BEGIN
137-
-- Remove all extraneous whitespace from the input JSON text
138-
cleaned_input := regexp_replace(input, '\s+', '', 'g');
139-
140-
-- Perform URL encoding on the cleaned input
141-
FOR i IN 1..length(cleaned_input) LOOP
142-
ch := substr(cleaned_input, i, 1);
143-
ch_code := ascii(ch);
144-
-- Allow only URL-safe characters (alphanumeric and unreserved characters)
145-
IF ch ~ '[a-zA-Z0-9_.~-]' THEN
146-
output := output || ch;
147-
ELSE
148-
-- Use lpad and upper to ensure two-character hexadecimal representation
149-
output := output || '%' || lpad(upper(to_hex(ch_code)), 2, '0');
150-
END IF;
151-
END LOOP;
152-
153-
RETURN output;
154-
END;
155-
$$ LANGUAGE plpgsql;
156-
157-
grant execute on function url_encode to anon;
158-
comment on function url_encode is '@omit';
159-
160-
drop function if exists filter_state_to_search_string(jsonb, int);
161-
drop function if exists filter_state_to_search_string(jsonb);
162-
163-
CREATE OR REPLACE FUNCTION filter_state_to_search_string(filters jsonb, sketch_class_id int)
164-
RETURNS text AS $$
165-
DECLARE
166-
state jsonb := '{}';
167-
filter jsonb;
168-
attr text;
169-
result text;
170-
attribute_name text;
171-
filter_server_location text;
172-
filter_version int;
173-
final_url text;
174-
BEGIN
175-
-- Retrieve the filter_api_server_location and filter_api_version from sketch_classes table
176-
SELECT sketch_classes.filter_api_server_location, sketch_classes.filter_api_version
177-
INTO filter_server_location, filter_version
178-
FROM sketch_classes
179-
WHERE id = sketch_class_id;
180-
181-
-- If filter_api_server_location is NULL, return NULL
182-
IF filter_server_location IS NULL THEN
183-
RETURN NULL;
184-
END IF;
185-
186-
-- Loop through each attribute in the input JSONB object
187-
FOR attr, filter IN
188-
SELECT key, value FROM jsonb_each(filters)
189-
LOOP
190-
-- Only process if "selected" is true
191-
IF filter->>'selected' = 'true' THEN
192-
if filter->>'attribute' is not null then
193-
attribute_name := filter->>'attribute';
194-
else
195-
-- Look up the attribute name from form_elements for the current attr ID
196-
SELECT component_settings->>'attribute'
197-
INTO attribute_name
198-
FROM form_elements
199-
WHERE id = attr::int; -- Cast attr to integer to match form_elements ID
200-
end if;
201-
202-
203-
-- Default to the original key if no match is found
204-
IF attribute_name IS NULL THEN
205-
attribute_name := attr;
206-
END IF;
207-
208-
-- Check for numberState
209-
IF filter ? 'numberState' THEN
210-
state := state || jsonb_build_object(attribute_name, jsonb_build_object(
211-
'min', filter->'numberState'->'min',
212-
'max', filter->'numberState'->'max'
213-
));
214-
215-
-- Check for stringState
216-
ELSIF filter ? 'stringState' THEN
217-
state := state || jsonb_build_object(attribute_name, jsonb_build_object(
218-
'choices', filter->'stringState'
219-
));
220-
221-
-- Check for booleanState
222-
ELSIF filter ? 'booleanState' THEN
223-
state := state || jsonb_build_object(attribute_name, jsonb_build_object(
224-
'bool', COALESCE(filter->'booleanState', 'false')::boolean
225-
));
226-
END IF;
227-
END IF;
228-
END LOOP;
229-
230-
-- If no keys were added, return an empty string; otherwise, encode the JSON
231-
IF state = '{}'::jsonb THEN
232-
RETURN '';
233-
ELSE
234-
-- Convert the JSONB object to a text string without formatting
235-
result := state::text;
236-
237-
-- URL encode the resulting JSON text using the updated url_encode function
238-
result := url_encode(result);
239-
240-
-- Construct the final URL
241-
final_url := filter_server_location || '/v' || filter_version || '/mvt/{z}/{x}/{y}.pbf?filter=' || result;
242-
RETURN final_url;
243-
END IF;
244-
END;
245-
$$ LANGUAGE plpgsql;
246-
247-
grant execute on function filter_state_to_search_string to anon;
248-
comment on function filter_state_to_search_string is '@omit';
249-
250-
alter table sketches drop column if exists filter_mvt_url;
251-
create or replace function sketches_filter_mvt_url(s sketches)
252-
returns text
253-
language sql
254-
security definer
255-
stable
256-
as $$
257-
select filter_state_to_search_string(s.properties, s.sketch_class_id);
258-
$$;
259-
260-
261-
grant execute on function sketches_filter_mvt_url to anon;
262-
-- alter table sketches add column if not exists filter_mvt_url text generated always as (filter_state_to_search_string(properties, sketch_class_id)) stored;
263-
264-
-- grant select(filter_mvt_url) on sketches to anon;
265-
266-
delete from form_element_types where component_name = 'CollapsibleGroup';
267-
insert into form_element_types (
268-
component_name,
269-
label,
270-
is_input,
271-
is_surveys_only
272-
) values (
273-
'CollapsibleGroup',
274-
'Collapsible Group',
275-
false,
276-
false
277-
);

0 commit comments

Comments
 (0)