This repository has been archived on 2023-08-20. You can view files and clone it, but cannot push or open issues or pull requests.
backend/internal/question/repository/pg_repository.go

171 lines
4.4 KiB
Go

package repository
import (
"context"
"github.com/Kichiyaki/gopgutil/v10"
"github.com/pkg/errors"
"strings"
"time"
"github.com/go-pg/pg/v10"
"gitea.dwysokinski.me/zdam-egzamin-zawodowy/backend/fstorage"
"gitea.dwysokinski.me/zdam-egzamin-zawodowy/backend/internal/model"
"gitea.dwysokinski.me/zdam-egzamin-zawodowy/backend/internal/question"
"gitea.dwysokinski.me/zdam-egzamin-zawodowy/backend/util/errorutil"
)
type PGRepositoryConfig struct {
DB *pg.DB
FileStorage fstorage.FileStorage
}
type PGRepository struct {
*pg.DB
*repository
}
var _ question.Repository = &PGRepository{}
func NewPGRepository(cfg *PGRepositoryConfig) (*PGRepository, error) {
if cfg == nil || cfg.DB == nil {
return nil, errors.New("cfg.DB is required")
}
if cfg.FileStorage == nil {
return nil, errors.New("cfg.FileStorage is required")
}
return &PGRepository{
cfg.DB,
&repository{
fileStorage: cfg.FileStorage,
},
}, nil
}
func (repo *PGRepository) Store(ctx context.Context, input *model.QuestionInput) (*model.Question, error) {
item := input.ToQuestion()
baseQuery := repo.
Model(item).
Context(ctx).
Returning("*")
if _, err := baseQuery.
Clone().
Insert(); err != nil {
return nil, handleInsertAndUpdateError(err)
}
repo.saveImages(item, input)
if _, err := baseQuery.
Clone().
WherePK().
Set("image = ?", item.Image).
Set("answer_a_image = ?", item.AnswerAImage).
Set("answer_b_image = ?", item.AnswerBImage).
Set("answer_c_image = ?", item.AnswerCImage).
Set("answer_d_image = ?", item.AnswerDImage).
Update(); err != nil && err != pg.ErrNoRows {
return nil, errorutil.Wrap(err, messageFailedToSaveModel)
}
return item, nil
}
func (repo *PGRepository) UpdateOneByID(ctx context.Context, id int, input *model.QuestionInput) (*model.Question, error) {
item := &model.Question{}
baseQuery := repo.
Model(item).
Context(ctx).
Returning("*").
Where(gopgutil.BuildConditionEquals("?"), gopgutil.AddAliasToColumnName("id", "question"), id).
Set("updated_at = ?", time.Now())
if _, err := baseQuery.
Clone().
Apply(input.ApplyUpdate).
Update(); err != nil && err != pg.ErrNoRows {
return nil, handleInsertAndUpdateError(err)
}
repo.saveImages(item, input)
repo.deleteImagesBasedOnInput(item, input)
if _, err := baseQuery.
Clone().
Set("image = ?", item.Image).
Set("answer_a_image = ?", item.AnswerAImage).
Set("answer_b_image = ?", item.AnswerBImage).
Set("answer_c_image = ?", item.AnswerCImage).
Set("answer_d_image = ?", item.AnswerDImage).
Update(); err != nil && err != pg.ErrNoRows {
return nil, handleInsertAndUpdateError(err)
}
return item, nil
}
func (repo *PGRepository) Delete(ctx context.Context, f *model.QuestionFilter) ([]*model.Question, error) {
items := make([]*model.Question, 0)
if _, err := repo.
Model(&items).
Context(ctx).
Returning("*").
Apply(f.Where).
Delete(); err != nil && err != pg.ErrNoRows {
return nil, errorutil.Wrap(err, messageFailedToDeleteModel)
}
go repo.getAllImagesAndDelete(items)
return items, nil
}
func (repo *PGRepository) Fetch(ctx context.Context, cfg *question.FetchConfig) ([]*model.Question, int, error) {
var err error
items := make([]*model.Question, 0)
total := 0
query := repo.
Model(&items).
Context(ctx).
Limit(cfg.Limit).
Offset(cfg.Offset).
Apply(cfg.Filter.Where).
Apply(gopgutil.OrderAppender{
Orders: cfg.Sort,
}.Apply)
if cfg.Count {
total, err = query.SelectAndCount()
} else {
err = query.Select()
}
if err != nil && err != pg.ErrNoRows {
return nil, 0, errorutil.Wrap(err, messageFailedToFetchModel)
}
return items, total, nil
}
func (repo *PGRepository) GenerateTest(ctx context.Context, cfg *question.GenerateTestConfig) ([]*model.Question, error) {
subquery := repo.
Model(&model.Question{}).
Column("id").
Where(gopgutil.BuildConditionArray("qualification_id"), pg.Array(cfg.Qualifications)).
OrderExpr("random()").
Limit(cfg.Limit)
items := make([]*model.Question, 0)
if err := repo.
Model(&items).
Context(ctx).
Where(gopgutil.BuildConditionIn("id"), subquery).
Select(); err != nil && err != pg.ErrNoRows {
return nil, errorutil.Wrap(err, messageFailedToFetchModel)
}
return items, nil
}
func handleInsertAndUpdateError(err error) error {
if strings.Contains(err.Error(), "questions_from_content_correct_answer_qualification_id_key") {
return errorutil.Wrap(err, messageSimilarRecordExists)
}
return errorutil.Wrap(err, messageFailedToSaveModel)
}