api-foundry-query-engine 0.8.1__tar.gz → 0.8.2__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.
Files changed (32) hide show
  1. {api_foundry_query_engine-0.8.1 → api_foundry_query_engine-0.8.2}/.gitignore +2 -0
  2. {api_foundry_query_engine-0.8.1 → api_foundry_query_engine-0.8.2}/PKG-INFO +1 -1
  3. api_foundry_query_engine-0.8.2/api_foundry_query_engine/.pre-commit-config.yaml +22 -0
  4. {api_foundry_query_engine-0.8.1 → api_foundry_query_engine-0.8.2}/api_foundry_query_engine/adapters/adapter.py +6 -3
  5. {api_foundry_query_engine-0.8.1 → api_foundry_query_engine-0.8.2}/api_foundry_query_engine/connectors/connection_factory.py +0 -1
  6. {api_foundry_query_engine-0.8.1 → api_foundry_query_engine-0.8.2}/api_foundry_query_engine/dao/operation_dao.py +5 -4
  7. {api_foundry_query_engine-0.8.1 → api_foundry_query_engine-0.8.2}/api_foundry_query_engine/dao/sql_insert_query_handler.py +12 -3
  8. {api_foundry_query_engine-0.8.1 → api_foundry_query_engine-0.8.2}/api_foundry_query_engine/dao/sql_select_query_handler.py +2 -2
  9. {api_foundry_query_engine-0.8.1 → api_foundry_query_engine-0.8.2}/api_foundry_query_engine/dao/sql_update_query_handler.py +13 -6
  10. {api_foundry_query_engine-0.8.1 → api_foundry_query_engine-0.8.2}/api_foundry_query_engine/lambda_handler.py +1 -4
  11. {api_foundry_query_engine-0.8.1 → api_foundry_query_engine-0.8.2}/api_foundry_query_engine/services/service.py +1 -4
  12. {api_foundry_query_engine-0.8.1 → api_foundry_query_engine-0.8.2}/api_foundry_query_engine/services/transactional_service.py +2 -2
  13. {api_foundry_query_engine-0.8.1 → api_foundry_query_engine-0.8.2}/api_foundry_query_engine/utils/api_model.py +25 -9
  14. {api_foundry_query_engine-0.8.1 → api_foundry_query_engine-0.8.2}/pyproject.toml +1 -1
  15. {api_foundry_query_engine-0.8.1 → api_foundry_query_engine-0.8.2}/LICENSE +0 -0
  16. {api_foundry_query_engine-0.8.1 → api_foundry_query_engine-0.8.2}/api_foundry_query_engine/__init__.py +0 -0
  17. {api_foundry_query_engine-0.8.1 → api_foundry_query_engine-0.8.2}/api_foundry_query_engine/adapters/case_change_adapter.py +0 -0
  18. {api_foundry_query_engine-0.8.1 → api_foundry_query_engine-0.8.2}/api_foundry_query_engine/adapters/gateway_adapter.py +0 -0
  19. {api_foundry_query_engine-0.8.1 → api_foundry_query_engine-0.8.2}/api_foundry_query_engine/adapters/security_adapter.py +0 -0
  20. {api_foundry_query_engine-0.8.1 → api_foundry_query_engine-0.8.2}/api_foundry_query_engine/connectors/athena_connector.py +0 -0
  21. {api_foundry_query_engine-0.8.1 → api_foundry_query_engine-0.8.2}/api_foundry_query_engine/connectors/connection.py +0 -0
  22. {api_foundry_query_engine-0.8.1 → api_foundry_query_engine-0.8.2}/api_foundry_query_engine/connectors/oracle_connector.py +0 -0
  23. {api_foundry_query_engine-0.8.1 → api_foundry_query_engine-0.8.2}/api_foundry_query_engine/connectors/postgres_connection.py +0 -0
  24. {api_foundry_query_engine-0.8.1 → api_foundry_query_engine-0.8.2}/api_foundry_query_engine/dao/dao.py +0 -0
  25. {api_foundry_query_engine-0.8.1 → api_foundry_query_engine-0.8.2}/api_foundry_query_engine/dao/sql_custom_query_handler.py +0 -0
  26. {api_foundry_query_engine-0.8.1 → api_foundry_query_engine-0.8.2}/api_foundry_query_engine/dao/sql_delete_query_handler.py +0 -0
  27. {api_foundry_query_engine-0.8.1 → api_foundry_query_engine-0.8.2}/api_foundry_query_engine/dao/sql_query_handler.py +0 -0
  28. {api_foundry_query_engine-0.8.1 → api_foundry_query_engine-0.8.2}/api_foundry_query_engine/dao/sql_subselect_query_handler.py +0 -0
  29. {api_foundry_query_engine-0.8.1 → api_foundry_query_engine-0.8.2}/api_foundry_query_engine/operation.py +0 -0
  30. {api_foundry_query_engine-0.8.1 → api_foundry_query_engine-0.8.2}/api_foundry_query_engine/services/security_service.py +0 -0
  31. {api_foundry_query_engine-0.8.1 → api_foundry_query_engine-0.8.2}/api_foundry_query_engine/utils/app_exception.py +0 -0
  32. {api_foundry_query_engine-0.8.1 → api_foundry_query_engine-0.8.2}/api_foundry_query_engine/utils/logger.py +0 -0
@@ -9,3 +9,5 @@ htmlcov/
9
9
  .coverage.*
10
10
  .coverage
11
11
  .vscode/
12
+ temp/
13
+ volume/
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: api-foundry-query-engine
3
- Version: 0.8.1
3
+ Version: 0.8.2
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,22 @@
1
+ repos:
2
+ - repo: https://github.com/pre-commit/pre-commit-hooks
3
+ rev: v3.4.0
4
+ hooks:
5
+ - id: trailing-whitespace
6
+ - id: end-of-file-fixer
7
+ - id: check-yaml
8
+ - id: check-added-large-files
9
+
10
+ - repo: https://github.com/psf/black
11
+ rev: 23.12.1
12
+ hooks:
13
+ - id: black
14
+ language_version: python3.11
15
+
16
+ - repo: https://github.com/PyCQA/flake8
17
+ rev: 7.0.0
18
+ hooks:
19
+ - id: flake8
20
+ args: [--max-line-length=120]
21
+
22
+ exclude: '^$'
@@ -10,7 +10,6 @@ log = logger(__name__)
10
10
 
11
11
 
12
12
  class Adapter(metaclass=abc.ABCMeta):
13
-
14
13
  service: Service
15
14
  config: Mapping[str, str]
16
15
 
@@ -23,9 +22,13 @@ class Adapter(metaclass=abc.ABCMeta):
23
22
  and callable(__subclass.unmarshal)
24
23
  )
25
24
 
26
- def __init__(self, config: Mapping[str, str] = {}, service: Optional[Service] = None) -> None:
25
+ def __init__(
26
+ self, config: Mapping[str, str] = {}, service: Optional[Service] = None
27
+ ) -> None:
27
28
  self.config = config
28
- self.service = service if service is not None else TransactionalService(config=self.config)
29
+ self.service = (
30
+ service if service is not None else TransactionalService(config=self.config)
31
+ )
29
32
 
30
33
  def unmarshal(self, event) -> Operation:
31
34
  """
@@ -1,7 +1,6 @@
1
1
  from typing import Mapping
2
2
  import boto3
3
3
  import json
4
- import os
5
4
 
6
5
  from api_foundry_query_engine.connectors.connection import Connection
7
6
  from api_foundry_query_engine.utils.app_exception import ApplicationException
@@ -20,7 +20,10 @@ from api_foundry_query_engine.utils.app_exception import ApplicationException
20
20
  from api_foundry_query_engine.dao.dao import DAO
21
21
  from api_foundry_query_engine.connectors.connection import Cursor
22
22
  from api_foundry_query_engine.operation import Operation
23
- from api_foundry_query_engine.utils.api_model import get_path_operation, get_schema_object
23
+ from api_foundry_query_engine.utils.api_model import (
24
+ get_path_operation,
25
+ get_schema_object,
26
+ )
24
27
  from api_foundry_query_engine.dao.sql_query_handler import SQLQueryHandler
25
28
 
26
29
 
@@ -83,9 +86,7 @@ class OperationDAO(DAO):
83
86
  )
84
87
  return self._query_handler
85
88
 
86
- def execute(
87
- self, connector, operation=None
88
- ) -> Union[list[dict], dict]:
89
+ def execute(self, connector, operation=None) -> Union[list[dict], dict]:
89
90
  """
90
91
  Execute the database operation based on the provided connector.
91
92
 
@@ -73,10 +73,15 @@ class SQLInsertSchemaQueryHandler(SQLSchemaQueryHandler):
73
73
  allowed_property_names = self.check_permissions(
74
74
  "write", self.schema_object.permissions, self.schema_object.properties
75
75
  )
76
- allowed_properties = {k: v for k, v in self.schema_object.properties.items() if k in allowed_property_names}
76
+ allowed_properties = {
77
+ k: v
78
+ for k, v in self.schema_object.properties.items()
79
+ if k in allowed_property_names
80
+ }
77
81
  log.info(f"allowed properties: {allowed_properties}")
78
82
 
79
83
  import json
84
+
80
85
  for name, value in self.operation.store_params.items():
81
86
  parts = name.split(".")
82
87
 
@@ -98,13 +103,17 @@ class SQLInsertSchemaQueryHandler(SQLSchemaQueryHandler):
98
103
 
99
104
  columns.append(property.column_name)
100
105
  if property.api_name is None:
101
- raise ApplicationException(400, f"Property '{name}' does not have a valid api_name.")
106
+ raise ApplicationException(
107
+ 400, f"Property '{name}' does not have a valid api_name."
108
+ )
102
109
  placeholders.append(self.placeholder(property, property.api_name))
103
110
  # Serialize embedded objects to JSON
104
111
  if property.api_type == "object":
105
112
  self.store_placeholders[property.api_name] = json.dumps(value)
106
113
  else:
107
- self.store_placeholders[property.api_name] = property.convert_to_db_value(value)
114
+ self.store_placeholders[
115
+ property.api_name
116
+ ] = property.convert_to_db_value(value)
108
117
 
109
118
  if self.key_property:
110
119
  if self.key_property.key_type == "sequence":
@@ -70,7 +70,7 @@ class SQLSelectSchemaQueryHandler(SQLSchemaQueryHandler):
70
70
  if self.schema_object.api_name is None:
71
71
  raise ApplicationException(
72
72
  500,
73
- "schema_object.api_name is None, cannot use as key in prefix_map"
73
+ "schema_object.api_name is None, cannot use as key in prefix_map",
74
74
  )
75
75
  prefix = self.prefix_map[self.schema_object.api_name]
76
76
  except KeyError:
@@ -80,7 +80,7 @@ class SQLSelectSchemaQueryHandler(SQLSchemaQueryHandler):
80
80
  + "schema object: "
81
81
  + str(self.schema_object.api_name)
82
82
  + ", property: "
83
- + name
83
+ + name,
84
84
  )
85
85
 
86
86
  assignment, holders = self.search_value_assignment(property, value, prefix)
@@ -42,29 +42,36 @@ class SQLUpdateSchemaQueryHandler(SQLSchemaQueryHandler):
42
42
  allowed_property_names = self.check_permissions(
43
43
  "write", self.schema_object.permissions, self.schema_object.properties
44
44
  )
45
- allowed_properties = {k: v for k, v in self.schema_object.properties.items() if k in allowed_property_names}
45
+ allowed_properties = {
46
+ k: v
47
+ for k, v in self.schema_object.properties.items()
48
+ if k in allowed_property_names
49
+ }
46
50
  self.store_placeholders = {}
47
51
  columns = []
48
52
  invalid_columns = []
49
53
 
50
54
  import json
55
+
51
56
  for name, value in self.operation.store_params.items():
52
57
  property = allowed_properties.get(name, None)
53
58
  if property is None:
54
59
  invalid_columns.append(name)
55
60
  continue
56
61
 
57
- placeholder = str(property.api_name) if property.api_name is not None else name
62
+ placeholder = (
63
+ str(property.api_name) if property.api_name is not None else name
64
+ )
58
65
  column_name = property.column_name
59
66
 
60
- columns.append(
61
- f"{column_name} = {self.placeholder(property, placeholder)}"
62
- )
67
+ columns.append(f"{column_name} = {self.placeholder(property, placeholder)}")
63
68
  # Serialize embedded objects to JSON
64
69
  if property.api_type == "object":
65
70
  self.store_placeholders[placeholder] = json.dumps(value)
66
71
  else:
67
- self.store_placeholders[placeholder] = property.convert_to_db_value(value)
72
+ self.store_placeholders[placeholder] = property.convert_to_db_value(
73
+ value
74
+ )
68
75
 
69
76
  if invalid_columns:
70
77
  raise ApplicationException(
@@ -1,21 +1,18 @@
1
- from fileinput import filename
2
1
  import json
3
2
  import logging
4
3
  import os
5
4
  from typing import Optional, Mapping
6
- import yaml
7
5
 
8
6
  from api_foundry_query_engine.utils.app_exception import ApplicationException
9
7
  from api_foundry_query_engine.adapters.gateway_adapter import GatewayAdapter
10
- from api_foundry_query_engine.utils.api_model import APIModel
11
8
 
12
9
  log = logging.getLogger(__name__)
13
10
 
14
11
  engine_config: Optional[Mapping[str, str]] = None
15
12
  adapter: Optional[GatewayAdapter] = None
16
13
 
17
- class QueryEngine:
18
14
 
15
+ class QueryEngine:
19
16
  def __init__(self, config: Mapping[str, str]):
20
17
  self.adapter = GatewayAdapter(config)
21
18
 
@@ -1,6 +1,5 @@
1
1
  import hashlib
2
2
  import json
3
- import os
4
3
 
5
4
  from api_foundry_query_engine.utils.logger import logger
6
5
  from api_foundry_query_engine.operation import Operation
@@ -8,7 +7,6 @@ from api_foundry_query_engine.operation import Operation
8
7
  log = logger(__name__)
9
8
 
10
9
 
11
-
12
10
  class Service:
13
11
  def __init__(self, config: dict = {}):
14
12
  self.config = config
@@ -17,7 +15,6 @@ class Service:
17
15
  raise NotImplementedError
18
16
 
19
17
 
20
-
21
18
  class ServiceAdapter(Service):
22
19
  def __init__(self, config: dict = {}):
23
20
  super().__init__(config)
@@ -26,7 +23,6 @@ class ServiceAdapter(Service):
26
23
  return super().execute(operation)
27
24
 
28
25
 
29
-
30
26
  class MutationPublisher(ServiceAdapter):
31
27
  def __init__(self, config: dict = {}):
32
28
  super().__init__(config)
@@ -65,6 +61,7 @@ class MutationPublisher(ServiceAdapter):
65
61
 
66
62
  def __client(self, client_type):
67
63
  import boto3
64
+
68
65
  region = self.config.get("AWS_REGION", "us-east-1")
69
66
  session = boto3.Session()
70
67
  if session:
@@ -1,5 +1,5 @@
1
1
  import traceback
2
- from typing import Optional, Mapping
2
+ from typing import Mapping
3
3
 
4
4
  from api_foundry_query_engine.utils.logger import logger
5
5
  from api_foundry_query_engine.utils.app_exception import ApplicationException
@@ -19,7 +19,7 @@ class TransactionalService(ServiceAdapter):
19
19
  def __init__(self, config: Mapping[str, str]):
20
20
  super().__init__()
21
21
  self.config = config
22
- self.connection_factory = ConnectionFactory(config)
22
+ self.connection_factory = ConnectionFactory(config)
23
23
 
24
24
  def execute(self, operation: Operation) -> list[dict]:
25
25
  path_operation = get_path_operation(operation.entity, operation.action)
@@ -4,25 +4,27 @@ import yaml
4
4
  from datetime import datetime
5
5
  from typing import Any, Dict, Mapping, Optional
6
6
 
7
- from api_foundry_query_engine.operation import Operation
8
7
  from api_foundry_query_engine.utils.logger import logger
9
8
 
10
9
  log = logger(__name__)
11
10
 
12
11
  api_model = None
13
12
 
13
+
14
14
  def get_schema_object(name: str) -> Optional["SchemaObject"]:
15
15
  global api_model
16
16
  if api_model is None:
17
17
  return None
18
18
  return api_model.schema_objects.get(name)
19
19
 
20
+
20
21
  def get_path_operation(path: str, method: str) -> Optional["PathOperation"]:
21
22
  global api_model
22
23
  if api_model is None:
23
24
  return None
24
25
  return api_model.path_operations.get(f"{path}_{method}")
25
26
 
27
+
26
28
  class SchemaObjectProperty:
27
29
  """Represents a property of a schema object."""
28
30
 
@@ -57,7 +59,9 @@ class SchemaObjectProperty:
57
59
  "date-time": lambda x: datetime.fromisoformat(x) if x else None,
58
60
  "time": lambda x: datetime.strptime(x, "%H:%M:%S").time() if x else None,
59
61
  }
60
- conversion_func = conversion_mapping.get(self.column_type if self.column_type is not None else "string", lambda x: x)
62
+ conversion_func = conversion_mapping.get(
63
+ self.column_type if self.column_type is not None else "string", lambda x: x
64
+ )
61
65
  return conversion_func(value)
62
66
 
63
67
  def convert_to_api_value(self, value) -> Optional[Any]:
@@ -73,7 +77,9 @@ class SchemaObjectProperty:
73
77
  "date-time": lambda x: x.isoformat() if x else None,
74
78
  "time": lambda x: x.time().isoformat() if x else None,
75
79
  }
76
- conversion_func = conversion_mapping.get(self.api_type if self.api_type is not None else "string", lambda x: x)
80
+ conversion_func = conversion_mapping.get(
81
+ self.api_type if self.api_type is not None else "string", lambda x: x
82
+ )
77
83
  return conversion_func(value)
78
84
 
79
85
 
@@ -101,7 +107,9 @@ class SchemaObjectAssociation:
101
107
  raise ValueError(f"Primary key not defined for schema '{self.schema_name}'")
102
108
  column_name = getattr(child_schema.primary_key, "column_name", None)
103
109
  if column_name is None:
104
- raise ValueError(f"Primary key property does not have 'column_name' for schema '{self.schema_name}'")
110
+ raise ValueError(
111
+ f"Primary key property does not have 'column_name' for schema '{self.schema_name}'"
112
+ )
105
113
  return column_name
106
114
 
107
115
  @property
@@ -112,10 +120,14 @@ class SchemaObjectAssociation:
112
120
  if not parent_schema_obj:
113
121
  raise ValueError(f"SchemaObject '{self.parent_schema}' not found")
114
122
  if not parent_schema_obj.primary_key:
115
- raise ValueError(f"Primary key not defined for schema '{self.parent_schema}'")
123
+ raise ValueError(
124
+ f"Primary key not defined for schema '{self.parent_schema}'"
125
+ )
116
126
  column_name = getattr(parent_schema_obj.primary_key, "column_name", None)
117
127
  if column_name is None:
118
- raise ValueError(f"Primary key property does not have 'column_name' for schema '{self.parent_schema}'")
128
+ raise ValueError(
129
+ f"Primary key property does not have 'column_name' for schema '{self.parent_schema}'"
130
+ )
119
131
  return column_name
120
132
 
121
133
  def __repr__(self):
@@ -147,7 +159,9 @@ class SchemaObject:
147
159
  for name, prop_data in data.get("properties", {}).items()
148
160
  }
149
161
  self.relations = {
150
- name: SchemaObjectAssociation(self.api_name if self.api_name is not None else "", assoc_data)
162
+ name: SchemaObjectAssociation(
163
+ self.api_name if self.api_name is not None else "", assoc_data
164
+ )
151
165
  for name, assoc_data in data.get("relations", {}).items()
152
166
  }
153
167
  self.concurrency_property = (
@@ -208,18 +222,20 @@ class APIModel:
208
222
  return None
209
223
  return self.path_operations.get(f"{path}_{method}")
210
224
 
211
-
212
225
  def __repr__(self):
213
226
  return (
214
227
  f"APIModel(schema_objects={list(self.schema_objects.keys())}, "
215
228
  + f"path_operations={list(self.path_operations.keys())})"
216
229
  )
217
230
 
231
+
218
232
  def set_api_model(engine_config: Mapping[str, str]):
219
233
  global api_model
220
234
  if api_model is None:
221
235
  if engine_config.get("API_SPEC"):
222
236
  api_model = APIModel(yaml.safe_load(engine_config["API_SPEC"]))
223
237
  else:
224
- with open(os.environ.get("API_SPEC", "/var/task/api_spec.yaml"), "r") as file:
238
+ with open(
239
+ os.environ.get("API_SPEC", "/var/task/api_spec.yaml"), "r"
240
+ ) as file:
225
241
  api_model = APIModel(yaml.safe_load(file))
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "api-foundry-query-engine"
7
- version = "0.8.1"
7
+ version = "0.8.2"
8
8
  authors = [
9
9
  { name="Daniel Repik", email="danrepik@icloud.com" },
10
10
  ]