dapper-sqls 0.9.7__py3-none-any.whl → 1.2.0__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.
- dapper_sqls/__init__.py +4 -2
- dapper_sqls/_types.py +25 -2
- dapper_sqls/async_dapper/async_dapper.py +1 -1
- dapper_sqls/async_dapper/async_executors.py +128 -53
- dapper_sqls/builders/model/model.py +421 -36
- dapper_sqls/builders/model/utils.py +337 -45
- dapper_sqls/builders/query.py +165 -44
- dapper_sqls/builders/stored.py +16 -10
- dapper_sqls/builders/stp.py +6 -2
- dapper_sqls/config.py +41 -32
- dapper_sqls/dapper/dapper.py +1 -1
- dapper_sqls/dapper/executors.py +131 -56
- dapper_sqls/decorators.py +5 -3
- dapper_sqls/http/__init__.py +4 -0
- dapper_sqls/http/aiohttp.py +155 -0
- dapper_sqls/http/decorators.py +123 -0
- dapper_sqls/http/models.py +58 -0
- dapper_sqls/http/request.py +140 -0
- dapper_sqls/models/__init__.py +3 -5
- dapper_sqls/models/base.py +246 -20
- dapper_sqls/models/connection.py +2 -2
- dapper_sqls/models/query_field.py +214 -0
- dapper_sqls/models/result.py +315 -45
- dapper_sqls/sqlite/__init__.py +5 -1
- dapper_sqls/sqlite/async_local_database.py +168 -0
- dapper_sqls/sqlite/decorators.py +69 -0
- dapper_sqls/sqlite/installer.py +97 -0
- dapper_sqls/sqlite/local_database.py +67 -185
- dapper_sqls/sqlite/models.py +51 -1
- dapper_sqls/sqlite/utils.py +9 -0
- dapper_sqls/utils.py +18 -6
- dapper_sqls-1.2.0.dist-info/METADATA +41 -0
- dapper_sqls-1.2.0.dist-info/RECORD +40 -0
- {dapper_sqls-0.9.7.dist-info → dapper_sqls-1.2.0.dist-info}/WHEEL +1 -1
- dapper_sqls-0.9.7.dist-info/METADATA +0 -19
- dapper_sqls-0.9.7.dist-info/RECORD +0 -30
- {dapper_sqls-0.9.7.dist-info → dapper_sqls-1.2.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,168 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
from sqlalchemy.ext.asyncio import create_async_engine, AsyncEngine
|
3
|
+
from sqlalchemy import text, insert, delete, select, Connection
|
4
|
+
from .models import BaseTables, Path, System, EnvVar, NotificationData
|
5
|
+
from .utils import get_value
|
6
|
+
|
7
|
+
class BaseAsyncLocalDatabase:
|
8
|
+
|
9
|
+
def __init__(self, app_name: str, path : str, is_new_database : bool, insistent_tables : list[str]):
|
10
|
+
self._app_name = app_name
|
11
|
+
self.is_new_database = is_new_database
|
12
|
+
self.insistent_tables = insistent_tables
|
13
|
+
self._engine: AsyncEngine = create_async_engine(f'sqlite+aiosqlite:///{path}')
|
14
|
+
|
15
|
+
@property
|
16
|
+
def engine(self):
|
17
|
+
return self._engine
|
18
|
+
|
19
|
+
@property
|
20
|
+
def app_name(self):
|
21
|
+
return self._app_name
|
22
|
+
|
23
|
+
async def close(self):
|
24
|
+
await self._engine.dispose()
|
25
|
+
self._engine.pool.dispose()
|
26
|
+
self._engine = None
|
27
|
+
|
28
|
+
async def init_db(self):
|
29
|
+
async with self.engine.begin() as conn:
|
30
|
+
await conn.run_sync(BaseTables.meta_data.create_all)
|
31
|
+
await conn.execute(BaseTables.system.insert().values(App=self.app_name, Tema='light'))
|
32
|
+
await conn.commit()
|
33
|
+
|
34
|
+
async def select(self, table: str, where: str = None, conn : Connection = None):
|
35
|
+
if not conn:
|
36
|
+
async with self.engine.connect() as conn:
|
37
|
+
query = f"SELECT * FROM {table} WHERE App = :app_name"
|
38
|
+
if where:
|
39
|
+
query += f" AND {where}"
|
40
|
+
result = await conn.execute(text(query), {'app_name': self.app_name})
|
41
|
+
return [row._mapping for row in result]
|
42
|
+
else:
|
43
|
+
query = f"SELECT * FROM {table} WHERE App = :app_name"
|
44
|
+
if where:
|
45
|
+
query += f" AND {where}"
|
46
|
+
result = await conn.execute(text(query), {'app_name': self.app_name})
|
47
|
+
return [row._mapping for row in result]
|
48
|
+
|
49
|
+
async def get_path(self, name):
|
50
|
+
name = get_value(name)
|
51
|
+
data = await self.select('path', f"Name = '{name}'")
|
52
|
+
return Path(data[0]).Path if data else None
|
53
|
+
|
54
|
+
async def update_path(self, name: str, path_name: str):
|
55
|
+
name, path_name = get_value(name), get_value(path_name)
|
56
|
+
exists_path = await self.get_path(name)
|
57
|
+
async with self.engine.begin() as conn:
|
58
|
+
if exists_path:
|
59
|
+
await conn.execute(
|
60
|
+
BaseTables.path.update().where(
|
61
|
+
(BaseTables.path.c.Name == name) & (BaseTables.path.c.App == self.app_name)
|
62
|
+
).values(Path=path_name)
|
63
|
+
)
|
64
|
+
else:
|
65
|
+
await conn.execute(BaseTables.path.insert().values(App=self.app_name, Name=name, Path=path_name))
|
66
|
+
|
67
|
+
async def delete_path(self, name: str):
|
68
|
+
name = get_value(name)
|
69
|
+
async with self.engine.begin() as conn:
|
70
|
+
await conn.execute(
|
71
|
+
BaseTables.path.delete().where(
|
72
|
+
(BaseTables.path.c.Name == name) & (BaseTables.path.c.App == self.app_name)
|
73
|
+
)
|
74
|
+
)
|
75
|
+
|
76
|
+
async def get_var(self, name):
|
77
|
+
name = get_value(name)
|
78
|
+
data = await self.select('env_var', f"Name = '{name}'")
|
79
|
+
return EnvVar(data[0]).Value if data else None
|
80
|
+
|
81
|
+
async def update_var(self, name: str, value: str):
|
82
|
+
name, value = get_value(name), get_value(value)
|
83
|
+
exists_var = await self.get_var(name)
|
84
|
+
async with self.engine.begin() as conn:
|
85
|
+
if exists_var:
|
86
|
+
await conn.execute(
|
87
|
+
BaseTables.env_var.update().where(
|
88
|
+
(BaseTables.env_var.c.Name == name) & (BaseTables.env_var.c.App == self.app_name)
|
89
|
+
).values(Value=value)
|
90
|
+
)
|
91
|
+
else:
|
92
|
+
await conn.execute(BaseTables.env_var.insert().values(App=self.app_name, Name=name, Value=value))
|
93
|
+
|
94
|
+
async def delete_var(self, name: str):
|
95
|
+
name = get_value(name)
|
96
|
+
async with self.engine.begin() as conn:
|
97
|
+
await conn.execute(
|
98
|
+
BaseTables.env_var.delete().where(
|
99
|
+
(BaseTables.env_var.c.Name == name) & (BaseTables.env_var.c.App == self.app_name)
|
100
|
+
)
|
101
|
+
)
|
102
|
+
|
103
|
+
async def get_theme(self):
|
104
|
+
data = await self.select('system')
|
105
|
+
if data:
|
106
|
+
return System(data[0]).Theme
|
107
|
+
async with self.engine.begin() as conn:
|
108
|
+
await conn.execute(BaseTables.system.insert().values(App=self.app_name, Tema='light'))
|
109
|
+
return 'light'
|
110
|
+
|
111
|
+
async def update_theme(self, theme: str):
|
112
|
+
theme = get_value(theme)
|
113
|
+
async with self.engine.begin() as conn:
|
114
|
+
await conn.execute(
|
115
|
+
BaseTables.system.update().where(BaseTables.system.c.App == self.app_name).values(Tema=theme)
|
116
|
+
)
|
117
|
+
|
118
|
+
async def insert_notification(self, data: NotificationData):
|
119
|
+
async with self.engine.begin() as conn:
|
120
|
+
ins = insert(BaseTables.notification).values(
|
121
|
+
App=self.app_name,
|
122
|
+
guid=data.guid,
|
123
|
+
local=data.local,
|
124
|
+
title=data.title,
|
125
|
+
message=data.message,
|
126
|
+
type=data.type,
|
127
|
+
date=data.date
|
128
|
+
)
|
129
|
+
await conn.execute(ins)
|
130
|
+
|
131
|
+
async def delete_notification(self, guid: str):
|
132
|
+
async with self.engine.begin() as conn:
|
133
|
+
stmt = delete(BaseTables.notification).where(
|
134
|
+
(BaseTables.notification.c.guid == guid) & (BaseTables.notification.c.App == self.app_name)
|
135
|
+
)
|
136
|
+
await conn.execute(stmt)
|
137
|
+
|
138
|
+
async def clear_notification(self):
|
139
|
+
async with self.engine.begin() as conn:
|
140
|
+
stmt = delete(BaseTables.notification).where(BaseTables.notification.c.App == self.app_name)
|
141
|
+
await conn.execute(stmt)
|
142
|
+
|
143
|
+
async def get_notifications(self):
|
144
|
+
async with self.engine.connect() as conn:
|
145
|
+
stmt = select(BaseTables.notification).where(BaseTables.notification.c.App == self.app_name)
|
146
|
+
result = await conn.execute(stmt)
|
147
|
+
notifications = result.fetchall()
|
148
|
+
return [NotificationData(**notification._mapping) for notification in notifications]
|
149
|
+
|
150
|
+
async def insert_notification(self, data : NotificationData):
|
151
|
+
async with self.engine.connect() as conn:
|
152
|
+
ins = insert(BaseTables.notification).values(App=self.app_name, guid=data.guid, local=data.local, title=data.title, message=data.message, type=data.type,date=data.date)
|
153
|
+
await conn.execute(ins)
|
154
|
+
await conn.commit()
|
155
|
+
|
156
|
+
async def delete_notification(self, guid : str):
|
157
|
+
async with self.engine.connect() as conn:
|
158
|
+
await conn.execute(delete(BaseTables.notification).where((BaseTables.notification.c.guid == guid) & (BaseTables.notification.c.App == self.app_name)))
|
159
|
+
await conn.commit()
|
160
|
+
|
161
|
+
async def clear_notification(self):
|
162
|
+
async with self.engine.connect() as conn:
|
163
|
+
await conn.execute(delete(BaseTables.notification).where(BaseTables.notification.c.App == self.app_name))
|
164
|
+
await conn.commit()
|
165
|
+
|
166
|
+
async def get_notifications(self):
|
167
|
+
notifications = await self.select('notification')
|
168
|
+
return [NotificationData(**notification) for notification in notifications]
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
from functools import wraps
|
3
|
+
from dataclasses import dataclass
|
4
|
+
from typing import Any, Callable, TypeVar
|
5
|
+
from enum import Enum
|
6
|
+
|
7
|
+
T = TypeVar("T")
|
8
|
+
|
9
|
+
# Tipos de erro padronizados
|
10
|
+
class SqliteErrorType(Enum):
|
11
|
+
UNIQUE_VIOLATION = "Unique violation"
|
12
|
+
FOREIGN_KEY_VIOLATION = "Foreign key violation"
|
13
|
+
CHECK_CONSTRAINT_VIOLATION = "Check constraint violation"
|
14
|
+
PERMISSION_DENIED = "Permission denied"
|
15
|
+
SYNTAX_ERROR = "Syntax error"
|
16
|
+
TIMEOUT = "Timeout"
|
17
|
+
CONNECTION_ERROR = "Connection error"
|
18
|
+
UNKNOWN = "Unknown"
|
19
|
+
|
20
|
+
# Classificador específico para SQLite
|
21
|
+
def classify_sqlite_error(message: str) -> SqliteErrorType:
|
22
|
+
msg = message.lower()
|
23
|
+
|
24
|
+
if "unique constraint failed" in msg:
|
25
|
+
return SqliteErrorType.UNIQUE_VIOLATION
|
26
|
+
if "foreign key constraint failed" in msg:
|
27
|
+
return SqliteErrorType.FOREIGN_KEY_VIOLATION
|
28
|
+
if "check constraint failed" in msg:
|
29
|
+
return SqliteErrorType.CHECK_CONSTRAINT_VIOLATION
|
30
|
+
if "permission denied" in msg:
|
31
|
+
return SqliteErrorType.PERMISSION_DENIED
|
32
|
+
if "syntax error" in msg or ("near" in msg and "syntax error" in msg):
|
33
|
+
return SqliteErrorType.SYNTAX_ERROR
|
34
|
+
if "database is locked" in msg or "timeout" in msg:
|
35
|
+
return SqliteErrorType.TIMEOUT
|
36
|
+
if any(kw in msg for kw in [
|
37
|
+
"unable to open database file",
|
38
|
+
"disk i/o error",
|
39
|
+
"not a database",
|
40
|
+
"file is encrypted",
|
41
|
+
"file is not a database"
|
42
|
+
]):
|
43
|
+
return SqliteErrorType.CONNECTION_ERROR
|
44
|
+
|
45
|
+
return SqliteErrorType.UNKNOWN
|
46
|
+
|
47
|
+
# Classe Error
|
48
|
+
class Error:
|
49
|
+
def __init__(self, exception: Exception = None):
|
50
|
+
self.message = str(exception) if isinstance(exception, Exception) else ""
|
51
|
+
self.type = classify_sqlite_error(self.message) if self.message.strip() else None
|
52
|
+
|
53
|
+
# Classe de retorno do decorador
|
54
|
+
@dataclass
|
55
|
+
class OperationResult:
|
56
|
+
success: bool
|
57
|
+
error: Error | None
|
58
|
+
result: Any = None
|
59
|
+
|
60
|
+
# Decorador
|
61
|
+
def safe_sqlite_operation(func: Callable[..., T]) -> Callable[..., OperationResult]:
|
62
|
+
@wraps(func)
|
63
|
+
def wrapper(*args, **kwargs) -> OperationResult:
|
64
|
+
try:
|
65
|
+
result = func(*args, **kwargs)
|
66
|
+
return OperationResult(success=True, error=None, result=result)
|
67
|
+
except Exception as e:
|
68
|
+
return OperationResult(success=False, error=Error(e), result=None)
|
69
|
+
return wrapper
|
@@ -0,0 +1,97 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
from sqlalchemy import create_engine, inspect, text, insert
|
3
|
+
from sqlalchemy.engine import Engine
|
4
|
+
from tempfile import gettempdir
|
5
|
+
from os import path, makedirs
|
6
|
+
from .models import BaseTables
|
7
|
+
from .utils import is_valid_name, get_value
|
8
|
+
from typing import TypeVar
|
9
|
+
T = TypeVar('T')
|
10
|
+
|
11
|
+
class DataBaseInstall(object):
|
12
|
+
|
13
|
+
def __init__(self, app_name : str, *, tables : BaseTables = None, path_local_database = gettempdir(), database_name="MyLocalDatabase", database_folder_name = "MyApp"):
|
14
|
+
app_name = get_value(app_name)
|
15
|
+
if not database_name.endswith('.db'):
|
16
|
+
database_name = f'{database_name}.db'
|
17
|
+
if not is_valid_name(app_name):
|
18
|
+
app_name = "my_app"
|
19
|
+
self._app_name = app_name
|
20
|
+
self._path_database = path.join(path_local_database,database_folder_name, database_name)
|
21
|
+
self.tables = tables if tables else BaseTables
|
22
|
+
self._engine : Engine = None
|
23
|
+
self.new_database = not path.isfile(self._path_database)
|
24
|
+
self.insistent_tables = []
|
25
|
+
if not path.isfile(self._path_database):
|
26
|
+
if not path.exists(path.join(path_local_database,database_folder_name)):
|
27
|
+
makedirs(path.join(path_local_database,database_folder_name))
|
28
|
+
|
29
|
+
with self.engine.connect() as conn:
|
30
|
+
conn.execute(text("PRAGMA encoding = 'UTF-8'"))
|
31
|
+
conn.commit()
|
32
|
+
|
33
|
+
|
34
|
+
with self.engine.connect() as conn:
|
35
|
+
self.tables.meta_data.create_all(self.engine)
|
36
|
+
if hasattr(self.tables, 'system'):
|
37
|
+
ins = insert(self.tables.system).values(App=app_name, Tema='light')
|
38
|
+
conn.execute(ins)
|
39
|
+
conn.commit()
|
40
|
+
else:
|
41
|
+
if not self.are_tables_existing(self.engine):
|
42
|
+
try:
|
43
|
+
self.tables.meta_data.create_all(self.engine)
|
44
|
+
except:
|
45
|
+
...
|
46
|
+
else:
|
47
|
+
try:
|
48
|
+
self.synchronize_columns(self.engine)
|
49
|
+
except:
|
50
|
+
...
|
51
|
+
|
52
|
+
def instance(self, obj : T) -> T:
|
53
|
+
return obj(self._app_name, self._path_database, self.new_database, self.insistent_tables)
|
54
|
+
|
55
|
+
@property
|
56
|
+
def engine(self):
|
57
|
+
if not self._engine:
|
58
|
+
self._engine = create_engine(f'sqlite:///{self._path_database}')
|
59
|
+
return self._engine
|
60
|
+
|
61
|
+
def are_columns_existing(self, engine):
|
62
|
+
inspector = inspect(engine)
|
63
|
+
existing_tables = inspector.get_table_names()
|
64
|
+
required_tables = self.tables.meta_data.tables.keys()
|
65
|
+
for table_name in required_tables:
|
66
|
+
if table_name in existing_tables:
|
67
|
+
existing_columns = inspector.get_columns(table_name)
|
68
|
+
existing_column_names = [column['name'] for column in existing_columns]
|
69
|
+
required_columns = self.tables.meta_data.tables[table_name].c.keys()
|
70
|
+
if not all(column in existing_column_names for column in required_columns):
|
71
|
+
return False
|
72
|
+
else:
|
73
|
+
return False
|
74
|
+
return True
|
75
|
+
|
76
|
+
def are_tables_existing(self, engine):
|
77
|
+
inspector = inspect(engine)
|
78
|
+
existing_tables = inspector.get_table_names()
|
79
|
+
required_tables = self.tables.meta_data.tables.keys()
|
80
|
+
self.insistent_tables = [table for table in required_tables if table not in existing_tables]
|
81
|
+
return not bool(self.insistent_tables)
|
82
|
+
|
83
|
+
def synchronize_columns(self, engine):
|
84
|
+
inspector = inspect(engine)
|
85
|
+
existing_tables = inspector.get_table_names()
|
86
|
+
for table_name in self.tables.meta_data.tables.keys():
|
87
|
+
if table_name in existing_tables:
|
88
|
+
existing_columns = inspector.get_columns(table_name)
|
89
|
+
existing_column_names = [column['name'] for column in existing_columns]
|
90
|
+
required_columns = self.tables.meta_data.tables[table_name].c.keys()
|
91
|
+
required_column_defs = {col.name: col for col in self.tables.meta_data.tables[table_name].columns}
|
92
|
+
for column in required_columns:
|
93
|
+
if column not in existing_column_names:
|
94
|
+
column_type = required_column_defs[column].type
|
95
|
+
add_column_sql = f'ALTER TABLE {table_name} ADD COLUMN {column} {column_type}'
|
96
|
+
with engine.connect() as conn:
|
97
|
+
conn.execute(text(add_column_sql))
|
@@ -1,173 +1,39 @@
|
|
1
|
-
#
|
1
|
+
# coding: utf-8
|
2
|
+
from sqlalchemy import create_engine, text, insert, delete, update, Connection
|
3
|
+
from .models import BaseTables, Path, System, EnvVar, NotificationData
|
4
|
+
from .utils import get_value
|
2
5
|
|
3
|
-
|
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
|
6
|
+
class BaseLocalDatabase(object):
|
9
7
|
|
10
|
-
|
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")
|
8
|
+
def __init__(self, app_name : str, path : str, is_new_database : bool, insistent_tables : list[str]):
|
68
9
|
self._app_name = app_name
|
69
|
-
self.
|
70
|
-
self.
|
71
|
-
|
72
|
-
|
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
|
-
|
10
|
+
self.is_new_database = is_new_database
|
11
|
+
self.insistent_tables = insistent_tables
|
12
|
+
self._engine = create_engine(f'sqlite:///{path}')
|
13
|
+
|
100
14
|
@property
|
101
15
|
def engine(self):
|
102
|
-
if not self._engine:
|
103
|
-
self._engine = create_engine(f'sqlite:///{self.path_database}')
|
104
16
|
return self._engine
|
105
17
|
|
106
18
|
@property
|
107
19
|
def app_name(self):
|
108
20
|
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
21
|
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
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:
|
22
|
+
def close(self):
|
23
|
+
self._engine.dispose()
|
24
|
+
self._engine.pool.dispose()
|
25
|
+
self._engine = None
|
26
|
+
|
27
|
+
def select(self, table : str, where : str = None, conn : Connection = None):
|
28
|
+
if not conn:
|
29
|
+
with self.engine.connect() as conn:
|
30
|
+
if where:
|
31
|
+
query = conn.execute(text(f"select * from {table} where App = '{self.app_name}' and {where}"))
|
32
|
+
else:
|
33
|
+
query = conn.execute(text(f"select * from {table} where App = '{self.app_name}'"))
|
34
|
+
data = [dict(zip(tuple(query.keys()), i)) for i in query.cursor]
|
35
|
+
return data
|
36
|
+
else:
|
171
37
|
if where:
|
172
38
|
query = conn.execute(text(f"select * from {table} where App = '{self.app_name}' and {where}"))
|
173
39
|
else:
|
@@ -175,90 +41,106 @@ class LocalDatabase(object):
|
|
175
41
|
data = [dict(zip(tuple(query.keys()), i)) for i in query.cursor]
|
176
42
|
return data
|
177
43
|
|
178
|
-
|
179
44
|
def get_path(self, name):
|
180
|
-
name =
|
45
|
+
name = get_value(name)
|
181
46
|
data = self.select('path', f"Name = '{name}'")
|
182
47
|
for d in data:
|
183
48
|
return Path(d).Path
|
184
49
|
|
185
50
|
def update_path(self, name : str, path_name : str):
|
186
|
-
name =
|
187
|
-
path_name =
|
51
|
+
name = get_value(name)
|
52
|
+
path_name = get_value(path_name)
|
188
53
|
existsPath = self.get_path(name)
|
189
54
|
|
190
55
|
with self.engine.connect() as conn:
|
191
56
|
if existsPath != None:
|
192
|
-
stmt = update(
|
193
|
-
(
|
194
|
-
(
|
57
|
+
stmt = update(BaseTables.path).where(
|
58
|
+
(BaseTables.path.c.Name == name) &
|
59
|
+
(BaseTables.path.c.App == self.app_name)
|
195
60
|
).values(Path=path_name)
|
196
61
|
conn.execute(stmt)
|
197
62
|
else:
|
198
|
-
ins = insert(
|
63
|
+
ins = insert(BaseTables.path).values(App=self.app_name, Name=name, Path=path_name)
|
199
64
|
conn.execute(ins)
|
200
65
|
conn.commit()
|
201
66
|
|
202
67
|
def delete_path(self, name : str):
|
203
|
-
name =
|
68
|
+
name = get_value(name)
|
204
69
|
with self.engine.connect() as conn:
|
205
|
-
stmt = delete(
|
70
|
+
stmt = delete(BaseTables.path).where((BaseTables.path.c.Name == name) & (BaseTables.env_var.c.App == self.app_name))
|
206
71
|
conn.execute(stmt)
|
207
72
|
conn.commit()
|
208
73
|
|
209
74
|
def get_var(self, name):
|
210
|
-
name =
|
75
|
+
name = get_value(name)
|
211
76
|
data = self.select('env_var', f"name = '{name}'")
|
212
77
|
for d in data:
|
213
78
|
return EnvVar(d).Value
|
214
79
|
|
215
80
|
def update_var(self, name : str, value : str):
|
216
|
-
name =
|
217
|
-
value =
|
81
|
+
name = get_value(name)
|
82
|
+
value = get_value(value)
|
218
83
|
existsVar = self.get_var(name)
|
219
84
|
with self.engine.connect() as conn:
|
220
85
|
if existsVar != None:
|
221
|
-
stmt = update(
|
222
|
-
(
|
223
|
-
(
|
86
|
+
stmt = update(BaseTables.env_var).where(
|
87
|
+
(BaseTables.env_var.c.Name == name) &
|
88
|
+
(BaseTables.env_var.c.App == self.app_name)
|
224
89
|
).values(Value=value)
|
225
90
|
conn.execute(stmt)
|
226
91
|
else:
|
227
|
-
ins = insert(
|
92
|
+
ins = insert(BaseTables.env_var).values(App=self.app_name, Name=name, Value=value)
|
228
93
|
conn.execute(ins)
|
229
94
|
conn.commit()
|
230
95
|
|
231
96
|
def delete_var(self, name : str):
|
232
|
-
name =
|
97
|
+
name = get_value(name)
|
233
98
|
with self.engine.connect() as conn:
|
234
|
-
stmt = delete(
|
99
|
+
stmt = delete(BaseTables.env_var).where((BaseTables.env_var.c.Name == name) & (BaseTables.env_var.c.App == self.app_name))
|
235
100
|
conn.execute(stmt)
|
236
101
|
conn.commit()
|
237
102
|
|
238
103
|
def get_theme(self):
|
239
|
-
# Consulta o tema no banco de dados
|
240
104
|
data = self.select('system')
|
241
105
|
if data:
|
242
|
-
# Se houver dados, retorna o tema
|
243
106
|
return System(data[0]).Theme
|
244
107
|
else:
|
245
|
-
# Se n�o houver dados, insere um tema padr�o e retorna 'light'
|
246
108
|
with self.engine.connect() as conn:
|
247
|
-
ins = insert(
|
109
|
+
ins = insert(BaseTables.system).values(App=self.app_name, Tema='light')
|
248
110
|
conn.execute(ins)
|
249
111
|
conn.commit()
|
250
112
|
return 'light'
|
251
113
|
|
252
114
|
def update_theme(self, theme : str):
|
253
|
-
theme =
|
115
|
+
theme = get_value(theme)
|
254
116
|
_theme = self.get_theme()
|
255
117
|
if _theme:
|
256
118
|
with self.engine.connect() as conn:
|
257
|
-
stmt = update(
|
258
|
-
|
119
|
+
stmt = update(BaseTables.system).where(
|
120
|
+
BaseTables.system.c.App == self.app_name
|
259
121
|
).values(Tema=theme)
|
260
122
|
conn.execute(stmt)
|
261
123
|
conn.commit()
|
124
|
+
|
125
|
+
def insert_notification(self, data : NotificationData):
|
126
|
+
with self.engine.connect() as conn:
|
127
|
+
ins = insert(BaseTables.notification).values(App=self.app_name, guid=data.guid, local=data.local, title=data.title, message=data.message, type=data.type,date=data.date)
|
128
|
+
conn.execute(ins)
|
129
|
+
conn.commit()
|
130
|
+
|
131
|
+
def delete_notification(self, guid : str):
|
132
|
+
with self.engine.connect() as conn:
|
133
|
+
conn.execute(delete(BaseTables.notification).where((BaseTables.notification.c.guid == guid) & (BaseTables.notification.c.App == self.app_name)))
|
134
|
+
conn.commit()
|
135
|
+
|
136
|
+
def clear_notification(self):
|
137
|
+
with self.engine.connect() as conn:
|
138
|
+
conn.execute(delete(BaseTables.notification).where(BaseTables.notification.c.App == self.app_name))
|
139
|
+
conn.commit()
|
140
|
+
|
141
|
+
def get_notifications(self):
|
142
|
+
notifications = self.select('notification')
|
143
|
+
return [NotificationData(**notification) for notification in notifications]
|
262
144
|
|
263
145
|
|
264
146
|
|