Move SmartArtistSort to library (#953)

Models can now have a dict of special sort classes.
This commit is contained in:
Adrian Sampson 2014-09-15 19:43:22 -07:00
parent e2b3fafefa
commit f9c6dd6d67
5 changed files with 44 additions and 24 deletions

View file

@ -124,6 +124,11 @@ class Model(object):
"""Optional Types for non-fixed (i.e., flexible and computed) fields.
"""
_sorts = {}
"""Optional named sort criteria. The keys are strings and the values
are subclasses of `Sort`.
"""
@classmethod
def _getters(cls):
"""Return a mapping from field names to getter functions.

View file

@ -619,25 +619,6 @@ class FixedFieldSort(FieldSort):
return "{0} {1}".format(self.field, order)
class SmartArtistSort(Sort):
"""Sort by artist (either album artist or track artist),
prioritizing the sort field over the raw field.
"""
def __init__(self, model_cls, is_ascending=True):
self.model_cls = model_cls
self.is_ascending = is_ascending
def order_clause(self):
order = "ASC" if self.is_ascending else "DESC"
if 'albumartist' in self.model_cls._fields:
field = 'albumartist'
else:
field = 'artist'
return ('(CASE {0}_sort WHEN NULL THEN {0} '
'WHEN "" THEN {0} '
'ELSE {0}_sort END) {1}').format(field, order)
class SlowFieldSort(FieldSort):
"""A sort criterion by some model field other than a fixed field:
i.e., a computed or flexible field.

View file

@ -136,11 +136,10 @@ def construct_sort_part(model_cls, part):
assert direction in ('+', '-'), "part must end with + or -"
is_ascending = direction == '+'
if field in model_cls._fields:
if field in model_cls._sorts:
sort = model_cls._sorts[field](model_cls, is_ascending)
elif field in model_cls._fields:
sort = query.FixedFieldSort(field, is_ascending)
elif field == 'smartartist':
# Special case for smart artist sort.
sort = query.SmartArtistSort(model_cls, is_ascending)
else:
# Flexible or computed.
sort = query.SlowFieldSort(field, is_ascending)

View file

@ -60,7 +60,6 @@ class PathQuery(dbcore.FieldQuery):
# Library-specific field types.
class DateType(types.Float):
# TODO representation should be `datetime` object
# TODO distinguish beetween date and time types
@ -144,6 +143,27 @@ class MusicalKey(types.String):
return self.parse(key)
# Library-specific sort types.
class SmartArtistSort(dbcore.query.Sort):
"""Sort by artist (either album artist or track artist),
prioritizing the sort field over the raw field.
"""
def __init__(self, model_cls, is_ascending=True):
self.model_cls = model_cls
self.is_ascending = is_ascending
def order_clause(self):
order = "ASC" if self.is_ascending else "DESC"
if 'albumartist' in self.model_cls._fields:
field = 'albumartist'
else:
field = 'artist'
return ('(CASE {0}_sort WHEN NULL THEN {0} '
'WHEN "" THEN {0} '
'ELSE {0}_sort END) {1}').format(field, order)
# Special path format key.
PF_KEY_DEFAULT = 'default'
@ -347,6 +367,8 @@ class Item(LibModel):
_formatter = FormattedItemMapping
_sorts = {'smartartist': SmartArtistSort}
@classmethod
def _getters(cls):
getters = plugins.item_field_getters()
@ -710,6 +732,8 @@ class Album(LibModel):
_search_fields = ('album', 'albumartist', 'genre')
_sorts = {'smartartist': SmartArtistSort}
item_keys = [
'added',
'albumartist',

View file

@ -25,6 +25,10 @@ from tempfile import mkstemp
# Fixture: concrete database and model classes. For migration tests, we
# have multiple models with different numbers of fields.
class TestSort(dbcore.query.FieldSort):
pass
class TestModel1(dbcore.Model):
_table = 'test'
_flex_table = 'testflex'
@ -35,6 +39,9 @@ class TestModel1(dbcore.Model):
_types = {
'some_float_field': dbcore.types.FLOAT,
}
_sorts = {
'some_sort': TestSort,
}
@classmethod
def _getters(cls):
@ -455,6 +462,10 @@ class SortFromStringsTest(unittest.TestCase):
self.assertIsInstance(s, dbcore.query.MultipleSort)
self.assertIsInstance(s.sorts[0], dbcore.query.SlowFieldSort)
def test_special_sort(self):
s = self.sfs(['some_sort+'])
self.assertIsInstance(s.sorts[0], TestSort)
def suite():
return unittest.TestLoader().loadTestsFromName(__name__)