OLD | NEW |
(Empty) | |
| 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, dynamize_value, \ |
| 29 item_object_hook |
| 30 |
| 31 |
| 32 def table_generator(tgen): |
| 33 """ |
| 34 A low-level generator used to page through results from |
| 35 query and scan operations. This is used by |
| 36 :class:`boto.dynamodb.layer2.TableGenerator` and is not intended |
| 37 to be used outside of that context. |
| 38 """ |
| 39 n = 0 |
| 40 while True: |
| 41 response = tgen.callable(**tgen.kwargs) |
| 42 if not response: |
| 43 break |
| 44 tgen.consumed_units += response.get('ConsumedCapacityUnits', 0) |
| 45 # at the expense of a possibly gratuitous dynamize, ensure that |
| 46 # early generator termination won't result in bad LEK values |
| 47 if 'LastEvaluatedKey' in response: |
| 48 lek = response['LastEvaluatedKey'] |
| 49 esk = tgen.table.layer2.dynamize_last_evaluated_key(lek) |
| 50 tgen.kwargs['exclusive_start_key'] = esk |
| 51 lektuple = (lek['HashKeyElement'],) |
| 52 if 'RangeKeyElement' in lek: |
| 53 lektuple += (lek['RangeKeyElement'],) |
| 54 tgen.last_evaluated_key = lektuple |
| 55 else: |
| 56 tgen.last_evaluated_key = None |
| 57 for item in response['Items']: |
| 58 if tgen.max_results is not None and n == tgen.max_results: |
| 59 break |
| 60 yield tgen.item_class(tgen.table, attrs=item) |
| 61 n += 1 |
| 62 else: |
| 63 if tgen.last_evaluated_key is not None: |
| 64 continue |
| 65 break |
| 66 |
| 67 |
| 68 class TableGenerator: |
| 69 """ |
| 70 This is an object that wraps up the table_generator function. |
| 71 The only real reason to have this is that we want to be able |
| 72 to accumulate and return the ConsumedCapacityUnits element that |
| 73 is part of each response. |
| 74 |
| 75 :ivar consumed_units: An integer that holds the number of |
| 76 ConsumedCapacityUnits accumulated thus far for this |
| 77 generator. |
| 78 |
| 79 :ivar last_evaluated_key: A sequence representing the key(s) |
| 80 of the item last evaluated, or None if no additional |
| 81 results are available. |
| 82 """ |
| 83 |
| 84 def __init__(self, table, callable, max_results, item_class, kwargs): |
| 85 self.table = table |
| 86 self.callable = callable |
| 87 self.max_results = max_results |
| 88 self.item_class = item_class |
| 89 self.kwargs = kwargs |
| 90 self.consumed_units = 0 |
| 91 self.last_evaluated_key = None |
| 92 |
| 93 def __iter__(self): |
| 94 return table_generator(self) |
| 95 |
| 96 |
| 97 class Layer2(object): |
| 98 |
| 99 def __init__(self, aws_access_key_id=None, aws_secret_access_key=None, |
| 100 is_secure=True, port=None, proxy=None, proxy_port=None, |
| 101 debug=0, security_token=None, region=None, |
| 102 validate_certs=True): |
| 103 self.layer1 = Layer1(aws_access_key_id, aws_secret_access_key, |
| 104 is_secure, port, proxy, proxy_port, |
| 105 debug, security_token, region, |
| 106 validate_certs=validate_certs) |
| 107 |
| 108 def dynamize_attribute_updates(self, pending_updates): |
| 109 """ |
| 110 Convert a set of pending item updates into the structure |
| 111 required by Layer1. |
| 112 """ |
| 113 d = {} |
| 114 for attr_name in pending_updates: |
| 115 action, value = pending_updates[attr_name] |
| 116 if value is None: |
| 117 # DELETE without an attribute value |
| 118 d[attr_name] = {"Action": action} |
| 119 else: |
| 120 d[attr_name] = {"Action": action, |
| 121 "Value": dynamize_value(value)} |
| 122 return d |
| 123 |
| 124 def dynamize_item(self, item): |
| 125 d = {} |
| 126 for attr_name in item: |
| 127 d[attr_name] = dynamize_value(item[attr_name]) |
| 128 return d |
| 129 |
| 130 def dynamize_range_key_condition(self, range_key_condition): |
| 131 """ |
| 132 Convert a layer2 range_key_condition parameter into the |
| 133 structure required by Layer1. |
| 134 """ |
| 135 return range_key_condition.to_dict() |
| 136 |
| 137 def dynamize_scan_filter(self, scan_filter): |
| 138 """ |
| 139 Convert a layer2 scan_filter parameter into the |
| 140 structure required by Layer1. |
| 141 """ |
| 142 d = None |
| 143 if scan_filter: |
| 144 d = {} |
| 145 for attr_name in scan_filter: |
| 146 condition = scan_filter[attr_name] |
| 147 d[attr_name] = condition.to_dict() |
| 148 return d |
| 149 |
| 150 def dynamize_expected_value(self, expected_value): |
| 151 """ |
| 152 Convert an expected_value parameter into the data structure |
| 153 required for Layer1. |
| 154 """ |
| 155 d = None |
| 156 if expected_value: |
| 157 d = {} |
| 158 for attr_name in expected_value: |
| 159 attr_value = expected_value[attr_name] |
| 160 if attr_value is True: |
| 161 attr_value = {'Exists': True} |
| 162 elif attr_value is False: |
| 163 attr_value = {'Exists': False} |
| 164 else: |
| 165 val = dynamize_value(expected_value[attr_name]) |
| 166 attr_value = {'Value': val} |
| 167 d[attr_name] = attr_value |
| 168 return d |
| 169 |
| 170 def dynamize_last_evaluated_key(self, last_evaluated_key): |
| 171 """ |
| 172 Convert a last_evaluated_key parameter into the data structure |
| 173 required for Layer1. |
| 174 """ |
| 175 d = None |
| 176 if last_evaluated_key: |
| 177 hash_key = last_evaluated_key['HashKeyElement'] |
| 178 d = {'HashKeyElement': dynamize_value(hash_key)} |
| 179 if 'RangeKeyElement' in last_evaluated_key: |
| 180 range_key = last_evaluated_key['RangeKeyElement'] |
| 181 d['RangeKeyElement'] = dynamize_value(range_key) |
| 182 return d |
| 183 |
| 184 def build_key_from_values(self, schema, hash_key, range_key=None): |
| 185 """ |
| 186 Build a Key structure to be used for accessing items |
| 187 in Amazon DynamoDB. This method takes the supplied hash_key |
| 188 and optional range_key and validates them against the |
| 189 schema. If there is a mismatch, a TypeError is raised. |
| 190 Otherwise, a Python dict version of a Amazon DynamoDB Key |
| 191 data structure is returned. |
| 192 |
| 193 :type hash_key: int, float, str, or unicode |
| 194 :param hash_key: The hash key of the item you are looking for. |
| 195 The type of the hash key should match the type defined in |
| 196 the schema. |
| 197 |
| 198 :type range_key: int, float, str or unicode |
| 199 :param range_key: The range key of the item your are looking for. |
| 200 This should be supplied only if the schema requires a |
| 201 range key. The type of the range key should match the |
| 202 type defined in the schema. |
| 203 """ |
| 204 dynamodb_key = {} |
| 205 dynamodb_value = dynamize_value(hash_key) |
| 206 if dynamodb_value.keys()[0] != schema.hash_key_type: |
| 207 msg = 'Hashkey must be of type: %s' % schema.hash_key_type |
| 208 raise TypeError(msg) |
| 209 dynamodb_key['HashKeyElement'] = dynamodb_value |
| 210 if range_key is not None: |
| 211 dynamodb_value = dynamize_value(range_key) |
| 212 if dynamodb_value.keys()[0] != schema.range_key_type: |
| 213 msg = 'RangeKey must be of type: %s' % schema.range_key_type |
| 214 raise TypeError(msg) |
| 215 dynamodb_key['RangeKeyElement'] = dynamodb_value |
| 216 return dynamodb_key |
| 217 |
| 218 def new_batch_list(self): |
| 219 """ |
| 220 Return a new, empty :class:`boto.dynamodb.batch.BatchList` |
| 221 object. |
| 222 """ |
| 223 return BatchList(self) |
| 224 |
| 225 def new_batch_write_list(self): |
| 226 """ |
| 227 Return a new, empty :class:`boto.dynamodb.batch.BatchWriteList` |
| 228 object. |
| 229 """ |
| 230 return BatchWriteList(self) |
| 231 |
| 232 def list_tables(self, limit=None): |
| 233 """ |
| 234 Return a list of the names of all tables associated with the |
| 235 current account and region. |
| 236 |
| 237 :type limit: int |
| 238 :param limit: The maximum number of tables to return. |
| 239 """ |
| 240 tables = [] |
| 241 start_table = None |
| 242 while not limit or len(tables) < limit: |
| 243 this_round_limit = None |
| 244 if limit: |
| 245 this_round_limit = limit - len(tables) |
| 246 this_round_limit = min(this_round_limit, 100) |
| 247 result = self.layer1.list_tables(limit=this_round_limit, start_table
=start_table) |
| 248 tables.extend(result.get('TableNames', [])) |
| 249 start_table = result.get('LastEvaluatedTableName', None) |
| 250 if not start_table: |
| 251 break |
| 252 return tables |
| 253 |
| 254 def describe_table(self, name): |
| 255 """ |
| 256 Retrieve information about an existing table. |
| 257 |
| 258 :type name: str |
| 259 :param name: The name of the desired table. |
| 260 |
| 261 """ |
| 262 return self.layer1.describe_table(name) |
| 263 |
| 264 def get_table(self, name): |
| 265 """ |
| 266 Retrieve the Table object for an existing table. |
| 267 |
| 268 :type name: str |
| 269 :param name: The name of the desired table. |
| 270 |
| 271 :rtype: :class:`boto.dynamodb.table.Table` |
| 272 :return: A Table object representing the table. |
| 273 """ |
| 274 response = self.layer1.describe_table(name) |
| 275 return Table(self, response) |
| 276 |
| 277 lookup = get_table |
| 278 |
| 279 def create_table(self, name, schema, read_units, write_units): |
| 280 """ |
| 281 Create a new Amazon DynamoDB table. |
| 282 |
| 283 :type name: str |
| 284 :param name: The name of the desired table. |
| 285 |
| 286 :type schema: :class:`boto.dynamodb.schema.Schema` |
| 287 :param schema: The Schema object that defines the schema used |
| 288 by this table. |
| 289 |
| 290 :type read_units: int |
| 291 :param read_units: The value for ReadCapacityUnits. |
| 292 |
| 293 :type write_units: int |
| 294 :param write_units: The value for WriteCapacityUnits. |
| 295 |
| 296 :rtype: :class:`boto.dynamodb.table.Table` |
| 297 :return: A Table object representing the new Amazon DynamoDB table. |
| 298 """ |
| 299 response = self.layer1.create_table(name, schema.dict, |
| 300 {'ReadCapacityUnits': read_units, |
| 301 'WriteCapacityUnits': write_units}) |
| 302 return Table(self, response) |
| 303 |
| 304 def update_throughput(self, table, read_units, write_units): |
| 305 """ |
| 306 Update the ProvisionedThroughput for the Amazon DynamoDB Table. |
| 307 |
| 308 :type table: :class:`boto.dynamodb.table.Table` |
| 309 :param table: The Table object whose throughput is being updated. |
| 310 |
| 311 :type read_units: int |
| 312 :param read_units: The new value for ReadCapacityUnits. |
| 313 |
| 314 :type write_units: int |
| 315 :param write_units: The new value for WriteCapacityUnits. |
| 316 """ |
| 317 response = self.layer1.update_table(table.name, |
| 318 {'ReadCapacityUnits': read_units, |
| 319 'WriteCapacityUnits': write_units}) |
| 320 table.update_from_response(response) |
| 321 |
| 322 def delete_table(self, table): |
| 323 """ |
| 324 Delete this table and all items in it. After calling this |
| 325 the Table objects status attribute will be set to 'DELETING'. |
| 326 |
| 327 :type table: :class:`boto.dynamodb.table.Table` |
| 328 :param table: The Table object that is being deleted. |
| 329 """ |
| 330 response = self.layer1.delete_table(table.name) |
| 331 table.update_from_response(response) |
| 332 |
| 333 def create_schema(self, hash_key_name, hash_key_proto_value, |
| 334 range_key_name=None, range_key_proto_value=None): |
| 335 """ |
| 336 Create a Schema object used when creating a Table. |
| 337 |
| 338 :type hash_key_name: str |
| 339 :param hash_key_name: The name of the HashKey for the schema. |
| 340 |
| 341 :type hash_key_proto_value: int|long|float|str|unicode |
| 342 :param hash_key_proto_value: A sample or prototype of the type |
| 343 of value you want to use for the HashKey. Alternatively, |
| 344 you can also just pass in the Python type (e.g. int, float, etc.). |
| 345 |
| 346 :type range_key_name: str |
| 347 :param range_key_name: The name of the RangeKey for the schema. |
| 348 This parameter is optional. |
| 349 |
| 350 :type range_key_proto_value: int|long|float|str|unicode |
| 351 :param range_key_proto_value: A sample or prototype of the type |
| 352 of value you want to use for the RangeKey. Alternatively, |
| 353 you can also pass in the Python type (e.g. int, float, etc.) |
| 354 This parameter is optional. |
| 355 """ |
| 356 schema = {} |
| 357 hash_key = {} |
| 358 hash_key['AttributeName'] = hash_key_name |
| 359 hash_key_type = get_dynamodb_type(hash_key_proto_value) |
| 360 hash_key['AttributeType'] = hash_key_type |
| 361 schema['HashKeyElement'] = hash_key |
| 362 if range_key_name and range_key_proto_value is not None: |
| 363 range_key = {} |
| 364 range_key['AttributeName'] = range_key_name |
| 365 range_key_type = get_dynamodb_type(range_key_proto_value) |
| 366 range_key['AttributeType'] = range_key_type |
| 367 schema['RangeKeyElement'] = range_key |
| 368 return Schema(schema) |
| 369 |
| 370 def get_item(self, table, hash_key, range_key=None, |
| 371 attributes_to_get=None, consistent_read=False, |
| 372 item_class=Item): |
| 373 """ |
| 374 Retrieve an existing item from the table. |
| 375 |
| 376 :type table: :class:`boto.dynamodb.table.Table` |
| 377 :param table: The Table object from which the item is retrieved. |
| 378 |
| 379 :type hash_key: int|long|float|str|unicode |
| 380 :param hash_key: The HashKey of the requested item. The |
| 381 type of the value must match the type defined in the |
| 382 schema for the table. |
| 383 |
| 384 :type range_key: int|long|float|str|unicode |
| 385 :param range_key: The optional RangeKey of the requested item. |
| 386 The type of the value must match the type defined in the |
| 387 schema for the table. |
| 388 |
| 389 :type attributes_to_get: list |
| 390 :param attributes_to_get: A list of attribute names. |
| 391 If supplied, only the specified attribute names will |
| 392 be returned. Otherwise, all attributes will be returned. |
| 393 |
| 394 :type consistent_read: bool |
| 395 :param consistent_read: If True, a consistent read |
| 396 request is issued. Otherwise, an eventually consistent |
| 397 request is issued. |
| 398 |
| 399 :type item_class: Class |
| 400 :param item_class: Allows you to override the class used |
| 401 to generate the items. This should be a subclass of |
| 402 :class:`boto.dynamodb.item.Item` |
| 403 """ |
| 404 key = self.build_key_from_values(table.schema, hash_key, range_key) |
| 405 response = self.layer1.get_item(table.name, key, |
| 406 attributes_to_get, consistent_read, |
| 407 object_hook=item_object_hook) |
| 408 item = item_class(table, hash_key, range_key, response['Item']) |
| 409 if 'ConsumedCapacityUnits' in response: |
| 410 item.consumed_units = response['ConsumedCapacityUnits'] |
| 411 return item |
| 412 |
| 413 def batch_get_item(self, batch_list): |
| 414 """ |
| 415 Return a set of attributes for a multiple items in |
| 416 multiple tables using their primary keys. |
| 417 |
| 418 :type batch_list: :class:`boto.dynamodb.batch.BatchList` |
| 419 :param batch_list: A BatchList object which consists of a |
| 420 list of :class:`boto.dynamoddb.batch.Batch` objects. |
| 421 Each Batch object contains the information about one |
| 422 batch of objects that you wish to retrieve in this |
| 423 request. |
| 424 """ |
| 425 request_items = batch_list.to_dict() |
| 426 return self.layer1.batch_get_item(request_items, |
| 427 object_hook=item_object_hook) |
| 428 |
| 429 def batch_write_item(self, batch_list): |
| 430 """ |
| 431 Performs multiple Puts and Deletes in one batch. |
| 432 |
| 433 :type batch_list: :class:`boto.dynamodb.batch.BatchWriteList` |
| 434 :param batch_list: A BatchWriteList object which consists of a |
| 435 list of :class:`boto.dynamoddb.batch.BatchWrite` objects. |
| 436 Each Batch object contains the information about one |
| 437 batch of objects that you wish to put or delete. |
| 438 """ |
| 439 request_items = batch_list.to_dict() |
| 440 return self.layer1.batch_write_item(request_items, |
| 441 object_hook=item_object_hook) |
| 442 |
| 443 def put_item(self, item, expected_value=None, return_values=None): |
| 444 """ |
| 445 Store a new item or completely replace an existing item |
| 446 in Amazon DynamoDB. |
| 447 |
| 448 :type item: :class:`boto.dynamodb.item.Item` |
| 449 :param item: The Item to write to Amazon DynamoDB. |
| 450 |
| 451 :type expected_value: dict |
| 452 :param expected_value: A dictionary of name/value pairs that you expect. |
| 453 This dictionary should have name/value pairs where the name |
| 454 is the name of the attribute and the value is either the value |
| 455 you are expecting or False if you expect the attribute not to |
| 456 exist. |
| 457 |
| 458 :type return_values: str |
| 459 :param return_values: Controls the return of attribute |
| 460 name-value pairs before then were changed. Possible |
| 461 values are: None or 'ALL_OLD'. If 'ALL_OLD' is |
| 462 specified and the item is overwritten, the content |
| 463 of the old item is returned. |
| 464 """ |
| 465 expected_value = self.dynamize_expected_value(expected_value) |
| 466 response = self.layer1.put_item(item.table.name, |
| 467 self.dynamize_item(item), |
| 468 expected_value, return_values, |
| 469 object_hook=item_object_hook) |
| 470 if 'ConsumedCapacityUnits' in response: |
| 471 item.consumed_units = response['ConsumedCapacityUnits'] |
| 472 return response |
| 473 |
| 474 def update_item(self, item, expected_value=None, return_values=None): |
| 475 """ |
| 476 Commit pending item updates to Amazon DynamoDB. |
| 477 |
| 478 :type item: :class:`boto.dynamodb.item.Item` |
| 479 :param item: The Item to update in Amazon DynamoDB. It is expected |
| 480 that you would have called the add_attribute, put_attribute |
| 481 and/or delete_attribute methods on this Item prior to calling |
| 482 this method. Those queued changes are what will be updated. |
| 483 |
| 484 :type expected_value: dict |
| 485 :param expected_value: A dictionary of name/value pairs that you |
| 486 expect. This dictionary should have name/value pairs where the |
| 487 name is the name of the attribute and the value is either the |
| 488 value you are expecting or False if you expect the attribute |
| 489 not to exist. |
| 490 |
| 491 :type return_values: str |
| 492 :param return_values: Controls the return of attribute name/value pairs |
| 493 before they were updated. Possible values are: None, 'ALL_OLD', |
| 494 'UPDATED_OLD', 'ALL_NEW' or 'UPDATED_NEW'. If 'ALL_OLD' is |
| 495 specified and the item is overwritten, the content of the old item |
| 496 is returned. If 'ALL_NEW' is specified, then all the attributes of |
| 497 the new version of the item are returned. If 'UPDATED_NEW' is |
| 498 specified, the new versions of only the updated attributes are |
| 499 returned. |
| 500 |
| 501 """ |
| 502 expected_value = self.dynamize_expected_value(expected_value) |
| 503 key = self.build_key_from_values(item.table.schema, |
| 504 item.hash_key, item.range_key) |
| 505 attr_updates = self.dynamize_attribute_updates(item._updates) |
| 506 |
| 507 response = self.layer1.update_item(item.table.name, key, |
| 508 attr_updates, |
| 509 expected_value, return_values, |
| 510 object_hook=item_object_hook) |
| 511 item._updates.clear() |
| 512 if 'ConsumedCapacityUnits' in response: |
| 513 item.consumed_units = response['ConsumedCapacityUnits'] |
| 514 return response |
| 515 |
| 516 def delete_item(self, item, expected_value=None, return_values=None): |
| 517 """ |
| 518 Delete the item from Amazon DynamoDB. |
| 519 |
| 520 :type item: :class:`boto.dynamodb.item.Item` |
| 521 :param item: The Item to delete from Amazon DynamoDB. |
| 522 |
| 523 :type expected_value: dict |
| 524 :param expected_value: A dictionary of name/value pairs that you expect. |
| 525 This dictionary should have name/value pairs where the name |
| 526 is the name of the attribute and the value is either the value |
| 527 you are expecting or False if you expect the attribute not to |
| 528 exist. |
| 529 |
| 530 :type return_values: str |
| 531 :param return_values: Controls the return of attribute |
| 532 name-value pairs before then were changed. Possible |
| 533 values are: None or 'ALL_OLD'. If 'ALL_OLD' is |
| 534 specified and the item is overwritten, the content |
| 535 of the old item is returned. |
| 536 """ |
| 537 expected_value = self.dynamize_expected_value(expected_value) |
| 538 key = self.build_key_from_values(item.table.schema, |
| 539 item.hash_key, item.range_key) |
| 540 return self.layer1.delete_item(item.table.name, key, |
| 541 expected=expected_value, |
| 542 return_values=return_values, |
| 543 object_hook=item_object_hook) |
| 544 |
| 545 def query(self, table, hash_key, range_key_condition=None, |
| 546 attributes_to_get=None, request_limit=None, |
| 547 max_results=None, consistent_read=False, |
| 548 scan_index_forward=True, exclusive_start_key=None, |
| 549 item_class=Item): |
| 550 """ |
| 551 Perform a query on the table. |
| 552 |
| 553 :type table: :class:`boto.dynamodb.table.Table` |
| 554 :param table: The Table object that is being queried. |
| 555 |
| 556 :type hash_key: int|long|float|str|unicode |
| 557 :param hash_key: The HashKey of the requested item. The |
| 558 type of the value must match the type defined in the |
| 559 schema for the table. |
| 560 |
| 561 :type range_key_condition: :class:`boto.dynamodb.condition.Condition` |
| 562 :param range_key_condition: A Condition object. |
| 563 Condition object can be one of the following types: |
| 564 |
| 565 EQ|LE|LT|GE|GT|BEGINS_WITH|BETWEEN |
| 566 |
| 567 The only condition which expects or will accept two |
| 568 values is 'BETWEEN', otherwise a single value should |
| 569 be passed to the Condition constructor. |
| 570 |
| 571 :type attributes_to_get: list |
| 572 :param attributes_to_get: A list of attribute names. |
| 573 If supplied, only the specified attribute names will |
| 574 be returned. Otherwise, all attributes will be returned. |
| 575 |
| 576 :type request_limit: int |
| 577 :param request_limit: The maximum number of items to retrieve |
| 578 from Amazon DynamoDB on each request. You may want to set |
| 579 a specific request_limit based on the provisioned throughput |
| 580 of your table. The default behavior is to retrieve as many |
| 581 results as possible per request. |
| 582 |
| 583 :type max_results: int |
| 584 :param max_results: The maximum number of results that will |
| 585 be retrieved from Amazon DynamoDB in total. For example, |
| 586 if you only wanted to see the first 100 results from the |
| 587 query, regardless of how many were actually available, you |
| 588 could set max_results to 100 and the generator returned |
| 589 from the query method will only yeild 100 results max. |
| 590 |
| 591 :type consistent_read: bool |
| 592 :param consistent_read: If True, a consistent read |
| 593 request is issued. Otherwise, an eventually consistent |
| 594 request is issued. |
| 595 |
| 596 :type scan_index_forward: bool |
| 597 :param scan_index_forward: Specified forward or backward |
| 598 traversal of the index. Default is forward (True). |
| 599 |
| 600 :type exclusive_start_key: list or tuple |
| 601 :param exclusive_start_key: Primary key of the item from |
| 602 which to continue an earlier query. This would be |
| 603 provided as the LastEvaluatedKey in that query. |
| 604 |
| 605 :type item_class: Class |
| 606 :param item_class: Allows you to override the class used |
| 607 to generate the items. This should be a subclass of |
| 608 :class:`boto.dynamodb.item.Item` |
| 609 |
| 610 :rtype: :class:`boto.dynamodb.layer2.TableGenerator` |
| 611 """ |
| 612 if range_key_condition: |
| 613 rkc = self.dynamize_range_key_condition(range_key_condition) |
| 614 else: |
| 615 rkc = None |
| 616 if exclusive_start_key: |
| 617 esk = self.build_key_from_values(table.schema, |
| 618 *exclusive_start_key) |
| 619 else: |
| 620 esk = None |
| 621 kwargs = {'table_name': table.name, |
| 622 'hash_key_value': dynamize_value(hash_key), |
| 623 'range_key_conditions': rkc, |
| 624 'attributes_to_get': attributes_to_get, |
| 625 'limit': request_limit, |
| 626 'consistent_read': consistent_read, |
| 627 'scan_index_forward': scan_index_forward, |
| 628 'exclusive_start_key': esk, |
| 629 'object_hook': item_object_hook} |
| 630 return TableGenerator(table, self.layer1.query, |
| 631 max_results, item_class, kwargs) |
| 632 |
| 633 def scan(self, table, scan_filter=None, |
| 634 attributes_to_get=None, request_limit=None, max_results=None, |
| 635 count=False, exclusive_start_key=None, item_class=Item): |
| 636 """ |
| 637 Perform a scan of DynamoDB. |
| 638 |
| 639 :type table: :class:`boto.dynamodb.table.Table` |
| 640 :param table: The Table object that is being scanned. |
| 641 |
| 642 :type scan_filter: A dict |
| 643 :param scan_filter: A dictionary where the key is the |
| 644 attribute name and the value is a |
| 645 :class:`boto.dynamodb.condition.Condition` object. |
| 646 Valid Condition objects include: |
| 647 |
| 648 * EQ - equal (1) |
| 649 * NE - not equal (1) |
| 650 * LE - less than or equal (1) |
| 651 * LT - less than (1) |
| 652 * GE - greater than or equal (1) |
| 653 * GT - greater than (1) |
| 654 * NOT_NULL - attribute exists (0, use None) |
| 655 * NULL - attribute does not exist (0, use None) |
| 656 * CONTAINS - substring or value in list (1) |
| 657 * NOT_CONTAINS - absence of substring or value in list (1) |
| 658 * BEGINS_WITH - substring prefix (1) |
| 659 * IN - exact match in list (N) |
| 660 * BETWEEN - >= first value, <= second value (2) |
| 661 |
| 662 :type attributes_to_get: list |
| 663 :param attributes_to_get: A list of attribute names. |
| 664 If supplied, only the specified attribute names will |
| 665 be returned. Otherwise, all attributes will be returned. |
| 666 |
| 667 :type request_limit: int |
| 668 :param request_limit: The maximum number of items to retrieve |
| 669 from Amazon DynamoDB on each request. You may want to set |
| 670 a specific request_limit based on the provisioned throughput |
| 671 of your table. The default behavior is to retrieve as many |
| 672 results as possible per request. |
| 673 |
| 674 :type max_results: int |
| 675 :param max_results: The maximum number of results that will |
| 676 be retrieved from Amazon DynamoDB in total. For example, |
| 677 if you only wanted to see the first 100 results from the |
| 678 query, regardless of how many were actually available, you |
| 679 could set max_results to 100 and the generator returned |
| 680 from the query method will only yeild 100 results max. |
| 681 |
| 682 :type count: bool |
| 683 :param count: If True, Amazon DynamoDB returns a total |
| 684 number of items for the Scan operation, even if the |
| 685 operation has no matching items for the assigned filter. |
| 686 |
| 687 :type exclusive_start_key: list or tuple |
| 688 :param exclusive_start_key: Primary key of the item from |
| 689 which to continue an earlier query. This would be |
| 690 provided as the LastEvaluatedKey in that query. |
| 691 |
| 692 :type item_class: Class |
| 693 :param item_class: Allows you to override the class used |
| 694 to generate the items. This should be a subclass of |
| 695 :class:`boto.dynamodb.item.Item` |
| 696 |
| 697 :rtype: :class:`boto.dynamodb.layer2.TableGenerator` |
| 698 """ |
| 699 if exclusive_start_key: |
| 700 esk = self.build_key_from_values(table.schema, |
| 701 *exclusive_start_key) |
| 702 else: |
| 703 esk = None |
| 704 kwargs = {'table_name': table.name, |
| 705 'scan_filter': self.dynamize_scan_filter(scan_filter), |
| 706 'attributes_to_get': attributes_to_get, |
| 707 'limit': request_limit, |
| 708 'count': count, |
| 709 'exclusive_start_key': esk, |
| 710 'object_hook': item_object_hook} |
| 711 return TableGenerator(table, self.layer1.scan, |
| 712 max_results, item_class, kwargs) |
OLD | NEW |