-
Notifications
You must be signed in to change notification settings - Fork 13
Expand file tree
/
Copy pathseed.go
More file actions
104 lines (84 loc) · 2.4 KB
/
Copy pathseed.go
File metadata and controls
104 lines (84 loc) · 2.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
package main
import (
"fmt"
"log"
"os"
"strings"
"github.com/pelletier/go-toml/v2"
)
// SeedConfig represents the structure of a seed TOML file.
type SeedConfig struct {
Links []SeedLink `toml:"links"`
}
// SeedLink represents a single link entry in the seed file.
type SeedLink struct {
URL string `toml:"url"`
Message string `toml:"message"`
Description string `toml:"description"`
ImageURL string `toml:"image_url"`
Weight int `toml:"weight"`
}
// applySeed reads a TOML seed file and replaces database links with the seed links.
func (app *App) applySeed(path string) error {
data, err := os.ReadFile(path)
if err != nil {
return fmt.Errorf("reading seed file: %w", err)
}
var seed SeedConfig
if err := toml.Unmarshal(data, &seed); err != nil {
return fmt.Errorf("parsing seed file: %w", err)
}
if err := app.DB.ReplaceLinks(seed.Links); err != nil {
return fmt.Errorf("applying seed file: %w", err)
}
log.Printf("seeded %d links from %s", len(seed.Links), path)
// Refresh the in-memory link cache
if err := app.UpdateLinks(); err != nil {
return fmt.Errorf("updating links after seed: %w", err)
}
return nil
}
// ReplaceLinks replaces all existing links with the provided declarative link set.
func (l *LinkDB) ReplaceLinks(links []SeedLink) error {
for i, link := range links {
if err := validateSeedLink(link); err != nil {
return fmt.Errorf("validating seed link %d: %w", i+1, err)
}
}
tx, err := l.db.Beginx()
if err != nil {
return fmt.Errorf("starting seed transaction: %w", err)
}
committed := false
defer func() {
if !committed {
_ = tx.Rollback()
}
}()
if _, err := tx.Exec("DELETE FROM links;"); err != nil {
return fmt.Errorf("clearing links table: %w", err)
}
for _, link := range links {
_, err := tx.Exec(
"INSERT INTO links (url, message, description, image_url, weight) VALUES (?, ?, ?, ?, ?);",
link.URL, link.Message, link.Description, link.ImageURL, link.Weight,
)
if err != nil {
return fmt.Errorf("inserting seed link %q: %w", link.URL, err)
}
}
if err := tx.Commit(); err != nil {
return fmt.Errorf("committing seed transaction: %w", err)
}
committed = true
return nil
}
func validateSeedLink(link SeedLink) error {
if strings.TrimSpace(link.URL) == "" {
return fmt.Errorf("url is required")
}
if strings.TrimSpace(link.Message) == "" {
return fmt.Errorf("message is required")
}
return nil
}