Skip to main content

openframe-adapters-db-mongo

MongoDB document store adapter for the OpenFrame Microservice Suite.

Part of the openframe-adapters monorepo. Implements BaseRepository[T] and HealthCheck from openframe-core using motor (AsyncIOMotorClient).


Installation

pip install openframe-adapters-db-mongo

Required env vars:

MONGO_URL=mongodb://user:password@host:27017
MONGO_DATABASE=mydb

Atlas SRV URIs work too:

MONGO_URL=mongodb+srv://user:password@cluster.mongodb.net

Quick start

Raw dict mode

from openframe.adapters.db.mongo import MongoSettings, MongoRepository

settings = MongoSettings()  # reads MONGO_URL and MONGO_DATABASE from env
repo = MongoRepository(settings, collection="artifacts")

doc = await repo.get("507f1f77bcf86cd799439011")   # dict | None
docs, total = await repo.list(10, 0)                # ([dict, ...], int)
created = await repo.create({"title": "paper"})
updated = await repo.update({"_id": "...", "title": "updated"})
deleted = await repo.delete("507f1f77bcf86cd799439011")  # bool

Typed domain mode

from dataclasses import dataclass
from openframe.adapters.db.mongo import MongoSettings, MongoRepository

@dataclass
class Artifact:
    id: str
    title: str
    artifact_type: str

class ArtifactRepository(MongoRepository[Artifact]):
    _collection = "artifacts"

    def _doc_to_entity(self, doc: dict) -> Artifact:
        return Artifact(
            id=doc["_id"],
            title=doc["title"],
            artifact_type=doc["artifact_type"],
        )

    def _entity_to_doc(self, entity: Artifact) -> dict:
        return {
            "_id": entity.id,
            "title": entity.title,
            "artifact_type": entity.artifact_type,
        }

settings = MongoSettings()
repo = ArtifactRepository(settings)
artifact: Artifact | None = await repo.get("507f1f77bcf86cd799439011")

Wiring into an application

The examples above construct MongoRepository directly and skip lifecycle management. For a real service, wire the adapter through its MongoPlugin (the BasePort-satisfying plugin class) so connect/health/close are handled for you. The recommended entry point is ApplicationBootstrap.compose() from openframe-core>=3.3:

from openframe.core.runtime import ApplicationBootstrap
from openframe.core.ports import Capability
from openframe.adapters.db.mongo import MongoPlugin, MongoSettings

mongo_port = MongoPlugin(MongoSettings(), collection="artifacts")

async with ApplicationBootstrap.compose(mongo_port) as app:
    repo = app.get(Capability.PERSISTENCE).get_repository()
    doc = await repo.get("507f1f77bcf86cd799439011")
# initialize() ran on entry, shutdown() runs automatically on exit

compose() is the right choice for the common case of one or a few ports. Reach for a subclassed ApplicationBootstrap with configure() only when you need per-port config=/init_timeout= or conditional registration order, and use ApplicationBootstrap.registry as an escape hatch for anything neither tier covers (e.g. registry.get_all(Capability.PERSISTENCE) when more than one persistence port is registered deliberately).


_id handling

MongoDB uses _id as the document identifier; BaseRepository uses entity_id: str. The adapter bridges this transparently:

  • Reading: _id is always returned as str — ObjectId is never exposed to callers. A convenience id key is also added mirroring _id.
  • Writing: If an entity dict has an id key but no _id key, the adapter maps id → _id before insertion.
  • Filtering: String entity IDs that are valid 24-char hex are parsed as ObjectId for indexed lookups; other strings are used as plain string _id values.

Configuration

All settings are read from environment variables.

Env var Type Default Description
MONGO_URL str required Motor/pymongo connection string
MONGO_DATABASE str required Database name
MONGO_MIN_POOL_SIZE int 5 Minimum pool connections
MONGO_MAX_POOL_SIZE int 20 Maximum pool connections
MONGO_SERVER_SELECTION_TIMEOUT_MS int 5000 Server selection timeout (ms)
MONGO_TLS bool False Enable TLS/SSL
MONGO_TLS_ALLOW_INVALID_CERTS bool False Skip cert validation (dev only)
CONNECTION_TIMEOUT float 30.0 Pool creation timeout (s)
OPERATION_TIMEOUT float 10.0 Per-operation timeout (s)
MAX_RETRIES int 3 Max retry attempts

Timeout strategy

Two layers of timeout on every operation:

  1. asyncio.timeout(settings.operation_timeout) — cancels the Python coroutine.
  2. max_time_ms=int(settings.operation_timeout * 1000) passed to motor query methods — instructs the MongoDB server to abort the query.

Health checks

MongoRepository implements the HealthCheck protocol from openframe-core.

alive = await repo.ping()       # admin.command("ping") — fast liveness check
ready = await repo.is_ready()   # list_collection_names() — full readiness check

Both methods return False on any failure and never raise.


Exception hierarchy

All exceptions are AdapterError subclasses from openframe.core.exceptions. Raw motor/pymongo exceptions never escape the adapter.

Situation Exception
Cannot connect to MongoDB AdapterConnectionError
Invalid MONGO_URL syntax AdapterConfigurationError
Query failed (constraint, auth, etc.) AdapterQueryError
Operation exceeded timeout AdapterTimeoutError

Development

# from the package directory
pip install -e ".[dev]"
pytest tests/ -v

Protocol conformance

from openframe.core.ports import BaseRepository
from openframe.core.health import HealthCheck

repo = MongoRepository(settings, collection="artifacts")
assert isinstance(repo, BaseRepository)   # True — structural check
assert isinstance(repo, HealthCheck)      # True — structural check

No inheritance from either Protocol is required or used.


License

MIT

Metadata

Release files for openframe-adapters-db-mongo 2.0.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for openframe-adapters-db-mongo 2.0.3
File Size Uploaded
openframe_adapters_db_mongo-2.0.3.tar.gz 20.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for openframe-adapters-db-mongo 2.0.3
File Interpreter ABI Platform
openframe_adapters_db_mongo-2.0.3-py3-none-any.whl Python 3 none any Details

Total release size: 34.5 kB

Release files / openframe_adapters_db_mongo-2.0.3.tar.gz

Download URL openframe_adapters_db_mongo-2.0.3.tar.gz
Size 20.0 kB
Tags Source
SHA-256 checksum
How to use checksums
4fac283039172118dbdee4b019e68505fb3b45dd89ec1c1521c7ffab4a296b2c
BLAKE2b-256 checksum
How to use checksums
982e1b326122bf8aa0d2048db89a329c21fbdeda15a2fc0b69c31378395119f6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / openframe_adapters_db_mongo-2.0.3-py3-none-any.whl

Download URL openframe_adapters_db_mongo-2.0.3-py3-none-any.whl
Size 14.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
e8abb7f69c8e6ad658b55967c9cacd74eb3deb5dd4fa13d79a11d182580d314f
BLAKE2b-256 checksum
How to use checksums
520c0d9f1688cc56a79d66f4663e21515b4ee0586b2a97c0503fb243d38d959b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release history Release notifications | RSS feed

2.0.4

2 release files

This release

2.0.3 This release

2 release files

2.0.2

2 release files

2.0.1

2 release files

2.0.0

2 release files

1.3.0

2 release files

1.2.0

2 release files

1.1.0

2 release files

1.0.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page