Skip to content

Conditions

Conditional expression DSL for queries, filters, and conditional writes.

conditions

Conditional writes DSL for Dynantic.

This module provides a DynCondition wrapper and Attr builder that create condition expressions compatible with DynamoDB's ConditionExpression. It delegates expression building to boto3's internal ConditionExpressionBuilder while keeping boto3 internals hidden from the public API.

Design: - DynCondition wraps boto3 ConditionBase, stored in .raw attribute - Attr builder wraps boto3 Attr internally, returns DynCondition - Operators &, |, ~ on DynCondition produce new DynCondition instances - At compilation time, DynCondition.raw is fed to boto3's builder

Usage

from dynantic import Attr

Simple conditions

user.save(condition=Attr("email").not_exists()) user.save(condition=Attr("version") == 1)

Composed conditions

condition = (Attr("age") >= 18) & (Attr("status") == "active") user.save(condition=condition)

Attr

Represents a DynamoDB attribute for building conditions.

This class wraps boto3.dynamodb.conditions.Attr internally and provides a clean API for building condition expressions. All methods return DynCondition instances (not raw boto3 objects).

Usage

Comparison operators

Attr("age") >= 18 Attr("status") == "active" Attr("score") < 100

DynamoDB functions

Attr("email").not_exists() # For create-if-not-exists Attr("name").begins_with("A") Attr("tags").contains("premium") Attr("age").between(18, 65) Attr("status").is_in(["active", "pending"])

Source code in dynantic/conditions.py
class Attr:
    """
    Represents a DynamoDB attribute for building conditions.

    This class wraps boto3.dynamodb.conditions.Attr internally and provides
    a clean API for building condition expressions. All methods return
    DynCondition instances (not raw boto3 objects).

    Usage:
        # Comparison operators
        Attr("age") >= 18
        Attr("status") == "active"
        Attr("score") < 100

        # DynamoDB functions
        Attr("email").not_exists()  # For create-if-not-exists
        Attr("name").begins_with("A")
        Attr("tags").contains("premium")
        Attr("age").between(18, 65)
        Attr("status").is_in(["active", "pending"])
    """

    __slots__ = ("name", "_boto3_attr")

    def __init__(self, name: str) -> None:
        """
        Initialize an attribute reference.

        Args:
            name: The attribute name in DynamoDB
        """
        self.name = name
        self._boto3_attr = Boto3Attr(name)

    # Comparison Operators - all return DynCondition

    def __eq__(self, value: Any) -> DynCondition:  # type: ignore[override]
        """Equals condition: Attr("field") == value"""
        return DynCondition(self._boto3_attr.eq(value))

    def __ne__(self, value: Any) -> DynCondition:  # type: ignore[override]
        """Not equals condition: Attr("field") != value"""
        return DynCondition(self._boto3_attr.ne(value))

    def __lt__(self, value: Any) -> DynCondition:
        """Less than condition: Attr("field") < value"""
        return DynCondition(self._boto3_attr.lt(value))

    def __le__(self, value: Any) -> DynCondition:
        """Less than or equal condition: Attr("field") <= value"""
        return DynCondition(self._boto3_attr.lte(value))

    def __gt__(self, value: Any) -> DynCondition:
        """Greater than condition: Attr("field") > value"""
        return DynCondition(self._boto3_attr.gt(value))

    def __ge__(self, value: Any) -> DynCondition:
        """Greater than or equal condition: Attr("field") >= value"""
        return DynCondition(self._boto3_attr.gte(value))

    # DynamoDB Function Methods - all return DynCondition

    def exists(self) -> DynCondition:
        """
        Checks if the attribute exists.

        Usage:
            Attr("optional_field").exists()
        """
        return DynCondition(self._boto3_attr.exists())

    def not_exists(self) -> DynCondition:
        """
        Checks if the attribute does NOT exist.

        Common use case: Create-if-not-exists pattern

        Usage:
            user.save(condition=Attr("email").not_exists())
        """
        return DynCondition(self._boto3_attr.not_exists())

    def begins_with(self, prefix: str) -> DynCondition:
        """
        Checks if string attribute begins with prefix.

        Usage:
            Attr("name").begins_with("John")
        """
        return DynCondition(self._boto3_attr.begins_with(prefix))

    def contains(self, value: Any) -> DynCondition:
        """
        Checks if attribute contains value.

        For strings: substring match
        For lists/sets: membership check

        Usage:
            Attr("email").contains("@gmail.com")
            Attr("tags").contains("premium")
        """
        return DynCondition(self._boto3_attr.contains(value))

    def between(self, low: Any, high: Any) -> DynCondition:
        """
        Checks if attribute is between low and high (inclusive).

        Usage:
            Attr("age").between(18, 65)
        """
        return DynCondition(self._boto3_attr.between(low, high))

    def is_in(self, values: list[Any]) -> DynCondition:
        """
        Checks if attribute value is in the provided list.

        Usage:
            Attr("status").is_in(["active", "pending", "review"])
        """
        return DynCondition(self._boto3_attr.is_in(values))

    def __repr__(self) -> str:
        return f"Attr({self.name!r})"

__init__

__init__(name: str) -> None

Initialize an attribute reference.

Parameters:

Name Type Description Default
name str

The attribute name in DynamoDB

required
Source code in dynantic/conditions.py
def __init__(self, name: str) -> None:
    """
    Initialize an attribute reference.

    Args:
        name: The attribute name in DynamoDB
    """
    self.name = name
    self._boto3_attr = Boto3Attr(name)

__eq__

__eq__(value: Any) -> DynCondition

Equals condition: Attr("field") == value

Source code in dynantic/conditions.py
def __eq__(self, value: Any) -> DynCondition:  # type: ignore[override]
    """Equals condition: Attr("field") == value"""
    return DynCondition(self._boto3_attr.eq(value))

__ne__

__ne__(value: Any) -> DynCondition

Not equals condition: Attr("field") != value

Source code in dynantic/conditions.py
def __ne__(self, value: Any) -> DynCondition:  # type: ignore[override]
    """Not equals condition: Attr("field") != value"""
    return DynCondition(self._boto3_attr.ne(value))

__lt__

__lt__(value: Any) -> DynCondition

Less than condition: Attr("field") < value

Source code in dynantic/conditions.py
def __lt__(self, value: Any) -> DynCondition:
    """Less than condition: Attr("field") < value"""
    return DynCondition(self._boto3_attr.lt(value))

__le__

__le__(value: Any) -> DynCondition

Less than or equal condition: Attr("field") <= value

Source code in dynantic/conditions.py
def __le__(self, value: Any) -> DynCondition:
    """Less than or equal condition: Attr("field") <= value"""
    return DynCondition(self._boto3_attr.lte(value))

__gt__

__gt__(value: Any) -> DynCondition

Greater than condition: Attr("field") > value

Source code in dynantic/conditions.py
def __gt__(self, value: Any) -> DynCondition:
    """Greater than condition: Attr("field") > value"""
    return DynCondition(self._boto3_attr.gt(value))

__ge__

__ge__(value: Any) -> DynCondition

Greater than or equal condition: Attr("field") >= value

Source code in dynantic/conditions.py
def __ge__(self, value: Any) -> DynCondition:
    """Greater than or equal condition: Attr("field") >= value"""
    return DynCondition(self._boto3_attr.gte(value))

exists

exists() -> DynCondition

Checks if the attribute exists.

Usage

Attr("optional_field").exists()

Source code in dynantic/conditions.py
def exists(self) -> DynCondition:
    """
    Checks if the attribute exists.

    Usage:
        Attr("optional_field").exists()
    """
    return DynCondition(self._boto3_attr.exists())

not_exists

not_exists() -> DynCondition

Checks if the attribute does NOT exist.

Common use case: Create-if-not-exists pattern

Usage

user.save(condition=Attr("email").not_exists())

Source code in dynantic/conditions.py
def not_exists(self) -> DynCondition:
    """
    Checks if the attribute does NOT exist.

    Common use case: Create-if-not-exists pattern

    Usage:
        user.save(condition=Attr("email").not_exists())
    """
    return DynCondition(self._boto3_attr.not_exists())

begins_with

begins_with(prefix: str) -> DynCondition

Checks if string attribute begins with prefix.

Usage

Attr("name").begins_with("John")

Source code in dynantic/conditions.py
def begins_with(self, prefix: str) -> DynCondition:
    """
    Checks if string attribute begins with prefix.

    Usage:
        Attr("name").begins_with("John")
    """
    return DynCondition(self._boto3_attr.begins_with(prefix))

contains

contains(value: Any) -> DynCondition

Checks if attribute contains value.

For strings: substring match For lists/sets: membership check

Usage

Attr("email").contains("@gmail.com") Attr("tags").contains("premium")

Source code in dynantic/conditions.py
def contains(self, value: Any) -> DynCondition:
    """
    Checks if attribute contains value.

    For strings: substring match
    For lists/sets: membership check

    Usage:
        Attr("email").contains("@gmail.com")
        Attr("tags").contains("premium")
    """
    return DynCondition(self._boto3_attr.contains(value))

between

between(low: Any, high: Any) -> DynCondition

Checks if attribute is between low and high (inclusive).

Usage

Attr("age").between(18, 65)

Source code in dynantic/conditions.py
def between(self, low: Any, high: Any) -> DynCondition:
    """
    Checks if attribute is between low and high (inclusive).

    Usage:
        Attr("age").between(18, 65)
    """
    return DynCondition(self._boto3_attr.between(low, high))

is_in

is_in(values: list[Any]) -> DynCondition

Checks if attribute value is in the provided list.

Usage

Attr("status").is_in(["active", "pending", "review"])

Source code in dynantic/conditions.py
def is_in(self, values: list[Any]) -> DynCondition:
    """
    Checks if attribute value is in the provided list.

    Usage:
        Attr("status").is_in(["active", "pending", "review"])
    """
    return DynCondition(self._boto3_attr.is_in(values))

DynCondition

Dynantic-owned wrapper for DynamoDB condition expressions.

This class wraps a boto3 condition object (stored in .raw) and provides Python operators for composing conditions. It keeps boto3 internals hidden from the public API while delegating expression correctness to boto3.

Users typically don't instantiate this directly - use Attr() instead.

Attributes:

Name Type Description
raw

The underlying boto3 ConditionBase object (internal use)

Source code in dynantic/conditions.py
class DynCondition:
    """
    Dynantic-owned wrapper for DynamoDB condition expressions.

    This class wraps a boto3 condition object (stored in .raw) and provides
    Python operators for composing conditions. It keeps boto3 internals
    hidden from the public API while delegating expression correctness
    to boto3.

    Users typically don't instantiate this directly - use Attr() instead.

    Attributes:
        raw: The underlying boto3 ConditionBase object (internal use)
    """

    __slots__ = ("raw",)

    def __init__(self, raw: Boto3ConditionBase) -> None:
        """
        Initialize with a boto3 condition object.

        Args:
            raw: The underlying boto3 condition (internal)
        """
        self.raw = raw

    def __and__(self, other: Condition) -> DynCondition:
        """
        Combine conditions with AND.

        Usage:
            condition = (Attr("age") >= 18) & (Attr("active") == True)
        """
        other_raw = _extract_raw(other)
        return DynCondition(Boto3And(self.raw, other_raw))

    def __rand__(self, other: Condition) -> DynCondition:
        """Support for: boto3_condition & DynCondition"""
        other_raw = _extract_raw(other)
        return DynCondition(Boto3And(other_raw, self.raw))

    def __or__(self, other: Condition) -> DynCondition:
        """
        Combine conditions with OR.

        Usage:
            condition = (Attr("role") == "admin") | (Attr("role") == "moderator")
        """
        other_raw = _extract_raw(other)
        return DynCondition(Boto3Or(self.raw, other_raw))

    def __ror__(self, other: Condition) -> DynCondition:
        """Support for: boto3_condition | DynCondition"""
        other_raw = _extract_raw(other)
        return DynCondition(Boto3Or(other_raw, self.raw))

    def __invert__(self) -> DynCondition:
        """
        Negate a condition with NOT.

        Usage:
            condition = ~Attr("deleted").exists()
        """
        return DynCondition(Boto3Not(self.raw))

    def __repr__(self) -> str:
        return f"DynCondition({self.raw!r})"

__init__

__init__(raw: ConditionBase) -> None

Initialize with a boto3 condition object.

Parameters:

Name Type Description Default
raw ConditionBase

The underlying boto3 condition (internal)

required
Source code in dynantic/conditions.py
def __init__(self, raw: Boto3ConditionBase) -> None:
    """
    Initialize with a boto3 condition object.

    Args:
        raw: The underlying boto3 condition (internal)
    """
    self.raw = raw

__and__

__and__(other: Condition) -> DynCondition

Combine conditions with AND.

Usage

condition = (Attr("age") >= 18) & (Attr("active") == True)

Source code in dynantic/conditions.py
def __and__(self, other: Condition) -> DynCondition:
    """
    Combine conditions with AND.

    Usage:
        condition = (Attr("age") >= 18) & (Attr("active") == True)
    """
    other_raw = _extract_raw(other)
    return DynCondition(Boto3And(self.raw, other_raw))

__rand__

__rand__(other: Condition) -> DynCondition

Support for: boto3_condition & DynCondition

Source code in dynantic/conditions.py
def __rand__(self, other: Condition) -> DynCondition:
    """Support for: boto3_condition & DynCondition"""
    other_raw = _extract_raw(other)
    return DynCondition(Boto3And(other_raw, self.raw))

__or__

__or__(other: Condition) -> DynCondition

Combine conditions with OR.

Usage

condition = (Attr("role") == "admin") | (Attr("role") == "moderator")

Source code in dynantic/conditions.py
def __or__(self, other: Condition) -> DynCondition:
    """
    Combine conditions with OR.

    Usage:
        condition = (Attr("role") == "admin") | (Attr("role") == "moderator")
    """
    other_raw = _extract_raw(other)
    return DynCondition(Boto3Or(self.raw, other_raw))

__ror__

__ror__(other: Condition) -> DynCondition

Support for: boto3_condition | DynCondition

Source code in dynantic/conditions.py
def __ror__(self, other: Condition) -> DynCondition:
    """Support for: boto3_condition | DynCondition"""
    other_raw = _extract_raw(other)
    return DynCondition(Boto3Or(other_raw, self.raw))

__invert__

__invert__() -> DynCondition

Negate a condition with NOT.

Usage

condition = ~Attr("deleted").exists()

Source code in dynantic/conditions.py
def __invert__(self) -> DynCondition:
    """
    Negate a condition with NOT.

    Usage:
        condition = ~Attr("deleted").exists()
    """
    return DynCondition(Boto3Not(self.raw))