|
28 | 28 | Date: 2024/05/16
|
29 | 29 | License: MIT
|
30 | 30 | """
|
31 |
| - |
| 31 | +import functools |
32 | 32 | import time
|
33 |
| -from typing import Dict, List, Type |
| 33 | +import warnings |
| 34 | +from typing import Any, Dict, List, Optional, Tuple, Type, Union |
34 | 35 |
|
35 | 36 | from sqlalchemy import delete
|
36 | 37 | from sqlalchemy.ext.declarative import DeclarativeMeta
|
| 38 | +from sqlalchemy.sql.elements import ClauseElement |
37 | 39 |
|
38 |
| -# from loguru import logger |
39 |
| -# import logging as logger |
40 | 40 | from .. import LOGGER as logger
|
41 | 41 | from .__import_sqlalchemy import import_sqlalchemy
|
42 | 42 | # Importing AsyncDatabase class from local module async_database
|
@@ -107,6 +107,22 @@ def handle_exceptions(ex: Exception) -> Dict[str, str]:
|
107 | 107 | return {"error": "General Exception", "details": str(ex)}
|
108 | 108 |
|
109 | 109 |
|
| 110 | +def deprecated(reason): |
| 111 | + def decorator(func): |
| 112 | + message = f"{func.__name__}() is deprecated: {reason}" |
| 113 | + |
| 114 | + @functools.wraps(func) |
| 115 | + async def wrapped(*args, **kwargs): |
| 116 | + warnings.warn( |
| 117 | + message, |
| 118 | + DeprecationWarning, |
| 119 | + stacklevel=2, |
| 120 | + ) |
| 121 | + return await func(*args, **kwargs) |
| 122 | + return wrapped |
| 123 | + return decorator |
| 124 | + |
| 125 | + |
110 | 126 | class DatabaseOperations:
|
111 | 127 | """
|
112 | 128 | This class provides methods for performing CRUD operations on a database using SQLAlchemy's asynchronous session.
|
@@ -435,6 +451,7 @@ async def get_table_names(self):
|
435 | 451 | logger.error(f"Exception occurred: {ex}") # pragma: no cover
|
436 | 452 | return handle_exceptions(ex) # pragma: no cover
|
437 | 453 |
|
| 454 | + @deprecated("Use `execute_one` with an INSERT query instead.") |
438 | 455 | async def create_one(self, record):
|
439 | 456 | """
|
440 | 457 | Adds a single record to the database.
|
@@ -506,6 +523,7 @@ async def create_one(self, record):
|
506 | 523 | logger.error(f"Exception occurred: {ex}")
|
507 | 524 | return handle_exceptions(ex)
|
508 | 525 |
|
| 526 | + @deprecated("Use `execute_one` with an INSERT query instead.") |
509 | 527 | async def create_many(self, records):
|
510 | 528 | """
|
511 | 529 | Adds multiple records to the database.
|
@@ -904,6 +922,7 @@ async def read_multi_query(self, queries: Dict[str, str]):
|
904 | 922 | logger.error(f"Exception occurred: {ex}")
|
905 | 923 | return handle_exceptions(ex)
|
906 | 924 |
|
| 925 | + @deprecated("Use `execute_one` with a UPDATE query instead.") |
907 | 926 | async def update_one(self, table, record_id: str, new_values: dict):
|
908 | 927 | """
|
909 | 928 | Updates a single record in the database identified by its ID.
|
@@ -997,6 +1016,7 @@ async def update_one(self, table, record_id: str, new_values: dict):
|
997 | 1016 | logger.error(f"Exception occurred: {ex}")
|
998 | 1017 | return handle_exceptions(ex)
|
999 | 1018 |
|
| 1019 | + @deprecated("Use `execute_many` with a DELETE query instead.") |
1000 | 1020 | async def delete_one(self, table, record_id: str):
|
1001 | 1021 | """
|
1002 | 1022 | Deletes a single record from the database based on the provided table
|
@@ -1100,6 +1120,7 @@ async def delete_one(self, table, record_id: str):
|
1100 | 1120 | logger.error(f"Exception occurred: {ex}")
|
1101 | 1121 | return handle_exceptions(ex)
|
1102 | 1122 |
|
| 1123 | + @deprecated("User 'execute_many' with a DELETE query instead.") |
1103 | 1124 | async def delete_many(
|
1104 | 1125 | self,
|
1105 | 1126 | table: Type[DeclarativeMeta],
|
@@ -1185,3 +1206,93 @@ async def delete_many(
|
1185 | 1206 | # Handle any exceptions that occur during the record deletion
|
1186 | 1207 | logger.error(f"Exception occurred: {ex}")
|
1187 | 1208 | return handle_exceptions(ex)
|
| 1209 | + |
| 1210 | + |
| 1211 | + async def execute_one( |
| 1212 | + self, |
| 1213 | + query: ClauseElement, |
| 1214 | + values: Optional[Dict[str, Any]] = None |
| 1215 | + ) -> Union[str, Dict[str, str]]: |
| 1216 | + """ |
| 1217 | + Executes a single non-read SQL query asynchronously. |
| 1218 | +
|
| 1219 | + This method executes a single SQL statement that modifies the database, |
| 1220 | + such as INSERT, UPDATE, or DELETE. It handles the execution within an |
| 1221 | + asynchronous session and commits the transaction upon success. |
| 1222 | +
|
| 1223 | + Args: |
| 1224 | + query (ClauseElement): An SQLAlchemy query object representing the SQL statement to execute. |
| 1225 | + values (Optional[Dict[str, Any]]): A dictionary of parameter values to bind to the query. |
| 1226 | + Defaults to None. |
| 1227 | +
|
| 1228 | + Returns: |
| 1229 | + Union[str, Dict[str, str]]: "complete" if the query executed and committed successfully, |
| 1230 | + or an error dictionary if an exception occurred. |
| 1231 | +
|
| 1232 | + Example: |
| 1233 | + ```python |
| 1234 | + from sqlalchemy import insert |
| 1235 | +
|
| 1236 | + query = insert(User).values(name='John Doe') |
| 1237 | + result = await db_ops.execute_one(query) |
| 1238 | + ``` |
| 1239 | + """ |
| 1240 | + logger.debug("Starting execute_one operation") |
| 1241 | + try: |
| 1242 | + async with self.async_db.get_db_session() as session: |
| 1243 | + logger.debug(f"Executing query: {query}") |
| 1244 | + await session.execute(query, params=values) |
| 1245 | + await session.commit() |
| 1246 | + logger.debug("Query executed successfully") |
| 1247 | + return "complete" |
| 1248 | + except Exception as ex: |
| 1249 | + logger.error(f"Exception occurred: {ex}") |
| 1250 | + return handle_exceptions(ex) |
| 1251 | + |
| 1252 | + async def execute_many( |
| 1253 | + self, |
| 1254 | + queries: List[Tuple[ClauseElement, Optional[Dict[str, Any]]]] |
| 1255 | + ) -> Union[str, Dict[str, str]]: |
| 1256 | + """ |
| 1257 | + Executes multiple non-read SQL queries asynchronously within a single transaction. |
| 1258 | +
|
| 1259 | + This method executes a list of SQL statements that modify the database, |
| 1260 | + such as multiple INSERTs, UPDATEs, or DELETEs. All queries are executed |
| 1261 | + within the same transaction, which is committed if all succeed, or rolled |
| 1262 | + back if any fail. |
| 1263 | +
|
| 1264 | + Args: |
| 1265 | + queries (List[Tuple[ClauseElement, Optional[Dict[str, Any]]]]): A list of tuples, each containing |
| 1266 | + a query and an optional dictionary of parameter values. Each tuple should be of the form |
| 1267 | + `(query, values)` where: |
| 1268 | + - `query` is an SQLAlchemy query object. |
| 1269 | + - `values` is a dictionary of parameters to bind to the query (or None). |
| 1270 | +
|
| 1271 | + Returns: |
| 1272 | + Union[str, Dict[str, str]]: "complete" if all queries executed and committed successfully, |
| 1273 | + or an error dictionary if an exception occurred. |
| 1274 | +
|
| 1275 | + Example: |
| 1276 | + ```python |
| 1277 | + from sqlalchemy import insert |
| 1278 | +
|
| 1279 | + queries = [ |
| 1280 | + (insert(User), {'name': 'User1'}), |
| 1281 | + (insert(User), {'name': 'User2'}), |
| 1282 | + (insert(User), {'name': 'User3'}), |
| 1283 | + ] |
| 1284 | + result = await db_ops.execute_many(queries) |
| 1285 | + ``` |
| 1286 | + """ |
| 1287 | + logger.debug("Starting execute_many operation") |
| 1288 | + try: |
| 1289 | + async with self.async_db.get_db_session() as session: |
| 1290 | + for query, values in queries: |
| 1291 | + logger.debug(f"Executing query: {query}") |
| 1292 | + await session.execute(query, params=values) |
| 1293 | + await session.commit() |
| 1294 | + logger.debug("All queries executed successfully") |
| 1295 | + return "complete" |
| 1296 | + except Exception as ex: |
| 1297 | + logger.error(f"Exception occurred: {ex}") |
| 1298 | + return handle_exceptions(ex) |
0 commit comments