agateblue / lifter

A generic query engine, inspired by Django ORM
ISC License
449 stars 16 forks source link

Some complex lookups fail on nested iterables #7

Closed agateblue closed 7 years ago

agateblue commented 8 years ago

Considering the following data:

users = [
    {
      "name": "Hazel Robertson",
      "gender": "female",
      "friends": [
        {
          "name": "Mays Conway",
          "tags": [
            {"name": "dolore"},
            {"name": "laborum"},
          ]
        },
      ],
    },
]

The following raise an exception:


manager = lifter.load(users)
manager.filter(friends__name=lifter.startswith('Mays'))

With the following stacktrace:

/path/lifter/lifter/query.py in filter(self, **kwargs)
     97     def filter(self, **kwargs):
     98         _filter = self._build_filter(**kwargs)
---> 99         return self._clone(filter(_filter, self._values))
    100 
    101     def exclude(self, **kwargs):

/path/lifter/lifter/query.py in _clone(self, new_values)
     39 
     40     def _clone(self, new_values):
---> 41         return self.__class__(new_values)
     42 
     43     def __repr__(self):

/path/lifter/lifter/query.py in __init__(self, values)
     19 class QuerySet(object):
     20     def __init__(self, values):
---> 21         self._values = list(values)
     22 
     23     def __iter__(self):

/path/lifter/lifter/query.py in object_filter(obj)
     57                 if hasattr(value, '__call__'):
     58                     # User passed a callable for a custom comparison
---> 59                     if not value(getter(obj)):
     60                         return False
     61                 else:

/path/lifter/lifter/lookups.py in __call__(self, value)
      2 class BaseLookup(object):
      3     def __call__(self, value):
----> 4         return self.lookup(value)
      5 
      6     def lookup(self, value):

/path/lifter/lifter/lookups.py in lookup(self, value)
     33 class startswith(OneValueLookup):
     34     def lookup(self, value):
---> 35         return value.startswith(self.reference_value)
     36 
     37 class istartswith(OneValueLookup):

AttributeError: 'IterableAttr' object has no attribute 'startswith'

@Ogreman since you worked on this, you may have an idea about this. It seems all lookups involving accessing a part of the iterable value (startswith, endswith, contains...) fail, while the ones using the whole value (such as value_in) works as expected.

Ogreman commented 8 years ago

Think it's just a matter of implementing the required magic methods for that Iter class. I'll get on that now.

agateblue commented 7 years ago

This is still an issue, see for example : http://indexerror.net/4461/it%C3%A9ration-dans-un-structure-de-dictionnaire-complexe?show=4467#c4467