MySQL with Desi¶
Desi connects to MySQL using a pure C wire protocol — no libmysqlclient dependency. Everything is bundled in libdesi.a.
Connecting¶
import db
# Connect to MySQL
let status = db.connect("mysql", "localhost", 3306, "mydb", "root", "password")
if db.is_connected() != 1:
print(f"Error: {db.last_error()}")
The driver accepts "mysql", "my", or "mariadb".
Querying¶
# SELECT — returns number of rows
let rows = db.query("SELECT id, name, email FROM users WHERE age > 21")
# Access results
for i in range(rows):
let name = db.get_field(i, "name")
let email = db.get_field(i, "email")
print(f"{name}: {email}")
# Or by column index
let first_name = db.get_value(0, 1)
Executing¶
# INSERT/UPDATE/DELETE — returns affected row count
let inserted = db.execute("INSERT INTO users (name, age) VALUES ('Alice', 30)")
let updated = db.execute("UPDATE users SET age = 31 WHERE name = 'Alice'")
let deleted = db.execute("DELETE FROM users WHERE id = 5")
Raw SQL — Full MySQL Power¶
# Subqueries
db.query("SELECT * FROM users WHERE id IN (SELECT user_id FROM orders)")
# JSON support (MySQL 5.7+)
db.query("SELECT JSON_EXTRACT(metadata, '$.theme') FROM settings")
# Multi-table UPDATE
db.execute("UPDATE orders o JOIN users u ON o.user_id = u.id SET o.status = 'active' WHERE u.active = 1")
# USE another database
db.execute("USE other_database")
# Variables
db.execute("SET @max_age = 50")
db.query("SELECT * FROM users WHERE age < @max_age")
ORM Field Types¶
| ORM Field | MySQL Type | Notes |
|---|---|---|
auto_field |
INT AUTO_INCREMENT PRIMARY KEY |
|
int_field |
INTEGER |
|
bigint_field |
BIGINT |
|
char_field |
VARCHAR(n) |
|
text_field |
TEXT |
|
bool_field |
TINYINT(1) |
0/1 |
float_field |
DOUBLE |
|
decimal_field |
DECIMAL(p,s) |
Exact numeric |
datetime_field |
DATETIME |
No timezone conversion |
json_field |
JSON |
MySQL 5.7+ |
uuid_field |
VARCHAR(36) |
Stored as string |
array_field |
JSON |
Arrays stored as JSON |
inet_field |
VARCHAR(45) |
IPv4/IPv6 as string |
foreign_key |
INTEGER REFERENCES |
InnoDB FK |
custom_field |
(any type) | Pass-through |
ORM Example¶
import db
# Define model
db.model("products")
db.auto_field("id")
db.uuid_field("sku", 0, 1)
db.char_field("name", 200, 0, 0)
db.decimal_field("price", 10, 2, 0)
db.bool_field("available", 1, 0)
db.datetime_field("created_at", 0, 1, 0)
db.json_field("attributes", 1)
db.custom_field("status", "ENUM('draft','published','archived')", 0)
# Connect and create
db.connect("mysql", "localhost", 3306, "shop", "root", "pass")
let sql = db.create_table_sql("products")
db.execute(sql)
Generated SQL:
CREATE TABLE IF NOT EXISTS products (
id INT AUTO_INCREMENT PRIMARY KEY,
sku VARCHAR(36) NOT NULL UNIQUE,
name VARCHAR(200) NOT NULL,
price DECIMAL(10,2) NOT NULL,
available TINYINT(1) NOT NULL DEFAULT TRUE,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
attributes JSON,
status ENUM('draft','published','archived') NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
Debugging¶
db.set_debug(1) # logs all protocol messages to stderr
db.dump_results() # prints formatted result table
print(db.connection_info())
print(db.driver()) # → "mysql"
Authentication¶
Supported MySQL auth methods: - mysql_native_password — SHA1-based (MySQL 5.x default) - caching_sha2_password — Fast auth (MySQL 8.x default) - Auth method switch — Server-initiated plugin change
MySQL-Specific Notes¶
- ENGINE=InnoDB — Auto-set on all ORM tables for transaction support
- utf8mb4 — Full Unicode by default (supports emoji)
- TIMESTAMP vs DATETIME — ORM uses
DATETIME(no UTC auto-conversion; useTIMESTAMPviacustom_fieldif needed)