eliminated pointless distinction between Queries and QueryElements

--HG--
extra : convert_revision : svn%3A41726ec3-264d-0410-9c23-a9f1637257cc/trunk%4014
This commit is contained in:
adrian.sampson 2008-06-11 07:14:37 +00:00
parent f6feb5fbb0
commit e07131830e
2 changed files with 39 additions and 39 deletions

View file

@ -188,16 +188,30 @@ class Item(object):
class QueryElement(object): class Query(object):
"""A building block for library queries.""" """An abstract class representing a query into the item database."""
def clause(self): def clause(self):
"""Returns (clause, subvals) where clause is a valid sqlite WHERE """Returns (clause, subvals) where clause is a valid sqlite WHERE
clause implementing the query element and subvals is a list of items clause implementing the query and subvals is a list of items to be
to be substituted for ?s in the clause.""" substituted for ?s in the clause."""
raise NotImplementedError raise NotImplementedError
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 SubstringQueryElement(QueryElement): class SubstringQuery(Query):
"""A query element that matches a substring in a specific item field.""" """A query that matches a substring in a specific item field."""
def __init__(self, field, pattern): def __init__(self, field, pattern):
if field not in item_keys: if field not in item_keys:
@ -212,8 +226,8 @@ class SubstringQueryElement(QueryElement):
subvals = [search] subvals = [search]
return (clause, subvals) return (clause, subvals)
class AnySubstringQueryElement(QueryElement): class AnySubstringQuery(Query):
"""A query element that matches a substring in any item field.""" """A query that matches a substring in any item field."""
def __init__(self, pattern): def __init__(self, pattern):
self.pattern = pattern self.pattern = pattern
@ -222,16 +236,16 @@ class AnySubstringQueryElement(QueryElement):
clause_parts = [] clause_parts = []
subvals = [] subvals = []
for field in item_keys: for field in item_keys:
el_clause, el_subvals = (SubstringQueryElement(field, self.pattern) el_clause, el_subvals = (SubstringQuery(field, self.pattern)
.clause()) .clause())
clause_parts.append('(' + el_clause + ')') clause_parts.append('(' + el_clause + ')')
subvals += el_subvals subvals += el_subvals
clause = ' or '.join(clause_parts) clause = ' or '.join(clause_parts)
return clause, subvals return clause, subvals
class AndQueryElement(QueryElement): class AndQuery(Query):
"""A conjunction of a list of other query elements. Can be indexed like a """A conjunction of a list of other queries. Can be indexed like a list to
list to access the sub-elements.""" access the sub-queries."""
def __init__(self, elements = None): def __init__(self, elements = None):
if elements is None: if elements is None:
@ -259,11 +273,11 @@ class AndQueryElement(QueryElement):
@classmethod @classmethod
def from_dict(cls, matches): def from_dict(cls, matches):
"""Construct a query element from a dictionary, matches, whose keys """Construct a query from a dictionary, matches, whose keys are item
are item field names and whose values are substring patterns.""" field names and whose values are substring patterns."""
elements = [] elements = []
for key, pattern in matches.iteritems(): for key, pattern in matches.iteritems():
elements.append(SubstringQueryElement(key, pattern)) elements.append(SubstringQuery(key, pattern))
return cls(elements) return cls(elements)
@ -277,7 +291,7 @@ class AndQueryElement(QueryElement):
r'(?<!\\):' # unescaped : r'(?<!\\):' # unescaped :
r')?' r')?'
r'(\S+)', # the term itself, greedily consumed r'(\S+)', # the term itself
re.I) # case-insensitive re.I) # case-insensitive
@classmethod @classmethod
def _parse_query(cls, query_string): def _parse_query(cls, query_string):
@ -304,34 +318,20 @@ class AndQueryElement(QueryElement):
elements = [] elements = []
for key, pattern in cls._parse_query(query_string): for key, pattern in cls._parse_query(query_string):
if key is None: # no key specified; match any field 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 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 if not elements: # no terms in query
elements = [TrueQueryElement()] elements = [TrueQuery()]
return cls(elements) return cls(elements)
class TrueQueryElement(QueryElement): class TrueQuery(Query):
"""A query element that always matches.""" """A query that always matches."""
def clause(self): def clause(self):
return '1', () return '1', ()
class Query(AndQueryElement): class Query(AndQuery):
"""A query into the item database.""" """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): class ResultIterator(object):
"""An iterator into an item query result set.""" """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 """Returns a ResultIterator to the items matching query, which may be
None (match the entire library), a Query object, or a query string.""" None (match the entire library), a Query object, or a query string."""
if query is None: if query is None:
query = Query([TrueQueryElement()]) query = TrueQuery()
elif isinstance(query, str) or isinstance(query, unicode): elif isinstance(query, str) or isinstance(query, unicode):
query = Query.from_string(query) query = AndQuery.from_string(query)
elif not isinstance(query, Query): elif not isinstance(query, Query):
raise ValueError('query must be None or have type Query or str') raise ValueError('query must be None or have type Query or str')
return query.execute(self) return query.execute(self)

View file

@ -3,7 +3,7 @@ import unittest, sys, os
sys.path.append('..') sys.path.append('..')
import beets.library import beets.library
parse_query = beets.library.AndQueryElement._parse_query parse_query = beets.library.AndQuery._parse_query
class QueryParseTest(unittest.TestCase): class QueryParseTest(unittest.TestCase):
def test_one_basic_term(self): def test_one_basic_term(self):