dapper-sqls 0.9.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,63 @@
1
+ # -*- coding: latin -*-
2
+ from functools import wraps
3
+ import asyncio
4
+ from time import perf_counter
5
+ from typing import Callable
6
+
7
+ def func_validation(callable_msg_error: Callable = None, use_raise: bool = False, use_log: bool = True):
8
+ """
9
+ Synchronous function decorator for validation, error handling, and logging execution time.
10
+ """
11
+ def decorator(func):
12
+ @wraps(func)
13
+ def wrapper(*args, **kwargs):
14
+ if use_log:
15
+ start = perf_counter()
16
+ try:
17
+ return func(*args, **kwargs)
18
+ except Exception as e:
19
+ error_message = str(e)
20
+ if error_message == "Database unavailable":
21
+ if callable_msg_error:
22
+ callable_msg_error("Service temporarily unavailable. Please try again later.")
23
+ else:
24
+ if use_raise:
25
+ raise
26
+ else:
27
+ print(f"Unhandled exception in '{func.__name__}': {error_message}")
28
+ finally:
29
+ if use_log:
30
+ stop = perf_counter()
31
+ execution_time = round(stop - start, 3)
32
+ print(f"The function '{func.__name__}' executed in {execution_time} seconds.")
33
+ return wrapper
34
+ return decorator
35
+
36
+ def async_func_validation(callable_msg_error: Callable = None, use_raise: bool = False, use_log: bool = True):
37
+ """
38
+ Asynchronous function decorator for validation, error handling, and logging execution time.
39
+ """
40
+ def decorator(func):
41
+ @wraps(func)
42
+ async def wrapper(*args, **kwargs):
43
+ if use_log:
44
+ start = perf_counter()
45
+ try:
46
+ return await asyncio.create_task(func(*args, **kwargs))
47
+ except Exception as e:
48
+ error_message = str(e)
49
+ if error_message == "Database unavailable":
50
+ if callable_msg_error:
51
+ callable_msg_error("Service temporarily unavailable. Please try again later.")
52
+ else:
53
+ if use_raise:
54
+ raise
55
+ else:
56
+ print(f"Unhandled exception in async function '{func.__name__}': {error_message}")
57
+ finally:
58
+ if use_log:
59
+ stop = perf_counter()
60
+ execution_time = round(stop - start, 3)
61
+ print(f"The async function '{func.__name__}' executed in {execution_time} seconds.")
62
+ return wrapper
63
+ return decorator
@@ -0,0 +1,8 @@
1
+ from .http import UnavailableServiceException
2
+ from .result import Result
3
+ from .connection import ConnectionStringData
4
+ from .base import TableBaseModel, BaseUpdate
5
+
6
+
7
+
8
+
@@ -0,0 +1,35 @@
1
+ from pydantic import BaseModel, BaseConfig
2
+ from abc import ABC
3
+ from abc import ABC, abstractmethod
4
+ from .result import Result
5
+
6
+ class TableBaseModel(BaseModel, ABC):
7
+ class Config(BaseConfig):
8
+ from_attributes = True
9
+
10
+ _TABLE_NAME: str = ''
11
+
12
+ @property
13
+ def TABLE_NAME(cls) -> str:
14
+ return cls._TABLE_NAME
15
+
16
+ class BaseUpdate(ABC):
17
+
18
+ def __init__(self, executor , model):
19
+ self._set_data = model
20
+ self._executor = executor
21
+
22
+ @property
23
+ def set_data(self):
24
+ return self._set_data
25
+
26
+ @property
27
+ def executor(self):
28
+ return self._executor
29
+
30
+ @abstractmethod
31
+ def where(self, *args) -> Result.Send:
32
+ pass
33
+
34
+
35
+
@@ -0,0 +1,60 @@
1
+ # -*- coding: latin -*-
2
+
3
+ class ConnectionStringData(object):
4
+ def __init__(self, server: str, database: str, username: str, password: str):
5
+ self._server = server
6
+ self._database = database
7
+ self._username = username
8
+ self._password = password
9
+
10
+ @property
11
+ def server(self) -> str:
12
+ return self._server
13
+
14
+ @server.setter
15
+ def server(self, value: str):
16
+ if not isinstance(value, str):
17
+ raise ValueError("O valor do servidor deve ser uma string.")
18
+ self._server = value
19
+
20
+ @property
21
+ def database(self) -> str:
22
+ return self._database
23
+
24
+ @database.setter
25
+ def database(self, value: str):
26
+ if not isinstance(value, str):
27
+ raise ValueError("O nome do banco de dados deve ser uma string.")
28
+ self._database = value
29
+
30
+ @property
31
+ def username(self) -> str:
32
+ return self._username
33
+
34
+ @username.setter
35
+ def username(self, value: str):
36
+ if not isinstance(value, str):
37
+ raise ValueError("O nome de usu�rio deve ser uma string.")
38
+ self._username = value
39
+
40
+ @property
41
+ def password(self) -> str:
42
+ return self._password
43
+
44
+ @password.setter
45
+ def password(self, value: str):
46
+ if not isinstance(value, str):
47
+ raise ValueError("A senha deve ser uma string.")
48
+ self._password = value
49
+
50
+ def get(self, server : str , database : str, username : str, password : str):
51
+ self.server = server
52
+ self.database = database
53
+ self.username = username
54
+ self.password = password
55
+
56
+ def get(self):
57
+ return ConnectionStringData(self.server, self.database, self.username, self.password)
58
+
59
+
60
+
@@ -0,0 +1,10 @@
1
+ class UnavailableServiceException(Exception):
2
+ def __init__(self, message="Database unavailable", code="DatabaseUnavailable", exception_type="Database", status_code=503):
3
+ self.message = message
4
+ self.code = code
5
+ self.type = exception_type
6
+ self.status_code = status_code
7
+ super().__init__(self.message)
8
+
9
+
10
+
@@ -0,0 +1,123 @@
1
+ # -*- coding: latin -*-
2
+
3
+ def result_dict(cursor, result):
4
+ return dict(
5
+ zip(
6
+ [column[0] for column in cursor.description],
7
+ result
8
+ )
9
+ )
10
+
11
+ class Result(object):
12
+
13
+ class Fetchone(object):
14
+ def __init__(self, cursor, result, status_code = 200, message : str = ""):
15
+ self._status_code = status_code
16
+ self._message = message
17
+ if result:
18
+ self._success = True
19
+ self._list = result
20
+ self._dict = dict(zip([column[0] for column in cursor.description], result))
21
+ else:
22
+ self._success = False
23
+ self._list = []
24
+ self._dict = {}
25
+
26
+ @property
27
+ def status_code(self):
28
+ return self._status_code
29
+
30
+ @property
31
+ def list(self):
32
+ return self._list
33
+
34
+ @property
35
+ def dict(self):
36
+ return self._dict
37
+
38
+ @property
39
+ def success(self):
40
+ return self._success
41
+
42
+ @property
43
+ def message(self):
44
+ return self._message
45
+
46
+
47
+ class Fetchall:
48
+
49
+ def __init__(self, cursor, result, status_code = 200, message : str = ""):
50
+ self._status_code = status_code
51
+ self._message = message
52
+ if result:
53
+ self._success = True
54
+ self._list_dict = []
55
+ for r in result:
56
+ self._list_dict.append(dict(zip([column[0] for column in cursor.description], r)))
57
+ else:
58
+ self._success = False
59
+ self._list_dict = []
60
+
61
+ @property
62
+ def status_code(self):
63
+ return self._status_code
64
+
65
+ @property
66
+ def list_dict(self):
67
+ return self._list_dict
68
+
69
+ @property
70
+ def dict(self):
71
+ return self._dict
72
+
73
+ @property
74
+ def success(self):
75
+ return self._success
76
+
77
+ @property
78
+ def message(self):
79
+ return self._message
80
+
81
+ class Insert:
82
+ def __init__(self, result : int | str, status_code = 200, message : str = ""):
83
+ self._id = result
84
+ self._status_code = status_code
85
+ self._success = bool(result)
86
+ self._message = message
87
+
88
+ @property
89
+ def id(self):
90
+ return self._id
91
+
92
+ @property
93
+ def status_code(self):
94
+ return self._status_code
95
+
96
+ @property
97
+ def success(self):
98
+ return self._success
99
+
100
+ @property
101
+ def message(self):
102
+ return self._message
103
+
104
+ class Send:
105
+ def __init__(self, result : bool, status_code = 200, message : str = ""):
106
+ self._status_code = status_code
107
+ self._success = result
108
+ self._message = message
109
+
110
+ @property
111
+ def status_code(self):
112
+ return self._status_code
113
+
114
+ @property
115
+ def success(self):
116
+ return self._success
117
+
118
+ @property
119
+ def message(self):
120
+ return self._message
121
+
122
+
123
+
@@ -0,0 +1,4 @@
1
+ from .local_database import LocalDatabase
2
+
3
+
4
+
@@ -0,0 +1,268 @@
1
+ # -*- coding: latin -*-
2
+
3
+ from sqlalchemy import create_engine, inspect, text, insert,MetaData, Table, Integer, Column, String, delete, update
4
+ from sqlalchemy.engine import Engine
5
+ from tempfile import gettempdir
6
+ from os import path, makedirs
7
+ from .models import Path, System ,EnvVar
8
+ import re
9
+
10
+ #C:\Users\Samuel\AppData\Local\Temp
11
+
12
+
13
+ def is_valid_name(name, max_length=255):
14
+ # Verifica se o nome n�o � vazio
15
+ if not name:
16
+ return False
17
+
18
+ # Verifica se o nome n�o excede o comprimento m�ximo permitido
19
+ if len(name) > max_length:
20
+ return False
21
+
22
+ # Verifica se o nome n�o cont�m caracteres inv�lidos
23
+ # Neste exemplo, permitimos apenas letras, n�meros, espa�os e underscore (_)
24
+ if not re.match(r'^[\w\s]+$', name):
25
+ return False
26
+
27
+ return True
28
+
29
+ class LocalDatabase(object):
30
+
31
+ class Tables(object):
32
+
33
+ meta_data = MetaData()
34
+
35
+ system = Table(
36
+ 'system', # Nome da tabela
37
+ meta_data,
38
+ Column('id', Integer, primary_key=True),
39
+ Column('App', String),
40
+ Column('Tema', String)
41
+ )
42
+
43
+ env_var = Table(
44
+ 'env_var',
45
+ meta_data,
46
+ Column('id', Integer, primary_key=True),
47
+ Column('App', String),
48
+ Column('Name', String),
49
+ Column('Value', String)
50
+ )
51
+
52
+ path = Table(
53
+ 'path',
54
+ meta_data,
55
+ Column('id', Integer, primary_key=True),
56
+ Column('App', String),
57
+ Column('Name', String),
58
+ Column('Path', String)
59
+ )
60
+
61
+
62
+ def __init__(self, app_name : str, *, path_local_database = gettempdir(), database_name="saftOnlineLocalDatabase", database_folder_name = "SaftOnline"):
63
+ app_name = self.get_value(app_name)
64
+ if not database_name.endswith('.db'):
65
+ database_name = f'{database_name}.db'
66
+ if not is_valid_name(app_name):
67
+ raise Exception("Nome de identifica��o do programa � inv�lido")
68
+ self._app_name = app_name
69
+ self._path_database = path.join(path_local_database,database_folder_name, database_name)
70
+ self._engine : Engine = None
71
+
72
+ if not path.isfile(self._path_database):
73
+ if not path.exists(path.join(path_local_database,database_folder_name)):
74
+ makedirs(path.join(path_local_database,database_folder_name))
75
+
76
+ # Se o banco de dados n�o existe, crie-o e crie a tabela
77
+ conn = self.engine.connect()
78
+
79
+ self.Tables.meta_data.create_all(self.engine)
80
+
81
+ ins = insert(self.Tables.system).values(App=app_name, Tema='light')
82
+ conn.execute(ins)
83
+ conn.commit()
84
+ conn.close()
85
+
86
+ else:
87
+ if not self.are_tables_existing(self.engine):
88
+ try:
89
+ self.Tables.meta_data.create_all(self.engine)
90
+ ...
91
+ except:
92
+ ...
93
+ else:
94
+ try:
95
+ self.synchronize_columns(self.engine)
96
+ except:
97
+ ...
98
+
99
+
100
+ @property
101
+ def engine(self):
102
+ if not self._engine:
103
+ self._engine = create_engine(f'sqlite:///{self.path_database}')
104
+ return self._engine
105
+
106
+ @property
107
+ def app_name(self):
108
+ return self._app_name
109
+
110
+ @property
111
+ def path_database(self):
112
+ return self._path_database
113
+
114
+ def are_columns_existing(self, engine):
115
+ inspector = inspect(engine)
116
+ existing_tables = inspector.get_table_names()
117
+ required_tables = self.Tables.meta_data.tables.keys()
118
+
119
+ for table_name in required_tables:
120
+ if table_name in existing_tables:
121
+ # Get the columns in the existing table
122
+ existing_columns = inspector.get_columns(table_name)
123
+ existing_column_names = [column['name'] for column in existing_columns]
124
+
125
+ # Get the columns defined in the Table class
126
+ required_columns = self.Tables.meta_data.tables[table_name].c.keys()
127
+
128
+ if not all(column in existing_column_names for column in required_columns):
129
+ return False
130
+ else:
131
+ return False
132
+ return True
133
+
134
+ def are_tables_existing(self, engine):
135
+ inspector = inspect(engine)
136
+ existing_tables = inspector.get_table_names()
137
+ required_tables = self.Tables.meta_data.tables.keys()
138
+
139
+ return all(table in existing_tables for table in required_tables)
140
+
141
+ def synchronize_columns(self, engine):
142
+ inspector = inspect(engine)
143
+ existing_tables = inspector.get_table_names()
144
+
145
+ for table_name in self.Tables.meta_data.tables.keys():
146
+ if table_name in existing_tables:
147
+ # Get the columns in the existing table
148
+ existing_columns = inspector.get_columns(table_name)
149
+ existing_column_names = [column['name'] for column in existing_columns]
150
+
151
+ # Get the columns defined in the Table class
152
+ required_columns = self.Tables.meta_data.tables[table_name].c.keys()
153
+ required_column_defs = {col.name: col for col in self.Tables.meta_data.tables[table_name].columns}
154
+
155
+ # Add columns in lack
156
+ for column in required_columns:
157
+ if column not in existing_column_names:
158
+ column_type = required_column_defs[column].type
159
+ add_column_sql = f'ALTER TABLE {table_name} ADD COLUMN {column} {column_type}'
160
+ with engine.connect() as conn:
161
+ conn.execute(text(add_column_sql))
162
+
163
+ def get_value(self, value):
164
+ try :
165
+ return value.value
166
+ except:
167
+ return value
168
+
169
+ def select(self, table : str, where : str = None):
170
+ with self.engine.connect() as conn:
171
+ if where:
172
+ query = conn.execute(text(f"select * from {table} where App = '{self.app_name}' and {where}"))
173
+ else:
174
+ query = conn.execute(text(f"select * from {table} where App = '{self.app_name}'"))
175
+ data = [dict(zip(tuple(query.keys()), i)) for i in query.cursor]
176
+ return data
177
+
178
+
179
+ def get_path(self, name):
180
+ name = self.get_value(name)
181
+ data = self.select('path', f"Name = '{name}'")
182
+ for d in data:
183
+ return Path(d).Path
184
+
185
+ def update_path(self, name : str, path_name : str):
186
+ name = self.get_value(name)
187
+ path_name = self.get_value(path_name)
188
+ existsPath = self.get_path(name)
189
+
190
+ with self.engine.connect() as conn:
191
+ if existsPath != None:
192
+ stmt = update(self.Tables.path).where(
193
+ (self.Tables.path.c.Name == name) &
194
+ (self.Tables.path.c.App == self.app_name)
195
+ ).values(Path=path_name)
196
+ conn.execute(stmt)
197
+ else:
198
+ ins = insert(self.Tables.path).values(App=self.app_name, Name=name, Path=path_name)
199
+ conn.execute(ins)
200
+ conn.commit()
201
+
202
+ def delete_path(self, name : str):
203
+ name = self.get_value(name)
204
+ with self.engine.connect() as conn:
205
+ stmt = delete(self.Tables.path).where((self.Tables.path.c.Name == name) & (self.Tables.env_var.c.App == self.app_name))
206
+ conn.execute(stmt)
207
+ conn.commit()
208
+
209
+ def get_var(self, name):
210
+ name = self.get_value(name)
211
+ data = self.select('env_var', f"name = '{name}'")
212
+ for d in data:
213
+ return EnvVar(d).Value
214
+
215
+ def update_var(self, name : str, value : str):
216
+ name = self.get_value(name)
217
+ value = self.get_value(value)
218
+ existsVar = self.get_var(name)
219
+ with self.engine.connect() as conn:
220
+ if existsVar != None:
221
+ stmt = update(self.Tables.env_var).where(
222
+ (self.Tables.env_var.c.Name == name) &
223
+ (self.Tables.env_var.c.App == self.app_name)
224
+ ).values(Value=value)
225
+ conn.execute(stmt)
226
+ else:
227
+ ins = insert(self.Tables.env_var).values(App=self.app_name, Name=name, Value=value)
228
+ conn.execute(ins)
229
+ conn.commit()
230
+
231
+ def delete_var(self, name : str):
232
+ name = self.get_value(name)
233
+ with self.engine.connect() as conn:
234
+ stmt = delete(self.Tables.env_var).where((self.Tables.env_var.c.Name == name) & (self.Tables.env_var.c.App == self.app_name))
235
+ conn.execute(stmt)
236
+ conn.commit()
237
+
238
+ def get_theme(self):
239
+ # Consulta o tema no banco de dados
240
+ data = self.select('system')
241
+ if data:
242
+ # Se houver dados, retorna o tema
243
+ return System(data[0]).Theme
244
+ else:
245
+ # Se n�o houver dados, insere um tema padr�o e retorna 'light'
246
+ with self.engine.connect() as conn:
247
+ ins = insert(self.Tables.system).values(App=self.app_name, Tema='light')
248
+ conn.execute(ins)
249
+ conn.commit()
250
+ return 'light'
251
+
252
+ def update_theme(self, theme : str):
253
+ theme = self.get_value(theme)
254
+ _theme = self.get_theme()
255
+ if _theme:
256
+ with self.engine.connect() as conn:
257
+ stmt = update(self.Tables.system).where(
258
+ self.Tables.system.c.App == self.app_name
259
+ ).values(Tema=theme)
260
+ conn.execute(stmt)
261
+ conn.commit()
262
+
263
+
264
+
265
+
266
+
267
+
268
+
@@ -0,0 +1,30 @@
1
+ # -*- coding: latin -*-
2
+
3
+ class BaseTableModel(object):
4
+ def __init__(self, dados : dict):
5
+ self.id : int = dados['id']
6
+ self.App : str = dados['App']
7
+
8
+ class Path(BaseTableModel):
9
+ def __init__(self, dados : dict):
10
+ super().__init__(dados)
11
+ self.Name : str = dados['Name']
12
+ self.Path : str = dados['Path']
13
+
14
+ class EnvVar(BaseTableModel):
15
+
16
+ def __init__(self, dados : dict):
17
+ super().__init__(dados)
18
+ self.Name : str = dados['Name']
19
+ self.Value : str = dados['Value']
20
+
21
+ class System(BaseTableModel):
22
+ def __init__(self, dados : dict):
23
+ super().__init__(dados)
24
+ self.Theme : str = dados['Tema']
25
+
26
+
27
+
28
+
29
+
30
+
dapper_sqls/utils.py ADDED
@@ -0,0 +1,89 @@
1
+
2
+
3
+ def get_dict_args(local : dict , ignore_args = [], ignore_values_none = True):
4
+ if ignore_values_none:
5
+ return {k: v for k, v in local.items() if k != 'self' and k != 'cls' and v != None and k not in ignore_args}
6
+ return {k: v for k, v in local.items() if k != 'self' and k != 'cls' and k not in ignore_args}
7
+
8
+ class ArgsStored:
9
+ def __init__(self, model : object | None, query : str | None, params : list | tuple | None, additional_sql : str, select_top : int | None):
10
+ self.model = model
11
+ self.query = query
12
+ self.params = params
13
+ self.additional_sql = additional_sql if isinstance(additional_sql, str) else ""
14
+ self.select_top = select_top if isinstance(select_top, int) else None
15
+
16
+ class ArgsQuery:
17
+ def __init__(self, model : object | None, query : str | None, additional_sql : str, select_top : int | None):
18
+ self.model = model
19
+ self.query = query
20
+ self.additional_sql = additional_sql
21
+ self.select_top = select_top
22
+
23
+ class ArgsSTP:
24
+ def __init__(self, model : object | None, attempts : str | None, wait_timeout : str | None):
25
+ self.model = model
26
+ self.attempts = attempts
27
+ self.wait_timeout = wait_timeout
28
+
29
+
30
+ class Utils(object):
31
+
32
+ @staticmethod
33
+ def args_stored(*args, **kwargs):
34
+ query = kwargs.get('query')
35
+ model = kwargs.get('model')
36
+ params = kwargs.get('params')
37
+ additional_sql = kwargs.get('additional_sql', '')
38
+ select_top = kwargs.get('select_top')
39
+
40
+ if not query and not model:
41
+ if isinstance(args[0], str):
42
+ query = args[0]
43
+ params = args[1:]
44
+ if len(params) == 1 and isinstance(params[0], (list, tuple)):
45
+ params = params[0]
46
+ params = tuple(params)
47
+
48
+ else:
49
+ model = args[0]
50
+ if not additional_sql.strip():
51
+ if len(args) > 1:
52
+ additional_sql = args[1] if len(args) > 1 else ""
53
+ if not select_top:
54
+ select_top = args[2] if len(args) > 2 else None
55
+
56
+ return ArgsStored(model, query, params, additional_sql, select_top)
57
+
58
+
59
+ @staticmethod
60
+ def args_query(*args, **kwargs):
61
+ query = kwargs.get('query')
62
+ model = kwargs.get('model')
63
+ additional_sql = kwargs.get('additional_sql', '')
64
+ select_top = kwargs.get('select_top')
65
+
66
+ if not query and not model:
67
+ if isinstance(args[0], str):
68
+ query = args[0]
69
+ else:
70
+ model = args[0]
71
+ if not additional_sql.strip():
72
+ additional_sql = args[1] if len(args) > 1 else ""
73
+ if not select_top:
74
+ select_top = args[2] if len(args) > 2 and not select_top else None
75
+
76
+ return ArgsQuery(model, query, additional_sql, select_top)
77
+
78
+ @staticmethod
79
+ def args_stp(*args, **kwargs):
80
+ model = kwargs.get('model')
81
+ attempts = kwargs.get('attempts')
82
+ wait_timeout = kwargs.get('wait_timeout')
83
+ if not model:
84
+ model = args[0] if len(args) > 0 else None
85
+ attempts = args[1] if len(args) > 1 else None
86
+ wait_timeout = args[2] if len(args) > 2 else None
87
+
88
+ return ArgsSTP(model, attempts, wait_timeout)
89
+