Option to query multiple times when result set exceeds 1000
It would be great to have an option for all queries to perform multiple queries to quickbooks when the count() > 1000 rather then having to do the multiple queries myself with start_position.
I currently have this hacked in to replace the query method on the QuickBooks class.
Great work btw!
This is what I am currently using, and appears to work fine for me with Deposit and Purchase so far. I would be great also for
everything that can multi-request to take a cb argument such that progress can notified as it chunks through.
import quickbooks.mixins
def _fixed_where(cls, where_clause="", order_by="", start_position="", max_results="", qb=None,cb=None):
"""
:param where_clause: QBO SQL where clause (DO NOT include 'WHERE')
:param order_by:
:param start_position:
:param max_results:
:param qb:
:return: Returns list filtered by input where_clause
"""
if where_clause:
where_clause = "WHERE " + where_clause
if order_by:
order_by = " ORDERBY " + order_by
if start_position != "":
start_position_= int(start_position)
start_position_query = " STARTPOSITION " + str(start_position)
else:
start_position = 0
start_position_query = ""
max_chunk = 1000
single_query = False
if max_results and int(max_results) <= max_chunk:
max_results_query = " MAXRESULTS " + str(max_results)
single_query = True
else:
max_results_query = " MAXRESULTS " + str(max_chunk)
select = "SELECT * FROM {0} {1}{2}{3}{4}".format(
cls.qbo_object_name, where_clause, order_by, start_position_query, max_results_query)
result = cls.query(select, qb=qb)
if single_query:
return result
total_results = cls.count(where_clause,qb) - start_position
if max_results:
total_results = min(int(max_results),total_results)
if total_results == max_chunk:
return result
for position in range(max_chunk+1,total_results,max_chunk):
start_position_query = " STARTPOSITION " + str(start_position + position)
max_results_query = " MAXRESULTS " + str(max_chunk)
select = "SELECT * FROM {0} {1}{2}{3}{4}".format(
cls.qbo_object_name, where_clause, order_by, start_position_query, max_results_query)
result += cls.query(select, qb=qb)
return result
quickbooks.mixins.ListMixin.where = classmethod(_fixed_where)
I am doing something similar, but without changing the base code:
def paginate(client, repo, per_page, method_name='all', order_by='Id', **kwargs):
# Can be any QBO object i.e. `Customer.count`
total = repo.count(qb=client)
pages = total // per_page
method = getattr(repo, method_name)
callback = partial(method, qb=client, max_results=per_page, order_by=order_by, **kwargs)
objects = [
callback(start_position=page * per_page + 1)
for page in range(pages + 1)
]
return list(reduce(lambda prev, curr: prev + curr, objects, []))
Another more robust alternative:
class Paginator(object):
def __init__(self, repo, per_page, qb=None):
self._repo = repo
self._per_page = per_page
self._client = qb
def all(self, order_by="", start_position=0):
total = self._repo.count(qb=self._client)
pages = total // self._per_page
callback = partial(self._repo.all, qb=self._client, max_results=self._per_page, order_by=order_by)
objects = [
callback(start_position=start_position + page * self._per_page + 1)
for page in range(pages + 1)
]
return list(reduce(lambda prev, curr: prev + curr, objects, []))
def filter(self, order_by="", start_position="", **kwargs):
...
def choose(self, choices, field="Id"):
...
def where(self, where_clause="", order_by="", start_position=""):
...
class ListMixin(object):
...
@classmethod
def paginate(cls, per_page=100, qb=None):
return Paginator(cls, per_page, qb)
There are some great examples here, but I think this is beyond the scope of this library.