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,
                                                                        {}, {})
Ejemplo n.º 4
0
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, {}
Ejemplo n.º 9
0
    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
Ejemplo n.º 10
0
    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