Yimaru-BackEnd/internal/repository/notification.go

194 lines
4.0 KiB
Go

package repository
import (
"context"
"encoding/json"
"strconv"
dbgen "Yimaru-Backend/gen/db"
"Yimaru-Backend/internal/domain"
"Yimaru-Backend/internal/ports"
"github.com/jackc/pgx/v5/pgtype"
)
func NewNotificationStore(s *Store) ports.NotificationStore {
return s
}
/* =========================
Create
========================= */
func (r *Store) CreateNotification(
ctx context.Context,
n *domain.Notification,
) (*domain.Notification, error) {
params := dbgen.CreateNotificationParams{
UserID: n.RecipientID,
Type: string(n.Type),
Level: string(n.Level),
Channel: pgtype.Text{String: string(n.DeliveryChannel)},
Title: n.Payload.Headline,
Message: n.Payload.Message,
Payload: marshalPayload(n.Payload),
}
dbNotif, err := r.queries.CreateNotification(ctx, params)
if err != nil {
return nil, err
}
return mapDBToDomain(&dbNotif), nil
}
/* =========================
Read
========================= */
func (r *Store) GetUserNotifications(
ctx context.Context,
userID int64,
limit, offset int,
) ([]domain.Notification, int64, error) {
params := dbgen.GetUserNotificationsParams{
UserID: userID,
Limit: int32(limit),
Offset: int32(offset),
}
rows, err := r.queries.GetUserNotifications(ctx, params)
if err != nil {
return nil, 0, err
}
total, err := r.queries.GetUserNotificationCount(ctx, userID)
if err != nil {
return nil, 0, err
}
result := make([]domain.Notification, 0, len(rows))
for _, row := range rows {
result = append(result, *mapDBToDomain(&row))
}
return result, total, nil
}
func (r *Store) GetAllNotifications(
ctx context.Context,
limit, offset int,
) ([]domain.Notification, error) {
rows, err := r.queries.GetAllNotifications(ctx, dbgen.GetAllNotificationsParams{
Limit: int32(limit),
Offset: int32(offset),
})
if err != nil {
return nil, err
}
result := make([]domain.Notification, 0, len(rows))
for _, row := range rows {
result = append(result, *mapDBToDomain(&row))
}
return result, nil
}
func (r *Store) CountUnreadNotifications(
ctx context.Context,
userID int64,
) (int64, error) {
return r.queries.CountUnreadNotifications(ctx, userID)
}
/* =========================
Update
========================= */
func (r *Store) MarkNotificationAsRead(
ctx context.Context,
id int64,
) (*domain.Notification, error) {
dbNotif, err := r.queries.MarkNotificationAsRead(ctx, id)
if err != nil {
return nil, err
}
return mapDBToDomain(&dbNotif), nil
}
func (r *Store) MarkAllUserNotificationsAsRead(
ctx context.Context,
userID int64,
) error {
return r.queries.MarkAllUserNotificationsAsRead(ctx, userID)
}
/* =========================
Delete
========================= */
func (r *Store) DeleteUserNotifications(
ctx context.Context,
userID int64,
) error {
return r.queries.DeleteUserNotifications(ctx, userID)
}
/* =========================
Mapping
========================= */
func mapDBToDomain(db *dbgen.Notification) *domain.Notification {
payload, err := unmarshalPayload(db.Payload)
if err != nil {
payload = domain.NotificationPayload{}
}
var channel domain.DeliveryChannel
if db.Channel.Valid {
channel = domain.DeliveryChannel(db.Channel.String)
}
return &domain.Notification{
ID: strconv.FormatInt(db.ID, 10),
RecipientID: db.UserID,
Type: domain.NotificationType(db.Type),
Level: domain.NotificationLevel(db.Level),
DeliveryChannel: channel,
DeliveryStatus: "PENDING",
Payload: domain.NotificationPayload{
Headline: payload.Headline,
Message: payload.Message,
},
IsRead: db.IsRead,
Timestamp: db.CreatedAt.Time,
// ReadAt: db.ReadAt.Time,
}
}
/* =========================
JSON Helpers
========================= */
func marshalPayload(p domain.NotificationPayload) []byte {
b, _ := json.Marshal(p)
return b
}
func unmarshalPayload(b []byte) (domain.NotificationPayload, error) {
var p domain.NotificationPayload
if len(b) == 0 {
return p, nil
}
if err := json.Unmarshal(b, &p); err != nil {
return p, err
}
return p, nil
}