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
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()
|
|
}
|
|
|