Passed
Push — master ( e3895d...c60dd0 )
by torrua
01:19
created

app.api.views.universal_get()   A

Complexity

Conditions 4

Size

Total Lines 33
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 19
dl 0
loc 33
rs 9.45
c 0
b 0
f 0
cc 4
nop 4
1
import os
2
3
from flask import request, Blueprint, Response, json
4
from loglan_core.addons.key_selector import KeySelector
5
from loglan_core.addons.word_selector import WordSelector
6
from sqlalchemy import select
7
8
from app.api.schemas.author import blue_print_export as bp_author
9
from app.api.schemas.definition import blue_print_export as bp_definition
10
from app.api.schemas.event import blue_print_export as bp_event
11
from app.api.schemas.key import blue_print_export as bp_key
12
from app.api.schemas.setting import blue_print_export as bp_setting
13
from app.api.schemas.syllable import blue_print_export as bp_syllable
14
from app.api.schemas.type import blue_print_export as bp_type
15
from app.api.schemas.word import blue_print_export as bp_word
16
from app.engine import Session
17
18
API_PATH = os.getenv("API_PATH", "/api")
19
API_VERSION = os.getenv("API_VERSION", "/v1")
20
21
22
def universal_get(schema_full, schema_nested, model, many: bool = True):
23
    """
24
    Return entity from DB through GET request
25
    :param schema_full:
26
    :param schema_nested:
27
    :param model:
28
    :param many:
29
    :return:
30
    """
31
    args = {**request.args}
32
33
    detailed = arg2bool(args.pop("detailed", False))
34
    statement, skipped_args = get_statement(model, args)
35
36
    with Session() as app_session:
37
        result = app_session.execute(statement)
38
        model_entities = result.scalars().all() if many else [result.scalar()]
39
40
        count = len(model_entities)
41
        schema = schema_full if detailed else schema_nested
42
        data = schema.dump(model_entities, many=many)
43
44
    return Response(
45
        mimetype="application/json",
46
        response=json.dumps(
47
            {
48
                "result": True,
49
                "data": data,
50
                "count": count,
51
                "skipped_arguments": skipped_args,
52
            }
53
        ),
54
        status=200,
55
    )
56
57
58
def get_statement(model, args):
59
    event_id = args.pop("event_id", None)
60
    case_sensitive = arg2bool(args.pop("case_sensitive", False))
61
    model_args, skipped_args = separate_arguments(model, args)
62
    statement = filter_statement_by_event_id(model, event_id)
63
64
    if model_args:
65
        for attr, value in model_args.items():
66
            if str(value).isdigit():
67
                value = int(value)
68
                statement = statement.filter(getattr(model, attr) == value)
69
                continue
70
71
            value = value.replace("*", "%")
72
            name_attr = getattr(model, attr)
73
            name_filter = (
74
                name_attr.like(value) if case_sensitive else name_attr.ilike(value)
75
            )
76
77
            statement = statement.filter(name_filter)
78
79
    return statement, skipped_args
80
81
82
def arg2bool(arg) -> bool:
83
    return True if str(arg).lower() == "true" else False
84
85
86
def filter_statement_by_event_id(model, event_id):
87
    api_section = request.path.strip("/").split("/")[-1]
88
    if event_id:
89
        if api_section == "words":
90
            return WordSelector().by_event(event_id=int(event_id))
91
        if api_section == "keys":
92
            return KeySelector().by_event(event_id=int(event_id))
93
    return select(model)
94
95
96
def separate_arguments(model, args):
97
    skipped_args = {}
98
    model_args = {}
99
    for parameter, value in args.items():
100
        if parameter in model.attributes_all():
101
            model_args[parameter] = value
102
        else:
103
            skipped_args[parameter] = value
104
    return model_args, skipped_args
105
106
107
def get_api_properties(entity):
108
    entity_name = entity.__tablename__.lower().removesuffix("s")
109
    section_name = f"/{entity_name}s"
110
    api_name = f"{entity_name}_api"
111
    blueprint = Blueprint(api_name, __name__)
112
    data = (blueprint, section_name)
113
    return blueprint, data
114
115
116
def create_blueprint_data(entity, schema_nested, schema_full):
117
    api_blueprint, api_data = get_api_properties(entity)
118
119
    @api_blueprint.route("/", methods=["GET"])
120
    def entity_get():
121
        """
122
        Get Entity by Entity's parameters Function
123
        """
124
        return universal_get(schema_full, schema_nested, entity)
125
126
    return api_data
127
128
129
dictionary_bp_data = [
130
    bp_author,
131
    bp_definition,
132
    bp_event,
133
    bp_key,
134
    bp_setting,
135
    bp_syllable,
136
    bp_type,
137
    bp_word,
138
]
139
140
dictionary_api_data = [create_blueprint_data(*data) for data in dictionary_bp_data]
141
142
blueprints = [
143
    {"blueprint": api[0], "url_prefix": f"{API_PATH}{API_VERSION}{api[1]}"}
144
    for api in dictionary_api_data
145
]
146