Skip to content

Commit

Permalink
Remove NamedQuery
Browse files Browse the repository at this point in the history
Remove 'NamedQuery' since it is not being used by any queries any more.

This simplifies query parsing logic in 'queryparse.py'. We know that
this logic can only receive 'FieldQuery' thus I adjusted types and
removed the logic that handles other cases.

Effectively, this means that the query parsing logic does not any more
care whether the query is named by the corresponding DB field. Instead,
queries like 'SingletonQuery' and 'PlaylistQuery' are responsible for
translating 'singleton' and 'playlist' to the underlying DB filters.
  • Loading branch information
snejus committed Apr 25, 2024
1 parent afe9043 commit 5a4e33c
Show file tree
Hide file tree
Showing 5 changed files with 19 additions and 54 deletions.
1 change: 0 additions & 1 deletion beets/dbcore/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
FieldQuery,
InvalidQueryError,
MatchQuery,
NamedQuery,
OrQuery,
Query,
)
Expand Down
12 changes: 4 additions & 8 deletions beets/dbcore/db.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.

"""The central Model and Database constructs for DBCore.
"""
"""The central Model and Database constructs for DBCore."""

from __future__ import annotations

Expand Down Expand Up @@ -308,7 +307,7 @@ class Model(ABC):
are subclasses of `Sort`.
"""

_queries: Dict[str, Type[Query]] = {}
_queries: Dict[str, Type[FieldQuery]] = {}
"""Named queries that use a field-like `name:value` syntax but which
do not relate to any specific field.
"""
Expand Down Expand Up @@ -598,8 +597,7 @@ def store(self, fields: Optional[Iterable[str]] = None):
# Deleted flexible attributes.
for key in self._dirty:
tx.mutate(
"DELETE FROM {} "
"WHERE entity_id=? AND key=?".format(self._flex_table),
f"DELETE FROM {self._flex_table} WHERE entity_id=? AND key=?",
(self.id, key),
)

Expand Down Expand Up @@ -1188,9 +1186,7 @@ def _make_attribute_table(self, flex_table: str):
UNIQUE(entity_id, key) ON CONFLICT REPLACE);
CREATE INDEX IF NOT EXISTS {0}_by_entity
ON {0} (entity_id);
""".format(
flex_table
)
""".format(flex_table)
)

# Querying.
Expand Down
9 changes: 0 additions & 9 deletions beets/dbcore/query.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,15 +115,6 @@ def __hash__(self) -> int:
return hash(type(self))


class NamedQuery(Query):
"""Non-field query, i.e. the query prefix is not a field but identifies the
query class.
"""

@abstractmethod
def __init__(self, pattern): ...


P = TypeVar("P")
SQLiteType = Union[str, float, int, memoryview]
AnySQLiteType = TypeVar("AnySQLiteType", bound=SQLiteType)
Expand Down
38 changes: 12 additions & 26 deletions beets/dbcore/queryparse.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,14 @@
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.

"""Parsing of strings into DBCore queries.
"""
"""Parsing of strings into DBCore queries."""

import itertools
import re
from typing import Collection, Dict, List, Optional, Sequence, Tuple, Type

from . import Model, query
from .query import Query, Sort
from .query import Sort

PARSE_QUERY_PART_REGEX = re.compile(
# Non-capturing optional segment for the keyword.
Expand All @@ -36,10 +35,10 @@

def parse_query_part(
part: str,
query_classes: Dict = {},
query_classes: Dict[str, Type[query.FieldQuery]] = {},
prefixes: Dict = {},
default_class: Type[query.SubstringQuery] = query.SubstringQuery,
) -> Tuple[Optional[str], str, Type[query.Query], bool]:
) -> Tuple[Optional[str], str, Type[query.FieldQuery], bool]:
"""Parse a single *query part*, which is a chunk of a complete query
string representing a single criterion.
Expand Down Expand Up @@ -128,7 +127,7 @@ def construct_query_part(

# Use `model_cls` to build up a map from field (or query) names to
# `Query` classes.
query_classes: Dict[str, Type[Query]] = {}
query_classes: Dict[str, Type[query.FieldQuery]] = {}
for k, t in itertools.chain(
model_cls._fields.items(), model_cls._types.items()
):
Expand All @@ -143,30 +142,17 @@ def construct_query_part(
# If there's no key (field name) specified, this is a "match
# anything" query.
if key is None:
if issubclass(query_class, query.FieldQuery):
# The query type matches a specific field, but none was
# specified. So we use a version of the query that matches
# any field.
out_query = query.AnyFieldQuery(
pattern, model_cls._search_fields, query_class
)
elif issubclass(query_class, query.NamedQuery):
# Non-field query type.
out_query = query_class(pattern)
else:
assert False, "Unexpected query type"
# The query type matches a specific field, but none was
# specified. So we use a version of the query that matches
# any field.
out_query = query.AnyFieldQuery(
pattern, model_cls._search_fields, query_class
)

# Field queries get constructed according to the name of the field
# they are querying.
elif issubclass(query_class, query.FieldQuery):
key = key.lower()
out_query = query_class(key.lower(), pattern, key in model_cls._fields)

# Non-field (named) query.
elif issubclass(query_class, query.NamedQuery):
out_query = query_class(pattern)
else:
assert False, "Unexpected query type"
out_query = query_class(key.lower(), pattern, key in model_cls._fields)

# Apply negation.
if negate:
Expand Down
13 changes: 3 additions & 10 deletions test/test_dbcore.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.

"""Tests for the DBCore database abstraction.
"""
"""Tests for the DBCore database abstraction."""

import os
import shutil
Expand All @@ -32,7 +31,7 @@ class SortFixture(dbcore.query.FieldSort):
pass


class QueryFixture(dbcore.query.NamedQuery):
class QueryFixture(dbcore.query.FieldQuery):
def __init__(self, pattern):
self.pattern = pattern

Expand Down Expand Up @@ -516,9 +515,7 @@ def pqp(self, part):
part,
{"year": dbcore.query.NumericQuery},
{":": dbcore.query.RegexpQuery},
)[
:-1
] # remove the negate flag
)[:-1] # remove the negate flag

def test_one_basic_term(self):
q = "test"
Expand Down Expand Up @@ -605,10 +602,6 @@ def test_empty_query_part(self):
q = self.qfs([""])
self.assertIsInstance(q.subqueries[0], dbcore.query.TrueQuery)

def test_parse_named_query(self):
q = self.qfs(["some_query:foo"])
self.assertIsInstance(q.subqueries[0], QueryFixture)


class SortFromStringsTest(unittest.TestCase):
def sfs(self, strings):
Expand Down

0 comments on commit 5a4e33c

Please sign in to comment.