Files
smart-search-back/internal/repository/request.go
vallyenfail 15f3703342 add service
2026-01-17 23:56:00 +03:00

217 lines
6.4 KiB
Go

package repository
import (
"context"
"encoding/json"
"errors"
"git.techease.ru/Smart-search/smart-search-back/internal/model"
errs "git.techease.ru/Smart-search/smart-search-back/pkg/errors"
sq "github.com/Masterminds/squirrel"
"github.com/google/uuid"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgxpool"
)
type requestRepository struct {
pool *pgxpool.Pool
qb sq.StatementBuilderType
}
func NewRequestRepository(pool *pgxpool.Pool) RequestRepository {
return &requestRepository{
pool: pool,
qb: sq.StatementBuilder.PlaceholderFormat(sq.Dollar),
}
}
func (r *requestRepository) Create(ctx context.Context, req *model.Request) error {
query := r.qb.Insert("requests_for_suppliers").Columns(
"user_id", "request_txt",
).Values(
req.UserID, req.RequestTxt,
).Suffix("RETURNING id, created_at")
sqlQuery, args, err := query.ToSql()
if err != nil {
return errs.NewInternalError(errs.DatabaseError, "failed to build query", err)
}
err = r.pool.QueryRow(ctx, sqlQuery, args...).Scan(&req.ID, &req.CreatedAt)
if err != nil {
return errs.NewInternalError(errs.DatabaseError, "failed to create request", err)
}
return nil
}
func (r *requestRepository) UpdateWithTZ(ctx context.Context, id uuid.UUID, tz string, generated bool) error {
return r.updateWithTZExecutor(ctx, r.pool, id, tz, generated)
}
func (r *requestRepository) UpdateWithTZTx(ctx context.Context, tx pgx.Tx, id uuid.UUID, tz string, generated bool) error {
return r.updateWithTZExecutor(ctx, tx, id, tz, generated)
}
func (r *requestRepository) updateWithTZExecutor(ctx context.Context, exec DBTX, id uuid.UUID, tz string, generated bool) error {
query := r.qb.Update("requests_for_suppliers").
Set("final_tz", tz).
Set("generated_tz", generated).
Set("generated_final_tz", generated).
Where(sq.Eq{"id": id})
sqlQuery, args, err := query.ToSql()
if err != nil {
return errs.NewInternalError(errs.DatabaseError, "failed to build query", err)
}
_, err = exec.Exec(ctx, sqlQuery, args...)
if err != nil {
return errs.NewInternalError(errs.DatabaseError, "failed to update request", err)
}
return nil
}
func (r *requestRepository) UpdateFinalTZ(ctx context.Context, id uuid.UUID, finalTZ string) error {
query := r.qb.Update("requests_for_suppliers").
Set("final_update_tz", finalTZ).
Where(sq.Eq{"id": id})
sqlQuery, args, err := query.ToSql()
if err != nil {
return errs.NewInternalError(errs.DatabaseError, "failed to build query", err)
}
_, err = r.pool.Exec(ctx, sqlQuery, args...)
if err != nil {
return errs.NewInternalError(errs.DatabaseError, "failed to update final TZ", err)
}
return nil
}
func (r *requestRepository) GetByUserID(ctx context.Context, userID int) ([]*model.Request, error) {
query := r.qb.Select(
"r.id", "r.request_txt", "ms.status_name as mailing_status",
).From("requests_for_suppliers r").
Join("mailling_status ms ON r.mailling_status_id = ms.id").
Where(sq.Eq{"r.user_id": userID}).
OrderBy("r.created_at DESC")
sqlQuery, args, err := query.ToSql()
if err != nil {
return nil, errs.NewInternalError(errs.DatabaseError, "failed to build query", err)
}
rows, err := r.pool.Query(ctx, sqlQuery, args...)
if err != nil {
return nil, errs.NewInternalError(errs.DatabaseError, "failed to get requests", err)
}
defer rows.Close()
var requests []*model.Request
for rows.Next() {
req := &model.Request{}
var statusName string
err := rows.Scan(&req.ID, &req.RequestTxt, &statusName)
if err != nil {
return nil, errs.NewInternalError(errs.DatabaseError, "failed to scan request", err)
}
requests = append(requests, req)
}
return requests, nil
}
func (r *requestRepository) GetByID(ctx context.Context, id uuid.UUID) (*model.Request, error) {
query := r.qb.Select(
"id", "user_id", "request_txt", "generated_tz", "final_tz",
"generated_final_tz", "final_update_tz", "mailling_status_id", "created_at",
).From("requests_for_suppliers").Where(sq.Eq{"id": id})
sqlQuery, args, err := query.ToSql()
if err != nil {
return nil, errs.NewInternalError(errs.DatabaseError, "failed to build query", err)
}
req := &model.Request{}
err = r.pool.QueryRow(ctx, sqlQuery, args...).Scan(
&req.ID, &req.UserID, &req.RequestTxt, &req.GeneratedTZ,
&req.FinalTZ, &req.GeneratedFinalTZ, &req.FinalUpdateTZ,
&req.MailingStatusID, &req.CreatedAt,
)
if errors.Is(err, pgx.ErrNoRows) {
return nil, errs.NewBusinessError(errs.RequestNotFound, "request not found")
}
if err != nil {
return nil, errs.NewInternalError(errs.DatabaseError, "failed to get request", err)
}
return req, nil
}
func (r *requestRepository) GetDetailByID(ctx context.Context, id uuid.UUID) (*model.RequestDetail, error) {
sqlQuery := `
SELECT
r.id AS request_id,
r.request_txt AS title,
r.final_update_tz AS mail_text,
COALESCE(json_agg(
json_build_object(
'email', COALESCE(s.email, ''),
'phone', COALESCE(s.phone, ''),
'company_name', COALESCE(s.name, ''),
'company_id', s.id,
'url', COALESCE(s.url, '')
)
) FILTER (WHERE s.id IS NOT NULL), '[]') AS suppliers
FROM requests_for_suppliers r
LEFT JOIN suppliers s ON s.request_id = r.id
WHERE r.id = $1
GROUP BY r.id, r.request_txt, r.final_update_tz
`
detail := &model.RequestDetail{}
var suppliersJSON []byte
err := r.pool.QueryRow(ctx, sqlQuery, id).Scan(
&detail.RequestID, &detail.Title, &detail.MailText, &suppliersJSON,
)
if err == pgx.ErrNoRows {
return nil, errs.NewBusinessError(errs.RequestNotFound, "request not found")
}
if err != nil {
return nil, errs.NewInternalError(errs.DatabaseError, "failed to get request detail", err)
}
if len(suppliersJSON) > 0 && string(suppliersJSON) != "[]" {
if err := json.Unmarshal(suppliersJSON, &detail.Suppliers); err != nil {
return nil, errs.NewInternalError(errs.DatabaseError, "failed to parse suppliers", err)
}
}
return detail, nil
}
func (r *requestRepository) GetUserStatistics(ctx context.Context, userID int) (requestsCount, suppliersCount, createdTZ int, err error) {
sqlQuery := `
SELECT
COUNT(DISTINCT r.id) AS requests_count,
COUNT(s.id) AS suppliers_count,
COUNT(r.request_txt) AS created_tz
FROM requests_for_suppliers r
LEFT JOIN suppliers s ON s.request_id = r.id
WHERE r.user_id = $1
`
err = r.pool.QueryRow(ctx, sqlQuery, userID).Scan(&requestsCount, &suppliersCount, &createdTZ)
if err != nil {
return 0, 0, 0, errs.NewInternalError(errs.DatabaseError, "failed to get statistics", err)
}
return requestsCount, suppliersCount, createdTZ, nil
}