forked from opendatacube/datacube-ows
-
Notifications
You must be signed in to change notification settings - Fork 0
/
update_ranges.py
executable file
·179 lines (162 loc) · 8.01 KB
/
update_ranges.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
#!/usr/bin/env python3
from datacube_wms.product_ranges import update_all_ranges, get_sqlconn, add_product_range, add_multiproduct_range, add_all, update_range
from datacube import Datacube
from psycopg2.sql import SQL, Identifier
import click
@click.command()
@click.option("--schema", is_flag=True, default=False, help="Create or update the OWS database schema.")
@click.option("--role", default=None, help="Role to grant database permissions to")
@click.option("--product", default=None, help="The name of a datacube product.")
@click.option("--multiproduct", default=None, help="The name of OWS multi-product." )
@click.option("--merge-only/--no-merge-only", default=False, help="When used with the multiproduct and calculate-extent options, the ranges for underlying datacube products are not updated.")
@click.option("--calculate-extent/--no-calculate-extent", default=True, help="no-calculate-extent uses database queries to maximise efficiency. calculate-extent calculates ranges directly and is the default.")
def main(product, multiproduct, merge_only, calculate_extent, schema, role):
"""Manage datacube-ows range tables.
A valid invocation should specify at most one of '--product', '--multiproduct' or '--schema'.
If neither of these options are specified, then the ranges for all products and multiproducts
are updated.
"""
if product and multiproduct:
print("Sorry, you specified both a product and multiproduct. One at a time, please.")
return 1
elif schema and (product or multiproduct):
print("Sorry, cannot update the schema and ranges in the same invocation.")
return 1
elif schema and not role:
print("Sorry, cannot update schema without specifying a role")
return 1
dc = Datacube(app="wms_update_ranges")
if schema:
print("Checking schema....")
print("Creating or replacing WMS database schema...")
create_schema(dc, role)
print("Done")
elif not calculate_extent:
if product:
print("Updating range for: ", product)
add_product_range(dc, product)
elif multiproduct:
print("Updating range for: ", multiproduct)
add_multiproduct_range(dc, multiproduct)
else:
print("Updating range for all, using SQL extent calculation")
add_all(dc)
print("Done")
else:
if product:
print("Updating range for: ", product)
p, u, i, sp, su, si = update_range(dc, product, multi=False)
if u:
print("Ranges updated for", product)
elif i:
print("New ranges inserted for", product)
else:
print("Ranges up to date for", product)
if sp or su or si:
print ("Updated ranges for %d existing sub-products and inserted ranges for %d new sub-products (%d existing sub-products unchanged)" % (su, si, sp))
elif multiproduct:
print("Updating range for: ", multiproduct)
p, u, i = update_range(dc, multiproduct, multi=True, follow_dependencies=not merge_only)
if u:
print("Merged ranges updated for", multiproduct)
elif i:
print("Merged ranges inserted for", multiproduct)
else:
print("Merged ranges up to date for", multiproduct)
else:
print ("Updating ranges for all layers/products")
p, u, i, sp, su, si, mp, mu, mi = update_all_ranges(dc)
print ("Updated ranges for %d existing layers/products and inserted ranges for %d new layers/products (%d existing layers/products unchanged)" % (u, i, p))
if sp or su or si:
print ("Updated ranges for %d existing sub-products and inserted ranges for %d new sub-products (%d existing sub-products unchanged)" % (su, si, sp))
if mp or mu or mi:
print ("Updated ranges for %d existing multi-products and inserted ranges for %d new multi-products (%d existing multi-products unchanged)" % (su, si, sp))
return 0
def create_schema(dc, role):
commands = [
("Creating/replacing wms schema", "create schema if not exists wms"),
("Creating/replacing product ranges table", """
create table if not exists wms.product_ranges (
id smallint not null primary key references agdc.dataset_type (id),
lat_min decimal not null,
lat_max decimal not null,
lon_min decimal not null,
lon_max decimal not null,
dates jsonb not null,
bboxes jsonb not null)
"""),
("Creating/replacing sub-product ranges table", """
create table if not exists wms.sub_product_ranges (
product_id smallint not null references agdc.dataset_type (id),
sub_product_id smallint not null,
lat_min decimal not null,
lat_max decimal not null,
lon_min decimal not null,
lon_max decimal not null,
dates jsonb not null,
bboxes jsonb not null,
constraint pk_sub_product_ranges primary key (product_id, sub_product_id) )
"""),
("Creating/replacing multi-product ranges table", """
create table if not exists wms.multiproduct_ranges (
wms_product_name varchar(128) not null primary key,
lat_min decimal not null,
lat_max decimal not null,
lon_min decimal not null,
lon_max decimal not null,
dates jsonb not null,
bboxes jsonb not null)
"""),
# Functions
("Creating/replacing wms_get_min() function", """
CREATE OR REPLACE FUNCTION wms_get_min(integer[], text) RETURNS numeric AS $$
DECLARE
ret numeric;
ul text[] DEFAULT array_append('{extent, coord, ul}', $2);
ur text[] DEFAULT array_append('{extent, coord, ur}', $2);
ll text[] DEFAULT array_append('{extent, coord, ll}', $2);
lr text[] DEFAULT array_append('{extent, coord, lr}', $2);
BEGIN
WITH m AS ( SELECT metadata FROM agdc.dataset WHERE dataset_type_ref = any($1) AND archived IS NULL )
SELECT MIN(LEAST((m.metadata#>>ul)::numeric, (m.metadata#>>ur)::numeric,
(m.metadata#>>ll)::numeric, (m.metadata#>>lr)::numeric))
INTO ret
FROM m;
RETURN ret;
END;
$$ LANGUAGE plpgsql;
"""),
("Creating/replacing wms_get_max() function", """
CREATE OR REPLACE FUNCTION wms_get_max(integer[], text) RETURNS numeric AS $$
DECLARE
ret numeric;
ul text[] DEFAULT array_append('{extent, coord, ul}', $2);
ur text[] DEFAULT array_append('{extent, coord, ur}', $2);
ll text[] DEFAULT array_append('{extent, coord, ll}', $2);
lr text[] DEFAULT array_append('{extent, coord, lr}', $2);
BEGIN
WITH m AS ( SELECT metadata FROM agdc.dataset WHERE dataset_type_ref = ANY ($1) AND archived IS NULL )
SELECT MAX(GREATEST((m.metadata#>>ul)::numeric, (m.metadata#>>ur)::numeric,
(m.metadata#>>ll)::numeric, (m.metadata#>>lr)::numeric))
INTO ret
FROM m;
RETURN ret;
END;
$$ LANGUAGE plpgsql;
"""),
]
conn = get_sqlconn(dc)
for msg, sql in commands:
print(msg)
conn.execute(sql)
# Add user based on param
# use psycopg2 directly to get proper psql
# quoting on the role name identifier
print("Granting usage on schema")
q = SQL("GRANT USAGE ON SCHEMA wms TO {}").format(Identifier(role))
with conn.connection.cursor() as psycopg2connection:
psycopg2connection.execute(q)
conn.close()
return
if __name__ == '__main__':
main()