def __getitem__(self, item):
if isinstance(item, slice):
start, stop, step = util.decode_slice(item)
- # if we slice from the end we need to execute the query before
- # slicing
- if start < 0 or stop < 0:
+
+ if isinstance(stop, int) and isinstance(start, int) and stop - start <= 0:
+ return []
+
+ # perhaps we should execute a count() here so that we
+ # can still use LIMIT/OFFSET ?
+ elif (isinstance(start, int) and start < 0) \
+ or (isinstance(stop, int) and stop < 0):
return list(self)[item]
+
+ res = self.slice(start, stop)
+ if step is not None:
+ return list(res)[None:None:item.step]
else:
- res = self.slice(start, stop)
- if step is not None:
- return list(res)[None:None:item.step]
- else:
- return list(res)
+ return list(res)
else:
return list(self[item:item+1])[0]
sess = create_session()
query = sess.query(Foo)
orig = query.all()
+
assert query[1] == orig[1]
assert list(query[10:20]) == orig[10:20]
assert list(query[10:]) == orig[10:]
assert list(query[:10]) == orig[:10]
assert list(query[:10]) == orig[:10]
+ assert list(query[5:5]) == orig[5:5]
assert list(query[10:40:3]) == orig[10:40:3]
assert list(query[-5:]) == orig[-5:]
+ assert list(query[-2:-5]) == orig[-2:-5]
+ assert list(query[-5:-2]) == orig[-5:-2]
+ assert list(query[:-2]) == orig[:-2]
+
assert query[10:20][5] == orig[10:20][5]
@testing.uses_deprecated('Call to deprecated function apply_max')
l = list(session.query(User).instances(s.execute(emailad = 'jack@bean.com')))
assert [User(id=7)] == l
+# more slice tests are available in test/orm/generative.py
class SliceTest(QueryTest):
def test_first(self):
assert User(id=7) == create_session().query(User).first()
assert create_session().query(User).filter(User.id==27).first() is None
- # more slice tests are available in test/orm/generative.py
+ @testing.fails_on_everything_except('sqlite')
+ def test_limit_offset_applies(self):
+ """Test that the expected LIMIT/OFFSET is applied for slices.
+
+ The LIMIT/OFFSET syntax differs slightly on all databases, and
+ query[x:y] executes immediately, so we are asserting against
+ SQL strings using sqlite's syntax.
+
+ """
+ sess = create_session()
+ q = sess.query(User)
+
+ self.assert_sql(testing.db, lambda: q[10:20], [
+ ("SELECT users.id AS users_id, users.name AS users_name FROM users LIMIT 10 OFFSET 10", {})
+ ])
+
+ self.assert_sql(testing.db, lambda: q[:20], [
+ ("SELECT users.id AS users_id, users.name AS users_name FROM users LIMIT 20 OFFSET 0", {})
+ ])
+
+ self.assert_sql(testing.db, lambda: q[5:], [
+ ("SELECT users.id AS users_id, users.name AS users_name FROM users LIMIT -1 OFFSET 5", {})
+ ])
+
+ self.assert_sql(testing.db, lambda: q[2:2], [])
+
+ self.assert_sql(testing.db, lambda: q[-2:-5], [])
+
+ self.assert_sql(testing.db, lambda: q[-5:-2], [
+ ("SELECT users.id AS users_id, users.name AS users_name FROM users", {})
+ ])
+
+ self.assert_sql(testing.db, lambda: q[-5:], [
+ ("SELECT users.id AS users_id, users.name AS users_name FROM users", {})
+ ])
+
+ self.assert_sql(testing.db, lambda: q[:], [
+ ("SELECT users.id AS users_id, users.name AS users_name FROM users", {})
+ ])
+
class TextTest(QueryTest):
def test_fulltext(self):