docs(flows): DoD obligatorio con user-facing surface + abrir issues 0100-0103 (taxonomia, frontmatter migration, dev_console, work dashboard)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type tableInfo struct {
|
||||
Name string
|
||||
RowCount int64
|
||||
}
|
||||
|
||||
// listTablesForDatabase returns the list of tables for a given DB file.
|
||||
// Supports kind="sqlite" (uses database/sql + sqlite3 driver) and
|
||||
// kind="duckdb" (uses python venv subprocess since go-duckdb is not linked
|
||||
// in sqlite_api — it lives in the root module, not here).
|
||||
func listTablesForDatabase(kind, path string) ([]tableInfo, error) {
|
||||
switch kind {
|
||||
case "sqlite":
|
||||
return listSQLiteTables(path)
|
||||
case "duckdb":
|
||||
return listDuckDBTablesViaCLI(path)
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported kind: %s", kind)
|
||||
}
|
||||
}
|
||||
|
||||
func listSQLiteTables(path string) ([]tableInfo, error) {
|
||||
db, err := sql.Open("sqlite3", "file:"+path+"?mode=ro")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
rows, err := db.Query(`
|
||||
SELECT name FROM sqlite_master
|
||||
WHERE type='table'
|
||||
AND name NOT LIKE 'sqlite_%'
|
||||
AND name != '_migrations'
|
||||
ORDER BY name`)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var out []tableInfo
|
||||
for rows.Next() {
|
||||
var name string
|
||||
if err := rows.Scan(&name); err != nil {
|
||||
continue
|
||||
}
|
||||
var cnt int64
|
||||
row := db.QueryRow(`SELECT count(*) FROM "` + name + `"`)
|
||||
_ = row.Scan(&cnt)
|
||||
out = append(out, tableInfo{Name: name, RowCount: cnt})
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func listDuckDBTablesViaCLI(path string) ([]tableInfo, error) {
|
||||
// Use the python venv's duckdb module to avoid linking go-duckdb.
|
||||
pyBin := "/home/lucas/fn_registry/python/.venv/bin/python3"
|
||||
script := fmt.Sprintf(
|
||||
`import duckdb,sys
|
||||
c=duckdb.connect(%q, read_only=True)
|
||||
for (name,) in c.execute("SELECT table_name FROM information_schema.tables WHERE table_schema='main' ORDER BY table_name").fetchall():
|
||||
cnt=c.execute(f'SELECT count(*) FROM "{name}"').fetchone()[0]
|
||||
print(f"{name}\t{cnt}")
|
||||
`, path)
|
||||
cmd := exec.Command(pyBin, "-c", script)
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("duckdb via python: %w (output: %s)", err, string(out))
|
||||
}
|
||||
|
||||
var result []tableInfo
|
||||
for _, line := range strings.Split(strings.TrimSpace(string(out)), "\n") {
|
||||
if line == "" {
|
||||
continue
|
||||
}
|
||||
parts := strings.SplitN(line, "\t", 2)
|
||||
if len(parts) != 2 {
|
||||
continue
|
||||
}
|
||||
cnt, _ := strconv.ParseInt(strings.TrimSpace(parts[1]), 10, 64)
|
||||
result = append(result, tableInfo{Name: parts[0], RowCount: cnt})
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
Reference in New Issue
Block a user