mdb-engine 0.1.6__py3-none-any.whl → 0.4.12__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.
Files changed (92) hide show
  1. mdb_engine/__init__.py +116 -11
  2. mdb_engine/auth/ARCHITECTURE.md +112 -0
  3. mdb_engine/auth/README.md +654 -11
  4. mdb_engine/auth/__init__.py +136 -29
  5. mdb_engine/auth/audit.py +592 -0
  6. mdb_engine/auth/base.py +252 -0
  7. mdb_engine/auth/casbin_factory.py +265 -70
  8. mdb_engine/auth/config_defaults.py +5 -5
  9. mdb_engine/auth/config_helpers.py +19 -18
  10. mdb_engine/auth/cookie_utils.py +12 -16
  11. mdb_engine/auth/csrf.py +483 -0
  12. mdb_engine/auth/decorators.py +10 -16
  13. mdb_engine/auth/dependencies.py +69 -71
  14. mdb_engine/auth/helpers.py +3 -3
  15. mdb_engine/auth/integration.py +61 -88
  16. mdb_engine/auth/jwt.py +11 -15
  17. mdb_engine/auth/middleware.py +79 -35
  18. mdb_engine/auth/oso_factory.py +21 -41
  19. mdb_engine/auth/provider.py +270 -171
  20. mdb_engine/auth/rate_limiter.py +505 -0
  21. mdb_engine/auth/restrictions.py +21 -36
  22. mdb_engine/auth/session_manager.py +24 -41
  23. mdb_engine/auth/shared_middleware.py +977 -0
  24. mdb_engine/auth/shared_users.py +775 -0
  25. mdb_engine/auth/token_lifecycle.py +10 -12
  26. mdb_engine/auth/token_store.py +17 -32
  27. mdb_engine/auth/users.py +99 -159
  28. mdb_engine/auth/utils.py +236 -42
  29. mdb_engine/cli/commands/generate.py +546 -10
  30. mdb_engine/cli/commands/validate.py +3 -7
  31. mdb_engine/cli/utils.py +7 -7
  32. mdb_engine/config.py +13 -28
  33. mdb_engine/constants.py +65 -0
  34. mdb_engine/core/README.md +117 -6
  35. mdb_engine/core/__init__.py +39 -7
  36. mdb_engine/core/app_registration.py +31 -50
  37. mdb_engine/core/app_secrets.py +289 -0
  38. mdb_engine/core/connection.py +20 -12
  39. mdb_engine/core/encryption.py +222 -0
  40. mdb_engine/core/engine.py +2862 -115
  41. mdb_engine/core/index_management.py +12 -16
  42. mdb_engine/core/manifest.py +628 -204
  43. mdb_engine/core/ray_integration.py +436 -0
  44. mdb_engine/core/seeding.py +13 -21
  45. mdb_engine/core/service_initialization.py +20 -30
  46. mdb_engine/core/types.py +40 -43
  47. mdb_engine/database/README.md +140 -17
  48. mdb_engine/database/__init__.py +17 -6
  49. mdb_engine/database/abstraction.py +37 -50
  50. mdb_engine/database/connection.py +51 -30
  51. mdb_engine/database/query_validator.py +367 -0
  52. mdb_engine/database/resource_limiter.py +204 -0
  53. mdb_engine/database/scoped_wrapper.py +747 -237
  54. mdb_engine/dependencies.py +427 -0
  55. mdb_engine/di/__init__.py +34 -0
  56. mdb_engine/di/container.py +247 -0
  57. mdb_engine/di/providers.py +206 -0
  58. mdb_engine/di/scopes.py +139 -0
  59. mdb_engine/embeddings/README.md +54 -24
  60. mdb_engine/embeddings/__init__.py +31 -24
  61. mdb_engine/embeddings/dependencies.py +38 -155
  62. mdb_engine/embeddings/service.py +78 -75
  63. mdb_engine/exceptions.py +104 -12
  64. mdb_engine/indexes/README.md +30 -13
  65. mdb_engine/indexes/__init__.py +1 -0
  66. mdb_engine/indexes/helpers.py +11 -11
  67. mdb_engine/indexes/manager.py +59 -123
  68. mdb_engine/memory/README.md +95 -4
  69. mdb_engine/memory/__init__.py +1 -2
  70. mdb_engine/memory/service.py +363 -1168
  71. mdb_engine/observability/README.md +4 -2
  72. mdb_engine/observability/__init__.py +26 -9
  73. mdb_engine/observability/health.py +17 -17
  74. mdb_engine/observability/logging.py +10 -10
  75. mdb_engine/observability/metrics.py +40 -19
  76. mdb_engine/repositories/__init__.py +34 -0
  77. mdb_engine/repositories/base.py +325 -0
  78. mdb_engine/repositories/mongo.py +233 -0
  79. mdb_engine/repositories/unit_of_work.py +166 -0
  80. mdb_engine/routing/README.md +1 -1
  81. mdb_engine/routing/__init__.py +1 -3
  82. mdb_engine/routing/websockets.py +41 -75
  83. mdb_engine/utils/__init__.py +3 -1
  84. mdb_engine/utils/mongo.py +117 -0
  85. mdb_engine-0.4.12.dist-info/METADATA +492 -0
  86. mdb_engine-0.4.12.dist-info/RECORD +97 -0
  87. {mdb_engine-0.1.6.dist-info → mdb_engine-0.4.12.dist-info}/WHEEL +1 -1
  88. mdb_engine-0.1.6.dist-info/METADATA +0 -213
  89. mdb_engine-0.1.6.dist-info/RECORD +0 -75
  90. {mdb_engine-0.1.6.dist-info → mdb_engine-0.4.12.dist-info}/entry_points.txt +0 -0
  91. {mdb_engine-0.1.6.dist-info → mdb_engine-0.4.12.dist-info}/licenses/LICENSE +0 -0
  92. {mdb_engine-0.1.6.dist-info → mdb_engine-0.4.12.dist-info}/top_level.txt +0 -0
