AtlatestRepositorysigil-sqlite
sigil-sqlite / tree / docssqlite.md
1
# SQLite3
> SQLite database bindings with high-level query helpers.5
```scheme6
(import (sigil sqlite))7
```9
## Opening and Closing11
```scheme12
;; Open a database file (created if it doesn't exist)13
(define db (sqlite-open "app.db"))15
;; In-memory database16
(define db (sqlite-open ":memory:"))18
;; Close when done19
(sqlite-close db)21
;; Resource-safe pattern: auto-closes on exit22
(call-with-database "app.db"23
(lambda (db)24
(sqlite-query db "SELECT * FROM users")))25
```27
`sqlite-open` returns `#f` on failure. `sqlite-close` is idempotent.29
## Type Mapping31
| SQLite | Scheme | Notes |32
|---------|--------------|--------------------------|33
| NULL | `#f` | Read and write |34
| INTEGER | integer | 64-bit signed |35
| REAL | flonum | IEEE 754 double |36
| TEXT | string | UTF-8 |37
| BLOB | bytevector | `#u8(...)` read and write |39
## High-Level API41
These three procedures handle statement preparation, parameter binding, and cleanup automatically.43
### sqlite-query45
Execute a query and return all rows as alists.47
```scheme48
(sqlite-query db "SELECT * FROM users")49
; => (((id . 1) (name . "Alice")) ((id . 2) (name . "Bob")))51
;; With parameter binding52
(sqlite-query db "SELECT * FROM users WHERE age > ?" 21)53
; => (((id . 1) (name . "Alice") (age . 30)))55
;; Multiple parameters56
(sqlite-query db "SELECT * FROM users WHERE name = ? AND age > ?" "Alice" 21)58
;; No results returns empty list59
(sqlite-query db "SELECT * FROM users WHERE id = ?" 999)60
; => ()61
```63
Column names become symbols in the alist keys.65
### sqlite-query-row67
Execute a query and return just the first row, or `#f` if no match.69
```scheme70
(define user (sqlite-query-row db "SELECT * FROM users WHERE id = ?" 1))71
; => ((id . 1) (name . "Alice") (email . "[email protected]"))73
(assoc-ref 'name user) ; => "Alice"74
(assoc-ref 'email user) ; => "[email protected]"76
(sqlite-query-row db "SELECT * FROM users WHERE id = ?" 999)77
; => #f78
```80
### sqlite-run82
Execute a statement that doesn't return rows (INSERT, UPDATE, DELETE). Returns `#t` on success, `#f` on failure.84
```scheme85
(sqlite-run db "INSERT INTO users (name, email) VALUES (?, ?)"86
"Alice" "[email protected]")87
; => #t89
(sqlite-run db "UPDATE users SET name = ? WHERE id = ?" "Bob" 1)90
; => #t92
(sqlite-run db "DELETE FROM users WHERE id = ?" 1)93
; => #t94
```96
## Database Info98
```scheme99
;; Row ID of last INSERT100
(sqlite-run db "INSERT INTO users (name) VALUES (?)" "Alice")101
(sqlite-last-insert-rowid db) ; => 1103
;; Number of rows changed by last INSERT/UPDATE/DELETE104
(sqlite-run db "UPDATE users SET name = 'Updated' WHERE id > ?" 0)105
(sqlite-changes db) ; => 3107
;; Error message from last operation108
(sqlite-errmsg db) ; => "not an error" (or description on failure)109
```111
## Schema Setup113
`sqlite-exec` executes SQL that doesn't use parameters or return rows.115
```scheme116
(sqlite-exec db "CREATE TABLE IF NOT EXISTS users (117
id INTEGER PRIMARY KEY,118
name TEXT NOT NULL,119
email TEXT,120
created_at TEXT DEFAULT CURRENT_TIMESTAMP)")121
; => #t123
(sqlite-exec db "CREATE INDEX IF NOT EXISTS idx_users_email ON users (email)")124
; => #t125
```127
## Low-Level API129
For fine-grained control over statement lifecycle.131
```scheme132
;; Prepare a statement133
(define stmt (sqlite-prepare db "SELECT * FROM users WHERE age > ?"))135
;; Bind parameters (1-based index)136
(sqlite-bind stmt 1 21)138
;; Step through results139
(let loop ()140
(when (eq? (sqlite-step stmt) 'row)141
(let ((id (sqlite-column stmt 0))142
(name (sqlite-column stmt 1)))143
(display (format "~a: ~a\n" id name))144
(loop))))146
;; Clean up147
(sqlite-finalize stmt)148
```150
- `sqlite-step` returns `'row` (data available), `'done` (complete), or `#f` (error)151
- `sqlite-column` uses 0-based indexing152
- `sqlite-column-count` and `sqlite-column-name` inspect result shape153
- `sqlite-reset` reuses a statement with new bindings154
- `sqlite-db?` / `sqlite-stmt?` type predicates for handle checking156
## Common Patterns158
### CRUD Operations160
```scheme161
(import (sigil sqlite))163
(define db (sqlite-open "app.db"))164
(sqlite-exec db "CREATE TABLE IF NOT EXISTS notes (165
id INTEGER PRIMARY KEY, title TEXT, body TEXT)")167
;; Create168
(sqlite-run db "INSERT INTO notes (title, body) VALUES (?, ?)"169
"First Note" "Hello, world!")170
(define id (sqlite-last-insert-rowid db))172
;; Read173
(define note (sqlite-query-row db "SELECT * FROM notes WHERE id = ?" id))174
(assoc-ref 'title note) ; => "First Note"176
;; Update177
(sqlite-run db "UPDATE notes SET title = ? WHERE id = ?" "Updated Title" id)179
;; Delete180
(sqlite-run db "DELETE FROM notes WHERE id = ?" id)182
(sqlite-close db)183
```185
### Resource Management187
```scheme188
(call-with-database ":memory:"189
(lambda (db)190
(sqlite-exec db "CREATE TABLE kv (key TEXT PRIMARY KEY, value TEXT)")191
(sqlite-run db "INSERT INTO kv VALUES (?, ?)" "lang" "sigil")192
(assoc-ref 'value193
(sqlite-query-row db "SELECT value FROM kv WHERE key = ?" "lang"))))194
; => "sigil"195
```