139 lines
3.5 KiB
Go
139 lines
3.5 KiB
Go
package photoprism
|
|
|
|
import (
|
|
"github.com/jinzhu/gorm"
|
|
"github.com/photoprism/photoprism/forms"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
type Search struct {
|
|
originalsPath string
|
|
db *gorm.DB
|
|
}
|
|
|
|
type SearchCount struct {
|
|
Total int
|
|
}
|
|
|
|
type PhotoSearchResult struct {
|
|
// Photo
|
|
ID uint
|
|
CreatedAt time.Time
|
|
UpdatedAt time.Time
|
|
DeletedAt time.Time
|
|
TakenAt time.Time
|
|
PhotoTitle string
|
|
PhotoDescription string
|
|
PhotoArtist string
|
|
PhotoKeywords string
|
|
PhotoColors string
|
|
PhotoVibrantColor string
|
|
PhotoMutedColor string
|
|
PhotoCanonicalName string
|
|
PhotoPerceptualHash string
|
|
PhotoLat float64
|
|
PhotoLong float64
|
|
PhotoFavorite bool
|
|
|
|
// Camera
|
|
CameraID uint
|
|
CameraModel string
|
|
|
|
// Location
|
|
LocationID uint
|
|
LocDisplayName string
|
|
LocName string
|
|
LocCity string
|
|
LocPostcode string
|
|
LocCounty string
|
|
LocState string
|
|
LocCountry string
|
|
LocCountryCode string
|
|
LocCategory string
|
|
LocType string
|
|
|
|
// File
|
|
FileID uint
|
|
FileName string
|
|
FileType string
|
|
FileMime string
|
|
FileWidth int
|
|
FileHeight int
|
|
FileOrientation int
|
|
FileAspectRatio float64
|
|
|
|
// Tags
|
|
Tags string
|
|
}
|
|
|
|
func NewSearch(originalsPath string, db *gorm.DB) *Search {
|
|
instance := &Search{
|
|
originalsPath: originalsPath,
|
|
db: db,
|
|
}
|
|
|
|
return instance
|
|
}
|
|
|
|
func (s *Search) Photos(form forms.PhotoSearchForm) ([]PhotoSearchResult, int, error) {
|
|
q := s.db.NewScope(nil).DB()
|
|
q = q.Table("photos").
|
|
Select(`SQL_CALC_FOUND_ROWS photos.*,
|
|
files.id AS file_id, files.file_name, files.file_type, files.file_mime, files.file_width, files.file_height, files.file_aspect_ratio, files.file_orientation,
|
|
cameras.camera_model,
|
|
locations.loc_display_name, locations.loc_name, locations.loc_city, locations.loc_postcode, locations.loc_country, locations.loc_country_code, locations.loc_category, locations.loc_type,
|
|
GROUP_CONCAT(tags.tag_label) AS tags`).
|
|
Joins("JOIN files ON files.photo_id = photos.id AND files.file_primary AND files.deleted_at IS NULL").
|
|
Joins("JOIN cameras ON cameras.id = photos.camera_id").
|
|
Joins("LEFT JOIN locations ON locations.id = photos.location_id").
|
|
Joins("LEFT JOIN photo_tags ON photo_tags.photo_id = photos.id").
|
|
Joins("LEFT JOIN tags ON photo_tags.tag_id = tags.id").
|
|
Where("photos.deleted_at IS NULL").
|
|
Group("photos.id, files.id")
|
|
|
|
if form.Query != "" {
|
|
q = q.Where("tags.tag_label LIKE ? OR MATCH (photo_title, photo_description, photo_artist, photo_colors) AGAINST (?)", "%"+strings.ToLower(form.Query)+"%", form.Query)
|
|
}
|
|
|
|
if form.CameraID > 0 {
|
|
q = q.Where("camera_id = ?", form.CameraID)
|
|
}
|
|
|
|
q = q.Order(form.Order).Limit(form.Count).Offset(form.Offset)
|
|
|
|
results := make([]PhotoSearchResult, 0, form.Count)
|
|
|
|
rows, err := q.Rows()
|
|
|
|
if err != nil {
|
|
return results, 0, err
|
|
}
|
|
|
|
defer rows.Close()
|
|
|
|
for rows.Next() {
|
|
var result PhotoSearchResult
|
|
s.db.ScanRows(rows, &result)
|
|
results = append(results, result)
|
|
}
|
|
|
|
// TODO: Check if this works properly with concurrent requests and caching
|
|
count := &SearchCount{}
|
|
s.db.Raw("SELECT FOUND_ROWS() AS total").Scan(&count)
|
|
total := count.Total
|
|
|
|
return results, total, nil
|
|
}
|
|
|
|
func (s *Search) FindFiles(count int, offset int) (files []File) {
|
|
s.db.Where(&File{}).Limit(count).Offset(offset).Find(&files)
|
|
|
|
return files
|
|
}
|
|
|
|
func (s *Search) FindFile(id string) (file File) {
|
|
s.db.Where("id = ?", id).First(&file)
|
|
|
|
return file
|
|
}
|