Skip to content

Commit

Permalink
Support sort by for observation queries.
Browse files Browse the repository at this point in the history
  • Loading branch information
synrg committed Jul 15, 2024
1 parent 730e454 commit 5386720
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 9 deletions.
17 changes: 13 additions & 4 deletions dronefly/core/parsers/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,11 @@
MACROS = {
"rg": {"opt": ["quality_grade=research"]},
"nid": {"opt": ["quality_grade=needs_id"]},
"oldest": {"opt": ["order=asc", "order_by=observed_on"]},
"newest": {"opt": ["order=desc", "order_by=observed_on"]},
"reverse": {"opt": ["order=asc"]},
"oldest": {"order": "asc", "sort_by": "observed"},
"newest": {"order": "desc", "sort_by": "observed"},
"my": {"by": "me"},
"home": {"from": "home"},
"faves": {"opt": ["popular", "order_by=votes"]},
"faves": {"sort_by": "votes", "opt": ["popular"]},
"spp": {"opt": ["hrank=species"]},
"species": {"opt": ["hrank=species"]},
"unseen": {"not by": "me", "from": "home"},
Expand Down Expand Up @@ -112,3 +111,13 @@
"without_taxon_id",
"year",
]
VALID_OBS_SORT_BY = {
"added": "created_at",
"observed": "observed_on",
"votes": "votes",
# Technically these are valid values, but we are not supporting them:
# - these fields are not typically shown in Dronefly displays
# - these sort options are of limited utility & hard to explain
# "guess": "species_guess",
# "id": "id",
}
6 changes: 4 additions & 2 deletions dronefly/core/parsers/unixlike.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,9 @@ def parse(self, argument: str):
controlled_term = [term_name, term_value]
else:
controlled_term = None
sort_by = None
if vals.sort_by:
sort_by = " ".join(vals.sort_by)
try:
obs_d1 = _parse_date_arg(vals.obs_d1, "first")
obs_d2 = _parse_date_arg(vals.obs_d2, "last")
Expand All @@ -159,8 +162,7 @@ def parse(self, argument: str):
id_by=" ".join(vals.id_by),
per=" ".join(vals.per),
project=" ".join(vals.project),
sort_by=" ".join(vals.sort_by),
order=vals.order,
sort_by=sort_by,
options=vals.options,
obs_d1=obs_d1,
obs_d2=obs_d2,
Expand Down
27 changes: 24 additions & 3 deletions dronefly/core/query/query.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

from dronefly.core.formatters.generic import format_taxon_name, format_user_name
from dronefly.core.models.controlled_terms import ControlledTermSelector
from dronefly.core.parsers.constants import VALID_OBS_OPTS
from dronefly.core.parsers.constants import VALID_OBS_OPTS, VALID_OBS_SORT_BY
from pyinaturalist.models import Place, Project, Taxon, User


Expand Down Expand Up @@ -164,8 +164,10 @@ def __str__(self):
self._add_clause("added since {}", self.added_d1)
self._add_clause("added until {}", self.added_d2)
self._add_clause("added on {}", self.added_on)
self._add_clause("sorted by {}", self.sort_by)
self._add_clause("({self.order})", self.order)
if self.sort_by:
self._add_clause("sort by {}", self.sort_by)
if self.order:
self._add_clause("order {}", self.order)
return self._query


Expand Down Expand Up @@ -245,6 +247,8 @@ def get_base_query_args(query):
_added["d1"] = query.added_d1 if has_value(query.added_d1) else None
_added["d2"] = query.added_d2 if has_value(query.added_d2) else None
args["added"] = DateSelector(**_added)
args["sort_by"] = query.sort_by if has_value(query.sort_by) else None
args["order"] = query.order if has_value(query.order) else None
return args


Expand Down Expand Up @@ -281,6 +285,8 @@ class QueryResponse:
controlled_term: Optional[ControlledTermSelector] = None
observed: Optional[DateSelector] = None
added: Optional[DateSelector] = None
sort_by: Optional[str] = None
order: Optional[str] = None
adjectives: Optional[List[str]] = field(init=False)

def __post_init__(self):
Expand Down Expand Up @@ -362,6 +368,10 @@ def obs_args(self):
kwargs["created_d1"] = self.added.d1.isoformat()
if self.added.d2:
kwargs["created_d2"] = self.added.d2.isoformat()
if self.sort_by:
kwargs["order_by"] = VALID_OBS_SORT_BY.get(str(self.sort_by))
if self.order:
kwargs["order"] = str(self.order)
return kwargs

def obs_query_description(self, with_adjectives: bool = True):
Expand Down Expand Up @@ -517,4 +527,15 @@ def _format_time(time: str):
message += " {} rank {} or {}".format(
with_or_and, hrank or lrank, higher_or_lower
)
order_by = kwargs.get("order_by")
order = kwargs.get("order")
if order:
_order = "ascending" if order == "asc" else "descending"
message += f" in {_order} order"
if order_by:
_order_by = str(VALID_OBS_SORT_BY.get(order_by)).replace("_", " ")
if order:
message += f" by `#{_order_by}`"
else:
message += f" ordered by `{_order_by}`"
return re.sub(r"^ ", "", message)
8 changes: 8 additions & 0 deletions tests/query_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,3 +105,11 @@ def test_query_added_on(self):
added_on = datetime.now()
query = Query(main=TaxonQuery(terms=["birds"]), user="me", added_on=added_on)
assert str(query) == "birds by me added on {}".format(added_on)

def test_query_order_by(self):
query = Query(main=TaxonQuery(terms=["birds"]), user="me", sort_by="observed")
assert str(query) == "birds by me sort by observed"

def test_query_order(self):
query = Query(main=TaxonQuery(terms=["birds"]), user="me", order="asc")
assert str(query) == "birds by me order asc"

0 comments on commit 5386720

Please sign in to comment.