added proper types to structs, return empty arrays instead of null

This commit is contained in:
slawk0
2025-02-07 23:29:03 +01:00
parent 7342c5b483
commit 68873dc44c
4 changed files with 46 additions and 44 deletions

View File

@@ -94,7 +94,7 @@ func InsertContact(db *sql.DB, userID uuid.UUID, contactID uuid.UUID, contactUse
`, userID).Scan(&conversationID) `, userID).Scan(&conversationID)
if err != nil && !errors.Is(err, sql.ErrNoRows) { if err != nil && !errors.Is(err, sql.ErrNoRows) {
return nil, helpers.NewError(helpers.ErrInternal, "internal server error", fmt.Errorf("failed to check existing conversation: %w", err)) return &model.Contact{}, helpers.NewError(helpers.ErrInternal, "internal server error", fmt.Errorf("failed to check existing conversation: %w", err))
} }
if conversationID == uuid.Nil { if conversationID == uuid.Nil {
@@ -104,7 +104,7 @@ func InsertContact(db *sql.DB, userID uuid.UUID, contactID uuid.UUID, contactUse
RETURNING conversation_id; RETURNING conversation_id;
`).Scan(&conversationID) `).Scan(&conversationID)
if err != nil { if err != nil {
return nil, helpers.NewError(helpers.ErrInternal, "internal server error", fmt.Errorf("failed to create conversation: %w", err)) return &model.Contact{}, helpers.NewError(helpers.ErrInternal, "internal server error", fmt.Errorf("failed to create conversation: %w", err))
} }
_, err = db.Exec(` _, err = db.Exec(`
@@ -113,7 +113,7 @@ func InsertContact(db *sql.DB, userID uuid.UUID, contactID uuid.UUID, contactUse
ON CONFLICT (conversation_id, user_id) DO NOTHING; ON CONFLICT (conversation_id, user_id) DO NOTHING;
`, conversationID, userID) `, conversationID, userID)
if err != nil { if err != nil {
return nil, helpers.NewError(helpers.ErrInternal, "internal server error", fmt.Errorf("failed to create membership: %w", err)) return &model.Contact{}, helpers.NewError(helpers.ErrInternal, "internal server error", fmt.Errorf("failed to create membership: %w", err))
} }
} }
} else { } else {
@@ -128,7 +128,7 @@ func InsertContact(db *sql.DB, userID uuid.UUID, contactID uuid.UUID, contactUse
`, userID, contactID).Scan(&conversationID) `, userID, contactID).Scan(&conversationID)
if err != nil && !errors.Is(err, sql.ErrNoRows) { if err != nil && !errors.Is(err, sql.ErrNoRows) {
return nil, helpers.NewError(helpers.ErrInternal, "internal server error", fmt.Errorf("failed to check existing conversation %w", err)) return &model.Contact{}, helpers.NewError(helpers.ErrInternal, "internal server error", fmt.Errorf("failed to check existing conversation %w", err))
} }
if conversationID == uuid.Nil { if conversationID == uuid.Nil {
@@ -138,7 +138,7 @@ func InsertContact(db *sql.DB, userID uuid.UUID, contactID uuid.UUID, contactUse
RETURNING conversation_id; RETURNING conversation_id;
`).Scan(&conversationID) `).Scan(&conversationID)
if err != nil { if err != nil {
return nil, helpers.NewError(helpers.ErrInternal, "internal server error", fmt.Errorf("failed to create conversation: %w", err)) return &model.Contact{}, helpers.NewError(helpers.ErrInternal, "internal server error", fmt.Errorf("failed to create conversation: %w", err))
} }
_, err = db.Exec(` _, err = db.Exec(`
@@ -147,19 +147,19 @@ func InsertContact(db *sql.DB, userID uuid.UUID, contactID uuid.UUID, contactUse
ON CONFLICT (conversation_id, user_id) DO NOTHING; ON CONFLICT (conversation_id, user_id) DO NOTHING;
`, conversationID, userID, contactID) `, conversationID, userID, contactID)
if err != nil { if err != nil {
return nil, helpers.NewError(helpers.ErrInternal, "internal server error", fmt.Errorf("failed to create memberships: %w", err)) return &model.Contact{}, helpers.NewError(helpers.ErrInternal, "internal server error", fmt.Errorf("failed to create memberships: %w", err))
} }
} }
} }
insertedContact, err := InsertContactByID(db, contactID, conversationID) insertedContact, err := InsertContactByID(db, contactID, conversationID)
if err != nil { if err != nil {
return nil, err return &model.Contact{}, err
} }
latestMessage, err := GetLatestMessage(db, conversationID) latestMessage, err := GetLatestMessage(db, conversationID)
if err != nil { if err != nil {
return nil, err return &model.Contact{}, err
} }
contact := model.Contact{ contact := model.Contact{
@@ -186,9 +186,9 @@ func InsertContactByID(db *sql.DB, userID uuid.UUID, conversationID uuid.UUID) (
`, userID, conversationID).Scan(&contact.ID, &contact.ConversationID, &contact.UserID) `, userID, conversationID).Scan(&contact.ID, &contact.ConversationID, &contact.UserID)
if err == nil { if err == nil {
return nil, helpers.NewError(helpers.ErrInvalidInput, "Contact already exists", nil) return &model.Contact{}, helpers.NewError(helpers.ErrInvalidInput, "Contact already exists", nil)
} else if !errors.Is(err, sql.ErrNoRows) { } else if !errors.Is(err, sql.ErrNoRows) {
return nil, helpers.NewError(helpers.ErrInternal, "internal server error", fmt.Errorf("failed to check contact existence: %w", err)) return &model.Contact{}, helpers.NewError(helpers.ErrInternal, "internal server error", fmt.Errorf("failed to check contact existence: %w", err))
} }
// Insert new contact // Insert new contact
@@ -199,7 +199,7 @@ func InsertContactByID(db *sql.DB, userID uuid.UUID, conversationID uuid.UUID) (
`, userID, conversationID).Scan(&contact.ID, &contact.ConversationID, &contact.UserID) `, userID, conversationID).Scan(&contact.ID, &contact.ConversationID, &contact.UserID)
if err != nil { if err != nil {
return nil, helpers.NewError(helpers.ErrInternal, "Failed to create contact", err) return &model.Contact{}, helpers.NewError(helpers.ErrInternal, "Failed to create contact", err)
} }
return &contact, nil return &contact, nil
@@ -228,9 +228,9 @@ func GetLatestMessage(db *sql.DB, conversationId uuid.UUID) (*model.Contact, err
if err != nil { if err != nil {
if errors.Is(err, sql.ErrNoRows) { if errors.Is(err, sql.ErrNoRows) {
return &model.Contact{}, nil // Return empty contact if no messages return &model.Contact{}, nil
} }
return nil, helpers.NewError(helpers.ErrInternal, "Failed to get latest message", err) return &model.Contact{}, helpers.NewError(helpers.ErrInternal, "Failed to get latest message", fmt.Errorf("failed to get latest message: %w", err))
} }
return &latestMessage, nil return &latestMessage, nil
@@ -287,21 +287,20 @@ func GetContacts(db *sql.DB, userID uuid.UUID) ([]*model.Contact, error) {
rows, err := db.Query(contactsQuery, userID) rows, err := db.Query(contactsQuery, userID)
if err != nil { if err != nil {
return nil, helpers.NewError(helpers.ErrInternal, "Failed to get contacts", err) return []*model.Contact{}, helpers.NewError(helpers.ErrInternal, "Failed to get contacts", fmt.Errorf("failed to get contacts: %w", err))
} }
var contacts []*model.Contact var contacts []*model.Contact
for rows.Next() { for rows.Next() {
contact := &model.Contact{} contact := &model.Contact{}
err := rows.Scan(&contact.ID, &contact.UserID, &contact.Username, err := rows.Scan(&contact.ID, &contact.UserID, &contact.Username, &contact.LastActive, &contact.ConversationID, &contact.Type, &contact.LastReadMessageID)
&contact.ConversationID, &contact.Type)
if err != nil { if err != nil {
return nil, helpers.NewError(helpers.ErrInternal, "internal server error", err) return []*model.Contact{}, helpers.NewError(helpers.ErrInternal, "internal server error", fmt.Errorf("failed to scan contact: %w", err))
} }
latestMessage, err := GetLatestMessage(db, contact.ConversationID) latestMessage, err := GetLatestMessage(db, contact.ConversationID)
if err != nil { if err != nil {
return nil, err return []*model.Contact{}, err
} }
contact.LastMessageID = latestMessage.LastMessageID contact.LastMessageID = latestMessage.LastMessageID
@@ -313,7 +312,7 @@ func GetContacts(db *sql.DB, userID uuid.UUID) ([]*model.Contact, error) {
} }
if err = rows.Err(); err != nil { if err = rows.Err(); err != nil {
return nil, helpers.NewError(helpers.ErrInternal, "internal server error", fmt.Errorf("failed to process contacts: %w", err)) return []*model.Contact{}, helpers.NewError(helpers.ErrInternal, "internal server error", fmt.Errorf("failed to process contacts: %w", err))
} }
return contacts, nil return contacts, nil
@@ -329,7 +328,7 @@ func ContactSuggestion(db *sql.DB, contactUsername string) ([]string, error) {
rows, err := db.Query(query, "%"+strings.ToLower(contactUsername)+"%") rows, err := db.Query(query, "%"+strings.ToLower(contactUsername)+"%")
if err != nil && !errors.Is(err, sql.ErrNoRows) { if err != nil && !errors.Is(err, sql.ErrNoRows) {
return nil, helpers.NewError(helpers.ErrInternal, "Failed to get contact suggestions", err) return []string{}, helpers.NewError(helpers.ErrInternal, "Failed to get contact suggestions", fmt.Errorf("failed to get contact suggestions: %w", err))
} }
var suggestions []string var suggestions []string
@@ -337,12 +336,12 @@ func ContactSuggestion(db *sql.DB, contactUsername string) ([]string, error) {
var suggestion string var suggestion string
err := rows.Scan(&suggestion) err := rows.Scan(&suggestion)
if err != nil { if err != nil {
return nil, helpers.NewError(helpers.ErrInternal, "internal server error", err) return []string{}, helpers.NewError(helpers.ErrInternal, "internal server error", fmt.Errorf("failed to scan contact suggestion: %w", err))
} }
suggestions = append(suggestions, suggestion) suggestions = append(suggestions, suggestion)
} }
if err = rows.Err(); err != nil { if err = rows.Err(); err != nil {
return nil, helpers.NewError(helpers.ErrInternal, "internal server error", fmt.Errorf("failed to process suggestions")) return []string{}, helpers.NewError(helpers.ErrInternal, "internal server error", fmt.Errorf("failed to process suggestions: %w", err))
} }
return suggestions, nil return suggestions, nil
} }

View File

@@ -11,7 +11,7 @@ import (
func GetMessages(db *sql.DB, userID uuid.UUID, conversationID uuid.UUID, limit int, cursor int) ([]*model.Message, error) { func GetMessages(db *sql.DB, userID uuid.UUID, conversationID uuid.UUID, limit int, cursor int) ([]*model.Message, error) {
_, err := checkMembership(db, userID, conversationID) _, err := checkMembership(db, userID, conversationID)
if err != nil { if err != nil {
return nil, err return []*model.Message{}, err
} }
var query string var query string
var messages []*model.Message var messages []*model.Message
@@ -33,19 +33,19 @@ func GetMessages(db *sql.DB, userID uuid.UUID, conversationID uuid.UUID, limit i
` `
rows, err := db.Query(query, conversationID, cursor, limit) rows, err := db.Query(query, conversationID, cursor, limit)
if err != nil { if err != nil {
return nil, helpers.NewError(helpers.ErrInternal, "Failed to get messages", fmt.Errorf("failed to get messages: %w", err)) return []*model.Message{}, helpers.NewError(helpers.ErrInternal, "Failed to get messages", fmt.Errorf("failed to get messages: %w", err))
} }
for rows.Next() { for rows.Next() {
message := &model.Message{} message := &model.Message{}
err = rows.Scan(&message.MessageID, &message.Message, &message.SentAt, &message.AttachmentUrl, &message.Sender) err = rows.Scan(&message.MessageID, &message.Message, &message.SentAt, &message.AttachmentUrl, &message.Sender)
if err != nil { if err != nil {
return nil, helpers.NewError(helpers.ErrInternal, "Failed to get messages", fmt.Errorf("failed to scan message: %w", err)) return []*model.Message{}, helpers.NewError(helpers.ErrInternal, "Failed to get messages", fmt.Errorf("failed to scan message: %w", err))
} }
messages = append(messages, message) messages = append(messages, message)
} }
if err = rows.Err(); err != nil { if err = rows.Err(); err != nil {
return nil, helpers.NewError(helpers.ErrInternal, "internal server error", fmt.Errorf("failed to process messages: %w", err)) return []*model.Message{}, helpers.NewError(helpers.ErrInternal, "internal server error", fmt.Errorf("failed to process messages: %w", err))
} }
} else { } else {
@@ -64,19 +64,19 @@ func GetMessages(db *sql.DB, userID uuid.UUID, conversationID uuid.UUID, limit i
` `
rows, err := db.Query(query, conversationID, cursor, limit) rows, err := db.Query(query, conversationID, cursor, limit)
if err != nil { if err != nil {
return nil, helpers.NewError(helpers.ErrInternal, "Failed to get messages", fmt.Errorf("failed to get messages: %w", err)) return []*model.Message{}, helpers.NewError(helpers.ErrInternal, "Failed to get messages", fmt.Errorf("failed to get messages: %w", err))
} }
for rows.Next() { for rows.Next() {
message := &model.Message{} message := &model.Message{}
err = rows.Scan(&message.MessageID, &message.Message, &message.SentAt, &message.AttachmentUrl, &message.Sender) err = rows.Scan(&message.MessageID, &message.Message, &message.SentAt, &message.AttachmentUrl, &message.Sender)
if err != nil { if err != nil {
return nil, helpers.NewError(helpers.ErrInternal, "Failed to get messages", fmt.Errorf("failed to scan message: %w", err)) return []*model.Message{}, helpers.NewError(helpers.ErrInternal, "Failed to get messages", fmt.Errorf("failed to scan message: %w", err))
} }
messages = append(messages, message) messages = append(messages, message)
} }
if err = rows.Err(); err != nil { if err = rows.Err(); err != nil {
return nil, helpers.NewError(helpers.ErrInternal, "internal server error", fmt.Errorf("failed to process messages: %w", err)) return []*model.Message{}, helpers.NewError(helpers.ErrInternal, "internal server error", fmt.Errorf("failed to process messages: %w", err))
} }
} }
if cursor != 0 { if cursor != 0 {

View File

@@ -3,6 +3,7 @@ package model
import ( import (
"github.com/golang-jwt/jwt/v5" "github.com/golang-jwt/jwt/v5"
"github.com/google/uuid" "github.com/google/uuid"
"time"
) )
type UserClaims struct { type UserClaims struct {
@@ -11,15 +12,17 @@ type UserClaims struct {
jwt.RegisteredClaims jwt.RegisteredClaims
} }
type Contact struct { type Contact struct {
ID int `json:"contact_id"` ID int `json:"contact_id"`
ConversationID uuid.UUID `json:"conversation_id"` ConversationID uuid.UUID `json:"conversation_id"`
UserID uuid.UUID `json:"user_id"` UserID uuid.UUID `json:"user_id"`
Username string `json:"username"` Username string `json:"username"`
Type string `json:"type"` LastActive *time.Time `json:"last_active"`
LastMessageID int `json:"last_message_id"` Type string `json:"type"`
LastMessage string `json:"last_message"` LastReadMessageID *int `json:"last_read_message_id"`
LastMessageTime string `json:"last_message_time"` LastMessageID *int `json:"last_message_id"`
LastMessageSender string `json:"last_message_sender"` LastMessage *time.Time `json:"last_message"`
LastMessageTime *string `json:"last_message_time"`
LastMessageSender *string `json:"last_message_sender"`
} }
type ContactSuggestion struct { type ContactSuggestion struct {
@@ -27,9 +30,9 @@ type ContactSuggestion struct {
} }
type Message struct { type Message struct {
MessageID int `json:"message_id"` MessageID int `json:"message_id"`
Message string `json:"message"` Message string `json:"message"`
SentAt string `json:"sent_at"` SentAt time.Time `json:"sent_at"`
Sender string `json:"sender"` Sender string `json:"sender"`
AttachmentUrl string `json:"attachment_url"` AttachmentUrl *string `json:"attachment_url"`
} }

View File

@@ -21,7 +21,7 @@ func SetupRoutes(app *fiber.App) {
auth.Get("/validate", middleware.Protected(), handlers.ValidateToken) auth.Get("/validate", middleware.Protected(), handlers.ValidateToken)
// Contacts group // Contacts group
contacts := chat.Group("/contact", middleware.Protected(), logger.New()) contacts := chat.Group("/contacts", middleware.Protected(), logger.New())
contacts.Delete("/:contactID/:conversation_id", handlers.DeleteContact) contacts.Delete("/:contactID/:conversation_id", handlers.DeleteContact)
contacts.Post("/:contactUsername", handlers.InsertContact) contacts.Post("/:contactUsername", handlers.InsertContact)
contacts.Get("/", handlers.GetContacts) contacts.Get("/", handlers.GetContacts)