diff --git a/tagstudio/src/core/library/alchemy/visitors.py b/tagstudio/src/core/library/alchemy/visitors.py index 2b649b41..1e9ec043 100644 --- a/tagstudio/src/core/library/alchemy/visitors.py +++ b/tagstudio/src/core/library/alchemy/visitors.py @@ -37,6 +37,11 @@ class SQLBoolExpressionBuilder(BaseVisitor): return Entry.suffix.in_(map(lambda x: x.replace(".", ""), extensions)) elif node.type == ConstraintType.FileType: 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) + ) # raise exception if Constraint stays unhandled raise NotImplementedError("This type of constraint is not implemented yet") diff --git a/tagstudio/src/core/query_lang/ast.py b/tagstudio/src/core/query_lang/ast.py index 820a79c5..d4346964 100644 --- a/tagstudio/src/core/query_lang/ast.py +++ b/tagstudio/src/core/query_lang/ast.py @@ -9,6 +9,7 @@ class ConstraintType(Enum): # TODO add remaining ones MediaType = 2 FileType = 3 Path = 4 + Special = 5 @staticmethod def from_string(text: str) -> "ConstraintType": @@ -18,6 +19,7 @@ class ConstraintType(Enum): # TODO add remaining ones "mediatype": ConstraintType.MediaType, "filetype": ConstraintType.FileType, "path": ConstraintType.Path, + "special": ConstraintType.Special, }.get(text.lower(), None)