From 0bfccb86ff7309216c265759679a359cc8ddb3f3 Mon Sep 17 00:00:00 2001 From: Lex Berezhny Date: Tue, 9 Oct 2018 20:46:41 -0400 Subject: [PATCH] refactored pagination per @seanyesmunt feedback --- lbrynet/daemon/Daemon.py | 153 +++++++++++++++----------------------- lbrynet/wallet/account.py | 36 +++++---- 2 files changed, 85 insertions(+), 104 deletions(-) diff --git a/lbrynet/daemon/Daemon.py b/lbrynet/daemon/Daemon.py index 49397d09c..2d82490ac 100644 --- a/lbrynet/daemon/Daemon.py +++ b/lbrynet/daemon/Daemon.py @@ -6,6 +6,7 @@ import urllib import json import textwrap +from typing import Callable, Optional from operator import itemgetter from binascii import hexlify, unhexlify from copy import deepcopy @@ -81,6 +82,22 @@ DIRECTION_DESCENDING = 'desc' DIRECTIONS = DIRECTION_ASCENDING, DIRECTION_DESCENDING +@defer.inlineCallbacks +def maybe_paginate(get_records: Callable, get_record_count: Callable, + page: Optional[int], page_size: Optional[int], **constraints): + if None not in (page, page_size): + constraints.update({ + "offset": page_size * (page-1), + "limit": page_size + }) + return { + "items": (yield get_records(**constraints)), + "total_pages": ((yield get_record_count(**constraints)) + (page_size-1)) / page_size, + "page": page, "page_size": page_size + } + return (yield get_records(**constraints)) + + class IterableContainer: def __iter__(self): for attr in dir(self): @@ -1506,37 +1523,28 @@ class Daemon(AuthJSONRPCServer): ) @requires(WALLET_COMPONENT) - @defer.inlineCallbacks - def jsonrpc_address_list(self, account_id=None, offset=None, limit=None): + def jsonrpc_address_list(self, account_id=None, page=None, page_size=None): """ List account addresses Usage: address_list [ | --account_id=] - [--offset=] [--limit=] + [--page=] [--page_size=] Options: --account_id= : (str) id of the account to use - --offset= : (int) slice address list starting at offset - --limit= : (int) limit number of addresses returned + --page= : (int) page to return during paginating + --page_size= : (int) number of items on page during pagination Returns: List of wallet addresses """ account = self.get_account_or_default(account_id) - if None not in (offset, limit): - constraints = { - 'account': account, - 'offset': offset, - 'limit': limit - } - return { - "list": (yield self.ledger.db.get_addresses(**constraints)), - "size": (yield self.ledger.db.get_address_count(**constraints)), - "offset": offset, - "limit": limit - } - return (yield account.get_addresses()) + return maybe_paginate( + account.get_addresses, + account.get_address_count, + page, page_size + ) @requires(WALLET_COMPONENT) def jsonrpc_address_unused(self, account_id=None): @@ -2052,38 +2060,29 @@ class Daemon(AuthJSONRPCServer): } @requires(WALLET_COMPONENT) - @defer.inlineCallbacks - def jsonrpc_channel_list(self, account_id=None, offset=None, limit=None): + def jsonrpc_channel_list(self, account_id=None, page=None, page_size=None): """ Get certificate claim infos for channels that can be published to Usage: channel_list [ | --account_id= ] - [--offset=] [--limit=] + [--page=] [--page_size=] Options: --account_id= : (str) id of the account to use - --offset= : (int) slice channel list starting at offset - --limit= : (int) limit number of channels returned + --page= : (int) page to return during paginating + --page_size= : (int) number of items on page during pagination Returns: (list) ClaimDict, includes 'is_mine' field to indicate if the certificate claim is in the wallet. """ account = self.get_account_or_default(account_id) - if None not in (offset, limit): - constraints = { - 'account': account, - 'offset': offset, - 'limit': limit - } - return { - "list": (yield self.ledger.db.get_channels(**constraints)), - "size": (yield self.ledger.db.get_channel_count(**constraints)), - "offset": offset, - "limit": limit - } - return (yield account.get_channels()) + return maybe_paginate( + account.get_channels, + account.get_channel_count, + page, page_size + ) @requires(WALLET_COMPONENT) @defer.inlineCallbacks @@ -2478,19 +2477,18 @@ class Daemon(AuthJSONRPCServer): ) @requires(WALLET_COMPONENT) - @defer.inlineCallbacks - def jsonrpc_claim_list_mine(self, account_id=None, offset=None, limit=None): + def jsonrpc_claim_list_mine(self, account_id=None, page=None, page_size=None): """ List my name claims Usage: claim_list_mine [ | --account_id=] - [--offset=] [--limit=] + [--page=] [--page_size=] Options: --account_id= : (str) id of the account to query - --offset= : (int) slice claim list starting at offset - --limit= : (int) limit number of claims returned + --page= : (int) page to return during paginating + --page_size= : (int) number of items on page during pagination Returns: (list) List of name claims owned by user @@ -2515,19 +2513,11 @@ class Daemon(AuthJSONRPCServer): ] """ account = self.get_account_or_default(account_id) - if None not in (offset, limit): - constraints = { - 'account': account, - 'offset': offset, - 'limit': limit - } - return { - "list": (yield self.ledger.db.get_claims(**constraints)), - "size": (yield self.ledger.db.get_claim_count(**constraints)), - "offset": offset, - "limit": limit - } - return (yield account.get_claims()) + return maybe_paginate( + account.get_claims, + account.get_claim_count, + page, page_size + ) @requires(WALLET_COMPONENT) @defer.inlineCallbacks @@ -2659,19 +2649,18 @@ class Daemon(AuthJSONRPCServer): return response @requires(WALLET_COMPONENT) - @defer.inlineCallbacks - def jsonrpc_transaction_list(self, account_id=None, offset=None, limit=None): + def jsonrpc_transaction_list(self, account_id=None, page=None, page_size=None): """ List transactions belonging to wallet Usage: transaction_list [ | --account_id=] - [--offset=] [--limit=] + [--page=] [--page_size=] Options: --account_id= : (str) id of the account to query - --offset= : (int) slice transaction list starting at offset - --limit= : (int) limit number of transactions returned + --page= : (int) page to return during paginating + --page_size= : (int) number of items on page during pagination Returns: (list) List of transactions @@ -2720,20 +2709,11 @@ class Daemon(AuthJSONRPCServer): """ account = self.get_account_or_default(account_id) - if None not in (offset, limit): - constraints = { - 'offset': offset, - 'limit': limit - } - return { - "list": (yield self.wallet_manager.get_history( - account=account, **constraints)), - "size": (yield self.ledger.db.get_transaction_count( - account=account, **constraints)), - "offset": offset, - "limit": limit - } - return (yield self.wallet_manager.get_history(account)) + return maybe_paginate( + self.wallet_manager.get_history, + self.ledger.db.get_transaction_count, + page, page_size, account=account + ) @requires(WALLET_COMPONENT) def jsonrpc_transaction_show(self, txid): @@ -2752,19 +2732,18 @@ class Daemon(AuthJSONRPCServer): return self.wallet_manager.get_transaction(txid) @requires(WALLET_COMPONENT) - @defer.inlineCallbacks - def jsonrpc_utxo_list(self, account_id=None, offset=None, limit=None): + def jsonrpc_utxo_list(self, account_id=None, page=None, page_size=None): """ List unspent transaction outputs Usage: utxo_list [ | --account_id=] - [--offset=] [--limit=] + [--page=] [--page_size=] Options: --account_id= : (str) id of the account to query - --offset= : (int) slice utxo list starting at offset - --limit= : (int) limit number of utxo returned + --page= : (int) page to return during paginating + --page_size= : (int) number of items on page during pagination Returns: (list) List of unspent transaction outputs (UTXOs) @@ -2784,19 +2763,11 @@ class Daemon(AuthJSONRPCServer): ] """ account = self.get_account_or_default(account_id) - if None not in (offset, limit): - constraints = { - 'account': account, - 'offset': offset, - 'limit': limit - } - return { - "list": (yield self.ledger.db.get_utxos(**constraints)), - "size": (yield self.ledger.db.get_utxo_count(**constraints)), - "offset": offset, - "limit": limit - } - return (yield account.get_utxos()) + return maybe_paginate( + account.get_utxos, + account.get_utxo_count, + page, page_size + ) @requires(WALLET_COMPONENT) def jsonrpc_block_show(self, blockhash=None, height=None): diff --git a/lbrynet/wallet/account.py b/lbrynet/wallet/account.py index 5c156c948..8a3b3e974 100644 --- a/lbrynet/wallet/account.py +++ b/lbrynet/wallet/account.py @@ -120,17 +120,6 @@ class Account(BaseAccount): constraints.update({'is_claim': 0, 'is_update': 0, 'is_support': 0}) return super().get_balance(confirmations, **constraints) - def get_utxos(self, include_claims=False, **constraints): - if not include_claims: - constraints.update({'is_claim': 0, 'is_update': 0, 'is_support': 0}) - return super().get_utxos(**constraints) - - def get_channels(self): - return super().get_utxos( - claim_type__any={'is_claim': 1, 'is_update': 1}, - claim_name__like='@%' - ) - @classmethod def get_private_key_from_seed(cls, ledger: 'baseledger.BaseLedger', seed: str, password: str): return super().get_private_key_from_seed( @@ -160,5 +149,26 @@ class Account(BaseAccount): elif txid is not None and nout is not None: return self.ledger.db.get_claims(**{'account': self, 'txo.txid': txid, 'txo.position': nout}) - def get_claims(self): - return self.ledger.db.get_claims(account=self) + @staticmethod + def constraint_utxos_sans_claims(constraints): + constraints.update({'is_claim': 0, 'is_update': 0, 'is_support': 0}) + + def get_utxos(self, **constraints): + self.constraint_utxos_sans_claims(constraints) + return super().get_utxos(**constraints) + + def get_utxo_count(self, **constraints): + self.constraint_utxos_sans_claims(constraints) + return super().get_utxo_count(**constraints) + + def get_claims(self, **constraints): + return self.ledger.db.get_claims(account=self, **constraints) + + def get_claim_count(self, **constraints): + return self.ledger.db.get_claim_count(account=self, **constraints) + + def get_channels(self, **constraints): + return self.ledger.db.get_channels(account=self, **constraints) + + def get_channel_count(self, **constraints): + return self.ledger.db.get_channel_count(account=self, **constraints)