semolina.fields

Field descriptors for Semolina semantic models.

Descriptor classes for defining typed fields in semantic view models. Fields use the descriptor protocol for class-level access and validation.

Classes

NullsOrdering

How to position NULL values in ORDER BY clause.

Field

Base descriptor for semantic view fields.

Metric

Descriptor for metric fields (aggregatable measures).

Dimension

Descriptor for dimension fields (groupable attributes).

Fact

Descriptor for fact fields (raw numeric values).

OrderTerm

Wrapper specifying sort direction and NULL handling for a field in order_by().

Module Contents

class semolina.fields.NullsOrdering[source]

Bases: enum.Enum

How to position NULL values in ORDER BY clause.

FIRST[source]

NULLS FIRST - NULL values appear before non-NULL values

LAST[source]

NULLS LAST - NULL values appear after non-NULL values

DEFAULT[source]

No NULLS clause - let backend decide

class semolina.fields.Field(source: str | None = None)[source]

Bases: Generic[T]

Base descriptor for semantic view fields.

Fields are descriptors that: - Validate field names at class creation time (__set_name__) - Return themselves for class-level access (Sales.revenue) - Prevent instance-level access, modification, and deletion - Support Python comparison operators to create Predicate filters

Operators:

Field descriptors support Python comparison operators that return typed Predicate nodes:

Users.country == 'US'      # -> Exact(field_name='country', value='US')
Users.country != 'CA'      # -> NotEqual(field_name='country', value='CA')
Users.revenue > 1000       # -> Gt(field_name='revenue', value=1000)
Users.revenue >= 1000      # -> Gte(...)
Users.revenue < 100        # -> Lt(...)
Users.revenue <= 100       # -> Lte(...)

Combine with & (AND) and | (OR):

(Users.country == 'US') | (Users.country == 'CA')  # -> Or(...)
(Users.revenue > 1000) & (Users.country == 'US')   # -> And(...)
Named filter methods:

Additional filter methods for common SQL operations:

Users.country.in_(['US', 'CA'])      # -> In(...)
Users.revenue.between(100, 1000)     # -> Between(...)
Users.name.like('%Smith%')            # -> Like(...)
Users.name.ilike('%smith%')           # -> ILike(...)
Users.name.startswith('A')            # -> StartsWith(...)
Users.name.endswith('son')            # -> EndsWith(...)
Users.country.iexact('united states') # -> IExact(...)
Users.country.isnull()                # -> IsNull(...)
between(lo: Any, hi: Any) semolina.filters.Between[source]

Create range predicate: field BETWEEN lo AND hi.

Parameters:
  • lo – Lower bound (inclusive).

  • hi – Upper bound (inclusive).

Returns:

Between predicate with value as (lo, hi) tuple.

Example

>>> Sales.revenue.between(100, 1000)
Between(field_name='revenue', value=(100, 1000))
in_(values: Any) semolina.filters.In[source]

Create membership predicate: field IN (values).

Parameters:

values – Collection of values to check membership against.

Returns:

In predicate with the given values.

Example

>>> Sales.country.in_(['US', 'CA', 'UK'])
In(field_name='country', value=['US', 'CA', 'UK'])
like(pattern: str) semolina.filters.Like[source]

Create case-sensitive pattern match: field LIKE pattern.

Parameters:

pattern – SQL LIKE pattern (use % and _ wildcards).

Returns:

Like predicate with the given pattern.

Example

>>> Users.name.like('%Smith%')
Like(field_name='name', value='%Smith%')
ilike(pattern: str) semolina.filters.ILike[source]

Create case-insensitive pattern match: field ILIKE pattern.

Parameters:

pattern – SQL ILIKE pattern (use % and _ wildcards).

Returns:

ILike predicate with the given pattern.

Example

>>> Users.name.ilike('%smith%')
ILike(field_name='name', value='%smith%')
startswith(prefix: str) semolina.filters.StartsWith[source]

Create case-sensitive prefix match: field LIKE 'prefix%'.

Parameters:

prefix – The prefix string to match.

Returns:

StartsWith predicate with the given prefix.

Example

>>> Users.name.startswith('A')
StartsWith(field_name='name', value='A')
istartswith(prefix: str) semolina.filters.IStartsWith[source]

