photoprism/internal/query/labels.go
Michael Mayer 842da9f09b Backend: Query package refactoring
Signed-off-by: Michael Mayer <michael@liquidbytes.net>
2020-05-08 15:41:01 +02:00

162 lines
4.9 KiB
Go

package query
import (
"fmt"
"strings"
"time"
"github.com/gosimple/slug"
"github.com/photoprism/photoprism/internal/entity"
"github.com/photoprism/photoprism/internal/form"
"github.com/photoprism/photoprism/pkg/capture"
"github.com/photoprism/photoprism/pkg/txt"
)
// PhotoLabel returns a photo label entity if exists.
func PhotoLabel(photoID, labelID uint) (label entity.PhotoLabel, err error) {
if err := Db().Where("photo_id = ? AND label_id = ?", photoID, labelID).Preload("Photo").Preload("Label").First(&label).Error; err != nil {
return label, err
}
return label, nil
}
// LabelBySlug returns a Label based on the slug name.
func LabelBySlug(labelSlug string) (label entity.Label, err error) {
if err := Db().Where("label_slug = ? OR custom_slug = ?", labelSlug, labelSlug).Preload("Links").First(&label).Error; err != nil {
return label, err
}
return label, nil
}
// LabelByUUID returns a Label based on the label UUID.
func LabelByUUID(labelUUID string) (label entity.Label, err error) {
if err := Db().Where("label_uuid = ?", labelUUID).Preload("Links").First(&label).Error; err != nil {
return label, err
}
return label, nil
}
// LabelThumbBySlug returns a label preview file based on the slug name.
func LabelThumbBySlug(labelSlug string) (file entity.File, err error) {
if err := Db().Where("files.file_primary AND files.deleted_at IS NULL").
Joins("JOIN labels ON labels.label_slug = ?", labelSlug).
Joins("JOIN photos_labels ON photos_labels.label_id = labels.id AND photos_labels.photo_id = files.photo_id").
Joins("JOIN photos ON photos.id = files.photo_id AND photos.photo_private = 0 AND photos.deleted_at IS NULL").
Order("photos.photo_quality DESC, photos_labels.uncertainty ASC").
First(&file).Error; err != nil {
return file, err
}
return file, nil
}
// LabelThumbByUUID returns a label preview file based on the label UUID.
func LabelThumbByUUID(labelUUID string) (file entity.File, err error) {
// Search matching label
err = Db().Where("files.file_primary AND files.deleted_at IS NULL").
Joins("JOIN labels ON labels.label_uuid = ?", labelUUID).
Joins("JOIN photos_labels ON photos_labels.label_id = labels.id AND photos_labels.photo_id = files.photo_id").
Joins("JOIN photos ON photos.id = files.photo_id AND photos.photo_private = 0 AND photos.deleted_at IS NULL").
Order("photos.photo_quality DESC, photos_labels.uncertainty ASC").
First(&file).Error
if err == nil {
return file, nil
}
// If failed, search for category instead
err = Db().Where("files.file_primary AND files.deleted_at IS NULL").
Joins("JOIN photos_labels ON photos_labels.photo_id = files.photo_id").
Joins("JOIN categories c ON photos_labels.label_id = c.label_id").
Joins("JOIN labels ON c.category_id = labels.id AND labels.label_uuid= ?", labelUUID).
Joins("JOIN photos ON photos.id = files.photo_id AND photos.photo_private = 0 AND photos.deleted_at IS NULL").
Order("photos.photo_quality DESC, photos_labels.uncertainty ASC").
First(&file).Error
return file, err
}
// Labels searches labels based on their name.
func Labels(f form.LabelSearch) (results []LabelResult, err error) {
if err := f.ParseQueryString(); err != nil {
return results, err
}
defer log.Debug(capture.Time(time.Now(), fmt.Sprintf("labels: %+v", f)))
s := UnscopedDb()
// s.LogMode(true)
s = s.Table("labels").
Select(`labels.*`).
Where("labels.deleted_at IS NULL").
Group("labels.id")
if f.ID != "" {
s = s.Where("labels.label_uuid = ?", f.ID)
if result := s.Scan(&results); result.Error != nil {
return results, result.Error
}
return results, nil
}
if f.Query != "" {
var labelIds []uint
var categories []entity.Category
var label entity.Label
slugString := slug.Make(f.Query)
likeString := "%" + strings.ToLower(f.Query) + "%"
if result := Db().First(&label, "label_slug = ? OR custom_slug = ?", slugString, slugString); result.Error != nil {
log.Infof("search: label %s not found", txt.Quote(f.Query))
s = s.Where("LOWER(labels.label_name) LIKE ?", likeString)
} else {
labelIds = append(labelIds, label.ID)
Db().Where("category_id = ?", label.ID).Find(&categories)
for _, category := range categories {
labelIds = append(labelIds, category.LabelID)
}
log.Infof("search: label %s includes %d categories", txt.Quote(label.LabelName), len(labelIds))
s = s.Where("labels.id IN (?)", labelIds)
}
}
if f.Favorites {
s = s.Where("labels.label_favorite = 1")
}
if !f.All {
s = s.Where("labels.label_priority >= 0 OR labels.label_favorite = 1")
}
switch f.Order {
case "slug":
s = s.Order("labels.label_favorite DESC, custom_slug ASC")
default:
s = s.Order("labels.label_favorite DESC, custom_slug ASC")
}
if f.Count > 0 && f.Count <= 1000 {
s = s.Limit(f.Count).Offset(f.Offset)
} else {
s = s.Limit(100).Offset(0)
}
if result := s.Scan(&results); result.Error != nil {
return results, result.Error
}
return results, nil
}