comparison env/lib/python3.9/site-packages/boto/dynamodb/layer2.py @ 0:4f3585e2f14b draft default tip

"planemo upload commit 60cee0fc7c0cda8592644e1aad72851dec82c959"
author shellac
date Mon, 22 Mar 2021 18:12:50 +0000
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:4f3585e2f14b
1 # Copyright (c) 2011 Mitch Garnaat http://garnaat.org/
2 # Copyright (c) 2011 Amazon.com, Inc. or its affiliates. All Rights Reserved
3 #
4 # Permission is hereby granted, free of charge, to any person obtaining a
5 # copy of this software and associated documentation files (the
6 # "Software"), to deal in the Software without restriction, including
7 # without limitation the rights to use, copy, modify, merge, publish, dis-
8 # tribute, sublicense, and/or sell copies of the Software, and to permit
9 # persons to whom the Software is furnished to do so, subject to the fol-
10 # lowing conditions:
11 #
12 # The above copyright notice and this permission notice shall be included
13 # in all copies or substantial portions of the Software.
14 #
15 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16 # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
17 # ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
18 # SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
19 # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 # IN THE SOFTWARE.
22 #
23 from boto.dynamodb.layer1 import Layer1
24 from boto.dynamodb.table import Table
25 from boto.dynamodb.schema import Schema
26 from boto.dynamodb.item import Item
27 from boto.dynamodb.batch import BatchList, BatchWriteList
28 from boto.dynamodb.types import get_dynamodb_type, Dynamizer, \
29 LossyFloatDynamizer, NonBooleanDynamizer
30
31
32 class TableGenerator(object):
33 """
34 This is an object that wraps up the table_generator function.
35 The only real reason to have this is that we want to be able
36 to accumulate and return the ConsumedCapacityUnits element that
37 is part of each response.
38
39 :ivar last_evaluated_key: A sequence representing the key(s)
40 of the item last evaluated, or None if no additional
41 results are available.
42
43 :ivar remaining: The remaining quantity of results requested.
44
45 :ivar table: The table to which the call was made.
46 """
47
48 def __init__(self, table, callable, remaining, item_class, kwargs):
49 self.table = table
50 self.callable = callable
51 self.remaining = -1 if remaining is None else remaining
52 self.item_class = item_class
53 self.kwargs = kwargs
54 self._consumed_units = 0.0
55 self.last_evaluated_key = None
56 self._count = 0
57 self._scanned_count = 0
58 self._response = None
59
60 @property
61 def count(self):
62 """
63 The total number of items retrieved thus far. This value changes with
64 iteration and even when issuing a call with count=True, it is necessary
65 to complete the iteration to assert an accurate count value.
66 """
67 self.response
68 return self._count
69
70 @property
71 def scanned_count(self):
72 """
73 As above, but representing the total number of items scanned by
74 DynamoDB, without regard to any filters.
75 """
76 self.response
77 return self._scanned_count
78
79 @property
80 def consumed_units(self):
81 """
82 Returns a float representing the ConsumedCapacityUnits accumulated.
83 """
84 self.response
85 return self._consumed_units
86
87 @property
88 def response(self):
89 """
90 The current response to the call from DynamoDB.
91 """
92 return self.next_response() if self._response is None else self._response
93
94 def next_response(self):
95 """
96 Issue a call and return the result. You can invoke this method
97 while iterating over the TableGenerator in order to skip to the
98 next "page" of results.
99 """
100 # preserve any existing limit in case the user alters self.remaining
101 limit = self.kwargs.get('limit')
102 if (self.remaining > 0 and (limit is None or limit > self.remaining)):
103 self.kwargs['limit'] = self.remaining
104 self._response = self.callable(**self.kwargs)
105 self.kwargs['limit'] = limit
106 self._consumed_units += self._response.get('ConsumedCapacityUnits', 0.0)
107 self._count += self._response.get('Count', 0)
108 self._scanned_count += self._response.get('ScannedCount', 0)
109 # at the expense of a possibly gratuitous dynamize, ensure that
110 # early generator termination won't result in bad LEK values
111 if 'LastEvaluatedKey' in self._response:
112 lek = self._response['LastEvaluatedKey']
113 esk = self.table.layer2.dynamize_last_evaluated_key(lek)
114 self.kwargs['exclusive_start_key'] = esk
115 lektuple = (lek['HashKeyElement'],)
116 if 'RangeKeyElement' in lek:
117 lektuple += (lek['RangeKeyElement'],)
118 self.last_evaluated_key = lektuple
119 else:
120 self.last_evaluated_key = None
121 return self._response
122
123 def __iter__(self):
124 while self.remaining != 0:
125 response = self.response
126 for item in response.get('Items', []):
127 self.remaining -= 1
128 yield self.item_class(self.table, attrs=item)
129 if self.remaining == 0:
130 break
131 if response is not self._response:
132 break
133 else:
134 if self.last_evaluated_key is not None:
135 self.next_response()
136 continue
137 break
138 if response is not self._response:
139 continue
140 break
141
142
143 class Layer2(object):
144
145 def __init__(self, aws_access_key_id=None, aws_secret_access_key=None,
146 is_secure=True, port=None, proxy=None, proxy_port=None,
147 debug=0, security_token=None, region=None,
148 validate_certs=True, dynamizer=LossyFloatDynamizer,
149 profile_name=None):
150 self.layer1 = Layer1(aws_access_key_id, aws_secret_access_key,
151 is_secure, port, proxy, proxy_port,
152 debug, security_token, region,
153 validate_certs=validate_certs,
154 profile_name=profile_name)
155 self.dynamizer = dynamizer()
156
157 def use_decimals(self, use_boolean=False):
158 """
159 Use the ``decimal.Decimal`` type for encoding/decoding numeric types.
160
161 By default, ints/floats are used to represent numeric types
162 ('N', 'NS') received from DynamoDB. Using the ``Decimal``
163 type is recommended to prevent loss of precision.
164
165 """
166 # Eventually this should be made the default dynamizer.
167 self.dynamizer = Dynamizer() if use_boolean else NonBooleanDynamizer()
168
169 def dynamize_attribute_updates(self, pending_updates):
170 """
171 Convert a set of pending item updates into the structure
172 required by Layer1.
173 """
174 d = {}
175 for attr_name in pending_updates:
176 action, value = pending_updates[attr_name]
177 if value is None:
178 # DELETE without an attribute value
179 d[attr_name] = {"Action": action}
180 else:
181 d[attr_name] = {"Action": action,
182 "Value": self.dynamizer.encode(value)}
183 return d
184
185 def dynamize_item(self, item):
186 d = {}
187 for attr_name in item:
188 d[attr_name] = self.dynamizer.encode(item[attr_name])
189 return d
190
191 def dynamize_range_key_condition(self, range_key_condition):
192 """
193 Convert a layer2 range_key_condition parameter into the
194 structure required by Layer1.
195 """
196 return range_key_condition.to_dict()
197
198 def dynamize_scan_filter(self, scan_filter):
199 """
200 Convert a layer2 scan_filter parameter into the
201 structure required by Layer1.
202 """
203 d = None
204 if scan_filter:
205 d = {}
206 for attr_name in scan_filter:
207 condition = scan_filter[attr_name]
208 d[attr_name] = condition.to_dict()
209 return d
210
211 def dynamize_expected_value(self, expected_value):
212 """
213 Convert an expected_value parameter into the data structure
214 required for Layer1.
215 """
216 d = None
217 if expected_value:
218 d = {}
219 for attr_name in expected_value:
220 attr_value = expected_value[attr_name]
221 if attr_value is True:
222 attr_value = {'Exists': True}
223 elif attr_value is False:
224 attr_value = {'Exists': False}
225 else:
226 val = self.dynamizer.encode(expected_value[attr_name])
227 attr_value = {'Value': val}
228 d[attr_name] = attr_value
229 return d
230
231 def dynamize_last_evaluated_key(self, last_evaluated_key):
232 """
233 Convert a last_evaluated_key parameter into the data structure
234 required for Layer1.
235 """
236 d = None
237 if last_evaluated_key:
238 hash_key = last_evaluated_key['HashKeyElement']
239 d = {'HashKeyElement': self.dynamizer.encode(hash_key)}
240 if 'RangeKeyElement' in last_evaluated_key:
241 range_key = last_evaluated_key['RangeKeyElement']
242 d['RangeKeyElement'] = self.dynamizer.encode(range_key)
243 return d
244
245 def build_key_from_values(self, schema, hash_key, range_key=None):
246 """
247 Build a Key structure to be used for accessing items
248 in Amazon DynamoDB. This method takes the supplied hash_key
249 and optional range_key and validates them against the
250 schema. If there is a mismatch, a TypeError is raised.
251 Otherwise, a Python dict version of a Amazon DynamoDB Key
252 data structure is returned.
253
254 :type hash_key: int|float|str|unicode|Binary
255 :param hash_key: The hash key of the item you are looking for.
256 The type of the hash key should match the type defined in
257 the schema.
258
259 :type range_key: int|float|str|unicode|Binary
260 :param range_key: The range key of the item your are looking for.
261 This should be supplied only if the schema requires a
262 range key. The type of the range key should match the
263 type defined in the schema.
264 """
265 dynamodb_key = {}
266 dynamodb_value = self.dynamizer.encode(hash_key)
267 if list(dynamodb_value.keys())[0] != schema.hash_key_type:
268 msg = 'Hashkey must be of type: %s' % schema.hash_key_type
269 raise TypeError(msg)
270 dynamodb_key['HashKeyElement'] = dynamodb_value
271 if range_key is not None:
272 dynamodb_value = self.dynamizer.encode(range_key)
273 if list(dynamodb_value.keys())[0] != schema.range_key_type:
274 msg = 'RangeKey must be of type: %s' % schema.range_key_type
275 raise TypeError(msg)
276 dynamodb_key['RangeKeyElement'] = dynamodb_value
277 return dynamodb_key
278
279 def new_batch_list(self):
280 """
281 Return a new, empty :class:`boto.dynamodb.batch.BatchList`
282 object.
283 """
284 return BatchList(self)
285
286 def new_batch_write_list(self):
287 """
288 Return a new, empty :class:`boto.dynamodb.batch.BatchWriteList`
289 object.
290 """
291 return BatchWriteList(self)
292
293 def list_tables(self, limit=None):
294 """
295 Return a list of the names of all tables associated with the
296 current account and region.
297
298 :type limit: int
299 :param limit: The maximum number of tables to return.
300 """
301 tables = []
302 start_table = None
303 while not limit or len(tables) < limit:
304 this_round_limit = None
305 if limit:
306 this_round_limit = limit - len(tables)
307 this_round_limit = min(this_round_limit, 100)
308 result = self.layer1.list_tables(limit=this_round_limit, start_table=start_table)
309 tables.extend(result.get('TableNames', []))
310 start_table = result.get('LastEvaluatedTableName', None)
311 if not start_table:
312 break
313 return tables
314
315 def describe_table(self, name):
316 """
317 Retrieve information about an existing table.
318
319 :type name: str
320 :param name: The name of the desired table.
321
322 """
323 return self.layer1.describe_table(name)
324
325 def table_from_schema(self, name, schema):
326 """
327 Create a Table object from a schema.
328
329 This method will create a Table object without
330 making any API calls. If you know the name and schema
331 of the table, you can use this method instead of
332 ``get_table``.
333
334 Example usage::
335
336 table = layer2.table_from_schema(
337 'tablename',
338 Schema.create(hash_key=('foo', 'N')))
339
340 :type name: str
341 :param name: The name of the table.
342
343 :type schema: :class:`boto.dynamodb.schema.Schema`
344 :param schema: The schema associated with the table.
345
346 :rtype: :class:`boto.dynamodb.table.Table`
347 :return: A Table object representing the table.
348
349 """
350 return Table.create_from_schema(self, name, schema)
351
352 def get_table(self, name):
353 """
354 Retrieve the Table object for an existing table.
355
356 :type name: str
357 :param name: The name of the desired table.
358
359 :rtype: :class:`boto.dynamodb.table.Table`
360 :return: A Table object representing the table.
361 """
362 response = self.layer1.describe_table(name)
363 return Table(self, response)
364
365 lookup = get_table
366
367 def create_table(self, name, schema, read_units, write_units):
368 """
369 Create a new Amazon DynamoDB table.
370
371 :type name: str
372 :param name: The name of the desired table.
373
374 :type schema: :class:`boto.dynamodb.schema.Schema`
375 :param schema: The Schema object that defines the schema used
376 by this table.
377
378 :type read_units: int
379 :param read_units: The value for ReadCapacityUnits.
380
381 :type write_units: int
382 :param write_units: The value for WriteCapacityUnits.
383
384 :rtype: :class:`boto.dynamodb.table.Table`
385 :return: A Table object representing the new Amazon DynamoDB table.
386 """
387 response = self.layer1.create_table(name, schema.dict,
388 {'ReadCapacityUnits': read_units,
389 'WriteCapacityUnits': write_units})
390 return Table(self, response)
391
392 def update_throughput(self, table, read_units, write_units):
393 """
394 Update the ProvisionedThroughput for the Amazon DynamoDB Table.
395
396 :type table: :class:`boto.dynamodb.table.Table`
397 :param table: The Table object whose throughput is being updated.
398
399 :type read_units: int
400 :param read_units: The new value for ReadCapacityUnits.
401
402 :type write_units: int
403 :param write_units: The new value for WriteCapacityUnits.
404 """
405 response = self.layer1.update_table(table.name,
406 {'ReadCapacityUnits': read_units,
407 'WriteCapacityUnits': write_units})
408 table.update_from_response(response)
409
410 def delete_table(self, table):
411 """
412 Delete this table and all items in it. After calling this
413 the Table objects status attribute will be set to 'DELETING'.
414
415 :type table: :class:`boto.dynamodb.table.Table`
416 :param table: The Table object that is being deleted.
417 """
418 response = self.layer1.delete_table(table.name)
419 table.update_from_response(response)
420
421 def create_schema(self, hash_key_name, hash_key_proto_value,
422 range_key_name=None, range_key_proto_value=None):
423 """
424 Create a Schema object used when creating a Table.
425
426 :type hash_key_name: str
427 :param hash_key_name: The name of the HashKey for the schema.
428
429 :type hash_key_proto_value: int|long|float|str|unicode|Binary
430 :param hash_key_proto_value: A sample or prototype of the type
431 of value you want to use for the HashKey. Alternatively,
432 you can also just pass in the Python type (e.g. int, float, etc.).
433
434 :type range_key_name: str
435 :param range_key_name: The name of the RangeKey for the schema.
436 This parameter is optional.
437
438 :type range_key_proto_value: int|long|float|str|unicode|Binary
439 :param range_key_proto_value: A sample or prototype of the type
440 of value you want to use for the RangeKey. Alternatively,
441 you can also pass in the Python type (e.g. int, float, etc.)
442 This parameter is optional.
443 """
444 hash_key = (hash_key_name, get_dynamodb_type(hash_key_proto_value))
445 if range_key_name and range_key_proto_value is not None:
446 range_key = (range_key_name,
447 get_dynamodb_type(range_key_proto_value))
448 else:
449 range_key = None
450 return Schema.create(hash_key, range_key)
451
452 def get_item(self, table, hash_key, range_key=None,
453 attributes_to_get=None, consistent_read=False,
454 item_class=Item):
455 """
456 Retrieve an existing item from the table.
457
458 :type table: :class:`boto.dynamodb.table.Table`
459 :param table: The Table object from which the item is retrieved.
460
461 :type hash_key: int|long|float|str|unicode|Binary
462 :param hash_key: The HashKey of the requested item. The
463 type of the value must match the type defined in the
464 schema for the table.
465
466 :type range_key: int|long|float|str|unicode|Binary
467 :param range_key: The optional RangeKey of the requested item.
468 The type of the value must match the type defined in the
469 schema for the table.
470
471 :type attributes_to_get: list
472 :param attributes_to_get: A list of attribute names.
473 If supplied, only the specified attribute names will
474 be returned. Otherwise, all attributes will be returned.
475
476 :type consistent_read: bool
477 :param consistent_read: If True, a consistent read
478 request is issued. Otherwise, an eventually consistent
479 request is issued.
480
481 :type item_class: Class
482 :param item_class: Allows you to override the class used
483 to generate the items. This should be a subclass of
484 :class:`boto.dynamodb.item.Item`
485 """
486 key = self.build_key_from_values(table.schema, hash_key, range_key)
487 response = self.layer1.get_item(table.name, key,
488 attributes_to_get, consistent_read,
489 object_hook=self.dynamizer.decode)
490 item = item_class(table, hash_key, range_key, response['Item'])
491 if 'ConsumedCapacityUnits' in response:
492 item.consumed_units = response['ConsumedCapacityUnits']
493 return item
494
495 def batch_get_item(self, batch_list):
496 """
497 Return a set of attributes for a multiple items in
498 multiple tables using their primary keys.
499
500 :type batch_list: :class:`boto.dynamodb.batch.BatchList`
501 :param batch_list: A BatchList object which consists of a
502 list of :class:`boto.dynamoddb.batch.Batch` objects.
503 Each Batch object contains the information about one
504 batch of objects that you wish to retrieve in this
505 request.
506 """
507 request_items = batch_list.to_dict()
508 return self.layer1.batch_get_item(request_items,
509 object_hook=self.dynamizer.decode)
510
511 def batch_write_item(self, batch_list):
512 """
513 Performs multiple Puts and Deletes in one batch.
514
515 :type batch_list: :class:`boto.dynamodb.batch.BatchWriteList`
516 :param batch_list: A BatchWriteList object which consists of a
517 list of :class:`boto.dynamoddb.batch.BatchWrite` objects.
518 Each Batch object contains the information about one
519 batch of objects that you wish to put or delete.
520 """
521 request_items = batch_list.to_dict()
522 return self.layer1.batch_write_item(request_items,
523 object_hook=self.dynamizer.decode)
524
525 def put_item(self, item, expected_value=None, return_values=None):
526 """
527 Store a new item or completely replace an existing item
528 in Amazon DynamoDB.
529
530 :type item: :class:`boto.dynamodb.item.Item`
531 :param item: The Item to write to Amazon DynamoDB.
532
533 :type expected_value: dict
534 :param expected_value: A dictionary of name/value pairs that you expect.
535 This dictionary should have name/value pairs where the name
536 is the name of the attribute and the value is either the value
537 you are expecting or False if you expect the attribute not to
538 exist.
539
540 :type return_values: str
541 :param return_values: Controls the return of attribute
542 name-value pairs before then were changed. Possible
543 values are: None or 'ALL_OLD'. If 'ALL_OLD' is
544 specified and the item is overwritten, the content
545 of the old item is returned.
546 """
547 expected_value = self.dynamize_expected_value(expected_value)
548 response = self.layer1.put_item(item.table.name,
549 self.dynamize_item(item),
550 expected_value, return_values,
551 object_hook=self.dynamizer.decode)
552 if 'ConsumedCapacityUnits' in response:
553 item.consumed_units = response['ConsumedCapacityUnits']
554 return response
555
556 def update_item(self, item, expected_value=None, return_values=None):
557 """
558 Commit pending item updates to Amazon DynamoDB.
559
560 :type item: :class:`boto.dynamodb.item.Item`
561 :param item: The Item to update in Amazon DynamoDB. It is expected
562 that you would have called the add_attribute, put_attribute
563 and/or delete_attribute methods on this Item prior to calling
564 this method. Those queued changes are what will be updated.
565
566 :type expected_value: dict
567 :param expected_value: A dictionary of name/value pairs that you
568 expect. This dictionary should have name/value pairs where the
569 name is the name of the attribute and the value is either the
570 value you are expecting or False if you expect the attribute
571 not to exist.
572
573 :type return_values: str
574 :param return_values: Controls the return of attribute name/value pairs
575 before they were updated. Possible values are: None, 'ALL_OLD',
576 'UPDATED_OLD', 'ALL_NEW' or 'UPDATED_NEW'. If 'ALL_OLD' is
577 specified and the item is overwritten, the content of the old item
578 is returned. If 'ALL_NEW' is specified, then all the attributes of
579 the new version of the item are returned. If 'UPDATED_NEW' is
580 specified, the new versions of only the updated attributes are
581 returned.
582
583 """
584 expected_value = self.dynamize_expected_value(expected_value)
585 key = self.build_key_from_values(item.table.schema,
586 item.hash_key, item.range_key)
587 attr_updates = self.dynamize_attribute_updates(item._updates)
588
589 response = self.layer1.update_item(item.table.name, key,
590 attr_updates,
591 expected_value, return_values,
592 object_hook=self.dynamizer.decode)
593 item._updates.clear()
594 if 'ConsumedCapacityUnits' in response:
595 item.consumed_units = response['ConsumedCapacityUnits']
596 return response
597
598 def delete_item(self, item, expected_value=None, return_values=None):
599 """
600 Delete the item from Amazon DynamoDB.
601
602 :type item: :class:`boto.dynamodb.item.Item`
603 :param item: The Item to delete from Amazon DynamoDB.
604
605 :type expected_value: dict
606 :param expected_value: A dictionary of name/value pairs that you expect.
607 This dictionary should have name/value pairs where the name
608 is the name of the attribute and the value is either the value
609 you are expecting or False if you expect the attribute not to
610 exist.
611
612 :type return_values: str
613 :param return_values: Controls the return of attribute
614 name-value pairs before then were changed. Possible
615 values are: None or 'ALL_OLD'. If 'ALL_OLD' is
616 specified and the item is overwritten, the content
617 of the old item is returned.
618 """
619 expected_value = self.dynamize_expected_value(expected_value)
620 key = self.build_key_from_values(item.table.schema,
621 item.hash_key, item.range_key)
622 return self.layer1.delete_item(item.table.name, key,
623 expected=expected_value,
624 return_values=return_values,
625 object_hook=self.dynamizer.decode)
626
627 def query(self, table, hash_key, range_key_condition=None,
628 attributes_to_get=None, request_limit=None,
629 max_results=None, consistent_read=False,
630 scan_index_forward=True, exclusive_start_key=None,
631 item_class=Item, count=False):
632 """
633 Perform a query on the table.
634
635 :type table: :class:`boto.dynamodb.table.Table`
636 :param table: The Table object that is being queried.
637
638 :type hash_key: int|long|float|str|unicode|Binary
639 :param hash_key: The HashKey of the requested item. The
640 type of the value must match the type defined in the
641 schema for the table.
642
643 :type range_key_condition: :class:`boto.dynamodb.condition.Condition`
644 :param range_key_condition: A Condition object.
645 Condition object can be one of the following types:
646
647 EQ|LE|LT|GE|GT|BEGINS_WITH|BETWEEN
648
649 The only condition which expects or will accept two
650 values is 'BETWEEN', otherwise a single value should
651 be passed to the Condition constructor.
652
653 :type attributes_to_get: list
654 :param attributes_to_get: A list of attribute names.
655 If supplied, only the specified attribute names will
656 be returned. Otherwise, all attributes will be returned.
657
658 :type request_limit: int
659 :param request_limit: The maximum number of items to retrieve
660 from Amazon DynamoDB on each request. You may want to set
661 a specific request_limit based on the provisioned throughput
662 of your table. The default behavior is to retrieve as many
663 results as possible per request.
664
665 :type max_results: int
666 :param max_results: The maximum number of results that will
667 be retrieved from Amazon DynamoDB in total. For example,
668 if you only wanted to see the first 100 results from the
669 query, regardless of how many were actually available, you
670 could set max_results to 100 and the generator returned
671 from the query method will only yeild 100 results max.
672
673 :type consistent_read: bool
674 :param consistent_read: If True, a consistent read
675 request is issued. Otherwise, an eventually consistent
676 request is issued.
677
678 :type scan_index_forward: bool
679 :param scan_index_forward: Specified forward or backward
680 traversal of the index. Default is forward (True).
681
682 :type count: bool
683 :param count: If True, Amazon DynamoDB returns a total
684 number of items for the Query operation, even if the
685 operation has no matching items for the assigned filter.
686 If count is True, the actual items are not returned and
687 the count is accessible as the ``count`` attribute of
688 the returned object.
689
690 :type exclusive_start_key: list or tuple
691 :param exclusive_start_key: Primary key of the item from
692 which to continue an earlier query. This would be
693 provided as the LastEvaluatedKey in that query.
694
695 :type item_class: Class
696 :param item_class: Allows you to override the class used
697 to generate the items. This should be a subclass of
698 :class:`boto.dynamodb.item.Item`
699
700 :rtype: :class:`boto.dynamodb.layer2.TableGenerator`
701 """
702 if range_key_condition:
703 rkc = self.dynamize_range_key_condition(range_key_condition)
704 else:
705 rkc = None
706 if exclusive_start_key:
707 esk = self.build_key_from_values(table.schema,
708 *exclusive_start_key)
709 else:
710 esk = None
711 kwargs = {'table_name': table.name,
712 'hash_key_value': self.dynamizer.encode(hash_key),
713 'range_key_conditions': rkc,
714 'attributes_to_get': attributes_to_get,
715 'limit': request_limit,
716 'count': count,
717 'consistent_read': consistent_read,
718 'scan_index_forward': scan_index_forward,
719 'exclusive_start_key': esk,
720 'object_hook': self.dynamizer.decode}
721 return TableGenerator(table, self.layer1.query,
722 max_results, item_class, kwargs)
723
724 def scan(self, table, scan_filter=None,
725 attributes_to_get=None, request_limit=None, max_results=None,
726 exclusive_start_key=None, item_class=Item, count=False):
727 """
728 Perform a scan of DynamoDB.
729
730 :type table: :class:`boto.dynamodb.table.Table`
731 :param table: The Table object that is being scanned.
732
733 :type scan_filter: A dict
734 :param scan_filter: A dictionary where the key is the
735 attribute name and the value is a
736 :class:`boto.dynamodb.condition.Condition` object.
737 Valid Condition objects include:
738
739 * EQ - equal (1)
740 * NE - not equal (1)
741 * LE - less than or equal (1)
742 * LT - less than (1)
743 * GE - greater than or equal (1)
744 * GT - greater than (1)
745 * NOT_NULL - attribute exists (0, use None)
746 * NULL - attribute does not exist (0, use None)
747 * CONTAINS - substring or value in list (1)
748 * NOT_CONTAINS - absence of substring or value in list (1)
749 * BEGINS_WITH - substring prefix (1)
750 * IN - exact match in list (N)
751 * BETWEEN - >= first value, <= second value (2)
752
753 :type attributes_to_get: list
754 :param attributes_to_get: A list of attribute names.
755 If supplied, only the specified attribute names will
756 be returned. Otherwise, all attributes will be returned.
757
758 :type request_limit: int
759 :param request_limit: The maximum number of items to retrieve
760 from Amazon DynamoDB on each request. You may want to set
761 a specific request_limit based on the provisioned throughput
762 of your table. The default behavior is to retrieve as many
763 results as possible per request.
764
765 :type max_results: int
766 :param max_results: The maximum number of results that will
767 be retrieved from Amazon DynamoDB in total. For example,
768 if you only wanted to see the first 100 results from the
769 query, regardless of how many were actually available, you
770 could set max_results to 100 and the generator returned
771 from the query method will only yeild 100 results max.
772
773 :type count: bool
774 :param count: If True, Amazon DynamoDB returns a total
775 number of items for the Scan operation, even if the
776 operation has no matching items for the assigned filter.
777 If count is True, the actual items are not returned and
778 the count is accessible as the ``count`` attribute of
779 the returned object.
780
781 :type exclusive_start_key: list or tuple
782 :param exclusive_start_key: Primary key of the item from
783 which to continue an earlier query. This would be
784 provided as the LastEvaluatedKey in that query.
785
786 :type item_class: Class
787 :param item_class: Allows you to override the class used
788 to generate the items. This should be a subclass of
789 :class:`boto.dynamodb.item.Item`
790
791 :rtype: :class:`boto.dynamodb.layer2.TableGenerator`
792 """
793 if exclusive_start_key:
794 esk = self.build_key_from_values(table.schema,
795 *exclusive_start_key)
796 else:
797 esk = None
798 kwargs = {'table_name': table.name,
799 'scan_filter': self.dynamize_scan_filter(scan_filter),
800 'attributes_to_get': attributes_to_get,
801 'limit': request_limit,
802 'count': count,
803 'exclusive_start_key': esk,
804 'object_hook': self.dynamizer.decode}
805 return TableGenerator(table, self.layer1.scan,
806 max_results, item_class, kwargs)