Inherit from Queryable
Closed this issue · 4 comments
Hello,
I'd like to create a custom collection which inherits from Queryable
but which also have some specific methods.
My first idea was to do:
from asq.queryables import Queryable
class DoableResults(Queryable):
def __init__(self, context, results) -> None:
super().__init__(results)
self._context = context
def do_it(self):
print("Let's do it with %s" % self._context)
unfortunately if I do
results = DoableResults(None, [1, 2, 3, 4, 5, 6])
results.do_it()
works fine but if I do
results.where(lambda n: n>2)
it returns a Queryable
... I was expecting it to return a DoableResults
I had a look at doc to see if you wrote some information about that
https://asq.readthedocs.io/en/latest/search.html?q=inheritance
but couldn't find much information
So what is a proper way to inherit from Queryable?
I noticed https://asq.readthedocs.io/en/latest/narrative.html#extending-asq
but I don't think it's a correct way to do what I'm looking for as it will create a do_it
method for any Queryable
which is not what I'm looking for.
Some help to tackle this will be great!
Kind regards
This is a good question. It's a while since I worked with asq
(if it ain't broke, don't fix it), so I had to refresh my memory. It looks like all the places that Queryable
returns another Queryable
are done by calling the Queryable._create(iterable)
or `Queryable._create_ordered(iterable, direction, func) factory methods. The docstrings of both say "This method exists to allow it to be overridden by subclasses of Queryable.", so I was obviously planning for this day.
Try overriding those, and please let me know how you get on.
Ok, thanks, I saw
Lines 92 to 120 in 389f647
I wonder (for at least Queryable._create(iterable)
if it wouldn't help to turn it to a classmethod
.
But I'm not sure how to tackle Queryable._create_ordered(iterable, direction, func)
in such a case.
I will try that tomorrow because I'm quite busy today.
It certainly could be a class method in its current form, but it's not clear to me that that would also be true for all possible subclass implementations.
It could also have a default implementation of something like:
def _create(self, iterable):
return type(self)(iterable)
so then in simple cases, like yours, it wouldn't need to be overridden.
This is how I handled this
from asq.queryables import Queryable, OrderedQueryable
class Doable:
def do_it(self):
print("Let's do it with contex=%s" % self._context)
class DoableResults(Queryable, Doable):
def __init__(self, context, results) -> None:
super().__init__(results)
self._context = context
def _create(self, iterable):
return type(self)(self._context, iterable)
def _create_ordered(self, iterable, direction, func):
return OrderedDoableResults(self._context, iterable, direction, func)
class OrderedDoableResults(OrderedQueryable, Doable):
def __init__(self, context, iterable, direction, func) -> None:
super().__init__(iterable, direction, func)
self._context = context
results = DoableResults(
None, [{"v": 1}, {"v": 2}, {"v": 3}, {"v": 4}, {"v": 5}, {"v": 6}]
)
print(results.count())
results.do_it()
print()
print(results.where(lambda n: n["v"] > 2).count())
results.where(lambda n: n["v"] > 2).do_it()
print()
print(results.order_by(lambda n: n["v"]).count())
results.order_by(lambda n: n["v"]).do_it()