Create case-insensitive prefix match: field ILIKE 'prefix%'.

Parameters:

prefix – The prefix string to match (case-insensitive).

Returns:

IStartsWith predicate with the given prefix.

Example

>>> Users.name.istartswith('a')
IStartsWith(field_name='name', value='a')
endswith(suffix: str) semolina.filters.EndsWith[source]

Create case-sensitive suffix match: field LIKE '%suffix'.

Parameters:

suffix – The suffix string to match.

Returns:

EndsWith predicate with the given suffix.

Example

>>> Users.name.endswith('son')
EndsWith(field_name='name', value='son')
iendswith(suffix: str) semolina.filters.IEndsWith[source]

Create case-insensitive suffix match: field ILIKE '%suffix'.

Parameters:

suffix – The suffix string to match (case-insensitive).

Returns:

IEndsWith predicate with the given suffix.

Example

>>> Users.name.iendswith('SON')
IEndsWith(field_name='name', value='SON')
iexact(value: str) semolina.filters.IExact[source]

Create case-insensitive equality: field ILIKE value (no wildcards).

Parameters:

value – The value to compare (case-insensitive).

Returns:

IExact predicate with the given value.

Example

>>> Users.country.iexact('united states')
IExact(field_name='country', value='united states')
isnull() semolina.filters.IsNull[source]

Create null check predicate: field IS NULL.

Returns:

IsNull predicate with value=True.

Example

>>> Users.country.isnull()
IsNull(field_name='country', value=True)
lookup(lookup_cls: type[semolina.filters.Lookup[Any]], value: Any) semolina.filters.Lookup[Any][source]

Create an arbitrary lookup predicate (escape hatch).

Use this when none of the built-in operators or named methods fit. Accepts any Lookup subclass and constructs it with this field’s name.

Parameters:
  • lookup_cls – A Lookup subclass to instantiate.

  • value – The value for the lookup.

Returns:

Instance of lookup_cls with this field’s name and the given value.

Example

>>> from semolina.filters import Exact
>>> Users.country.lookup(Exact, 'US')
Exact(field_name='country', value='US')
asc(nulls: NullsOrdering | None = None) OrderTerm[source]

Return ascending OrderTerm for use in order_by().

Parameters:

nulls – How to position NULL values (NullsOrdering.FIRST, NullsOrdering.LAST, or None for default)

Returns:

OrderTerm with descending=False

Example

>>> term = Sales.revenue.asc()
>>> term.descending
False
desc(nulls: NullsOrdering | None = None) OrderTerm[source]

Return descending OrderTerm for use in order_by().

Parameters:

nulls – How to position NULL values (NullsOrdering.FIRST, NullsOrdering.LAST, or None for default)

Returns:

OrderTerm with descending=True

Example

>>> term = Sales.revenue.desc()
>>> term.descending
True
class semolina.fields.Metric(source: str | None = None)[source]

Bases: Field[T]

Descriptor for metric fields (aggregatable measures).

Metrics represent quantitative measurements that can be aggregated, such as SUM(revenue), AVG(price), COUNT(*).

class semolina.fields.Dimension(source: str | None = None)[source]

Bases: Field[T]

Descriptor for dimension fields (groupable attributes).

Dimensions represent categorical or descriptive attributes used for grouping and filtering, such as country, product_category, date.

class semolina.fields.Fact(source: str | None = None)[source]

Bases: Field[T]

Descriptor for fact fields (raw numeric values).

Facts represent raw numeric values in fact tables that may be used in calculations but aren’t pre-aggregated, such as unit_price, quantity.

class semolina.fields.OrderTerm[source]

Wrapper specifying sort direction and NULL handling for a field in order_by().

Created via Field.asc() or Field.desc() methods.

field[source]

The Field to sort by

descending[source]

If True, sort descending (DESC). If False, sort ascending (ASC).

nulls[source]

How to position NULL values (NullsOrdering.FIRST, NullsOrdering.LAST, or NullsOrdering.DEFAULT)

Example

>>> term = Sales.revenue.desc()
>>> term.descending
True
>>> term_nulls = Sales.revenue.desc(NullsOrdering.FIRST)
>>> term_nulls.nulls
NULLS FIRST