You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

128 lines
4.0 KiB

package models
import (
"database/sql"
"time"
)
type Project struct {
ID int `json:"id"`
Title string `json:"title"`
Description string `json:"description"`
Status string `json:"status"`
URL string `json:"url"`
SourceURL string `json:"source_url"`
Tags []string `json:"tags"`
DisplayOrder int `json:"display_order"`
Featured bool `json:"featured"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
}
type ProjectStore struct {
DB *sql.DB
}
func (s *ProjectStore) ListAll() ([]Project, error) {
rows, err := s.DB.Query(`SELECT id, title, description, status, url, source_url, tags, display_order, featured, created_at, updated_at FROM projects ORDER BY display_order ASC, created_at DESC`)
if err != nil {
return nil, err
}
defer rows.Close()
return scanProjects(rows)
}
func (s *ProjectStore) ListFeatured() ([]Project, error) {
rows, err := s.DB.Query(`SELECT id, title, description, status, url, source_url, tags, display_order, featured, created_at, updated_at FROM projects WHERE featured = 1 ORDER BY display_order ASC, created_at DESC`)
if err != nil {
return nil, err
}
defer rows.Close()
return scanProjects(rows)
}
func (s *ProjectStore) GetByID(id int) (*Project, error) {
var p Project
err := s.DB.QueryRow(`SELECT id, title, description, status, url, source_url, tags, display_order, featured, created_at, updated_at FROM projects WHERE id = ?`, id).
Scan(&p.ID, &p.Title, &p.Description, &p.Status, &p.URL, &p.SourceURL, &scannableJSON{&p.Tags}, &p.DisplayOrder, &p.Featured, &p.CreatedAt, &p.UpdatedAt)
if err == sql.ErrNoRows {
return nil, nil
}
if err != nil {
return nil, err
}
return &p, nil
}
func (s *ProjectStore) Create(p *Project) error {
p.CreatedAt = time.Now().UTC().Format(time.RFC3339)
p.UpdatedAt = p.CreatedAt
res, err := s.DB.Exec(`INSERT INTO projects (title, description, status, url, source_url, tags, display_order, featured, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
p.Title, p.Description, p.Status, p.URL, p.SourceURL, tagsToJSON(p.Tags), p.DisplayOrder, boolToInt(p.Featured), p.CreatedAt, p.UpdatedAt)
if err != nil {
return err
}
id, err := res.LastInsertId()
if err != nil {
return err
}
p.ID = int(id)
return nil
}
func (s *ProjectStore) Update(p *Project) error {
p.UpdatedAt = time.Now().UTC().Format(time.RFC3339)
_, err := s.DB.Exec(`UPDATE projects SET title=?, description=?, status=?, url=?, source_url=?, tags=?, display_order=?, featured=?, updated_at=? WHERE id=?`,
p.Title, p.Description, p.Status, p.URL, p.SourceURL, tagsToJSON(p.Tags), p.DisplayOrder, boolToInt(p.Featured), p.UpdatedAt, p.ID)
return err
}
func (s *ProjectStore) Delete(id int) error {
_, err := s.DB.Exec(`DELETE FROM projects WHERE id = ?`, id)
return err
}
func (s *ProjectStore) ReplaceAll(projects []Project) error {
tx, err := s.DB.Begin()
if err != nil {
return err
}
defer tx.Rollback()
if _, err := tx.Exec(`DELETE FROM projects`); err != nil {
return err
}
stmt, err := tx.Prepare(`INSERT INTO projects (title, description, status, url, source_url, tags, display_order, featured, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
if err != nil {
return err
}
defer stmt.Close()
for _, p := range projects {
if p.CreatedAt == "" {
p.CreatedAt = p.UpdatedAt
}
if p.UpdatedAt == "" {
p.UpdatedAt = p.CreatedAt
}
_, err := stmt.Exec(p.Title, p.Description, p.Status, p.URL, p.SourceURL, tagsToJSON(p.Tags), p.DisplayOrder, boolToInt(p.Featured), p.CreatedAt, p.UpdatedAt)
if err != nil {
return err
}
}
return tx.Commit()
}
func scanProjects(rows *sql.Rows) ([]Project, error) {
var projects []Project
for rows.Next() {
var p Project
if err := rows.Scan(&p.ID, &p.Title, &p.Description, &p.Status, &p.URL, &p.SourceURL, &scannableJSON{&p.Tags}, &p.DisplayOrder, &p.Featured, &p.CreatedAt, &p.UpdatedAt); err != nil {
return nil, err
}
projects = append(projects, p)
}
return projects, rows.Err()
}