def parse_batch_get_request_items(cls, request_items_json): request_list = [] for table_name, request_body in request_items_json.iteritems(): validation.validate_table_name(table_name) validation.validate_object(request_body, table_name) consistent = request_body.pop(Props.CONSISTENT_READ, False) validation.validate_boolean(consistent, Props.CONSISTENT_READ) attributes_to_get = request_body.pop(Props.ATTRIBUTES_TO_GET, None) if attributes_to_get is not None: attributes_to_get = validation.validate_set( attributes_to_get, Props.ATTRIBUTES_TO_GET) for attr_name in attributes_to_get: validation.validate_attr_name(attr_name) keys = request_body.pop(Props.KEYS, None) validation.validate_list(keys, Props.KEYS) validation.validate_unexpected_props(request_body, table_name) for key in keys: key_attribute_map = cls.parse_item_attributes(key) request_list.append( models.GetItemRequest(table_name, key_attribute_map, attributes_to_get, consistent=consistent)) return request_list
def parse_local_secondary_index(cls, local_secondary_index_json): key_attrs_json = local_secondary_index_json.pop(Props.KEY_SCHEMA, None) validation.validate_list(key_attrs_json, Props.KEY_SCHEMA) key_attrs_for_projection = cls.parse_key_schema(key_attrs_json) hash_key = key_attrs_for_projection[0] try: range_key = key_attrs_for_projection[1] except IndexError: raise exception.ValidationError( _("Range key in index wasn't specified")) index_name = local_secondary_index_json.pop(Props.INDEX_NAME, None) validation.validate_index_name(index_name) projection_json = local_secondary_index_json.pop(Props.PROJECTION, None) validation.validate_object(projection_json, Props.PROJECTION) validation.validate_unexpected_props( local_secondary_index_json, "local_secondary_index" ) projection_type = projection_json.pop( Props.PROJECTION_TYPE, Values.PROJECTION_TYPE_INCLUDE ) if projection_type == Values.PROJECTION_TYPE_ALL: projected_attrs = None elif projection_type == Values.PROJECTION_TYPE_KEYS_ONLY: projected_attrs = tuple() elif projection_type == Values.PROJECTION_TYPE_INCLUDE: projected_attrs = projection_json.pop( Props.NON_KEY_ATTRIBUTES, None ) else: raise exception.ValidationError( _("Only '%(pt_all)', '%(pt_ko)' of '%(pt_incl)' projection " "types are allowed, but '%(projection_type)s' is found"), pt_all=Values.PROJECTION_TYPE_ALL, pt_ko=Values.PROJECTION_TYPE_KEYS_ONLY, pt_incl=Values.PROJECTION_TYPE_INCLUDE, projection_type=projection_type ) validation.validate_unexpected_props(projection_json, Props.PROJECTION) return index_name, models.IndexDefinition( hash_key, range_key, projected_attrs )
def parse_local_secondary_index(cls, local_secondary_index_json): key_attrs_json = local_secondary_index_json.pop(Props.KEY_SCHEMA, None) validation.validate_list(key_attrs_json, Props.KEY_SCHEMA) key_attrs_for_projection = cls.parse_key_schema(key_attrs_json) hash_key = key_attrs_for_projection[0] try: range_key = key_attrs_for_projection[1] except IndexError: raise ValidationError(_("Range key in index wasn't specified")) index_name = local_secondary_index_json.pop(Props.INDEX_NAME, None) validation.validate_index_name(index_name) projection_json = local_secondary_index_json.pop(Props.PROJECTION, None) validation.validate_object(projection_json, Props.PROJECTION) validation.validate_unexpected_props( local_secondary_index_json, "local_secondary_index" ) projection_type = projection_json.pop( Props.PROJECTION_TYPE, Values.PROJECTION_TYPE_INCLUDE ) if projection_type == Values.PROJECTION_TYPE_ALL: projected_attrs = None elif projection_type == Values.PROJECTION_TYPE_KEYS_ONLY: projected_attrs = tuple() elif projection_type == Values.PROJECTION_TYPE_INCLUDE: projected_attrs = projection_json.pop( Props.NON_KEY_ATTRIBUTES, None ) else: raise ValidationError( _("Only '%(pt_all)', '%(pt_ko)' of '%(pt_incl)' projection " "types are allowed, but '%(projection_type)s' is found"), pt_all=Values.PROJECTION_TYPE_ALL, pt_ko=Values.PROJECTION_TYPE_KEYS_ONLY, pt_incl=Values.PROJECTION_TYPE_INCLUDE, projection_type=projection_type ) validation.validate_unexpected_props(projection_json, Props.PROJECTION) return index_name, IndexDefinition( hash_key, range_key, projected_attrs )
def parse_batch_get_request_items(cls, request_items_json): request_list = [] for table_name, request_body in request_items_json.iteritems(): validation.validate_table_name(table_name) validation.validate_object(request_body, table_name) consistent = request_body.pop(Props.CONSISTENT_READ, False) validation.validate_boolean(consistent, Props.CONSISTENT_READ) attributes_to_get = request_body.pop( Props.ATTRIBUTES_TO_GET, None ) if attributes_to_get is not None: attributes_to_get = validation.validate_set( attributes_to_get, Props.ATTRIBUTES_TO_GET ) for attr_name in attributes_to_get: validation.validate_attr_name(attr_name) keys = request_body.pop(Props.KEYS, None) validation.validate_list(keys, Props.KEYS) validation.validate_unexpected_props(request_body, table_name) for key in keys: key_attribute_map = cls.parse_item_attributes(key) request_list.append( models.GetItemRequest( table_name, key_attribute_map, attributes_to_get, consistent=consistent ) ) return request_list
def create_table(self, req, body, project_id): with probe.Probe(__name__ + '.validate'): validation.validate_object(body, "body") table_name = body.pop(parser.Props.TABLE_NAME, None) validation.validate_table_name(table_name) # parse table attributes attribute_definitions_json = body.pop( parser.Props.ATTRIBUTE_DEFINITIONS, None ) validation.validate_list_of_objects( attribute_definitions_json, parser.Props.ATTRIBUTE_DEFINITIONS ) attribute_definitions = parser.Parser.parse_attribute_definitions( attribute_definitions_json ) # parse table key schema key_attrs_json = body.pop(parser.Props.KEY_SCHEMA, None) validation.validate_list(key_attrs_json, parser.Props.KEY_SCHEMA) key_attrs = parser.Parser.parse_key_schema(key_attrs_json) # parse table indexed field list lsi_defs_json = body.pop( parser.Props.LOCAL_SECONDARY_INDEXES, None ) if lsi_defs_json: validation.validate_list_of_objects( lsi_defs_json, parser.Props.LOCAL_SECONDARY_INDEXES ) index_def_map = parser.Parser.parse_local_secondary_indexes( lsi_defs_json ) else: index_def_map = {} # validate the uniqueness of table and its indices' key schema range_keys = [] if len(key_attrs) > 1: range_keys.append(key_attrs[1]) else: # table has hash type primary key if len(index_def_map) > 0: raise exception.ValidationError( _("Table without range key in primary key schema " "can not have indices")) for index in index_def_map.values(): range_keys.append(index.alt_range_key_attr) try: validation.validate_set(range_keys, "key_schema") except exception.ValidationError: raise exception.ValidationError( _("Table and its indices must have unique key schema")) validation.validate_unexpected_props(body, "body") # prepare table_schema structure table_schema = models.TableSchema( attribute_definitions, key_attrs, index_def_map) table_meta = storage.create_table( req.context, table_name, table_schema) url = req.path_url + "/" + table_name bookmark = req.path_url + "/" + table_name result = { parser.Props.TABLE_DESCRIPTION: { parser.Props.ATTRIBUTE_DEFINITIONS: ( parser.Parser.format_attribute_definitions( table_meta.schema.attribute_type_map ) ), parser.Props.CREATION_DATE_TIME: table_meta.creation_date_time, parser.Props.ITEM_COUNT: 0, parser.Props.KEY_SCHEMA: ( parser.Parser.format_key_schema( table_meta.schema.key_attributes ) ), parser.Props.TABLE_ID: str(table_meta.id), parser.Props.TABLE_NAME: table_name, parser.Props.TABLE_STATUS: ( parser.Parser.format_table_status(table_meta.status) ), parser.Props.TABLE_SIZE_BYTES: 0, parser.Props.LINKS: [ { parser.Props.HREF: url, parser.Props.REL: parser.Values.SELF }, { parser.Props.HREF: bookmark, parser.Props.REL: parser.Values.BOOKMARK } ] } } if table_meta.schema.index_def_map: table_def = result[parser.Props.TABLE_DESCRIPTION] table_def[parser.Props.LOCAL_SECONDARY_INDEXES] = ( parser.Parser.format_local_secondary_indexes( table_meta.schema.key_attributes[0], table_meta.schema.index_def_map ) ) return result
def scan(self, req, body, project_id, table_name): utils.check_project_id(req.context, project_id) req.context.tenant = project_id with probe.Probe(__name__ + '.validation'): validation.validate_object(body, "body") # get attributes_to_get attributes_to_get = body.pop(parser.Props.ATTRIBUTES_TO_GET, None) if attributes_to_get: validation.validate_list(attributes_to_get, parser.Props.ATTRIBUTES_TO_GET) for attr_name in attributes_to_get: validation.validate_attr_name(attr_name) select = body.pop(parser.Props.SELECT, None) if select is None: if attributes_to_get: select = models.SelectType.SELECT_TYPE_SPECIFIC else: select = models.SelectType.SELECT_TYPE_ALL else: validation.validate_string(select, parser.Props.SELECT) select_type = models.SelectType(select, attributes_to_get) limit = body.pop(parser.Props.LIMIT, None) if limit is not None: limit = validation.validate_integer(limit, parser.Props.LIMIT, min_val=0) # parse exclusive_start_key_attributes exclusive_start_key_attributes_json = body.pop( parser.Props.EXCLUSIVE_START_KEY, None) if exclusive_start_key_attributes_json is not None: validation.validate_object(exclusive_start_key_attributes_json, parser.Props.EXCLUSIVE_START_KEY) exclusive_start_key_attributes = ( parser.Parser.parse_item_attributes( exclusive_start_key_attributes_json ) ) else: exclusive_start_key_attributes = None scan_filter_json = body.pop(parser.Props.SCAN_FILTER, None) if scan_filter_json: validation.validate_object(scan_filter_json, parser.Props.SCAN_FILTER) condition_map = parser.Parser.parse_attribute_conditions( scan_filter_json, condition_class=ScanCondition ) else: condition_map = None total_segments = body.pop(parser.Props.TOTAL_SEGMENTS, 1) total_segments = validation.validate_integer( total_segments, parser.Props.TOTAL_SEGMENTS, min_val=1, max_val=4096 ) segment = body.pop(parser.Props.SEGMENT, 0) segment = validation.validate_integer( segment, parser.Props.SEGMENT, min_val=0, max_val=total_segments ) validation.validate_unexpected_props(body, "body") result = storage.scan( req.context, table_name, condition_map, attributes_to_get=attributes_to_get, limit=limit, exclusive_start_key=exclusive_start_key_attributes) response = { parser.Props.COUNT: result.count, parser.Props.SCANNED_COUNT: result.scanned_count } if not select_type.is_count: response[parser.Props.ITEMS] = [ parser.Parser.format_item_attributes(row) for row in result.items] if result.last_evaluated_key: response[parser.Props.LAST_EVALUATED_KEY] = ( parser.Parser.format_item_attributes( result.last_evaluated_key ) ) return response
def scan(self, req, body, project_id, table_name): utils.check_project_id(req.context, project_id) req.context.tenant = project_id with probe.Probe(__name__ + '.validation'): validation.validate_object(body, "body") # get attributes_to_get attributes_to_get = body.pop(parser.Props.ATTRIBUTES_TO_GET, None) if attributes_to_get: validation.validate_list(attributes_to_get, parser.Props.ATTRIBUTES_TO_GET) for attr_name in attributes_to_get: validation.validate_attr_name(attr_name) select = body.pop(parser.Props.SELECT, None) if select is None: if attributes_to_get: select = models.SelectType.SELECT_TYPE_SPECIFIC else: select = models.SelectType.SELECT_TYPE_ALL else: validation.validate_string(select, parser.Props.SELECT) select_type = models.SelectType(select, attributes_to_get) limit = body.pop(parser.Props.LIMIT, None) if limit is not None: limit = validation.validate_integer(limit, parser.Props.LIMIT, min_val=0) # parse exclusive_start_key_attributes exclusive_start_key_attributes_json = body.pop( parser.Props.EXCLUSIVE_START_KEY, None) if exclusive_start_key_attributes_json is not None: validation.validate_object(exclusive_start_key_attributes_json, parser.Props.EXCLUSIVE_START_KEY) exclusive_start_key_attributes = ( parser.Parser.parse_item_attributes( exclusive_start_key_attributes_json)) else: exclusive_start_key_attributes = None scan_filter_json = body.pop(parser.Props.SCAN_FILTER, None) if scan_filter_json: validation.validate_object(scan_filter_json, parser.Props.SCAN_FILTER) condition_map = parser.Parser.parse_attribute_conditions( scan_filter_json, condition_class=ScanCondition) else: condition_map = None total_segments = body.pop(parser.Props.TOTAL_SEGMENTS, 1) total_segments = validation.validate_integer( total_segments, parser.Props.TOTAL_SEGMENTS, min_val=1, max_val=4096) segment = body.pop(parser.Props.SEGMENT, 0) segment = validation.validate_integer(segment, parser.Props.SEGMENT, min_val=0, max_val=total_segments) validation.validate_unexpected_props(body, "body") result = storage.scan( req.context, table_name, condition_map, attributes_to_get=attributes_to_get, limit=limit, exclusive_start_key=exclusive_start_key_attributes) response = { parser.Props.COUNT: result.count, parser.Props.SCANNED_COUNT: result.scanned_count } if not select_type.is_count: response[parser.Props.ITEMS] = [ parser.Parser.format_item_attributes(row) for row in result.items ] if result.last_evaluated_key: response[parser.Props.LAST_EVALUATED_KEY] = ( parser.Parser.format_item_attributes( result.last_evaluated_key)) return response
def query(self, req, body, project_id, table_name): utils.check_project_id(req.context, project_id) req.context.tenant = project_id with probe.Probe(__name__ + '.validation'): validation.validate_object(body, "body") # get attributes_to_get attributes_to_get = body.pop(parser.Props.ATTRIBUTES_TO_GET, None) if attributes_to_get: validation.validate_list(attributes_to_get, parser.Props.ATTRIBUTES_TO_GET) for attr_name in attributes_to_get: validation.validate_attr_name(attr_name) index_name = body.pop(parser.Props.INDEX_NAME, None) if index_name is not None: validation.validate_index_name(index_name) select = body.pop(parser.Props.SELECT, None) if select is None: if attributes_to_get: select = models.SelectType.SELECT_TYPE_SPECIFIC else: if index_name is not None: select = models.SelectType.SELECT_TYPE_ALL_PROJECTED else: select = models.SelectType.SELECT_TYPE_ALL else: validation.validate_string(select, parser.Props.SELECT) select_type = models.SelectType(select, attributes_to_get) # parse exclusive_start_key_attributes exclusive_start_key_attributes_json = body.pop( parser.Props.EXCLUSIVE_START_KEY, None) if exclusive_start_key_attributes_json is not None: validation.validate_object(exclusive_start_key_attributes_json, parser.Props.EXCLUSIVE_START_KEY) exclusive_start_key_attributes = ( parser.Parser.parse_item_attributes( exclusive_start_key_attributes_json ) ) else: exclusive_start_key_attributes = None # parse indexed_condition_map key_conditions = body.pop(parser.Props.KEY_CONDITIONS, None) validation.validate_object(key_conditions, parser.Props.KEY_CONDITIONS) indexed_condition_map = parser.Parser.parse_attribute_conditions( key_conditions, condition_class=IndexedCondition ) # TODO(dukhlov): # it would be nice to validate given table_name, key_attributes and # attributes_to_get to schema expectation consistent_read = body.pop(parser.Props.CONSISTENT_READ, False) validation.validate_boolean(consistent_read, parser.Props.CONSISTENT_READ) limit = body.pop(parser.Props.LIMIT, None) if limit is not None: limit = validation.validate_integer(limit, parser.Props.LIMIT, min_val=0) scan_forward = body.pop(parser.Props.SCAN_INDEX_FORWARD, None) if scan_forward is not None: validation.validate_boolean(scan_forward, parser.Props.SCAN_INDEX_FORWARD) order_type = ( models.ORDER_TYPE_ASC if scan_forward else models.ORDER_TYPE_DESC ) else: order_type = None validation.validate_unexpected_props(body, "body") # select item result = storage.select_item( req.context, table_name, indexed_condition_map, select_type=select_type, index_name=index_name, limit=limit, consistent=consistent_read, order_type=order_type, exclusive_start_key=exclusive_start_key_attributes ) # format response if select_type.type == models.SelectType.SELECT_TYPE_COUNT: response = { parser.Props.COUNT: result.count } else: response = { parser.Props.COUNT: result.count, parser.Props.ITEMS: [ parser.Parser.format_item_attributes(row) for row in result.items ] } if limit == result.count: response[parser.Props.LAST_EVALUATED_KEY] = ( parser.Parser.format_item_attributes( result.last_evaluated_key) ) return response
def create_table(self, req, body, project_id): utils.check_project_id(req.context, project_id) req.context.tenant = project_id with probe.Probe(__name__ + '.validate'): validation.validate_object(body, "body") table_name = body.pop(parser.Props.TABLE_NAME, None) validation.validate_table_name(table_name) # parse table attributes attribute_definitions_json = body.pop( parser.Props.ATTRIBUTE_DEFINITIONS, None ) validation.validate_list_of_objects( attribute_definitions_json, parser.Props.ATTRIBUTE_DEFINITIONS ) attribute_definitions = parser.Parser.parse_attribute_definitions( attribute_definitions_json ) # parse table key schema key_attrs_json = body.pop(parser.Props.KEY_SCHEMA, None) validation.validate_list(key_attrs_json, parser.Props.KEY_SCHEMA) key_attrs = parser.Parser.parse_key_schema(key_attrs_json) # parse table indexed field list lsi_defs_json = body.pop( parser.Props.LOCAL_SECONDARY_INDEXES, None ) if lsi_defs_json: validation.validate_list_of_objects( lsi_defs_json, parser.Props.LOCAL_SECONDARY_INDEXES ) index_def_map = parser.Parser.parse_local_secondary_indexes( lsi_defs_json ) else: index_def_map = {} validation.validate_unexpected_props(body, "body") # prepare table_schema structure table_schema = models.TableSchema( attribute_definitions, key_attrs, index_def_map) table_meta = storage.create_table( req.context, table_name, table_schema) url = req.path_url + "/" + table_name bookmark = req.path_url + "/" + table_name result = { parser.Props.TABLE_DESCRIPTION: { parser.Props.ATTRIBUTE_DEFINITIONS: ( parser.Parser.format_attribute_definitions( table_meta.schema.attribute_type_map ) ), parser.Props.CREATION_DATE_TIME: table_meta.creation_date_time, parser.Props.ITEM_COUNT: 0, parser.Props.KEY_SCHEMA: ( parser.Parser.format_key_schema( table_meta.schema.key_attributes ) ), parser.Props.TABLE_NAME: table_name, parser.Props.TABLE_STATUS: ( parser.Parser.format_table_status(table_meta.status) ), parser.Props.TABLE_SIZE_BYTES: 0, parser.Props.LINKS: [ { parser.Props.HREF: url, parser.Props.REL: parser.Values.SELF }, { parser.Props.HREF: bookmark, parser.Props.REL: parser.Values.BOOKMARK } ] } } if table_meta.schema.index_def_map: table_def = result[parser.Props.TABLE_DESCRIPTION] table_def[parser.Props.LOCAL_SECONDARY_INDEXES] = ( parser.Parser.format_local_secondary_indexes( table_meta.schema.key_attributes[0], table_meta.schema.index_def_map ) ) return result
def query(self, req, body, project_id, table_name): with probe.Probe(__name__ + '.validation'): validation.validate_object(body, "body") # get attributes_to_get attributes_to_get = body.pop(parser.Props.ATTRIBUTES_TO_GET, None) if attributes_to_get is not None: validation.validate_list(attributes_to_get, parser.Props.ATTRIBUTES_TO_GET) for attr_name in attributes_to_get: validation.validate_attr_name(attr_name) index_name = body.pop(parser.Props.INDEX_NAME, None) if index_name is not None: validation.validate_index_name(index_name) select = body.pop(parser.Props.SELECT, None) if select is None: if attributes_to_get: select = models.SelectType.SELECT_TYPE_SPECIFIC else: if index_name is not None: select = models.SelectType.SELECT_TYPE_ALL_PROJECTED else: select = models.SelectType.SELECT_TYPE_ALL else: validation.validate_string(select, parser.Props.SELECT) select_type = models.SelectType(select, attributes_to_get) # parse exclusive_start_key_attributes exclusive_start_key_attributes_json = body.pop( parser.Props.EXCLUSIVE_START_KEY, None) if exclusive_start_key_attributes_json is not None: validation.validate_object(exclusive_start_key_attributes_json, parser.Props.EXCLUSIVE_START_KEY) exclusive_start_key_attributes = ( parser.Parser.parse_item_attributes( exclusive_start_key_attributes_json)) else: exclusive_start_key_attributes = None # parse indexed_condition_map key_conditions = body.pop(parser.Props.KEY_CONDITIONS, None) validation.validate_object(key_conditions, parser.Props.KEY_CONDITIONS) indexed_condition_map = parser.Parser.parse_attribute_conditions( key_conditions, condition_class=IndexedCondition) # TODO(dukhlov): # it would be nice to validate given table_name, key_attributes and # attributes_to_get to schema expectation consistent_read = body.pop(parser.Props.CONSISTENT_READ, False) validation.validate_boolean(consistent_read, parser.Props.CONSISTENT_READ) limit = body.pop(parser.Props.LIMIT, None) if limit is not None: limit = validation.validate_integer(limit, parser.Props.LIMIT, min_val=0) scan_forward = body.pop(parser.Props.SCAN_INDEX_FORWARD, None) if scan_forward is not None: validation.validate_boolean(scan_forward, parser.Props.SCAN_INDEX_FORWARD) order_type = (models.ORDER_TYPE_ASC if scan_forward else models.ORDER_TYPE_DESC) else: order_type = None validation.validate_unexpected_props(body, "body") # select item result = storage.query( req.context, table_name, indexed_condition_map, select_type=select_type, index_name=index_name, limit=limit, consistent=consistent_read, order_type=order_type, exclusive_start_key=exclusive_start_key_attributes) # format response if select_type.type == models.SelectType.SELECT_TYPE_COUNT: response = {parser.Props.COUNT: result.count} else: response = { parser.Props.COUNT: result.count, parser.Props.ITEMS: [ parser.Parser.format_item_attributes(row) for row in result.items ] } if limit == result.count: response[parser.Props.LAST_EVALUATED_KEY] = ( parser.Parser.format_item_attributes( result.last_evaluated_key)) return response
def create_table(self, req, body, project_id): with probe.Probe(__name__ + '.validate'): validation.validate_object(body, "body") table_name = body.pop(parser.Props.TABLE_NAME, None) validation.validate_table_name(table_name) # parse table attributes attribute_definitions_json = body.pop( parser.Props.ATTRIBUTE_DEFINITIONS, None) validation.validate_list_of_objects( attribute_definitions_json, parser.Props.ATTRIBUTE_DEFINITIONS) attribute_definitions = parser.Parser.parse_attribute_definitions( attribute_definitions_json) # parse table key schema key_attrs_json = body.pop(parser.Props.KEY_SCHEMA, None) validation.validate_list(key_attrs_json, parser.Props.KEY_SCHEMA) key_attrs = parser.Parser.parse_key_schema(key_attrs_json) # parse table indexed field list lsi_defs_json = body.pop(parser.Props.LOCAL_SECONDARY_INDEXES, None) if lsi_defs_json: validation.validate_list_of_objects( lsi_defs_json, parser.Props.LOCAL_SECONDARY_INDEXES) index_def_map = parser.Parser.parse_local_secondary_indexes( lsi_defs_json) else: index_def_map = {} validation.validate_unexpected_props(body, "body") # prepare table_schema structure table_schema = models.TableSchema(attribute_definitions, key_attrs, index_def_map) table_meta = storage.create_table(req.context, table_name, table_schema) url = req.path_url + "/" + table_name bookmark = req.path_url + "/" + table_name result = { parser.Props.TABLE_DESCRIPTION: { parser.Props.ATTRIBUTE_DEFINITIONS: (parser.Parser.format_attribute_definitions( table_meta.schema.attribute_type_map)), parser.Props.CREATION_DATE_TIME: table_meta.creation_date_time, parser.Props.ITEM_COUNT: 0, parser.Props.KEY_SCHEMA: (parser.Parser.format_key_schema( table_meta.schema.key_attributes)), parser.Props.TABLE_ID: str(table_meta.id), parser.Props.TABLE_NAME: table_name, parser.Props.TABLE_STATUS: (parser.Parser.format_table_status(table_meta.status)), parser.Props.TABLE_SIZE_BYTES: 0, parser.Props.LINKS: [{ parser.Props.HREF: url, parser.Props.REL: parser.Values.SELF }, { parser.Props.HREF: bookmark, parser.Props.REL: parser.Values.BOOKMARK }] } } if table_meta.schema.index_def_map: table_def = result[parser.Props.TABLE_DESCRIPTION] table_def[parser.Props.LOCAL_SECONDARY_INDEXES] = ( parser.Parser.format_local_secondary_indexes( table_meta.schema.key_attributes[0], table_meta.schema.index_def_map)) return result
def create_table(self, req, body, project_id): with probe.Probe(__name__ + '.validate'): validation.validate_object(body, "body") table_name = body.pop(parser.Props.TABLE_NAME, None) validation.validate_table_name(table_name) # parse table attributes attribute_definitions_json = body.pop( parser.Props.ATTRIBUTE_DEFINITIONS, None) validation.validate_list_of_objects( attribute_definitions_json, parser.Props.ATTRIBUTE_DEFINITIONS) attribute_definitions = parser.Parser.parse_attribute_definitions( attribute_definitions_json) # parse table key schema key_attrs_json = body.pop(parser.Props.KEY_SCHEMA, None) validation.validate_list(key_attrs_json, parser.Props.KEY_SCHEMA) key_attrs = parser.Parser.parse_key_schema(key_attrs_json) # parse table indexed field list lsi_defs_json = body.pop(parser.Props.LOCAL_SECONDARY_INDEXES, None) if lsi_defs_json: validation.validate_list_of_objects( lsi_defs_json, parser.Props.LOCAL_SECONDARY_INDEXES) index_def_map = parser.Parser.parse_local_secondary_indexes( lsi_defs_json) else: index_def_map = {} # validate the uniqueness of table and its indices' key schema range_keys = [] if len(key_attrs) > 1: range_keys.append(key_attrs[1]) else: # table has hash type primary key if len(index_def_map) > 0: raise exception.ValidationError( _("Table without range key in primary key schema " "can not have indices")) for index in index_def_map.values(): range_keys.append(index.alt_range_key_attr) try: validation.validate_set(range_keys, "key_schema") except exception.ValidationError: raise exception.ValidationError( _("Table and its indices must have unique key schema")) validation.validate_unexpected_props(body, "body") # prepare table_schema structure table_schema = models.TableSchema(attribute_definitions, key_attrs, index_def_map) table_meta = storage.create_table(req.context, table_name, table_schema) url = req.path_url + "/" + table_name bookmark = req.path_url + "/" + table_name result = { parser.Props.TABLE_DESCRIPTION: { parser.Props.ATTRIBUTE_DEFINITIONS: (parser.Parser.format_attribute_definitions( table_meta.schema.attribute_type_map)), parser.Props.CREATION_DATE_TIME: table_meta.creation_date_time, parser.Props.ITEM_COUNT: 0, parser.Props.KEY_SCHEMA: (parser.Parser.format_key_schema( table_meta.schema.key_attributes)), parser.Props.TABLE_ID: str(table_meta.id), parser.Props.TABLE_NAME: table_name, parser.Props.TABLE_STATUS: (parser.Parser.format_table_status(table_meta.status)), parser.Props.TABLE_SIZE_BYTES: 0, parser.Props.LINKS: [{ parser.Props.HREF: url, parser.Props.REL: parser.Values.SELF }, { parser.Props.HREF: bookmark, parser.Props.REL: parser.Values.BOOKMARK }] } } if table_meta.schema.index_def_map: table_def = result[parser.Props.TABLE_DESCRIPTION] table_def[parser.Props.LOCAL_SECONDARY_INDEXES] = ( parser.Parser.format_local_secondary_indexes( table_meta.schema.key_attributes[0], table_meta.schema.index_def_map)) return result