mirror of
https://github.com/beetbox/beets.git
synced 2025-12-06 16:42:42 +01:00
eliminated pointless distinction between Queries and QueryElements
--HG-- extra : convert_revision : svn%3A41726ec3-264d-0410-9c23-a9f1637257cc/trunk%4014
This commit is contained in:
parent
f6feb5fbb0
commit
e07131830e
2 changed files with 39 additions and 39 deletions
|
|
@ -188,16 +188,30 @@ class Item(object):
|
|||
|
||||
|
||||
|
||||
class QueryElement(object):
|
||||
"""A building block for library queries."""
|
||||
class Query(object):
|
||||
"""An abstract class representing a query into the item database."""
|
||||
def clause(self):
|
||||
"""Returns (clause, subvals) where clause is a valid sqlite WHERE
|
||||
clause implementing the query element and subvals is a list of items
|
||||
to be substituted for ?s in the clause."""
|
||||
clause implementing the query and subvals is a list of items to be
|
||||
substituted for ?s in the clause."""
|
||||
raise NotImplementedError
|
||||
|
||||
class SubstringQueryElement(QueryElement):
|
||||
"""A query element that matches a substring in a specific item field."""
|
||||
def statement(self, columns='*'):
|
||||
"""Returns (query, subvals) where clause is a sqlite SELECT statement
|
||||
to enact this query and subvals is a list of values to substitute in
|
||||
for ?s in the query."""
|
||||
clause, subvals = self.clause()
|
||||
return ('select ' + columns + ' from items where ' + clause, subvals)
|
||||
|
||||
def execute(self, library):
|
||||
"""Runs the query in the specified library, returning an
|
||||
ItemResultIterator."""
|
||||
cursor = library.conn.cursor()
|
||||
cursor.execute(*self.statement())
|
||||
return ResultIterator(cursor)
|
||||
|
||||
class SubstringQuery(Query):
|
||||
"""A query that matches a substring in a specific item field."""
|
||||
|
||||
def __init__(self, field, pattern):
|
||||
if field not in item_keys:
|
||||
|
|
@ -212,8 +226,8 @@ class SubstringQueryElement(QueryElement):
|
|||
subvals = [search]
|
||||
return (clause, subvals)
|
||||
|
||||
class AnySubstringQueryElement(QueryElement):
|
||||
"""A query element that matches a substring in any item field."""
|
||||
class AnySubstringQuery(Query):
|
||||
"""A query that matches a substring in any item field."""
|
||||
|
||||
def __init__(self, pattern):
|
||||
self.pattern = pattern
|
||||
|
|
@ -222,16 +236,16 @@ class AnySubstringQueryElement(QueryElement):
|
|||
clause_parts = []
|
||||
subvals = []
|
||||
for field in item_keys:
|
||||
el_clause, el_subvals = (SubstringQueryElement(field, self.pattern)
|
||||
el_clause, el_subvals = (SubstringQuery(field, self.pattern)
|
||||
.clause())
|
||||
clause_parts.append('(' + el_clause + ')')
|
||||
subvals += el_subvals
|
||||
clause = ' or '.join(clause_parts)
|
||||
return clause, subvals
|
||||
|
||||
class AndQueryElement(QueryElement):
|
||||
"""A conjunction of a list of other query elements. Can be indexed like a
|
||||
list to access the sub-elements."""
|
||||
class AndQuery(Query):
|
||||
"""A conjunction of a list of other queries. Can be indexed like a list to
|
||||
access the sub-queries."""
|
||||
|
||||
def __init__(self, elements = None):
|
||||
if elements is None:
|
||||
|
|
@ -259,11 +273,11 @@ class AndQueryElement(QueryElement):
|
|||
|
||||
@classmethod
|
||||
def from_dict(cls, matches):
|
||||
"""Construct a query element from a dictionary, matches, whose keys
|
||||
are item field names and whose values are substring patterns."""
|
||||
"""Construct a query from a dictionary, matches, whose keys are item
|
||||
field names and whose values are substring patterns."""
|
||||
elements = []
|
||||
for key, pattern in matches.iteritems():
|
||||
elements.append(SubstringQueryElement(key, pattern))
|
||||
elements.append(SubstringQuery(key, pattern))
|
||||
return cls(elements)
|
||||
|
||||
|
||||
|
|
@ -277,7 +291,7 @@ class AndQueryElement(QueryElement):
|
|||
r'(?<!\\):' # unescaped :
|
||||
r')?'
|
||||
|
||||
r'(\S+)', # the term itself, greedily consumed
|
||||
r'(\S+)', # the term itself
|
||||
re.I) # case-insensitive
|
||||
@classmethod
|
||||
def _parse_query(cls, query_string):
|
||||
|
|
@ -304,35 +318,21 @@ class AndQueryElement(QueryElement):
|
|||
elements = []
|
||||
for key, pattern in cls._parse_query(query_string):
|
||||
if key is None: # no key specified; match any field
|
||||
elements.append(AnySubstringQueryElement(pattern))
|
||||
elements.append(AnySubstringQuery(pattern))
|
||||
elif key.lower() in item_keys: # ignore unrecognized keys
|
||||
elements.append(SubstringQueryElement(key.lower(), pattern))
|
||||
elements.append(SubstringQuery(key.lower(), pattern))
|
||||
if not elements: # no terms in query
|
||||
elements = [TrueQueryElement()]
|
||||
elements = [TrueQuery()]
|
||||
return cls(elements)
|
||||
|
||||
class TrueQueryElement(QueryElement):
|
||||
"""A query element that always matches."""
|
||||
class TrueQuery(Query):
|
||||
"""A query that always matches."""
|
||||
def clause(self):
|
||||
return '1', ()
|
||||
|
||||
class Query(AndQueryElement):
|
||||
class Query(AndQuery):
|
||||
"""A query into the item database."""
|
||||
|
||||
def statement(self, columns='*'):
|
||||
"""Returns (query, subvals) where clause is a sqlite SELECT statement
|
||||
to enact this query and subvals is a list of values to substitute in
|
||||
for ?s in the query."""
|
||||
clause, subvals = self.clause()
|
||||
return ('select ' + columns + ' from items where ' + clause, subvals)
|
||||
|
||||
def execute(self, library):
|
||||
"""Runs the query in the specified library, returning an
|
||||
ItemResultIterator."""
|
||||
cursor = library.conn.cursor()
|
||||
cursor.execute(*self.statement())
|
||||
return ResultIterator(cursor)
|
||||
|
||||
class ResultIterator(object):
|
||||
"""An iterator into an item query result set."""
|
||||
|
||||
|
|
@ -428,9 +428,9 @@ class Library(object):
|
|||
"""Returns a ResultIterator to the items matching query, which may be
|
||||
None (match the entire library), a Query object, or a query string."""
|
||||
if query is None:
|
||||
query = Query([TrueQueryElement()])
|
||||
query = TrueQuery()
|
||||
elif isinstance(query, str) or isinstance(query, unicode):
|
||||
query = Query.from_string(query)
|
||||
query = AndQuery.from_string(query)
|
||||
elif not isinstance(query, Query):
|
||||
raise ValueError('query must be None or have type Query or str')
|
||||
return query.execute(self)
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import unittest, sys, os
|
|||
sys.path.append('..')
|
||||
import beets.library
|
||||
|
||||
parse_query = beets.library.AndQueryElement._parse_query
|
||||
parse_query = beets.library.AndQuery._parse_query
|
||||
|
||||
class QueryParseTest(unittest.TestCase):
|
||||
def test_one_basic_term(self):
|
||||
|
|
|
|||
Loading…
Reference in a new issue