agateblue / lifter

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

Better handling of lookups on nested iterables #11

Closed agateblue closed 8 years ago

agateblue commented 8 years ago

Okay, I spend a few hours working on this and I have to say my brain is burning. There is a real complexity when working on nested iterable, mostly because there is a lot of edge cases to handle.

Thanks to Q objects, and the work @Ogreman already done on iterables, I've managed to build a simple implementation that does the work, but when I try to handle all the cases, everything becomes an incredible mess.

Right now, the tests pass on a few complex lookups, so I'm pretty confident it will work on all:

self.assertEqual([companies[0]], manager.filter(employees__tags__name='friendly'))
self.assertEqual([companies[0]], manager.filter(employees__tags__name=lifter.startswith('fr')))
self.assertEqual([companies[1], companies[2]], manager.filter(employees__tags__name=lifter.icontains('act')))

All previous example pass, you can find them in the test suite.

But, when you try to match on an iterable element exactly (not on an iterable element attribute), everything the queryset just return empty:

self.assertEqual([companies[1], companies[2]], manager.filter(employees__tags={'name': 'activist'}))

Internally, it seems IterableAttr stores things in nested list in some situations, which cause exact lookup on iterable to fail. All my attempts to flatten them broke everything.

@Ogreman: if you have an idea to solve this last case, it would be great because the recursion just gave me a headache :p

agateblue commented 8 years ago

An interesting issue regarding the whole query engine has been open (#15), we should probably wait for it to be resolved before continuing the work on this.

Ogreman commented 8 years ago

I think the failing test is actually failing because __tags will never be equal to a single dict.

self.assertEqual([companies[1], companies[2]], manager.filter(employees__tags={'name': 'activist'}))

What should be used is something like:

self.assertEqual([companies[1], companies[2]], manager.filter(employees__tags=lifter.contains({'name': 'activist'})))
self.assertEqual([companies[1]], manager.filter(employees__tags=[{'name': 'activist'}]))

Note the square brackets on the last line.

Thoughts, @EliotBerriot?

agateblue commented 8 years ago

I'm closing this one, since the whole api changed after the 0.2 release, see #28 for a more up to date proposal.