add two new packages - envutils and db, add .gitignore

This commit is contained in:
Dawid Wysokiński 2021-02-27 10:13:35 +01:00
parent 26abcb7a45
commit d39a6317fc
7 changed files with 163 additions and 6 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
.env.local

82
internal/db/db.go Normal file
View File

@ -0,0 +1,82 @@
package db
import (
"context"
"os"
"github.com/sirupsen/logrus"
envutils "github.com/zdam-egzamin-zawodowy/backend/pkg/utils/env"
"github.com/go-pg/pg/v10"
"github.com/go-pg/pg/v10/orm"
"github.com/pkg/errors"
"github.com/zdam-egzamin-zawodowy/backend/internal/models"
)
const (
extensions = `
CREATE EXTENSION IF NOT EXISTS tsm_system_rows;
`
)
func init() {
orm.RegisterTable((*models.QualificationToProfession)(nil))
}
type Config struct {
DebugHook bool
}
func New(cfg *Config) (*pg.DB, error) {
db := pg.Connect(prepareOptions())
if err := createSchema(db); err != nil {
return nil, err
}
if cfg != nil {
if cfg.DebugHook {
db.AddQueryHook(DebugHook{
Entry: logrus.WithField("package", "internal/db"),
})
}
}
return db, nil
}
func prepareOptions() *pg.Options {
return &pg.Options{
User: os.Getenv("DB_USER"),
Password: os.Getenv("DB_PASSWORD"),
Database: os.Getenv("DB_NAME"),
Addr: os.Getenv("DB_HOST") + ":" + os.Getenv("DB_PORT"),
PoolSize: envutils.GetenvInt("DB_POOL_SIZE"),
}
}
func createSchema(db *pg.DB) error {
return db.RunInTransaction(context.Background(), func(tx *pg.Tx) error {
if _, err := tx.Exec(extensions); err != nil {
return errors.Wrap(err, "createSchema")
}
models := []interface{}{
(*models.User)(nil),
(*models.Profession)(nil),
(*models.Qualification)(nil),
(*models.QualificationToProfession)(nil),
(*models.Question)(nil),
}
for _, model := range models {
err := tx.Model(model).CreateTable(&orm.CreateTableOptions{
IfNotExists: true,
})
if err != nil {
return errors.Wrap(err, "createSchema")
}
}
return nil
})
}

33
internal/db/debug_hook.go Normal file
View File

@ -0,0 +1,33 @@
package db
import (
"context"
"github.com/go-pg/pg/v10"
"github.com/sirupsen/logrus"
)
type DebugHook struct {
Entry *logrus.Entry
}
var _ pg.QueryHook = (*DebugHook)(nil)
func (logger DebugHook) BeforeQuery(ctx context.Context, evt *pg.QueryEvent) (context.Context, error) {
q, err := evt.FormattedQuery()
if err != nil {
return nil, err
}
if evt.Err != nil {
logger.Entry.Errorf("%s executing a query:\n%s\n", evt.Err, q)
} else {
logger.Entry.Info(string(q))
}
return ctx, nil
}
func (DebugHook) AfterQuery(context.Context, *pg.QueryEvent) error {
return nil
}

View File

@ -1,4 +1,5 @@
#!/bin/sh
cd ./internal/graphql
go run github.com/99designs/gqlgen
go mod tidy
go mod tidy
cd ../..

View File

@ -11,19 +11,21 @@ import (
)
type Question struct {
tableName struct{} `pg:"alias:question"`
ID int `json:"id" xml:"id" gqlgen:"id"`
From string `pg:",unique:group_1" json:"from" xml:"from" gqlgen:"from"`
Content string `pg:",unique:group_1,notnull" json:"content" xml:"content" gqlgen:"content"`
Explanation string `json:"explanation" xml:"explanation" gqlgen:"explanation"`
CorrectAnswer Answer `pg:",unique:group_1,notnull" json:"correctAnswer" xml:"correctAnswer" gqlgen:"correctAnswer"`
Image string `json:"image" xml:"image" gqlgen:"image"`
AnswerA Answer `json:"answerA" xml:"answerA" gqlgen:"answerA"`
AnswerA Answer `pg:"answer_a" json:"answerA" xml:"answerA" gqlgen:"answerA"`
AnswerAImage string `pg:"answer_a_image" json:"answerAImage" xml:"answerAImage" gqlgen:"answerAImage"`
AnswerB Answer `json:"answerB" xml:"answerB" gqlgen:"answerB"`
AnswerB Answer `pg:"answer_b" json:"answerB" xml:"answerB" gqlgen:"answerB"`
AnswerBImage string `pg:"answer_b_image" json:"answerBImage" xml:"answerBImage" gqlgen:"answerBImage"`
AnswerC Answer `json:"answerC" xml:"answerC" gqlgen:"answerC"`
AnswerC Answer `pg:"answer_c" json:"answerC" xml:"answerC" gqlgen:"answerC"`
AnswerCImage string `pg:"answer_c_image" json:"answerCImage" xml:"answerCImage" gqlgen:"answerCImage"`
AnswerD Answer `json:"answerD" xml:"answerD" gqlgen:"answerD"`
AnswerD Answer `pg:"answer_d" json:"answerD" xml:"answerD" gqlgen:"answerD"`
AnswerDImage string `pg:"answer_d_image" json:"answerDImage" xml:"answerDImage" gqlgen:"answerDImage"`
QualificationID int `pg:",unique:group_1,on_delete:CASCADE" json:"qualificationID" xml:"qualificationID" gqlgen:"qualificationID"`
Qualification *Qualification `pg:"rel:has-one" json:"qualification" xml:"qualification" gqlgen:"qualification"`

14
main.go
View File

@ -7,11 +7,15 @@ import (
"os/signal"
"time"
"github.com/pkg/errors"
"github.com/zdam-egzamin-zawodowy/backend/internal/db"
"github.com/gin-contrib/cors"
"github.com/gin-gonic/gin"
"github.com/joho/godotenv"
"github.com/sirupsen/logrus"
"github.com/zdam-egzamin-zawodowy/backend/pkg/mode"
envutils "github.com/zdam-egzamin-zawodowy/backend/pkg/utils/env"
)
func init() {
@ -25,6 +29,14 @@ func init() {
}
func main() {
_, err := db.New(&db.Config{
DebugHook: envutils.GetenvBool("LOG_DB_QUERIES"),
})
if err != nil {
logrus.Fatal(errors.Wrap(err, "Error establishing a database connection"))
}
logrus.Info("Database connection established")
router := gin.Default()
if mode.Get() == mode.DevelopmentMode {
router.Use(cors.New(cors.Config{
@ -35,7 +47,7 @@ func main() {
ExposeHeaders: []string{"X-Access-Token", "X-Refresh-Token"},
AllowMethods: []string{"GET", "POST", "PUT", "PATCH", "DELETE", "HEAD"},
AllowHeaders: []string{"Origin", "Content-Length", "Content-Type", "Authorization"},
AllowWebSockets: true,
AllowWebSockets: false,
}))
}

26
pkg/utils/env/env.go vendored Normal file
View File

@ -0,0 +1,26 @@
package envutils
import (
"os"
"strconv"
)
func GetenvInt(key string) int {
str := os.Getenv(key)
if str == "" {
return 0
}
i, err := strconv.Atoi(str)
if err != nil {
return 0
}
return i
}
func GetenvBool(key string) bool {
str := os.Getenv(key)
if str == "" {
return false
}
return str == "true" || str == "1"
}