def queryItemsByKey(table: DynamoDBLowLevelTableClient, data: dict) -> Tuple[bool, Optional[dict], dict]: class RequestDataModel(BaseModel): keyValue: str fieldsPathElements: List[List[FieldPathElementItemModel]] paginationRecordsLimit: Optional[int] = None filterExpression: Optional[Any] = None request_data = RequestDataModel(**data) fields_path_elements: List[List[DatabasePathElement]] = [[ DatabasePathElement(element_key=item.elementKey, default_type=item.defaultType, custom_default_value=item.customDefaultValue) for item in path_elements ] for path_elements in request_data.fieldsPathElements] records_attributes, query_metadata = table.dynamodb_client.query_items_by_key( index_name=table.primary_index_name, key_value=request_data.keyValue, fields_path_elements=fields_path_elements, pagination_records_limit=request_data.paginationRecordsLimit, filter_expression=request_data.filterExpression) return True, { 'data': records_attributes, 'metadata': query_metadata.serialize() }, {}
def setUpdateMultipleDataElementsToMapWithDefaultInitialization( table: DynamoDBLowLevelTableClient, data: dict) -> Tuple[bool, Optional[dict], dict]: class RequestDataModel(BaseModel): keyValue: str fieldPathElements: List[FieldPathElementItemModel] value: Any returnOldValue: bool = False request_data = RequestDataModel(**data) field_path_elements: List[DatabasePathElement] = [ DatabasePathElement(element_key=item.elementKey, default_type=item.defaultType, custom_default_value=item.customDefaultValue) for item in request_data.fieldPathElements ] response: Optional[ Response] = table.dynamodb_client.set_update_data_element_to_map_with_default_initialization( index_name=table.primary_index_name, key_value=request_data.keyValue, field_path_elements=field_path_elements, return_old_value=request_data.returnOldValue, value=request_data.value, ) if response is None: return False, None, {} from StructNoSQL.clients_middlewares.dynamodb.backend.dynamodb_utils import DynamoDBUtils response_attributes: Optional[Dict[str, Any]] = ( DynamoDBUtils.dynamodb_to_python_higher_level(response.attributes) if response.attributes is not None else None) return True, response_attributes, {}
def getValuesInMultiplePathTarget( table: DynamoDBLowLevelTableClient, data: dict) -> Tuple[bool, Optional[dict], dict]: class RequestDataModel(BaseModel): keyValue: str fieldsPathElements: Dict[str, List[FieldPathElementItemModel]] request_data = RequestDataModel(**data) fields_path_elements: Dict[str, List[DatabasePathElement]] = { key: [ DatabasePathElement(element_key=item.elementKey, default_type=item.defaultType, custom_default_value=item.customDefaultValue) for item in path_elements_container ] for key, path_elements_container in request_data.fieldsPathElements.items() } response_data = table.dynamodb_client.get_values_in_multiple_path_target( index_name=table.primary_index_name, key_value=request_data.keyValue, fields_path_elements=fields_path_elements, metadata=False) return (True, response_data, {}) if response_data is not None else (False, {}, {})
def make_rendered_database_path( database_path_elements: List[DatabasePathElement], query_kwargs: dict) -> List[DatabasePathElement]: output_database_path_elements: List[DatabasePathElement] = [] for path_element in database_path_elements: if "$key$:" not in path_element.element_key: # If the path_element do not contains a key that need to be modified, we can use the current # instance of the path element, since it will not be modified, and so will not cause issue # when other invocations of queries and operations will use the same path element instance. output_database_path_elements.append(path_element) else: variable_name = path_element.element_key.replace('$key$:', '') if query_kwargs is not None: matching_kwarg: Optional[Any] = query_kwargs.get( variable_name, None) if matching_kwarg is not None: # If the key of the path_element needs to be modified, we do not modify the existing path element, # but we create a new instance of path element. Since the database_path_elements variable is retrieved # using the static _database_path variable, the path elements in database_path_elements needs to # remained unmodified, so that other invocations of queries and operations will be able to have # cleans element keys that will properly be filled with the query_kwargs specified in the request. output_database_path_elements.append( DatabasePathElement( element_key=matching_kwarg, default_type=path_element.default_type, custom_default_value=path_element. custom_default_value)) else: raise MissingQueryKwarg( message_with_vars( message= "A variable was required but not found in the query_kwargs dict passed to the make_rendered_database_path function.", vars_dict={ "keyVariableName": variable_name, "matchingKwarg": matching_kwarg, "queryKwargs": query_kwargs, "databasePathElements": database_path_elements })) else: raise Exception( message_with_vars( message= "A variable was required but no query_kwargs have been passed to the make_rendered_database_path function.", vars_dict={ "keyVariableName": variable_name, "queryKwargs": query_kwargs, "databasePathElements": database_path_elements })) return output_database_path_elements
def getOrQuerySingleItem(table: DynamoDBLowLevelTableClient, data: dict) -> Tuple[bool, Optional[dict], dict]: class RequestDataModel(BaseModel): keyValue: str fieldsPathElements: List[List[FieldPathElementItemModel]] request_data = RequestDataModel(**data) fields_path_elements: List[List[DatabasePathElement]] = [[ DatabasePathElement(element_key=item.elementKey, default_type=item.defaultType, custom_default_value=item.customDefaultValue) for item in path_elements_container ] for path_elements_container in request_data.fieldsPathElements] response_data = table.dynamodb_client.get_or_query_single_item( index_name=table.primary_index_name, key_value=request_data.keyValue, fields_path_elements=fields_path_elements) return True, response_data, {}
def getSingleValueInPathTarget( table: DynamoDBLowLevelTableClient, data: dict) -> Tuple[bool, Optional[dict], dict]: class RequestDataModel(BaseModel): keyValue: str fieldPathElements: List[FieldPathElementItemModel] request_data = RequestDataModel(**data) field_path_elements: List[DatabasePathElement] = [ DatabasePathElement(element_key=item.elementKey, default_type=item.defaultType, custom_default_value=item.customDefaultValue) for item in request_data.fieldPathElements ] response_data = table.dynamodb_client.get_value_in_path_target( index_name=table.primary_index_name, key_value=request_data.keyValue, field_path_elements=field_path_elements) return True, response_data, {}
def deleteDataElementsFromMap(table: DynamoDBLowLevelTableClient, data: dict) -> Tuple[bool, Optional[dict], dict]: class RequestDataModel(BaseModel): keyValue: str fieldsPathElements: List[List[FieldPathElementItemModel]] request_data = RequestDataModel(**data) fields_path_elements: List[List[DatabasePathElement]] = [[ DatabasePathElement(element_key=item.elementKey, default_type=item.defaultType, custom_default_value=item.customDefaultValue) for item in path_elements_container ] for path_elements_container in request_data.fieldsPathElements] response_data = table.dynamodb_client.remove_data_elements_from_map( index_name=table.primary_index_name, key_value=request_data.keyValue, targets_path_elements=fields_path_elements, retrieve_removed_elements=False) return True if response_data is not None else False, {}, {}
def setUpdateMultipleDataElementsToMap( table: DynamoDBLowLevelTableClient, data: dict) -> Tuple[bool, Optional[dict], dict]: class RequestDataModel(BaseModel): keyValue: str class SetterItemModel(BaseModel): valueToSet: Any fieldPathElements: List[FieldPathElementItemModel] setters: List[SetterItemModel] returnOldValues: bool = False request_data = RequestDataModel(**data) setters: List[FieldPathSetter] = [ FieldPathSetter(value_to_set=setter_item.valueToSet, field_path_elements=[ DatabasePathElement( element_key=item.elementKey, default_type=item.defaultType, custom_default_value=item.customDefaultValue) for item in setter_item.fieldPathElements ]) for setter_item in request_data.setters ] response: Optional[ Response] = table.dynamodb_client.set_update_multiple_data_elements_to_map( index_name=table.primary_index_name, key_value=request_data.keyValue, setters=setters, return_old_values=request_data.returnOldValues) if response is None: return False, None, {} from StructNoSQL.clients_middlewares.dynamodb.backend.dynamodb_utils import DynamoDBUtils response_attributes: Optional[dict] = ( DynamoDBUtils.dynamodb_to_python_higher_level(response.attributes) if response.attributes is not None else None) return True, response_attributes, {}
def __init__(self, parent_field: BaseField, model_type: type, field_type: type): super().__init__( field_type=field_type, custom_default_value=BaseItem.instantiate_default_value_type( field_type)) self.map_model = model_type self._key_name = parent_field.key_name # The _key_name will be initialized by the call to the super().__init__, but since a MapItem is special and does # not include a name, the key_name that the BaseField will create will be invalid. For MapItem's, we just want # to re-use the key_name of the parent_field (which will have been already prepared and processed in cases of # nested recursive fields), and override the existing _key_name value. element_key = make_dict_key_var_name(parent_field.key_name) default_type = try_to_get_primitive_default_type_of_item( parent_field.items_excepted_type) database_path_element = DatabasePathElement(element_key=element_key, default_type=default_type) self._database_path = [ *parent_field.database_path, database_path_element ] self._table = parent_field.table
def process_item(self, item_key_name: Optional[str], class_type: Optional[type], variable_item: Any, current_field_path: str, current_path_elements: Optional[ List[DatabasePathElement]] = None, is_nested: bool = False) -> list: required_fields = [] if current_path_elements is None: current_path_elements = [] field_is_valid: bool = False try: if isinstance(variable_item, DictModel): variable_item: DictModel """new_database_path_element = DatabasePathElement( element_key=variable_item.key_name, default_type=variable_item.item_type )""" variable_item._database_path = [ *current_path_elements ] #, new_database_path_element] variable_item._table = self.table """if variable_item.required is True: required_fields.append(variable_item)""" current_field_path += ( "" if len(current_field_path) == 0 else ".") + "{{" + variable_item.key_name + "}}" field_is_valid = self.table.fields_switch.set( key=current_field_path, item=copy(variable_item)) elif MapModel in getattr(variable_item, '__mro__', ()): if len(current_path_elements) > 0: self.assign_internal_mapping_from_class( class_type=variable_item, nested_field_path=current_field_path, current_path_elements=[*current_path_elements]) elif isinstance(variable_item, BaseField): variable_item: BaseField if item_key_name is not None and variable_item.field_name is None: variable_item.field_name = item_key_name new_database_path_element = DatabasePathElement( element_key=variable_item.field_name, default_type=variable_item.default_field_type, custom_default_value=variable_item.custom_default_value) variable_item._database_path = [ *current_path_elements, new_database_path_element ] variable_item._table = self.table if variable_item.required is True: required_fields.append(variable_item) current_field_path += f"{variable_item.field_name}" if len( current_field_path ) == 0 else f".{variable_item.field_name}" field_is_valid = self.table.fields_switch.set( key=current_field_path, item=copy(variable_item)) if variable_item.key_name is not None: if "{i}" not in variable_item.key_name: # The current_field_path concat is being handled lower in the code for the nested fields current_field_path += ".{{" + variable_item.key_name + "}}" if field_is_valid is True: if variable_item.map_model is not None: self.assign_internal_mapping_from_class( class_type=variable_item.map_model, nested_field_path=current_field_path, current_path_elements=[*variable_item.database_path]) if variable_item.items_excepted_type is not None: from StructNoSQL import ActiveSelf if variable_item.items_excepted_type is ActiveSelf: if class_type is None: raise Exception( message_with_vars( message= "Cannot use the ActiveSelf attribute as the items_excepted_type when the class type is None", vars_dict={ 'field_name': variable_item.field_name })) variable_item._items_excepted_type = class_type item_default_type = try_to_get_primitive_default_type_of_item( item_type=variable_item.items_excepted_type) item_key_name = make_dict_key_var_name( variable_item.key_name) if "{i}" in variable_item.key_name: if is_nested is not True: current_nested_field_path = "" if current_field_path is None else current_field_path current_nested_database_path = [ *variable_item.database_path ] for i in range(variable_item.max_nested): if len(current_nested_database_path) > 32: print( message_with_vars( message= "Imposed a max nested database depth on field missing or with a too high nested depth limit.", vars_dict={ 'current_field_path': current_field_path, 'field_name': variable_item.field_name, 'imposedMaxNestedDepth': i })) break else: nested_variable_item = variable_item.copy() item_rendered_key_name: str = nested_variable_item.key_name.replace( "{i}", f"{i}") nested_variable_item._database_path = [ *current_nested_database_path ] nested_variable_item._key_name = item_rendered_key_name # We create a copy of the variable_item unpon which we render the key_name and add # the appropriate database_path_elements into to prepare the creation of the MapItem. map_item = MapItem( parent_field=nested_variable_item, field_type=nested_variable_item. default_field_type, model_type=nested_variable_item. items_excepted_type) # The MapItem will retrieve the key_name of its parent_field when initialized. # Hence, it is important to do the modifications on the nested_variable_item # before the initialization of the MapItem. if i > 0: current_nested_field_path += f".{variable_item.field_name}" current_nested_field_path += ".{{" + map_item.key_name + "}}" current_nested_database_path.append( DatabasePathElement( element_key=make_dict_key_var_name( map_item.key_name), default_type=nested_variable_item. default_field_type, custom_default_value= nested_variable_item. custom_default_value)) field_is_valid = self.table.fields_switch.set( key=current_nested_field_path, item=map_item) if field_is_valid is True: if variable_item.items_excepted_type not in PRIMITIVE_TYPES: self.assign_internal_mapping_from_class( class_type=variable_item. items_excepted_type, nested_field_path= current_nested_field_path, current_path_elements=[ *current_nested_database_path ], is_nested=True) current_nested_database_path.append( DatabasePathElement( element_key=nested_variable_item. field_name, default_type=nested_variable_item. default_field_type, custom_default_value= nested_variable_item. custom_default_value)) else: map_item = MapItem( parent_field=variable_item, field_type=item_default_type, model_type=variable_item.items_excepted_type) field_is_valid = self.table.fields_switch.set( current_field_path, map_item) if field_is_valid is True: items_excepted_type = variable_item.items_excepted_type if items_excepted_type not in PRIMITIVE_TYPES: new_database_dict_item_path_element = DatabasePathElement( element_key=item_key_name, default_type=item_default_type) current_path_elements = [ *variable_item.database_path, new_database_dict_item_path_element ] if isinstance(items_excepted_type, DictModel): if items_excepted_type.key_name is None: # If the key_name of a DictModel is not defined (for example, when a nested typed Dict is converted # to a DictModel) we set its key to the key of its parent plus the child keyword. So, a parent key # of itemKey will give itemKeyChild, and a parent of itemKeyChild will give itemKeyChildChild. items_excepted_type.key_name = f"{variable_item.key_name}Child" self.process_item( class_type=None, item_key_name=None, variable_item=variable_item. items_excepted_type, current_field_path=current_field_path, current_path_elements=current_path_elements ) self.assign_internal_mapping_from_class( class_type=variable_item. items_excepted_type, nested_field_path=current_field_path, current_path_elements=current_path_elements ) except Exception as e: print(e) return required_fields