Passed
Push — main ( 570b65...2ff189 )
by Acho
02:48
created

User   A

Complexity

Conditions 2

Size

Total Lines 10
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 7
dl 0
loc 10
rs 10
c 0
b 0
f 0
nop 2
1
package repositories
2
3
import (
4
	"context"
5
	"fmt"
6
	"time"
7
8
	"github.com/google/uuid"
9
10
	"github.com/pkg/errors"
11
12
	"github.com/NdoleStudio/httpsms/pkg/entities"
13
	"github.com/NdoleStudio/httpsms/pkg/telemetry"
14
	"github.com/palantir/stacktrace"
15
	"gorm.io/gorm"
16
)
17
18
// gormHeartbeatRepository is responsible for persisting entities.Heartbeat
19
type gormHeartbeatMonitorRepository struct {
20
	logger telemetry.Logger
21
	tracer telemetry.Tracer
22
	db     *gorm.DB
23
}
24
25
func (repository *gormHeartbeatMonitorRepository) DeleteAllForUser(ctx context.Context, userID entities.UserID) error {
26
	ctx, span := repository.tracer.Start(ctx)
27
	defer span.End()
28
29
	if err := repository.db.WithContext(ctx).Where("user_id = ?", userID).Delete(&entities.HeartbeatMonitor{}).Error; err != nil {
30
		msg := fmt.Sprintf("cannot delete all [%T] for user with ID [%s]", &entities.HeartbeatMonitor{}, userID)
31
		return repository.tracer.WrapErrorSpan(span, stacktrace.Propagate(err, msg))
32
	}
33
34
	return nil
35
}
36
37
// UpdatePhoneOnline updates the online status of a phone
38
func (repository *gormHeartbeatMonitorRepository) UpdatePhoneOnline(ctx context.Context, userID entities.UserID, monitorID uuid.UUID, isOnline bool) error {
39
	ctx, span := repository.tracer.Start(ctx)
40
	defer span.End()
41
42
	ctx, cancel := context.WithTimeout(ctx, dbOperationDuration)
43
	defer cancel()
44
45
	err := repository.db.
46
		Model(&entities.HeartbeatMonitor{}).
47
		Where("id = ?", monitorID).
48
		Where("user_id = ?", userID).
49
		Updates(map[string]any{
50
			"phone_online": isOnline,
51
			"updated_at":   time.Now().UTC(),
52
		}).Error
53
	if err != nil {
54
		msg := fmt.Sprintf("cannot update heartbeat monitor ID [%s] for user [%s]", monitorID, userID)
55
		return repository.tracer.WrapErrorSpan(span, stacktrace.Propagate(err, msg))
56
	}
57
	return nil
58
}
59
60
// UpdateQueueID updates the queueID of a monitor
61
func (repository *gormHeartbeatMonitorRepository) UpdateQueueID(ctx context.Context, monitorID uuid.UUID, queueID string) error {
62
	ctx, span := repository.tracer.Start(ctx)
63
	defer span.End()
64
65
	ctx, cancel := context.WithTimeout(ctx, dbOperationDuration)
66
	defer cancel()
67
68
	err := repository.db.
69
		Model(&entities.HeartbeatMonitor{}).
70
		Where("id = ?", monitorID).
71
		Updates(map[string]any{
72
			"queue_id":   queueID,
73
			"updated_at": time.Now().UTC(),
74
		}).Error
75
	if err != nil {
76
		msg := fmt.Sprintf("cannot update heartbeat monitor ID [%s]", monitorID)
77
		return repository.tracer.WrapErrorSpan(span, stacktrace.Propagate(err, msg))
78
	}
79
	return nil
80
}
81
82
func (repository *gormHeartbeatMonitorRepository) Delete(ctx context.Context, userID entities.UserID, owner string) error {
83
	ctx, span := repository.tracer.Start(ctx)
84
	defer span.End()
85
86
	ctx, cancel := context.WithTimeout(ctx, dbOperationDuration)
87
	defer cancel()
88
89
	err := repository.db.WithContext(ctx).
90
		Where("user_id = ?", userID).
91
		Where("owner = ?", owner).
92
		Delete(&entities.HeartbeatMonitor{}).Error
93
	if err != nil {
94
		msg := fmt.Sprintf("cannot delete heartbeat monitor with owner [%s] and userID [%s]", owner, userID)
95
		return repository.tracer.WrapErrorSpan(span, stacktrace.Propagate(err, msg))
96
	}
97
98
	return nil
99
}
100
101
// NewGormHeartbeatMonitorRepository creates the GORM version of the HeartbeatMonitorRepository
102
func NewGormHeartbeatMonitorRepository(
103
	logger telemetry.Logger,
104
	tracer telemetry.Tracer,
105
	db *gorm.DB,
106
) HeartbeatMonitorRepository {
107
	return &gormHeartbeatMonitorRepository{
108
		logger: logger.WithService(fmt.Sprintf("%T", &gormHeartbeatRepository{})),
109
		tracer: tracer,
110
		db:     db,
111
	}
112
}
113
114
// Index entities.Message between 2 parties
115
func (repository *gormHeartbeatMonitorRepository) Index(ctx context.Context, userID entities.UserID, owner string, params IndexParams) (*[]entities.Heartbeat, error) {
116
	ctx, span := repository.tracer.Start(ctx)
117
	defer span.End()
118
119
	ctx, cancel := context.WithTimeout(ctx, dbOperationDuration)
120
	defer cancel()
121
122
	query := repository.db.WithContext(ctx).Where("user_id = ?", userID).Where("owner = ?", owner)
123
	heartbeats := new([]entities.Heartbeat)
124
	if err := query.Order("timestamp DESC").Limit(params.Limit).Offset(params.Skip).Find(&heartbeats).Error; err != nil {
125
		msg := fmt.Sprintf("cannot fetch heartbeats with owner [%s] and params [%+#v]", owner, params)
126
		return nil, repository.tracer.WrapErrorSpan(span, stacktrace.Propagate(err, msg))
127
	}
128
129
	return heartbeats, nil
130
}
131
132
// Store a new heartbeat monitor
133
func (repository *gormHeartbeatMonitorRepository) Store(ctx context.Context, heartbeatMonitor *entities.HeartbeatMonitor) error {
134
	ctx, span := repository.tracer.Start(ctx)
135
	defer span.End()
136
137
	ctx, cancel := context.WithTimeout(ctx, dbOperationDuration)
138
	defer cancel()
139
140
	if err := repository.db.WithContext(ctx).Create(heartbeatMonitor).Error; err != nil {
141
		msg := fmt.Sprintf("cannot save heartbeatMonitor monitor with ID [%s]", heartbeatMonitor.ID)
142
		return repository.tracer.WrapErrorSpan(span, stacktrace.Propagate(err, msg))
143
	}
144
145
	return nil
146
}
147
148
// Load a heartbeat monitor by userID and owner
149
func (repository *gormHeartbeatMonitorRepository) Load(ctx context.Context, userID entities.UserID, owner string) (*entities.HeartbeatMonitor, error) {
150
	ctx, span := repository.tracer.Start(ctx)
151
	defer span.End()
152
153
	ctx, cancel := context.WithTimeout(ctx, dbOperationDuration)
154
	defer cancel()
155
156
	phone := new(entities.HeartbeatMonitor)
157
	err := repository.db.WithContext(ctx).
158
		Where("user_id = ?", userID).
159
		Where("owner = ?", owner).
160
		First(&phone).Error
161
162
	if errors.Is(err, gorm.ErrRecordNotFound) {
163
		msg := fmt.Sprintf("heartbeat monitor with userID [%s] and owner [%s] does not exist", userID, owner)
164
		return nil, repository.tracer.WrapErrorSpan(span, stacktrace.PropagateWithCode(err, ErrCodeNotFound, msg))
165
	}
166
167
	if err != nil {
168
		msg := fmt.Sprintf("cannot load heartbeat monitor with userID [%s] and owner [%s]", userID, owner)
169
		return nil, repository.tracer.WrapErrorSpan(span, stacktrace.Propagate(err, msg))
170
	}
171
172
	return phone, nil
173
}
174
175
// Exists checks of a heartbeat monitor exists for the userID and owner
176
func (repository *gormHeartbeatMonitorRepository) Exists(ctx context.Context, userID entities.UserID, monitorID uuid.UUID) (bool, error) {
177
	ctx, span := repository.tracer.Start(ctx)
178
	defer span.End()
179
180
	ctx, cancel := context.WithTimeout(ctx, dbOperationDuration)
181
	defer cancel()
182
183
	var exists bool
184
	err := repository.db.WithContext(ctx).
185
		Model(&entities.HeartbeatMonitor{}).
186
		Select("count(*) > 0").
187
		Where("user_id = ?", userID).
188
		Where("id = ?", monitorID).
189
		Find(&exists).Error
190
	if err != nil {
191
		msg := fmt.Sprintf("cannot check if heartbeat monitor exists with userID [%s] and montiorID [%s]", userID, monitorID)
192
		return exists, repository.tracer.WrapErrorSpan(span, stacktrace.Propagate(err, msg))
193
	}
194
195
	return exists, nil
196
}
197