api-foundry-query-engine 0.0.4__tar.gz → 0.0.5__tar.gz
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.
- {api_foundry_query_engine-0.0.4 → api_foundry_query_engine-0.0.5}/PKG-INFO +1 -1
- api_foundry_query_engine-0.0.5/api_foundry_query_engine/connectors/athena_connector.py +120 -0
- {api_foundry_query_engine-0.0.4 → api_foundry_query_engine-0.0.5}/api_foundry_query_engine/connectors/connection_factory.py +0 -1
- {api_foundry_query_engine-0.0.4 → api_foundry_query_engine-0.0.5}/pyproject.toml +1 -1
- {api_foundry_query_engine-0.0.4 → api_foundry_query_engine-0.0.5}/.gitignore +0 -0
- {api_foundry_query_engine-0.0.4 → api_foundry_query_engine-0.0.5}/LICENSE +0 -0
- {api_foundry_query_engine-0.0.4 → api_foundry_query_engine-0.0.5}/api_foundry_query_engine/__init__.py +0 -0
- {api_foundry_query_engine-0.0.4 → api_foundry_query_engine-0.0.5}/api_foundry_query_engine/adapters/adapter.py +0 -0
- {api_foundry_query_engine-0.0.4 → api_foundry_query_engine-0.0.5}/api_foundry_query_engine/adapters/case_change_adapter.py +0 -0
- {api_foundry_query_engine-0.0.4 → api_foundry_query_engine-0.0.5}/api_foundry_query_engine/adapters/gateway_adapter.py +0 -0
- {api_foundry_query_engine-0.0.4 → api_foundry_query_engine-0.0.5}/api_foundry_query_engine/connectors/connection.py +0 -0
- {api_foundry_query_engine-0.0.4 → api_foundry_query_engine-0.0.5}/api_foundry_query_engine/connectors/oracle_connector.py +0 -0
- {api_foundry_query_engine-0.0.4 → api_foundry_query_engine-0.0.5}/api_foundry_query_engine/connectors/postgres_connection.py +0 -0
- {api_foundry_query_engine-0.0.4 → api_foundry_query_engine-0.0.5}/api_foundry_query_engine/dao/dao.py +0 -0
- {api_foundry_query_engine-0.0.4 → api_foundry_query_engine-0.0.5}/api_foundry_query_engine/dao/operation_dao.py +0 -0
- {api_foundry_query_engine-0.0.4 → api_foundry_query_engine-0.0.5}/api_foundry_query_engine/dao/sql_custom_query_handler.py +0 -0
- {api_foundry_query_engine-0.0.4 → api_foundry_query_engine-0.0.5}/api_foundry_query_engine/dao/sql_delete_query_handler.py +0 -0
- {api_foundry_query_engine-0.0.4 → api_foundry_query_engine-0.0.5}/api_foundry_query_engine/dao/sql_insert_query_handler.py +0 -0
- {api_foundry_query_engine-0.0.4 → api_foundry_query_engine-0.0.5}/api_foundry_query_engine/dao/sql_query_handler.py +0 -0
- {api_foundry_query_engine-0.0.4 → api_foundry_query_engine-0.0.5}/api_foundry_query_engine/dao/sql_select_query_handler.py +0 -0
- {api_foundry_query_engine-0.0.4 → api_foundry_query_engine-0.0.5}/api_foundry_query_engine/dao/sql_subselect_query_handler.py +0 -0
- {api_foundry_query_engine-0.0.4 → api_foundry_query_engine-0.0.5}/api_foundry_query_engine/dao/sql_update_query_handler.py +0 -0
- {api_foundry_query_engine-0.0.4 → api_foundry_query_engine-0.0.5}/api_foundry_query_engine/lambda_handler.py +0 -0
- {api_foundry_query_engine-0.0.4 → api_foundry_query_engine-0.0.5}/api_foundry_query_engine/operation.py +0 -0
- {api_foundry_query_engine-0.0.4 → api_foundry_query_engine-0.0.5}/api_foundry_query_engine/services/service.py +0 -0
- {api_foundry_query_engine-0.0.4 → api_foundry_query_engine-0.0.5}/api_foundry_query_engine/services/transactional_service.py +0 -0
- {api_foundry_query_engine-0.0.4 → api_foundry_query_engine-0.0.5}/api_foundry_query_engine/utils/api_model.py +0 -0
- {api_foundry_query_engine-0.0.4 → api_foundry_query_engine-0.0.5}/api_foundry_query_engine/utils/app_exception.py +0 -0
- {api_foundry_query_engine-0.0.4 → api_foundry_query_engine-0.0.5}/api_foundry_query_engine/utils/logger.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: api-foundry-query-engine
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.5
|
|
4
4
|
Summary: The AWS lambda service handler use by the `api_foundry` project is a powerful tool designed to automate the deployment of REST APIs on AWS using Lambda services to access and interact with relational databases (RDBMS). This project leverages the OpenAPI specification to define and manage the APIs
|
|
5
5
|
Project-URL: Documentation, https://github.com/DanRepik/api-foundry
|
|
6
6
|
Project-URL: Source, https://github.com/DanRepik/api-foundry
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
from api_foundry_query_engine.connectors.connection import Connection, Cursor
|
|
2
|
+
from api_foundry_query_engine.utils.logger import logger
|
|
3
|
+
import boto3
|
|
4
|
+
import time
|
|
5
|
+
|
|
6
|
+
# Initialize the logger
|
|
7
|
+
log = logger(__name__)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class AthenaCursor(Cursor):
|
|
11
|
+
def __init__(self, athena_client, db_config):
|
|
12
|
+
self.athena_client = athena_client
|
|
13
|
+
self.db_config = db_config
|
|
14
|
+
|
|
15
|
+
def execute(self, sql: str, parameters: dict, result_columns: list[str]) -> list:
|
|
16
|
+
"""
|
|
17
|
+
Execute a SQL statement on the Athena database.
|
|
18
|
+
|
|
19
|
+
Parameters:
|
|
20
|
+
- sql (str): The SQL query to execute.
|
|
21
|
+
- parameters (dict): Parameters for the query (currently unused; substitute manually in the query).
|
|
22
|
+
- result_columns (list[str]): Column names for the results.
|
|
23
|
+
|
|
24
|
+
Returns:
|
|
25
|
+
- list[dict]: Query results as a list of dictionaries.
|
|
26
|
+
"""
|
|
27
|
+
# Substitute parameters into the query manually (Athena doesn't support placeholders)
|
|
28
|
+
for key, value in parameters.items():
|
|
29
|
+
placeholder = f":{key}"
|
|
30
|
+
if isinstance(value, str):
|
|
31
|
+
value = f"'{value}'" # Wrap strings in quotes
|
|
32
|
+
sql = sql.replace(placeholder, str(value))
|
|
33
|
+
|
|
34
|
+
log.info(f"Executing query: {sql}")
|
|
35
|
+
|
|
36
|
+
# Start the query execution
|
|
37
|
+
response = self.athena_client.start_query_execution(
|
|
38
|
+
QueryString=sql,
|
|
39
|
+
QueryExecutionContext={"Database": self.db_config["database"]},
|
|
40
|
+
ResultConfiguration={"OutputLocation": self.db_config["output_location"]},
|
|
41
|
+
)
|
|
42
|
+
query_execution_id = response["QueryExecutionId"]
|
|
43
|
+
log.info(f"Query execution started: {query_execution_id}")
|
|
44
|
+
|
|
45
|
+
# Wait for the query to complete
|
|
46
|
+
while True:
|
|
47
|
+
status_response = self.athena_client.get_query_execution(
|
|
48
|
+
QueryExecutionId=query_execution_id
|
|
49
|
+
)
|
|
50
|
+
status = status_response["QueryExecution"]["Status"]["State"]
|
|
51
|
+
|
|
52
|
+
if status in ["SUCCEEDED", "FAILED", "CANCELLED"]:
|
|
53
|
+
break
|
|
54
|
+
time.sleep(2)
|
|
55
|
+
|
|
56
|
+
if status == "FAILED":
|
|
57
|
+
raise Exception(
|
|
58
|
+
f"Query failed: {status_response['QueryExecution']['Status']['StateChangeReason']}"
|
|
59
|
+
)
|
|
60
|
+
elif status == "CANCELLED":
|
|
61
|
+
raise Exception("Query was cancelled.")
|
|
62
|
+
|
|
63
|
+
# Fetch results
|
|
64
|
+
results_response = self.athena_client.get_query_results(
|
|
65
|
+
QueryExecutionId=query_execution_id
|
|
66
|
+
)
|
|
67
|
+
rows = results_response["ResultSet"]["Rows"]
|
|
68
|
+
|
|
69
|
+
# Convert rows to dictionaries
|
|
70
|
+
result = []
|
|
71
|
+
for row in rows[1:]: # Skip the first row (header row)
|
|
72
|
+
record = {
|
|
73
|
+
col: value.get("VarCharValue", None)
|
|
74
|
+
for col, value in zip(result_columns, row["Data"])
|
|
75
|
+
}
|
|
76
|
+
result.append(record)
|
|
77
|
+
|
|
78
|
+
return result
|
|
79
|
+
|
|
80
|
+
def close(self):
|
|
81
|
+
log.info("Closing Athena cursor (no persistent connection to close).")
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class AthenaConnection(Connection):
|
|
85
|
+
def __init__(self, db_config: dict) -> None:
|
|
86
|
+
"""
|
|
87
|
+
Initialize the AthenaConnection with the given configuration.
|
|
88
|
+
|
|
89
|
+
Parameters:
|
|
90
|
+
- db_config (dict): A dictionary containing Athena connection configuration.
|
|
91
|
+
Required keys:
|
|
92
|
+
- 'region': AWS region of the Athena service.
|
|
93
|
+
- 'output_location': S3 bucket location for query results.
|
|
94
|
+
- 'database': Athena database name.
|
|
95
|
+
"""
|
|
96
|
+
super().__init__(db_config)
|
|
97
|
+
self.athena_client = self.get_athena_client()
|
|
98
|
+
|
|
99
|
+
def engine(self) -> str:
|
|
100
|
+
return "athena"
|
|
101
|
+
|
|
102
|
+
def cursor(self) -> Cursor:
|
|
103
|
+
return AthenaCursor(self.athena_client, self.db_config)
|
|
104
|
+
|
|
105
|
+
def commit(self):
|
|
106
|
+
# Athena queries are read-only; no commit operation is required
|
|
107
|
+
log.info("Athena does not support transactions. Commit is a no-op.")
|
|
108
|
+
|
|
109
|
+
def close(self):
|
|
110
|
+
# Athena uses a stateless API, so there's nothing to close
|
|
111
|
+
log.info("Closing Athena connection (no persistent connection to close).")
|
|
112
|
+
|
|
113
|
+
def get_athena_client(self):
|
|
114
|
+
"""
|
|
115
|
+
Get a Boto3 client for Athena.
|
|
116
|
+
"""
|
|
117
|
+
region = self.db_config.get("region")
|
|
118
|
+
if not region:
|
|
119
|
+
raise ValueError("Athena configuration must include 'region'.")
|
|
120
|
+
return boto3.client("athena", region_name=region)
|
|
@@ -99,7 +99,6 @@ class ConnectionFactory:
|
|
|
99
99
|
|
|
100
100
|
# Get the secret value from AWS Secrets Manager
|
|
101
101
|
log.info(f"db_secret_name: {db_secret_name}")
|
|
102
|
-
db_secret = secretsmanager.describe_secret(SecretId=db_secret_name)
|
|
103
102
|
db_secret = secretsmanager.get_secret_value(SecretId=db_secret_name)
|
|
104
103
|
log.debug(f"loading secret name: {db_secret}")
|
|
105
104
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|