diff --git a/tagstudio/src/core/library/alchemy/library.py b/tagstudio/src/core/library/alchemy/library.py index b700b4fc5..ee508179a 100644 --- a/tagstudio/src/core/library/alchemy/library.py +++ b/tagstudio/src/core/library/alchemy/library.py @@ -49,7 +49,7 @@ TextField, _FieldID, ) -from .joins import TagSubtag +from .joins import TagEntry, TagSubtag from .models import Entry, Folder, Preferences, Tag, TagAlias, ValueType from .visitors import SQLBoolExpressionBuilder @@ -558,7 +558,7 @@ def search_library( statement = select(Entry) if search.ast: - statement = statement.outerjoin(Entry.tag_box_fields).where( + statement = statement.outerjoin(TagEntry).where( SQLBoolExpressionBuilder(self).visit(search.ast) ) diff --git a/tagstudio/src/core/library/alchemy/visitors.py b/tagstudio/src/core/library/alchemy/visitors.py index 6f73a45a2..a27749c4f 100644 --- a/tagstudio/src/core/library/alchemy/visitors.py +++ b/tagstudio/src/core/library/alchemy/visitors.py @@ -7,8 +7,8 @@ from src.core.query_lang import BaseVisitor from src.core.query_lang.ast import AST, ANDList, Constraint, ConstraintType, Not, ORList, Property -from .joins import TagField -from .models import Entry, Tag, TagAlias, TagBoxField +from .joins import TagEntry +from .models import Entry, Tag, TagAlias # workaround to have autocompletion in the Editor if TYPE_CHECKING: @@ -50,19 +50,20 @@ def visit_and_list(self, node: ANDList) -> ColumnExpressionArgument: # If there is just one tag id, check the normal way elif len(tag_ids) == 1: bool_expressions.append( - self.__entry_satisfies_expression(TagField.tag_id == tag_ids[0]) + self.__entry_satisfies_expression(TagEntry.tag_id == tag_ids[0]) ) return and_(*bool_expressions) def visit_constraint(self, node: Constraint) -> ColumnExpressionArgument: + """Returns a Boolean Expression that is true, if the Entry satisfies the constraint.""" if len(node.properties) != 0: raise NotImplementedError("Properties are not implemented yet") # TODO TSQLANG if node.type == ConstraintType.Tag: - return TagBoxField.tags.any(Tag.id.in_(self.__get_tag_ids(node.value))) + return Entry.tags.any(Tag.id.in_(self.__get_tag_ids(node.value))) elif node.type == ConstraintType.TagID: - return TagBoxField.tags.any(Tag.id == int(node.value)) + return Entry.tags.any(Tag.id == int(node.value)) elif node.type == ConstraintType.Path: return Entry.path.op("GLOB")(node.value) elif node.type == ConstraintType.MediaType: @@ -76,9 +77,7 @@ def visit_constraint(self, node: Constraint) -> ColumnExpressionArgument: return Entry.suffix.ilike(node.value) elif node.type == ConstraintType.Special: # noqa: SIM102 unnecessary once there is a second special constraint if node.value.lower() == "untagged": - return ~Entry.id.in_( - select(Entry.id).join(Entry.tag_box_fields).join(TagBoxField.tags) - ) + return ~Entry.id.in_(select(Entry.id).join(TagEntry)) # raise exception if Constraint stays unhandled raise NotImplementedError("This type of constraint is not implemented yet") @@ -105,11 +104,10 @@ def __entry_has_all_tags(self, tag_ids: list[int]) -> BinaryExpression[bool]: # Relational Division Query return Entry.id.in_( select(Entry.id) - .outerjoin(TagBoxField) - .outerjoin(TagField) - .where(TagField.tag_id.in_(tag_ids)) + .outerjoin(TagEntry) + .where(TagEntry.tag_id.in_(tag_ids)) .group_by(Entry.id) - .having(func.count(distinct(TagField.tag_id)) == len(tag_ids)) + .having(func.count(distinct(TagEntry.tag_id)) == len(tag_ids)) ) def __entry_satisfies_ast(self, partial_query: AST) -> BinaryExpression[bool]: @@ -119,7 +117,8 @@ def __entry_satisfies_ast(self, partial_query: AST) -> BinaryExpression[bool]: def __entry_satisfies_expression( self, expr: ColumnExpressionArgument ) -> BinaryExpression[bool]: - """Returns Binary Expression that is true if the Entry satisfies the column expression.""" - return Entry.id.in_( - select(Entry.id).outerjoin(Entry.tag_box_fields).outerjoin(TagField).where(expr) - ) + """Returns Binary Expression that is true if the Entry satisfies the column expression. + + Executed on: Entry ⟕ TagEntry (Entry LEFT OUTER JOIN TagEntry). + """ + return Entry.id.in_(select(Entry.id).outerjoin(TagEntry).where(expr))