# 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*
