package result import ( "context" "database/sql" "fmt" "penahub.gitlab.yandexcloud.net/backend/quiz/common/dal/sqlcgen" "penahub.gitlab.yandexcloud.net/backend/quiz/common/model" "strconv" "strings" "time" ) type Deps struct { Queries *sqlcgen.Queries Pool *sql.DB } type ResultRepository struct { queries *sqlcgen.Queries pool *sql.DB } func NewResultRepository(deps Deps) *ResultRepository { return &ResultRepository{ queries: deps.Queries, pool: deps.Pool, } } type GetQuizResDeps struct { To, From time.Time New bool Page uint64 Limit uint64 } // test + func (r *ResultRepository) GetQuizResults(ctx context.Context, quizID uint64, reqExport GetQuizResDeps, payment bool) ([]model.AnswerExport, uint64, error) { var results []model.AnswerExport queryBase := "FROM answer WHERE quiz_id = $1 AND result = TRUE AND deleted = FALSE" queryParams := []interface{}{quizID} if !reqExport.From.IsZero() { queryBase += " AND created_at >= $" + strconv.Itoa(len(queryParams)+1) queryParams = append(queryParams, reqExport.From) } if !reqExport.To.IsZero() { queryBase += " AND created_at <= $" + strconv.Itoa(len(queryParams)+1) queryParams = append(queryParams, reqExport.To) } if reqExport.New { queryBase += " AND new = $" + strconv.Itoa(len(queryParams)+1) queryParams = append(queryParams, reqExport.New) } offset := reqExport.Page * reqExport.Limit mainQuery := "SELECT content, id, new, created_at " + queryBase + " ORDER BY created_at DESC LIMIT $" + strconv.Itoa(len(queryParams)+1) + " OFFSET $" + strconv.Itoa(len(queryParams)+2) queryParams = append(queryParams, reqExport.Limit, offset) rows, err := r.pool.QueryContext(ctx, mainQuery, queryParams...) if err != nil { return nil, 0, err } defer rows.Close() for rows.Next() { var answer model.AnswerExport if err := rows.Scan(&answer.Content, &answer.Id, &answer.New, &answer.CreatedAt); err != nil { return nil, 0, err } if !payment { answer.Content = "***" } results = append(results, answer) } totalCountQuery := "SELECT COUNT(*) " + queryBase var totalCount uint64 if err := r.pool.QueryRowContext(ctx, totalCountQuery, queryParams[:len(queryParams)-2]...).Scan(&totalCount); err != nil { return nil, 0, err } return results, totalCount, nil } // test + func (r *ResultRepository) UpdateAnswersStatus(ctx context.Context, accountID string, answersIDs []uint64) error { idsPlaceholder := make([]string, len(answersIDs)) params := make([]interface{}, len(answersIDs)+1) params[0] = accountID for i, id := range answersIDs { params[i+1] = id idsPlaceholder[i] = fmt.Sprintf("$%d", i+2) } placeholders := strings.Join(idsPlaceholder, ", ") sqlStatement := ` UPDATE answer AS ans SET new = false FROM quiz WHERE ans.quiz_id = quiz.id AND quiz.accountid = $1 AND ans.new = true AND ans.id IN (` + placeholders + ")" _, err := r.pool.ExecContext(ctx, sqlStatement, params...) return err } // test + func (r *ResultRepository) GetQuizResultsCSV(ctx context.Context, quizID uint64, reqExport GetQuizResDeps) ([]model.Answer, error) { var results []model.Answer mainQuery := `SELECT DISTINCT ON (a.question_id, a.session) a.id, a.content, a.question_id, a.quiz_id, a.fingerprint, a.session, a.result, a.created_at, a.new, a.deleted FROM answer a WHERE a.quiz_id = $1 AND a.deleted = FALSE` queryParams := []interface{}{quizID} if !reqExport.From.IsZero() || !reqExport.To.IsZero() { mainQuery += ` AND a.created_at BETWEEN $2 AND $3` queryParams = append(queryParams, reqExport.From, reqExport.To) } if reqExport.New { mainQuery += ` AND a.new = $` + strconv.Itoa(len(queryParams)+1) queryParams = append(queryParams, reqExport.New) } mainQuery += ` AND EXISTS ( SELECT 1 FROM answer as a2 WHERE a2.session = a.session AND a2.result = TRUE AND a2.quiz_id = a.quiz_id )` mainQuery += ` ORDER BY a.question_id, a.session, a.created_at DESC, a.result DESC` rows, err := r.pool.QueryContext(ctx, mainQuery, queryParams...) if err != nil { return nil, err } defer rows.Close() for rows.Next() { var answer model.Answer if err := rows.Scan(&answer.Id, &answer.Content, &answer.QuestionId, &answer.QuizId, &answer.Fingerprint, &answer.Session, &answer.Result, &answer.CreatedAt, &answer.New, &answer.Deleted); err != nil { return nil, err } results = append(results, answer) } return results, nil } // test + func (r *ResultRepository) CheckResultsOwner(ctx context.Context, answersIDs []int64, accountID string) ([]uint64, error) { answerIDs, err := r.queries.CheckResultsOwner(ctx, sqlcgen.CheckResultsOwnerParams{ Column1: answersIDs, Accountid: accountID, }) if err != nil { return nil, err } var answers []uint64 for _, answerID := range answerIDs { answers = append(answers, uint64(answerID)) } return answers, nil } func (r *ResultRepository) SoftDeleteResultByID(ctx context.Context, answerID uint64) error { err := r.queries.SoftDeleteResultByID(ctx, int64(answerID)) if err != nil { return err } return nil } // test + func (r *ResultRepository) GetQuestions(ctx context.Context, quizID uint64) ([]model.Question, error) { rows, err := r.queries.GetQuestions(ctx, int64(quizID)) if err != nil { return nil, err } var questions []model.Question for _, row := range rows { question := model.Question{ Id: uint64(row.ID), QuizId: uint64(row.QuizID), Title: row.Title, Description: row.Description.String, Type: string(row.Questiontype.([]byte)), Required: row.Required.Bool, Deleted: row.Deleted.Bool, Page: int(row.Page.Int16), Content: row.Content.String, Version: int(row.Version.Int16), ParentIds: row.ParentIds, CreatedAt: row.CreatedAt.Time, UpdatedAt: row.UpdatedAt.Time, } questions = append(questions, question) } return questions, nil } // test + func (r *ResultRepository) GetResultAnswers(ctx context.Context, answerID uint64) ([]model.Answer, error) { rows, err := r.queries.GetResultAnswers(ctx, int64(answerID)) if err != nil { return nil, err } var answers []model.Answer for _, row := range rows { answer := model.Answer{ Id: uint64(row.ID), Content: row.Content.String, QuestionId: uint64(row.QuestionID), QuizId: uint64(row.QuizID), Fingerprint: row.Fingerprint.String, Session: row.Session.String, Result: row.Result.Bool, CreatedAt: row.CreatedAt.Time, New: row.New.Bool, Deleted: row.Deleted.Bool, } answers = append(answers, answer) } return answers, nil } // test + func (r *ResultRepository) CheckResultOwner(ctx context.Context, answerID uint64, accountID string) (bool, error) { ownerAccountID, err := r.queries.CheckResultOwner(ctx, int64(answerID)) if err != nil { return false, err } return ownerAccountID == accountID, nil }