Merge lp:~cr3/storm/reference_is_in into lp:storm

Proposed by Marc Tardif
Status: Work in progress
Proposed branch: lp:~cr3/storm/reference_is_in
Merge into: lp:storm
Diff against target: 50 lines
To merge this branch: bzr merge lp:~cr3/storm/reference_is_in
Reviewer Review Type Date Requested Status
James Henstridge Needs Fixing
Storm Developers Pending
Review via email: mp+5120@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Marc Tardif (cr3) wrote :

Proposing is_method to Reference class so that it would be possible to call this:

  Computer.account.is_in(account_objects)

Instead of

  Computer.account_id.is_in([a.id for a in account_objects])

Revision history for this message
James Henstridge (jamesh) wrote :

The implementation looks wrong for compound key references when a list of objects is passed in:

    for i, other in enumerate(others):
        where = self._relation.get_where_for_local(other)
        others[i] = where.expr2

In such a case, get_where_for_local() will return an And() object, which has no expr2 attribute.

Probably the best you can do in such a situation would be something like:

    return Or(*[self._relation.get_where_for_local(other)
                for other in others])

You can do better for PostgreSQL and MySQL with "(key1, key2) in ((val1, val2), (val1', val2'), ...)" but that doesn't seem to work with SQLite.

You'd also want to make sure it does the right thing when passed an empty list.

review: Needs Fixing
Revision history for this message
Marc Tardif (cr3) wrote :

Interestingly, I had originally implemented the is_in method on references using the Or expression but I later found it preferable to use the In expression. However, in order to support a wider range of backends, I'm fine with reverting to the Or expression.

Thanks for suggesting to test the corner case when passing an empty list. I made sure to write the corresponding test which then failed when just uring the Or expression. So, when the given argument to the is_in method is an empty list, it simply returns False which seems to work fine.

The branch has been updated with these changes.

lp:~cr3/storm/reference_is_in updated
306. By Marc Tardif

Fixed is_in method in references to support compound key references and added test when passed an empty list.

Revision history for this message
James Henstridge (jamesh) wrote :

> Interestingly, I had originally implemented the is_in method on references
> using the Or expression but I later found it preferable to use the In
> expression. However, in order to support a wider range of backends, I'm fine
> with reverting to the Or expression.
>
> Thanks for suggesting to test the corner case when passing an empty list. I
> made sure to write the corresponding test which then failed when just uring
> the Or expression. So, when the given argument to the is_in method is an empty
> list, it simply returns False which seems to work fine.
>
> The branch has been updated with these changes.

With your new changes, passing an Expr object to is_in() will now fail. With the previous version of your patch it was possible to do something like:

    Employee.company.is_in(Select(Company.id, Company.name.like("%corp%")))

The cast to list() in your new version would fail here.

Revision history for this message
Jamu Kakar (jkakar) wrote :

Is anything going on with this branch?

Unmerged revisions

306. By Marc Tardif

Fixed is_in method in references to support compound key references and added test when passed an empty list.

305. By Marc Tardif

Added is_in method to Reference class.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'storm/references.py'
--- storm/references.py 2009-02-19 16:44:33 +0000
+++ storm/references.py 2009-08-13 20:20:47 +0000
@@ -22,7 +22,7 @@
22from storm.store import Store, get_where_for_args22from storm.store import Store, get_where_for_args
23from storm.variables import LazyValue23from storm.variables import LazyValue
24from storm.expr import (24from storm.expr import (
25 Select, Column, Exists, ComparableExpr, LeftJoin, Not, SQLRaw,25 Select, Column, Exists, ComparableExpr, LeftJoin, Or, Not, SQLRaw,
26 compare_columns, compile)26 compare_columns, compile)
27from storm.info import get_cls_info, get_obj_info27from storm.info import get_cls_info, get_obj_info
2828
@@ -203,6 +203,14 @@
203 def __ne__(self, other):203 def __ne__(self, other):
204 return Not(self == other)204 return Not(self == other)
205205
206 def is_in(self, others):
207 others = list(others)
208 if not others:
209 return False
210
211 return Or(*[self._relation.get_where_for_local(other)
212 for other in others])
213
206214
207class ReferenceSet(object):215class ReferenceSet(object):
208216
209217
=== modified file 'tests/store/base.py'
--- tests/store/base.py 2009-07-31 01:53:08 +0000
+++ tests/store/base.py 2009-08-13 20:20:47 +0000
@@ -3008,6 +3008,18 @@
3008 LinkWithRef, LinkWithRef.myself != (link.foo_id, link.bar_id)))3008 LinkWithRef, LinkWithRef.myself != (link.foo_id, link.bar_id)))
3009 self.assertTrue(link not in result, "%r not in %r" % (link, result))3009 self.assertTrue(link not in result, "%r not in %r" % (link, result))
30103010
3011 def test_reference_is_in(self):
3012 foo1 = self.store.get(Foo, 10)
3013 foo2 = self.store.get(Foo, 20)
3014
3015 result = self.store.find(Bar, Bar.foo.is_in([foo1, foo2]))
3016 self.assertEquals(result.count(), 2)
3017 self.assertEquals([100, 200], sorted(bar.id for bar in result))
3018
3019 def test_reference_is_in_with_empty(self):
3020 result = self.store.find(Bar, Bar.foo.is_in([]))
3021 self.assertEquals(result.count(), 0)
3022
3011 def test_reference_self(self):3023 def test_reference_self(self):
3012 selfref = self.store.add(SelfRef())3024 selfref = self.store.add(SelfRef())
3013 selfref.id = 4003025 selfref.id = 400

Subscribers

People subscribed via source and target branches

to status/vote changes: