api-foundry-query-engine 0.8.33__tar.gz → 0.8.34__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 (37) hide show
  1. {api_foundry_query_engine-0.8.33 → api_foundry_query_engine-0.8.34}/PKG-INFO +1 -1
  2. {api_foundry_query_engine-0.8.33 → api_foundry_query_engine-0.8.34}/api_foundry_query_engine/dao/sql_update_query_handler.py +86 -0
  3. {api_foundry_query_engine-0.8.33 → api_foundry_query_engine-0.8.34}/pyproject.toml +1 -1
  4. {api_foundry_query_engine-0.8.33 → api_foundry_query_engine-0.8.34}/.gitignore +0 -0
  5. {api_foundry_query_engine-0.8.33 → api_foundry_query_engine-0.8.34}/LICENSE +0 -0
  6. {api_foundry_query_engine-0.8.33 → api_foundry_query_engine-0.8.34}/api_foundry_query_engine/.pre-commit-config.yaml +0 -0
  7. {api_foundry_query_engine-0.8.33 → api_foundry_query_engine-0.8.34}/api_foundry_query_engine/__init__.py +0 -0
  8. {api_foundry_query_engine-0.8.33 → api_foundry_query_engine-0.8.34}/api_foundry_query_engine/adapters/adapter.py +0 -0
  9. {api_foundry_query_engine-0.8.33 → api_foundry_query_engine-0.8.34}/api_foundry_query_engine/adapters/case_change_adapter.py +0 -0
  10. {api_foundry_query_engine-0.8.33 → api_foundry_query_engine-0.8.34}/api_foundry_query_engine/adapters/gateway_adapter.py +0 -0
  11. {api_foundry_query_engine-0.8.33 → api_foundry_query_engine-0.8.34}/api_foundry_query_engine/adapters/security_adapter.py +0 -0
  12. {api_foundry_query_engine-0.8.33 → api_foundry_query_engine-0.8.34}/api_foundry_query_engine/connectors/connection.py +0 -0
  13. {api_foundry_query_engine-0.8.33 → api_foundry_query_engine-0.8.34}/api_foundry_query_engine/connectors/connection_factory.py +0 -0
  14. {api_foundry_query_engine-0.8.33 → api_foundry_query_engine-0.8.34}/api_foundry_query_engine/connectors/oracle_connector.py +0 -0
  15. {api_foundry_query_engine-0.8.33 → api_foundry_query_engine-0.8.34}/api_foundry_query_engine/connectors/postgres_connection.py +0 -0
  16. {api_foundry_query_engine-0.8.33 → api_foundry_query_engine-0.8.34}/api_foundry_query_engine/dao/batch_operation_handler.py +0 -0
  17. {api_foundry_query_engine-0.8.33 → api_foundry_query_engine-0.8.34}/api_foundry_query_engine/dao/dao.py +0 -0
  18. {api_foundry_query_engine-0.8.33 → api_foundry_query_engine-0.8.34}/api_foundry_query_engine/dao/operation_dao.py +0 -0
  19. {api_foundry_query_engine-0.8.33 → api_foundry_query_engine-0.8.34}/api_foundry_query_engine/dao/sql_custom_query_handler.py +0 -0
  20. {api_foundry_query_engine-0.8.33 → api_foundry_query_engine-0.8.34}/api_foundry_query_engine/dao/sql_delete_query_handler.py +0 -0
  21. {api_foundry_query_engine-0.8.33 → api_foundry_query_engine-0.8.34}/api_foundry_query_engine/dao/sql_insert_query_handler.py +0 -0
  22. {api_foundry_query_engine-0.8.33 → api_foundry_query_engine-0.8.34}/api_foundry_query_engine/dao/sql_query_handler.py +0 -0
  23. {api_foundry_query_engine-0.8.33 → api_foundry_query_engine-0.8.34}/api_foundry_query_engine/dao/sql_restore_query_handler.py +0 -0
  24. {api_foundry_query_engine-0.8.33 → api_foundry_query_engine-0.8.34}/api_foundry_query_engine/dao/sql_select_query_handler.py +0 -0
  25. {api_foundry_query_engine-0.8.33 → api_foundry_query_engine-0.8.34}/api_foundry_query_engine/dao/sql_subselect_query_handler.py +0 -0
  26. {api_foundry_query_engine-0.8.33 → api_foundry_query_engine-0.8.34}/api_foundry_query_engine/lambda_handler.py +0 -0
  27. {api_foundry_query_engine-0.8.33 → api_foundry_query_engine-0.8.34}/api_foundry_query_engine/operation.py +0 -0
  28. {api_foundry_query_engine-0.8.33 → api_foundry_query_engine-0.8.34}/api_foundry_query_engine/services/service.py +0 -0
  29. {api_foundry_query_engine-0.8.33 → api_foundry_query_engine-0.8.34}/api_foundry_query_engine/services/transactional_service.py +0 -0
  30. {api_foundry_query_engine-0.8.33 → api_foundry_query_engine-0.8.34}/api_foundry_query_engine/utils/api_model.py +0 -0
  31. {api_foundry_query_engine-0.8.33 → api_foundry_query_engine-0.8.34}/api_foundry_query_engine/utils/app_exception.py +0 -0
  32. {api_foundry_query_engine-0.8.33 → api_foundry_query_engine-0.8.34}/api_foundry_query_engine/utils/claims_check.py +0 -0
  33. {api_foundry_query_engine-0.8.33 → api_foundry_query_engine-0.8.34}/api_foundry_query_engine/utils/dependency_resolver.py +0 -0
  34. {api_foundry_query_engine-0.8.33 → api_foundry_query_engine-0.8.34}/api_foundry_query_engine/utils/gateway_operation.py +0 -0
  35. {api_foundry_query_engine-0.8.33 → api_foundry_query_engine-0.8.34}/api_foundry_query_engine/utils/logger.py +0 -0
  36. {api_foundry_query_engine-0.8.33 → api_foundry_query_engine-0.8.34}/api_foundry_query_engine/utils/reference_resolver.py +0 -0
  37. {api_foundry_query_engine-0.8.33 → api_foundry_query_engine-0.8.34}/api_foundry_query_engine/utils/token_decoder.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: api-foundry-query-engine
3
- Version: 0.8.33
3
+ Version: 0.8.34
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
@@ -1,3 +1,5 @@
1
+ import re
2
+ from typing import Match
1
3
  from api_foundry_query_engine.dao.sql_query_handler import SQLSchemaQueryHandler
2
4
  from api_foundry_query_engine.operation import Operation
3
5
  from api_foundry_query_engine.utils.app_exception import ApplicationException
@@ -10,6 +12,68 @@ class SQLUpdateSchemaQueryHandler(SQLSchemaQueryHandler):
10
12
  ) -> None:
11
13
  super().__init__(operation, schema_object, engine)
12
14
 
15
+ def _template_where(self, expr: str) -> str:
16
+ """Template substitution for WHERE clause expressions with claim values."""
17
+ if not expr:
18
+ return expr
19
+
20
+ def _quote(val: object) -> str:
21
+ if val is None:
22
+ return "NULL"
23
+ if isinstance(val, (int, float)):
24
+ return str(val)
25
+ s = str(val).replace("'", "''")
26
+ return f"'{s}'"
27
+
28
+ def _replace(m: Match[str]) -> str:
29
+ key = m.group(1)
30
+ claims = self.operation.claims or {}
31
+ return _quote(claims.get(key))
32
+
33
+ return re.sub(r"\$\{claims\.([A-Za-z0-9_]+)\}", _replace, expr)
34
+
35
+ def _row_where_clause(self) -> str:
36
+ """
37
+ Generate row-level WHERE clause based on write permissions.
38
+ Only applies to UPDATE operations, not CREATE.
39
+ """
40
+ perms = getattr(self.schema_object, "permissions", None) or {}
41
+ # provider-first default
42
+ if "default" in perms:
43
+ provider = perms.get("default", {}) or {}
44
+ write_map = provider.get("write", {}) or {}
45
+ role_permissions = perms.get("default", {})
46
+ else:
47
+ # legacy role-first -> synthesize write map
48
+ write_map = {}
49
+ role_permissions = perms
50
+ for role, role_perms in perms.items():
51
+ if isinstance(role_perms, dict):
52
+ write_map[role] = role_perms.get("write")
53
+
54
+ filters = []
55
+ for role in self.operation.roles or []:
56
+ # Check for role-level WHERE clause (hybrid approach)
57
+ role_where = None
58
+ if isinstance(role_permissions.get(role), dict):
59
+ role_where = role_permissions[role].get("where")
60
+
61
+ # Check for operation-level WHERE clause
62
+ operation_where = None
63
+ rule = write_map.get(role)
64
+ if isinstance(rule, dict):
65
+ operation_where = rule.get("where")
66
+
67
+ # Operation-level takes precedence, fallback to role-level
68
+ where_clause = operation_where if operation_where else role_where
69
+
70
+ if isinstance(where_clause, str) and where_clause.strip():
71
+ filters.append(self._template_where(where_clause))
72
+
73
+ if not filters:
74
+ return ""
75
+ return "(" + ") OR (".join(filters) + ")"
76
+
13
77
  @property
14
78
  def sql(self) -> str:
15
79
  concurrency_property = self.schema_object.concurrency_property
@@ -109,3 +173,25 @@ class SQLUpdateSchemaQueryHandler(SQLSchemaQueryHandler):
109
173
  f"Subject does not have permission to update properties: {invalid_columns}",
110
174
  )
111
175
  return f" SET {', '.join(columns)}"
176
+
177
+ @property
178
+ def search_condition(self) -> str:
179
+ """
180
+ Override to add permission-based WHERE clause for UPDATE operations.
181
+ """
182
+ # Get the base search condition from parent class
183
+ base_condition = super().search_condition
184
+
185
+ # Get row-level permission filters
186
+ row_filter = self._row_where_clause()
187
+
188
+ # If we have both, combine them
189
+ if base_condition and row_filter:
190
+ # base_condition already has " WHERE ", so add AND
191
+ return f"{base_condition} AND ({row_filter})"
192
+ elif row_filter:
193
+ # Only row filter, add WHERE prefix
194
+ return f" WHERE ({row_filter})"
195
+ else:
196
+ # Only base condition or neither
197
+ return base_condition
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "api-foundry-query-engine"
7
- version = "0.8.33"
7
+ version = "0.8.34"
8
8
  authors = [
9
9
  { name="Daniel Repik", email="danrepik@icloud.com" },
10
10
  ]