更新若干功能

This commit is contained in:
李琦
2026-08-15 17:18:00 +08:00
parent 4954295961
commit 6a81e479ef
77 changed files with 8165 additions and 2372 deletions

View File

@@ -1,9 +1,14 @@
// Applies init.sql using the packaged sync defaults (build/sync.defaults.json).
// Applies nl-pms-api/init.sql to MySQL.
// Usage (from view repo root):
//
// go run ./tools/applyinit -dsn "user:pass@tcp(host:3306)/"
//
// Or set MYSQL_DSN. Schema source of truth is ../nl-pms-api/init.sql.
package main
import (
"database/sql"
"encoding/json"
"flag"
"fmt"
"os"
"path/filepath"
@@ -12,55 +17,39 @@ import (
_ "github.com/go-sql-driver/mysql"
)
type syncDefaults struct {
Host string `json:"host"`
Port int `json:"port"`
User string `json:"user"`
Password string `json:"password"`
Database string `json:"database"`
}
func loadDefaults() syncDefaults {
path := filepath.Join("build", "sync.defaults.json")
func main() {
dsnFlag := flag.String("dsn", "", "MySQL DSN without database (or set MYSQL_DSN)")
sqlPath := flag.String("sql", "", "path to init.sql (default: ../nl-pms-api/init.sql)")
flag.Parse()
dsn := strings.TrimSpace(*dsnFlag)
if dsn == "" {
dsn = strings.TrimSpace(os.Getenv("MYSQL_DSN"))
}
if dsn == "" {
fmt.Fprintln(os.Stderr, "缺少 -dsn 或 MYSQL_DSN例: root:root@tcp(127.0.0.1:3306)/")
os.Exit(2)
}
if !strings.Contains(dsn, "multiStatements") {
if strings.Contains(dsn, "?") {
dsn += "&multiStatements=false&charset=utf8mb4"
} else {
dsn += "?multiStatements=false&charset=utf8mb4"
}
}
path := *sqlPath
if path == "" {
path = filepath.Join("..", "nl-pms-api", "init.sql")
}
raw, err := os.ReadFile(path)
if err != nil {
panic(err)
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
var c syncDefaults
if err := json.Unmarshal(raw, &c); err != nil {
panic(err)
}
if c.Port <= 0 {
c.Port = 3306
}
return c
}
func dsn(c syncDefaults, withDB bool) string {
db := ""
if withDB {
db = c.Database
}
return fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?multiStatements=false&charset=utf8mb4",
c.User, c.Password, c.Host, c.Port, db)
}
func main() {
cfg := loadDefaults()
if len(os.Args) > 1 && os.Args[1] == "inspect" {
inspect(cfg)
return
}
raw, err := os.ReadFile("init.sql")
if err != nil {
panic(err)
}
db, err := sql.Open("mysql", dsn(cfg, false))
db, err := sql.Open("mysql", dsn)
if err != nil {
panic(err)
}
defer db.Close()
// init.sql 的升级段依赖会话变量SET @sql / PREPARE必须固定在同一连接上执行。
db.SetMaxOpenConns(1)
var kept []string
@@ -81,11 +70,11 @@ func main() {
}
}
var n int
if err := db.QueryRow("SELECT COUNT(*) FROM " + cfg.Database + ".sync_settings").Scan(&n); err != nil {
if err := db.QueryRow("SELECT COUNT(*) FROM code_count.users").Scan(&n); err != nil {
fmt.Println("verify failed:", err)
os.Exit(1)
}
fmt.Println("ok, sync_settings rows:", n, "host:", cfg.Host)
fmt.Println("ok, users rows:", n, "sql:", path)
}
func min(a, b int) int {
@@ -94,25 +83,3 @@ func min(a, b int) int {
}
return b
}
func inspect(cfg syncDefaults) {
db, err := sql.Open("mysql", dsn(cfg, true))
if err != nil {
panic(err)
}
defer db.Close()
rows, err := db.Query("SELECT user_id, name, LENGTH(value), updated_at FROM sync_settings ORDER BY user_id, name")
if err != nil {
panic(err)
}
defer rows.Close()
for rows.Next() {
var uid int64
var name, at string
var n int
if err := rows.Scan(&uid, &name, &n, &at); err != nil {
panic(err)
}
fmt.Printf("user=%d name=%-12s bytes=%-6d at=%s\n", uid, name, n, at)
}
}