Skip to content

popoto.fields.unique_field_mixin

popoto.fields.unique_field_mixin

Unique Field Mixin for Popoto Redis ORM.

This module provides the UniqueFieldMixin class, which enforces uniqueness constraints on field values within a Popoto model. It is designed to be used as a mixin with KeyField to create fields that require globally unique values across all instances of a model.

Design Philosophy

In relational databases, unique constraints are typically enforced at the database level with UNIQUE indexes. Redis, being a key-value store, does not have native unique constraint enforcement. This mixin bridges that gap by ensuring that any field marked as unique will reject duplicate values at the application layer.

The mixin follows Python's cooperative multiple inheritance pattern, using super() to work seamlessly with Field and other mixins in the inheritance chain. This allows UniqueFieldMixin to be combined with KeyFieldMixin to create UniqueKeyField, which provides both indexing capabilities and uniqueness guarantees.

System Integration

This mixin works in conjunction with: - KeyFieldMixin: Provides the indexing infrastructure that UniqueFieldMixin relies on - Field: The base class that provides core field behavior - UniqueKeyField (shortcuts.py): The primary consumer of this mixin's behavior

Note: In the current implementation, UniqueKeyField in shortcuts.py directly sets unique=True rather than using this mixin. This mixin exists as a composable building block for custom field types that need uniqueness constraints.

Example Usage

from popoto import Model, UniqueKeyField

class User(Model):
    # Email must be unique across all User instances
    email = UniqueKeyField(type=str)
    username = UniqueKeyField(type=str, max_length=30)

# This will succeed
user1 = User(email="alice@example.com", username="alice")
user1.save()

# This would fail validation due to duplicate email
user2 = User(email="alice@example.com", username="bob")

UniqueFieldMixin

Mixin that enforces uniqueness constraints on field values.

This mixin guarantees that no two model instances can share the same value for a field marked as unique. It is intended to be combined with KeyFieldMixin (via UniqueKeyField) to create fields that are both indexed and unique.

The uniqueness constraint is enforced at two levels: 1. At field definition time: The mixin ensures unique=True cannot be overridden 2. At query/save time: Inherited behavior from KeyFieldMixin maintains Redis sets that track which values exist, enabling duplicate detection

Attributes

unique : bool Always True for this mixin. Attempting to set unique=False will raise a ModelException. This attribute signals to the validation and indexing system that duplicate values should be rejected.

Design Decision

The decision to make unique=True immutable (raising an exception if set to False) ensures that developers cannot accidentally create a "UniqueKeyField" that isn't actually unique. This follows the principle of making invalid states unrepresentable.

Source code in src/popoto/fields/unique_field_mixin.py
class UniqueFieldMixin:
    """
    Mixin that enforces uniqueness constraints on field values.

    This mixin guarantees that no two model instances can share the same value
    for a field marked as unique. It is intended to be combined with KeyFieldMixin
    (via UniqueKeyField) to create fields that are both indexed and unique.

    The uniqueness constraint is enforced at two levels:
    1. At field definition time: The mixin ensures unique=True cannot be overridden
    2. At query/save time: Inherited behavior from KeyFieldMixin maintains Redis
       sets that track which values exist, enabling duplicate detection

    Attributes
    ----------
    unique : bool
        Always True for this mixin. Attempting to set unique=False will raise
        a ModelException. This attribute signals to the validation and indexing
        system that duplicate values should be rejected.

    Design Decision
    ---------------
    The decision to make unique=True immutable (raising an exception if set to
    False) ensures that developers cannot accidentally create a "UniqueKeyField"
    that isn't actually unique. This follows the principle of making invalid
    states unrepresentable.
    """

    unique: bool = True

    def __init__(self, **kwargs):
        """
        Initialize the unique field mixin with uniqueness enforcement.

        This method participates in Python's cooperative multiple inheritance,
        calling super().__init__() to ensure all mixins in the inheritance chain
        are properly initialized. It sets the unique=True default and validates
        that the uniqueness constraint is not being disabled.

        Parameters
        ----------
        **kwargs : dict
            Field configuration options. The 'unique' key, if provided, must be
            True or omitted. Passing unique=False will raise a ModelException.

        Raises
        ------
        ModelException
            If unique=False is explicitly passed, since a UniqueField must
            enforce uniqueness by definition.

        Notes
        -----
        The field_defaults dictionary is updated to include unique=True, ensuring
        that this setting propagates correctly through the field system's
        introspection and serialization mechanisms.
        """
        super().__init__(**kwargs)
        uniquekeyfield_defaults = {
            "unique": True,
        }
        self.field_defaults.update(uniquekeyfield_defaults)
        # set field options, let kwargs override
        for k, v in uniquekeyfield_defaults.items():
            setattr(self, k, kwargs.get(k, v))

        if not kwargs.get("unique", True):
            from ..exceptions import ModelException

            raise ModelException("UniqueKey field MUST be unique")