103 lines
2.2 KiB
Go
103 lines
2.2 KiB
Go
package main
|
|
|
|
import (
|
|
"database/sql"
|
|
"encoding/json"
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
|
|
"inou/lib"
|
|
|
|
_ "github.com/mattn/go-sqlite3"
|
|
)
|
|
|
|
const dbPath = "/tank/inou/data/inou.db"
|
|
|
|
func main() {
|
|
if len(os.Args) < 2 {
|
|
fmt.Fprintln(os.Stderr, "Usage: dbquery <SQL>")
|
|
fmt.Fprintln(os.Stderr, " Runs SQL against inou.db, decrypts fields, outputs JSON.")
|
|
fmt.Fprintln(os.Stderr, " Example: dbquery \"SELECT * FROM dossiers LIMIT 5\"")
|
|
os.Exit(1)
|
|
}
|
|
|
|
query := strings.Join(os.Args[1:], " ")
|
|
|
|
// Init crypto only (we open DB ourselves for raw queries)
|
|
if err := lib.CryptoInit(lib.KeyPathDefault); err != nil {
|
|
fmt.Fprintf(os.Stderr, "crypto init: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
db, err := sql.Open("sqlite3", dbPath)
|
|
if err != nil {
|
|
fmt.Fprintf(os.Stderr, "db open: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
defer db.Close()
|
|
|
|
rows, err := db.Query(query)
|
|
if err != nil {
|
|
fmt.Fprintf(os.Stderr, "query: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
defer rows.Close()
|
|
|
|
cols, err := rows.Columns()
|
|
if err != nil {
|
|
fmt.Fprintf(os.Stderr, "columns: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
var results []map[string]interface{}
|
|
|
|
for rows.Next() {
|
|
// Scan all as NullString
|
|
scanDest := make([]interface{}, len(cols))
|
|
for i := range scanDest {
|
|
scanDest[i] = new(sql.NullString)
|
|
}
|
|
|
|
if err := rows.Scan(scanDest...); err != nil {
|
|
fmt.Fprintf(os.Stderr, "scan: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
row := make(map[string]interface{})
|
|
for i, col := range cols {
|
|
ns := scanDest[i].(*sql.NullString)
|
|
if !ns.Valid {
|
|
row[col] = nil
|
|
continue
|
|
}
|
|
val := ns.String
|
|
|
|
// Try to decrypt — if it decrypts, use the decrypted value
|
|
if decrypted := lib.CryptoDecrypt(val); decrypted != "" {
|
|
// If decrypted looks like JSON, parse it
|
|
if strings.HasPrefix(decrypted, "{") || strings.HasPrefix(decrypted, "[") {
|
|
var parsed interface{}
|
|
if json.Unmarshal([]byte(decrypted), &parsed) == nil {
|
|
row[col] = parsed
|
|
continue
|
|
}
|
|
}
|
|
row[col] = decrypted
|
|
} else {
|
|
// Try parsing as number for cleaner output
|
|
row[col] = val
|
|
}
|
|
}
|
|
results = append(results, row)
|
|
}
|
|
|
|
if err := rows.Err(); err != nil {
|
|
fmt.Fprintf(os.Stderr, "rows: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
out, _ := json.MarshalIndent(results, "", " ")
|
|
fmt.Println(string(out))
|
|
}
|