Skip to content

Commit 69b1d8b

Browse files
committed
fix limits (#123)
* use limit logic from @joshowen fork c3b51d9 * tests for limit iterators and api calls
1 parent 0c481b7 commit 69b1d8b

File tree

2 files changed

+85
-3
lines changed

2 files changed

+85
-3
lines changed

pynamodb/models.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -574,19 +574,19 @@ def query(cls,
574574
log.debug("Fetching query page with exclusive start key: %s", last_evaluated_key)
575575
# If the user provided a limit, we need to subtract the number of results returned for each page
576576
if limit is not None:
577-
limit -= data.get("Count", 0)
578577
if limit == 0:
579578
return
579+
limit -= data.get(CAMEL_COUNT, 0)
580580
query_kwargs['exclusive_start_key'] = last_evaluated_key
581581
query_kwargs['limit'] = limit
582582
log.debug("Fetching query page with exclusive start key: %s", last_evaluated_key)
583583
data = cls._get_connection().query(hash_key, **query_kwargs)
584584
cls._throttle.add_record(data.get(CONSUMED_CAPACITY))
585585
for item in data.get(ITEMS):
586586
if limit is not None:
587-
limit -= 1
588-
if not limit:
587+
if limit == 0:
589588
return
589+
limit -= 1
590590
yield cls.from_raw_data(item)
591591
last_evaluated_key = data.get(LAST_EVALUATED_KEY, None)
592592

pynamodb/tests/test_model.py

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1117,6 +1117,88 @@ def test_index_count(self):
11171117
}
11181118
deep_eq(args, params, _assert=True)
11191119

1120+
def test_query_limit_greater_than_available_items_single_page(self):
1121+
with patch(PATCH_METHOD) as req:
1122+
req.return_value = MODEL_TABLE_DATA
1123+
UserModel('foo', 'bar')
1124+
1125+
with patch(PATCH_METHOD) as req:
1126+
items = []
1127+
for idx in range(5):
1128+
item = copy.copy(GET_MODEL_ITEM_DATA.get(ITEM))
1129+
item['user_id'] = {STRING_SHORT: 'id-{0}'.format(idx)}
1130+
items.append(item)
1131+
1132+
req.return_value = {'Items': items}
1133+
results = list(UserModel.query('foo', limit=25))
1134+
self.assertEqual(len(results), 5)
1135+
self.assertEquals(req.mock_calls[0][1][1]['Limit'], 25)
1136+
1137+
def test_query_limit_identical_to_available_items_single_page(self):
1138+
with patch(PATCH_METHOD) as req:
1139+
req.return_value = MODEL_TABLE_DATA
1140+
UserModel('foo', 'bar')
1141+
1142+
with patch(PATCH_METHOD) as req:
1143+
items = []
1144+
for idx in range(5):
1145+
item = copy.copy(GET_MODEL_ITEM_DATA.get(ITEM))
1146+
item['user_id'] = {STRING_SHORT: 'id-{0}'.format(idx)}
1147+
items.append(item)
1148+
1149+
req.return_value = {'Items': items}
1150+
results = list(UserModel.query('foo', limit=5))
1151+
self.assertEqual(len(results), 5)
1152+
self.assertEquals(req.mock_calls[0][1][1]['Limit'], 5)
1153+
1154+
def test_query_limit_less_than_available_items_multiple_page(self):
1155+
with patch(PATCH_METHOD) as req:
1156+
req.return_value = MODEL_TABLE_DATA
1157+
UserModel('foo', 'bar')
1158+
1159+
with patch(PATCH_METHOD) as req:
1160+
items = []
1161+
for idx in range(30):
1162+
item = copy.copy(GET_MODEL_ITEM_DATA.get(ITEM))
1163+
item['user_id'] = {STRING_SHORT: 'id-{0}'.format(idx)}
1164+
items.append(item)
1165+
1166+
req.side_effect = [
1167+
{'Items': items[:10], 'LastEvaluatedKey': 'x'},
1168+
{'Items': items[10:20], 'LastEvaluatedKey': 'y'},
1169+
{'Items': items[20:30]},
1170+
]
1171+
results = list(UserModel.query('foo', limit=25))
1172+
self.assertEqual(len(results), 25)
1173+
self.assertEqual(len(req.mock_calls), 3)
1174+
self.assertEquals(req.mock_calls[0][1][1]['Limit'], 25)
1175+
self.assertEquals(req.mock_calls[1][1][1]['Limit'], 15)
1176+
self.assertEquals(req.mock_calls[2][1][1]['Limit'], 5)
1177+
1178+
def test_query_limit_greater_than_available_items_multiple_page(self):
1179+
with patch(PATCH_METHOD) as req:
1180+
req.return_value = MODEL_TABLE_DATA
1181+
UserModel('foo', 'bar')
1182+
1183+
with patch(PATCH_METHOD) as req:
1184+
items = []
1185+
for idx in range(30):
1186+
item = copy.copy(GET_MODEL_ITEM_DATA.get(ITEM))
1187+
item['user_id'] = {STRING_SHORT: 'id-{0}'.format(idx)}
1188+
items.append(item)
1189+
1190+
req.side_effect = [
1191+
{'Items': items[:10], 'LastEvaluatedKey': 'x'},
1192+
{'Items': items[10:20], 'LastEvaluatedKey': 'y'},
1193+
{'Items': items[20:30]},
1194+
]
1195+
results = list(UserModel.query('foo', limit=50))
1196+
self.assertEqual(len(results), 30)
1197+
self.assertEqual(len(req.mock_calls), 3)
1198+
self.assertEquals(req.mock_calls[0][1][1]['Limit'], 50)
1199+
self.assertEquals(req.mock_calls[1][1][1]['Limit'], 40)
1200+
self.assertEquals(req.mock_calls[2][1][1]['Limit'], 30)
1201+
11201202
def test_query(self):
11211203
"""
11221204
Model.query

0 commit comments

Comments
 (0)