Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions pygeofilter/backends/sqlalchemy/filters.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from datetime import timedelta
from datetime import datetime, timedelta
from functools import reduce
from inspect import signature
from typing import Callable, Dict, Optional
Expand Down Expand Up @@ -196,6 +196,12 @@ def temporal(lhs, time_or_period, op):
low = time_or_period
elif op == "TEQUALS":
equal = time_or_period
elif op == "DISJOINT":
if isinstance(time_or_period, datetime):
low = time_or_period
high = time_or_period
else:
high, low = time_or_period
else:
low, high = time_or_period

Expand All @@ -205,7 +211,7 @@ def temporal(lhs, time_or_period, op):
high = low + high
if low is not None or high is not None:
if low is not None and high is not None:
return between(lhs, low, high)
return between(lhs, low, high, negate = (op == "DISJOINT"))
elif low is not None:
return runop(lhs, low, ">=")
else:
Expand Down
1 change: 1 addition & 0 deletions pygeofilter/cql2.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
"t_endedby": ast.TimeEndedBy,
"t_equals": ast.TimeEquals,
"t_intersects": ast.TimeOverlaps,
"t_disjoint": ast.TimeDisjoint
}


Expand Down
2 changes: 2 additions & 0 deletions pygeofilter/parsers/cql2_text/grammar.lark
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@


?temporal_predicate: expression _binary_temporal_predicate_func expression -> binary_temporal_predicate
| _binary_temporal_predicate_func "(" expression "," expression ")" -> prefixed_temporal_predicate

!_binary_temporal_predicate_func: "T_BEFORE"i
| "T_AFTER"i
Expand All @@ -79,6 +80,7 @@
| "T_ENDEDBY"i
| "T_EQUALS"i
| "T_INTERSECTS"i
| "T_DISJOINT"i


?spatial_predicate: _binary_spatial_predicate_func "(" expression "," expression ")" -> binary_spatial_predicate
Expand Down
4 changes: 4 additions & 0 deletions pygeofilter/parsers/cql2_text/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,10 @@ def binary_spatial_predicate(self, op, lhs, rhs):
def binary_temporal_predicate(self, lhs, op, rhs):
op = op.lower()
return TEMPORAL_PREDICATES_MAP[op](lhs, rhs)

def prefixed_temporal_predicate(self, op, lhs, rhs):
op = op.lower()
return TEMPORAL_PREDICATES_MAP[op](lhs, rhs)

def relate_spatial_predicate(self, lhs, rhs, pattern):
return ast.Relate(lhs, rhs, pattern)
Expand Down
9 changes: 9 additions & 0 deletions tests/backends/sqlalchemy/test_evaluate.py
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,15 @@ def test_casei_json_like(db_session):

# temporal predicates

def test_tbefore(db_session):
evaluate(db_session, "T_BEFORE(datetimeAttribute, TIMESTAMP('2000-01-01T00:00:01Z'))", ("A",), None, parse_cql_text)

def test_tdisjoint(db_session):
evaluate(db_session, "T_DISJOINT(datetimeAttribute, TIMESTAMP('2000-01-01T00:00:10Z'))", ("A",), None, parse_cql_text)

def test_tintersects(db_session):
evaluate(db_session, "T_INTERSECTS(datetimeAttribute, INTERVAL('2000-01-01T00:00:09Z', '2000-01-01T00:00:11Z'))", ("B",), None, parse_cql_text)

def test_date_gte(db_session):
Comment thread
mikemahoney218-usgs marked this conversation as resolved.
evaluate(db_session, "datetimeAttribute >= DATE('2000-01-01')", ("A", "B",), None, parse_cql_text)

Expand Down
104 changes: 104 additions & 0 deletions tests/parsers/cql2_text/test_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,110 @@ def test_attribute_tintersects_dt_dr():
),
)

def test_prefix_tafter_timestamp():
result = parse(
"T_AFTER(attr, TIMESTAMP('2022-04-24T07:59:57Z'))"
)
assert result == ast.TimeAfter(
ast.Attribute("attr"),
datetime(2022, 4, 24, 7, 59, 57, tzinfo=StaticTzInfo("Z", timedelta(0)))
)

