httk.data.query

Typed protocols for the store/searcher query contract.

These protocols define the backend-agnostic query interface shared by httk data stores: the database layer in httk-data implements them over SQL, and serving modules (such as httk-optimade, whose in-memory store also conforms) program against them. They mirror the query interface of the httk v1 database layer (httk.db FilteredCollection searchers), so lightweight fakes can stand in for a real store in tests.

Classes

SearchExpression

Base class for protocol classes.

SearchField

A queryable field of a search variable.

SearchVariable

A query variable bound to a target type; attribute access yields fields.

SearchResult

One match: the declared output values, and the names they were declared under.

Searcher

A single query under construction, and its results once iterated.

Store

Base class for protocol classes.

Module Contents

class httk.data.query.SearchExpression[source]

Bases: Protocol

Base class for protocol classes.

Protocol classes are defined as:

class Proto(Protocol):
    def meth(self) -> int:
        ...

Such classes are primarily used with static type checkers that recognize structural subtyping (static duck-typing).

For example:

class C:
    def meth(self) -> int:
        return 0

def func(x: Proto) -> int:
    return x.meth()

func(C())  # Passes static type check

See PEP 544 for details. Protocol classes decorated with @typing.runtime_checkable act as simple-minded runtime protocols that check only the presence of given attributes, ignoring their type signatures. Protocol classes can be generic, they are defined as:

class GenProto[T](Protocol):
    def meth(self) -> T:
        ...
class httk.data.query.SearchField[source]

Bases: Protocol

A queryable field of a search variable.

In addition to the methods below, fields support the rich comparison operators (==, !=, <, <=, >, >=), returning SearchExpression. The handlers invoke those via getattr(field, '__eq__')(value) since the comparison dunders cannot be typed as expression-returning.

The three string-matching methods take literal text: no wildcard or pattern syntax whatsoever crosses this contract, so % and _ (and any other metacharacter) match themselves. A backend is therefore free to implement them with SQL LIKE over an escaped pattern, with a regular expression, or with a full-text index — the choice is invisible here.

has_any(*values: Any) SearchExpression[source]
has_only(*values: Any) SearchExpression[source]
contains(text: str) SearchExpression[source]

Match values containing text as a literal substring.

startswith(prefix: str) SearchExpression[source]

Match values beginning with the literal prefix.

endswith(suffix: str) SearchExpression[source]

Match values ending with the literal suffix.

class httk.data.query.SearchVariable[source]

Bases: Protocol

A query variable bound to a target type; attribute access yields fields.

always_true/always_false are reserved names: they are real methods of the variable, never stored fields resolved through __getattr__. They exist so a translation layer can express a constant truth value without inventing a probe field. A field == field probe is NULL-unsound, since it yields NULL (not true) for a NULL field.

always_true() SearchExpression[source]

An expression that matches every row.

always_false() SearchExpression[source]

An expression that matches no row.

class httk.data.query.SearchResult[source]

Bases: NamedTuple

One match: the declared output values, and the names they were declared under.

values holds one entry per Searcher.output() call in declaration order; it is a tuple, so values, names = result and result[0][0] both work.

values: tuple[Any, Ellipsis][source]
names: tuple[str, Ellipsis][source]
class httk.data.query.Searcher[source]

Bases: Protocol

A single query under construction, and its results once iterated.

Iteration yields one SearchResult per match, so item[0][0] is the first declared output of the match (typically the matched row object). The expressions received by add are always ones produced by this same backend’s search variables, so implementations may type them as their own expression class; a backend that needs a second (post-filter) evaluation position decides that from the expression itself, not from the caller.

offset: int[source]
variable(target: Any) Any[source]
output(variable: Any, name: str) None[source]
add(expression: Any) None[source]
count() int[source]
set_limit(limit: int) None[source]
add_offset(offset: int) None[source]
add_sort(field: Any, descending: bool) None[source]
class httk.data.query.Store[source]

Bases: Protocol

Base class for protocol classes.

Protocol classes are defined as:

class Proto(Protocol):
    def meth(self) -> int:
        ...

Such classes are primarily used with static type checkers that recognize structural subtyping (static duck-typing).

For example:

class C:
    def meth(self) -> int:
        return 0

def func(x: Proto) -> int:
    return x.meth()

func(C())  # Passes static type check

See PEP 544 for details. Protocol classes decorated with @typing.runtime_checkable act as simple-minded runtime protocols that check only the presence of given attributes, ignoring their type signatures. Protocol classes can be generic, they are defined as:

class GenProto[T](Protocol):
    def meth(self) -> T:
        ...
searcher() Searcher[source]