Skip to main content

Tiny MongoDB collection injector decorator for Python classes.

Project description

mongollect

mongollect is a tiny, zero-dependency Python utility that lets you inject MongoDB collections into your classes using decorators.


🚀 Features

✅ Simple @injector.collection("name") decorator for single collections
@injector.multiple_collections() decorator for multiple collections
✅ Keeps your services clean — no repeated DB connection logic
✅ Lets you control the MongoDB connection (great for FastAPI, Flask, etc.)
✅ Easy to test and mock
✅ Early validation of collection existence
✅ Full type hint support


💻 Installation

pip install mongollect

⚡ Quick Start

Single Collection Injection

from pymongo import MongoClient
from mongollect import CollectionInjector

# Set up your MongoDB connection
client = MongoClient("mongodb://localhost:27017/")
db = client["mydatabase"]

# Create the injector
injector = CollectionInjector(db)

# Apply to your service
@injector.collection("accounts")
class AccountService:
    def create(self, data):
        return self.collection.insert_one(data)

    def find_all(self):
        return list(self.collection.find())

# Example usage
service = AccountService()
service.create({"username": "john_doe", "email": "john@example.com"})
print(service.find_all())

Multiple Collections Injection

# Inject multiple collections into a single class
@injector.multiple_collections(
    users="users",
    orders="orders", 
    products="products"
)
class CommerceService:
    def get_user_orders(self, user_id):
        # Access collections via their attribute names
        user = self.users.find_one({"_id": user_id})
        orders = list(self.orders.find({"user_id": user_id}))
        return {"user": user, "orders": orders}
    
    def get_order_details(self, order_id):
        order = self.orders.find_one({"_id": order_id})
        if order:
            # Enrich with product details
            product_ids = [item["product_id"] for item in order.get("items", [])]
            products = list(self.products.find({"_id": {"$in": product_ids}}))
            order["product_details"] = products
        return order

# Example usage
commerce = CommerceService()
user_orders = commerce.get_user_orders("user123")
order_details = commerce.get_order_details("order456")

🛠 API Reference

CollectionInjector(db)

Create an injector with your MongoDB database instance.

Parameters:

  • db → A pymongo.database.Database instance

Raises:

  • ValueError → If db is None

@injector.collection(name)

A class decorator that injects a single MongoDB collection into self.collection.

Parameters:

  • name → The MongoDB collection name (string)

Raises:

  • ValueError → If collection name is empty or not a string
  • KeyError → If the specified collection doesn't exist in the database
  • TypeError → If decorator is not applied to a class

Example:

@injector.collection("users")
class UserService:
    def find_user(self, user_id):
        return self.collection.find_one({"_id": user_id})

@injector.multiple_collections(**collections)

A class decorator that injects multiple MongoDB collections as named attributes.

Parameters:

  • **collections → Keyword arguments where keys are attribute names and values are collection names

Raises:

  • ValueError → If no collections are specified
  • KeyError → If any specified collection doesn't exist in the database
  • TypeError → If decorator is not applied to a class

Example:

@injector.multiple_collections(
    users="user_collection",
    posts="post_collection", 
    comments="comment_collection"
)
class BlogService:
    def get_user_posts_with_comments(self, user_id):
        user = self.users.find_one({"_id": user_id})
        posts = list(self.posts.find({"author_id": user_id}))
        
        for post in posts:
            post["comments"] = list(
                self.comments.find({"post_id": post["_id"]})
            )
        
        return {"user": user, "posts": posts}

🎯 Advanced Usage

Custom Attribute Names

When using multiple_collections, you can map collections to custom attribute names:

@injector.multiple_collections(
    user_db="users",           # self.user_db -> "users" collection
    order_db="orders",         # self.order_db -> "orders" collection  
    inventory="products"       # self.inventory -> "products" collection
)
class ECommerceService:
    def process_order(self, order_data):
        # Use custom attribute names
        user = self.user_db.find_one({"_id": order_data["user_id"]})
        product = self.inventory.find_one({"_id": order_data["product_id"]})
        
        if user and product:
            return self.order_db.insert_one(order_data)

Error Handling

The decorators validate collections at decoration time, not runtime:

# This will raise KeyError immediately when the decorator is applied
try:
    @injector.collection("nonexistent_collection")
    class BadService:
        pass
except KeyError as e:
    print(f"Collection validation failed: {e}")

✅ Why use mongollect?

  • Clean Architecture: Keeps your service layer clean and DRY
  • Flexible: Works with any MongoDB database you set up
  • Testable: Easy to inject mock databases for testing
  • Type Safe: Full type hint support for better IDE experience
  • Early Validation: Catches collection errors at decoration time
  • Lightweight: Zero dependencies beyond Python standard library
  • Multiple Collections: Handle complex services that need multiple collections

📄 License

MIT — do whatever you want, just give credit!

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

mongollect-0.1.0.tar.gz (6.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

mongollect-0.1.0-py3-none-any.whl (5.2 kB view details)

Uploaded Python 3

File details

Details for the file mongollect-0.1.0.tar.gz.

File metadata

  • Download URL: mongollect-0.1.0.tar.gz
  • Upload date:
  • Size: 6.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.9.6

File hashes

Hashes for mongollect-0.1.0.tar.gz
Algorithm Hash digest
SHA256 b851f45c1ac99389ec119546f8a3c0627868c6d9573cfa616219a2f320fa3a35
MD5 70a6531c641494c8e0c1c8e5c600521f
BLAKE2b-256 cd4d639d81ed1e8a01a6ab8667b17eb9d075b68dbf43de058aff09d2d6ed3782

See more details on using hashes here.

File details

Details for the file mongollect-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: mongollect-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 5.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.9.6

File hashes

Hashes for mongollect-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 637c867184a4502f3feb7eb317b3cfa6cc1d98a6f17ae330d6ec79edeab5bb0a
MD5 6723831723bc0de6db5849e5d5d92d9f
BLAKE2b-256 adeabc1b0362e645b9cd09441a43809365b81cfb899197d90d26b65aeb6d33d1

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page