feat: store connection and source CRUD

This commit is contained in:
2026-06-27 13:02:17 +08:00
parent 3d0b91fe23
commit 7cd84c8468
5 changed files with 131 additions and 2 deletions
+4 -1
View File
@@ -5,7 +5,10 @@
"Bash(go build *)",
"Bash(go run *)",
"Bash(git add *)",
"Bash(git commit *)"
"Bash(git commit *)",
"Bash(go vet *)",
"Bash(/Users/ryan/.claude/plugins/cache/superpowers-marketplace/superpowers/6.0.3/skills/subagent-driven-development/scripts/task-brief *)",
"Bash(go get *)"
]
}
}
+6 -1
View File
@@ -2,9 +2,14 @@ module aiaa-notification-service
go 1.26.2
require github.com/spf13/viper v1.21.0
require (
github.com/go-sql-driver/mysql v1.10.0
github.com/jmoiron/sqlx v1.4.0
github.com/spf13/viper v1.21.0
)
require (
filippo.io/edwards25519 v1.2.0 // indirect
github.com/fsnotify/fsnotify v1.9.0 // indirect
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
+12
View File
@@ -1,17 +1,29 @@
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
filippo.io/edwards25519 v1.2.0 h1:crnVqOiS4jqYleHd9vaKZ+HKtHfllngJIiOpNpoJsjo=
filippo.io/edwards25519 v1.2.0/go.mod h1:xzAOLCNug/yB62zG1bQ8uziwrIqIuxhctzJT18Q77mc=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
github.com/go-sql-driver/mysql v1.10.0 h1:Q+1LV8DkHJvSYAdR83XzuhDaTykuDx0l6fkXxoWCWfw=
github.com/go-sql-driver/mysql v1.10.0/go.mod h1:M+cqaI7+xxXGG9swrdeUIoPG3Y3KCkF0pZej+SK+nWk=
github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs=
github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o=
github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+28
View File
@@ -0,0 +1,28 @@
package store
import (
"fmt"
"aiaa-notification-service/internal/config"
"github.com/jmoiron/sqlx"
_ "github.com/go-sql-driver/mysql"
)
type Store struct {
DB *sqlx.DB
}
func NewStore(cfg config.DatabaseConfig) (*Store, error) {
db, err := sqlx.Connect("mysql", cfg.DSN())
if err != nil {
return nil, fmt.Errorf("connect mysql: %w", err)
}
db.SetMaxOpenConns(25)
db.SetMaxIdleConns(5)
return &Store{DB: db}, nil
}
func (s *Store) Close() error {
return s.DB.Close()
}
+81
View File
@@ -0,0 +1,81 @@
package store
import (
"context"
"crypto/rand"
"encoding/hex"
"fmt"
"aiaa-notification-service/internal/model"
)
func generateAPIKey() string {
b := make([]byte, 32)
rand.Read(b)
return "sk-" + hex.EncodeToString(b)
}
func (s *Store) CreateSource(ctx context.Context, src *model.Source) error {
src.APIKey = generateAPIKey()
query := `INSERT INTO source (name, api_key, parse_mode, parse_pattern, status) VALUES (?, ?, ?, ?, ?)`
result, err := s.DB.ExecContext(ctx, query, src.Name, src.APIKey, src.ParseMode, src.ParsePattern, src.Status)
if err != nil {
return fmt.Errorf("create source: %w", err)
}
id, _ := result.LastInsertId()
src.ID = int(id)
return nil
}
func (s *Store) GetSource(ctx context.Context, id int) (*model.Source, error) {
var src model.Source
err := s.DB.GetContext(ctx, &src, `SELECT * FROM source WHERE id = ?`, id)
if err != nil {
return nil, fmt.Errorf("get source %d: %w", id, err)
}
return &src, nil
}
func (s *Store) GetSourceByAPIKey(ctx context.Context, apiKey string) (*model.Source, error) {
var src model.Source
err := s.DB.GetContext(ctx, &src, `SELECT * FROM source WHERE api_key = ? AND status = 1`, apiKey)
if err != nil {
return nil, fmt.Errorf("get source by api_key: %w", err)
}
return &src, nil
}
func (s *Store) GetSourceByName(ctx context.Context, name string) (*model.Source, error) {
var src model.Source
err := s.DB.GetContext(ctx, &src, `SELECT * FROM source WHERE name = ?`, name)
if err != nil {
return nil, fmt.Errorf("get source by name %s: %w", name, err)
}
return &src, nil
}
func (s *Store) ListSources(ctx context.Context) ([]model.Source, error) {
var sources []model.Source
err := s.DB.SelectContext(ctx, &sources, `SELECT * FROM source ORDER BY id`)
if err != nil {
return nil, fmt.Errorf("list sources: %w", err)
}
return sources, nil
}
func (s *Store) UpdateSource(ctx context.Context, id int, src *model.Source) error {
query := `UPDATE source SET name=?, parse_mode=?, parse_pattern=?, status=? WHERE id=?`
_, err := s.DB.ExecContext(ctx, query, src.Name, src.ParseMode, src.ParsePattern, src.Status, id)
if err != nil {
return fmt.Errorf("update source %d: %w", id, err)
}
return nil
}
func (s *Store) DeleteSource(ctx context.Context, id int) error {
_, err := s.DB.ExecContext(ctx, `DELETE FROM source WHERE id = ?`, id)
if err != nil {
return fmt.Errorf("delete source %d: %w", id, err)
}
return nil
}