diff --git a/functions/infra/sqlite_open.go b/functions/infra/sqlite_open.go index cf894f6d..e368b989 100644 --- a/functions/infra/sqlite_open.go +++ b/functions/infra/sqlite_open.go @@ -3,6 +3,7 @@ package infra import ( "database/sql" "fmt" + "path/filepath" _ "github.com/mattn/go-sqlite3" ) @@ -10,18 +11,27 @@ import ( // SQLiteOpen opens (or creates) a SQLite database file with WAL mode and // foreign key support enabled. Returns a ready-to-use *sql.DB or an error. // Pass ":memory:" for an in-memory database. -func SQLiteOpen(path string) (*sql.DB, error) { +// +// If basePath is non-empty and path is relative, the path is resolved as +// filepath.Join(basePath, path). This is useful when the path comes from a +// config file and must be interpreted relative to that file's directory rather +// than the process working directory. +func SQLiteOpen(path string, basePath string) (*sql.DB, error) { if path == "" { return nil, fmt.Errorf("sqlite_open: path must not be empty (use ':memory:' for in-memory)") } - dsn := fmt.Sprintf("file:%s?_journal_mode=WAL&_foreign_keys=on", path) + resolved := path + if basePath != "" && path != ":memory:" && !filepath.IsAbs(path) { + resolved = filepath.Join(basePath, path) + } + dsn := fmt.Sprintf("file:%s?_journal_mode=WAL&_foreign_keys=on", resolved) db, err := sql.Open("sqlite3", dsn) if err != nil { - return nil, fmt.Errorf("sqlite_open: open %q: %w", path, err) + return nil, fmt.Errorf("sqlite_open: open %q: %w", resolved, err) } if err := db.Ping(); err != nil { db.Close() - return nil, fmt.Errorf("sqlite_open: ping %q: %w", path, err) + return nil, fmt.Errorf("sqlite_open: ping %q: %w", resolved, err) } return db, nil } diff --git a/functions/infra/sqlite_open.md b/functions/infra/sqlite_open.md index bb9964c9..05d4fede 100644 --- a/functions/infra/sqlite_open.md +++ b/functions/infra/sqlite_open.md @@ -3,17 +3,17 @@ name: sqlite_open kind: function lang: go domain: infra -version: "1.0.0" +version: "1.1.0" purity: impure -signature: "func SQLiteOpen(path string) (*sql.DB, error)" -description: "Abre (o crea) una base de datos SQLite con WAL mode y foreign keys habilitados. Hace ping para verificar la conexion." +signature: "func SQLiteOpen(path string, basePath string) (*sql.DB, error)" +description: "Abre (o crea) una base de datos SQLite con WAL mode y foreign keys habilitados. Hace ping para verificar la conexion. Si basePath es no-vacio y path es relativo, resuelve el path como filepath.Join(basePath, path)." tags: [database, sqlite, connection, sql] uses_functions: [] uses_types: [db_config_go_infra] returns: [] returns_optional: false error_type: "error_go_core" -imports: ["database/sql", "github.com/mattn/go-sqlite3"] +imports: ["database/sql", "path/filepath", "github.com/mattn/go-sqlite3"] tested: false tests: [] test_file_path: "" @@ -23,15 +23,27 @@ file_path: "functions/infra/sqlite_open.go" ## Ejemplo ```go -db, err := SQLiteOpen("/data/myapp.db") +// Path absoluto o relativo al cwd +db, err := SQLiteOpen("/data/myapp.db", "") if err != nil { log.Fatal(err) } defer DBClose(db) +// Path relativo al directorio del archivo YAML de configuracion +configDir := filepath.Dir(configPath) +db, err := SQLiteOpen(cfg.DatabasePath, configDir) +if err != nil { + log.Fatal(err) +} + rows, err := DBQuery(db, "SELECT * FROM users WHERE active = ?", 1) ``` ## Notas -Usa el driver `github.com/mattn/go-sqlite3` (CGO). El DSN incluye `_journal_mode=WAL` para mejor concurrencia y `_foreign_keys=on`. Acepta `:memory:` para base de datos en memoria. Hace ping al abrir para detectar errores temprano. +Usa el driver `github.com/mattn/go-sqlite3` (CGO). El DSN incluye `_journal_mode=WAL` para mejor concurrencia y `_foreign_keys=on`. Acepta `:memory:` para base de datos en memoria (basePath se ignora en este caso). Hace ping al abrir para detectar errores temprano. + +El parametro `basePath` resuelve el problema de paths relativos en configs YAML: cuando el binario corre desde un directorio distinto al del archivo de config, el path relativo se interpreta incorrectamente. Pasar `filepath.Dir(configPath)` como basePath corrige esto. + +Para mantener el comportamiento anterior (resolver vs cwd), pasar `basePath = ""`.