include-db.go (4408B)
1 package main 2 3 import ( 4 "database/sql" 5 "strings" 6 7 _ "github.com/mattn/go-sqlite3" 8 ) 9 10 // InitDatabase opens the database connection and creates tables if needed 11 func InitDatabase(dbPath string) (*sql.DB, error) { 12 db, err := sql.Open("sqlite3", dbPath+"?_busy_timeout=5000") 13 if err != nil { 14 return nil, err 15 } 16 17 if err := createTables(db); err != nil { 18 db.Close() 19 return nil, err 20 } 21 22 return db, nil 23 } 24 25 // createTables creates all necessary database tables 26 func createTables(db *sql.DB) error { 27 schema := ` 28 CREATE TABLE IF NOT EXISTS files ( 29 id INTEGER PRIMARY KEY AUTOINCREMENT, 30 filename TEXT, 31 path TEXT, 32 description TEXT DEFAULT '' 33 ); 34 CREATE TABLE IF NOT EXISTS categories ( 35 id INTEGER PRIMARY KEY AUTOINCREMENT, 36 name TEXT UNIQUE 37 ); 38 CREATE TABLE IF NOT EXISTS tags ( 39 id INTEGER PRIMARY KEY AUTOINCREMENT, 40 category_id INTEGER, 41 value TEXT, 42 UNIQUE(category_id, value) 43 ); 44 CREATE TABLE IF NOT EXISTS file_tags ( 45 file_id INTEGER, 46 tag_id INTEGER, 47 UNIQUE(file_id, tag_id) 48 ); 49 CREATE TABLE IF NOT EXISTS file_properties ( 50 file_id INTEGER, 51 key TEXT, 52 value TEXT, 53 UNIQUE(file_id, key) 54 ); 55 CREATE TABLE IF NOT EXISTS notes ( 56 id INTEGER PRIMARY KEY CHECK (id = 1), 57 content TEXT DEFAULT '', 58 updated_at DATETIME DEFAULT CURRENT_TIMESTAMP 59 ); 60 CREATE TABLE IF NOT EXISTS settings ( 61 key TEXT PRIMARY KEY, 62 value TEXT NOT NULL DEFAULT '' 63 ); 64 CREATE TABLE IF NOT EXISTS tag_aliases ( 65 id INTEGER PRIMARY KEY AUTOINCREMENT, 66 category TEXT NOT NULL, 67 aliases TEXT NOT NULL 68 ); 69 CREATE TABLE IF NOT EXISTS sed_rules ( 70 id INTEGER PRIMARY KEY AUTOINCREMENT, 71 name TEXT NOT NULL, 72 description TEXT NOT NULL DEFAULT '', 73 command TEXT NOT NULL 74 ); 75 ` 76 77 _, err := db.Exec(schema) 78 return err 79 } 80 81 func LoadConfig(db *sql.DB) (Config, error) { 82 cfg := Config{ 83 GallerySize: "400px", 84 ItemsPerPage: "100", 85 TagAliases: []TagAliasGroup{}, 86 SedRules: []SedRule{}, 87 } 88 89 rows, err := db.Query(`SELECT key, value FROM settings`) 90 if err != nil { 91 return cfg, err 92 } 93 defer rows.Close() 94 for rows.Next() { 95 var key, value string 96 if err := rows.Scan(&key, &value); err != nil { 97 return cfg, err 98 } 99 switch key { 100 case "gallery_size": 101 if value != "" { 102 cfg.GallerySize = value 103 } 104 case "items_per_page": 105 if value != "" { 106 cfg.ItemsPerPage = value 107 } 108 } 109 } 110 if err := rows.Err(); err != nil { 111 return cfg, err 112 } 113 114 aliasRows, err := db.Query(`SELECT category, aliases FROM tag_aliases ORDER BY id`) 115 if err != nil { 116 return cfg, err 117 } 118 defer aliasRows.Close() 119 for aliasRows.Next() { 120 var category, aliasesStr string 121 if err := aliasRows.Scan(&category, &aliasesStr); err != nil { 122 return cfg, err 123 } 124 cfg.TagAliases = append(cfg.TagAliases, TagAliasGroup{ 125 Category: category, 126 Aliases: strings.Split(aliasesStr, "|"), 127 }) 128 } 129 if err := aliasRows.Err(); err != nil { 130 return cfg, err 131 } 132 133 sedRows, err := db.Query(`SELECT name, description, command FROM sed_rules ORDER BY id`) 134 if err != nil { 135 return cfg, err 136 } 137 defer sedRows.Close() 138 for sedRows.Next() { 139 var rule SedRule 140 if err := sedRows.Scan(&rule.Name, &rule.Description, &rule.Command); err != nil { 141 return cfg, err 142 } 143 cfg.SedRules = append(cfg.SedRules, rule) 144 } 145 if err := sedRows.Err(); err != nil { 146 return cfg, err 147 } 148 149 return cfg, nil 150 } 151 152 func SaveConfig(db *sql.DB, cfg Config) error { 153 tx, err := db.Begin() 154 if err != nil { 155 return err 156 } 157 defer tx.Rollback() 158 159 for _, kv := range [][2]string{ 160 {"gallery_size", cfg.GallerySize}, 161 {"items_per_page", cfg.ItemsPerPage}, 162 } { 163 if _, err := tx.Exec(` 164 INSERT INTO settings (key, value) VALUES (?, ?) 165 ON CONFLICT(key) DO UPDATE SET value = excluded.value 166 `, kv[0], kv[1]); err != nil { 167 return err 168 } 169 } 170 171 if _, err := tx.Exec(`DELETE FROM tag_aliases`); err != nil { 172 return err 173 } 174 for _, group := range cfg.TagAliases { 175 aliasesStr := strings.Join(group.Aliases, "|") 176 if _, err := tx.Exec( 177 `INSERT INTO tag_aliases (category, aliases) VALUES (?, ?)`, 178 group.Category, aliasesStr, 179 ); err != nil { 180 return err 181 } 182 } 183 184 if _, err := tx.Exec(`DELETE FROM sed_rules`); err != nil { 185 return err 186 } 187 for _, rule := range cfg.SedRules { 188 if _, err := tx.Exec( 189 `INSERT INTO sed_rules (name, description, command) VALUES (?, ?, ?)`, 190 rule.Name, rule.Description, rule.Command, 191 ); err != nil { 192 return err 193 } 194 } 195 196 return tx.Commit() 197 }