Skip to content

Commit 64d653a

Browse files
author
Repumba
committed
Querying by related files
1 parent dc4c917 commit 64d653a

File tree

2 files changed

+85
-0
lines changed

2 files changed

+85
-0
lines changed

mwdb/core/search/fields.py

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
Member,
2020
Object,
2121
ObjectPermission,
22+
RelatedFile,
2223
TextBlob,
2324
User,
2425
db,
@@ -732,3 +733,85 @@ def _get_condition(
732733
else:
733734
condition = or_((self.column == value), File.alt_names.any(value))
734735
return condition
736+
737+
738+
class RelatedField(BaseField):
739+
accepts_range = True
740+
accepts_subfields = True
741+
accepts_wildcards = True
742+
743+
def count_condition(self, expression):
744+
def parse_count_value(value):
745+
try:
746+
value = int(value)
747+
if value < 0:
748+
raise ValueError
749+
except ValueError:
750+
raise UnsupportedGrammarException(
751+
"Field related.count accepts statements with "
752+
"only correct integer values"
753+
)
754+
return value
755+
756+
if isinstance(expression, Range):
757+
low_value = expression.low.value
758+
high_value = expression.high.value
759+
760+
if low_value != "*":
761+
low_value = parse_count_value(low_value)
762+
if high_value != "*":
763+
high_value = parse_count_value(high_value)
764+
765+
low_condition = (
766+
func.count() >= low_value
767+
if expression.include_low
768+
else func.count() > low_value
769+
)
770+
high_condition = (
771+
func.count() <= high_value
772+
if expression.include_high
773+
else func.count() < high_value
774+
)
775+
776+
if high_value == "*" and low_value == "*":
777+
condition = True
778+
elif high_value == "*":
779+
condition = low_condition
780+
elif low_value == "*":
781+
condition = high_condition
782+
else:
783+
condition = and_(low_condition, high_condition)
784+
else:
785+
upload_value = parse_count_value(expression.value)
786+
condition = func.count() == upload_value
787+
788+
related = (
789+
db.session.query(RelatedFile.object_id)
790+
.group_by(RelatedFile.object_id)
791+
.having(condition)
792+
).all()
793+
found_ids = [r[0] for r in related]
794+
return RelatedFile.object_id.in_(found_ids)
795+
796+
def _get_condition(
797+
self, expression: Expression, subfields: List[Tuple[str, int]]
798+
) -> Any:
799+
if len(subfields) <= 1: # [('related', 0)]
800+
raise FieldNotQueryableException("One subfield is required")
801+
if len(subfields) > 2:
802+
raise FieldNotQueryableException(f"Too many subfields: {len(subfields)}")
803+
804+
key = subfields[1][0]
805+
806+
if key == "name":
807+
field = StringField(RelatedFile.file_name)
808+
elif key == "size":
809+
field = SizeField(RelatedFile.file_size)
810+
elif key == "sha256":
811+
field = StringField(RelatedFile.sha256)
812+
elif key == "count":
813+
return self.column.any(self.count_condition(expression))
814+
else:
815+
raise FieldNotQueryableException(f"No such subfield: {key}")
816+
817+
return self.column.any(field._get_condition(expression, subfields))

mwdb/core/search/mappings.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
JSONField,
2424
ListField,
2525
MultiField,
26+
RelatedField,
2627
RelationField,
2728
ShareField,
2829
SizeField,
@@ -56,6 +57,7 @@
5657
"karton": UUIDField(Object.analyses, KartonAnalysis.id),
5758
"comment_author": CommentAuthorField(Object.comment_authors, User.login),
5859
"upload_count": UploadCountField(Object.upload_count),
60+
"related": RelatedField(Object.related_files),
5961
},
6062
File.__name__: {
6163
"name": FileNameField(File.file_name),

0 commit comments

Comments
 (0)