mirror of
https://github.com/photoprism/photoprism.git
synced 2026-01-23 02:24:24 +00:00
Merge e3848a03c0 into 26b5cbafcd
This commit is contained in:
commit
98a7965aee
8 changed files with 656 additions and 262 deletions
38
internal/entity/search/near.go
Normal file
38
internal/entity/search/near.go
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
package search
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/photoprism/photoprism/pkg/geo"
|
||||
"github.com/photoprism/photoprism/pkg/geo/s2"
|
||||
)
|
||||
|
||||
// nearSQLCreator uses the near from frm.Near and dist from frm.Dist to generate the qs (Query String) and interface of values to allow Gorm to generate the required clause
|
||||
func nearSQLCreator(near string, dist float64) (qs string, values []interface{}, err error) {
|
||||
photos := []Photo{}
|
||||
if err := Db().Model(&Photo{}).Where("photo_uid IN (?)", SplitOr(near)).Select("photo_uid, cell_id").Find(&photos).Error; err != nil {
|
||||
log.Debugf("search: %s (find nearby)", err)
|
||||
return qs, values, ErrNotFound
|
||||
}
|
||||
|
||||
if len(photos) == 0 {
|
||||
return qs, values, ErrNotFound
|
||||
}
|
||||
|
||||
wheres := make([]string, len(photos))
|
||||
for item, photo := range photos {
|
||||
// Set the S2 Cell ID to search for.
|
||||
s2Cell := photo.CellID
|
||||
|
||||
// Set the search distance if unspecified.
|
||||
if dist <= 0 {
|
||||
dist = geo.DefaultDist
|
||||
}
|
||||
|
||||
wheres[item] = "photos.cell_id BETWEEN ? AND ?"
|
||||
s2Min, s2Max := s2.PrefixedRange(s2Cell, s2.Level(dist))
|
||||
values = append(values, s2Min)
|
||||
values = append(values, s2Max)
|
||||
}
|
||||
return strings.Join(wheres, " OR "), values, nil
|
||||
}
|
||||
67
internal/entity/search/near_test.go
Normal file
67
internal/entity/search/near_test.go
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
package search
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestNearSQLCreator(t *testing.T) {
|
||||
t.Run("Empty", func(t *testing.T) {
|
||||
if _, _, err := nearSQLCreator("", float64(0)); err != nil {
|
||||
assert.Equal(t, ErrNotFound, err)
|
||||
} else {
|
||||
t.Fail()
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("ps6sg6be2lvl0y24", func(t *testing.T) {
|
||||
if qs, values, err := nearSQLCreator("ps6sg6be2lvl0y24", float64(0)); err != nil {
|
||||
assert.Nil(t, err)
|
||||
} else {
|
||||
assert.Equal(t, 2, len(values))
|
||||
assert.Equal(t, "photos.cell_id BETWEEN ? AND ?", qs)
|
||||
assert.Equal(t, "s2:85d1ea400004", values[0])
|
||||
assert.Equal(t, "s2:85d1ea800004", values[1])
|
||||
}
|
||||
})
|
||||
t.Run("ps6sg6byk7wrbk30", func(t *testing.T) {
|
||||
if qs, values, err := nearSQLCreator("ps6sg6byk7wrbk30", float64(0)); err != nil {
|
||||
assert.Nil(t, err)
|
||||
} else {
|
||||
assert.Equal(t, 2, len(values))
|
||||
assert.Equal(t, "photos.cell_id BETWEEN ? AND ?", qs)
|
||||
assert.Equal(t, "s2:1ef75a400004", values[0])
|
||||
assert.Equal(t, "s2:1ef75a800004", values[1])
|
||||
}
|
||||
})
|
||||
t.Run("ps6sg6be2lvl0y24 pipe ps6sg6byk7wrbk30", func(t *testing.T) {
|
||||
if qs, values, err := nearSQLCreator("ps6sg6be2lvl0y24|ps6sg6byk7wrbk30", float64(0)); err != nil {
|
||||
assert.Nil(t, err)
|
||||
} else {
|
||||
assert.Equal(t, 4, len(values))
|
||||
assert.Equal(t, "photos.cell_id BETWEEN ? AND ? OR photos.cell_id BETWEEN ? AND ?", qs)
|
||||
assert.Equal(t, "s2:85d1ea400004", values[0])
|
||||
assert.Equal(t, "s2:85d1ea800004", values[1])
|
||||
assert.Equal(t, "s2:1ef75a400004", values[2])
|
||||
assert.Equal(t, "s2:1ef75a800004", values[3])
|
||||
}
|
||||
})
|
||||
t.Run("ps6sg6be2lvl0y24 pipe ps6sg6byk7wrtest", func(t *testing.T) {
|
||||
if qs, values, err := nearSQLCreator("ps6sg6be2lvl0y24|ps6sg6byk7wrtest", float64(0)); err != nil {
|
||||
assert.Nil(t, err)
|
||||
} else {
|
||||
assert.Equal(t, 2, len(values))
|
||||
assert.Equal(t, "photos.cell_id BETWEEN ? AND ?", qs)
|
||||
assert.Equal(t, "s2:85d1ea400004", values[0])
|
||||
assert.Equal(t, "s2:85d1ea800004", values[1])
|
||||
}
|
||||
})
|
||||
t.Run("ps6sg6be2lvltest pipe ps6sg6byk7wrtest", func(t *testing.T) {
|
||||
if _, _, err := nearSQLCreator("ps6sg6be2lvltest|ps6sg6byk7wrtest", float64(0)); err != nil {
|
||||
assert.Equal(t, ErrNotFound, err)
|
||||
} else {
|
||||
t.Fail()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
@ -59,20 +59,6 @@ func searchPhotos(frm form.SearchPhotos, sess *entity.Session, resultCols string
|
|||
return PhotoResults{}, 0, ErrBadRequest
|
||||
}
|
||||
|
||||
// Find photos near another?
|
||||
if txt.NotEmpty(frm.Near) {
|
||||
photo := Photo{}
|
||||
|
||||
// Find a nearby picture using the UID or return an empty result otherwise.
|
||||
if err = Db().First(&photo, "photo_uid = ?", frm.Near).Error; err != nil {
|
||||
log.Debugf("search: %s (find nearby)", err)
|
||||
return PhotoResults{}, 0, ErrNotFound
|
||||
}
|
||||
|
||||
// Set the S2 Cell ID to search for.
|
||||
frm.S2 = photo.CellID
|
||||
}
|
||||
|
||||
// Set default search distance.
|
||||
if frm.Dist <= 0 {
|
||||
frm.Dist = geo.DefaultDist
|
||||
|
|
@ -288,26 +274,26 @@ func searchPhotos(frm form.SearchPhotos, sess *entity.Session, resultCols string
|
|||
if txt.NotEmpty(frm.Label) {
|
||||
var categories []entity.Category
|
||||
var labels []entity.Label
|
||||
var labelIds []uint
|
||||
var labelIDs []uint
|
||||
|
||||
if labelErr := Db().Where(AnySlug("label_slug", frm.Label, txt.Or)).Or(AnySlug("custom_slug", frm.Label, txt.Or)).Find(&labels).Error; len(labels) == 0 || labelErr != nil {
|
||||
log.Debugf("search: label %s not found", txt.LogParamLower(frm.Label))
|
||||
return PhotoResults{}, 0, nil
|
||||
} else {
|
||||
for _, l := range labels {
|
||||
labelIds = append(labelIds, l.ID)
|
||||
|
||||
Log("find categories", Db().Where("category_id = ?", l.ID).Find(&categories).Error)
|
||||
log.Debugf("search: label %s includes %d categories", txt.LogParamLower(l.LabelName), len(categories))
|
||||
|
||||
for _, category := range categories {
|
||||
labelIds = append(labelIds, category.LabelID)
|
||||
}
|
||||
}
|
||||
|
||||
s = s.Joins("JOIN photos_labels ON photos_labels.photo_id = files.photo_id AND photos_labels.uncertainty < 100 AND photos_labels.label_id IN (?)", labelIds).
|
||||
Group("photos.id, files.id")
|
||||
}
|
||||
|
||||
for _, l := range labels {
|
||||
labelIDs = append(labelIDs, l.ID)
|
||||
|
||||
Log("find categories", Db().Where("category_id = ?", l.ID).Find(&categories).Error)
|
||||
log.Debugf("search: label %s includes %d categories", txt.LogParamLower(l.LabelName), len(categories))
|
||||
|
||||
for _, category := range categories {
|
||||
labelIDs = append(labelIDs, category.LabelID)
|
||||
}
|
||||
}
|
||||
|
||||
s = s.Joins("JOIN photos_labels ON photos_labels.photo_id = files.photo_id AND photos_labels.uncertainty < 100 AND photos_labels.label_id IN (?)", labelIDs).
|
||||
Group("photos.id, files.id")
|
||||
}
|
||||
|
||||
// Set search filters based on search terms.
|
||||
|
|
@ -398,7 +384,7 @@ func searchPhotos(frm form.SearchPhotos, sess *entity.Session, resultCols string
|
|||
if frm.Query != "" {
|
||||
var categories []entity.Category
|
||||
var labels []entity.Label
|
||||
var labelIds []uint
|
||||
var labelIDs []uint
|
||||
|
||||
if labelsErr := Db().Where(AnySlug("custom_slug", frm.Query, " ")).Find(&labels).Error; len(labels) == 0 || labelsErr != nil {
|
||||
log.Tracef("search: label %s not found, using fuzzy search", txt.LogParamLower(frm.Query))
|
||||
|
|
@ -408,24 +394,24 @@ func searchPhotos(frm form.SearchPhotos, sess *entity.Session, resultCols string
|
|||
}
|
||||
} else {
|
||||
for _, l := range labels {
|
||||
labelIds = append(labelIds, l.ID)
|
||||
labelIDs = append(labelIDs, l.ID)
|
||||
|
||||
Db().Where("category_id = ?", l.ID).Find(&categories)
|
||||
|
||||
log.Tracef("search: label %s includes %d categories", txt.LogParamLower(l.LabelName), len(categories))
|
||||
|
||||
for _, category := range categories {
|
||||
labelIds = append(labelIds, category.LabelID)
|
||||
labelIDs = append(labelIDs, category.LabelID)
|
||||
}
|
||||
}
|
||||
|
||||
if wheres := LikeAnyKeyword("k.keyword", frm.Query); len(wheres) > 0 {
|
||||
for _, where := range wheres {
|
||||
s = s.Where("files.photo_id IN (SELECT pk.photo_id FROM keywords k JOIN photos_keywords pk ON k.id = pk.keyword_id WHERE (?)) OR "+
|
||||
"files.photo_id IN (SELECT pl.photo_id FROM photos_labels pl WHERE pl.uncertainty < 100 AND pl.label_id IN (?))", gorm.Expr(where), labelIds)
|
||||
"files.photo_id IN (SELECT pl.photo_id FROM photos_labels pl WHERE pl.uncertainty < 100 AND pl.label_id IN (?))", gorm.Expr(where), labelIDs)
|
||||
}
|
||||
} else {
|
||||
s = s.Where("files.photo_id IN (SELECT pl.photo_id FROM photos_labels pl WHERE pl.uncertainty < 100 AND pl.label_id IN (?))", labelIds)
|
||||
s = s.Where("files.photo_id IN (SELECT pl.photo_id FROM photos_labels pl WHERE pl.uncertainty < 100 AND pl.label_id IN (?))", labelIDs)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -751,8 +737,14 @@ func searchPhotos(frm form.SearchPhotos, sess *entity.Session, resultCols string
|
|||
s = s.Where("files.file_hash IN (?)", SplitOr(strings.ToLower(frm.Hash)))
|
||||
}
|
||||
|
||||
// Filter by location code.
|
||||
if txt.NotEmpty(frm.S2) {
|
||||
// Find photos near another?
|
||||
if txt.NotEmpty(frm.Near) {
|
||||
if qs, values, err := nearSQLCreator(frm.Near, frm.Dist); err != nil {
|
||||
return PhotoResults{}, 0, ErrNotFound
|
||||
} else {
|
||||
s = s.Where(qs, values...)
|
||||
}
|
||||
} else if txt.NotEmpty(frm.S2) { // Filter by location code.
|
||||
// S2 Cell ID.
|
||||
s2Min, s2Max := s2.PrefixedRange(frm.S2, s2.Level(frm.Dist))
|
||||
s = s.Where("photos.cell_id BETWEEN ? AND ?", s2Min, s2Max)
|
||||
|
|
|
|||
398
internal/entity/search/photos_filter_near_test.go
Normal file
398
internal/entity/search/photos_filter_near_test.go
Normal file
|
|
@ -0,0 +1,398 @@
|
|||
package search
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/photoprism/photoprism/internal/form"
|
||||
)
|
||||
|
||||
func TestPhotosFilterNear(t *testing.T) {
|
||||
t.Run("ps6sg6be2lvl0y24", func(t *testing.T) {
|
||||
var f form.SearchPhotos
|
||||
|
||||
f.Near = "ps6sg6be2lvl0y24"
|
||||
|
||||
photos, _, err := Photos(f)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.Equal(t, 13, len(photos))
|
||||
})
|
||||
t.Run("ps6sg6byk7wrbk30", func(t *testing.T) {
|
||||
var f form.SearchPhotos
|
||||
|
||||
f.Near = "ps6sg6byk7wrbk30"
|
||||
|
||||
photos, _, err := Photos(f)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.Equal(t, 29, len(photos))
|
||||
})
|
||||
t.Run("StartsWithPercent", func(t *testing.T) {
|
||||
var f form.SearchPhotos
|
||||
|
||||
f.Near = "%gold"
|
||||
_, _, err := Photos(f)
|
||||
|
||||
assert.Equal(t, err.Error(), "Not found")
|
||||
})
|
||||
t.Run("CenterPercent", func(t *testing.T) {
|
||||
var f form.SearchPhotos
|
||||
|
||||
f.Near = "I love % dog"
|
||||
_, _, err := Photos(f)
|
||||
|
||||
assert.Equal(t, err.Error(), "Not found")
|
||||
})
|
||||
t.Run("EndsWithPercent", func(t *testing.T) {
|
||||
var f form.SearchPhotos
|
||||
|
||||
f.Near = "sale%"
|
||||
|
||||
_, _, err := Photos(f)
|
||||
|
||||
assert.Equal(t, err.Error(), "Not found")
|
||||
})
|
||||
t.Run("StartsWithAmpersand", func(t *testing.T) {
|
||||
var f form.SearchPhotos
|
||||
|
||||
f.Near = "&IlikeFood"
|
||||
|
||||
_, _, err := Photos(f)
|
||||
|
||||
assert.Equal(t, err.Error(), "Not found")
|
||||
})
|
||||
t.Run("CenterAmpersand", func(t *testing.T) {
|
||||
var f form.SearchPhotos
|
||||
|
||||
f.Near = "Pets & Dogs"
|
||||
|
||||
_, _, err := Photos(f)
|
||||
|
||||
assert.Equal(t, err.Error(), "Not found")
|
||||
})
|
||||
t.Run("EndsWithAmpersand", func(t *testing.T) {
|
||||
var f form.SearchPhotos
|
||||
|
||||
f.Near = "Light&"
|
||||
|
||||
_, _, err := Photos(f)
|
||||
|
||||
assert.Equal(t, err.Error(), "Not found")
|
||||
})
|
||||
t.Run("StartsWithSingleQuote", func(t *testing.T) {
|
||||
var f form.SearchPhotos
|
||||
|
||||
f.Near = "'Family"
|
||||
|
||||
_, _, err := Photos(f)
|
||||
|
||||
assert.Equal(t, err.Error(), "Not found")
|
||||
})
|
||||
t.Run("CenterSingleQuote", func(t *testing.T) {
|
||||
var f form.SearchPhotos
|
||||
|
||||
f.Near = "Father's type"
|
||||
|
||||
_, _, err := Photos(f)
|
||||
|
||||
assert.Equal(t, err.Error(), "Not found")
|
||||
})
|
||||
t.Run("EndsWithSingleQuote", func(t *testing.T) {
|
||||
var f form.SearchPhotos
|
||||
|
||||
f.Near = "Ice Cream'"
|
||||
|
||||
_, _, err := Photos(f)
|
||||
|
||||
assert.Equal(t, err.Error(), "Not found")
|
||||
})
|
||||
t.Run("StartsWithAsterisk", func(t *testing.T) {
|
||||
var f form.SearchPhotos
|
||||
|
||||
f.Near = "*Forrest"
|
||||
|
||||
_, _, err := Photos(f)
|
||||
|
||||
assert.Equal(t, err.Error(), "Not found")
|
||||
})
|
||||
t.Run("CenterAsterisk", func(t *testing.T) {
|
||||
var f form.SearchPhotos
|
||||
|
||||
f.Near = "My*Kids"
|
||||
|
||||
_, _, err := Photos(f)
|
||||
|
||||
assert.Equal(t, err.Error(), "Not found")
|
||||
})
|
||||
t.Run("EndsWithAsterisk", func(t *testing.T) {
|
||||
var f form.SearchPhotos
|
||||
|
||||
f.Near = "Yoga***"
|
||||
|
||||
_, _, err := Photos(f)
|
||||
|
||||
assert.Equal(t, err.Error(), "Not found")
|
||||
})
|
||||
t.Run("StartsWithPipe", func(t *testing.T) {
|
||||
var f form.SearchPhotos
|
||||
|
||||
f.Near = "|Banana"
|
||||
|
||||
_, _, err := Photos(f)
|
||||
|
||||
assert.Equal(t, err.Error(), "Not found")
|
||||
})
|
||||
t.Run("CenterPipe", func(t *testing.T) {
|
||||
var f form.SearchPhotos
|
||||
|
||||
f.Near = "Red|Green"
|
||||
|
||||
_, _, err := Photos(f)
|
||||
|
||||
assert.Equal(t, err.Error(), "Not found")
|
||||
})
|
||||
t.Run("EndsWithPipe", func(t *testing.T) {
|
||||
var f form.SearchPhotos
|
||||
|
||||
f.Near = "Blue|"
|
||||
|
||||
_, _, err := Photos(f)
|
||||
|
||||
assert.Equal(t, err.Error(), "Not found")
|
||||
})
|
||||
t.Run("StartsWithNumber", func(t *testing.T) {
|
||||
var f form.SearchPhotos
|
||||
|
||||
f.Near = "345 Shirt"
|
||||
|
||||
_, _, err := Photos(f)
|
||||
|
||||
assert.Equal(t, err.Error(), "Not found")
|
||||
})
|
||||
t.Run("CenterNumber", func(t *testing.T) {
|
||||
var f form.SearchPhotos
|
||||
|
||||
f.Near = "type555 Blue"
|
||||
|
||||
_, _, err := Photos(f)
|
||||
|
||||
assert.Equal(t, err.Error(), "Not found")
|
||||
})
|
||||
t.Run("EndsWithNumber", func(t *testing.T) {
|
||||
var f form.SearchPhotos
|
||||
|
||||
f.Near = "Route 66"
|
||||
|
||||
_, _, err := Photos(f)
|
||||
|
||||
assert.Equal(t, err.Error(), "Not found")
|
||||
})
|
||||
}
|
||||
|
||||
func TestPhotosQueryNear(t *testing.T) {
|
||||
t.Run("ps6sg6be2lvl0y24", func(t *testing.T) {
|
||||
var f form.SearchPhotos
|
||||
|
||||
f.Query = "near:ps6sg6be2lvl0y24"
|
||||
|
||||
photos, _, err := Photos(f)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
assert.Equal(t, 13, len(photos))
|
||||
})
|
||||
t.Run("ps6sg6byk7wrbk30", func(t *testing.T) {
|
||||
var f form.SearchPhotos
|
||||
|
||||
f.Query = "near:ps6sg6byk7wrbk30"
|
||||
|
||||
photos, _, err := Photos(f)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.Equal(t, 29, len(photos))
|
||||
})
|
||||
t.Run("ps6sg6be2lvl0y24 pipe ps6sg6byk7wrbk30", func(t *testing.T) {
|
||||
var f form.SearchPhotos
|
||||
|
||||
f.Query = "near:ps6sg6be2lvl0y24|ps6sg6byk7wrbk30"
|
||||
|
||||
photos, _, err := Photos(f)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.Equal(t, 42, len(photos))
|
||||
})
|
||||
t.Run("StartsWithPercent", func(t *testing.T) {
|
||||
var f form.SearchPhotos
|
||||
|
||||
f.Query = "near:\"%gold\""
|
||||
|
||||
_, _, err := Photos(f)
|
||||
|
||||
assert.Equal(t, err.Error(), "Not found")
|
||||
})
|
||||
t.Run("CenterPercent", func(t *testing.T) {
|
||||
var f form.SearchPhotos
|
||||
|
||||
f.Query = "near:\"I love % dog\""
|
||||
|
||||
_, _, err := Photos(f)
|
||||
|
||||
assert.Equal(t, err.Error(), "Not found")
|
||||
})
|
||||
t.Run("EndsWithPercent", func(t *testing.T) {
|
||||
var f form.SearchPhotos
|
||||
|
||||
f.Query = "near:\"sale%\""
|
||||
|
||||
_, _, err := Photos(f)
|
||||
|
||||
assert.Equal(t, err.Error(), "Not found")
|
||||
})
|
||||
t.Run("StartsWithAmpersand", func(t *testing.T) {
|
||||
var f form.SearchPhotos
|
||||
|
||||
f.Query = "near:\"&IlikeFood\""
|
||||
|
||||
_, _, err := Photos(f)
|
||||
|
||||
assert.Equal(t, err.Error(), "Not found")
|
||||
})
|
||||
t.Run("CenterAmpersand", func(t *testing.T) {
|
||||
var f form.SearchPhotos
|
||||
|
||||
f.Query = "near:\"Pets & Dogs\""
|
||||
|
||||
_, _, err := Photos(f)
|
||||
|
||||
assert.Equal(t, err.Error(), "Not found")
|
||||
})
|
||||
t.Run("EndsWithAmpersand", func(t *testing.T) {
|
||||
var f form.SearchPhotos
|
||||
|
||||
f.Query = "near:\"Light&\""
|
||||
|
||||
_, _, err := Photos(f)
|
||||
|
||||
assert.Equal(t, err.Error(), "Not found")
|
||||
})
|
||||
t.Run("StartsWithSingleQuote", func(t *testing.T) {
|
||||
var f form.SearchPhotos
|
||||
|
||||
f.Query = "near:\"'Family\""
|
||||
|
||||
_, _, err := Photos(f)
|
||||
|
||||
assert.Equal(t, err.Error(), "Not found")
|
||||
})
|
||||
t.Run("CenterSingleQuote", func(t *testing.T) {
|
||||
var f form.SearchPhotos
|
||||
|
||||
f.Query = "near:\"Father's type\""
|
||||
|
||||
_, _, err := Photos(f)
|
||||
|
||||
assert.Equal(t, err.Error(), "Not found")
|
||||
})
|
||||
t.Run("EndsWithSingleQuote", func(t *testing.T) {
|
||||
var f form.SearchPhotos
|
||||
|
||||
f.Query = "near:\"Ice Cream'\""
|
||||
|
||||
_, _, err := Photos(f)
|
||||
|
||||
assert.Equal(t, err.Error(), "Not found")
|
||||
})
|
||||
t.Run("StartsWithAsterisk", func(t *testing.T) {
|
||||
var f form.SearchPhotos
|
||||
|
||||
f.Query = "near:\"*Forrest\""
|
||||
|
||||
_, _, err := Photos(f)
|
||||
|
||||
assert.Equal(t, err.Error(), "Not found")
|
||||
})
|
||||
t.Run("CenterAsterisk", func(t *testing.T) {
|
||||
var f form.SearchPhotos
|
||||
|
||||
f.Query = "near:\"My*Kids\""
|
||||
|
||||
_, _, err := Photos(f)
|
||||
|
||||
assert.Equal(t, err.Error(), "Not found")
|
||||
})
|
||||
t.Run("EndsWithAsterisk", func(t *testing.T) {
|
||||
var f form.SearchPhotos
|
||||
|
||||
f.Query = "near:\"Yoga***\""
|
||||
|
||||
_, _, err := Photos(f)
|
||||
|
||||
assert.Equal(t, err.Error(), "Not found")
|
||||
})
|
||||
t.Run("StartsWithPipe", func(t *testing.T) {
|
||||
var f form.SearchPhotos
|
||||
|
||||
f.Query = "near:\"|Banana\""
|
||||
|
||||
_, _, err := Photos(f)
|
||||
|
||||
assert.Equal(t, err.Error(), "Not found")
|
||||
})
|
||||
t.Run("CenterPipe", func(t *testing.T) {
|
||||
var f form.SearchPhotos
|
||||
|
||||
f.Query = "near:\"Red|Green\""
|
||||
|
||||
_, _, err := Photos(f)
|
||||
|
||||
assert.Equal(t, err.Error(), "Not found")
|
||||
})
|
||||
t.Run("EndsWithPipe", func(t *testing.T) {
|
||||
var f form.SearchPhotos
|
||||
|
||||
f.Query = "near:\"Blue|\""
|
||||
|
||||
_, _, err := Photos(f)
|
||||
|
||||
assert.Equal(t, err.Error(), "Not found")
|
||||
})
|
||||
t.Run("StartsWithNumber", func(t *testing.T) {
|
||||
var f form.SearchPhotos
|
||||
|
||||
f.Query = "near:\"345 Shirt\""
|
||||
|
||||
_, _, err := Photos(f)
|
||||
|
||||
assert.Equal(t, err.Error(), "Not found")
|
||||
})
|
||||
t.Run("CenterNumber", func(t *testing.T) {
|
||||
var f form.SearchPhotos
|
||||
|
||||
f.Query = "near:\"type555 Blue\""
|
||||
|
||||
_, _, err := Photos(f)
|
||||
|
||||
assert.Equal(t, err.Error(), "Not found")
|
||||
})
|
||||
t.Run("EndsWithNumber", func(t *testing.T) {
|
||||
var f form.SearchPhotos
|
||||
|
||||
f.Query = "near:\"Route 66\""
|
||||
|
||||
_, _, err := Photos(f)
|
||||
|
||||
assert.Equal(t, err.Error(), "Not found")
|
||||
})
|
||||
}
|
||||
|
|
@ -43,25 +43,6 @@ func UserPhotosGeo(frm form.SearchPhotosGeo, sess *entity.Session) (results GeoR
|
|||
return GeoResults{}, ErrBadRequest
|
||||
}
|
||||
|
||||
// Find photos near another?
|
||||
if txt.NotEmpty(frm.Near) {
|
||||
photo := Photo{}
|
||||
|
||||
// Find a nearby picture using the UID or return an empty result otherwise.
|
||||
if err = Db().First(&photo, "photo_uid = ?", frm.Near).Error; err != nil {
|
||||
log.Debugf("search: %s (find nearby)", err)
|
||||
return GeoResults{}, ErrNotFound
|
||||
}
|
||||
|
||||
// Set the S2 Cell ID to search for.
|
||||
frm.S2 = photo.CellID
|
||||
|
||||
// Set the search distance if unspecified.
|
||||
if frm.Dist <= 0 {
|
||||
frm.Dist = geo.DefaultDist
|
||||
}
|
||||
}
|
||||
|
||||
// Set default search distance.
|
||||
if frm.Dist <= 0 {
|
||||
frm.Dist = geo.DefaultDist
|
||||
|
|
@ -161,7 +142,20 @@ func UserPhotosGeo(frm form.SearchPhotosGeo, sess *entity.Session) (results GeoR
|
|||
s = s.Order("taken_at, photos.photo_uid")
|
||||
} else {
|
||||
// Sort by distance to UID.
|
||||
s = s.Order(gorm.Expr("(photos.photo_uid = ?) DESC, ABS(? - photos.photo_lat)+ABS(? - photos.photo_lng)", frm.Near, frm.Lat, frm.Lng))
|
||||
sq := ""
|
||||
var values []interface{}
|
||||
for item, value := range SplitOr(frm.Near) {
|
||||
if item == 0 {
|
||||
sq = "(photos.photo_uid IN (?"
|
||||
} else {
|
||||
sq = sq + ", ?"
|
||||
}
|
||||
values = append(values, value)
|
||||
}
|
||||
sq = sq + ")) DESC, ABS(? - photos.photo_lat)+ABS(? - photos.photo_lng)"
|
||||
values = append(values, frm.Lat)
|
||||
values = append(values, frm.Lng)
|
||||
s = s.Order(gorm.Expr(sq, values...))
|
||||
}
|
||||
|
||||
// Find specific UIDs only.
|
||||
|
|
@ -210,26 +204,27 @@ func UserPhotosGeo(frm form.SearchPhotosGeo, sess *entity.Session) (results GeoR
|
|||
if txt.NotEmpty(frm.Label) {
|
||||
var categories []entity.Category
|
||||
var labels []entity.Label
|
||||
var labelIds []uint
|
||||
var labelIDs []uint
|
||||
|
||||
if labelErr := Db().Where(AnySlug("label_slug", frm.Label, txt.Or)).Or(AnySlug("custom_slug", frm.Label, txt.Or)).Find(&labels).Error; len(labels) == 0 || labelErr != nil {
|
||||
log.Debugf("search: label %s not found", txt.LogParamLower(frm.Label))
|
||||
return GeoResults{}, nil
|
||||
} else {
|
||||
for _, l := range labels {
|
||||
labelIds = append(labelIds, l.ID)
|
||||
|
||||
Log("find categories", Db().Where("category_id = ?", l.ID).Find(&categories).Error)
|
||||
log.Debugf("search: label %s includes %d categories", txt.LogParamLower(l.LabelName), len(categories))
|
||||
|
||||
for _, category := range categories {
|
||||
labelIds = append(labelIds, category.LabelID)
|
||||
}
|
||||
}
|
||||
|
||||
s = s.Joins("JOIN photos_labels ON photos_labels.photo_id = files.photo_id AND photos_labels.uncertainty < 100 AND photos_labels.label_id IN (?)", labelIds).
|
||||
Group("photos.id, files.id")
|
||||
}
|
||||
|
||||
for _, l := range labels {
|
||||
labelIDs = append(labelIDs, l.ID)
|
||||
|
||||
Log("find categories", Db().Where("category_id = ?", l.ID).Find(&categories).Error)
|
||||
log.Debugf("search: label %s includes %d categories", txt.LogParamLower(l.LabelName), len(categories))
|
||||
|
||||
for _, category := range categories {
|
||||
labelIDs = append(labelIDs, category.LabelID)
|
||||
}
|
||||
}
|
||||
|
||||
s = s.Joins("JOIN photos_labels ON photos_labels.photo_id = files.photo_id AND photos_labels.uncertainty < 100 AND photos_labels.label_id IN (?)", labelIDs).
|
||||
Group("photos.id, files.id")
|
||||
|
||||
}
|
||||
|
||||
// Set search filters based on search terms.
|
||||
|
|
@ -310,7 +305,7 @@ func UserPhotosGeo(frm form.SearchPhotosGeo, sess *entity.Session) (results GeoR
|
|||
if frm.Query != "" {
|
||||
var categories []entity.Category
|
||||
var labels []entity.Label
|
||||
var labelIds []uint
|
||||
var labelIDs []uint
|
||||
|
||||
if labelsErr := Db().Where(AnySlug("custom_slug", frm.Query, " ")).Find(&labels).Error; len(labels) == 0 || labelsErr != nil {
|
||||
log.Tracef("search: label %s not found, using fuzzy search", txt.LogParamLower(frm.Query))
|
||||
|
|
@ -320,23 +315,23 @@ func UserPhotosGeo(frm form.SearchPhotosGeo, sess *entity.Session) (results GeoR
|
|||
}
|
||||
} else {
|
||||
for _, l := range labels {
|
||||
labelIds = append(labelIds, l.ID)
|
||||
labelIDs = append(labelIDs, l.ID)
|
||||
|
||||
Log("find categories", Db().Where("category_id = ?", l.ID).Find(&categories).Error)
|
||||
log.Tracef("search: label %s includes %d categories", txt.LogParamLower(l.LabelName), len(categories))
|
||||
|
||||
for _, category := range categories {
|
||||
labelIds = append(labelIds, category.LabelID)
|
||||
labelIDs = append(labelIDs, category.LabelID)
|
||||
}
|
||||
}
|
||||
|
||||
if wheres := LikeAnyKeyword("k.keyword", frm.Query); len(wheres) > 0 {
|
||||
for _, where := range wheres {
|
||||
s = s.Where("photos.id IN (SELECT pk.photo_id FROM keywords k JOIN photos_keywords pk ON k.id = pk.keyword_id WHERE (?)) OR "+
|
||||
"photos.id IN (SELECT pl.photo_id FROM photos_labels pl WHERE pl.uncertainty < 100 AND pl.label_id IN (?))", gorm.Expr(where), labelIds)
|
||||
"photos.id IN (SELECT pl.photo_id FROM photos_labels pl WHERE pl.uncertainty < 100 AND pl.label_id IN (?))", gorm.Expr(where), labelIDs)
|
||||
}
|
||||
} else {
|
||||
s = s.Where("photos.id IN (SELECT pl.photo_id FROM photos_labels pl WHERE pl.uncertainty < 100 AND pl.label_id IN (?))", labelIds)
|
||||
s = s.Where("photos.id IN (SELECT pl.photo_id FROM photos_labels pl WHERE pl.uncertainty < 100 AND pl.label_id IN (?))", labelIDs)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -639,8 +634,21 @@ func UserPhotosGeo(frm form.SearchPhotosGeo, sess *entity.Session) (results GeoR
|
|||
s = s.Where("photos.photo_private = 1")
|
||||
}
|
||||
|
||||
// Filter by location code.
|
||||
if txt.NotEmpty(frm.S2) {
|
||||
// Filter private pictures.
|
||||
if frm.Public {
|
||||
s = s.Where("photos.photo_private = 0")
|
||||
} else if frm.Private {
|
||||
s = s.Where("photos.photo_private = 1")
|
||||
}
|
||||
|
||||
// Find photos near another?
|
||||
if txt.NotEmpty(frm.Near) {
|
||||
if qs, values, err := nearSQLCreator(frm.Near, frm.Dist); err != nil {
|
||||
return GeoResults{}, ErrNotFound
|
||||
} else {
|
||||
s = s.Where(qs, values...)
|
||||
}
|
||||
} else if txt.NotEmpty(frm.S2) { // Filter by location code.
|
||||
// S2 Cell ID.
|
||||
s2Min, s2Max := s2.PrefixedRange(frm.S2, s2.Level(frm.Dist))
|
||||
s = s.Where("photos.cell_id BETWEEN ? AND ?", s2Min, s2Max)
|
||||
|
|
|
|||
|
|
@ -49,202 +49,150 @@ func TestPhotosGeoFilterNear(t *testing.T) {
|
|||
|
||||
assert.Equal(t, err.Error(), "Not found")
|
||||
})
|
||||
//TODO error
|
||||
/*t.Run("EndsWithPercent", func(t *testing.T) {
|
||||
t.Run("EndsWithPercent", func(t *testing.T) {
|
||||
var f form.SearchPhotosGeo
|
||||
|
||||
f.Near = "sale%"
|
||||
|
||||
photos, err := PhotosGeo(f)
|
||||
_, err := PhotosGeo(f)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.Len(t, photos, 0)
|
||||
assert.Equal(t, err.Error(), "Not found")
|
||||
})
|
||||
t.Run("StartsWithAmpersand", func(t *testing.T) {
|
||||
var f form.SearchPhotosGeo
|
||||
|
||||
f.Near = "&IlikeFood"
|
||||
|
||||
photos, err := PhotosGeo(f)
|
||||
_, err := PhotosGeo(f)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.Len(t, photos, 0)
|
||||
assert.Equal(t, err.Error(), "Not found")
|
||||
})
|
||||
t.Run("CenterAmpersand", func(t *testing.T) {
|
||||
var f form.SearchPhotosGeo
|
||||
|
||||
f.Near = "Pets & Dogs"
|
||||
|
||||
photos, err := PhotosGeo(f)
|
||||
_, err := PhotosGeo(f)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.Len(t, photos, 0)
|
||||
assert.Equal(t, err.Error(), "Not found")
|
||||
})
|
||||
t.Run("EndsWithAmpersand", func(t *testing.T) {
|
||||
var f form.SearchPhotosGeo
|
||||
|
||||
f.Near = "Light&"
|
||||
|
||||
photos, err := PhotosGeo(f)
|
||||
_, err := PhotosGeo(f)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.Len(t, photos, 0)
|
||||
assert.Equal(t, err.Error(), "Not found")
|
||||
})
|
||||
t.Run("StartsWithSingleQuote", func(t *testing.T) {
|
||||
var f form.SearchPhotosGeo
|
||||
|
||||
f.Near = "'Family"
|
||||
|
||||
photos, err := PhotosGeo(f)
|
||||
_, err := PhotosGeo(f)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.Len(t, photos, 0)
|
||||
assert.Equal(t, err.Error(), "Not found")
|
||||
})
|
||||
t.Run("CenterSingleQuote", func(t *testing.T) {
|
||||
var f form.SearchPhotosGeo
|
||||
|
||||
f.Near = "Father's type"
|
||||
|
||||
photos, err := PhotosGeo(f)
|
||||
_, err := PhotosGeo(f)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
assert.Len(t, photos, 0)
|
||||
assert.Equal(t, err.Error(), "Not found")
|
||||
})
|
||||
t.Run("EndsWithSingleQuote", func(t *testing.T) {
|
||||
var f form.SearchPhotosGeo
|
||||
|
||||
f.Near = "Ice Cream'"
|
||||
|
||||
photos, err := PhotosGeo(f)
|
||||
_, err := PhotosGeo(f)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.Len(t, photos, 0)
|
||||
assert.Equal(t, err.Error(), "Not found")
|
||||
})
|
||||
t.Run("StartsWithAsterisk", func(t *testing.T) {
|
||||
var f form.SearchPhotosGeo
|
||||
|
||||
f.Near = "*Forrest"
|
||||
|
||||
photos, err := PhotosGeo(f)
|
||||
_, err := PhotosGeo(f)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.Len(t, photos, 0)
|
||||
assert.Equal(t, err.Error(), "Not found")
|
||||
})
|
||||
t.Run("CenterAsterisk", func(t *testing.T) {
|
||||
var f form.SearchPhotosGeo
|
||||
|
||||
f.Near = "My*Kids"
|
||||
|
||||
photos, err := PhotosGeo(f)
|
||||
_, err := PhotosGeo(f)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.Len(t, photos, 0)
|
||||
assert.Equal(t, err.Error(), "Not found")
|
||||
})
|
||||
t.Run("EndsWithAsterisk", func(t *testing.T) {
|
||||
var f form.SearchPhotosGeo
|
||||
|
||||
f.Near = "Yoga***"
|
||||
|
||||
photos, err := PhotosGeo(f)
|
||||
_, err := PhotosGeo(f)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.Len(t, photos, 0)
|
||||
assert.Equal(t, err.Error(), "Not found")
|
||||
})
|
||||
t.Run("StartsWithPipe", func(t *testing.T) {
|
||||
var f form.SearchPhotosGeo
|
||||
|
||||
f.Near = "|Banana"
|
||||
|
||||
photos, err := PhotosGeo(f)
|
||||
_, err := PhotosGeo(f)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.Len(t, photos, 0)
|
||||
assert.Equal(t, err.Error(), "Not found")
|
||||
})
|
||||
t.Run("CenterPipe", func(t *testing.T) {
|
||||
var f form.SearchPhotosGeo
|
||||
|
||||
f.Near = "Red|Green"
|
||||
|
||||
photos, err := PhotosGeo(f)
|
||||
_, err := PhotosGeo(f)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
assert.Len(t, photos, 0)
|
||||
assert.Equal(t, err.Error(), "Not found")
|
||||
})
|
||||
t.Run("EndsWithPipe", func(t *testing.T) {
|
||||
var f form.SearchPhotosGeo
|
||||
|
||||
f.Near = "Blue|"
|
||||
|
||||
photos, err := PhotosGeo(f)
|
||||
_, err := PhotosGeo(f)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
assert.Len(t, photos, 0)
|
||||
assert.Equal(t, err.Error(), "Not found")
|
||||
})
|
||||
t.Run("StartsWithNumber", func(t *testing.T) {
|
||||
var f form.SearchPhotosGeo
|
||||
|
||||
f.Near = "345 Shirt"
|
||||
|
||||
photos, err := PhotosGeo(f)
|
||||
_, err := PhotosGeo(f)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.Len(t, photos, 0)
|
||||
assert.Equal(t, err.Error(), "Not found")
|
||||
})
|
||||
t.Run("CenterNumber", func(t *testing.T) {
|
||||
var f form.SearchPhotosGeo
|
||||
|
||||
f.Near = "type555 Blue"
|
||||
|
||||
photos, err := PhotosGeo(f)
|
||||
_, err := PhotosGeo(f)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.Len(t, photos, 0)
|
||||
assert.Equal(t, err.Error(), "Not found")
|
||||
})
|
||||
t.Run("EndsWithNumber", func(t *testing.T) {
|
||||
var f form.SearchPhotosGeo
|
||||
|
||||
f.Near = "Route 66"
|
||||
|
||||
photos, err := PhotosGeo(f)
|
||||
_, err := PhotosGeo(f)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.Len(t, photos, 0)
|
||||
})*/
|
||||
assert.Equal(t, err.Error(), "Not found")
|
||||
})
|
||||
}
|
||||
|
||||
func TestPhotosGeoQueryNear(t *testing.T) {
|
||||
|
|
@ -273,8 +221,7 @@ func TestPhotosGeoQueryNear(t *testing.T) {
|
|||
}
|
||||
assert.Len(t, photos, 26)
|
||||
})
|
||||
//TODO error
|
||||
/*t.Run("Ps6sg6be2lvl0y24PipePs6sg6byk7wrbk30", func(t *testing.T) {
|
||||
t.Run("Ps6sg6be2lvl0y24PipePs6sg6byk7wrbk30", func(t *testing.T) {
|
||||
var f form.SearchPhotosGeo
|
||||
|
||||
f.Query = "near:ps6sg6be2lvl0y24|ps6sg6byk7wrbk30"
|
||||
|
|
@ -284,224 +231,168 @@ func TestPhotosGeoQueryNear(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.Len(t, photos, 0)
|
||||
assert.Len(t, photos, 35)
|
||||
})
|
||||
t.Run("StartsWithPercent", func(t *testing.T) {
|
||||
var f form.SearchPhotosGeo
|
||||
|
||||
f.Query = "near:\"%gold\""
|
||||
|
||||
photos, err := PhotosGeo(f)
|
||||
_, err := PhotosGeo(f)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.Len(t, photos, 0)
|
||||
assert.Equal(t, err.Error(), "Not found")
|
||||
})
|
||||
t.Run("CenterPercent", func(t *testing.T) {
|
||||
var f form.SearchPhotosGeo
|
||||
|
||||
f.Query = "near:\"I love % dog\""
|
||||
|
||||
photos, err := PhotosGeo(f)
|
||||
_, err := PhotosGeo(f)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.Len(t, photos, 0)
|
||||
assert.Equal(t, err.Error(), "Not found")
|
||||
})
|
||||
t.Run("EndsWithPercent", func(t *testing.T) {
|
||||
var f form.SearchPhotosGeo
|
||||
|
||||
f.Query = "near:\"sale%\""
|
||||
|
||||
photos, err := PhotosGeo(f)
|
||||
_, err := PhotosGeo(f)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.Len(t, photos, 0)
|
||||
assert.Equal(t, err.Error(), "Not found")
|
||||
})
|
||||
t.Run("StartsWithAmpersand", func(t *testing.T) {
|
||||
var f form.SearchPhotosGeo
|
||||
|
||||
f.Query = "near:\"&IlikeFood\""
|
||||
|
||||
photos, err := PhotosGeo(f)
|
||||
_, err := PhotosGeo(f)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.Len(t, photos, 0)
|
||||
assert.Equal(t, err.Error(), "Not found")
|
||||
})
|
||||
t.Run("CenterAmpersand", func(t *testing.T) {
|
||||
var f form.SearchPhotosGeo
|
||||
|
||||
f.Query = "near:\"Pets & Dogs\""
|
||||
|
||||
photos, err := PhotosGeo(f)
|
||||
_, err := PhotosGeo(f)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.Len(t, photos, 0)
|
||||
assert.Equal(t, err.Error(), "Not found")
|
||||
})
|
||||
t.Run("EndsWithAmpersand", func(t *testing.T) {
|
||||
var f form.SearchPhotosGeo
|
||||
|
||||
f.Query = "near:\"Light&\""
|
||||
|
||||
photos, err := PhotosGeo(f)
|
||||
_, err := PhotosGeo(f)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.Len(t, photos, 0)
|
||||
assert.Equal(t, err.Error(), "Not found")
|
||||
})
|
||||
t.Run("StartsWithSingleQuote", func(t *testing.T) {
|
||||
var f form.SearchPhotosGeo
|
||||
|
||||
f.Query = "near:\"'Family\""
|
||||
|
||||
photos, err := PhotosGeo(f)
|
||||
_, err := PhotosGeo(f)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.Len(t, photos, 0)
|
||||
assert.Equal(t, err.Error(), "Not found")
|
||||
})
|
||||
t.Run("CenterSingleQuote", func(t *testing.T) {
|
||||
var f form.SearchPhotosGeo
|
||||
|
||||
f.Query = "near:\"Father's type\""
|
||||
|
||||
photos, err := PhotosGeo(f)
|
||||
_, err := PhotosGeo(f)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
assert.Len(t, photos, 0)
|
||||
assert.Equal(t, err.Error(), "Not found")
|
||||
})
|
||||
t.Run("EndsWithSingleQuote", func(t *testing.T) {
|
||||
var f form.SearchPhotosGeo
|
||||
|
||||
f.Query = "near:\"Ice Cream'\""
|
||||
|
||||
photos, err := PhotosGeo(f)
|
||||
_, err := PhotosGeo(f)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.Len(t, photos, 0)
|
||||
assert.Equal(t, err.Error(), "Not found")
|
||||
})
|
||||
t.Run("StartsWithAsterisk", func(t *testing.T) {
|
||||
var f form.SearchPhotosGeo
|
||||
|
||||
f.Query = "near:\"*Forrest\""
|
||||
|
||||
photos, err := PhotosGeo(f)
|
||||
_, err := PhotosGeo(f)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.Len(t, photos, 0)
|
||||
assert.Equal(t, err.Error(), "Not found")
|
||||
})
|
||||
t.Run("CenterAsterisk", func(t *testing.T) {
|
||||
var f form.SearchPhotosGeo
|
||||
|
||||
f.Query = "near:\"My*Kids\""
|
||||
|
||||
photos, err := PhotosGeo(f)
|
||||
_, err := PhotosGeo(f)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.Len(t, photos, 0)
|
||||
assert.Equal(t, err.Error(), "Not found")
|
||||
})
|
||||
t.Run("EndsWithAsterisk", func(t *testing.T) {
|
||||
var f form.SearchPhotosGeo
|
||||
|
||||
f.Query = "near:\"Yoga***\""
|
||||
|
||||
photos, err := PhotosGeo(f)
|
||||
_, err := PhotosGeo(f)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.Len(t, photos, 0)
|
||||
assert.Equal(t, err.Error(), "Not found")
|
||||
})
|
||||
t.Run("StartsWithPipe", func(t *testing.T) {
|
||||
var f form.SearchPhotosGeo
|
||||
|
||||
f.Query = "near:\"|Banana\""
|
||||
|
||||
photos, err := PhotosGeo(f)
|
||||
_, err := PhotosGeo(f)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.Len(t, photos, 0)
|
||||
assert.Equal(t, err.Error(), "Not found")
|
||||
})
|
||||
t.Run("CenterPipe", func(t *testing.T) {
|
||||
var f form.SearchPhotosGeo
|
||||
|
||||
f.Query = "near:\"Red|Green\""
|
||||
|
||||
photos, err := PhotosGeo(f)
|
||||
_, err := PhotosGeo(f)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
assert.Len(t, photos, 0)
|
||||
assert.Equal(t, err.Error(), "Not found")
|
||||
})
|
||||
t.Run("EndsWithPipe", func(t *testing.T) {
|
||||
var f form.SearchPhotosGeo
|
||||
|
||||
f.Query = "near:\"Blue|\""
|
||||
|
||||
photos, err := PhotosGeo(f)
|
||||
_, err := PhotosGeo(f)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.Len(t, photos, 0)
|
||||
assert.Equal(t, err.Error(), "Not found")
|
||||
})
|
||||
t.Run("StartsWithNumber", func(t *testing.T) {
|
||||
var f form.SearchPhotosGeo
|
||||
|
||||
f.Query = "near:\"345 Shirt\""
|
||||
|
||||
photos, err := PhotosGeo(f)
|
||||
_, err := PhotosGeo(f)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.Len(t, photos, 0)
|
||||
assert.Equal(t, err.Error(), "Not found")
|
||||
})
|
||||
t.Run("CenterNumber", func(t *testing.T) {
|
||||
var f form.SearchPhotosGeo
|
||||
|
||||
f.Query = "near:\"type555 Blue\""
|
||||
|
||||
photos, err := PhotosGeo(f)
|
||||
_, err := PhotosGeo(f)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.Len(t, photos, 0)
|
||||
assert.Equal(t, err.Error(), "Not found")
|
||||
})
|
||||
t.Run("EndsWithNumber", func(t *testing.T) {
|
||||
var f form.SearchPhotosGeo
|
||||
|
||||
f.Query = "near:\"Route 66\""
|
||||
|
||||
photos, err := PhotosGeo(f)
|
||||
_, err := PhotosGeo(f)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.Len(t, photos, 0)
|
||||
})*/
|
||||
assert.Equal(t, err.Error(), "Not found")
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ type SearchPhotos struct {
|
|||
Hidden bool `form:"hidden" notes:"Finds hidden content (broken or unsupported)"`
|
||||
Favorite string `form:"favorite" example:"favorite:true favorite:false" notes:"Finds favorite content"`
|
||||
Unsorted bool `form:"unsorted" notes:"Finds content that is not in an album"`
|
||||
Near string `form:"near" example:"near:pqbcf5j446s0futy" notes:"Finds nearby pictures (UID)"`
|
||||
Near string `form:"near" example:"near:pqbcf5j446s0futy" notes:"Finds nearby pictures (UID), separated by |"`
|
||||
S2 string `form:"s2" example:"s2:4799e370ca54c8b9" notes:"Position, specified as S2 Cell ID"`
|
||||
Olc string `form:"olc" example:"olc:8FWCHX7W+" notes:"Open Location Code (OLC)"`
|
||||
Lat float64 `form:"lat" example:"lat:41.894043" notes:"Position latitude (-90.0 to 90.0 deg)"`
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ type SearchPhotosGeo struct {
|
|||
Quality int `form:"quality" notes:"Minimum quality score (1-7)"`
|
||||
Face string `form:"face" notes:"Find pictures with a specific face ID, you can also specify yes, no, new, or a face type"`
|
||||
Faces string `form:"faces" example:"faces:yes faces:3" notes:"Minimum number of detected faces (yes means 1)"` // Find or exclude faces if detected.
|
||||
Near string `form:"near" example:"near:pqbcf5j446s0futy" notes:"Finds nearby pictures (UID)"`
|
||||
Near string `form:"near" example:"near:pqbcf5j446s0futy" notes:"Finds nearby pictures (UID), separated by |"`
|
||||
S2 string `form:"s2" example:"s2:4799e370ca54c8b9" notes:"Position, specified as S2 Cell ID"`
|
||||
Olc string `form:"olc" example:"olc:8FWCHX7W+" notes:"Open Location Code (OLC)"`
|
||||
Lat float64 `form:"lat" example:"lat:41.894043" notes:"Position latitude (-90.0 to 90.0 deg)"`
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue