mdb-engine 0.1.6__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 (75) hide show
  1. mdb_engine/README.md +144 -0
  2. mdb_engine/__init__.py +37 -0
  3. mdb_engine/auth/README.md +631 -0
  4. mdb_engine/auth/__init__.py +128 -0
  5. mdb_engine/auth/casbin_factory.py +199 -0
  6. mdb_engine/auth/casbin_models.py +46 -0
  7. mdb_engine/auth/config_defaults.py +71 -0
  8. mdb_engine/auth/config_helpers.py +213 -0
  9. mdb_engine/auth/cookie_utils.py +158 -0
  10. mdb_engine/auth/decorators.py +350 -0
  11. mdb_engine/auth/dependencies.py +747 -0
  12. mdb_engine/auth/helpers.py +64 -0
  13. mdb_engine/auth/integration.py +578 -0
  14. mdb_engine/auth/jwt.py +225 -0
  15. mdb_engine/auth/middleware.py +241 -0
  16. mdb_engine/auth/oso_factory.py +323 -0
  17. mdb_engine/auth/provider.py +570 -0
  18. mdb_engine/auth/restrictions.py +271 -0
  19. mdb_engine/auth/session_manager.py +477 -0
  20. mdb_engine/auth/token_lifecycle.py +213 -0
  21. mdb_engine/auth/token_store.py +289 -0
  22. mdb_engine/auth/users.py +1516 -0
  23. mdb_engine/auth/utils.py +614 -0
  24. mdb_engine/cli/__init__.py +13 -0
  25. mdb_engine/cli/commands/__init__.py +7 -0
  26. mdb_engine/cli/commands/generate.py +105 -0
  27. mdb_engine/cli/commands/migrate.py +83 -0
  28. mdb_engine/cli/commands/show.py +70 -0
  29. mdb_engine/cli/commands/validate.py +63 -0
  30. mdb_engine/cli/main.py +41 -0
  31. mdb_engine/cli/utils.py +92 -0
  32. mdb_engine/config.py +217 -0
  33. mdb_engine/constants.py +160 -0
  34. mdb_engine/core/README.md +542 -0
  35. mdb_engine/core/__init__.py +42 -0
  36. mdb_engine/core/app_registration.py +392 -0
  37. mdb_engine/core/connection.py +243 -0
  38. mdb_engine/core/engine.py +749 -0
  39. mdb_engine/core/index_management.py +162 -0
  40. mdb_engine/core/manifest.py +2793 -0
  41. mdb_engine/core/seeding.py +179 -0
  42. mdb_engine/core/service_initialization.py +355 -0
  43. mdb_engine/core/types.py +413 -0
  44. mdb_engine/database/README.md +522 -0
  45. mdb_engine/database/__init__.py +31 -0
  46. mdb_engine/database/abstraction.py +635 -0
  47. mdb_engine/database/connection.py +387 -0
  48. mdb_engine/database/scoped_wrapper.py +1721 -0
  49. mdb_engine/embeddings/README.md +184 -0
  50. mdb_engine/embeddings/__init__.py +62 -0
  51. mdb_engine/embeddings/dependencies.py +193 -0
  52. mdb_engine/embeddings/service.py +759 -0
  53. mdb_engine/exceptions.py +167 -0
  54. mdb_engine/indexes/README.md +651 -0
  55. mdb_engine/indexes/__init__.py +21 -0
  56. mdb_engine/indexes/helpers.py +145 -0
  57. mdb_engine/indexes/manager.py +895 -0
  58. mdb_engine/memory/README.md +451 -0
  59. mdb_engine/memory/__init__.py +30 -0
  60. mdb_engine/memory/service.py +1285 -0
  61. mdb_engine/observability/README.md +515 -0
  62. mdb_engine/observability/__init__.py +42 -0
  63. mdb_engine/observability/health.py +296 -0
  64. mdb_engine/observability/logging.py +161 -0
  65. mdb_engine/observability/metrics.py +297 -0
  66. mdb_engine/routing/README.md +462 -0
  67. mdb_engine/routing/__init__.py +73 -0
  68. mdb_engine/routing/websockets.py +813 -0
  69. mdb_engine/utils/__init__.py +7 -0
  70. mdb_engine-0.1.6.dist-info/METADATA +213 -0
  71. mdb_engine-0.1.6.dist-info/RECORD +75 -0
  72. mdb_engine-0.1.6.dist-info/WHEEL +5 -0
  73. mdb_engine-0.1.6.dist-info/entry_points.txt +2 -0
  74. mdb_engine-0.1.6.dist-info/licenses/LICENSE +661 -0
  75. mdb_engine-0.1.6.dist-info/top_level.txt +1 -0
