Skip to content

Repository files navigation

ladybug-adbc — Arrow Flight / ADBC for LadybugDB

app.py serves LadybugDB Cypher results as Flask REST + JSON (Arrow -> to_pydict() -> json.dumps, Snowflake {"data": [[row, json], ...]} protocol). This package serves the same queries as native Arrow columnar batches over gRPC, consumed with the standard columnar.tech ADBC methods — no row-by-row JSON.

Install (uv)

uv sync                 # creates .venv (ladybug comes from PyPI)
# recipe one-liner also works:
# uv pip install ladybug pyarrow adbc-driver-flightsql

Run

# 1. server (:memory: demo graph, same data as app.build_demo_graph)
uv run python ladybug_flight_server.py
# grpc://localhost:50051, try: --db /tmp/graph.lbdb --port 50051 --no-demo

# 2. client — ADBC, exactly the posted recipe but pointed at LadybugDB
uv run python ladybug_adbc_client.py
uv run python ladybug_adbc_client.py --demo            # all 6 demo queries
uv run python ladybug_adbc_client.py --no-adbc --demo  # plain FlightClient path

The recipe, adapted

import adbc_driver_flightsql.dbapi as flight_sql

with flight_sql.connect("grpc://localhost:50051") as conn:
    with conn.cursor() as cur:
        cur.execute("MATCH (u:User) RETURN u.name, u.age ORDER BY u.id")
        table = cur.fetch_arrow_table()  # pyarrow.Table — zero JSON overhead
        print(table)

SQL vs Cypher

adbc_driver_flightsql is typically tied to SQL (cursor.execute(sql), CommandStatementQuery{query}), but query is just a string on the wire. LadybugFlightServer treats it as Cypher (see extract_query()), so the columnar.tech call pattern works unchanged for a graph DB. CALL show_tables() keeps working for schema introspection.

REST vs Arrow

REST (app.py) Arrow (ladybug_flight_server.py)
encoding to_pydictjson.dumps → parse Arrow IPC over gRPC
types lost (everything is JSON) preserved (schema, fetch_arrow_table)
client POST /query {"data": [[0, cypher]]} cursor.execute(cypher)
batching manual row-index envelope RecordBatchStream / fetch_arrow_table

Docker (GHCR)

Prebuilt multi-arch images (amd64/arm64, Debian 3.14-slim base) are published to GHCR on every GitHub Release — no PyPI publish for this repo by design.

docker pull ghcr.io/ladybugdb/ladybug-adbc-python:latest

# :memory: demo graph on localhost:50051
docker run --rm -p 50051:50051 ghcr.io/ladybugdb/ladybug-adbc-python:latest

# persistent graph via a volume (server runs as non-root, /data is writable)
docker run --rm -p 50051:50051 -v ladybug-data:/data \
  -e LADYBUG_DB=/data/graph.lbdb \
  ghcr.io/ladybugdb/ladybug-adbc-python:latest

# query it (same columnar.tech recipe, local or remote host)
uv run python ladybug_adbc_client.py --demo

Env knobs: FLIGHT_HOST (default 0.0.0.0 in the image), FLIGHT_PORT (default 50051), LADYBUG_DB (default :memory:). CLI flags (--host/--port/--db) override env. A HEALTHCHECK probes the server with a trivial RETURN 1 Flight query.

Build locally:

docker build -t ladybug-adbc:dev .

Releasing

  1. Bump version in pyproject.toml, commit, push.
  2. GitHub UI → Releases → Draft a new release, tag vX.Y.Z → Publish.
  3. .github/workflows/docker-publish.yml runs tests, then pushes ghcr.io/ladybugdb/ladybug-adbc-python:X.Y.Z, X.Y, and latest (latest skipped for prereleases). No PyPI upload — PyPI later, maybe.

Files

  • app.py — legacy Flask REST (unchanged, for comparison).
  • ladybug_flight_server.pyLadybugFlightServer(FlightServerBase), demo graph, protobuf-tolerant extract_query.
  • ladybug_adbc_client.pyquery_cypher_adbc() / query_cypher_flight().
  • tests/test_flight.py — spins up the server on an ephemeral port, asserts ADBC + Flight return identical Arrow tables.

About

Arrow Flight / ADBC columnar server for LadybugDB (Docker images on GHCR)

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages