duckdb

DuckDB bindings for Kit - in-process analytical database

Files

FileDescription
.editorconfigEditor formatting configuration
.gitignoreGit ignore rules for build artifacts and dependencies
.tool-versionsasdf tool versions (Zig, Kit)
LICENSEMIT license file
README.mdThis file
c/kit_duckdb.cC FFI wrapper
c/kit_duckdb.hC header for FFI wrapper
examples/basic.kitBasic usage example
examples/sql-dsl.kitExample: SQL DSL
kit.tomlPackage manifest with metadata and dependencies
src/duckdb.kitDuckDB bindings for Kit
tests/duckdb.test.kitTests for DuckDB constants and error types
tests/error-types.test.kitTests for typed DuckDB errors

Dependencies

No Kit package dependencies.

Native dependency:

  • DuckDB C library (duckdb)

On macOS:

brew install duckdb

Installation

kit add gitlab.com/kit-lang/packages/kit-duckdb.git

Usage

import Env

import Kit.DuckDB as DuckDB

load-users = fn(path) =>
  db = DuckDB.try-connect path ?!

  db.execute "CREATE TABLE users (id INTEGER, name VARCHAR, score DOUBLE)" ?!
  db.execute "INSERT INTO users VALUES (1, 'Alice', 95.5), (2, 'Bob', 87.3), (3, 'Carol', 91.0)" ?!

  rows = db.query "SELECT name, score FROM users ORDER BY score DESC" ?!
  high-scores = sql db {SELECT name, score FROM users WHERE score > 90 ORDER BY score DESC} ?!

  Ok {users: List.length rows, high-scores: List.length high-scores}

main = fn =>
  db-path = Env.get "DUCKDB_DATABASE" ?? ":memory:"

  match load-users db-path
    | Ok summary ->
      println "Loaded ${summary.users} users"
      println "High scores: ${summary.high-scores}"
    | Err e ->
      println "DuckDB error: ${show e}"

main

Development

Running Examples

Run examples with the interpreter:

kit run examples/basic.kit --allow=ffi,file --no-spinner

Compile examples to a native binary:

kit build examples/basic.kit --allow=ffi,file --no-spinner && ./basic

Run interpreter/compiler parity for examples:

kit parity --no-spinner --failures-only

Running Tests

Run the test suite:

kit test

Run the test suite with coverage:

kit test --coverage

Running kit dev

Run the standard development workflow (format, check, test):

kit dev --no-spinner

This will:

  1. Build the native C wrapper
  2. Format and check source and example files
  3. Run tests in tests/ with coverage

Generating Documentation

Generate API documentation from doc comments:

kit doc

Note: Kit sources with doc comments (##) will generate HTML documents in docs/*.html

Cleaning Build Artifacts

Remove generated files, caches, and build artifacts:

kit task clean

Note: Defined in kit.toml.

Local Installation

To install this package locally for development:

kit install

This installs the package to ~/.kit/packages/@kit/duckdb/, making it available for import as Kit.DuckDB in other projects.

License

This package is released under the MIT License - see LICENSE for details.

DuckDB is also released under the MIT License.

Exported Functions & Types

DuckDBError

DuckDB error type for typed error handling. Variants distinguish between different failure modes.

Variants

DuckDBConnectionError {message}
DuckDBQueryError {message}
DuckDBExecuteError {message}
DuckDBTypeError {message}

duckdb-success

Okresult state constant.

duckdb-error

Error result state constant.

duckdb-type-invalid

Invalid column type constant.

duckdb-type-boolean

Boolean column type constant.

duckdb-type-tinyint

Tiny integer column type constant.

duckdb-type-smallint

Small integer column type constant.

duckdb-type-integer

Integer column type constant.

duckdb-type-bigint

Big integer column type constant.

duckdb-type-utinyint

Unsigned tiny integer column type constant.

duckdb-type-usmallint

Unsigned small integer column type constant.

duckdb-type-uinteger

Unsigned integer column type constant.

duckdb-type-ubigint

Unsigned big integer column type constant.

duckdb-type-float

Float column type constant.

duckdb-type-double

Double column type constant.

duckdb-type-timestamp

Timestamp column type constant.

duckdb-type-date

Date column type constant.

duckdb-type-time

Time column type constant.

duckdb-type-interval

Interval column type constant.

duckdb-type-hugeint

Huge integer column type constant.

duckdb-type-varchar

Variable character column type constant.

duckdb-type-blob

Binary large object column type constant.

duckdb-type-decimal

Decimal column type constant.

connect

Note: This module uses Kit's standard Result type (Ok a | Err DuckDBError).

Opens a DuckDB database connection.

Creates a connection to a DuckDB database, either in-memory or file-backed. Returns a connection record containing the database handle and methods for query execution. The connection record includes error information if the connection fails.

Parameters:

Returns:

String -> {handle: Ptr, database: Ptr, driver: String, connected: Bool, error: String, query: String -> Result (List (Map String a)) DuckDBError, execute: String -> Result Int DuckDBError}

db = DuckDB.connect ":memory:"    # in-memory database
db = DuckDB.connect "analytics.db" # file-based database
result = db.query "SELECT * FROM users"

try-connect

Attempts to connect to DuckDB, returning Result type.

Similar to connect but uses a Result type for functional error handling. Returns Ok with a connection record if successful, or Error with a message string if the connection fails.

Parameters:

Returns:

String -> Result {handle: Ptr, database: Ptr, driver: String, connected: Bool, error: String, query: String -> Result (List (Map String a)) DuckDBError, execute: String -> Result Int DuckDBError} DuckDBError

match DuckDB.try-connect ":memory:"
| Ok db ->
    result = db.query "SELECT 42 as answer"
| Err e ->
    print "Connection failed: ${e}"

is-connected?

Checks if a database connection is valid.

Parameters:

Returns:

{connected: Bool | r} -> Bool

db = DuckDB.connect "test.db"
if DuckDB.is-connected? db then
  print "Connected successfully"

close

Closes a database connection and database.

Cleans up resources associated with a database connection. Currently a no-op due to crashes in cleanup functions. Resources are automatically cleaned up when the process exits.

Parameters:

Returns:

a -> Unit

db = DuckDB.connect ":memory:"
# ... use database ...

query

Executes a query and returns all rows as a list of records.

Executes a SQL SELECT query and parses all result rows into Kit records. Each row is returned as a record with column names as keys and values wrapped in Option types (Some for non-null, None for null).

Parameters:

Returns:

Ptr -> NonEmptyString -> Result (List (Map String a)) DuckDBError

match query connection "SELECT id, name FROM users WHERE id > 10"
| Ok rows ->
    rows |> List.each fn(row) =>
      match Map.get "name" row
      | Some (Some name) -> print name
      | _ -> print "No name"
| Err e -> print "Query error: ${e}"

execute

Executes a statement (INSERT, UPDATE, DELETE, CREATE, etc.) and returns affected row count.

Executes a SQL statement that modifies data or schema and returns the number of rows affected. Use this for INSERT, UPDATE, DELETE, CREATE TABLE, DROP TABLE, and other non-SELECT statements.

Parameters:

Returns:

Ptr -> NonEmptyString -> Result Int DuckDBError

match execute connection "INSERT INTO users (id, name) VALUES (1, 'Alice')"
| Ok count -> print "Inserted ${Int.to-string count} rows"
| Err e -> print "Insert error: ${e}"