from copy import deepcopy
from itertools import islice
from .exceptions import FilterError
class GenericSet(object):
"""Class representing a generic grouping of iatikit objects.
Objects in this grouping can be filtered and iterated over.
Queries are only constructed and run when needed, so they
can be efficient.
"""
_key = None
_filters = []
_multi_filters = []
_instance_class = None
def __init__(self, **kwargs):
self.wheres = {}
self.where(**kwargs)
def where(self, **kwargs):
"""Return a new set, with the filters provided in ``**kwargs``.
"""
out = deepcopy(self)
for k, v in kwargs.items():
if k.split('__')[0] not in (self._filters + self._multi_filters):
raise FilterError('Unknown filter: {}'.format(k))
if k.split('__')[0] in self._filters:
if k in out.wheres:
raise FilterError('Too many {} filters provided'.format(k))
out.wheres[k] = v
else:
if k not in out.wheres:
out.wheres[k] = []
out.wheres[k].append(v)
return out
def filter(self, **kwargs):
"""Return a new set, with the filters provided in ``**kwargs``.
Alias of ``where(**kwargs)``.
"""
return self.where(**kwargs)
def __getitem__(self, index):
try:
return next(islice(self, index, index + 1))
except TypeError:
return list(islice(self, index.start, index.stop, index.step))
except StopIteration:
pass
raise IndexError('index out of range')
def __len__(self):
return sum(1 for x in self)
def count(self):
"""The number of items in this set.
Equivalent to ``len(self)``.
"""
return len(self)
def first(self):
"""Return the first item in this set.
Raises an ``IndexError`` if the set contains zero items.
Equivalent to ``self[0]``.
"""
return self[0]
def all(self):
"""Return a list of all items in this set.
"""
return list(x for x in self)
def get(self, item, default=None):
"""Return an item from the set, according to the primary key.
If no matching item is found, ``default`` is returned.
"""
if isinstance(item, self._instance_class):
item = getattr(item, self._key)
try:
return self.find(**{self._key: item})
except IndexError:
return default
def find(self, **kwargs):
"""Return the first matching item from the set, according to the
filters provided in ``kwargs``.
If no matching item is found, an ``IndexError`` is raised.
"""
return self.where(**kwargs).first()
class GenericType(object):
def __init__(self, expr):
self._expr = expr
def get(self):
return self._expr
def run(self, etree):
return etree.xpath(self.get())
def where(self, operation, value):
if operation == 'exists':
sub_operation = '!= 0' if value else '= 0'
return 'count({expr}) {subop}'.format(
expr=self.get(),
subop=sub_operation,
)
elif operation == 'eq':
return '{expr} = "{value}"'.format(
expr=self.get(),
value=value,
)
raise FilterError('Unknown filter modifier: {}'.format(operation))