Atualiza o banco de dados YASUC, refletindo alterações na estrutura e dados. Esta modificação é parte do processo contínuo de melhorias e otimizações do sistema.
This commit is contained in:
@@ -0,0 +1,181 @@
|
||||
// migrate-to-sql - Script para migrar dados do BoltDB para arquivo SQL
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"math/rand"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/boltdb/bolt"
|
||||
)
|
||||
|
||||
const shortIDLength = 7
|
||||
|
||||
// generateShortID gera um ID único de 7 caracteres
|
||||
func generateShortID() string {
|
||||
const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
||||
b := make([]byte, shortIDLength)
|
||||
for i := range b {
|
||||
b[i] = charset[rand.Intn(len(charset))]
|
||||
}
|
||||
return string(b)
|
||||
}
|
||||
|
||||
// generateUniqueShortID gera um ID único verificando contra um mapa
|
||||
func generateUniqueShortID(usedIDs map[string]bool) string {
|
||||
maxAttempts := 100
|
||||
for i := 0; i < maxAttempts; i++ {
|
||||
id := generateShortID()
|
||||
if !usedIDs[id] {
|
||||
return id
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func main() {
|
||||
// Initialize random seed
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
|
||||
var boltPath, sqlOutputPath string
|
||||
flag.StringVar(&boltPath, "bolt", "", "caminho para o arquivo BoltDB")
|
||||
flag.StringVar(&sqlOutputPath, "output", "", "caminho para o arquivo SQL de saída")
|
||||
flag.Parse()
|
||||
|
||||
if boltPath == "" || sqlOutputPath == "" {
|
||||
fmt.Fprintf(os.Stderr, "Uso: %s -bolt <arquivo_bolt.db> -output <arquivo_sql.sql>\n", os.Args[0])
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Verificar se o arquivo BoltDB existe
|
||||
if _, err := os.Stat(boltPath); os.IsNotExist(err) {
|
||||
log.Fatal("Arquivo BoltDB não encontrado:", boltPath)
|
||||
}
|
||||
|
||||
// Abrir banco BoltDB
|
||||
boltDB, err := bolt.Open(boltPath, 0600, &bolt.Options{Timeout: 1 * time.Second})
|
||||
if err != nil {
|
||||
log.Fatal("Erro ao abrir BoltDB:", err)
|
||||
}
|
||||
defer boltDB.Close()
|
||||
|
||||
// Criar arquivo SQL de saída
|
||||
sqlFile, err := os.Create(sqlOutputPath)
|
||||
if err != nil {
|
||||
log.Fatal("Erro ao criar arquivo SQL:", err)
|
||||
}
|
||||
defer sqlFile.Close()
|
||||
|
||||
// Escrever cabeçalho do arquivo SQL
|
||||
sqlFile.WriteString(`-- Script de migração do BoltDB para SQLite3
|
||||
-- Gerado automaticamente em ` + time.Now().Format("02/01/2006 15:04:05") + `
|
||||
|
||||
-- Criar tabela se não existir
|
||||
CREATE TABLE IF NOT EXISTS pastes (
|
||||
short_id TEXT PRIMARY KEY,
|
||||
content TEXT NOT NULL,
|
||||
content_hash TEXT NOT NULL,
|
||||
created_at INTEGER NOT NULL
|
||||
);
|
||||
|
||||
-- Criar índices
|
||||
CREATE INDEX IF NOT EXISTS idx_pastes_content_hash ON pastes(content_hash);
|
||||
CREATE INDEX IF NOT EXISTS idx_pastes_created_at ON pastes(created_at);
|
||||
|
||||
-- Inserir dados migrados
|
||||
`)
|
||||
|
||||
// Mapear hashes para IDs curtos para evitar duplicatas
|
||||
hashToShortID := make(map[string]string)
|
||||
usedShortIDs := make(map[string]bool)
|
||||
|
||||
// Contadores
|
||||
totalPastes := 0
|
||||
duplicates := 0
|
||||
insertCount := 0
|
||||
|
||||
// Migrar dados do BoltDB
|
||||
err = boltDB.View(func(tx *bolt.Tx) error {
|
||||
b := tx.Bucket([]byte("pastes"))
|
||||
if b == nil {
|
||||
return fmt.Errorf("bucket 'pastes' não encontrado")
|
||||
}
|
||||
|
||||
return b.ForEach(func(k, v []byte) error {
|
||||
totalPastes++
|
||||
|
||||
// Calcular hash SHA-256 do conteúdo
|
||||
hash := sha256.Sum256(v)
|
||||
hashStr := hex.EncodeToString(hash[:])
|
||||
|
||||
// Verificar se já existe um paste com o mesmo conteúdo
|
||||
if existingShortID, exists := hashToShortID[hashStr]; exists {
|
||||
// Paste já existe, usar o mesmo ID curto
|
||||
duplicates++
|
||||
fmt.Printf("Duplicata encontrada: %s -> %s\n", hashStr[:8], existingShortID)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Gerar ID curto único
|
||||
shortID := generateUniqueShortID(usedShortIDs)
|
||||
if shortID == "" {
|
||||
return fmt.Errorf("não foi possível gerar ID único para paste %d", totalPastes)
|
||||
}
|
||||
|
||||
// Marcar ID como usado
|
||||
usedShortIDs[shortID] = true
|
||||
hashToShortID[hashStr] = shortID
|
||||
|
||||
// Preparar conteúdo para SQL (escapar aspas)
|
||||
content := strings.ReplaceAll(string(v), "'", "''")
|
||||
|
||||
// Gerar timestamp (usar timestamp atual para todos)
|
||||
timestamp := time.Now().Unix()
|
||||
|
||||
// Escrever comando INSERT
|
||||
insertSQL := fmt.Sprintf("INSERT OR IGNORE INTO pastes (short_id, content, content_hash, created_at) VALUES ('%s', '%s', '%s', %d);\n",
|
||||
shortID, content, hashStr, timestamp)
|
||||
|
||||
_, err := sqlFile.WriteString(insertSQL)
|
||||
if err != nil {
|
||||
return fmt.Errorf("erro ao escrever SQL: %v", err)
|
||||
}
|
||||
|
||||
insertCount++
|
||||
|
||||
// Progresso a cada 100 pastes
|
||||
if totalPastes%100 == 0 {
|
||||
fmt.Printf("Processados %d pastes...\n", totalPastes)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
log.Fatal("Erro durante migração:", err)
|
||||
}
|
||||
|
||||
// Escrever comentários finais
|
||||
sqlFile.WriteString(fmt.Sprintf(`
|
||||
-- Resumo da migração:
|
||||
-- Total de pastes processados: %d
|
||||
-- Pastes únicos inseridos: %d
|
||||
-- Duplicatas ignoradas: %d
|
||||
-- Arquivo gerado em: %s
|
||||
`, totalPastes, insertCount, duplicates, time.Now().Format("02/01/2006 15:04:05")))
|
||||
|
||||
fmt.Printf("\n=== Migração concluída! ===\n")
|
||||
fmt.Printf("Total de pastes processados: %d\n", totalPastes)
|
||||
fmt.Printf("Pastes únicos inseridos: %d\n", insertCount)
|
||||
fmt.Printf("Duplicatas ignoradas: %d\n", duplicates)
|
||||
fmt.Printf("Arquivo SQL gerado: %s\n", sqlOutputPath)
|
||||
fmt.Printf("\nPara aplicar a migração:\n")
|
||||
fmt.Printf("sqlite3 data/yasuc.sqlite3 < %s\n", sqlOutputPath)
|
||||
}
|
||||
Reference in New Issue
Block a user