Yimaru-BackEnd/internal/services/assessment/initial_assessment.go

304 lines
7.5 KiB
Go

package assessment
import (
dbgen "Yimaru-Backend/gen/db"
"Yimaru-Backend/internal/domain"
"context"
"errors"
"github.com/jackc/pgx/v5/pgtype"
)
func (s *Service) CreateQuestion(
ctx context.Context,
input domain.CreateAssessmentQuestionInput,
) error {
repo := s.initialAssessmentStore
// 1. Create Question
question, err := repo.CreateAssessmentQuestion(
ctx,
dbgen.CreateAssessmentQuestionParams{
Title: input.Title,
Description: func() pgtype.Text {
ns := toNullString(input.Description)
return pgtype.Text{String: ns.String, Valid: ns.Valid}
}(),
QuestionType: string(input.QuestionType),
DifficultyLevel: pgtype.Text{String: input.DifficultyLevel},
Points: input.Points,
IsActive: input.IsActive,
},
)
if err != nil {
return err
}
// 2. Branch by Question Type
switch input.QuestionType {
case domain.MultipleChoice:
if len(input.Options) == 0 {
return errors.New("multiple choice question requires options")
}
for _, opt := range input.Options {
_, err := repo.CreateQuestionOption(
ctx,
dbgen.CreateQuestionOptionParams{
QuestionID: question.ID,
OptionText: opt.Text,
OptionOrder: opt.Order,
IsCorrect: opt.IsCorrect,
},
)
if err != nil {
return err
}
}
case domain.TrueFalse:
// TRUE
if _, err := repo.CreateQuestionOption(
ctx,
dbgen.CreateQuestionOptionParams{
QuestionID: question.ID,
OptionText: "True",
OptionOrder: 1,
IsCorrect: true,
},
); err != nil {
return err
}
// FALSE
if _, err := repo.CreateQuestionOption(
ctx,
dbgen.CreateQuestionOptionParams{
QuestionID: question.ID,
OptionText: "False",
OptionOrder: 2,
IsCorrect: false,
},
); err != nil {
return err
}
case domain.ShortAnswer:
if input.CorrectAnswer == nil || *input.CorrectAnswer == "" {
return errors.New("short answer question requires correct_answer")
}
_, err := repo.CreateShortAnswer(
ctx,
dbgen.CreateShortAnswerParams{
QuestionID: question.ID,
CorrectAnswer: *input.CorrectAnswer,
},
)
if err != nil {
return err
}
default:
return errors.New("unsupported question type")
}
return nil
}
func (s *Service) ListQuestions(ctx context.Context) ([]domain.QuestionWithDetails, error) {
// repo := s.initialAssessmentStore
questions, err := s.initialAssessmentStore.GetActiveAssessmentQuestions(ctx)
if err != nil {
return nil, err
}
out := make([]domain.QuestionWithDetails, 0, len(questions))
for _, q := range questions {
item := domain.QuestionWithDetails{Question: q}
switch domain.QuestionType(q.QuestionType) {
case domain.MultipleChoice, domain.TrueFalse:
opts, err := s.initialAssessmentStore.GetQuestionOptions(ctx, q.ID)
if err != nil {
return nil, err
}
for _, opt := range opts {
tempOpt := domain.QuestionOption{
QuestionID: opt.ID,
OptionText: opt.OptionText,
}
item.Options = append(item.Options, tempOpt)
}
// case domain.ShortAnswer:
// sa, err := s.initialAssessmentStore.GetShortAnswerByQuestionID(ctx, q.ID)
// if err != nil {
// return nil, err
// }
// item.ShortAnswer = &sa
// }
out = append(out, item)
}
}
return out, nil
}
func (s *Service) GetQuestionByID(ctx context.Context, id int64) (domain.QuestionWithDetails, error) {
repo := s.initialAssessmentStore
q, err := repo.GetAssessmentQuestionByID(ctx, id)
if err != nil {
return domain.QuestionWithDetails{}, err
}
item := domain.QuestionWithDetails{Question: q}
switch domain.QuestionType(q.QuestionType) {
case domain.MultipleChoice, domain.TrueFalse:
opts, err := repo.GetQuestionOptions(ctx, q.ID)
if err != nil {
return domain.QuestionWithDetails{}, err
}
for _, opt := range opts {
tempOpt := domain.QuestionOption{
QuestionID: opt.ID,
OptionText: opt.OptionText,
}
item.Options = append(item.Options, tempOpt)
}
// case domain.ShortAnswer:
// sa, err := repo.GetShortAnswerByQuestionID(ctx, q.ID)
// if err != nil {
// return QuestionWithDetails{}, err
// }
// item.ShortAnswer = &sa
}
return item, nil
}
// func (s *Service) UpdateQuestion(ctx context.Context, id int64, input domain.UpdateAssessmentQuestionInput) error {
// repo := s.initialAssessmentStore
// // fetch existing
// existing, err := repo.GetAssessmentQuestionByID(ctx, id)
// if err != nil {
// return err
// }
// // update base question
// _, err = repo.UpdateAssessmentQuestion(
// ctx,
// dbgen.UpdateAssessmentQuestionParams{
// ID: id,
// Title: input.Title,
// Description: func() pgtype.Text {
// ns := toNullString(input.Description)
// return pgtype.Text{String: ns.String, Valid: ns.Valid}
// }(),
// QuestionType: string(input.QuestionType),
// DifficultyLevel: pgtype.Text{String: input.DifficultyLevel},
// Points: input.Points,
// IsActive: input.IsActive,
// },
// )
// if err != nil {
// return err
// }
// // remove previous dependents (safe to remove regardless of new type)
// // try delete options and short answer; ignore not-found errors if repo returns them
// if err := repo.DeleteQuestionOptionsByQuestionID(ctx, id); err != nil {
// return err
// }
// if err := repo.DeleteShortAnswerByQuestionID(ctx, id); err != nil {
// return err
// }
// // create dependents for new type
// switch input.QuestionType {
// case domain.MultipleChoice:
// if len(input.Options) == 0 {
// return errors.New("multiple choice question requires options")
// }
// for _, opt := range input.Options {
// if _, err := repo.CreateQuestionOption(
// ctx,
// dbgen.CreateQuestionOptionParams{
// QuestionID: id,
// OptionText: opt.Text,
// OptionOrder: opt.Order,
// IsCorrect: opt.IsCorrect,
// },
// ); err != nil {
// return err
// }
// }
// case domain.TrueFalse:
// if _, err := repo.CreateQuestionOption(ctx, dbgen.CreateQuestionOptionParams{
// QuestionID: id,
// OptionText: "True",
// OptionOrder: 1,
// IsCorrect: true,
// }); err != nil {
// return err
// }
// if _, err := repo.CreateQuestionOption(ctx, dbgen.CreateQuestionOptionParams{
// QuestionID: id,
// OptionText: "False",
// OptionOrder: 2,
// IsCorrect: false,
// }); err != nil {
// return err
// }
// case domain.ShortAnswer:
// if input.CorrectAnswer == nil || *input.CorrectAnswer == "" {
// return errors.New("short answer question requires correct_answer")
// }
// if _, err := repo.CreateShortAnswer(ctx, dbgen.CreateShortAnswerParams{
// QuestionID: id,
// CorrectAnswer: *input.CorrectAnswer,
// }); err != nil {
// return err
// }
// default:
// return errors.New("unsupported question type")
// }
// _ = existing
// return nil
// }
// func (s *Service) DeleteQuestion(ctx context.Context, id int64) error {
// repo := s.initialAssessmentStore
// q, err := repo.GetAssessmentQuestionByID(ctx, id)
// if err != nil {
// return err
// }
// // delete dependents by existing type
// switch domain.QuestionType(q.QuestionType) {
// case domain.MultipleChoice, domain.TrueFalse:
// if err := repo.DeleteQuestionOptionsByQuestionID(ctx, id); err != nil {
// return err
// }
// case domain.ShortAnswer:
// if err := repo.DeleteShortAnswerByQuestionID(ctx, id); err != nil {
// return err
// }
// }
// if err := repo.DeleteAssessmentQuestion(ctx, id); err != nil {
// return err
// }
// return nil
// }
// ...existing code...