CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-odmantic

AsyncIO MongoDB Object Document Mapper for Python using type hints

Pending
Overview
Eval results
Files

bson-types.mddocs/

BSON Types

ODMantic provides native MongoDB BSON types for precise data representation and serialization. These types ensure proper handling of MongoDB-specific data formats.

from odmantic import ObjectId, WithBsonSerializer
from odmantic.bson import Int64, Long, Decimal128, Binary, Regex
from decimal import Decimal

Capabilities

ObjectId

MongoDB's primary key type providing unique document identifiers.

class ObjectId:
    """MongoDB ObjectId type for unique document identification."""
    
    def __init__(self, oid=None):
        """
        Create ObjectId from hex string, bytes, or generate new one.
        
        Args:
            oid: Hex string, bytes, or None for auto-generation
        """
    
    def __str__(self):
        """
        String representation as 24-character hex string.
        
        Returns:
            str: Hex string representation
        """
    
    def __repr__(self):
        """
        Python representation.
        
        Returns:
            str: ObjectId('hex_string')
        """
    
    @property
    def generation_time(self):
        """
        Time when ObjectId was generated.
        
        Returns:
            datetime: Generation timestamp
        """
    
    @classmethod
    def from_datetime(cls, dt):
        """
        Create ObjectId from datetime.
        
        Args:
            dt: datetime object
            
        Returns:
            ObjectId: ObjectId with timestamp from datetime
        """
    
    @classmethod
    def is_valid(cls, oid):
        """
        Check if string/bytes represents valid ObjectId.
        
        Args:
            oid: String or bytes to validate
            
        Returns:
            bool: True if valid ObjectId format
        """

BSON Serialization Support

Mixin class for custom BSON serialization behavior.

class WithBsonSerializer:
    """Mixin for custom BSON serialization."""
    
    def __bson__(self):
        """
        Custom BSON serialization method.
        
        Returns:
            Any: BSON-serializable representation
        """

Extended BSON Types

Additional MongoDB BSON types for specialized use cases.

class Int64:
    """64-bit integer type for MongoDB."""
    
    def __init__(self, value: int):
        """
        Create 64-bit integer.
        
        Args:
            value: Integer value
        """

Long = Int64  # Alias for Int64

class Decimal128:
    """128-bit decimal type for high-precision numbers."""
    
    def __init__(self, value: Union[str, int, float, Decimal]):
        """
        Create 128-bit decimal.
        
        Args:
            value: Decimal, string, int, or float value
        """
    
    def to_decimal(self) -> Decimal:
        """
        Convert to Python decimal.Decimal.
        
        Returns:
            Decimal: Python decimal representation
        """

class Binary:
    """Binary data type for MongoDB."""
    
    def __init__(self, data: bytes, subtype: int = 0):
        """
        Create binary data.
        
        Args:
            data: Bytes data
            subtype: Binary subtype (0-255)
        """

class Regex:
    """Regular expression type for MongoDB."""
    
    def __init__(self, pattern: str, flags: int = 0):
        """
        Create regex.
        
        Args:
            pattern: Regular expression pattern string
            flags: Regex flags (integer)
        """
    
    @property
    def pattern(self) -> str:
        """
        Get regex pattern.
        
        Returns:
            str: Regular expression pattern
        """
    
    @property
    def flags(self) -> int:
        """
        Get regex flags.
        
        Returns:
            int: Regular expression flags
        """

Usage Examples

ObjectId Usage

from odmantic import Model, ObjectId
from datetime import datetime

class User(Model):
    name: str
    # Default ObjectId primary key (automatic)
    # id: ObjectId is added automatically

class Post(Model):
    title: str
    author_id: ObjectId  # Reference to User
    content: str

# Creating ObjectIds
def objectid_examples():
    # Auto-generated ObjectId
    user_id = ObjectId()
    print(f"Generated: {user_id}")
    
    # From hex string
    existing_id = ObjectId("507f1f77bcf86cd799439011")
    print(f"From string: {existing_id}")
    
    # From datetime (useful for date-based queries)
    yesterday = datetime.utcnow().replace(hour=0, minute=0, second=0, microsecond=0)
    yesterday_id = ObjectId.from_datetime(yesterday)
    print(f"From datetime: {yesterday_id}")
    
    # Validation
    if ObjectId.is_valid("507f1f77bcf86cd799439011"):
        print("Valid ObjectId format")
    
    # Generation time
    print(f"Generated at: {user_id.generation_time}")

# Using ObjectIds in models
async def model_objectid_example(engine):
    # Create user with auto-generated ID
    user = User(name="John Doe")
    await engine.save(user)
    print(f"User ID: {user.id}")
    
    # Create post referencing the user
    post = Post(
        title="My First Post",
        author_id=user.id,  # Reference using ObjectId
        content="Hello world!"
    )
    await engine.save(post)
    
    # Query by ObjectId
    found_user = await engine.find_one(User, User.id == user.id)
    user_posts = await engine.find(Post, Post.author_id == user.id)

Custom Primary Keys with ObjectId

class CustomModel(Model):
    # Custom ObjectId field as primary key
    custom_id: ObjectId = Field(primary_field=True, default_factory=ObjectId)
    name: str
    value: int

