server: implemented filter/sort by date taken

- [overview] implemented filtering and sorting by date taken, optionally
  with null.
- [server] added `SORT_DESC_NULL_LAST` search token in `search/tokens.py`,
  `search/base_search_config.py`
- [server] implemented `SORT_DESC_NULL_LAST` functionality in
  `search/executor.py`
- [server] added date taken search aliases in
  `search/configs/post_search_config.py`
- [server] added `NullCriterion` in `search/criteria.py`; it's literally
  null
- [server] implemented filtering by null for date criterion in
  `search/configs/util.py`
- [server] aliased `NullCriterion` to "null", "none", "unknown", or "?" in
  `search/parser.py`
- [server][minor] added "posted" and "edited" aliases to creation_date
  and last_edit_date
This commit is contained in:
skybldev 2021-11-29 17:04:56 -05:00
parent f73dd02c7d
commit 066993ee07
7 changed files with 35 additions and 1 deletions

View file

@ -11,6 +11,7 @@ class BaseSearchConfig:
SORT_NONE = tokens.SortToken.SORT_NONE
SORT_ASC = tokens.SortToken.SORT_ASC
SORT_DESC = tokens.SortToken.SORT_DESC
SORT_DESC_NULL_LAST = tokens.SortToken.SORT_DESC_NULL_LAST
def on_search_query_parsed(self, search_query: SearchQuery) -> None:
pass

View file

@ -305,7 +305,13 @@ class PostSearchConfig(BaseSearchConfig):
),
),
(
["creation-date", "creation-time", "date", "time"],
[
"creation-date",
"creation-time",
"date",
"time",
"posted",
],
search_util.create_date_filter(model.Post.creation_time),
),
(
@ -314,9 +320,14 @@ class PostSearchConfig(BaseSearchConfig):
"last-edit-time",
"edit-date",
"edit-time",
"edited",
],
search_util.create_date_filter(model.Post.last_edit_time),
),
(
["date-taken", "time-taken", "taken"],
search_util.create_date_filter(model.Post.date_taken),
),
(
["comment-date", "comment-time"],
search_util.create_date_filter(
@ -403,6 +414,10 @@ class PostSearchConfig(BaseSearchConfig):
],
(model.Post.last_edit_time, self.SORT_DESC),
),
(
["date-taken", "taken"],
(model.Post.date_taken, self.SORT_DESC_NULL_LAST),
),
(
["comment-date", "comment-time"],
(model.Post.last_comment_creation_time, self.SORT_DESC),

View file

@ -179,6 +179,8 @@ def apply_date_criterion_to_column(
elif criterion.max_value:
max_date = util.parse_time_range(criterion.max_value)[1]
expr = column <= max_date
elif isinstance(criterion, criteria.NullCriterion):
expr = column == sa.sql.null()
else:
assert False
return expr

View file

@ -42,3 +42,12 @@ class ArrayCriterion(BaseCriterion):
def __hash__(self) -> int:
return hash(tuple(["array"] + self.values))
class NullCriterion(BaseCriterion):
def __init__(self, original_text) -> None:
super().__init__(original_text)
self.value = None
def __hash__(self) -> int:
return hash(self.value)

View file

@ -189,6 +189,10 @@ class Executor:
db_query = db_query.order_by(column.asc())
elif order == sort_token.SORT_DESC:
db_query = db_query.order_by(column.desc())
elif order == sort_token.SORT_DESC_NULL_LAST:
db_query = db_query.order_by(
column.is_(None), column.desc()
)
db_query = self.config.finalize_query(db_query)
return db_query

View file

@ -19,6 +19,8 @@ def _create_criterion(
if not low and not high:
raise errors.SearchError("Empty ranged value")
return criteria.RangedCriterion(original_value, low, high)
if value.lower() in ["null", "none", "unknown", "?"]:
return criteria.NullCriterion(original_value)
return criteria.PlainCriterion(original_value, value)

View file

@ -23,6 +23,7 @@ class NamedToken(AnonymousToken):
class SortToken:
SORT_DESC = "desc"
SORT_DESC_NULL_LAST = "desc null last"
SORT_ASC = "asc"
SORT_NONE = ""
SORT_DEFAULT = "default"