github.com/nais/knorten@v0.0.0-20240104110906-55926958e361/pkg/database/repo.go (about) 1 package database 2 3 import ( 4 "context" 5 "database/sql" 6 "embed" 7 "fmt" 8 "time" 9 10 "github.com/gin-contrib/sessions" 11 "github.com/gin-contrib/sessions/postgres" 12 "github.com/gin-gonic/gin" 13 "github.com/google/uuid" 14 _ "github.com/lib/pq" 15 "github.com/nais/knorten/pkg/database/crypto" 16 "github.com/nais/knorten/pkg/database/gensql" 17 "github.com/pressly/goose/v3" 18 "github.com/sirupsen/logrus" 19 20 // Pin version of sqlc cli 21 _ "github.com/kyleconroy/sqlc" 22 ) 23 24 //go:embed migrations/*.sql 25 var embedMigrations embed.FS 26 27 type Repository interface { 28 EventSetStatus(context.Context, uuid.UUID, EventStatus) error 29 EventSetPendingStatus(context.Context, uuid.UUID) error 30 DispatchableEventsGet(context.Context) ([]gensql.Event, error) 31 EventLogCreate(context.Context, uuid.UUID, string, LogType) error 32 } 33 34 type Repo struct { 35 querier Querier 36 db *sql.DB 37 cryptClient *crypto.EncrypterDecrypter 38 log *logrus.Entry 39 } 40 41 type Querier interface { 42 gensql.Querier 43 WithTx(tx *sql.Tx) *gensql.Queries 44 } 45 46 func New(dbConnDSN, cryptoKey string, log *logrus.Entry) (*Repo, error) { 47 db, err := sql.Open("postgres", dbConnDSN) 48 if err != nil { 49 return nil, fmt.Errorf("open sql connection: %w", err) 50 } 51 52 err = gooseMigrationWithRetries(log, db) 53 if err != nil { 54 return nil, fmt.Errorf("goose up: %w", err) 55 } 56 57 return &Repo{ 58 querier: gensql.New(db), 59 db: db, 60 cryptClient: crypto.New(cryptoKey), 61 log: log, 62 }, nil 63 } 64 65 func gooseMigrationWithRetries(log *logrus.Entry, db *sql.DB) error { 66 goose.SetLogger(log) 67 goose.SetBaseFS(embedMigrations) 68 69 err := goose.Up(db, "migrations") 70 if err != nil { 71 backoffSchedule := []time.Duration{ 72 5 * time.Second, 73 15 * time.Second, 74 30 * time.Second, 75 60 * time.Second, 76 } 77 78 for _, duration := range backoffSchedule { 79 time.Sleep(duration) 80 err = goose.Up(db, "migrations") 81 if err == nil { 82 return nil 83 } 84 log.Infof("goose up failed: %v", err) 85 } 86 } 87 88 return err 89 } 90 91 func (r *Repo) NewSessionStore(key string) (gin.HandlerFunc, error) { 92 store, err := postgres.NewStore(r.db, []byte(key)) 93 if err != nil { 94 return nil, err 95 } 96 97 return sessions.Sessions("session", store), nil 98 } 99 100 func (r *Repo) DecryptValue(encValue string) (string, error) { 101 return r.cryptClient.DecryptValue(encValue) 102 } 103 104 func (r *Repo) EncryptValue(encValue string) (string, error) { 105 return r.cryptClient.EncryptValue(encValue) 106 }