include-previews.go (3334B)
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.IsProperty { 75 query += ` 76 AND EXISTS ( 77 SELECT 1 78 FROM file_properties fp 79 WHERE fp.file_id = f.id AND fp.key = ? AND fp.value = ? 80 )` 81 args = append(args, filter.Category, filter.Value) 82 } else if filter.Value == "unassigned" { 83 query += ` 84 AND NOT EXISTS ( 85 SELECT 1 86 FROM file_tags ft 87 JOIN tags t ON ft.tag_id = t.id 88 JOIN categories c ON c.id = t.category_id 89 WHERE ft.file_id = f.id AND c.name = ? 90 )` 91 args = append(args, filter.Category) 92 } else { 93 // Normal filter with aliases 94 placeholders := make([]string, len(filter.Values)) 95 for i := range filter.Values { 96 placeholders[i] = "?" 97 } 98 99 query += fmt.Sprintf(` 100 AND EXISTS ( 101 SELECT 1 102 FROM file_tags ft 103 JOIN tags t ON ft.tag_id = t.id 104 JOIN categories c ON c.id = t.category_id 105 WHERE ft.file_id = f.id AND c.name = ? AND t.value IN (%s) 106 )`, strings.Join(placeholders, ",")) 107 108 args = append(args, filter.Category) 109 for _, v := range filter.Values { 110 args = append(args, v) 111 } 112 } 113 } 114 115 query += ` ORDER BY f.id DESC LIMIT 1` 116 117 files, err := queryFilesWithTags(query, args...) 118 if err != nil { 119 return nil, fmt.Errorf("failed to query files for tag %s: %w", tagValue, err) 120 } 121 122 if len(files) > 0 { 123 allFiles = append(allFiles, files[0]) 124 } 125 } 126 127 return allFiles, nil 128 }