zcatsql/CLAUDE.md
reugenio 7742f44667 v0.4: Fase 3A complete - Blob I/O, Hooks, Aggregate Functions
New features:
- Blob I/O: Incremental read/write for large BLOBs
  - Blob.open(), close(), deinit()
  - Blob.read(), write() with offset support
  - Blob.bytes(), reopen(), readAll()
- Hooks: Monitor database changes
  - setCommitHook() - called on transaction commit
  - setRollbackHook() - called on transaction rollback
  - setUpdateHook() - called on INSERT/UPDATE/DELETE
  - clearHooks() - remove all hooks
  - UpdateOperation enum (insert, update, delete)
- Aggregate Functions: Custom multi-row aggregates
  - createAggregateFunction(name, num_args, step_fn, final_fn)
  - AggregateContext with getAggregateContext() for state management
  - Support for setNull/Int/Float/Text/Blob/Error results

Documentation:
- Updated docs/API.md to v0.4 with new features and examples
- Updated docs/CGO_PARITY_ANALYSIS.md - Fase 3A marked complete
- Updated CLAUDE.md to v0.4 with all new implementations

Tests: 28 total (8 new tests for Fase 3A features)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-08 18:02:01 +01:00

523 lines
15 KiB
Markdown

# zsqlite - SQLite Wrapper para Zig
> **Ultima actualizacion**: 2025-12-08
> **Lenguaje**: Zig 0.15.2
> **Estado**: v0.4 - Fase 3A completada
> **Inspiracion**: CGo go-sqlite3, SQLite C API
## Descripcion del Proyecto
**zsqlite** es un wrapper idiomatico de SQLite para Zig que compila SQLite amalgamation directamente en el binario, resultando en un ejecutable unico sin dependencias externas.
**Filosofia**:
- Zero dependencias runtime
- API idiomatica Zig (errores, allocators, iteradores)
- Binario unico y portable
- Compatible con bases de datos SQLite existentes
- Calidad open source (doc comments, codigo claro)
**Objetivo**: Ser el pilar para trabajar con databases en Zig con codigo 100% propio, replicando toda la funcionalidad de wrappers maduros como CGo go-sqlite3.
---
## Estado Actual del Proyecto
### Implementacion v0.4 (Fase 3A Completada)
| Componente | Estado | Archivo |
|------------|--------|---------|
| **Core** | | |
| Database open/close | ✅ | `src/root.zig` |
| Database open with flags | ✅ | `src/root.zig` |
| exec() SQL simple | ✅ | `src/root.zig` |
| execAlloc() runtime strings | ✅ | `src/root.zig` |
| Error mapping completo | ✅ | `src/root.zig` |
| **Prepared Statements** | | |
| prepare/finalize | ✅ | `src/root.zig` |
| prepareAlloc() runtime strings | ✅ | `src/root.zig` |
| reset/clearBindings | ✅ | `src/root.zig` |
| step() iteration | ✅ | `src/root.zig` |
| sql() / isReadOnly() | ✅ | `src/root.zig` |
| parameterCount/Index/Name | ✅ | `src/root.zig` |
| **Bind Parameters** | | |
| bindNull | ✅ | `src/root.zig` |
| bindInt (i64) | ✅ | `src/root.zig` |
| bindFloat (f64) | ✅ | `src/root.zig` |
| bindText | ✅ | `src/root.zig` |
| bindBlob | ✅ | `src/root.zig` |
| bindBool | ✅ | `src/root.zig` |
| bindZeroblob | ✅ | `src/root.zig` |
| **Named Parameters** | | |
| bindNullNamed | ✅ | `src/root.zig` |
| bindIntNamed | ✅ | `src/root.zig` |
| bindFloatNamed | ✅ | `src/root.zig` |
| bindTextNamed | ✅ | `src/root.zig` |
| bindBlobNamed | ✅ | `src/root.zig` |
| bindBoolNamed | ✅ | `src/root.zig` |
| **Column Access** | | |
| columnCount | ✅ | `src/root.zig` |
| columnName | ✅ | `src/root.zig` |
| columnType | ✅ | `src/root.zig` |
| columnInt | ✅ | `src/root.zig` |
| columnFloat | ✅ | `src/root.zig` |
| columnText | ✅ | `src/root.zig` |
| columnBlob | ✅ | `src/root.zig` |
| columnIsNull | ✅ | `src/root.zig` |
| columnBool | ✅ | `src/root.zig` |
| columnBytes | ✅ | `src/root.zig` |
| columnDeclType | ✅ | `src/root.zig` |
| **Transacciones** | | |
| begin/commit/rollback | ✅ | `src/root.zig` |
| beginImmediate | ✅ | `src/root.zig` |
| beginExclusive | ✅ | `src/root.zig` |
| **Savepoints** | | |
| savepoint(name) | ✅ | `src/root.zig` |
| release(name) | ✅ | `src/root.zig` |
| rollbackTo(name) | ✅ | `src/root.zig` |
| **Pragmas/Config** | | |
| setBusyTimeout | ✅ | `src/root.zig` |
| setJournalMode | ✅ | `src/root.zig` |
| setSynchronous | ✅ | `src/root.zig` |
| enableWalMode | ✅ | `src/root.zig` |
| setForeignKeys | ✅ | `src/root.zig` |
| **ATTACH/DETACH** | | |
| attach(file, schema) | ✅ | `src/root.zig` |
| attachMemory(schema) | ✅ | `src/root.zig` |
| detach(schema) | ✅ | `src/root.zig` |
| listDatabases() | ✅ | `src/root.zig` |
| **Backup API** | | |
| Backup.init/initMain | ✅ | `src/root.zig` |
| Backup.step/stepAll | ✅ | `src/root.zig` |
| Backup.finish/deinit | ✅ | `src/root.zig` |
| Backup.remaining/pageCount | ✅ | `src/root.zig` |
| Backup.progress | ✅ | `src/root.zig` |
| backupDatabase() | ✅ | `src/root.zig` |
| backupToFile() | ✅ | `src/root.zig` |
| loadFromFile() | ✅ | `src/root.zig` |
| **User-Defined Functions** | | |
| createScalarFunction() | ✅ | `src/root.zig` |
| removeFunction() | ✅ | `src/root.zig` |
| FunctionContext (setInt/Float/Text/etc) | ✅ | `src/root.zig` |
| FunctionValue (asInt/Float/Text/etc) | ✅ | `src/root.zig` |
| **Custom Collations** | | |
| createCollation() | ✅ | `src/root.zig` |
| removeCollation() | ✅ | `src/root.zig` |
| **Aggregate Functions** | | |
| createAggregateFunction() | ✅ | `src/root.zig` |
| AggregateContext | ✅ | `src/root.zig` |
| **Blob I/O** | | |
| Blob.open/openAlloc | ✅ | `src/root.zig` |
| Blob.read/write | ✅ | `src/root.zig` |
| Blob.bytes | ✅ | `src/root.zig` |
| Blob.reopen | ✅ | `src/root.zig` |
| Blob.readAll | ✅ | `src/root.zig` |
| **Hooks** | | |
| setCommitHook | ✅ | `src/root.zig` |
| setRollbackHook | ✅ | `src/root.zig` |
| setUpdateHook | ✅ | `src/root.zig` |
| clearHooks | ✅ | `src/root.zig` |
| **Utilidades** | | |
| lastInsertRowId | ✅ | `src/root.zig` |
| changes/totalChanges | ✅ | `src/root.zig` |
| errorMessage | ✅ | `src/root.zig` |
| errorCode/extendedErrorCode | ✅ | `src/root.zig` |
| interrupt | ✅ | `src/root.zig` |
| isReadOnly | ✅ | `src/root.zig` |
| filename | ✅ | `src/root.zig` |
| version/versionNumber | ✅ | `src/root.zig` |
### Tests
| Categoria | Tests | Estado |
|-----------|-------|--------|
| Version | 1 | ✅ |
| Open/Close | 1 | ✅ |
| Create/Insert | 1 | ✅ |
| Prepared Statements | 1 | ✅ |
| Select Query | 1 | ✅ |
| Transaction Commit | 1 | ✅ |
| Transaction Rollback | 1 | ✅ |
| Foreign Keys | 1 | ✅ |
| Null Values | 1 | ✅ |
| Blob Data | 1 | ✅ |
| Named Parameters | 1 | ✅ |
| Savepoints | 1 | ✅ |
| Busy Timeout | 1 | ✅ |
| Statement Metadata | 1 | ✅ |
| Boolean bind/column | 1 | ✅ |
| Backup memory to memory | 1 | ✅ |
| Backup convenience | 1 | ✅ |
| ATTACH/DETACH | 1 | ✅ |
| User-defined functions | 1 | ✅ |
| Custom collations | 1 | ✅ |
| Blob I/O | 3 | ✅ |
| Hooks | 3 | ✅ |
| Aggregate functions | 2 | ✅ |
| **Total** | **28** | ✅ |
---
## Roadmap
### Fase 1 - Core (COMPLETADO)
- [x] Estructura proyecto
- [x] Compilar SQLite amalgamation
- [x] Abrir/cerrar bases de datos
- [x] Ejecutar SQL simple (exec)
- [x] Prepared statements basicos
- [x] Bind de parametros (int, text, blob, null, float)
- [x] Iterador de resultados
- [x] Transacciones basicas
### Fase 2A - Paridad CGo Core (COMPLETADO)
- [x] SAVEPOINT support
- [x] Named parameters (:name, @name, $name)
- [x] Busy timeout
- [x] WAL mode helpers
- [x] Statement metadata (sql, isReadOnly, parameterCount)
- [x] Boolean bind/column
- [x] Error codes (errorCode, extendedErrorCode)
- [x] Database info (isReadOnly, filename)
- [x] interrupt()
### Fase 2B - Paridad CGo Avanzada (COMPLETADO)
- [x] Backup API completo
- [x] User-defined functions (scalar)
- [x] Collations personalizadas
- [x] ATTACH/DETACH databases
- [ ] Batch bind con tuples/structs
- [ ] Row iterator idiomatico
### Fase 3A - Avanzado (COMPLETADO)
- [x] Blob streaming (para archivos grandes)
- [x] User-defined functions (aggregate)
- [x] Update/Commit/Rollback hooks
### Fase 3B - Avanzado (EN PROGRESO)
- [ ] Authorizer callback
- [ ] Progress handler
- [ ] Pre-update hook
- [ ] Window functions
- [ ] Busy handler (custom callback)
- [ ] Batch bind con tuples/structs
- [ ] Row iterator idiomatico
- [ ] Connection pooling
### Fase 4 - Extras
- [ ] Connection URI parsing
- [ ] Virtual tables
- [ ] FTS5 helpers
- [ ] JSON1 helpers
- [ ] R-Tree helpers
---
## Arquitectura
### Estructura de Archivos
```
zsqlite/
├── CLAUDE.md # Este archivo - estado del proyecto
├── build.zig # Sistema de build
├── src/
│ └── root.zig # Wrapper principal (~1000 lineas)
├── vendor/
│ ├── sqlite3.c # SQLite 3.47.2 amalgamation
│ ├── sqlite3.h # Headers SQLite
│ ├── sqlite3ext.h # Extension headers
│ └── shell.c # SQLite shell (no usado)
├── examples/
│ └── basic.zig # Ejemplo basico funcional
└── docs/
├── ARCHITECTURE.md # Diseno interno
├── API.md # Referencia rapida API
└── CGO_PARITY_ANALYSIS.md # Analisis de paridad con go-sqlite3
```
### SQLite Amalgamation
**Version**: SQLite 3.47.2
**Flags de compilacion**:
```
-DSQLITE_DQS=0 # Disable double-quoted strings
-DSQLITE_THREADSAFE=0 # Single-threaded (mas rapido)
-DSQLITE_DEFAULT_MEMSTATUS=0 # Disable memory tracking
-DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1
-DSQLITE_LIKE_DOESNT_MATCH_BLOBS
-DSQLITE_OMIT_DEPRECATED
-DSQLITE_OMIT_SHARED_CACHE
-DSQLITE_ENABLE_FTS5 # Full-text search
-DSQLITE_ENABLE_JSON1 # JSON functions
-DSQLITE_ENABLE_RTREE # R-Tree geospatial
-DSQLITE_OMIT_LOAD_EXTENSION # No dynamic extensions
```
---
## API Actual
### Abrir Base de Datos
```zig
const sqlite = @import("zsqlite");
// In-memory
var db = try sqlite.openMemory();
defer db.close();
// Archivo
var db = try sqlite.open("test.db");
defer db.close();
// Con flags
var db = try sqlite.Database.openWithFlags("test.db", .{
.read_only = true,
.create = false,
});
defer db.close();
```
### Ejecutar SQL Simple
```zig
try db.exec("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)");
try db.exec("INSERT INTO users (name) VALUES ('Alice')");
// Con string runtime
try db.execAlloc(allocator, sql_string);
```
### Prepared Statements
```zig
var stmt = try db.prepare("INSERT INTO users (name, age) VALUES (?, ?)");
defer stmt.finalize();
try stmt.bindText(1, "Bob");
try stmt.bindInt(2, 30);
_ = try stmt.step();
// Reusar
try stmt.reset();
try stmt.clearBindings();
try stmt.bindText(1, "Charlie");
try stmt.bindInt(2, 25);
_ = try stmt.step();
```
### Named Parameters (NUEVO v0.2)
```zig
var stmt = try db.prepare("INSERT INTO users (name, age) VALUES (:name, :age)");
defer stmt.finalize();
try stmt.bindTextNamed(":name", "Alice");
try stmt.bindIntNamed(":age", 30);
_ = try stmt.step();
// Tambien soporta @name y $name estilos
```
### Queries
```zig
var stmt = try db.prepare("SELECT id, name FROM users ORDER BY id");
defer stmt.finalize();
while (try stmt.step()) {
const id = stmt.columnInt(0);
const name = stmt.columnText(1) orelse "(null)";
std.debug.print("User {}: {s}\n", .{ id, name });
}
```
### Transacciones
```zig
try db.begin();
errdefer db.rollback() catch {};
try db.exec("INSERT INTO users (name) VALUES ('Alice')");
try db.exec("INSERT INTO users (name) VALUES ('Bob')");
try db.commit();
```
### Savepoints (NUEVO v0.2)
```zig
const allocator = std.heap.page_allocator;
try db.begin();
try db.savepoint(allocator, "sp1");
try db.exec("INSERT INTO test VALUES (1)");
// Revertir al savepoint
try db.rollbackTo(allocator, "sp1");
// O confirmar el savepoint
try db.release(allocator, "sp1");
try db.commit();
```
### WAL Mode (NUEVO v0.2)
```zig
const allocator = std.heap.page_allocator;
// Habilitar WAL mode con settings recomendados
try db.enableWalMode(allocator);
// O configurar individualmente
try db.setJournalMode(allocator, "WAL");
try db.setSynchronous(allocator, "NORMAL");
try db.setBusyTimeout(5000); // 5 segundos
```
### Foreign Keys
```zig
try db.setForeignKeys(true);
```
---
## Comandos
```bash
# Zig path
ZIG=/mnt/cello2/arno/re/recode/zig/zig-0.15.2/zig-x86_64-linux-0.15.2/zig
# Compilar
$ZIG build
# Tests
$ZIG build test
# Ejecutar ejemplo
$ZIG build basic && ./zig-out/bin/basic
```
---
## Equipo y Metodologia
### Normas de Trabajo Centralizadas
**IMPORTANTE**: Todas las normas de trabajo estan en:
```
/mnt/cello2/arno/re/recode/TEAM_STANDARDS/
```
**Archivos clave a leer**:
- `LAST_UPDATE.md` - **LEER PRIMERO** - Cambios recientes en normas
- `NORMAS_TRABAJO_CONSENSUADAS.md` - Metodologia fundamental
- `QUICK_REFERENCE.md` - Cheat sheet rapido
### Estandares Zig Open Source (Seccion #24)
- **Claridad**: Codigo autoexplicativo, nombres descriptivos
- **Doc comments**: `///` en todas las funciones publicas
- **Idiomatico**: snake_case, error handling explicito
- **Sin magia**: Preferir codigo explicito sobre abstracciones complejas
### Control de Versiones
```bash
# Remote
git remote: git@git.reugenio.com:reugenio/zsqlite.git
# Branches
main # Codigo estable
```
---
## Referencias
### CGo go-sqlite3 (Referencia principal)
- Repo: https://github.com/mattn/go-sqlite3
- Objetivo: Replicar toda su funcionalidad en Zig
- Analisis: `docs/CGO_PARITY_ANALYSIS.md`
### SQLite C API
- Docs: https://sqlite.org/c3ref/intro.html
- Objetivo: Wrapper completo de funciones relevantes
### Otros Wrappers Zig (Referencia)
- zig-sqlite: https://github.com/vrischmann/zig-sqlite
- zqlite.zig: https://github.com/karlseguin/zqlite.zig
---
## Historial de Desarrollo
### 2025-12-08 - v0.3 (Fase 2B Completada)
- **Backup API completo**:
- Backup struct con init/step/finish/remaining/pageCount/progress
- Funciones de conveniencia: backupDatabase, backupToFile, loadFromFile
- **User-Defined Functions (Scalar)**:
- createScalarFunction() para registrar funciones Zig en SQL
- FunctionContext para retornar resultados
- FunctionValue para acceder a argumentos
- Cleanup automatico con destructores
- **Custom Collations**:
- createCollation() para orden personalizado de strings
- removeCollation() para eliminar collations
- **ATTACH/DETACH Databases**:
- attach(), attachMemory(), detach()
- listDatabases() para enumerar schemas adjuntos
- 20 tests pasando
- ~1700 lineas de codigo en root.zig
### 2025-12-08 - v0.2 (Fase 2A Completada)
- Named parameters (:name, @name, $name)
- Savepoints (savepoint, release, rollbackTo)
- WAL mode helpers (enableWalMode, setJournalMode, setSynchronous)
- Busy timeout (setBusyTimeout)
- Statement metadata (sql, isReadOnly, parameterCount, parameterIndex, parameterName)
- Boolean bind/column (bindBool, columnBool)
- Error codes (errorCode, extendedErrorCode)
- Database info (isReadOnly, filename, interrupt)
- bindZeroblob, columnBytes, columnDeclType
- 15 tests pasando
- Documentacion docs/ creada (ARCHITECTURE.md, API.md, CGO_PARITY_ANALYSIS.md)
### 2025-12-08 - v0.1 (Core Funcional)
- Estructura inicial del proyecto
- SQLite 3.47.2 amalgamation compilando
- Database, Statement, Error types
- Bind parameters completos (null, int, float, text, blob)
- Column access completo
- Transacciones basicas
- 10 tests unitarios pasando
- Ejemplo basic.zig funcional
---
## Notas de Desarrollo
### Proxima Sesion
1. Blob streaming (para archivos grandes)
2. User-defined aggregate functions
3. Update/Commit hooks
4. Batch bind con comptime structs
### Lecciones Aprendidas
- SQLite amalgamation compila limpiamente con Zig build system
- `@cImport` funciona bien para headers SQLite
- SQLITE_TRANSIENT necesario para strings/blobs que Zig puede mover
- En Zig 0.15 usar `std.fmt.allocPrint` + `\x00` manual en lugar de `allocPrintZ`
- Named parameters funcionan con el prefijo incluido (":name", no "name")
- Callbacks C requieren `callconv(.c)` y estructuras wrapper para pasar estado
- `std.ArrayListUnmanaged` en Zig 0.15 (no `ArrayList.init`)
- UDFs y Collations usan page_allocator interno para simplicidad
---
**© zsqlite - Wrapper SQLite para Zig**
*2025-12-08 - En desarrollo activo*