package volunteer import ( "context" "database/sql" "errors" "fmt" "time" ) var ErrNotFound = fmt.Errorf("volunteer not found") type Volunteer struct { ID int64 `json:"id"` Name string `json:"name"` Email string `json:"email"` Role string `json:"role"` Active bool `json:"active"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` } type CreateInput struct { Name string `json:"name"` Email string `json:"email"` Password string `json:"password"` Role string `json:"role"` } type UpdateInput struct { Name *string `json:"name"` Email *string `json:"email"` Role *string `json:"role"` Active *bool `json:"active"` } type Store struct { db *sql.DB } func NewStore(db *sql.DB) *Store { return &Store{db: db} } func (s *Store) Create(ctx context.Context, name, email, hashedPassword, role string) (*Volunteer, error) { res, err := s.db.ExecContext(ctx, `INSERT INTO volunteers (name, email, password, role) VALUES (?, ?, ?, ?)`, name, email, hashedPassword, role, ) if err != nil { return nil, fmt.Errorf("insert volunteer: %w", err) } id, _ := res.LastInsertId() return s.GetByID(ctx, id) } func (s *Store) GetByID(ctx context.Context, id int64) (*Volunteer, error) { v := &Volunteer{} var createdAt, updatedAt string err := s.db.QueryRowContext(ctx, `SELECT id, name, email, role, active, created_at, updated_at FROM volunteers WHERE id = ?`, id, ).Scan(&v.ID, &v.Name, &v.Email, &v.Role, &v.Active, &createdAt, &updatedAt) if errors.Is(err, sql.ErrNoRows) { return nil, ErrNotFound } if err != nil { return nil, fmt.Errorf("get volunteer: %w", err) } v.CreatedAt, _ = time.Parse("2006-01-02 15:04:05", createdAt) v.UpdatedAt, _ = time.Parse("2006-01-02 15:04:05", updatedAt) return v, nil } func (s *Store) List(ctx context.Context, activeOnly bool) ([]Volunteer, error) { query := `SELECT id, name, email, role, active, created_at, updated_at FROM volunteers` if activeOnly { query += ` WHERE active = 1` } query += ` ORDER BY name` rows, err := s.db.QueryContext(ctx, query) if err != nil { return nil, fmt.Errorf("list volunteers: %w", err) } defer rows.Close() var volunteers []Volunteer for rows.Next() { var v Volunteer var createdAt, updatedAt string if err := rows.Scan(&v.ID, &v.Name, &v.Email, &v.Role, &v.Active, &createdAt, &updatedAt); err != nil { return nil, err } v.CreatedAt, _ = time.Parse("2006-01-02 15:04:05", createdAt) v.UpdatedAt, _ = time.Parse("2006-01-02 15:04:05", updatedAt) volunteers = append(volunteers, v) } return volunteers, rows.Err() } func (s *Store) Update(ctx context.Context, id int64, in UpdateInput) (*Volunteer, error) { v, err := s.GetByID(ctx, id) if err != nil { return nil, err } if in.Name != nil { v.Name = *in.Name } if in.Email != nil { v.Email = *in.Email } if in.Role != nil { v.Role = *in.Role } if in.Active != nil { v.Active = *in.Active } activeInt := 0 if v.Active { activeInt = 1 } _, err = s.db.ExecContext(ctx, `UPDATE volunteers SET name=?, email=?, role=?, active=?, updated_at=NOW() WHERE id=?`, v.Name, v.Email, v.Role, activeInt, id, ) if err != nil { return nil, fmt.Errorf("update volunteer: %w", err) } return s.GetByID(ctx, id) }