118 lines
3.0 KiB
Go
118 lines
3.0 KiB
Go
//go:build ignore
|
|
|
|
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"flag"
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"sort"
|
|
"time"
|
|
|
|
"github.com/glebarez/sqlite"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
type snapshot struct {
|
|
GeneratedAt string `json:"generated_at"`
|
|
Path string `json:"path"`
|
|
FileSize int64 `json:"file_size"`
|
|
Existing []string `json:"existing_tables"`
|
|
Missing []string `json:"missing_tables"`
|
|
Tables map[string]int64 `json:"tables"`
|
|
SampleUsers []string `json:"sample_users"`
|
|
}
|
|
|
|
func main() {
|
|
dbPath := flag.String("db", "./data/user_management.db", "sqlite database path")
|
|
jsonOutput := flag.Bool("json", false, "emit snapshot as JSON")
|
|
flag.Parse()
|
|
|
|
info, err := os.Stat(*dbPath)
|
|
if err != nil {
|
|
log.Fatalf("stat db failed: %v", err)
|
|
}
|
|
|
|
db, err := gorm.Open(sqlite.Open(*dbPath), &gorm.Config{})
|
|
if err != nil {
|
|
log.Fatalf("open db failed: %v", err)
|
|
}
|
|
|
|
tableNames := []string{
|
|
"users",
|
|
"roles",
|
|
"permissions",
|
|
"user_roles",
|
|
"role_permissions",
|
|
"devices",
|
|
"login_logs",
|
|
"operation_logs",
|
|
"social_accounts",
|
|
"webhooks",
|
|
"webhook_deliveries",
|
|
"password_histories",
|
|
}
|
|
|
|
var existingTables []string
|
|
if err := db.Raw("SELECT name FROM sqlite_master WHERE type = 'table'").Scan(&existingTables).Error; err != nil {
|
|
log.Fatalf("load sqlite table names failed: %v", err)
|
|
}
|
|
sort.Strings(existingTables)
|
|
existingTableSet := make(map[string]struct{}, len(existingTables))
|
|
for _, tableName := range existingTables {
|
|
existingTableSet[tableName] = struct{}{}
|
|
}
|
|
|
|
tableCounts := make(map[string]int64, len(tableNames))
|
|
missingTables := make([]string, 0)
|
|
for _, tableName := range tableNames {
|
|
if _, ok := existingTableSet[tableName]; !ok {
|
|
missingTables = append(missingTables, tableName)
|
|
continue
|
|
}
|
|
var count int64
|
|
if err := db.Raw("SELECT COUNT(*) FROM " + tableName).Scan(&count).Error; err != nil {
|
|
log.Fatalf("count table %s failed: %v", tableName, err)
|
|
}
|
|
tableCounts[tableName] = count
|
|
}
|
|
|
|
var sampleUsers []string
|
|
if err := db.Raw("SELECT username FROM users ORDER BY id ASC LIMIT 10").Scan(&sampleUsers).Error; err != nil {
|
|
log.Fatalf("load sample users failed: %v", err)
|
|
}
|
|
sort.Strings(sampleUsers)
|
|
|
|
result := snapshot{
|
|
GeneratedAt: time.Now().Format(time.RFC3339),
|
|
Path: *dbPath,
|
|
FileSize: info.Size(),
|
|
Existing: existingTables,
|
|
Missing: missingTables,
|
|
Tables: tableCounts,
|
|
SampleUsers: sampleUsers,
|
|
}
|
|
|
|
if *jsonOutput {
|
|
encoder := json.NewEncoder(os.Stdout)
|
|
encoder.SetIndent("", " ")
|
|
if err := encoder.Encode(result); err != nil {
|
|
log.Fatalf("encode snapshot failed: %v", err)
|
|
}
|
|
return
|
|
}
|
|
|
|
fmt.Printf("snapshot generated_at=%s\n", result.GeneratedAt)
|
|
fmt.Printf("path=%s size=%d\n", result.Path, result.FileSize)
|
|
for _, tableName := range tableNames {
|
|
if count, ok := result.Tables[tableName]; ok {
|
|
fmt.Printf("%s=%d\n", tableName, count)
|
|
continue
|
|
}
|
|
fmt.Printf("%s=missing\n", tableName)
|
|
}
|
|
fmt.Printf("sample_users=%v\n", result.SampleUsers)
|
|
}
|