Skip to content

Commit 8a68dfd

Browse files
authoredNov 17, 2024
Merge pull request #34 from geoCML/length-constraint
Implement 'length' data constraint
2 parents d30e027 + 7e0ea68 commit 8a68dfd

File tree

2 files changed

+46
-5
lines changed

2 files changed

+46
-5
lines changed
 

‎src/constraint.py

+45-4
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,17 @@ def __init__(self, constraint: dict, layer: str) -> None:
1515

1616

1717
def on(self, other_layer: str) -> str:
18-
return f"""CREATE OR REPLACE FUNCTION {self.layer}_on_{other_layer}() RETURNS trigger AS $$ DECLARE overlap boolean; BEGIN SELECT Count(*) INTO overlap FROM {other_layer} WHERE ST_Covers({other_layer}.geom, NEW.geom); IF NOT overlap THEN RAISE EXCEPTION '{self.layer} is not on {other_layer}'; END IF; RETURN NEW; END; $$ LANGUAGE 'plpgsql'; CREATE CONSTRAINT TRIGGER {self.layer}_on_{other_layer} AFTER INSERT OR UPDATE ON {self.layer} FOR EACH ROW EXECUTE FUNCTION {self.layer}_on_{other_layer}();"""
18+
return f"""CREATE OR REPLACE FUNCTION {self.layer}___on___{other_layer}() RETURNS trigger AS $$ DECLARE overlap boolean; BEGIN SELECT Count(*) INTO overlap FROM {other_layer} WHERE ST_Covers({other_layer}.geom, NEW.geom); IF NOT overlap THEN RAISE EXCEPTION '{self.layer} is not on {other_layer}'; END IF; RETURN NEW; END; $$ LANGUAGE 'plpgsql'; CREATE CONSTRAINT TRIGGER {self.layer}___on___{other_layer} AFTER INSERT OR UPDATE ON {self.layer} FOR EACH ROW EXECUTE FUNCTION {self.layer}___on___{other_layer}();"""
19+
20+
21+
def length(self, maximum: float | None, minimum: float | None):
22+
if not maximum:
23+
maximum = 99999999999
24+
25+
if not minimum:
26+
minimum = 0
27+
28+
return f"""CREATE OR REPLACE FUNCTION {self.layer}___length___{str(minimum).replace(".", "d")}_{str(maximum).replace(".", "d")}() RETURNS trigger AS $$ DECLARE length numeric; BEGIN SELECT ST_LENGTH(NEW.geom::geography) INTO length; IF length > {maximum} THEN RAISE EXCEPTION '{self.layer} is longer than {maximum}'; ELSE IF length < {minimum} THEN RAISE EXCEPTION '{self.layer} is shorter than {minimum}'; END IF; END IF; RETURN NEW; END; $$ LANGUAGE 'plpgsql'; CREATE CONSTRAINT TRIGGER {self.layer}___length___{str(minimum).replace(".", "d")}_{str(maximum).replace(".", "d")} AFTER INSERT OR UPDATE ON {self.layer} FOR EACH ROW EXECUTE FUNCTION {self.layer}___length___{str(minimum).replace(".", "d")}_{str(maximum).replace(".", "d")}();"""
1929

2030

2131
def as_dict(self) -> dict:
@@ -29,6 +39,30 @@ def __str__(self) -> str:
2939
except KeyError:
3040
raise Exception("Constraint 'on' needs a relative layer value")
3141
return self.on(layer)
42+
43+
if self.constraint_type.type == "length":
44+
maximum = None
45+
minimum = None
46+
47+
if "maximum" in self.constraint:
48+
maximum = self.constraint["maximum"]
49+
try:
50+
float(maximum)
51+
except ValueError:
52+
raise Exception(f"Value '{maximum}' is not a numeric value")
53+
54+
if "minimum" in self.constraint:
55+
minimum = self.constraint["minimum"]
56+
try:
57+
float(minimum)
58+
except ValueError:
59+
raise Exception(f"Value '{minimum}' is not a numeric value")
60+
61+
if not minimum and not maximum:
62+
raise Exception("Constraint 'length' needs a minimum or maximum value")
63+
64+
return self.length(maximum, minimum)
65+
3266
return ""
3367

3468

@@ -43,10 +77,17 @@ def __init__(self, name: str) -> None:
4377

4478

4579
def derive_constraint_from_name(self, name) -> Constraint:
46-
if "_on_" in name:
80+
if "___on___" in name:
4781
return Constraint({
4882
"name": "on",
49-
"layer": name.split("_on_")[1]
50-
}, name.split("_on_")[0])
83+
"layer": name.split("___on___")[1]
84+
}, name.split("___on___")[0])
85+
elif "___length___" in name:
86+
return Constraint({
87+
"name": "length",
88+
"minimum": float(name.split("___length___")[1].split("_")[0].replace("d", ".")),
89+
"maximum": float(name.split("___length___")[1].split("_")[1].replace("d", "."))
90+
}, name.split("___length___")[0])
5191

5292
raise Exception(f"Cannot derive a constraint from trigger '{name}'")
93+

‎src/tabor_constraint_type.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
class TaborConstraintType(object):
2-
valid_constraints = ("on")
2+
valid_constraints = ("on", "length")
33

44
def __init__(self, constraint: str) -> None:
55
if constraint not in self.valid_constraints:

0 commit comments

Comments
 (0)