def custom_primary_example():
    # Model uses custom_id as _id in MongoDB
    model = CustomModel(name="test", value=42)
    print(f"Custom ID: {model.custom_id}")
    
    # Can also set explicitly
    specific_id = ObjectId("507f1f77bcf86cd799439011")
    model2 = CustomModel(custom_id=specific_id, name="specific", value=100)

Date-based ObjectId Queries

from datetime import datetime, timedelta

async def date_based_queries(engine):
    # Find documents created since yesterday
    yesterday = datetime.utcnow() - timedelta(days=1)
    yesterday_id = ObjectId.from_datetime(yesterday)
    
    recent_posts = await engine.find(Post, Post.id >= yesterday_id)
    
    # Find documents from specific date range
    week_ago = datetime.utcnow() - timedelta(days=7)
    week_ago_id = ObjectId.from_datetime(week_ago)
    
    last_week_posts = await engine.find(
        Post,
        Post.id >= week_ago_id,
        Post.id < yesterday_id
    )

Custom BSON Serialization

from odmantic import WithBsonSerializer
from decimal import Decimal
import json

class CustomSerializable(WithBsonSerializer):
    def __init__(self, data):
        self.data = data
    
    def __bson__(self):
        # Custom serialization for BSON
        return {
            "type": "custom",
            "data": json.dumps(self.data),
            "version": 1
        }

class DocumentWithCustom(Model):
    name: str
    custom_field: CustomSerializable
    
def custom_serialization_example():
    # Create document with custom serialization
    custom_data = CustomSerializable({"key": "value", "number": 42})
    doc = DocumentWithCustom(name="test", custom_field=custom_data)
    
    # When saved, custom_field will be serialized using __bson__ method

Extended BSON Types Usage

from odmantic.bson import Int64, Decimal128, Binary, Regex
from decimal import Decimal

class AdvancedDocument(Model):
    name: str
    large_number: Int64
    precise_decimal: Decimal128
    binary_data: Binary
    pattern: Regex

def extended_types_example():
    # Int64 for large integers
    large_num = Int64(9223372036854775807)
    
    # Decimal128 for high precision
    precise = Decimal128(Decimal("99999.999999999999999999999999999"))
    
    # Binary for byte data
    binary = Binary(b"binary data here", subtype=0)
    
    # Regex for pattern matching
    regex = Regex(r"^[a-zA-Z]+$", flags=0)
    
    doc = AdvancedDocument(
        name="advanced",
        large_number=large_num,
        precise_decimal=precise,
        binary_data=binary,
        pattern=regex
    )

Working with Raw BSON

import bson
from odmantic.bson import ObjectId

def raw_bson_examples():
    # Converting to/from raw BSON
    data = {
        "_id": ObjectId(),
        "name": "John",  
        "age": 30,
        "balance": Decimal128("1234.56")
    }
    
    # Encode to BSON bytes
    bson_bytes = bson.encode(data)
    print(f"BSON size: {len(bson_bytes)} bytes")
    
    # Decode from BSON bytes
    decoded = bson.decode(bson_bytes)
    print(f"Decoded: {decoded}")
    
    # ODMantic handles this automatically, but you can work with raw BSON if needed

Type Validation and Conversion

from pydantic import field_validator

class ValidatedModel(Model):
    id_field: ObjectId
    int64_field: Int64
    decimal_field: Decimal128
    
    @field_validator('id_field', mode='before')
    @classmethod
    def validate_objectid(cls, v):
        if isinstance(v, str):
            if ObjectId.is_valid(v):
                return ObjectId(v)
            else:
                raise ValueError('Invalid ObjectId format')
        return v
    
    @field_validator('decimal_field', mode='before') 
    @classmethod
    def validate_decimal(cls, v):
        if isinstance(v, (int, float, str)):
            return Decimal128(str(v))
        return v

def validation_example():
    # Valid conversions
    model = ValidatedModel(
        id_field="507f1f77bcf86cd799439011",  # String -> ObjectId
        int64_field=123456789,  # int -> Int64
        decimal_field="123.456"  # str -> Decimal128
    )
    
    print(f"ID: {model.id_field}")
    print(f"Int64: {model.int64_field}")
    print(f"Decimal: {model.decimal_field}")

BSON Type Queries

async def bson_type_queries(engine):
    # Query by ObjectId
    user_id = ObjectId("507f1f77bcf86cd799439011")
    user = await engine.find_one(User, User.id == user_id)
    
    # Query by ObjectId string (automatic conversion)
    user = await engine.find_one(User, User.id == "507f1f77bcf86cd799439011")
    
    # Query with Decimal128
    products = await engine.find(Product, Product.price >= Decimal128("99.99"))
    
    # Query with Int64
    large_orders = await engine.find(Order, Order.total_cents >= Int64(10000))
    
    # Regex queries
    pattern_match = await engine.find(
        User, 
        match(User.name, Regex(r"^John", flags=re.IGNORECASE))
    )

Install with Tessl CLI

npx tessl i tessl/pypi-odmantic

docs

bson-types.md

engines.md

fields.md

index.md

indexes.md

models.md

queries.md

sessions.md

tile.json