Yimaru-BackEnd/internal/repository/initial_assessment.go

176 lines
4.5 KiB
Go

package repository
import (
dbgen "Yimaru-Backend/gen/db"
"Yimaru-Backend/internal/domain"
"Yimaru-Backend/internal/ports"
"context"
"math/big"
"github.com/jackc/pgx/v5/pgtype"
)
func NewInitialAssessmentStore(s *Store) ports.InitialAssessmentStore { return s }
func (r *Store) GetCorrectOptionForQuestion(
ctx context.Context,
questionID int64,
) (int64, error) {
optId, err := r.queries.GetCorrectOptionForQuestion(ctx, questionID)
if err != nil {
return 0, err
}
return optId, nil
}
func (r *Store) GetLatestAssessmentAttempt(
ctx context.Context,
userID int64,
) (*dbgen.AssessmentAttempt, error) {
attempt, err := r.queries.GetLatestAssessmentAttempt(ctx, userID)
if err != nil {
return nil, err
}
return &attempt, nil
}
func (s *Store) CreateAssessmentQuestion(
ctx context.Context,
q domain.AssessmentQuestion,
) (domain.AssessmentQuestion, error) {
row, err := s.queries.CreateAssessmentQuestion(ctx, dbgen.CreateAssessmentQuestionParams{
Title: q.Title,
Description: pgtype.Text{String: q.Description, Valid: q.Description != ""},
QuestionType: q.QuestionType,
DifficultyLevel: q.DifficultyLevel,
})
if err != nil {
return domain.AssessmentQuestion{}, err
}
for _, opt := range q.Options {
if err := s.queries.CreateAssessmentQuestionOption(ctx,
dbgen.CreateAssessmentQuestionOptionParams{
QuestionID: row.ID,
OptionText: opt.OptionText,
IsCorrect: opt.IsCorrect,
},
); err != nil {
return domain.AssessmentQuestion{}, err
}
}
q.ID = row.ID
return q, nil
}
func (s *Store) GetActiveAssessmentQuestions(ctx context.Context) ([]domain.AssessmentQuestion, error) {
questionsRows, err := s.queries.GetActiveAssessmentQuestions(ctx)
if err != nil {
return nil, err
}
questions := make([]domain.AssessmentQuestion, 0, len(questionsRows))
for _, q := range questionsRows {
optionsRows, err := s.queries.GetQuestionOptions(ctx, q.ID)
if err != nil {
return nil, err
}
options := make([]domain.AssessmentOption, 0, len(optionsRows))
for _, o := range optionsRows {
options = append(options, domain.AssessmentOption{
ID: o.ID,
OptionText: o.OptionText,
IsCorrect: o.IsCorrect,
})
}
questions = append(questions, domain.AssessmentQuestion{
ID: q.ID,
Title: q.Title,
Description: q.Description.String,
QuestionType: q.QuestionType,
DifficultyLevel: q.DifficultyLevel,
Options: options,
})
}
return questions, nil
}
// SaveAssessmentAttempt saves the attempt summary and answers
func (s *Store) SaveAssessmentAttempt(ctx context.Context, userID int64, answers []domain.UserAnswer) (domain.AssessmentAttempt, error) {
total := len(answers)
correct := 0
for _, ans := range answers {
if ans.IsCorrect {
correct++
}
}
score := float64(correct) / float64(total) * 100
knowledgeLevel := "BEGINNER"
switch {
case score >= 80:
knowledgeLevel = "ADVANCED"
case score >= 50:
knowledgeLevel = "INTERMEDIATE"
}
// Save attempt
attemptRow, err := s.queries.CreateAssessmentAttempt(ctx, dbgen.CreateAssessmentAttemptParams{
UserID: userID,
TotalQuestions: int32(total),
CorrectAnswers: int32(correct),
ScorePercentage: pgtype.Numeric{Int: big.NewInt(int64(score * 100)), Valid: true},
KnowledgeLevel: knowledgeLevel,
})
if err != nil {
return domain.AssessmentAttempt{}, err
}
// Save answers
for _, ans := range answers {
err := s.queries.CreateAssessmentAnswer(ctx, dbgen.CreateAssessmentAnswerParams{
AttemptID: attemptRow.ID,
QuestionID: ans.QuestionID,
SelectedOptionID: pgtype.Int8{Int64: ans.SelectedOptionID, Valid: true},
ShortAnswer: pgtype.Text{String: ans.ShortAnswer, Valid: true},
IsCorrect: ans.IsCorrect,
})
if err != nil {
return domain.AssessmentAttempt{}, err
}
}
return domain.AssessmentAttempt{
ID: attemptRow.ID,
UserID: userID,
TotalQuestions: total,
CorrectAnswers: correct,
ScorePercentage: score,
KnowledgeLevel: knowledgeLevel,
CompletedAt: attemptRow.CompletedAt.Time,
}, nil
}
// GetOptionByID fetches a single option to validate correctness
func (s *Store) GetOptionByID(ctx context.Context, optionID int64) (domain.AssessmentOption, error) {
o, err := s.queries.GetAssessmentOptionByID(ctx, optionID)
if err != nil {
return domain.AssessmentOption{}, err
}
return domain.AssessmentOption{
ID: o.ID,
OptionText: o.OptionText,
IsCorrect: o.IsCorrect,
}, nil
}