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.
- mdb_engine/README.md +144 -0
- mdb_engine/__init__.py +37 -0
- mdb_engine/auth/README.md +631 -0
- mdb_engine/auth/__init__.py +128 -0
- mdb_engine/auth/casbin_factory.py +199 -0
- mdb_engine/auth/casbin_models.py +46 -0
- mdb_engine/auth/config_defaults.py +71 -0
- mdb_engine/auth/config_helpers.py +213 -0
- mdb_engine/auth/cookie_utils.py +158 -0
- mdb_engine/auth/decorators.py +350 -0
- mdb_engine/auth/dependencies.py +747 -0
- mdb_engine/auth/helpers.py +64 -0
- mdb_engine/auth/integration.py +578 -0
- mdb_engine/auth/jwt.py +225 -0
- mdb_engine/auth/middleware.py +241 -0
- mdb_engine/auth/oso_factory.py +323 -0
- mdb_engine/auth/provider.py +570 -0
- mdb_engine/auth/restrictions.py +271 -0
- mdb_engine/auth/session_manager.py +477 -0
- mdb_engine/auth/token_lifecycle.py +213 -0
- mdb_engine/auth/token_store.py +289 -0
- mdb_engine/auth/users.py +1516 -0
- mdb_engine/auth/utils.py +614 -0
- mdb_engine/cli/__init__.py +13 -0
- mdb_engine/cli/commands/__init__.py +7 -0
- mdb_engine/cli/commands/generate.py +105 -0
- mdb_engine/cli/commands/migrate.py +83 -0
- mdb_engine/cli/commands/show.py +70 -0
- mdb_engine/cli/commands/validate.py +63 -0
- mdb_engine/cli/main.py +41 -0
- mdb_engine/cli/utils.py +92 -0
- mdb_engine/config.py +217 -0
- mdb_engine/constants.py +160 -0
- mdb_engine/core/README.md +542 -0
- mdb_engine/core/__init__.py +42 -0
- mdb_engine/core/app_registration.py +392 -0
- mdb_engine/core/connection.py +243 -0
- mdb_engine/core/engine.py +749 -0
- mdb_engine/core/index_management.py +162 -0
- mdb_engine/core/manifest.py +2793 -0
- mdb_engine/core/seeding.py +179 -0
- mdb_engine/core/service_initialization.py +355 -0
- mdb_engine/core/types.py +413 -0
- mdb_engine/database/README.md +522 -0
- mdb_engine/database/__init__.py +31 -0
- mdb_engine/database/abstraction.py +635 -0
- mdb_engine/database/connection.py +387 -0
- mdb_engine/database/scoped_wrapper.py +1721 -0
- mdb_engine/embeddings/README.md +184 -0
- mdb_engine/embeddings/__init__.py +62 -0
- mdb_engine/embeddings/dependencies.py +193 -0
- mdb_engine/embeddings/service.py +759 -0
- mdb_engine/exceptions.py +167 -0
- mdb_engine/indexes/README.md +651 -0
- mdb_engine/indexes/__init__.py +21 -0
- mdb_engine/indexes/helpers.py +145 -0
- mdb_engine/indexes/manager.py +895 -0
- mdb_engine/memory/README.md +451 -0
- mdb_engine/memory/__init__.py +30 -0
- mdb_engine/memory/service.py +1285 -0
- mdb_engine/observability/README.md +515 -0
- mdb_engine/observability/__init__.py +42 -0
- mdb_engine/observability/health.py +296 -0
- mdb_engine/observability/logging.py +161 -0
- mdb_engine/observability/metrics.py +297 -0
- mdb_engine/routing/README.md +462 -0
- mdb_engine/routing/__init__.py +73 -0
- mdb_engine/routing/websockets.py +813 -0
- mdb_engine/utils/__init__.py +7 -0
- mdb_engine-0.1.6.dist-info/METADATA +213 -0
- mdb_engine-0.1.6.dist-info/RECORD +75 -0
- mdb_engine-0.1.6.dist-info/WHEEL +5 -0
- mdb_engine-0.1.6.dist-info/entry_points.txt +2 -0
- mdb_engine-0.1.6.dist-info/licenses/LICENSE +661 -0
- 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
|
+
]
|