AI Decision System
Replayable, offline-verifiable records for AI-assisted go/no-go decisions: experiment promotions, typed model answers and human-approved actions.
A safe, embedded-first Rust client for DuckDB — with an optional Diesel 2.3 ORM backend, UDF/derive macros, and a Tauri v2 plugin.
Developer toolsRust · TypeScriptGitHub @nimdeveloperOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
A safe, embedded-first Rust client for DuckDB, with an optional Diesel 2.3 ORM backend.
Taken from the repository README
Loading the full README.
Read the full README ↗A safe, embedded-first Rust client for DuckDB, with an optional Diesel 2.3 ORM backend.
[!WARNING] Beta — the API is settling. Breaking changes before
1.0are possible; check the changelog before upgrading.
arrow feature exports results via the Arrow C Data Interface with no added dependencies.unsafe leaks into your code, across the full DuckDB type system.DECIMAL, UUID, BIT, BIGNUM, temporals, and the composite LIST / ARRAY / STRUCT / MAP / UNION / ENUM types.#[derive(…)] — no unsafe, no manual vector handling.[dependencies]
# DuckDB client
better-duck-core = "0.1.0-beta.8"
# Optional: Diesel ORM backend
better-duck-diesel = "0.1.0-beta.8"
[!NOTE] Cargo's default version requirement (e.g.
"0.1") excludes pre-releases like-beta.4. Pin the exact version as shown, or runcargo add better-duck-core --version 0.1.0-beta.8.better-duck-macrosis pulled in automatically by theudf/derivefeature flags — you don't depend on it directly.
Beyond being a safe DuckDB client, better-duck adds capabilities that other Rust DuckDB bindings don't offer. Each is opt-in behind a feature flag, and each is designed to need no unsafe and no manual FFI on your side.
feature = "derive"Four derives turn plain Rust structs and enums into DuckDB rows, values, and types — no hand-written column indexing, no manual DuckValue matching.
#[derive(FromRow)] — read a query row into a struct by column name; ResultSet::to_structs::<T>() collects a whole result into Vec<T>.#[derive(ToRow)] — append a struct's fields as one bulk-appender row, or bind them as consecutive statement parameters.#[derive(DuckEnum)] — map a Rust unit enum to a DuckDB ENUM (read + write), with #[duck_enum(rename_all = "…")] / per-variant rename.#[derive(DuckStruct)] — map a Rust struct to a DuckDB STRUCT value (read + write).use better_duck_core::{connection::Connection, DuckEnum, FromRow};
#[derive(DuckEnum, Debug, PartialEq, Clone, Copy)]
#[duck_enum(rename_all = "snake_case")]
enum Priority { Low, High }
#[derive(FromRow, Debug)]
struct Task { id: i32, priority: Priority }
let tasks: Vec<Task> = conn.execute("SELECT id, priority FROM tasks")?.to_structs()?;
Field/variant names honor #[duck(rename = "…")] and #[duck(rename_all = "…")]. With better-duck-diesel's derive feature on, DuckEnum/DuckStruct also emit Diesel FromSql/ToSql, so the same type works through the ORM at its sql_types::DuckEnum / sql_types::DuckStruct column type.
feature = "udf"Register ordinary Rust functions as DuckDB functions with an attribute macro. Parameter and return types are inferred from the signature; Option<T> propagates NULL, a Result<T, E> return fails the query with E's message, and panics are caught and surfaced as a query error rather than crossing the FFI boundary.
| Macro | Applies to | Becomes |
|---|---|---|
#[duckdb_scalar] | fn(args) -> T | a scalar function (one value per row) |
#[duckdb_table_function] | fn(args) -> impl Iterator | a table function usable in FROM (named params, projection pushdown, shared state) |
#[duckdb_aggregate] | mod { init, update, combine, finalize } | a custom aggregate |
#[duckdb_cast] | fn(from) -> to | a CAST / TRY_CAST implementation |
use better_duck_core::{connection::Connection, duckdb_scalar, duckdb_table_function};
#[duckdb_scalar]
fn shout(s: &str) -> String { s.to_uppercase() }
#[duckdb_table_function(name = "series", columns("n"))]
fn series(start: i64, stop: i64) -> impl Iterator<Item = i64> + Send { start..stop }
shout::register(&mut conn)?;
series::register(&mut conn)?;
conn.execute("SELECT shout('hi')")?; // "HI"
conn.execute("SELECT sum(n) FROM series(1, 101)")?; // 5050
better-duck-diesel feature = "udf"Register a UDF on the connection, declare it once as a Diesel function, and then call it as a typed method inside the query DSL — the same Rust function, reachable from the ORM without dropping to sql_query.
use better_duck_diesel::DuckDbConnection;
use diesel::prelude::*;
#[duckdb_scalar(name = "add_one")]
fn add_one(x: i32) -> i32 { x + 1 }
diesel::define_sql_function! { fn add_one(x: Integer) -> Integer; }
add_one_impl::register(conn.inner_mut())?; // register on the underlying connection
let bumped: Vec<i32> = items::table.select(add_one(items::id)).load(&mut conn)?;
For connection pools, SharedDuckDbConnectionManager::on_connect(|c| …) runs a per-connection setup hook — the place to register UDFs (or LOAD extensions) so every pooled connection carries them.
use better_duck_diesel::dsl::*;A large library of DuckDB-specific SQL, exposed as typed Diesel DSL that stock Diesel has no equivalent for:
.ilike(), .not_ilike(), .similar_to(), .glob(), .regexp_matches(), .starts_with_op(), .is_distinct_from() / .is_not_distinct_from().levenshtein, jaro_winkler_similarity, lpad, split_part, …), numeric & trig (sqrt, pow, gcd, sin, atan2, …), regex, date/time (date_trunc, strftime, make_timestamp, datediff, …), UUID, hashing (sha256), encoding (base64, hex), JSON, and LIST / MAP helpers.string_agg, array_agg, bool_and/or, arg_max/min), statistical (stddev, corr, regr_slope, skewness, …), approximate (approx_count_distinct, approx_quantile), bitwise, and JSON aggregates.use better_duck_diesel::dsl::*;
let hits = products::table
.filter(products::name.ilike("wid%")) // case-insensitive LIKE operator
.select(products::id)
.load::<i32>(&mut conn)?;
Custom-typed values (u64, i128, UUID, BIT, BIGNUM, …) bind and load through the better_duck_diesel::values::* newtypes, which sidestep the coherence limits that block binding those types directly.
Every scalar and composite DuckDB type round-trips through DuckValue and the Diesel sql_types: integers of every width (including HUGEINT/UHUGEINT ↔ i128/u128), DECIMAL, UUID, BIT, BIGNUM, all temporal precisions (TIMESTAMP_S/MS/NS, TIMESTAMPTZ, TIME_TZ with its offset preserved), and the composites LIST / ARRAY / STRUCT / MAP / UNION / ENUM. Date/time types map to chrono (feature = "chrono") or to plain native structs without it.
feature = "derive"transaction!(conn, { … }) — a scope that commits on Ok and rolls back on Err or panic. It works for both the core Connection and a DuckDbConnection, since both expose transaction(|c| -> Result<_>).params![a, b, Null, …] — build the &mut [&mut dyn AppendAble] slice for execute_with without the boilerplate.feature = "spatial"Connection can install / load / ensure / query extensions (ensure_extension("json")). The diesel spatial module adds ST_* DSL functions plus ensure_loaded(conn), which installs and loads DuckDB's spatial extension on demand; geometries travel as WKB.
feature = "async" / feature = "pool" / r2d2An async facade (AsyncConnection, AsyncDatabase, AsyncPool) runs each call on spawn_blocking so it never blocks the executor, and connection pooling is available both through Diesel's own r2d2 manager and a SharedDuckDbConnectionManager that shares one database across the pool.
| Crate | Flag | What it enables |
|---|---|---|
| core | chrono (default) | chrono date/time conversions |
| core | decimal (default) | rust_decimal::Decimal for DECIMAL |
| core | json / parquet | bundle DuckDB's JSON / Parquet extensions |
| core | arrow | zero-dependency Arrow C Data Interface export of query results |
| core | udf | the #[duckdb_*] function macros |
| core | derive | #[derive(FromRow/ToRow/DuckEnum/DuckStruct)] + transaction! / params! |
| core | async / pool | async facade / r2d2 pool over a shared database |
| diesel | derive | re-export the data derives with Diesel FromSql/ToSql emission |
| diesel | udf | register UDFs on a DuckDbConnection and call them in the DSL |
| diesel | spatial | ST_* DSL functions + ensure_loaded helper |
| diesel | json | bundle the JSON extension so the JSON DSL works offline |
| diesel | r2d2 / chrono | r2d2 pooling / Diesel date-time impls |
Full API documentation lives on docs.rs.
Full per-crate documentation. Each section is collapsed by default — expand what you need, or read the rendered API docs on docs.rs.
use better_duck_core::connection::Connection;
let mut conn = Connection::open_in_memory()?; // in-memory
let mut conn = Connection::open("my_database.duckdb")?; // on-disk
execute returns a DuckResult, which is an Iterator of DuckRow:
let mut result = conn.execute("SELECT id, label FROM events ORDER BY id")?;
for row in result {
let row = row?;
println!("{:?} {:?}", row.get("id"), row.get("label"));
}
Parameters are positional ($1, $2, …). Pass them as &mut [&mut dyn AppendAble] — or use the
params! macro (feature derive):
use better_duck_core::types::value::DuckValue;
let mut threshold = DuckValue::Double(8.0);
let rows = conn.execute_with(
"SELECT id, label FROM events WHERE score > $1",
&mut [&mut threshold],
)?;
The Appender streams rows into DuckDB's bulk-ingest path — far faster than individual INSERTs.
Implement AppendAble by hand, or derive it with #[derive(ToRow)] (feature derive):
use better_duck_core::{connection::Connection, ToRow};
#[derive(ToRow)]
struct NewItem { id: i32, name: String }
let mut conn = Connection::open_in_memory()?;
conn.execute_batch("CREATE TABLE items (id INTEGER, name TEXT)")?;
let mut app = conn.appender("items", "main")?;
app.append(&mut NewItem { id: 1, name: "a".to_owned() })?;
app.save()?; // flush (also auto-flushes on drop)
open_in_memory() gives each connection its own database. To share one database across connections,
open a Database and connect() from it:
use better_duck_core::database::Database;
let db = Database::open_in_memory()?;
let mut a = db.connect()?;
let mut b = db.connect()?; // sees a's tables
pool — Database backs an r2d2 pool: DuckDbConnectionManager::memory()? → Pool::builder().build(manager)?.async — AsyncConnection runs each call on spawn_blocking, never blocking the executor; async + pool gives AsyncPool::with(...).conn.ensure_extension("json")?; // load, installing first if needed
let loaded = conn.is_extension_loaded("json")?; // query duckdb_extensions()
DuckValue and supported typesRows are DuckRow; each column value is a #[non_exhaustive] DuckValue — match with a _ arm to stay forward-compatible.
| DuckDB type | Rust type |
|---|---|
BOOLEAN | bool |
TINYINT / UTINYINT | i8 / u8 |
SMALLINT / USMALLINT | i16 / u16 |
INTEGER / UINTEGER | i32 / u32 |
BIGINT / UBIGINT | i64 / u64 |
HUGEINT / UHUGEINT | i128 / u128 |
FLOAT / DOUBLE | f32 / f64 |
DECIMAL (feature: decimal) | rust_decimal::Decimal |
VARCHAR / TEXT | String |
BLOB | better_duck_core::types::blob::Blob |
DATE / TIME / TIMESTAMP | chrono::NaiveDate / NaiveTime / NaiveDateTime (chrono) / native |
TIMESTAMPTZ | chrono::DateTime<Utc> (chrono) |
TIME_TZ | date_chrono::TimeTz (chrono) / DuckTimeTz — UTC offset preserved |
INTERVAL | chrono::Duration (chrono) / std::time::Duration |
LIST / ARRAY | Vec<DuckValue> / Box<[DuckValue]> |
STRUCT / MAP | HashMap<String, DuckValue> / HashMap<DuckValue, DuckValue> |
UNION | active member (see roadmap for multi-arm write) |
Register plain Rust functions with attribute macros — parameter/return types inferred from the signature, no unsafe. See the macros reference below for the full set (#[duckdb_scalar], #[duckdb_table_function], #[duckdb_aggregate], #[duckdb_cast]), named parameters, projection pushdown, scalar state, and replacement scans.
| Feature | Default | Description |
|---|---|---|
chrono | ✓ | chrono date/time conversions for DATE, TIME, TIMESTAMP, TIMESTAMPTZ, INTERVAL |
decimal | ✓ | rust_decimal::Decimal support for DECIMAL columns |
json | — | Statically bundle DuckDB's JSON extension (compiled into the embedded library) |
parquet | — | Statically bundle DuckDB's Parquet extension (compiled into the embedded library) |
arrow | — | Export query results via the Arrow C Data Interface (no added dependencies) |
columnar | — | Columnar data-chunk read/write: fetch_chunk, zero-copy as_slice reads, build-and-bulk-insert (also enabled by udf) |
async | — | Tokio async facade (AsyncConnection, AsyncDatabase, AsyncPool) |
pool | — | r2d2 connection pool backed by a shared Database handle |
udf | — | #[duckdb_scalar] / #[duckdb_table_function] / #[duckdb_aggregate] / #[duckdb_cast] |
derive | — | #[derive(FromRow/ToRow/DuckEnum/DuckStruct)] + transaction! / params! |
buildtime_bindgen | — | Regenerate FFI bindings at build time (requires LLVM/clang) |
use better_duck_diesel::DuckDbConnection;
use diesel::prelude::*;
let mut conn = DuckDbConnection::establish(":memory:")?; // in-memory
let mut conn = DuckDbConnection::establish("/path/to/db.duckdb")?; // on-disk
let mut conn = DuckDbConnection::establish("duckdb:///path/db.duckdb")?; // duckdb:// prefix stripped
Standard Diesel — INSERT (with RETURNING), SELECT with filter/order, UPDATE, DELETE all work:
diesel::insert_into(products::table)
.values((products::id.eq(1), products::name.eq("widget"), products::price.eq(9.99)))
.returning(products::id)
.get_results::<i32>(&mut conn)?;
let rows: Vec<(i32, String, f64)> = products::table
.filter(products::price.lt(20.0))
.order(products::name.asc())
.load(&mut conn)?;
diesel::update(products::table.filter(products::id.eq(1)))
.set(products::price.eq(11.99))
.execute(&mut conn)?;
diesel::delete(products::table.filter(products::id.eq(2))).execute(&mut conn)?;
conn.transaction(|conn| {
diesel::insert_into(products::table)
.values((products::id.eq(3), products::name.eq("doohickey"), products::price.eq(4.99)))
.execute(conn)?;
Ok::<_, diesel::result::Error>(()) // Err rolls back; Ok commits
})?;
Import types that have no standard Diesel equivalent via sql_types:
diesel::table! {
use diesel::sql_types::*;
use better_duck_diesel::sql_types::*;
readings (id) {
id -> Integer,
sensor -> DuckEnum, // ENUM
ts -> DuckTimestamptz, // TIMESTAMPTZ
tags -> DuckList, // LIST
}
}
use better_duck_diesel::dsl::*; brings in a large library of DuckDB SQL that Diesel doesn't ship by
default — string/search/similarity, numeric & trig, regex, date/time, hashing, encoding, JSON, list &
map functions; general/statistical/approximate/bit aggregates; and operator methods like .ilike(),
.similar_to(), .glob(), and .is_distinct_from().
use better_duck_diesel::dsl::*;
use diesel::prelude::*;
let hits: Vec<i32> = products::table
.filter(products::name.ilike("wid%")) // case-insensitive LIKE operator
.select(products::id)
.load(&mut conn)?;
let n: f64 = diesel::select(sqrt(16.0_f64)).get_result(&mut conn)?; // scalar fn → 4.0
Custom-typed values (u64, i128, UUID, BIT, BIGNUM, …) bind and load through the
better_duck_diesel::values::* newtypes (e.g. values::UBigInt, values::Uuid).
use better_duck_diesel::spatial::{ensure_loaded, st_as_text, st_point};
ensure_loaded(&mut conn)?; // INSTALL + LOAD the spatial extension if needed
let wkt: String = diesel::select(st_as_text(st_point(1.0, 2.0))).get_result(&mut conn)?; // "POINT (1 2)"
Standard Diesel types (work out of the box):
| Diesel SQL type | DuckDB type | Rust type |
|---|---|---|
Bool | BOOLEAN | bool |
SmallInt | SMALLINT | i16 |
Integer | INTEGER | i32 |
BigInt | BIGINT | i64 |
Float / Double | FLOAT / DOUBLE | f32 / f64 |
Text | VARCHAR | String |
Binary | BLOB | Vec<u8> |
Date / Time / Timestamp | DATE / TIME / TIMESTAMP | chrono::* (chrono) |
Numeric | DECIMAL | rust_decimal::Decimal (decimal) |
DuckDB-specific types (use better_duck_diesel::sql_types::*;):
| Diesel SQL type | DuckDB type | Rust type |
|---|---|---|
DuckTinyInt / DuckUTinyInt | TINYINT / UTINYINT | i8 / u8 |
DuckUSmallInt / DuckUInt / DuckUBigInt | USMALLINT / UINTEGER / UBIGINT | u16 / u32 / u64 |
DuckHugeInt / DuckUHugeInt | HUGEINT / UHUGEINT | i128 / u128 |
DuckTimestamptz / DuckInterval | TIMESTAMPTZ / INTERVAL | chrono::DateTime<Utc> / Duration (chrono) |
DuckTimeTz / DuckTimeNs | TIME WITH TIME ZONE / TIME_NS | TimeTz / NaiveTime (chrono) |
DuckEnum | ENUM | String or #[derive(DuckEnum)] |
DuckList / DuckArray | LIST / ARRAY | Vec<DuckValue> |
DuckStruct / DuckMap / DuckUnion | STRUCT / MAP / UNION | HashMap<…> / active member |
DuckUuid / DuckBit / DuckBignum | UUID / BIT / BIGNUM | DuckUuid / DuckBit / DuckBignum |
[!NOTE] Date/time types map to
chronowith thechronofeature, or tobetter_duck_core::types::date_nativeplain structs without it. Only one set is compiled at a time.
r2d2 — Diesel's own diesel::r2d2::ConnectionManager<DuckDbConnection>, plus a
SharedDuckDbConnectionManager that shares one Database across the pool (so an in-memory pool
observes one consistent database). Its .on_connect(|c| …) hook registers UDFs / loads extensions
per pooled connection.With better-duck-diesel's derive feature, #[derive(DuckEnum)] and #[derive(DuckStruct)] also
emit Diesel FromSql/ToSql, so a derived Rust enum/struct binds and loads at its sql_types::DuckEnum
/ sql_types::DuckStruct column type (via sql_query + QueryableByName).
| Feature | Default | Description |
|---|---|---|
decimal | ✓ | Diesel Numeric ↔ rust_decimal::Decimal |
chrono | — | Diesel date/time impls for DATE, TIME, TIMESTAMP, TIMESTAMPTZ, INTERVAL, TIME_TZ, TIME_NS |
r2d2 | — | r2d2 connection pool support (SharedDuckDbConnectionManager + diesel::r2d2) |
udf | — | Expose the underlying core connection for registering UDFs on a diesel connection |
derive | — | Re-export the data derives with Diesel FromSql/ToSql emission |
spatial | — | ST_* DSL functions + ensure_loaded helper for the DuckDB spatial extension |
json | — | Bundle the JSON extension so the JSON DSL works offline |
better-duck-macros is not a direct dependency — it's re-exported through better-duck-core's
udf and derive features (and better-duck-diesel's derive feature for ORM emission).
| Macro | Applies to | Generates |
|---|---|---|
#[duckdb_scalar] | fn(args) -> T | a scalar function (one value per row) |
#[duckdb_table_function] | fn(args) -> impl Iterator | a table function (rows + columns, usable in FROM) |
#[duckdb_aggregate] | mod { init, update, combine, finalize } | a custom aggregate |
#[duckdb_cast] | fn(from) -> to | a CAST / TRY_CAST implementation |
use better_duck_core::{connection::Connection, duckdb_scalar, duckdb_table_function};
#[duckdb_scalar]
fn repeat_str(s: &str, n: i32) -> String { s.repeat(n.max(0) as usize) }
#[duckdb_table_function(name = "series", columns("n"))]
fn series(start: i64, stop: i64) -> impl Iterator<Item = i64> + Send { start..stop }
let mut conn = Connection::open_in_memory()?;
repeat_str::register(&mut conn)?;
series::register(&mut conn)?;
conn.execute("SELECT sum(n) FROM series(1, 101)")?; // 5050
Parameter/return types are inferred from the signature. Option<T> propagates NULL; a
Result<T, E> return fails the query with E's message. Table functions also support named
(keyword) parameters, projection pushdown, and scalar functions support shared state — read via the
duck_projection! / duck_extra_info! / duck_state! macros. Panics are caught and surfaced as
query errors under panic = "unwind".
| Derive | Maps | Direction |
|---|---|---|
#[derive(FromRow)] | struct ← query row (by column name) | read |
#[derive(ToRow)] | struct → appender row / bind params | write |
#[derive(DuckEnum)] | unit enum ↔ DuckDB ENUM | read + write |
#[derive(DuckStruct)] | struct ↔ DuckDB STRUCT value | read + write |
use better_duck_core::{connection::Connection, DuckEnum, FromRow};
#[derive(DuckEnum, Debug, PartialEq, Clone, Copy)]
#[duck_enum(rename_all = "snake_case")]
enum Priority { Low, High }
#[derive(FromRow, Debug)]
struct Task { id: i32, priority: Priority }
Field/variant naming is controlled with #[duck(rename = "…")] / #[duck(rename_all = "…")]
(and #[duck_enum(...)] for DuckEnum). ResultSet::to_structs::<T>() reads a whole result into
Vec<T> for a FromRow type. With better-duck-diesel's derive feature on, DuckEnum/DuckStruct
additionally emit Diesel FromSql/ToSql.
use better_duck_core::{params, transaction};
// commit-on-Ok / rollback-on-Err transaction scope (works for core and diesel connections)
transaction!(conn, {
conn.execute_with("INSERT INTO t VALUES ($1, $2)", &mut params![1_i32, "hi".to_owned()])?;
Ok(())
})?;
| Platform | Status |
|---|---|
| Linux x86_64 | ✓ CI-tested |
| macOS Apple Silicon (aarch64) | ✓ CI-tested |
| macOS x86_64 | ✓ CI-tested |
| Windows x86_64 | ✓ CI-tested |
| iOS aarch64 | ✓ CI cross-build |
| iOS Simulator x86_64 | ✓ CI cross-build |
The library is usable today for most workloads. A condensed view of what's here and what's next — contributions are very welcome.
Available now
LIST/ARRAY/STRUCT/MAP/UNION/ENUM), plus UUID,
BIT, and BIGNUM end-to-end (core read/write + Diesel FromSql/ToSql).TIME_TZ timezone offset preserved on read and write; Diesel date/time with or without chrono.FromRow/ToRow/DuckEnum/DuckStruct) with optional Diesel emission.async) and connection pooling (pool / r2d2).spatial module.In progress
GEOMETRY / VARIANT / ANY / INTEGER_LITERAL reads (no value accessor in the DuckDB C API yet).UNION writes (the current write path builds single-member unions).DECIMAL declared-precision round-tripping (width is read but not yet carried on the value).WITHIN GROUP quantiles) in the Diesel query builder.Exploratory
better-duck-tauri plugin crate, and a wasm32 build target.This repo ships Claude Agent Skills that teach an AI agent to use DuckDB and this driver well —
one skill per surface: duckdb, better-duck, better-duck-core, better-duck-macros,
better-duck-diesel, and better-duck-tauri.
Auto-discovered when you work in this repo: the skills live in .claude/skills/, so a
Claude Code session opened here loads them with no install step.
Installable anywhere via the plugin marketplace this repo also defines:
claude plugin marketplace add nimdeveloper/better-duck
claude plugin install better-duck-skills@better-duck
Both paths serve the same files (the plugin's skills path points at .claude/skills/), so there's
a single source of truth.
See CONTRIBUTING.md for environment setup, git flow, commit conventions, how to add a new DuckDB type, and the PR checklist. Found a bug or have a feature idea? Open an issue.
Licensed under either of MIT or Apache-2.0, at your option.
ENUM | String / a derived enum (#[derive(DuckEnum)]) |
UUID / BIT / BIGNUM | DuckUuid / DuckBit / DuckBignum |