From 76a7cc4e586733bc15749d1465dd463c3660fe83 Mon Sep 17 00:00:00 2001
From: kafene <kafene@users.noreply.github.com>
Date: Mon, 21 May 2018 00:24:18 -0400
Subject: [PATCH] refactor file list sorting per request

---
 lbrynet/daemon/Daemon.py                      | 49 ++++++++++---------
 .../tests/unit/lbrynet_daemon/test_Daemon.py  |  4 +-
 2 files changed, 27 insertions(+), 26 deletions(-)

diff --git a/lbrynet/daemon/Daemon.py b/lbrynet/daemon/Daemon.py
index a9ba048eb..b0278d653 100644
--- a/lbrynet/daemon/Daemon.py
+++ b/lbrynet/daemon/Daemon.py
@@ -97,12 +97,9 @@ CONNECTION_MESSAGES = {
 SHORT_ID_LEN = 20
 MAX_UPDATE_FEE_ESTIMATE = 0.3
 
-FILE_SORT_DIRECTION_ASCENDING = 'asc'
-FILE_SORT_DIRECTION_DESCENDING = 'desc'
-FILE_SORT_DIRECTIONS = (
-    FILE_SORT_DIRECTION_ASCENDING,
-    FILE_SORT_DIRECTION_DESCENDING,
-)
+DIRECTION_ASCENDING = 'asc'
+DIRECTION_DESCENDING = 'desc'
+DIRECTIONS = DIRECTION_ASCENDING, DIRECTION_DESCENDING
 
 class IterableContainer(object):
     def __iter__(self):
@@ -947,18 +944,8 @@ class Daemon(AuthJSONRPCServer):
 
     def _sort_lbry_files(self, lbry_files, sort_by):
         for field, direction in sort_by:
-            is_reverse = direction == FILE_SORT_DIRECTION_DESCENDING
-            key_getter = None
-            if field:
-                search_path = field.split('.')
-                def key_getter(value):
-                    for key in search_path:
-                        try:
-                            value = value[key]
-                        except KeyError as e:
-                            errmsg = 'Failed to sort by "{}", key "{}" was not found.'
-                            raise Exception(errmsg.format(field, e.message))
-                    return value
+            is_reverse = direction == DIRECTION_DESCENDING
+            key_getter = create_key_getter(field) if field else None
             lbry_files = sorted(lbry_files, key=key_getter, reverse=is_reverse)
         return lbry_files
 
@@ -969,12 +956,13 @@ class Daemon(AuthJSONRPCServer):
         Direction defaults to ascending.
         """
 
-        pieces = sort.rsplit(',', 1)
-        field = pieces[0].strip() or None
-        direction = pieces[1].strip().lower() if len(pieces) > 1 else None
-        if direction and direction not in FILE_SORT_DIRECTIONS:
-            raise Exception('Sort direction must be one of {}'.format(FILE_SORT_DIRECTIONS))
-        return (field, direction or FILE_SORT_DIRECTION_ASCENDING)
+        pieces = [p.strip() for p in sort.split(',')]
+        field = pieces.pop(0)
+        direction = DIRECTION_ASCENDING
+        if pieces and pieces[0] in DIRECTIONS:
+            direction = pieces[0]
+        return field, direction
+
 
     def _get_single_peer_downloader(self):
         downloader = SinglePeerDownloader()
@@ -3435,3 +3423,16 @@ def get_blob_payment_rate_manager(session, payment_rate_manager=None):
             payment_rate_manager = rate_managers[payment_rate_manager]
             log.info("Downloading blob with rate manager: %s", payment_rate_manager)
     return payment_rate_manager or session.payment_rate_manager
+
+
+def create_key_getter(field):
+    search_path = field.split('.')
+    def key_getter(value):
+        for key in search_path:
+            try:
+                value = value[key]
+            except KeyError as e:
+                errmsg = 'Failed to get "{}", key "{}" was not found.'
+                raise Exception(errmsg.format(field, e.message))
+        return value
+    return key_getter
diff --git a/lbrynet/tests/unit/lbrynet_daemon/test_Daemon.py b/lbrynet/tests/unit/lbrynet_daemon/test_Daemon.py
index af242af3f..d47c36ba2 100644
--- a/lbrynet/tests/unit/lbrynet_daemon/test_Daemon.py
+++ b/lbrynet/tests/unit/lbrynet_daemon/test_Daemon.py
@@ -250,14 +250,14 @@ class TestFileListSorting(trial.unittest.TestCase):
         deferred = defer.maybeDeferred(self.test_daemon.jsonrpc_file_list, sort=sort_options)
         failure_assertion = self.assertFailure(deferred, Exception)
         exception = self.successResultOf(failure_assertion)
-        expected_message = 'Failed to sort by "meta.author", key "meta" was not found.'
+        expected_message = 'Failed to get "meta.author", key "meta" was not found.'
         self.assertEquals(expected_message, exception.message)
 
         sort_options = ['metadata.foo.bar']
         deferred = defer.maybeDeferred(self.test_daemon.jsonrpc_file_list, sort=sort_options)
         failure_assertion = self.assertFailure(deferred, Exception)
         exception = self.successResultOf(failure_assertion)
-        expected_message = 'Failed to sort by "metadata.foo.bar", key "foo" was not found.'
+        expected_message = 'Failed to get "metadata.foo.bar", key "foo" was not found.'
         self.assertEquals(expected_message, exception.message)
 
     def _get_fake_lbry_files(self):