package repository // NoteRepo provides database operations for the Note model. // Reference: Chatwoot app/models/note.rb — scope :latest, -> { order(created_at: :desc) } import ( "context" "github.com/gochat/gochat/internal/model" "gorm.io/gorm" ) // NoteRepo handles CRUD for contact notes. type NoteRepo struct { db *gorm.DB } // NewNoteRepo creates a new NoteRepo instance. func NewNoteRepo(db *gorm.DB) *NoteRepo { return &NoteRepo{db: db} } // FindByContact returns all notes for a contact, ordered by latest first. // Compatible with ContactService which calls this with ctx parameter. // Reference: Chatwoot `@contact.notes.latest.includes(:user)` func (r *NoteRepo) FindByContact(ctx context.Context, accountID, contactID uint) ([]model.Note, error) { var notes []model.Note err := r.db.WithContext(ctx).Where("account_id = ? AND contact_id = ?", accountID, contactID). Order("created_at DESC"). Preload("User"). Find(¬es).Error return notes, err } // Create creates a new note. Compatible with ContactService which passes ctx. func (r *NoteRepo) Create(ctx context.Context, note *model.Note) error { return r.db.WithContext(ctx).Create(note).Error } // ListByContact returns all notes for a contact, ordered by latest first. // Reference: Chatwoot `@contact.notes.latest.includes(:user)` func (r *NoteRepo) ListByContact(accountID, contactID uint) ([]model.Note, error) { var notes []model.Note err := r.db.Where("account_id = ? AND contact_id = ?", accountID, contactID). Order("created_at DESC"). Preload("User"). Find(¬es).Error return notes, err } // GetByID returns a single note by ID within the account scope. func (r *NoteRepo) GetByID(accountID, contactID, noteID uint) (*model.Note, error) { return r.GetByIDContext(context.Background(), accountID, contactID, noteID) } func (r *NoteRepo) GetByIDContext(ctx context.Context, accountID, contactID, noteID uint) (*model.Note, error) { var note model.Note err := r.db.WithContext(ctx).Where("account_id = ? AND contact_id = ? AND id = ?", accountID, contactID, noteID). Preload("User"). First(¬e).Error if err != nil { return nil, err } return ¬e, nil } // CreateNote creates a new note for a contact (NoteService uses this). // BeforeCreate hook ensures account_id is set from contact if missing. func (r *NoteRepo) CreateNote(note *model.Note) (*model.Note, error) { if err := r.db.Create(note).Error; err != nil { return nil, err } // Reload to get User association r.db.Preload("User").First(note, note.ID) return note, nil } // Update updates an existing note. func (r *NoteRepo) Update(note *model.Note) (*model.Note, error) { if err := r.db.Save(note).Error; err != nil { return nil, err } r.db.Preload("User").First(note, note.ID) return note, nil } // Delete hard-deletes a note, matching Chatwoot `@note.destroy!` for notes. func (r *NoteRepo) Delete(accountID, contactID, noteID uint) error { return r.DeleteContext(context.Background(), accountID, contactID, noteID) } func (r *NoteRepo) DeleteContext(ctx context.Context, accountID, contactID, noteID uint) error { return r.db.WithContext(ctx).Where("account_id = ? AND contact_id = ? AND id = ?", accountID, contactID, noteID). Unscoped().Delete(&model.Note{}).Error }