@@ -0,0 +1,522 @@
1
+ # Database Module
2
+
3
+ Database abstraction layer providing app-scoped database access with automatic data isolation, connection pooling, and MongoDB-style API.
4
+
5
+ ## Features
6
+
7
+ - **Scoped Database Wrappers**: Automatic app-level data isolation
8
+ - **Connection Pooling**: Shared MongoDB connection pool for efficiency
9
+ - **MongoDB-Style API**: Familiar Motor/pymongo API with automatic scoping
10
+ - **AutoIndexManager**: Automatic index creation based on query patterns
11
+ - **AsyncAtlasIndexManager**: Async-native interface for Atlas Search/Vector indexes
12
+ - **AppDB Abstraction**: High-level database abstraction for FastAPI
13
+
14
+ ## Installation
15
+
16
+ The database module is part of MDB_ENGINE. No additional installation required.
17
+
18
+ ## Quick Start
19
+
20
+ ### Basic Usage
21
+
22
+ ```python
23
+ from mdb_engine.database import ScopedMongoWrapper
24
+ from mdb_engine.core import MongoDBEngine
25
+
26
+ # Get scoped database from engine
27
+ engine = MongoDBEngine(mongo_uri="...", db_name="...")
28
+ await engine.initialize()
29
+
30
+ db = engine.get_scoped_db("my_app")
31
+
32
+ # All queries automatically scoped to "my_app"
33
+ docs = await db.my_collection.find({"status": "active"}).to_list(length=10)
34
+ await db.my_collection.insert_one({"name": "Test", "status": "active"})
35
+ ```
36
+
37
+ ## ScopedMongoWrapper
38
+
39
+ The `ScopedMongoWrapper` provides automatic app-level data isolation. All read operations are automatically filtered by `app_id`, and all write operations automatically include `app_id`.
40
+
41
+ ### Basic Usage
42
+
43
+ ```python
44
+ from mdb_engine.database import ScopedMongoWrapper
45
+ from motor.motor_asyncio import AsyncIOMotorDatabase
46
+
47
+ # Create scoped wrapper
48
+ db = ScopedMongoWrapper(
49
+ real_db=mongo_db,
50
+ read_scopes=["my_app"], # Can read from these apps
51
+ write_scope="my_app", # Write to this app
52
+ auto_index=True # Enable automatic indexing
53
+ )
54
+
55
+ # Access collections (MongoDB-style)
56
+ collection = db.my_collection
57
+
58
+ # All operations automatically scoped
59
+ doc = await collection.find_one({"name": "test"})
60
+ docs = await collection.find({"status": "active"}).to_list(length=10)
61
+ await collection.insert_one({"name": "new_doc"})
62
+ ```
63
+
64
+ ### Cross-App Data Access
65
+
66
+ Read from multiple apps while writing to one:
67
+
68
+ ```python
69
+ # Read from multiple apps, write to one
70
+ db = ScopedMongoWrapper(
71
+ real_db=mongo_db,
72
+ read_scopes=["app1", "app2", "shared"], # Can read from these
73
+ write_scope="app1" # Write to this one
74
+ )
75
+
76
+ # Queries will search across app1, app2, and shared
77
+ docs = await db.collection.find({}).to_list(length=100)
78
+ ```
79
+
80
+ ## ScopedCollectionWrapper
81
+
82
+ The `ScopedCollectionWrapper` automatically injects `app_id` filters into all read operations and adds `app_id` to all write operations.
83
+
84
+ ### Read Operations
85
+
86
+ All read operations are automatically scoped:
87
+
88
+ ```python
89
+ collection = db.my_collection
90
+
91
+ # find_one - automatically filters by app_id
92
+ doc = await collection.find_one({"name": "test"})
93
+ # Equivalent to: find_one({"name": "test", "app_id": {"$in": read_scopes}})
94
+
95
+ # find - automatically filters by app_id
96
+ cursor = collection.find({"status": "active"})
97
+ docs = await cursor.to_list(length=10)
98
+
99
+ # count_documents - automatically filters by app_id
100
+ count = await collection.count_documents({"status": "active"})
101
+
102
+ # aggregate - automatically filters by app_id
103
+ pipeline = [{"$match": {"status": "active"}}, {"$group": {"_id": "$category"}}]
104
+ results = await collection.aggregate(pipeline).to_list(length=100)
105
+ ```
106
+
107
+ ### Write Operations
108
+
109
+ All write operations automatically include `app_id`:
110
+
111
+ ```python
112
+ # insert_one - automatically adds app_id
113
+ result = await collection.insert_one({"name": "New Document"})
114
+ # Document stored as: {"name": "New Document", "app_id": "my_app"}
115
+
116
+ # insert_many - automatically adds app_id to each document
117
+ result = await collection.insert_many([
118
+ {"name": "Doc 1"},
119
+ {"name": "Doc 2"}
120
+ ])
121
+
122
+ # update_one/update_many - automatically filters by app_id
123
+ result = await collection.update_one(
124
+ {"name": "test"},
125
+ {"$set": {"status": "updated"}}
126
+ )
127
+
128
+ # delete_one/delete_many - automatically filters by app_id
129
+ result = await collection.delete_one({"name": "test"})
130
+ ```
131
+
132
+ ### Direct Collection Access
133
+
134
+ Access the underlying unscoped collection for administrative operations:
135
+
136
+ ```python
137
+ # Get unscoped collection (bypasses app_id filtering)
138
+ real_collection = collection._collection
139
+
140
+ # Use for admin operations (use with caution!)
141
+ await real_collection.create_index([("field", 1)])
142
+ ```
143
+
144
+ ## AutoIndexManager
145
+
146
+ Automatic index creation based on query patterns. Enabled by default for all collections.
147
+
148
+ ### How It Works
149
+
150
+ The `AutoIndexManager` monitors query patterns and automatically creates indexes to optimize performance:
151
+
152
+ ```python
153
+ # AutoIndexManager is enabled by default
154
+ db = ScopedMongoWrapper(real_db=mongo_db, read_scopes=["my_app"])
155
+
156
+ # First query - no index yet
157
+ docs = await db.collection.find({"status": "active"}).to_list(length=10)
158
+
159
+ # AutoIndexManager detects the query pattern and creates an index
160
+ # Subsequent queries are optimized automatically
161
+ ```
162
+
163
+ ### Disable Auto-Indexing
164
+
165
+ ```python
166
+ # Disable automatic indexing
167
+ db = ScopedMongoWrapper(
168
+ real_db=mongo_db,
169
+ read_scopes=["my_app"],
170
+ auto_index=False # Disable automatic indexing
171
+ )
172
+ ```
173
+
174
+ ## AsyncAtlasIndexManager
175
+
176
+ Async-native interface for managing Atlas Search and Vector indexes.
177
+
178
+ ### Basic Usage
179
+
180
+ ```python
181
+ from mdb_engine.database import AsyncAtlasIndexManager
182
+
183
+ # Get index manager from collection
184
+ collection = db.my_collection
185
+ index_manager = AsyncAtlasIndexManager(collection._collection) # Use unscoped collection
186
+
187
+ # Create vector search index
188
+ await index_manager.create_vector_search_index(
189
+ name="vector_idx",
190
+ definition={
191
+ "fields": [{
192
+ "type": "vector",
193
+ "path": "embedding",
194
+ "numDimensions": 1536,
195
+ "similarity": "cosine"
196
+ }]
197
+ },
198
+ wait_for_ready=True
199
+ )
200
+
201
+ # Create search index
202
+ await index_manager.create_search_index(
203
+ name="text_search",
204
+ definition={
205
+ "mappings": {
206
+ "dynamic": False,
207
+ "fields": {
208
+ "title": {"type": "string"},
209
+ "content": {"type": "string"}
210
+ }
211
+ }
212
+ },
213
+ wait_for_ready=True
214
+ )
215
+
216
+ # List indexes
217
+ indexes = await index_manager.list_search_indexes()
218
+
219
+ # Get index status
220
+ index_info = await index_manager.get_search_index("vector_idx")
221
+
222
+ # Drop index
223
+ await index_manager.drop_search_index("vector_idx", wait_for_drop=True)
224
+ ```
225
+
226
+ ### Vector Search Index
227
+
228
+ ```python
229
+ # Create vector search index
230
+ await index_manager.create_vector_search_index(
231
+ name="embeddings_idx",
232
+ definition={
233
+ "fields": [{
234
+ "type": "vector",
235
+ "path": "embedding",
236
+ "numDimensions": 1536,
237
+ "similarity": "cosine"
238
+ }]
239
+ }
240
+ )
241
+
242
+ # Update vector index
243
+ await index_manager.update_search_index(
244
+ name="embeddings_idx",
245
+ definition={
246
+ "fields": [{
247
+ "type": "vector",
248
+ "path": "embedding",
249
+ "numDimensions": 3072, # Updated dimensions
250
+ "similarity": "dotProduct"
251
+ }]
252
+ }
253
+ )
254
+ ```
255
+
256
+ ### Search Index
257
+
258
+ ```python
259
+ # Create Lucene search index
260
+ await index_manager.create_search_index(
261
+ name="full_text_search",
262
+ definition={
263
+ "mappings": {
264
+ "dynamic": False,
265
+ "fields": {
266
+ "title": {
267
+ "type": "string",
268
+ "analyzer": "lucene.standard"
269
+ },
270
+ "content": {
271
+ "type": "string",
272
+ "analyzer": "lucene.english"
273
+ }
274
+ }
275
+ }
276
+ }
277
+ )
278
+ ```
279
+
280
+ ## Connection Pooling
281
+
282
+ The database module provides shared MongoDB connection pooling for efficient resource usage.
283
+
284
+ ### Get Shared Client
285
+
286
+ ```python
287
+ from mdb_engine.database import get_shared_mongo_client
288
+
289
+ # Get or create shared MongoDB client
290
+ client = get_shared_mongo_client(
291
+ mongo_uri="mongodb://localhost:27017",
292
+ max_pool_size=10,
293
+ min_pool_size=1
294
+ )
295
+
296
+ db = client["my_database"]
297
+ ```
298
+
299
+ ### Pool Metrics
300
+
301
+ Monitor connection pool usage:
302
+
303
+ ```python
304
+ from mdb_engine.database import get_pool_metrics
305
+
306
+ # Get pool metrics
307
+ metrics = await get_pool_metrics(client)
308
+
309
+ print(f"Pool size: {metrics['pool_size']}")
310
+ print(f"Active connections: {metrics['active_connections']}")
311
+ print(f"Available connections: {metrics['available_connections']}")
312
+ ```
313
+
314
+ ### Verify Connection
315
+
316
+ ```python
317
+ from mdb_engine.database import verify_shared_client
318
+
319
+ # Verify client is connected
320
+ is_connected = await verify_shared_client()
321
+ if not is_connected:
322
+ print("MongoDB client is not connected")
323
+ ```
324
+
325
+ ## AppDB Abstraction
326
+
327
+ High-level database abstraction for FastAPI applications.
328
+
329
+ ### Basic Usage
330
+
331
+ ```python
332
+ from mdb_engine.database import AppDB, Collection, get_app_db
333
+ from fastapi import Depends
334
+
335
+ # In FastAPI route
336
+ @app.get("/data")
337
+ async def get_data(db: AppDB = Depends(get_app_db)):
338
+ # MongoDB-style operations
339
+ doc = await db.my_collection.find_one({"_id": "doc123"})
340
+ docs = await db.my_collection.find({"status": "active"}).to_list(length=10)
341
+ return {"data": docs}
342
+ ```
343
+
344
+ ### Collection Wrapper
345
+
346
+ Use the `Collection` wrapper for MongoDB-style API:
347
+
348
+ ```python
349
+ from mdb_engine.database import Collection
350
+
351
+ collection = Collection(db.my_collection)
352
+
353
+ # MongoDB-style methods
354
+ doc = await collection.find_one({"_id": "doc123"})
355
+ docs = await collection.find({"status": "active"}).to_list(length=10)
356
+ await collection.insert_one({"name": "New Doc"})
357
+ count = await collection.count_documents({})
358
+ ```
359
+
360
+ ## API Reference
361
+
362
+ ### ScopedMongoWrapper
363
+
364
+ #### Initialization
365
+
366
+ ```python
367
+ ScopedMongoWrapper(
368
+ real_db: AsyncIOMotorDatabase,
369
+ read_scopes: List[str],
370
+ write_scope: str,
371
+ auto_index: bool = True
372
+ )
373
+ ```
374
+
375
+ #### Methods
376
+
377
+ - `get_collection(name)` - Get scoped collection wrapper
378
+ - Collections accessed via attribute (e.g., `db.my_collection`)
379
+
380
+ ### ScopedCollectionWrapper
381
+
382
+ #### Read Methods
383
+
384
+ - `find_one(filter, **kwargs)` - Find single document (auto-scoped)
385
+ - `find(filter, **kwargs)` - Find documents (auto-scoped)
386
+ - `count_documents(filter, **kwargs)` - Count documents (auto-scoped)
387
+ - `aggregate(pipeline, **kwargs)` - Aggregate pipeline (auto-scoped)
388
+ - `distinct(key, filter=None, **kwargs)` - Distinct values (auto-scoped)
389
+
390
+ #### Write Methods
391
+
392
+ - `insert_one(document)` - Insert document (auto-adds app_id)
393
+ - `insert_many(documents)` - Insert multiple documents (auto-adds app_id)
394
+ - `update_one(filter, update, **kwargs)` - Update document (auto-scoped)
395
+ - `update_many(filter, update, **kwargs)` - Update documents (auto-scoped)
396
+ - `delete_one(filter, **kwargs)` - Delete document (auto-scoped)
397
+ - `delete_many(filter, **kwargs)` - Delete documents (auto-scoped)
398
+
399
+ #### Properties
400
+
401
+ - `_collection` - Underlying unscoped collection (for admin operations)
402
+ - `index_manager` - AsyncAtlasIndexManager instance
403
+
404
+ ### AsyncAtlasIndexManager
405
+
406
+ #### Methods
407
+
408
+ - `create_vector_search_index(name, definition, wait_for_ready=True, timeout=300)` - Create vector index
409
+ - `create_search_index(name, definition, wait_for_ready=True, timeout=300)` - Create search index
410
+ - `get_search_index(name)` - Get index info
411
+ - `list_search_indexes()` - List all indexes
412
+ - `update_search_index(name, definition, wait_for_ready=True, timeout=300)` - Update index
413
+ - `drop_search_index(name, wait_for_drop=True, timeout=60)` - Drop index
414
+
415
+ ### Connection Pooling
416
+
417
+ #### Functions
418
+
419
+ - `get_shared_mongo_client(mongo_uri, max_pool_size=None, min_pool_size=None, ...)` - Get shared client
420
+ - `verify_shared_client()` - Verify client connection
421
+ - `get_pool_metrics(client=None)` - Get pool metrics
422
+ - `register_client_for_metrics(client)` - Register client for metrics
423
+ - `close_shared_client()` - Close shared client
424
+
425
+ ### AppDB
426
+
427
+ #### Functions
428
+
429
+ - `get_app_db()` - FastAPI dependency for AppDB
430
+
431
+ ## Configuration
432
+
433
+ ### Environment Variables
434
+
435
+ ```bash
436
+ # Connection pool settings
437
+ export MONGO_ACTOR_MAX_POOL_SIZE=10
438
+ export MONGO_ACTOR_MIN_POOL_SIZE=1
439
+
440
+ # Server selection timeout
441
+ export MONGO_SERVER_SELECTION_TIMEOUT_MS=5000
442
+ export MONGO_MAX_IDLE_TIME_MS=45000
443
+ ```
444
+
445
+ ### AutoIndexManager Settings
446
+
447
+ ```python
448
+ # Configure auto-indexing thresholds
449
+ from mdb_engine.constants import AUTO_INDEX_HINT_THRESHOLD
450
+
451
+ # Threshold for creating indexes (default: 100 queries)
452
+ AUTO_INDEX_HINT_THRESHOLD = 100
453
+ ```
454
+
455
+ ## Best Practices
456
+
457
+ 1. **Always use scoped wrappers** - Never access unscoped collections directly
458
+ 2. **Use connection pooling** - Use `get_shared_mongo_client()` for efficiency
459
+ 3. **Monitor pool metrics** - Regularly check pool usage to prevent exhaustion
460
+ 4. **Enable auto-indexing** - Let AutoIndexManager optimize queries automatically
461
+ 5. **Use read_scopes carefully** - Only enable cross-app reads when necessary
462
+ 6. **Handle errors** - Wrap database operations in try/except blocks
463
+ 7. **Use transactions** - For multi-document operations requiring consistency
464
+ 8. **Index management** - Use AsyncAtlasIndexManager for Atlas indexes
465
+
466
+ ## Error Handling
467
+
468
+ ```python
469
+ from pymongo.errors import OperationFailure, AutoReconnect
470
+
471
+ try:
472
+ doc = await collection.find_one({"_id": "doc123"})
473
+ except OperationFailure as e:
474
+ print(f"MongoDB operation failed: {e.details}")
475
+ except AutoReconnect as e:
476
+ print(f"MongoDB reconnection: {e}")
477
+ except Exception as e:
478
+ print(f"Unexpected error: {e}")
479
+ ```
480
+
481
+ ## Integration Examples
482
+
483
+ ### FastAPI Integration
484
+
485
+ ```python
486
+ from fastapi import FastAPI, Depends
487
+ from mdb_engine.database import get_app_db, AppDB
488
+ from mdb_engine.core import MongoDBEngine
489
+
490
+ app = FastAPI()
491
+ engine = MongoDBEngine(mongo_uri="...", db_name="...")
492
+
493
+ @app.on_event("startup")
494
+ async def startup():
495
+ await engine.initialize()
496
+
497
+ @app.get("/data")
498
+ async def get_data(db: AppDB = Depends(get_app_db)):
499
+ docs = await db.collection.find({}).to_list(length=10)
500
+ return {"data": docs}
501
+ ```
502
+
503
+ ### Multiple Apps
504
+
505
+ ```python
506
+ # Access different apps
507
+ db1 = engine.get_scoped_db("app1")
508
+ db2 = engine.get_scoped_db("app2")
509
+
510
+ # Cross-app read (read from app1, write to app2)
511
+ shared_db = ScopedMongoWrapper(
512
+ real_db=engine.mongo_db,
513
+ read_scopes=["app1", "app2"],
514
+ write_scope="shared"
515
+ )
516
+ ```
517
+
518
+ ## Related Modules
519
+
520
+ - **`core/`** - MongoDBEngine for app registration
521
+ - **`indexes/`** - Index management orchestration
522
+ - **`observability/`** - Metrics and logging
@@ -0,0 +1,31 @@
1
+ """
2
+ Database abstraction layer.
3
+
4
+ Provides scoped database access with automatic app isolation
5
+ and MongoDB-style API for familiarity.
6
+ """
7
+
8
+ from .abstraction import AppDB, Collection, get_app_db
9
+ from .connection import (close_shared_client, get_pool_metrics,
10
+ get_shared_mongo_client, register_client_for_metrics,
11
+ verify_shared_client)
12
+ from .scoped_wrapper import (AsyncAtlasIndexManager, AutoIndexManager,
13
+ ScopedCollectionWrapper, ScopedMongoWrapper)
14
+
15
+ __all__ = [
16
+ # Scoped wrappers
17
+ "ScopedMongoWrapper",
18
+ "ScopedCollectionWrapper",
19
+ "AsyncAtlasIndexManager",
20
+ "AutoIndexManager",
21
+ # Database abstraction
22
+ "AppDB",
23
+ "Collection",
24
+ "get_app_db",
25
+ # Connection pooling
26
+ "get_shared_mongo_client",
27
+ "verify_shared_client",
28
+ "get_pool_metrics",
29
+ "register_client_for_metrics",
30
+ "close_shared_client",
31
+ ]