previews.go (3333B)
1 package app 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 if len(tagValues) == 0 { 48 return []File{}, nil 49 } 50 51 // For each tag value, find one representative file 52 var allFiles []File 53 for _, tagValue := range tagValues { 54 // Build query for this specific tag value with all filters applied 55 query := `SELECT f.id, f.filename, f.path, COALESCE(f.description, '') as description 56 FROM files f 57 WHERE 1=1` 58 args := []interface{}{} 59 60 // Apply all filters (including the preview category with this specific value) 61 for _, filter := range filters { 62 if filter.IsPreviews { 63 // For the preview filter, use the current tag value we're iterating over 64 query += ` 65 AND EXISTS ( 66 SELECT 1 67 FROM file_tags ft 68 JOIN tags t ON ft.tag_id = t.id 69 JOIN categories c ON c.id = t.category_id 70 WHERE ft.file_id = f.id AND c.name = ? AND t.value = ? 71 )` 72 args = append(args, filter.Category, tagValue) 73 } else if filter.IsProperty { 74 query += ` 75 AND EXISTS ( 76 SELECT 1 77 FROM file_properties fp 78 WHERE fp.file_id = f.id AND fp.key = ? AND fp.value = ? 79 )` 80 args = append(args, filter.Category, filter.Value) 81 } else if filter.Value == "unassigned" { 82 query += ` 83 AND NOT EXISTS ( 84 SELECT 1 85 FROM file_tags ft 86 JOIN tags t ON ft.tag_id = t.id 87 JOIN categories c ON c.id = t.category_id 88 WHERE ft.file_id = f.id AND c.name = ? 89 )` 90 args = append(args, filter.Category) 91 } else { 92 // Normal filter with aliases 93 placeholders := make([]string, len(filter.Values)) 94 for i := range filter.Values { 95 placeholders[i] = "?" 96 } 97 98 query += fmt.Sprintf(` 99 AND EXISTS ( 100 SELECT 1 101 FROM file_tags ft 102 JOIN tags t ON ft.tag_id = t.id 103 JOIN categories c ON c.id = t.category_id 104 WHERE ft.file_id = f.id AND c.name = ? AND t.value IN (%s) 105 )`, strings.Join(placeholders, ",")) 106 107 args = append(args, filter.Category) 108 for _, v := range filter.Values { 109 args = append(args, v) 110 } 111 } 112 } 113 114 query += ` ORDER BY f.id DESC LIMIT 1` 115 116 files, err := queryFilesWithTags(query, args...) 117 if err != nil { 118 return nil, fmt.Errorf("failed to query files for tag %s: %w", tagValue, err) 119 } 120 121 if len(files) > 0 { 122 allFiles = append(allFiles, files[0]) 123 } 124 } 125 126 return allFiles, nil 127 }