47235e702c
Funciones Go con interfaz unificada para operaciones DB: open, close, create_table, exec, query, insert_row, insert_batch. Openers específicos por engine. Tipo DBConfig para configuración común. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
55 lines
1.3 KiB
Go
55 lines
1.3 KiB
Go
package infra
|
|
|
|
import (
|
|
"database/sql"
|
|
"fmt"
|
|
"sort"
|
|
"strings"
|
|
)
|
|
|
|
// DBInsertRow generates and executes a single-row INSERT from a map of
|
|
// column→value pairs. Returns the last insert ID reported by the driver.
|
|
// Column and table names are validated to contain only safe identifier chars.
|
|
func DBInsertRow(db *sql.DB, table string, row map[string]any) (int64, error) {
|
|
if !validIdentifier.MatchString(table) {
|
|
return 0, fmt.Errorf("db_insert_row: invalid table name %q", table)
|
|
}
|
|
if len(row) == 0 {
|
|
return 0, fmt.Errorf("db_insert_row: row map must not be empty")
|
|
}
|
|
|
|
// Sort keys for deterministic query generation.
|
|
cols := make([]string, 0, len(row))
|
|
for col := range row {
|
|
if !validIdentifier.MatchString(col) {
|
|
return 0, fmt.Errorf("db_insert_row: invalid column name %q", col)
|
|
}
|
|
cols = append(cols, col)
|
|
}
|
|
sort.Strings(cols)
|
|
|
|
placeholders := make([]string, len(cols))
|
|
values := make([]any, len(cols))
|
|
for i, col := range cols {
|
|
placeholders[i] = "?"
|
|
values[i] = row[col]
|
|
}
|
|
|
|
query := fmt.Sprintf(
|
|
"INSERT INTO %s (%s) VALUES (%s)",
|
|
table,
|
|
strings.Join(cols, ", "),
|
|
strings.Join(placeholders, ", "),
|
|
)
|
|
|
|
result, err := db.Exec(query, values...)
|
|
if err != nil {
|
|
return 0, fmt.Errorf("db_insert_row %q: %w", table, err)
|
|
}
|
|
id, err := result.LastInsertId()
|
|
if err != nil {
|
|
return 0, nil
|
|
}
|
|
return id, nil
|
|
}
|