🍬 Candybase — Procedural Database Access for Rust
As simple as PHP's
mysqli_*functions. As safe as Rust.
The Idea
Most Rust database crates require you to learn builders, traits, generics, and async runtimes before you can run a single query. Candy takes the opposite approach: flat functions, immediate results, no ceremony.
If you have ever written PHP like this:
Then Candy will feel familiar:
use *;
let conn = candy_connect?;
let res = candy_query?;
let rows = candy_fetch_all?;
Design Goals
| Goal | How Candy achieves it |
|---|---|
| Simplicity | Flat procedural functions, no builders, no traits |
| Safety | Every function returns Result<T, CandyError> |
| Universality | MySQL, PostgreSQL, and SQLite through one API |
| Framework-agnostic | Works in Axum, Rocket, Yew, or plain main() |
| Familiar | Mirrors the mental model of mysqli_* |
Installation
Add Candy to Cargo.toml with the backend(s) you need:
[]
# SQLite only (default, no server required)
= "0.1"
# MySQL
= { = "0.1", = ["mysql"] }
# PostgreSQL
= { = "0.1", = ["postgres"] }
# All three backends
= { = "0.1", = ["all"] }
Feature Flags
| Flag | Backend | External dependency? |
|---|---|---|
sqlite (default) |
SQLite | No — bundled via rusqlite |
mysql |
MySQL / MariaDB | Requires a running server |
postgres |
PostgreSQL | Requires a running server |
all |
All three | — |
Quick Start
SQLite (no server needed)
use *;
MySQL
use *;
PostgreSQL
use *;
Environment Variable
Set CANDY_DB_URL and call candy_connect with empty strings:
// Reads CANDY_DB_URL automatically
let conn = candy_connect?;
Or use candy_connect_url directly:
let conn = candy_connect_url?;
let conn = candy_connect_url?;
let conn = candy_connect_url?;
API Reference
candy_connect
Opens a connection. Backend is inferred from CANDY_DB_URL, the host scheme, or the enabled feature flags. Returns a CandyConn handle.
candy_connect_url
Opens a connection from a full URL string. URL scheme selects the backend:
| URL prefix | Backend |
|---|---|
mysql:// |
MySQL |
postgres:// or postgresql:// |
PostgreSQL |
sqlite:// |
SQLite |
candy_query
Executes a SQL statement and returns a buffered CandyResult. Intended for SELECT statements. All rows are fetched into memory.
candy_fetch_all
Consumes a CandyResult and returns every row as a Vec<HashMap<String, String>>. All column values are strings; NULL becomes "NULL".
candy_fetch_one
Returns only the first row. Returns CandyError::Fetch if the result set is empty.
candy_insert
Executes an INSERT statement. Returns the number of rows inserted.
candy_update
Executes an UPDATE statement. Returns the number of rows affected.
candy_delete
Executes a DELETE statement. Returns the number of rows deleted.
candy_transaction
Executes a list of SQL statements as a single atomic transaction. Automatically rolls back if any statement fails and returns CandyError::Transaction.
candy_close
Closes the connection and releases resources. The CandyConn is consumed. Dropping a CandyConn without calling candy_close is also safe.
Error Handling
use ;
match candy_connect
| Variant | When raised |
|---|---|
CandyError::Connection |
Cannot reach the server / bad credentials |
CandyError::Query |
SQL statement rejected by the database |
CandyError::Fetch |
Row decoding failed / empty result set |
CandyError::Transaction |
A statement inside a transaction failed |
CandyError::UrlParse |
Unrecognised URL scheme |
CandyError::Internal |
Unexpected internal error |
Running the Examples
# SQLite (no server needed)
# MySQL (requires a running server)
# PostgreSQL (requires a running server)
Running Tests
# SQLite unit tests (always available)
# All backends (requires live MySQL + PostgreSQL)
MYSQL_URL="mysql://root:secret@localhost/test" \
PG_URL="postgres://postgres:secret@localhost/test" \
Using with Web Frameworks
Axum
use ;
use *;
use HashMap;
async
Rocket
use get;
use *;
Comparison with Other Crates
| Crate | Style | Backends | Learning curve |
|---|---|---|---|
| candy | Procedural functions | MySQL, PG, SQLite | Minimal |
| sqlx | Async, macro-heavy | MySQL, PG, SQLite | Steep |
| diesel | ORM, schema-first | MySQL, PG, SQLite | Very steep |
| rusqlite | Low-level | SQLite only | Moderate |
| tokio-postgres | Async, low-level | PG only | Steep |
Candy is not a replacement for sqlx or Diesel in production systems that need async, connection pooling, migrations, or type-safe queries. It is the right choice when you want to get something working quickly with the least possible friction.
Roadmap
- Async support (
candy_asynccompanion crate) - Prepared statement API (
candy_prepare/candy_execute) - Connection pool helpers
- Named parameter binding (
?namestyle) -
serdedeserialization into typed structs
Licensed Under MIT License