mdb_engine/exceptions.py CHANGED
@@ -5,7 +5,7 @@ These exceptions provide more specific error types while maintaining
5
5
  backward compatibility with RuntimeError.
6
6
  """
7
7
 
8
- from typing import Any, Dict, List, Optional
8
+ from typing import Any
9
9
 
10
10
 
11
11
  class MongoDBEngineError(RuntimeError):
@@ -21,7 +21,7 @@ class MongoDBEngineError(RuntimeError):
21
21
  collection_name, etc.)
22
22
  """
23
23
 
24
- def __init__(self, message: str, context: Optional[Dict[str, Any]] = None) -> None:
24
+ def __init__(self, message: str, context: dict[str, Any] | None = None) -> None:
25
25
  """
26
26
  Initialize the exception.
27
27
 
@@ -58,9 +58,9 @@ class InitializationError(MongoDBEngineError):
58
58
  def __init__(
59
59
  self,
60
60
  message: str,
61
- mongo_uri: Optional[str] = None,
62
- db_name: Optional[str] = None,
63
- context: Optional[Dict[str, Any]] = None,
61
+ mongo_uri: str | None = None,
62
+ db_name: str | None = None,
63
+ context: dict[str, Any] | None = None,
64
64
  ) -> None:
65
65
  """
66
66
  Initialize the initialization error.
@@ -99,10 +99,10 @@ class ManifestValidationError(MongoDBEngineError):
99
99
  def __init__(
100
100
  self,
101
101
  message: str,
102
- error_paths: Optional[List[str]] = None,
103
- manifest_slug: Optional[str] = None,
104
- schema_version: Optional[str] = None,
105
- context: Optional[Dict[str, Any]] = None,
102
+ error_paths: list[str] | None = None,
103
+ manifest_slug: str | None = None,
104
+ schema_version: str | None = None,
105
+ context: dict[str, Any] | None = None,
106
106
  ) -> None:
107
107
  """
108
108
  Initialize the manifest validation error.
@@ -144,9 +144,9 @@ class ConfigurationError(MongoDBEngineError):
144
144
  def __init__(
145
145
  self,
146
146
  message: str,
147
- config_key: Optional[str] = None,
148
- config_value: Optional[Any] = None,
149
- context: Optional[Dict[str, Any]] = None,
147
+ config_key: str | None = None,
148
+ config_value: Any | None = None,
149
+ context: dict[str, Any] | None = None,
150
150
  ) -> None:
151
151
  """
152
152
  Initialize the configuration error.
@@ -165,3 +165,95 @@ class ConfigurationError(MongoDBEngineError):
165
165
  super().__init__(message, context=context)
166
166
  self.config_key = config_key
167
167
  self.config_value = config_value
