Skip to main content

In-process bridge between DuckDB connections with permission-based access control

Project description

n6k-duckdb

In-process bridge between DuckDB connections with permission-based access control.

Install

pip install n6k-duckdb

Usage

import duckdb
from n6k_duckdb.bridge import bridge

cfg = {"allow_unsigned_extensions": "true"}
source = duckdb.connect(config=cfg)
source.sql("CREATE TABLE users(id INTEGER, name VARCHAR)")
source.sql("INSERT INTO users VALUES (1, 'alice'), (2, 'bob')")

target = duckdb.connect(config=cfg)
bridge(source, target, "app", permissions={"users": "readwrite"})

# Query through the bridge
target.sql("SELECT * FROM app.users").show()

# Insert through the bridge (requires 'readwrite')
target.sql("INSERT INTO app.users VALUES (3, 'charlie')")

# Update and delete also work with 'readwrite'
target.sql("UPDATE app.users SET name = 'Alice' WHERE id = 1")
target.sql("DELETE FROM app.users WHERE id = 2")

Permissions

Permission Allows
'read' SELECT only
'readwrite' SELECT, INSERT, UPDATE, DELETE

Tables not listed in permissions are inaccessible.

How it works

bridge() automatically installs and loads the n6k_bridge DuckDB extension from the n6k extension repository. The extension creates an in-process bridge between two DuckDB database instances using a token-based handshake.

No network server is required — data flows directly between connections in the same process.

Server framework (optional extra)

This package also ships a reusable FastAPI framework for serving the n6k protocol — install with pip install "n6k-duckdb[test-server]".

Minimal server with a DuckDB backend:

import duckdb
from fastapi import FastAPI, WebSocket
from n6k_duckdb.duckdb_handler import DuckDBHandler
from n6k_duckdb.server_fastapi.register import register, resolve_ws_catalog
from n6k_duckdb.server_asgi.ws import WsReject

app = FastAPI()


def session_factory(ws: WebSocket, **_):
    # The catalog comes from ?catalog=<name> or the FT_HELLO handshake frame —
    # resolve_ws_catalog merges the two and raises on a mismatch.
    catalog = resolve_ws_catalog(ws)
    if not catalog:
        raise WsReject(code=4400, reason="missing catalog")
    con = duckdb.connect()
    con.execute(f"ATTACH ':memory:' AS \"{catalog}\"")
    # ... populate tables in `con` ...
    return DuckDBHandler(con, catalog_name=catalog)


# catalog_from_handshake lets clients that dial a bare /ws (wsFd / wsId, where the
# host owns the socket) declare the catalog in the handshake frame; the adapter
# reads it when ?catalog= is absent.
register(app, prefix="", session=session_factory, catalog_from_handshake=True)

# Run: `uvicorn your_module:app --port 8099`

A worked example — auth, per-WS observability, read-only sessionless — lives in src/n6k_duckdb/test_server/app.py. Run it with python -m n6k_duckdb.test_server --port 8099.

Notifying clients of stale catalog entries

When the server's catalog state changes outside of a client's own DDL (e.g. another writer dropped a view), peers' cached table listings go stale. DuckDBHandler exposes three helpers, gated on a bound Provider (the version counters live in n6k_bridge's provider registry):

  • await handler.get_invalidated_schemas() — schema names whose provider version is ahead of the last snapshot we acknowledged in a push.
  • await handler.notify_invalidate(["main"]) — send one FT_PUSH(OP_CATALOG_INVALIDATED) naming the given schemas; the client drops its cached entries for them and refetches on next access.
  • await handler.notify_invalidate_if_stale() — convenience: poll + push; returns True iff a frame was sent.

The framework does not auto-fire these — call them wherever your server considers correct (after a mutation, on an idle tick, etc.).

The framework is backend-agnostic: N6KSessionHandler / N6KSessionlessHandler can wrap any data source. For a non-duckdb example see src/n6k_duckdb/server/__tests__/test_memory_handler.py (an in-memory dict[str, pa.Table] backend).

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

n6k_duckdb-0.7.2.tar.gz (100.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

n6k_duckdb-0.7.2-py3-none-any.whl (129.7 kB view details)

Uploaded Python 3

File details

Details for the file n6k_duckdb-0.7.2.tar.gz.

File metadata

  • Download URL: n6k_duckdb-0.7.2.tar.gz
  • Upload date:
  • Size: 100.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for n6k_duckdb-0.7.2.tar.gz
Algorithm Hash digest
SHA256 06404b724c03da7aed941f3c81b9d3a62a70e11bab4ff513ae05a86f4547fca1
MD5 8c96ecdf4da8a724fd97570b352d5caa
BLAKE2b-256 336804225f250d6e0559c82de3234faef8e3bd9a576b25959b06d8f9b36c4888

See more details on using hashes here.

Provenance

The following attestation bundles were made for n6k_duckdb-0.7.2.tar.gz:

Publisher: release-python.yml on n6k-io/duckdb-extension

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file n6k_duckdb-0.7.2-py3-none-any.whl.

File metadata

  • Download URL: n6k_duckdb-0.7.2-py3-none-any.whl
  • Upload date:
  • Size: 129.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for n6k_duckdb-0.7.2-py3-none-any.whl
Algorithm Hash digest
SHA256 c04e028e1ef86d7b1dda87eb22aed57aaa7bb5c16cba24093ebb1079866ea6b0
MD5 eca621bcf12840b87538a06d36ab3c8d
BLAKE2b-256 47fe602f98bb1ea9f35d50435439b6be1e1e21e9a8c2f8e8ea4a9e572ff863d9

See more details on using hashes here.

Provenance

The following attestation bundles were made for n6k_duckdb-0.7.2-py3-none-any.whl:

Publisher: release-python.yml on n6k-io/duckdb-extension

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page