SQLite Driver
Luma includes a built-in SQLite driver that reads SQLite3 database files directly using random-access file I/O and byte manipulation. Like the MySQL driver, it is written entirely in Luma with no external dependencies.
The SQLite driver is read-only. It supports SELECT queries with WHERE and LIMIT clauses. Write operations (INSERT, UPDATE, DELETE, CREATE) will panic with a clear error message.
Quick Start
sqlite = import "sqlite"
conn = db.open(sqlite, "/path/to/database.db")
rows = conn.query("SELECT name, age FROM users WHERE age > 20")
rows.walk(row) -> {
name: str = row.get("name")
age: int = row.get("age")
print("${name}: ${age}")
}
conn.close()DSN Format
The DSN is simply a file path to an existing SQLite database file:
conn = db.open(sqlite, "/tmp/mydata.db")
conn = db.open(sqlite, "data/local.db")Supported SQL
SELECT *
rows = conn.query("SELECT * FROM users")Column Projection
rows = conn.query("SELECT name, score FROM users")WHERE Clause
Supports =, !=, >, <, >=, <= operators with AND for combining conditions:
rows = conn.query("SELECT * FROM users WHERE age > 28")
rows = conn.query("SELECT * FROM users WHERE name = 'Alice'")
rows = conn.query("SELECT * FROM users WHERE age >= 25 AND score > 90")Numeric comparisons work with both integers and floats.
LIMIT
rows = conn.query("SELECT * FROM users LIMIT 10")Combining Clauses
rows = conn.query("SELECT name, score FROM users WHERE age > 25 LIMIT 5")Transactions
Transaction stubs are supported as no-ops for compatibility:
conn.beginTransaction() // no-op
conn.commit() // no-op
conn.rollback() // no-opLimitations
| Limitation | Details |
|---|---|
| Read-only | No INSERT, UPDATE, DELETE, or CREATE support |
| UTF-8 only | Panics on UTF-16 encoded databases |
| No WITHOUT ROWID tables | These use a different B-tree structure |
| No index usage | Always does full table scan |
| Basic SQL only | No JOIN, GROUP BY, ORDER BY, subqueries, or aggregates |
| No WAL mode | Only reads rollback-journal mode databases |
| No named parameters | Use string interpolation for dynamic values |
Supported Data Types
The driver reads all SQLite serial types and converts them to strings (matching the driver contract):
| SQLite Type | Serial Types | Conversion |
|---|---|---|
| NULL | 0 | Empty string "" |
| INTEGER | 1-6, 8, 9 | Decimal string (e.g., "42") |
| REAL | 7 | Float string (e.g., "3.14") |
| TEXT | N >= 13, odd | UTF-8 string |
| BLOB | N >= 12, even | Hex-encoded string |
INTEGER PRIMARY KEY columns are automatically mapped to the row’s rowid value.
How It Works
The SQLite driver implements a pure-Luma SQLite3 file format parser:
- File header – reads the first 100 bytes to get page size, encoding, and reserved bytes
- Schema loading – reads
sqlite_masteron page 1 to discover tables and their column names - B-tree traversal – recursively walks interior and leaf pages to find all rows
- Record decoding – decodes SQLite varint-encoded record headers and field data
- Overflow handling – follows overflow page chains for records larger than a single page
All I/O uses file.read_at() for random access. Each read opens, reads, and closes the file, matching Luma’s stateless file I/O model.
Example
sqlite = import "sqlite"
conn = db.open(sqlite, "/tmp/analytics.db")
// Get all records
rows = conn.query("SELECT * FROM events")
print("Total events: " + to_str(rows.count()))
// Filter and project
recent = conn.query("SELECT name, timestamp FROM events WHERE type = 'click' LIMIT 100")
recent.walk(row) -> {
print(row.get("name") + " at " + row.get("timestamp"))
}
conn.close()