168
+
169
+
170
+ class QueryValidationError(MongoDBEngineError):
171
+ """
172
+ Raised when a query fails validation checks.
173
+
174
+ This exception is raised when a query contains dangerous operators,
175
+ exceeds complexity limits, or violates security policies.
176
+
177
+ Attributes:
178
+ message: Error message
179
+ query_type: Type of query that failed (filter, pipeline, etc.)
180
+ operator: Dangerous operator that was found (if applicable)
181
+ path: JSON path where the issue was found (if applicable)
182
+ context: Additional context information
183
+ """
184
+
185
+ def __init__(
186
+ self,
187
+ message: str,
188
+ query_type: str | None = None,
189
+ operator: str | None = None,
190
+ path: str | None = None,
191
+ context: dict[str, Any] | None = None,
192
+ ) -> None:
193
+ """
194
+ Initialize the query validation error.
195
+
196
+ Args:
197
+ message: Error message
198
+ query_type: Type of query that failed (filter, pipeline, etc.)
199
+ operator: Dangerous operator that was found (if applicable)
200
+ path: JSON path where the issue was found (if applicable)
201
+ context: Additional context information
202
+ """
203
+ context = context or {}
204
+ if query_type:
205
+ context["query_type"] = query_type
206
+ if operator:
207
+ context["operator"] = operator
208
+ if path:
209
+ context["path"] = path
210
+ super().__init__(message, context=context)
211
+ self.query_type = query_type
212
+ self.operator = operator
213
+ self.path = path
214
+
215
+
216
+ class ResourceLimitExceeded(MongoDBEngineError):
217
+ """
218
+ Raised when a resource limit is exceeded.
219
+
220
+ This exception is raised when queries exceed timeouts, result sizes,
221
+ or other resource limits.
222
+
223
+ Attributes:
224
+ message: Error message
225
+ limit_type: Type of limit that was exceeded (timeout, size, etc.)
226
+ limit_value: The limit value that was exceeded
227
+ actual_value: The actual value that exceeded the limit
228
+ context: Additional context information
229
+ """
230
+
231
+ def __init__(
232
+ self,
233
+ message: str,
234
+ limit_type: str | None = None,
235
+ limit_value: Any | None = None,
236
+ actual_value: Any | None = None,
237
+ context: dict[str, Any] | None = None,
238
+ ) -> None:
239
+ """
240
+ Initialize the resource limit exceeded error.
241
+
242
+ Args:
243
+ message: Error message
244
+ limit_type: Type of limit that was exceeded (timeout, size, etc.)
245
+ limit_value: The limit value that was exceeded
246
+ actual_value: The actual value that exceeded the limit
247
+ context: Additional context information
248
+ """
249
+ context = context or {}
250
+ if limit_type:
251
+ context["limit_type"] = limit_type
252
+ if limit_value is not None:
253
+ context["limit_value"] = limit_value
254
+ if actual_value is not None:
255
+ context["actual_value"] = actual_value
256
+ super().__init__(message, context=context)
257
+ self.limit_type = limit_type
258
+ self.limit_value = limit_value
259
+ self.actual_value = actual_value
@@ -573,7 +573,7 @@ try:
573
573
  collection_name="users",
574
574
  index_definitions=index_definitions
575
575
  )
576
- except Exception as e:
576
+ except (PyMongoError, ValueError, TypeError) as e:
577
577
  logger.error(f"Failed to create indexes: {e}", exc_info=True)
578
578
  raise
579
579
  ```
@@ -613,12 +613,20 @@ index_definitions = [
613
613
  }
614
614
  ]
615
615
 
616
- await run_index_creation_for_collection(
617
- db=engine.mongo_db,
618
- slug="my_app",
619
- collection_name="users",
620
- index_definitions=index_definitions
621
- )
616
+ # Get scoped database and collection
617
+ db = engine.get_scoped_db("my_app")
618
+ collection = db.users
619
+
620
+ # Use collection.index_manager for index operations
621
+ index_manager = collection.index_manager
622
+ for index_def in index_definitions:
623
+ if index_def["type"] == "regular":
624
+ await index_manager.create_index(
625
+ keys=list(index_def["keys"].items()),
626
+ name=index_def.get("name"),
627
+ **index_def.get("options", {})
628
+ )
629
+ # Handle other index types similarly...
622
630
  ```
623
631
 
624
632
  ### Multiple Collections
@@ -635,13 +643,22 @@ collections_with_indexes = {
635
643
  ]
636
644
  }
637
645
 
646
+ # Get scoped database
647
+ db = engine.get_scoped_db("my_app")
648
+
649
+ # Use collection.index_manager for each collection
638
650
  for collection_name, index_definitions in collections_with_indexes.items():
639
- await run_index_creation_for_collection(
640
- db=engine.mongo_db,
641
- slug="my_app",
642
- collection_name=collection_name,
643
- index_definitions=index_definitions
644
- )
651
+ collection = getattr(db, collection_name)
652
+ index_manager = collection.index_manager
653
+
654
+ for index_def in index_definitions:
655
+ if index_def["type"] == "regular":
656
+ await index_manager.create_index(
657
+ keys=list(index_def["keys"].items()),
658
+ name=index_def.get("name"),
659
+ **index_def.get("options", {})
660
+ )
661
+ # Handle other index types similarly...
645
662
  ```
646
663
 
647
664
  ## Related Modules
@@ -8,6 +8,7 @@ This module is part of MDB_ENGINE - MongoDB Engine.
8
8
 
9
9
  # Re-export index managers from database module for convenience
10
10
  from ..database.scoped_wrapper import AsyncAtlasIndexManager, AutoIndexManager
11
+
11
12
  # Export high-level management functions
12
13
  from .manager import normalize_json_def, run_index_creation_for_collection
13
14
 
@@ -6,14 +6,14 @@ in index creation and management.
6
6
  """
7
7
 
8
8
  import logging
9
- from typing import Any, Dict, List, Optional, Tuple, Union
9
+ from typing import Any
10
10
 
11
11
  logger = logging.getLogger(__name__)
12
12
 
13
13
 
14
14
  def normalize_keys(
15
- keys: Union[Dict[str, Any], List[Tuple[str, Any]]]
16
- ) -> List[Tuple[str, Any]]:
15
+ keys: dict[str, Any] | list[tuple[str, Any]],
16
+ ) -> list[tuple[str, Any]]:
17
17
  """
18
18
  Normalize index keys to a consistent format.
19
19
 
@@ -28,7 +28,7 @@ def normalize_keys(
28
28
  return keys
29
29
 
30
30
 
31
- def keys_to_dict(keys: Union[Dict[str, Any], List[Tuple[str, Any]]]) -> Dict[str, Any]:
31
+ def keys_to_dict(keys: dict[str, Any] | list[tuple[str, Any]]) -> dict[str, Any]:
32
32
  """
33
33
  Convert index keys to dictionary format for comparison.
34
34
 
@@ -43,7 +43,7 @@ def keys_to_dict(keys: Union[Dict[str, Any], List[Tuple[str, Any]]]) -> Dict[str
43
43
  return {k: v for k, v in keys}
44
44
 
45
45
 
46
- def is_id_index(keys: Union[Dict[str, Any], List[Tuple[str, Any]]]) -> bool:
46
+ def is_id_index(keys: dict[str, Any] | list[tuple[str, Any]]) -> bool:
47
47
  """
48
48
  Check if index keys target the _id field (which MongoDB creates automatically).
49
49
 
@@ -63,10 +63,10 @@ def is_id_index(keys: Union[Dict[str, Any], List[Tuple[str, Any]]]) -> bool:
63
63
  async def check_and_update_index(
64
64
  index_manager: Any,
65
65
  index_name: str,
66
- expected_keys: Union[Dict[str, Any], List[Tuple[str, Any]]],
67
- expected_options: Optional[Dict[str, Any]] = None,
66
+ expected_keys: dict[str, Any] | list[tuple[str, Any]],
67
+ expected_options: dict[str, Any] | None = None,
68
68
  log_prefix: str = "",
69
- ) -> Tuple[bool, Optional[Dict[str, Any]]]:
69
+ ) -> tuple[bool, dict[str, Any] | None]:
70
70
  """
71
71
  Check if an index exists and matches the expected definition.
72
72
 
@@ -118,11 +118,11 @@ async def check_and_update_index(
118
118
 
119
119
 
120
120
  def validate_index_definition_basic(
121
- index_def: Dict[str, Any],
121
+ index_def: dict[str, Any],
122
122
  index_name: str,
123
- required_fields: List[str],
123
+ required_fields: list[str],
124
124
  log_prefix: str = "",
125
- ) -> Tuple[bool, Optional[str]]:
125
+ ) -> tuple[bool, str | None]:
126
126
  """
127
127
  Basic validation for index definitions.
128
128