def test_prefix_tafter_interval():
result = parse(
"T_AFTER(attr, INTERVAL('2021-01-01T00:00:00Z','2021-12-31T23:59:59Z'))"
)
assert result == ast.TimeAfter(
ast.Attribute("attr"),
values.Interval(
datetime(2021, 1, 1, 0, 0, 0, tzinfo=StaticTzInfo("Z", timedelta(0))),
datetime(2021, 12, 31, 23, 59, 59, tzinfo=StaticTzInfo("Z", timedelta(0))),
)
)

def test_prefix_tbefore_timestamp():
result = parse(
"T_BEFORE(attr, TIMESTAMP('2022-04-24T07:59:57Z'))"
)
assert result == ast.TimeBefore(
ast.Attribute("attr"),
datetime(2022, 4, 24, 7, 59, 57, tzinfo=StaticTzInfo("Z", timedelta(0)))
)

def test_prefix_tbefore_interval():
result = parse(
"T_BEFORE(attr, INTERVAL('2021-01-01T00:00:00Z','2021-12-31T23:59:59Z'))"
)
assert result == ast.TimeBefore(
ast.Attribute("attr"),
values.Interval(
datetime(2021, 1, 1, 0, 0, 0, tzinfo=StaticTzInfo("Z", timedelta(0))),
datetime(2021, 12, 31, 23, 59, 59, tzinfo=StaticTzInfo("Z", timedelta(0))),
)
)

def test_prefix_tdisjoint_timestamp():
result = parse(
"T_DISJOINT(attr, TIMESTAMP('2022-04-24T07:59:57Z'))"
)
assert result == ast.TimeDisjoint(
ast.Attribute("attr"),
datetime(2022, 4, 24, 7, 59, 57, tzinfo=StaticTzInfo("Z", timedelta(0)))
)

def test_prefix_tdisjoint_interval():
result = parse(
"T_DISJOINT(attr, INTERVAL('2021-01-01T00:00:00Z','2021-12-31T23:59:59Z'))"
)
assert result == ast.TimeDisjoint(
ast.Attribute("attr"),
values.Interval(
datetime(2021, 1, 1, 0, 0, 0, tzinfo=StaticTzInfo("Z", timedelta(0))),
datetime(2021, 12, 31, 23, 59, 59, tzinfo=StaticTzInfo("Z", timedelta(0))),
)
)

def test_prefix_tequals_timestamp():
result = parse(
"T_EQUALS(attr, TIMESTAMP('2022-04-24T07:59:57Z'))"
)
assert result == ast.TimeEquals(
ast.Attribute("attr"),
datetime(2022, 4, 24, 7, 59, 57, tzinfo=StaticTzInfo("Z", timedelta(0)))
)

def test_prefix_tequals_interval():
result = parse(
"T_EQUALS(attr, INTERVAL('2021-01-01T00:00:00Z','2021-12-31T23:59:59Z'))"
)
assert result == ast.TimeEquals(
ast.Attribute("attr"),
values.Interval(
datetime(2021, 1, 1, 0, 0, 0, tzinfo=StaticTzInfo("Z", timedelta(0))),
datetime(2021, 12, 31, 23, 59, 59, tzinfo=StaticTzInfo("Z", timedelta(0))),
)
)

def test_prefix_tintersects_timestamp():
result = parse(
"T_INTERSECTS(attr, TIMESTAMP('2022-04-24T07:59:57Z'))"
)
assert result == ast.TimeOverlaps(
ast.Attribute("attr"),
datetime(2022, 4, 24, 7, 59, 57, tzinfo=StaticTzInfo("Z", timedelta(0)))
)

def test_prefix_tintersects_interval():
result = parse(
"T_INTERSECTS(attr, INTERVAL('2021-01-01T00:00:00Z','2021-12-31T23:59:59Z'))"
)
assert result == ast.TimeOverlaps(
ast.Attribute("attr"),
values.Interval(
datetime(2021, 1, 1, 0, 0, 0, tzinfo=StaticTzInfo("Z", timedelta(0))),
datetime(2021, 12, 31, 23, 59, 59, tzinfo=StaticTzInfo("Z", timedelta(0))),
)
)

def test_intersects_geometry():
result = parse(
Expand Down
Loading