Backend: Update label photo count and refactor entity fixtures

Signed-off-by: Michael Mayer <michael@liquidbytes.net>
This commit is contained in:
Michael Mayer 2020-05-10 19:43:49 +02:00
parent 406737e180
commit 8ccaaff4e5
32 changed files with 398 additions and 304 deletions

View file

@ -131,15 +131,16 @@ func (c *Config) ClientConfig() ClientConfig {
Take(&position)
var count = struct {
Photos uint `json:"photos"`
Hidden uint `json:"hidden"`
Favorites uint `json:"favorites"`
Private uint `json:"private"`
Stories uint `json:"stories"`
Labels uint `json:"labels"`
Albums uint `json:"albums"`
Countries uint `json:"countries"`
Places uint `json:"places"`
Photos uint `json:"photos"`
Hidden uint `json:"hidden"`
Favorites uint `json:"favorites"`
Private uint `json:"private"`
Stories uint `json:"stories"`
Albums uint `json:"albums"`
Countries uint `json:"countries"`
Places uint `json:"places"`
Labels uint `json:"labels"`
LabelMaxPhotos uint `json:"labelMaxPhotos"`
}{}
db.Table("photos").
@ -148,8 +149,10 @@ func (c *Config) ClientConfig() ClientConfig {
Take(&count)
db.Table("labels").
Select("COUNT(*) AS labels").
Where("(label_priority >= 0 || label_favorite = 1) && deleted_at IS NULL").
Select("MAX(photo_count) as label_max_photos, COUNT(*) AS labels").
Where("photo_count > 0").
Where("deleted_at IS NULL").
Where("(label_priority >= 0 || label_favorite = 1)").
Take(&count)
db.Table("albums").

View file

@ -5,7 +5,9 @@ import (
"time"
)
var AccountFixtures = map[string]Account{
type AccountMap map[string]Account
var AccountFixtures = AccountMap{
"webdav-dummy": {
ID: 1000000,
AccName: "Test Account",

View file

@ -4,7 +4,9 @@ import (
"time"
)
var AlbumFixtures = map[string]Album{
type AlbumMap map[string]Album
var AlbumFixtures = AlbumMap{
"christmas2030": {
ID: 1000000,
CoverUUID: "",

View file

@ -4,7 +4,9 @@ import (
"time"
)
var CameraFixtures = map[string]Camera{
type CameraMap map[string]Camera
var CameraFixtures = CameraMap{
"apple-iphone-se": {
ID: 1000000,
CameraSlug: "apple-iphone-se",

View file

@ -1,17 +1,17 @@
package entity
var CategoryFixtures = map[string]Category{
"1": {
"flower_landscape": {
LabelID: 1000001,
Label: LabelFixtures.Pointer("flower"),
CategoryID: 1000000,
Label: &LabelFixtureFlower,
Category: &LabelFixtureLandscape,
Category: LabelFixtures.Pointer("landscape"),
},
}
// CreateCategoryFixtures inserts known entities into the database for testing.
func CreateCategoryFixtures() {
for _, entity := range KeywordFixtures {
for _, entity := range CategoryFixtures {
Db().Create(&entity)
}
}

View file

@ -1,6 +1,8 @@
package entity
var CountryFixtures = map[string]Country{
type CountryMap map[string]Country
var CountryFixtures = CountryMap{
"apple-iphone-se": {
ID: "de",
CountrySlug: "germany",

View file

@ -1,6 +1,26 @@
package entity
var DescriptionFixtures = map[string]Description{
type DescriptionMap map[string]Description
func (m DescriptionMap) Get(name string, photoId uint) Description {
if result, ok := m[name]; ok {
result.PhotoID = photoId
return result
}
return Description{PhotoID: photoId}
}
func (m DescriptionMap) Pointer(name string, photoId uint) *Description {
if result, ok := m[name]; ok {
result.PhotoID = photoId
return &result
}
return &Description{PhotoID: photoId}
}
var DescriptionFixtures = DescriptionMap{
"lake": {
PhotoID: 1000000,
PhotoDescription: "photo description",
@ -12,11 +32,3 @@ var DescriptionFixtures = map[string]Description{
PhotoLicense: "MIT",
},
}
var DescriptionFixtureLake = DescriptionFixtures["lake"]
// CreateDescriptionFixtures inserts known entities into the database for testing.
func CreateDescriptionFixtures() {
for _, entity := range DescriptionFixtures {
Db().Create(&entity)
}
}

View file

@ -7,7 +7,7 @@ import (
var FileFixtures = map[string]File{
"exampleFileName.jpg": {
ID: 1000000,
Photo: &PhotoFixture19800101_000002_D640C559,
Photo: PhotoFixtures.Pointer("19800101_000002_D640C559"),
PhotoID: 1000000,
PhotoUUID: "pt9jtdre2lvl0yh7",
FileUUID: "ft8es39w45bnlqdw",
@ -46,7 +46,7 @@ var FileFixtures = map[string]File{
},
"exampleDNGFile.dng": {
ID: 1000001,
Photo: &PhotoFixturePhoto01,
Photo: PhotoFixtures.Pointer("Photo01"),
PhotoID: 1000001,
PhotoUUID: "pt9jtdre2lvl0yh8",
FileUUID: "ft9es39w45bnlqdw",
@ -85,7 +85,7 @@ var FileFixtures = map[string]File{
},
"exampleXmpFile.xmp": {
ID: 1000002,
Photo: &PhotoFixturePhoto01,
Photo: PhotoFixtures.Pointer("Photo01"),
PhotoID: 1000001,
PhotoUUID: "pt9jtdre2lvl0yh8",
FileUUID: "ft1es39w45bnlqdw",
@ -124,7 +124,7 @@ var FileFixtures = map[string]File{
},
"bridge.jpg": {
ID: 1000003,
Photo: &PhotoFixturePhoto04,
Photo: PhotoFixtures.Pointer("Photo04"),
PhotoID: 1000004,
PhotoUUID: "pt9jtdre2lvl0y11",
FileUUID: "ft2es39w45bnlqdw",
@ -163,7 +163,7 @@ var FileFixtures = map[string]File{
},
"reunion.jpg": {
ID: 1000004,
Photo: &PhotoFixturePhoto05,
Photo: PhotoFixtures.Pointer("Photo05"),
PhotoID: 1000005,
PhotoUUID: "pt9jtdre2lvl0y12",
FileUUID: "ft3es39w45bnlqdw",

View file

@ -14,8 +14,6 @@ func CreateTestFixtures() {
CreateKeywordFixtures()
CreatePhotoKeywordFixtures()
CreateCategoryFixtures()
CreatePhotoLabelFixtures()
CreateLocationFixtures()
CreatePlaceFixtures()
CreateDescriptionFixtures()
}

View file

@ -1,6 +1,8 @@
package entity
var KeywordFixtures = map[string]Keyword{
type KeywordMap map[string]Keyword
var KeywordFixtures = KeywordMap{
"bridge": {
ID: 1000000,
Keyword: "bridge",

View file

@ -23,7 +23,7 @@ type Label struct {
LabelNotes string `gorm:"type:text;"`
LabelCategories []*Label `gorm:"many2many:categories;association_jointable_foreignkey:category_id"`
Links []Link `gorm:"foreignkey:ShareUUID;association_foreignkey:LabelUUID"`
PhotoCount int
PhotoCount int `gorm:"default:1"`
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt *time.Time `sql:"index"`
@ -55,6 +55,7 @@ func NewLabel(name string, priority int) *Label {
CustomSlug: labelSlug,
LabelName: labelName,
LabelPriority: priority,
PhotoCount: 1,
}
return result

View file

@ -4,7 +4,34 @@ import (
"time"
)
var LabelFixtures = map[string]Label{
type LabelMap map[string]Label
func (m LabelMap) Get(name string) Label {
if result, ok := m[name]; ok {
return result
}
return *NewLabel(name, 0)
}
func (m LabelMap) Pointer(name string) *Label {
if result, ok := m[name]; ok {
return &result
}
return NewLabel(name, 0)
}
func (m LabelMap) PhotoLabel(photoId uint, labelName string, uncertainty int, source string) PhotoLabel {
label := m.Get(labelName)
photoLabel := NewPhotoLabel(photoId, label.ID, uncertainty, source)
photoLabel.Label = &label
return *photoLabel
}
var LabelFixtures = LabelMap{
"landscape": {
ID: 1000000,
LabelUUID: "lt9k3pw1wowuy3c2",
@ -15,6 +42,7 @@ var LabelFixtures = map[string]Label{
LabelFavorite: true,
LabelDescription: "",
LabelNotes: "",
PhotoCount: 1,
LabelCategories: []*Label{},
Links: []Link{},
CreatedAt: time.Now(),
@ -32,6 +60,7 @@ var LabelFixtures = map[string]Label{
LabelFavorite: true,
LabelDescription: "",
LabelNotes: "",
PhotoCount: 2,
LabelCategories: []*Label{},
Links: []Link{},
CreatedAt: time.Now(),
@ -49,6 +78,7 @@ var LabelFixtures = map[string]Label{
LabelFavorite: false,
LabelDescription: "",
LabelNotes: "",
PhotoCount: 3,
LabelCategories: []*Label{},
Links: []Link{},
CreatedAt: time.Now(),
@ -66,6 +96,7 @@ var LabelFixtures = map[string]Label{
LabelFavorite: true,
LabelDescription: "",
LabelNotes: "",
PhotoCount: 4,
LabelCategories: []*Label{},
Links: []Link{},
CreatedAt: time.Now(),
@ -83,6 +114,7 @@ var LabelFixtures = map[string]Label{
LabelFavorite: true,
LabelDescription: "",
LabelNotes: "",
PhotoCount: 5,
LabelCategories: []*Label{},
Links: []Link{},
CreatedAt: time.Now(),
@ -100,6 +132,7 @@ var LabelFixtures = map[string]Label{
LabelFavorite: false,
LabelDescription: "",
LabelNotes: "",
PhotoCount: 1,
LabelCategories: []*Label{},
Links: []Link{},
CreatedAt: time.Now(),
@ -117,6 +150,7 @@ var LabelFixtures = map[string]Label{
LabelFavorite: false,
LabelDescription: "",
LabelNotes: "",
PhotoCount: 1,
LabelCategories: []*Label{},
Links: []Link{},
CreatedAt: time.Now(),
@ -126,12 +160,6 @@ var LabelFixtures = map[string]Label{
},
}
var LabelFixtureLandscape = LabelFixtures["landscape"]
var LabelFixtureFlower = LabelFixtures["flower"]
var LabelFixtureCake = LabelFixtures["cake"]
var LabelFixtureCow = LabelFixtures["cow"]
var LabelFixtureUpdatePhotoLabel = LabelFixtures["updatePhotoLabel"]
// CreateLabelFixtures inserts known entities into the database for testing.
func CreateLabelFixtures() {
for _, entity := range LabelFixtures {

View file

@ -53,7 +53,8 @@ func TestLabel_SetName(t *testing.T) {
}
func TestLabel_FirstOrCreate(t *testing.T) {
r := LabelFixtureFlower.FirstOrCreate()
label := LabelFixtures.Get("flower")
r := label.FirstOrCreate()
assert.Equal(t, "Flower", r.LabelName)
assert.Equal(t, "flower", r.LabelSlug)
}
@ -100,7 +101,7 @@ func TestLabel_Update(t *testing.T) {
})
t.Run("update name and Categories", func(t *testing.T) {
classifyLabel := &classify.Label{Name: "classify", Uncertainty: 30, Source: "manual", Priority: 5, Categories: []string{"flower", "plant"}}
Label := &Label{LabelName: "label34", LabelSlug: "labelslug2", CustomSlug: "labelslug2", LabelPriority: 5, LabelCategories: []*Label{&LabelFixtureFlower}}
Label := &Label{LabelName: "label34", LabelSlug: "labelslug2", CustomSlug: "labelslug2", LabelPriority: 5, LabelCategories: []*Label{LabelFixtures.Pointer("flower")}}
assert.Equal(t, 5, Label.LabelPriority)
assert.Equal(t, "labelslug2", Label.LabelSlug)

View file

@ -4,7 +4,9 @@ import "time"
var date = time.Date(2050, 3, 6, 2, 6, 51, 0, time.UTC)
var LinkFixtures = map[string]Link{
type LinkMap map[string]Link
var LinkFixtures = LinkMap{
"1jxf3jfn2k": {
LinkToken: "1jxf3jfn2k",
LinkPassword: "somepassword",

View file

@ -2,21 +2,31 @@ package entity
import "time"
var LocationFixtures = map[string]Location{
type LocationMap map[string]Location
var LocationFixtures = LocationMap{
"mexico": {
ID: "1000000",
PlaceID: "1000000",
ID: "85d1ea7d382c",
PlaceID: PlaceFixtures.Get("teotihuacan").ID,
LocName: "Adosada Platform",
LocCategory: "tourism",
Place: &PlaceFixtureTeotihuacan,
Place: PlaceFixtures.Pointer("teotihuacan"),
LocSource: "places",
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
},
"caravan park": {
ID: "1000001",
PlaceID: "",
Place: nil,
ID: "1ef75a71a36c",
PlaceID: "1ef75a71a36c",
Place: &Place{
ID: "1ef75a71a36",
LocLabel: "Mandeni, KwaZulu-Natal, South Africa",
LocCity: "Mandeni",
LocState: "KwaZulu-Natal",
LocCountry: "za",
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
},
LocName: "Lobotes Caravan Park",
LocCategory: "camping",
LocSource: "manual",
@ -24,9 +34,9 @@ var LocationFixtures = map[string]Location{
UpdatedAt: time.Now(),
},
"zinkwazi": {
ID: "1000002",
PlaceID: "",
Place: &PlaceFixtureZinkwazi,
ID: "1ef744d1e28c",
PlaceID: PlaceFixtures.Get("zinkwazi").ID,
Place: PlaceFixtures.Pointer("zinkwazi"),
LocName: "Zinkwazi Beach",
LocCategory: "",
LocSource: "places",
@ -35,10 +45,6 @@ var LocationFixtures = map[string]Location{
},
}
var LocationFixtureMexico = LocationFixtures["mexico"]
var LocationFixtureCaravanPark = LocationFixtures["caravan park"]
var LocationFixtureZinkawzi = LocationFixtures["zinkwazi"]
// CreateLocationFixtures inserts known entities into the database for testing.
func CreateLocationFixtures() {
for _, entity := range LocationFixtures {

View file

@ -11,7 +11,7 @@ func TestNewLocation(t *testing.T) {
l := NewLocation(1, 1)
l.LocCategory = "restaurant"
l.LocName = "LocationName"
l.Place = &PlaceFixtureZinkwazi
l.Place = PlaceFixtures.Pointer("zinkwazi")
l.LocSource = "places"
assert.Equal(t, "restaurant", l.Category())
@ -34,19 +34,22 @@ func TestNewLocation(t *testing.T) {
}
func TestLocation_Keywords(t *testing.T) {
t.Run("location with place", func(t *testing.T) {
r := LocationFixtureMexico.Keywords()
t.Run("mexico", func(t *testing.T) {
m := LocationFixtures["mexico"]
r := m.Keywords()
assert.Equal(t, []string{"adosada", "ancient", "mexico", "platform", "pyramid", "teotihuacán", "tourism"}, r)
})
t.Run("location without place", func(t *testing.T) {
r := LocationFixtureCaravanPark.Keywords()
assert.Nil(t, r)
t.Run("caravan park", func(t *testing.T) {
m := LocationFixtures["caravan park"]
r := m.Keywords()
assert.Equal(t, []string{"camping", "caravan", "kwazulu-natal", "lobotes", "mandeni", "park", "south-africa"}, r)
})
}
func TestLocation_Find(t *testing.T) {
t.Run("place in db", func(t *testing.T) {
r := LocationFixtureMexico.Find("")
m := LocationFixtures["mexico"]
r := m.Find("")
assert.Nil(t, r)
})
t.Run("invalid api", func(t *testing.T) {

View file

@ -9,7 +9,7 @@ var PhotoAlbumFixtures = map[string]PhotoAlbum{
Order: 0,
CreatedAt: time.Date(2020, 3, 6, 2, 6, 51, 0, time.UTC),
UpdatedAt: time.Date(2020, 3, 28, 14, 6, 0, 0, time.UTC),
Photo: &PhotoFixture19800101_000002_D640C559,
Photo: PhotoFixtures.Pointer("19800101_000002_D640C559"),
Album: &AlbumFixtureHoliday2030,
},
"2": {
@ -18,7 +18,7 @@ var PhotoAlbumFixtures = map[string]PhotoAlbum{
Order: 0,
CreatedAt: time.Date(2020, 2, 6, 2, 6, 51, 0, time.UTC),
UpdatedAt: time.Date(2020, 4, 28, 14, 6, 0, 0, time.UTC),
Photo: &PhotoFixturePhoto04,
Photo: PhotoFixtures.Pointer("Photo04"),
Album: &AlbumFixtureBerlin2019,
},
}

View file

@ -6,7 +6,25 @@ import (
var editTime = time.Date(2008, 1, 1, 0, 0, 0, 0, time.UTC)
var PhotoFixtures = map[string]Photo{
type PhotoMap map[string]Photo
func (m PhotoMap) Get(name string) Photo {
if result, ok := m[name]; ok {
return result
}
return Photo{PhotoName: name}
}
func (m PhotoMap) Pointer(name string) *Photo {
if result, ok := m[name]; ok {
return &result
}
return &Photo{PhotoName: name}
}
var PhotoFixtures = PhotoMap{
"19800101_000002_D640C559": {
ID: 1000000,
PhotoUUID: "pt9jtdre2lvl0yh7",
@ -40,7 +58,7 @@ var PhotoFixtures = map[string]Photo{
PhotoCountry: "zz",
PhotoYear: 2790,
PhotoMonth: 2,
Description: DescriptionFixtureLake,
Description: DescriptionFixtures.Get("lake", 1000000),
DescriptionSrc: "",
Camera: &CameraFixtureEOS6D,
Lens: nil,
@ -50,7 +68,10 @@ var PhotoFixtures = map[string]Photo{
Keywords: []Keyword{},
Albums: []Album{},
Files: []File{},
Labels: []PhotoLabel{},
Labels: []PhotoLabel{
LabelFixtures.PhotoLabel(1000000, "flower", 38, "image"),
LabelFixtures.PhotoLabel(1000000, "cake", 38, "manual"),
},
CreatedAt: time.Date(2009, 1, 1, 0, 0, 0, 0, time.UTC),
UpdatedAt: time.Date(2008, 1, 1, 0, 0, 0, 0, time.UTC),
EditedAt: nil,
@ -148,7 +169,7 @@ var PhotoFixtures = map[string]Photo{
Keywords: []Keyword{},
Albums: []Album{},
Files: []File{},
Labels: []PhotoLabel{},
Labels: []PhotoLabel{LabelFixtures.PhotoLabel(1000002, "cake", 20, "image")},
CreatedAt: time.Date(2009, 1, 1, 0, 0, 0, 0, time.UTC),
UpdatedAt: time.Date(2008, 1, 1, 0, 0, 0, 0, time.UTC),
EditedAt: nil,
@ -197,7 +218,10 @@ var PhotoFixtures = map[string]Photo{
Keywords: []Keyword{},
Albums: []Album{},
Files: []File{},
Labels: []PhotoLabel{},
Labels: []PhotoLabel{
LabelFixtures.PhotoLabel(1000003, "cow", 20, "image"),
LabelFixtures.PhotoLabel(1000003, "updatePhotoLabel", 20, "manual"),
},
CreatedAt: time.Date(2009, 1, 1, 0, 0, 0, 0, time.UTC),
UpdatedAt: time.Date(2008, 1, 1, 0, 0, 0, 0, time.UTC),
EditedAt: nil,
@ -246,7 +270,7 @@ var PhotoFixtures = map[string]Photo{
Keywords: []Keyword{},
Albums: []Album{},
Files: []File{},
Labels: []PhotoLabel{},
Labels: []PhotoLabel{LabelFixtures.PhotoLabel(1000004, "batchdelete", 20, "image")},
CreatedAt: time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC),
UpdatedAt: time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC),
EditedAt: nil,
@ -295,7 +319,7 @@ var PhotoFixtures = map[string]Photo{
Keywords: []Keyword{},
Albums: []Album{},
Files: []File{},
Labels: []PhotoLabel{},
Labels: []PhotoLabel{LabelFixtures.PhotoLabel(1000005, "updateLabel", 20, "image")},
CreatedAt: time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC),
UpdatedAt: time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC),
EditedAt: nil,
@ -344,7 +368,7 @@ var PhotoFixtures = map[string]Photo{
Keywords: []Keyword{},
Albums: []Album{},
Files: []File{},
Labels: []PhotoLabel{},
Labels: []PhotoLabel{LabelFixtures.PhotoLabel(1000006, "updatePhotoLabel", 20, "image")},
CreatedAt: time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC),
UpdatedAt: time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC),
EditedAt: nil,
@ -393,7 +417,7 @@ var PhotoFixtures = map[string]Photo{
Keywords: []Keyword{},
Albums: []Album{},
Files: []File{},
Labels: []PhotoLabel{},
Labels: []PhotoLabel{LabelFixtures.PhotoLabel(1000007, "landscape", 20, "image")},
CreatedAt: time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC),
UpdatedAt: time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC),
EditedAt: &editTime,
@ -442,7 +466,7 @@ var PhotoFixtures = map[string]Photo{
Keywords: []Keyword{},
Albums: []Album{},
Files: []File{},
Labels: []PhotoLabel{},
Labels: []PhotoLabel{LabelFixtures.PhotoLabel(1000008, "landscape", 20, "image")},
CreatedAt: time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC),
UpdatedAt: time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC),
EditedAt: nil,
@ -450,15 +474,6 @@ var PhotoFixtures = map[string]Photo{
},
}
var PhotoFixture19800101_000002_D640C559 = PhotoFixtures["19800101_000002_D640C559"]
var PhotoFixturePhoto04 = PhotoFixtures["Photo04"]
var PhotoFixturePhoto01 = PhotoFixtures["Photo01"]
var PhotoFixturePhoto05 = PhotoFixtures["Photo05"]
var PhotoFixturePhoto03 = PhotoFixtures["Photo03"]
var PhotoFixturePhoto06 = PhotoFixtures["Photo06"]
var PhotoFixturePhoto07 = PhotoFixtures["Photo07"]
var PhotoFixturePhoto08 = PhotoFixtures["Photo08"]
// CreatePhotoFixtures inserts known entities into the database for testing.
func CreatePhotoFixtures() {
for _, entity := range PhotoFixtures {

View file

@ -1,14 +1,14 @@
package entity
var PhotoKeywordFixtures = map[string]PhotoKeyword{
type PhotoKeywordMap map[string]PhotoKeyword
var PhotoKeywordFixtures = PhotoKeywordMap{
"1": {
PhotoID: 1000004,
KeywordID: 1000000,
},
}
var PhotoKeywordFixture1 = PhotoKeywordFixtures["1"]
// CreatePhotoKeywordFixtures inserts known entities into the database for testing.
func CreatePhotoKeywordFixtures() {
for _, entity := range PhotoKeywordFixtures {

View file

@ -22,6 +22,7 @@ func TestPhotoKeyword_TableName(t *testing.T) {
}
func TestPhotoKeywords_FirstOrCreate(t *testing.T) {
r := PhotoKeywordFixture1.FirstOrCreate()
m := PhotoKeywordFixtures["1"]
r := m.FirstOrCreate()
assert.Equal(t, uint(0xf4244), r.PhotoID)
}

View file

@ -1,37 +0,0 @@
package entity
var PhotoLabelFixtures = map[string]PhotoLabel{
"1": {
PhotoID: 1000000,
LabelID: 1000001,
LabelSrc: "image",
Uncertainty: 38,
Photo: &PhotoFixture19800101_000002_D640C559,
Label: &LabelFixtureFlower,
},
"2": {
PhotoID: 1000000,
LabelID: 1000002,
LabelSrc: "manual",
Uncertainty: 38,
Photo: &PhotoFixture19800101_000002_D640C559,
Label: &LabelFixtureCake,
},
"3": {
PhotoID: 1000003,
LabelID: 1000006,
LabelSrc: "manual",
Uncertainty: 20,
Photo: &PhotoFixturePhoto03,
Label: &LabelFixtureUpdatePhotoLabel,
},
}
var PhotoLabelFixture1 = PhotoLabelFixtures["1"]
// CreatePhotoLabelFixtures inserts known entities into the database for testing.
func CreatePhotoLabelFixtures() {
for _, entity := range PhotoLabelFixtures {
Db().Create(&entity)
}
}

View file

@ -23,13 +23,15 @@ func TestPhotoLabel_TableName(t *testing.T) {
}
func TestPhotoLabel_FirstOrCreate(t *testing.T) {
r := PhotoLabelFixture1.FirstOrCreate()
assert.Equal(t, uint(0xf4240), r.PhotoID)
pl := LabelFixtures.PhotoLabel(1000000, "flower", 38, "image")
r := pl.FirstOrCreate()
assert.Equal(t, uint(1000000), r.PhotoID)
}
func TestPhotoLabel_ClassifyLabel(t *testing.T) {
t.Run("success", func(t *testing.T) {
r := PhotoLabelFixture1.ClassifyLabel()
pl := LabelFixtures.PhotoLabel(1000000, "flower", 38, "image")
r := pl.ClassifyLabel()
assert.Equal(t, "Flower", r.Name)
assert.Equal(t, 38, r.Uncertainty)
assert.Equal(t, "image", r.Source)

View file

@ -7,15 +7,15 @@ import (
func TestPhoto_QualityScore(t *testing.T) {
t.Run("PhotoFixture19800101_000002_D640C559", func(t *testing.T) {
assert.Equal(t, 4, PhotoFixture19800101_000002_D640C559.QualityScore())
assert.Equal(t, 4, PhotoFixtures.Pointer("19800101_000002_D640C559").QualityScore())
})
t.Run("PhotoFixturePhoto01 - favorite true - taken at before 2008", func(t *testing.T) {
assert.Equal(t, 7, PhotoFixturePhoto01.QualityScore())
assert.Equal(t, 7, PhotoFixtures.Pointer("Photo01").QualityScore())
})
t.Run("PhotoFixturePhoto06 - taken at after 2012 - resolution 2", func(t *testing.T) {
assert.Equal(t, 4, PhotoFixturePhoto06.QualityScore())
assert.Equal(t, 4, PhotoFixtures.Pointer("Photo06").QualityScore())
})
t.Run("PhotoFixturePhoto07 - score < 3 bit edited", func(t *testing.T) {
assert.Equal(t, 3, PhotoFixturePhoto07.QualityScore())
assert.Equal(t, 3, PhotoFixtures.Pointer("Photo07").QualityScore())
})
}

View file

@ -91,7 +91,8 @@ func TestPhoto_Save(t *testing.T) {
}
})
t.Run("existing photo", func(t *testing.T) {
err := PhotoFixture19800101_000002_D640C559.Save()
m := PhotoFixtures.Get("19800101_000002_D640C559")
err := m.Save()
if err != nil {
t.Fatal(err)
}
@ -100,13 +101,13 @@ func TestPhoto_Save(t *testing.T) {
func TestPhoto_ClassifyLabels(t *testing.T) {
t.Run("new photo", func(t *testing.T) {
m := PhotoFixturePhoto01
m := PhotoFixtures.Get("Photo01")
Db().Set("gorm:auto_preload", true).Model(&m).Related(&m.Labels)
labels := m.ClassifyLabels()
assert.Empty(t, labels)
})
t.Run("existing photo", func(t *testing.T) {
m := PhotoFixture19800101_000002_D640C559
m := PhotoFixtures.Get("19800101_000002_D640C559")
Db().Set("gorm:auto_preload", true).Model(&m).Related(&m.Labels)
labels := m.ClassifyLabels()
assert.LessOrEqual(t, 2, labels.Len())

View file

@ -2,9 +2,27 @@ package entity
import "time"
var PlaceFixtures = map[string]Place{
type PlacesMap map[string]Place
func (m PlacesMap) Get(name string) Place {
if result, ok := m[name]; ok {
return result
}
return UnknownPlace
}
func (m PlacesMap) Pointer(name string) *Place {
if result, ok := m[name]; ok {
return &result
}
return &UnknownPlace
}
var PlaceFixtures = PlacesMap{
"teotihuacan": {
ID: "1000000",
ID: "85d1ea7d382c",
LocLabel: "Teotihuacán, Mexico, Mexico",
LocCity: "Teotihuacán",
LocState: "Mexico",
@ -12,11 +30,12 @@ var PlaceFixtures = map[string]Place{
LocKeywords: "ancient, pyramid",
LocNotes: "",
LocFavorite: false,
PhotoCount: 1,
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
},
"zinkwazi": {
ID: "1000001",
ID: "1ef744d1e28c",
LocLabel: "KwaDukuza, KwaZulu-Natal, South Africa",
LocCity: "KwaDukuza",
LocState: "KwaZulu-Natal",
@ -24,14 +43,12 @@ var PlaceFixtures = map[string]Place{
LocKeywords: "",
LocNotes: "africa",
LocFavorite: true,
PhotoCount: 2,
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
},
}
var PlaceFixtureTeotihuacan = PlaceFixtures["teotihuacan"]
var PlaceFixtureZinkwazi = PlaceFixtures["zinkwazi"]
// CreatePlaceFixtures inserts known entities into the database for testing.
func CreatePlaceFixtures() {
for _, entity := range PlaceFixtures {

View file

@ -14,22 +14,36 @@ func TestCreateUnknownPlace(t *testing.T) {
func TestFindPlaceByLabel(t *testing.T) {
t.Run("find by id", func(t *testing.T) {
r := FindPlaceByLabel("1000000", "")
r := FindPlaceByLabel("85d1ea7d382c", "")
if r == nil {
t.Fatal("result should not be nil")
}
assert.Equal(t, "mx", r.LocCountry)
})
t.Run("find by label", func(t *testing.T) {
r := FindPlaceByLabel("", "KwaDukuza, KwaZulu-Natal, South Africa")
if r == nil {
t.Fatal("result should not be nil")
}
assert.Equal(t, "za", r.LocCountry)
})
t.Run("not matching", func(t *testing.T) {
r := FindPlaceByLabel("111", "xxx")
assert.Nil(t, r)
if r != nil {
t.Fatal("result should be nil")
}
})
}
func TestPlace_Find(t *testing.T) {
t.Run("record exists", func(t *testing.T) {
r := PlaceFixtureTeotihuacan.Find()
m := PlaceFixtures.Get("teotihuacan")
r := m.Find()
assert.Nil(t, r)
})
t.Run("record does not exist", func(t *testing.T) {
@ -53,6 +67,7 @@ func TestPlace_Find(t *testing.T) {
}
func TestPlace_FirstOrCreate(t *testing.T) {
r := PlaceFixtureZinkwazi.FirstOrCreate()
m := PlaceFixtures.Pointer("zinkwazi")
r := m.FirstOrCreate()
assert.Equal(t, "KwaDukuza, KwaZulu-Natal, South Africa", r.LocLabel)
}

72
internal/query/label.go Normal file
View file

@ -0,0 +1,72 @@
package query
import (
"github.com/photoprism/photoprism/internal/entity"
)
// 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 AND photos_labels.uncertainty < 100").
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 AND photos_labels.uncertainty < 100").
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 AND photos_labels.uncertainty < 100").
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
}

View file

@ -16,8 +16,8 @@ type LabelResult struct {
CustomSlug string
LabelName string
LabelPriority int
LabelCount int
LabelFavorite bool
LabelDescription string
LabelNotes string
PhotoCount int
}

View file

@ -0,0 +1,83 @@
package query
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestLabelBySlug(t *testing.T) {
t.Run("files found", func(t *testing.T) {
label, err := LabelBySlug("flower")
if err != nil {
t.Fatal(err)
}
assert.Equal(t, "Flower", label.LabelName)
})
t.Run("no files found", func(t *testing.T) {
label, err := LabelBySlug("111")
assert.Error(t, err, "record not found")
assert.Empty(t, label.ID)
})
}
func TestLabelByUUID(t *testing.T) {
t.Run("files found", func(t *testing.T) {
label, err := LabelByUUID("lt9k3pw1wowuy3c5")
if err != nil {
t.Fatal(err)
}
assert.Equal(t, "COW", label.LabelName)
})
t.Run("no files found", func(t *testing.T) {
label, err := LabelByUUID("111")
assert.Error(t, err, "record not found")
assert.Empty(t, label.ID)
})
}
func TestLabelThumbBySlug(t *testing.T) {
t.Run("files found", func(t *testing.T) {
file, err := LabelThumbBySlug("flower")
if err != nil {
t.Fatal(err)
}
assert.Equal(t, "exampleFileName.jpg", file.FileName)
})
t.Run("no files found", func(t *testing.T) {
file, err := LabelThumbBySlug("cow")
assert.Error(t, err, "record not found")
t.Log(file)
})
}
func TestLabelThumbByUUID(t *testing.T) {
t.Run("files found", func(t *testing.T) {
file, err := LabelThumbByUUID("lt9k3pw1wowuy3c4")
if err != nil {
t.Fatal(err)
}
assert.Equal(t, "exampleFileName.jpg", file.FileName)
})
t.Run("no files found", func(t *testing.T) {
file, err := LabelThumbByUUID("14")
assert.Error(t, err, "record not found")
t.Log(file)
})
}

View file

@ -12,73 +12,6 @@ import (
"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 AND photos_labels.uncertainty < 100").
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 AND photos_labels.uncertainty < 100").
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 AND photos_labels.uncertainty < 100").
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 {
@ -94,6 +27,7 @@ func Labels(f form.LabelSearch) (results []LabelResult, err error) {
s = s.Table("labels").
Select(`labels.*`).
Where("labels.deleted_at IS NULL").
Where("labels.photo_count > 0").
Group("labels.id")
if f.ID != "" {

View file

@ -8,82 +8,6 @@ import (
"github.com/stretchr/testify/assert"
)
func TestLabelBySlug(t *testing.T) {
t.Run("files found", func(t *testing.T) {
label, err := LabelBySlug("flower")
if err != nil {
t.Fatal(err)
}
assert.Equal(t, "Flower", label.LabelName)
})
t.Run("no files found", func(t *testing.T) {
label, err := LabelBySlug("111")
assert.Error(t, err, "record not found")
assert.Empty(t, label.ID)
})
}
func TestLabelByUUID(t *testing.T) {
t.Run("files found", func(t *testing.T) {
label, err := LabelByUUID("lt9k3pw1wowuy3c5")
if err != nil {
t.Fatal(err)
}
assert.Equal(t, "COW", label.LabelName)
})
t.Run("no files found", func(t *testing.T) {
label, err := LabelByUUID("111")
assert.Error(t, err, "record not found")
assert.Empty(t, label.ID)
})
}
func TestLabelThumbBySlug(t *testing.T) {
t.Run("files found", func(t *testing.T) {
file, err := LabelThumbBySlug("flower")
if err != nil {
t.Fatal(err)
}
assert.Equal(t, "exampleFileName.jpg", file.FileName)
})
t.Run("no files found", func(t *testing.T) {
file, err := LabelThumbBySlug("cow")
assert.Error(t, err, "record not found")
t.Log(file)
})
}
func TestLabelThumbByUUID(t *testing.T) {
t.Run("files found", func(t *testing.T) {
file, err := LabelThumbByUUID("lt9k3pw1wowuy3c4")
if err != nil {
t.Fatal(err)
}
assert.Equal(t, "exampleFileName.jpg", file.FileName)
})
t.Run("no files found", func(t *testing.T) {
file, err := LabelThumbByUUID("14")
assert.Error(t, err, "record not found")
t.Log(file)
})
}
func TestLabels(t *testing.T) {
t.Run("search with query", func(t *testing.T) {
query := form.NewLabelSearch("Query:C Count:1005 Order:slug")

View file

@ -14,16 +14,19 @@ func UpdatePhotoCounts() error {
}
if err := Db().Table("labels").
UpdateColumn("photo_count", gorm.Expr("(SELECT COUNT(*) FROM photos_labels pl "+
"JOIN photos ph ON pl.photo_id = ph.id "+
"LEFT JOIN categories c ON c.label_id = pl.label_id "+
"LEFT JOIN labels lc ON lc.id = c.category_id "+
"WHERE pl.label_id = labels.id "+
"AND lc.deleted_at IS NULL "+
"AND pl.uncertainty < 100 "+
"AND ph.photo_quality >= 0 "+
"AND ph.photo_private = 0 "+
"AND ph.deleted_at IS NULL)")).Error; err != nil {
UpdateColumn("photo_count", gorm.Expr(`(SELECT COUNT(DISTINCT ph.id) FROM labels l
LEFT JOIN categories c ON c.category_id = l.id
LEFT JOIN photos_labels pl ON pl.label_id = l.id
LEFT JOIN photos_labels plc ON plc.label_id = c.label_id
LEFT JOIN labels lc ON lc.id = plc.label_id
LEFT JOIN photos ph ON pl.photo_id = ph.id OR plc.photo_id = ph.id
WHERE l.id = labels.id
AND lc.deleted_at IS NULL
AND (pl.uncertainty < 100 OR pl.uncertainty IS NULL)
AND (plc.uncertainty < 100 OR plc.uncertainty IS NULL)
AND ph.photo_quality >= 0
AND ph.photo_private = 0
AND ph.deleted_at IS NULL)`)).Error; err != nil {
return err
}