Skip to content

Commit 16a932a

Browse files
Merge pull request #36 from geoCML/near-constraint
Implement 'near' constraint
2 parents 8a68dfd + 83efc60 commit 16a932a

File tree

2 files changed

+29
-4
lines changed

2 files changed

+29
-4
lines changed

src/constraint.py

+28-3
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,11 @@ def length(self, maximum: float | None, minimum: float | None):
2525
if not minimum:
2626
minimum = 0
2727

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")}();"""
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")}();"""
29+
30+
31+
def near(self, distance: float, other_layer: str):
32+
return f"""CREATE OR REPLACE FUNCTION {self.layer}___near___{other_layer}__{str(distance).replace(".", "d")}() RETURNS trigger AS $$ DECLARE within boolean; BEGIN SELECT Count(*) INTO within FROM {other_layer} WHERE ST_DWithin({other_layer}.geom, NEW.geom, {distance}); IF NOT within THEN RAISE EXCEPTION '{self.layer} is too far from {other_layer}'; END IF; RETURN NEW; END; $$ LANGUAGE 'plpgsql'; CREATE CONSTRAINT TRIGGER {self.layer}___near___{other_layer}__{str(distance).replace(".", "d")} AFTER INSERT OR UPDATE ON {self.layer} FOR EACH ROW EXECUTE FUNCTION {self.layer}___near___{other_layer}__{str(distance).replace(".", "d")}();"""
2933

3034

3135
def as_dict(self) -> dict:
@@ -63,6 +67,21 @@ def __str__(self) -> str:
6367

6468
return self.length(maximum, minimum)
6569

70+
if self.constraint_type.type == "near":
71+
try:
72+
layer = self.constraint["layer"]
73+
except KeyError:
74+
raise Exception("Constraint 'near' needs a relative layer value")
75+
76+
if "distance" in self.constraint:
77+
distance = self.constraint["distance"]
78+
try:
79+
float(distance)
80+
except ValueError:
81+
raise Exception(f"Value '{distance}' is not a numeric value")
82+
83+
return self.near(distance, layer)
84+
6685
return ""
6786

6887

@@ -85,9 +104,15 @@ def derive_constraint_from_name(self, name) -> Constraint:
85104
elif "___length___" in name:
86105
return Constraint({
87106
"name": "length",
88-
"minimum": float(name.split("___length___")[1].split("_")[0].replace("d", ".")),
89-
"maximum": float(name.split("___length___")[1].split("_")[1].replace("d", "."))
107+
"minimum": float(name.split("___length___")[1].split("__")[0].replace("d", ".")),
108+
"maximum": float(name.split("___length___")[1].split("__")[1].replace("d", "."))
90109
}, name.split("___length___")[0])
110+
elif "___near___" in name:
111+
return Constraint({
112+
"name": "near",
113+
"layer": name.split("___near___")[1].split("__")[0],
114+
"distance": float(name.split("___near___")[1].split("__")[1].replace("d", "."))
115+
}, name.split("___near___")[0])
91116

92117
raise Exception(f"Cannot derive a constraint from trigger '{name}'")
93118

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", "length")
2+
valid_constraints = ("on", "length", "near")
33

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

0 commit comments

Comments
 (0)