2026-05-16 23:03:50 +00:00
package store
import (
"context"
"database/sql"
)
func ( s * Store ) Projects ( ctx context . Context , featuredOnly bool ) ( [ ] Project , error ) {
2026-05-17 12:36:50 +00:00
query := ` select id, slug, title, location, year, category, summary, scope, status, position, description, cover_image, featured, created_at from projects `
2026-05-16 23:03:50 +00:00
if featuredOnly {
query += ` where featured = 1 `
}
2026-05-17 12:36:50 +00:00
query += ` order by position asc, created_at desc, id desc `
2026-05-16 23:03:50 +00:00
rows , err := s . db . QueryContext ( ctx , query )
if err != nil {
return nil , err
}
defer rows . Close ( )
var projects [ ] Project
for rows . Next ( ) {
var p Project
var featured int
2026-05-17 12:36:50 +00:00
if err := rows . Scan ( & p . ID , & p . Slug , & p . Title , & p . Location , & p . Year , & p . Category , & p . Summary , & p . Scope , & p . Status , & p . Position , & p . Description , & p . CoverImage , & featured , & p . CreatedAt ) ; err != nil {
2026-05-16 23:03:50 +00:00
return nil , err
}
p . Featured = featured == 1
projects = append ( projects , p )
}
return projects , rows . Err ( )
}
func ( s * Store ) ProjectBySlug ( ctx context . Context , slug string ) ( Project , error ) {
var p Project
var featured int
2026-05-17 12:36:50 +00:00
err := s . db . QueryRowContext ( ctx , ` select id, slug, title, location, year, category, summary, scope, status, position, description, cover_image, featured, created_at from projects where slug = ? ` , slug ) .
Scan ( & p . ID , & p . Slug , & p . Title , & p . Location , & p . Year , & p . Category , & p . Summary , & p . Scope , & p . Status , & p . Position , & p . Description , & p . CoverImage , & featured , & p . CreatedAt )
2026-05-16 23:03:50 +00:00
if err != nil {
return p , err
}
p . Featured = featured == 1
p . Images , err = s . ProjectImages ( ctx , p . ID )
return p , err
}
func ( s * Store ) ProjectImages ( ctx context . Context , projectID int64 ) ( [ ] ProjectImage , error ) {
rows , err := s . db . QueryContext ( ctx , ` select id, project_id, path, caption, position from project_images where project_id = ? order by position asc, id asc ` , projectID )
if err != nil {
return nil , err
}
defer rows . Close ( )
var images [ ] ProjectImage
for rows . Next ( ) {
var img ProjectImage
if err := rows . Scan ( & img . ID , & img . ProjectID , & img . Path , & img . Caption , & img . Position ) ; err != nil {
return nil , err
}
images = append ( images , img )
}
return images , rows . Err ( )
}
func ( s * Store ) ProjectImagesByProject ( ctx context . Context ) ( map [ int64 ] [ ] ProjectImage , error ) {
rows , err := s . db . QueryContext ( ctx , ` select id, project_id, path, caption, position from project_images order by project_id asc, position asc, id asc ` )
if err != nil {
return nil , err
}
defer rows . Close ( )
images := make ( map [ int64 ] [ ] ProjectImage )
for rows . Next ( ) {
var img ProjectImage
if err := rows . Scan ( & img . ID , & img . ProjectID , & img . Path , & img . Caption , & img . Position ) ; err != nil {
return nil , err
}
images [ img . ProjectID ] = append ( images [ img . ProjectID ] , img )
}
return images , rows . Err ( )
}
func ( s * Store ) ProjectImageForSlug ( ctx context . Context , slug string , imageID int64 ) ( Project , ProjectImage , error ) {
p , err := s . ProjectBySlug ( ctx , slug )
if err != nil {
return Project { } , ProjectImage { } , err
}
for _ , img := range p . Images {
if img . ID == imageID {
return p , img , nil
}
}
return Project { } , ProjectImage { } , sql . ErrNoRows
}
func ( s * Store ) CreateProject ( ctx context . Context , p Project ) ( int64 , error ) {
2026-05-17 12:36:50 +00:00
res , err := s . db . ExecContext ( ctx , ` insert into projects (slug, title, location, year, category, summary, scope, status, position, description, cover_image, featured) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ` ,
p . Slug , p . Title , p . Location , p . Year , p . Category , p . Summary , p . Scope , p . Status , p . Position , p . Description , p . CoverImage , boolInt ( p . Featured ) )
2026-05-16 23:03:50 +00:00
if err != nil {
return 0 , err
}
return res . LastInsertId ( )
}
func ( s * Store ) UpdateProject ( ctx context . Context , p Project ) error {
2026-05-17 12:36:50 +00:00
_ , err := s . db . ExecContext ( ctx , ` update projects set slug=?, title=?, location=?, year=?, category=?, summary=?, scope=?, status=?, position=?, description=?, cover_image=?, featured=? where id=? ` ,
p . Slug , p . Title , p . Location , p . Year , p . Category , p . Summary , p . Scope , p . Status , p . Position , p . Description , p . CoverImage , boolInt ( p . Featured ) , p . ID )
2026-05-16 23:03:50 +00:00
return err
}
func ( s * Store ) DeleteProject ( ctx context . Context , id int64 ) error {
_ , err := s . db . ExecContext ( ctx , ` delete from projects where id = ? ` , id )
return err
}
func ( s * Store ) AddProjectImage ( ctx context . Context , projectID int64 , path , caption string ) error {
var pos int
_ = s . db . QueryRowContext ( ctx , ` select coalesce(max(position), -1) + 1 from project_images where project_id = ? ` , projectID ) . Scan ( & pos )
_ , err := s . db . ExecContext ( ctx , ` insert into project_images (project_id, path, caption, position) values (?, ?, ?, ?) ` , projectID , path , caption , pos )
return err
}
func ( s * Store ) DeleteProjectImage ( ctx context . Context , id int64 ) error {
_ , err := s . db . ExecContext ( ctx , ` delete from project_images where id = ? ` , id )
return err
}