Skip to content

Expression Evaluation

Expressions can be evaluated against actual data to determine if the data satisfies the filter criteria. Useful for in-memory filtering, testing filter logic, client-side filtering, and access control checks.

All input data must be wrapped with unwind_data before evaluation.

Basic Evaluation

from therismos import F, unwind_data

age = F("age")
status = F("status")

expr = (age > 18) & (status == "active")

result = expr.evaluate(unwind_data({"age": 25, "status": "active"}))  # True
result = expr.evaluate(unwind_data({"age": 15, "status": "active"}))  # False

Evaluation with Type Casting

When fields have declared types, values are automatically cast during evaluation:

age = F("age", int)
expr = age >= 18

result = expr.evaluate(unwind_data({"age": "25"}))  # True — "25" cast to int

Membership and Regex

import re

status = F("status")
expr = status.is_in("active", "pending", "approved")
result = expr.evaluate(unwind_data({"status": "active"}))  # True

log_messages = F("logs")
expr = log_messages.matches(r"ERROR:", re.IGNORECASE)
data = {"logs": ["INFO: User logged in", "ERROR: Connection failed"]}
result = expr.evaluate(unwind_data(data))  # True

Complex Evaluation

age = F("age", int)
country = F("country")
verified = F("verified")
subscription = F("subscription")

expr = (
    (age >= 18) &
    (country.is_one_of(["US", "UK", "CA"])) &
    ((verified == True) | (subscription.is_in("premium", "enterprise")))
)

result = expr.evaluate(unwind_data({
    "age": 25, "country": "US", "verified": True, "subscription": "free"
}))  # True

result = expr.evaluate(unwind_data({
    "age": 16, "country": "US", "verified": True, "subscription": "premium"
}))  # False — fails age check

Evaluating Optimized Expressions

from therismos import optimize

expr = (
    ((age > 18) | (age > 25)) &  # Redundant
    (status == "active") &
    ((age < 30) | (age >= 30))   # Tautology
)

optimized, _ = optimize(expr)
# optimized: (age > 18) AND (status == "active")

result = optimized.evaluate(unwind_data({"age": 25, "status": "active"}))  # True

Error Handling

age = F("age")
expr = age > 18

try:
    expr.evaluate(unwind_data({"name": "Alice"}))  # age field missing
except KeyError:
    print("Required field 'age' not found")

age_typed = F("age", int)
try:
    age_typed.cast("not_a_number")
except (TypeError, ValueError):
    print("Cannot cast value to required type")

See Multi-Valued Fields for list and nested field evaluation.