all repos

onasty @ 943fcdb

a one-time notes service

onasty/internal/store/psql/noterepo/noterepo.go (view raw)

Smirnov Oleksandr Smirnov Oleksandr
ss2316544@gmail.com
refactor: make NoteSlugDTO type as string alias (#19), 1 year ago
1
package noterepo
2
3
import (
4
	"context"
5
	"errors"
6
7
	"github.com/gofrs/uuid/v5"
8
	"github.com/henvic/pgq"
9
	"github.com/jackc/pgx/v5"
10
	"github.com/olexsmir/onasty/internal/dtos"
11
	"github.com/olexsmir/onasty/internal/models"
12
	"github.com/olexsmir/onasty/internal/store/psqlutil"
13
)
14
15
type NoteStorer interface {
16
	Create(ctx context.Context, inp dtos.CreateNoteDTO) error
17
	GetBySlug(ctx context.Context, slug dtos.NoteSlugDTO) (dtos.NoteDTO, error)
18
	DeleteBySlug(ctx context.Context, slug dtos.NoteSlugDTO) error
19
20
	SetAuthorIDBySlug(ctx context.Context, slug dtos.NoteSlugDTO, authorID uuid.UUID) error
21
}
22
23
var _ NoteStorer = (*NoteRepo)(nil)
24
25
type NoteRepo struct {
26
	db *psqlutil.DB
27
}
28
29
func New(db *psqlutil.DB) *NoteRepo {
30
	return &NoteRepo{db}
31
}
32
33
func (s *NoteRepo) Create(ctx context.Context, inp dtos.CreateNoteDTO) error {
34
	query, args, err := pgq.
35
		Insert("notes").
36
		Columns("content", "slug", "burn_before_expiration ", "created_at", "expires_at").
37
		Values(inp.Content, inp.Slug, inp.BurnBeforeExpiration, inp.CreatedAt, inp.ExpiresAt).
38
		SQL()
39
	if err != nil {
40
		return err
41
	}
42
43
	_, err = s.db.Exec(ctx, query, args...)
44
	if psqlutil.IsDuplicateErr(err) {
45
		return models.ErrNoteSlugIsAlreadyInUse
46
	}
47
48
	return err
49
}
50
51
func (s *NoteRepo) GetBySlug(ctx context.Context, slug dtos.NoteSlugDTO) (dtos.NoteDTO, error) {
52
	query, args, err := pgq.
53
		Select("content", "slug", "burn_before_expiration", "created_at", "expires_at").
54
		From("notes").
55
		Where("slug = ?", slug).
56
		SQL()
57
	if err != nil {
58
		return dtos.NoteDTO{}, err
59
	}
60
61
	var note dtos.NoteDTO
62
	err = s.db.QueryRow(ctx, query, args...).
63
		Scan(&note.Content, &note.Slug, &note.BurnBeforeExpiration, &note.CreatedAt, &note.ExpiresAt)
64
65
	if errors.Is(err, pgx.ErrNoRows) {
66
		return dtos.NoteDTO{}, models.ErrNoteNotFound
67
	}
68
69
	return note, err
70
}
71
72
func (s *NoteRepo) DeleteBySlug(ctx context.Context, slug dtos.NoteSlugDTO) error {
73
	query, args, err := pgq.
74
		Delete("notes").
75
		Where(pgq.Eq{"slug": slug}).
76
		SQL()
77
	if err != nil {
78
		return err
79
	}
80
81
	_, err = s.db.Exec(ctx, query, args...)
82
	if errors.Is(err, pgx.ErrNoRows) {
83
		return models.ErrNoteNotFound
84
	}
85
86
	return err
87
}
88
89
func (s *NoteRepo) SetAuthorIDBySlug(
90
	ctx context.Context,
91
	slug dtos.NoteSlugDTO,
92
	authorID uuid.UUID,
93
) error {
94
	tx, err := s.db.Begin(ctx)
95
	if err != nil {
96
		return err
97
	}
98
	defer tx.Rollback(ctx) //nolint:errcheck
99
100
	var noteID uuid.UUID
101
	err = tx.QueryRow(ctx, "select id from notes where slug = $1", slug).Scan(&noteID)
102
	if err != nil {
103
		if errors.Is(err, pgx.ErrNoRows) {
104
			return models.ErrNoteNotFound
105
		}
106
		return err
107
	}
108
109
	_, err = tx.Exec(
110
		ctx,
111
		"insert into notes_authors (note_id, user_id) values ($1, $2)",
112
		noteID, authorID,
113
	)
114
	if err != nil {
115
		return err
116
	}
117
118
	return tx.Commit(ctx)
119
}