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 }