File size: 3,158 Bytes
8ba64a4
 
 
 
 
 
 
 
 
 
9645c29
e85027d
8ba64a4
 
 
 
 
 
 
 
 
e85027d
8ba64a4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9645c29
 
e85027d
 
 
 
 
8ba64a4
 
 
 
 
 
e85027d
 
 
 
 
 
 
 
8ba64a4
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
from enum import Enum  # do not remove this import for exec
from typing import List  # do not remove this import for exec
from typing import Any, Dict

import jsonschema
from jsf import JSF
from pydantic import BaseModel, Field  # do not remove this import for exec

from app.core.errors import VendorError
from app.schemas.requests import Attribute
from app.utils.converter import to_snake_case
from app.utils.logger import exception_to_str


def validate_json_data(data: Dict[str, Any], schema: Dict[str, Any]):
    """
    Standalone JSON schema validation utility
    """
    try:
        jsonschema.validate(instance=data, schema=schema)
    except jsonschema.ValidationError as e:
        raise VendorError(f"Vendor generated invalid data {exception_to_str(e)}")


def validate_json_schema(schema: Dict[str, Any]):
    """
    Standalone JSON schema validation utility
    """
    if schema == {}:
        raise ValueError(f"JSON Schema validation failed")

    try:
        faker = JSF(schema)
        _ = faker.generate()
    except:
        raise ValueError(f"JSON Schema validation failed")


SUPPORTED_DATA_TYPE = [
    "string",
    "int",
    "float",
    "bool",
    "list[string]",
    "list[int]",
    "list[float]",
    "list[bool]",
]


def convert_attribute_to_model(attributes: Dict[str, Attribute]) -> Dict[str, Any]:
    import_code = ""
    enum_code_list = []
    master_class_code = "class Product(BaseModel):\n"
    for key, value in attributes.items():
        description = value.description
        data_type = value.data_type
        allowed_values = value.allowed_values
        is_list = False

        if data_type not in SUPPORTED_DATA_TYPE:
            raise ValueError(f"Data type {data_type} is not supported")

        if "list" in data_type:
            is_list = True

        if "int" in data_type:
            data_type = "int"
        elif "float" in data_type:
            data_type = "float"
        elif "bool" in data_type:
            data_type = "bool"
        elif "string" in data_type:
            data_type = "str"

        if len(allowed_values) > 0:
            enum_code = f"class {key.capitalize()}Enum(str, Enum):\n"
            for i, allowed_value in enumerate(allowed_values):
                enum_name = f'{to_snake_case(allowed_value).upper()}_{i}'

                if "'" in allowed_value:
                    enum_code += f'    E{enum_name} = "{allowed_value}"\n'
                else:
                    enum_code += f"    E{enum_name} = '{allowed_value}'\n"
            enum_code_list.append(enum_code)
            data_type = f"{key.capitalize()}Enum"

        if is_list:
            data_type = f"List[{data_type}]"

        if "'" in description:
            master_class_code += (
                f'    {key}: {data_type} = Field(..., description="{description}")\n'
            )
        else:
            master_class_code += (
                f"    {key}: {data_type} = Field(..., description='{description}')\n"
            )

    entire_code = import_code + "\n".join(enum_code_list) + "\n" + master_class_code
    exec(entire_code, globals())

    return Product  # type: ignore