common/repository/result/result.go
2024-02-19 19:33:15 +03:00

260 lines
6.8 KiB
Go

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
}