Metadata-Version: 2.2
Name: ubik-sql
Version: 1.2.1
Summary: Embeddable streaming SQL, in-process: import ubik, real SQL, exactly-once windows, no cluster.
Keywords: streaming,sql,kafka,exactly-once,duckdb,windows,embeddable
Author: Ubik
License: Proprietary
Classifier: License :: Other/Proprietary License
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Database :: Database Engines/Servers
Classifier: Topic :: Scientific/Engineering :: Information Analysis
Project-URL: Homepage, https://getubik.dev
Requires-Python: >=3.9
Requires-Dist: pyarrow>=14
Provides-Extra: pandas
Requires-Dist: pandas>=2.2; extra == "pandas"
Provides-Extra: polars
Requires-Dist: polars>=0.20; extra == "polars"
Description-Content-Type: text/markdown

# ubik

Embeddable streaming SQL, in-process. `import ubik`, one query string, real SQL
with exactly-once windows underneath, in a notebook, zero infra.

```sh
pip install ubik-sql
```

The module is `ubik`.

```python
import ubik
import pandas

# enrich a Kafka stream against a DataFrame, windowed, in one cell
merchants = pandas.DataFrame({"id": [10, 20], "region": ["EU", "US"]})
tbl = ubik.stream(
    "SELECT m.region, count(*) AS c "
    "FROM orders o JOIN merchants m ON o.merchant_id = m.id "
    "GROUP BY m.region, TUMBLE(o.event_time, INTERVAL 1 MINUTE)",
    from_="kafka://localhost:9092/orders",
    tables={"merchants": merchants},
).arrow()
```

Arrow in, Arrow out: a host table (pandas, polars, pyarrow) enters through the
Arrow C stream, results leave as Arrow record batches. Read the whole result with
`.arrow()` / `.df()` / `.pl()`, iterate it for record batches, or `.rows()` for
dicts.

## Durable live pipelines

`ubik.pipeline(..., checkpoint=...)` tails a topic without end and survives a
process restart from its checkpoint. The kill-9 guarantee, native to Python: a
restart loses no event and double-counts none.

```python
Q = ("SELECT merchant, TUMBLE(ts, INTERVAL 1 MINUTE) AS w, count(*) AS c "
     "FROM orders GROUP BY merchant, TUMBLE(ts, INTERVAL 1 MINUTE)")
with ubik.pipeline(Q, from_="kafka://localhost:9092/orders",
                   checkpoint="~/.ubik/orders") as p:
    for window in p:          # yields each closed window as it emits
        react(window)         # a pyarrow RecordBatch
```

The `checkpoint` path is the pipeline's identity: the first run creates it, a
later run (after a clean exit or a crash) resumes from it automatically.

## Errors

Every error raises `ubik.UbikError` carrying `.code`, `.message`, `.hint`.

```python
try:
    ubik.stream(sql, from_="kafka://localhost:9092/orders").arrow()
except ubik.UbikError as e:
    print(e.code, e.hint)
```

## Requirements

`pyarrow>=14` is the result surface (installed with ubik). `pandas` and `polars`
are optional, imported lazily by `.df()` / `.pl()`.
