Add a query class for years with support for ranges.

This commit is contained in:
Michael Schuerig 2013-04-25 00:36:21 +02:00
parent bf904187e2
commit fe41bba380
2 changed files with 74 additions and 0 deletions

View file

@ -549,6 +549,31 @@ class BooleanQuery(MatchQuery):
self.pattern = util.str2bool(pattern)
self.pattern = int(self.pattern)
class YearQuery(FieldQuery):
"""Matches a year or years against a year field.
"""
@classmethod
def applies_to(cls, field):
return field in ['year', 'original_year']
@classmethod
def value_match(cls, pattern, value):
"""Determine whether the value matches the pattern. Both
arguments are strings.
"""
return value in cls._expanded_years(pattern)
def clause(self):
years = YearQuery._expanded_years(self.pattern)
return self.field + " IN (" + ",".join(years) + ")", ()
@classmethod
def _expanded_years(self, pattern):
ranges = [[int(y) for y in se.split('-')] for se in pattern.split(',')]
years = [range(r[0], r[1] + 1) if len(r) > 1 else [r[0]] for r in ranges]
return [str(y) for yrs in years for y in yrs]
class SingletonQuery(Query):
"""Matches either singleton or non-singleton items."""
def __init__(self, sense):
@ -750,6 +775,8 @@ def parse_query_part(part):
for pre, query_class in prefixes.items():
if term.startswith(pre):
return key, term[len(pre):], query_class
if YearQuery.applies_to(key):
return key, term, YearQuery
return key, term, SubstringQuery # The default query type.
def construct_query_part(query_part, default_fields, all_keys):

View file

@ -60,6 +60,22 @@ class QueryParseTest(unittest.TestCase):
r = (None, 'test:regexp', beets.library.RegexpQuery)
self.assertEqual(pqp(q), r)
def test_single_year(self):
q = 'year:1999'
r = ('year', '1999', beets.library.YearQuery)
self.assertEqual(pqp(q), r)
def test_multiple_years(self):
q = 'year:1999,2002,2010'
r = ('year', '1999,2002,2010', beets.library.YearQuery)
self.assertEqual(pqp(q), r)
def test_year_range(self):
q = 'year:1999-2001'
r = ('year', '1999-2001', beets.library.YearQuery)
self.assertEqual(pqp(q), r)
class AnyFieldQueryTest(unittest.TestCase):
def setUp(self):
self.lib = beets.library.Library(':memory:')
@ -219,6 +235,29 @@ class GetTest(unittest.TestCase, AssertsMixin):
self.assert_matched(results, 'Littlest Things')
self.assert_done(results)
def test_single_year(self):
q = 'year:2006'
results = self.lib.items(q)
self.assert_matched(results, 'Littlest Things')
self.assert_matched(results, 'Lovers Who Uncover')
self.assert_done(results)
def test_year_range(self):
q = 'year:2000-2010'
results = self.lib.items(q)
self.assert_matched(results, 'Littlest Things')
self.assert_matched(results, 'Take Pills')
self.assert_matched(results, 'Lovers Who Uncover')
self.assert_done(results)
def test_multiple_years(self):
q = 'year:1987,2004-2006'
results = self.lib.items(q)
self.assert_matched(results, 'Littlest Things')
self.assert_matched(results, 'Lovers Who Uncover')
self.assert_matched(results, 'Boracay')
self.assert_done(results)
class MemoryGetTest(unittest.TestCase, AssertsMixin):
def setUp(self):
self.album_item = _common.item()
@ -312,6 +351,14 @@ class MatchTest(unittest.TestCase):
q = beets.library.SubstringQuery('disc', '6')
self.assertTrue(q.match(self.item))
def test_year_match_positive(self):
q = beets.library.YearQuery('year', '1')
self.assertTrue(q.match(self.item))
def test_year_match_negative(self):
q = beets.library.YearQuery('year', '10')
self.assertFalse(q.match(self.item))
class PathQueryTest(unittest.TestCase, AssertsMixin):
def setUp(self):
self.lib = beets.library.Library(':memory:')