include-previews.go (3098B)
1 package main 2 3 import ( 4 "fmt" 5 "strings" 6 ) 7 8 // getPreviewFiles returns one representative file for each tag value in the specified category 9 func getPreviewFiles(filters []filter) ([]File, error) { 10 // Find the preview filter category 11 var previewCategory string 12 for _, f := range filters { 13 if f.IsPreviews { 14 previewCategory = f.Category 15 break 16 } 17 } 18 19 if previewCategory == "" { 20 return []File{}, nil 21 } 22 23 // First, get all tag values for the preview category that have files 24 tagQuery := ` 25 SELECT DISTINCT t.value 26 FROM tags t 27 JOIN categories c ON t.category_id = c.id 28 JOIN file_tags ft ON ft.tag_id = t.id 29 WHERE c.name = ? 30 ORDER BY t.value` 31 32 tagRows, err := db.Query(tagQuery, previewCategory) 33 if err != nil { 34 return nil, fmt.Errorf("failed to query tag values: %w", err) 35 } 36 defer tagRows.Close() 37 38 var tagValues []string 39 for tagRows.Next() { 40 var tagValue string 41 if err := tagRows.Scan(&tagValue); err != nil { 42 return nil, fmt.Errorf("failed to scan tag value: %w", err) 43 } 44 tagValues = append(tagValues, tagValue) 45 } 46 47 48 if len(tagValues) == 0 { 49 return []File{}, nil 50 } 51 52 // For each tag value, find one representative file 53 var allFiles []File 54 for _, tagValue := range tagValues { 55 // Build query for this specific tag value with all filters applied 56 query := `SELECT f.id, f.filename, f.path, COALESCE(f.description, '') as description 57 FROM files f 58 WHERE 1=1` 59 args := []interface{}{} 60 61 // Apply all filters (including the preview category with this specific value) 62 for _, filter := range filters { 63 if filter.IsPreviews { 64 // For the preview filter, use the current tag value we're iterating over 65 query += ` 66 AND EXISTS ( 67 SELECT 1 68 FROM file_tags ft 69 JOIN tags t ON ft.tag_id = t.id 70 JOIN categories c ON c.id = t.category_id 71 WHERE ft.file_id = f.id AND c.name = ? AND t.value = ? 72 )` 73 args = append(args, filter.Category, tagValue) 74 } else if filter.Value == "unassigned" { 75 query += ` 76 AND NOT EXISTS ( 77 SELECT 1 78 FROM file_tags ft 79 JOIN tags t ON ft.tag_id = t.id 80 JOIN categories c ON c.id = t.category_id 81 WHERE ft.file_id = f.id AND c.name = ? 82 )` 83 args = append(args, filter.Category) 84 } else { 85 // Normal filter with aliases 86 placeholders := make([]string, len(filter.Values)) 87 for i := range filter.Values { 88 placeholders[i] = "?" 89 } 90 91 query += fmt.Sprintf(` 92 AND EXISTS ( 93 SELECT 1 94 FROM file_tags ft 95 JOIN tags t ON ft.tag_id = t.id 96 JOIN categories c ON c.id = t.category_id 97 WHERE ft.file_id = f.id AND c.name = ? AND t.value IN (%s) 98 )`, strings.Join(placeholders, ",")) 99 100 args = append(args, filter.Category) 101 for _, v := range filter.Values { 102 args = append(args, v) 103 } 104 } 105 } 106 107 query += ` ORDER BY f.id DESC LIMIT 1` 108 109 files, err := queryFilesWithTags(query, args...) 110 if err != nil { 111 return nil, fmt.Errorf("failed to query files for tag %s: %w", tagValue, err) 112 } 113 114 if len(files) > 0 { 115 allFiles = append(allFiles, files[0]) 116 } 117 } 118 119 return allFiles, nil 120 }