API
ZSets
ZSet
s can be added a + b
, negated -a
, ZSetPython
s can be multiplied a * n
They also have the following methods:
def iter(
self,
match: frozenset[T] | MatchAll
) -> Iterator[tuple[T, int]]:
...
[src] Iterates over the value, count of the ZSet
in no particular order. Optionally filter on a set of values.
def iter_by_index(
self,
index: Index[T, K],
match_keys: frozenset[K] | MatchAll
) -> Iterator[tuple[K, T, int]]:
...
[src] Iterates over the key, value, count of the indexed ZSet
in the order defined by the index. Optionally filter on a set of values.
Operators
Debugging
st.identity_print(
a: T,
) -> T
[src] Prints a
, then returns it.
Day to day
st.map(
a: st.ZSet[T],
*,
f: Callable[[T], V],
) -> st.ZSet[V]
[src] Maps function f
over all the values in a
st.map_many(
a: st.ZSet[T],
*,
f: Callable[[T], frozenset[V]],
) -> st.ZSet[V]
[src] Maps function f
over all the values in a
. f
returns many values in a frozenset
, these are unioned together in the returned ZSet
st.filter(
a: st.ZSet[T],
*,
f: Callable[[T], bool],
) -> st.ZSet[T]
[src] Equivalent to SQL’s WHERE
st.join(
l: st.ZSet[T],
r: st.ZSet[U],
*,
on_left: st.Index[T, K],
on_right: st.Index[U, K],
) -> st.ZSet[st.Pair[T, U]]
[src] Equivalent to SQL’s JOIN
st.outer_join(
l: st.ZSet[T],
r: st.ZSet[U],
*,
on_left: st.Index[T, K],
on_right: st.Index[U, K],
) -> st.ZSet[st.Pair[T, Union[U, st.Empty]]]
[src] Equivalent to SQL’s LEFT OUTER JOIN
, with Empty()
equivalent to NULL
st.distinct(
a: st.ZSet[T],
) -> st.ZSet[T]
[src] Equivalent to SQL’s DISTINCT
st.add(
a: TAddable,
b: TAddable,
) -> TAddable
[src] Adds two values, equivalent to SQL’s UNION
when applied to ZSet
s.
st.count(
a: st.ZSet[T],
) -> st.ZSet[int]
[src] Counts the number of values (effectively sum(count for _, count in a.iter())
). Returns a ZSet
containing a single int
st.first_n(
a: st.ZSet[T],
*,
index: st.Index[T, K],
n: int,
) -> st.ZSet[T]
[src] Similar to SQL’s ORDER BY ... LIMIT n
. The output is unordered (it’s still a ZSet
), but calling:
for key, value, count in z.iter_by_index(index):
...
Will yield values ordered by the index.
st.transitive_closure(
a: st.ZSet[st.Pair[TIndexable, TIndexable]],
) -> st.ZSet[st.Pair[TIndexable, TIndexable]]
[src] Given a set of edges left -> right
, returns the transitive closure of all the edges.
Example – given:
left right
0 1
1 2
2 3
0 4
1 5
Output:
left right
0 1
0 2
0 3
0 4
0 5
1 2
1 3
1 5
2 3
Read the code for ideas implementing other recursive functions.
Group/Reduce
st.reduce(
a: st.ZSet[T],
*,
zero: Callable[[], TReducable],
pick_value: Callable[[T], TReducable],
) -> st.ZSet[TReducable]
[src] A more general version of st.count(...)
. In common usage zero
and pick_value
will be functions that either:
- Return
0
and anint
, thereby implementing SQL’sSUM
. - Return an empty
ZSetPython[SomeType]
and aZSetPython[SomeType]
respectively, thereby (kinda) implementing SQL’sARRAY_AGG
Note that to handle the removal of rows in the inputted changes, TReducable
has to implement __mul__
(which luckily ZSetPython
s do).
st.group_reduce_flatten(
a: st.ZSet[T],
*,
by: st.Index[T, K],
zero: Callable[[], TReducable],
pick_value: Callable[[T], TReducable],
) -> st.ZSet[st.Pair[TReducable, K]]
[src] Equivalent to SQL’s SELECT reduce(...) FROM ... GROUP BY ...
. In common usage zero
and pick_value
will be functions that return a ZSetPython[SomeType]
The output is a ZSet
of pairs of the reduced value and the key they were grouped by.
st.group(
a: st.ZSet[T],
*,
by: st.Index[T, K],
) -> st.Grouped[st.ZSet[T], K]
[src] Groups a
by a key.
st.flatten(
a: st.Grouped[st.ZSet[T], K],
) -> st.ZSet[st.Pair[T, K]]
[src] Flattens a Group
to a more useful ZSet
Internal
st.neg(
a: TNegable,
) -> TNegable
[src] Returns -a
(remember, applicable to ZSet
s).
st.make_scalar(
a: st.ZSet[T],
*,
zero: Callable[[], T],
) -> T
[src] Turn a ZSet
of count = 1 to a scalar value.
st.make_set(
a: T,
) -> st.ZSet[T]
[src] Turn a scalar into a ZSet
of count = 1. SQL implicitly does this if you do SELECT 1
st.add3(
a: TAddable,
b: TAddable,
c: TAddable,
) -> TAddable
[src] Add three things.
st.haitch(
a: st.ZSet[T],
b: st.ZSet[T],
) -> st.ZSet[T]
[src] Used internally by st.distinct(...)
, efficiently watches for change of sign in counts.
Delay/Differentiate/Integrate
st.delay(
a: T,
) -> T
[src] Returns the previous value it was called with, see reference page.
st.delay_indexed(
a: st.ZSet[T],
*,
indexes: tuple[st.Index[T, K]], ...],
) -> st.ZSet[T]
[src] Returns the previous value it was called with, with indexes.
st.differentiate(
a: TAddAndNegable,
) -> TAddAndNegable
[src] Differentiates input values over time. See reference page.
st.integrate(
a: TAddable,
) -> TAddable
[src] Integrates input values over time. See reference page.
st.integrate_indexed(
a: st.ZSet[T],
*,
indexes: tuple[st.Index[T, K]], ...],
) -> st.ZSet[T]
[src] Integrates input values over time, adds indexes to the delay node. See reference page.
st.integrate_delay(
a: TAddable,
) -> TAddable
[src] Integrates input values over time, returns the previous value. See reference page.
Compile
st.compile(
func: Callable[..., Any],
) -> st.Graph[Any, Any]
[src] Compile a query function to a graph.
st.compile_lazy(
func: Callable[..., Any],
) -> Callable[[], st.Graph[Any, Any]]
[src] Returns a function with no arguments that compiles the graph, caches it and returns it.
st.compile_typeof(
t: T,
) -> type[T]
[src] Get the resolved type of t
at query compile time.
with st.at_compile_time:
...
[src] Run this code block at query compile time.
Run
st.iteration(
store: st.Store,
g: st.Graph[Any, Any],
inputs: tuple[Any, ...],
flush: bool,
) -> tuple[Any, ...]
[src] Run a single iteration of a graph, returning resultant changes.
st.actions(
store: st.Store,
g: st.Graph[Any, Any],
) -> Any
[src] Return a tuple of helpers to insert, remove, replace. Examples dotted around the docs.
Indexes
Indexes pick a key of type K
from a value of type T
. The index key should be indexable:
IndexableAtom = str | int | float | bool | None | date | datetime | UUID
Indexable = IndexableAtom | tuple[IndexableAtom, ...]
For each of the constructor methods, an optional boolean ascending
can be passed in, this is equivalent to SQL’s ASC
/DESC
. If the key is tuple[IndexableAtom, ...]
, ascending
must be a tuple of bools of the same length.
st.Index.atom(
name: str,
t: type[T],
k: type[KAtom],
f: Callable[[T], KAtom],
ascending: bool = True,
) -> Index[T, KAtom]:
[src] Pick an index of t
using an f
that returns an IndexableAtom
.
st.Index.composite(
names: tuple[str, ...],
t: type[T],
k: type[KTuple],
f: Callable[[T], KTuple],
ascendings: tuple[bool, ...] | None = None,
) -> Index[T, KTuple]:
[src] Pick an index of t
using an f
that returns a composite value, i.e. a tuple[IndexableAtom, IndexableAtom, ...]
.
st.Index.identity(
t: type[KAtom],
ascending: bool = True,
) -> Index[KAtom, KAtom]:
[src] Use a value that is already an IndexableAtom
as an index.
st.Index.pick(
t: type[T],
f: Callable[[T], K],
ascending: bool | tuple[bool, ...] = True,
) -> st.Index[T, K]
[src] Pick an index of t
using a lambda
function. The lambda function gets immediately called to determine the names and types of the index, so is somewhat restricted.
Database Connections
with st.connection_postgres(db_url: str) as conn:
...
[src] Context manager for a Postgres connection.
with st.connection_sqlite(db_url: pathlib.Path) as conn:
...
[src] Context manager for a SQLite connection.
Helpers
st.batched(
iterable: list[T],
n: int,
) -> Iterator[list[T]]
[src] See itertools docs.
st.write_png(
graph: st.Graph[Any, Any],
path: str,
simplify_labels: bool,
level: int,
) -> NoneType
[src] Write a graph to a .png
file using dot