From 45355c7303c07bb2287f0861ba35a3858a19dda1 Mon Sep 17 00:00:00 2001 From: Michael Mayer Date: Fri, 13 Aug 2021 20:31:41 +0200 Subject: [PATCH] People: Update entity database table names #22 Work in progress. --- .../entity/{embeddings.go => embedding.go} | 0 internal/entity/entity.go | 56 +++++++++---------- internal/entity/{person_face.go => face.go} | 30 +++++----- internal/entity/face_test.go | 12 ++++ internal/entity/marker.go | 2 +- internal/entity/marker_test.go | 4 +- internal/entity/person.go | 27 +-------- internal/entity/person_test.go | 5 ++ internal/photoprism/faces.go | 6 +- internal/query/people.go | 6 +- internal/query/people_test.go | 36 ++++++++++++ 11 files changed, 106 insertions(+), 78 deletions(-) rename internal/entity/{embeddings.go => embedding.go} (100%) rename internal/entity/{person_face.go => face.go} (73%) create mode 100644 internal/entity/face_test.go create mode 100644 internal/query/people_test.go diff --git a/internal/entity/embeddings.go b/internal/entity/embedding.go similarity index 100% rename from internal/entity/embeddings.go rename to internal/entity/embedding.go diff --git a/internal/entity/entity.go b/internal/entity/entity.go index 9e3a176a5..1ece440d0 100644 --- a/internal/entity/entity.go +++ b/internal/entity/entity.go @@ -30,34 +30,34 @@ type Types map[string]interface{} // Entities contains database entities and their table names. var Entities = Types{ - "errors": &Error{}, - "addresses": &Address{}, - "users": &User{}, - "accounts": &Account{}, - "folders": &Folder{}, - "duplicates": &Duplicate{}, - "files": &File{}, - "files_share": &FileShare{}, - "files_sync": &FileSync{}, - "photos": &Photo{}, - "details": &Details{}, - "places": &Place{}, - "cells": &Cell{}, - "cameras": &Camera{}, - "lenses": &Lens{}, - "countries": &Country{}, - "albums": &Album{}, - "photos_albums": &PhotoAlbum{}, - "labels": &Label{}, - "categories": &Category{}, - "photos_labels": &PhotoLabel{}, - "keywords": &Keyword{}, - "photos_keywords": &PhotoKeyword{}, - "passwords": &Password{}, - "links": &Link{}, - Marker{}.TableName(): &Marker{}, - Person{}.TableName(): &Person{}, - PersonFace{}.TableName(): &PersonFace{}, + "errors": &Error{}, + "addresses": &Address{}, + "users": &User{}, + "accounts": &Account{}, + "folders": &Folder{}, + "duplicates": &Duplicate{}, + "files": &File{}, + "files_share": &FileShare{}, + "files_sync": &FileSync{}, + "photos": &Photo{}, + "details": &Details{}, + "places": &Place{}, + "cells": &Cell{}, + "cameras": &Camera{}, + "lenses": &Lens{}, + "countries": &Country{}, + "albums": &Album{}, + "photos_albums": &PhotoAlbum{}, + "labels": &Label{}, + "categories": &Category{}, + "photos_labels": &PhotoLabel{}, + "keywords": &Keyword{}, + "photos_keywords": &PhotoKeyword{}, + "passwords": &Password{}, + "links": &Link{}, + Person{}.TableName(): &Person{}, + Face{}.TableName(): &Face{}, + Marker{}.TableName(): &Marker{}, } type RowCount struct { diff --git a/internal/entity/person_face.go b/internal/entity/face.go similarity index 73% rename from internal/entity/person_face.go rename to internal/entity/face.go index efffe1550..6729531c5 100644 --- a/internal/entity/person_face.go +++ b/internal/entity/face.go @@ -6,10 +6,10 @@ import ( "time" ) -type PeopleFaces []PersonFace +type Faces []Face -// PersonFace represents the face of a Person. -type PersonFace struct { +// Face represents the face of a Person. +type Face struct { ID string `gorm:"type:VARBINARY(42);primary_key;auto_increment:false;" json:"ID" yaml:"ID"` PersonUID string `gorm:"type:VARBINARY(42);index;" json:"PersonUID" yaml:"PersonUID,omitempty"` Embedding string `gorm:"type:LONGTEXT;" json:"Embedding" yaml:"Embedding,omitempty"` @@ -19,16 +19,16 @@ type PersonFace struct { } // TableName returns the entity database table name. -func (PersonFace) TableName() string { - return "people_faces_dev" +func (Face) TableName() string { + return "faces_dev2" } // NewPersonFace returns a new face. -func NewPersonFace(personUID, embedding string) *PersonFace { +func NewPersonFace(personUID, embedding string) *Face { timeStamp := Timestamp() s := sha1.Sum([]byte(embedding)) - result := &PersonFace{ + result := &Face{ ID: base32.StdEncoding.EncodeToString(s[:]), PersonUID: personUID, Embedding: embedding, @@ -40,12 +40,12 @@ func NewPersonFace(personUID, embedding string) *PersonFace { } // UnmarshalEmbedding parses the face embedding JSON string. -func (m *PersonFace) UnmarshalEmbedding() (result Embedding) { +func (m *Face) UnmarshalEmbedding() (result Embedding) { return UnmarshalEmbedding(m.Embedding) } // Save updates the existing or inserts a new face. -func (m *PersonFace) Save() error { +func (m *Face) Save() error { peopleMutex.Lock() defer peopleMutex.Unlock() @@ -53,7 +53,7 @@ func (m *PersonFace) Save() error { } // Create inserts the face to the database. -func (m *PersonFace) Create() error { +func (m *Face) Create() error { peopleMutex.Lock() defer peopleMutex.Unlock() @@ -61,17 +61,17 @@ func (m *PersonFace) Create() error { } // Delete removes the face from the database. -func (m *PersonFace) Delete() error { +func (m *Face) Delete() error { return Db().Delete(m).Error } // Deleted returns true if the face is deleted. -func (m *PersonFace) Deleted() bool { +func (m *Face) Deleted() bool { return m.DeletedAt != nil } // Restore restores the face in the database. -func (m *PersonFace) Restore() error { +func (m *Face) Restore() error { if m.Deleted() { return UnscopedDb().Model(m).Update("DeletedAt", nil).Error } @@ -80,11 +80,11 @@ func (m *PersonFace) Restore() error { } // Update a face property in the database. -func (m *PersonFace) Update(attr string, value interface{}) error { +func (m *Face) Update(attr string, value interface{}) error { return UnscopedDb().Model(m).Update(attr, value).Error } // Updates face properties in the database. -func (m *PersonFace) Updates(values interface{}) error { +func (m *Face) Updates(values interface{}) error { return UnscopedDb().Model(m).Updates(values).Error } diff --git a/internal/entity/face_test.go b/internal/entity/face_test.go new file mode 100644 index 000000000..15ad5f7e6 --- /dev/null +++ b/internal/entity/face_test.go @@ -0,0 +1,12 @@ +package entity + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestFace_TableName(t *testing.T) { + m := &Face{} + assert.Contains(t, m.TableName(), "faces") +} diff --git a/internal/entity/marker.go b/internal/entity/marker.go index 05d8c15d0..d9c609fb6 100644 --- a/internal/entity/marker.go +++ b/internal/entity/marker.go @@ -45,7 +45,7 @@ var UnknownMarker = NewMarker(0, "", SrcAuto, MarkerUnknown, 0, 0, 0, 0) // TableName returns the entity database table name. func (Marker) TableName() string { - return "markers_dev" + return "markers_dev2" } // NewMarker creates a new entity. diff --git a/internal/entity/marker_test.go b/internal/entity/marker_test.go index d89d4f763..46c91924f 100644 --- a/internal/entity/marker_test.go +++ b/internal/entity/marker_test.go @@ -7,8 +7,8 @@ import ( ) func TestMarker_TableName(t *testing.T) { - fileSync := &Marker{} - assert.Equal(t, "markers_dev", fileSync.TableName()) + m := &Marker{} + assert.Contains(t, m.TableName(), "markers") } func TestNewMarker(t *testing.T) { diff --git a/internal/entity/person.go b/internal/entity/person.go index 47849a727..bb70fdd69 100644 --- a/internal/entity/person.go +++ b/internal/entity/person.go @@ -15,31 +15,6 @@ var peopleMutex = sync.Mutex{} type People []Person -// Relationships. -/* -const ( - RelUnknown = "" - RelBaby = "baby" - RelWife = "wife" - RelHusband = "husband" - RelDad = "dad" - RelMom = "mom" - RelWorkmate = "workmate" - RelBestFriend = "best-friend" - RelFriend = "friend" - RelClassmate = "classmate" - RelBoyfriend = "boyfriend" - RelGirlfriend = "girlfriend" - RelFamily = "family" - RelGrandfather = "grandfather" - RelGrandmother = "grandmother" - RelBrother = "brother" - RelSister = "sister" - RelRelative = "relative" - RelOther = "other" -) -*/ - // Person represents a person on one or more photos. type Person struct { ID uint `gorm:"primary_key" json:"ID" yaml:"-"` @@ -80,7 +55,7 @@ func CreateUnknownPerson() { // TableName returns the entity database table name. func (Person) TableName() string { - return "people_dev" + return "people_dev2" } // BeforeCreate creates a random UID if needed before inserting a new row to the database. diff --git a/internal/entity/person_test.go b/internal/entity/person_test.go index 2fc80b7b9..98ee6f427 100644 --- a/internal/entity/person_test.go +++ b/internal/entity/person_test.go @@ -7,6 +7,11 @@ import ( "github.com/stretchr/testify/assert" ) +func TestPerson_TableName(t *testing.T) { + m := &Person{} + assert.Contains(t, m.TableName(), "people") +} + func TestNewPerson(t *testing.T) { t.Run("Jens_Mander", func(t *testing.T) { m := NewPerson("Jens Mander", SrcAuto, 0) diff --git a/internal/photoprism/faces.go b/internal/photoprism/faces.go index 2270c6c37..adac8428f 100644 --- a/internal/photoprism/faces.go +++ b/internal/photoprism/faces.go @@ -82,7 +82,7 @@ func (w *Faces) Analyze() (err error) { log.Infof("faces: max Ø %f < median %f < %f", maxMin, maxMedian, maxMax) } - if known, err := query.PeopleFaces(); err != nil { + if known, err := query.Faces(); err != nil { log.Errorf("faces: %s", err) } else if len(known) == 0 { log.Infof("faces: no faces found") @@ -233,7 +233,7 @@ func (w *Faces) Start() (err error) { log.Errorf("faces: %s", err) } - peopleFaces, err := query.PeopleFaces() + peopleFaces, err := query.Faces() if err != nil { return err @@ -298,7 +298,7 @@ func (w *Faces) Start() (err error) { log.Errorf("faces: failed adding %s", txt.Quote(marker.MarkerLabel)) } else if f, ok := faceMap[faceId]; ok { faceMap[faceId] = Face{Embedding: f.Embedding, PersonUID: person.PersonUID} - entity.Db().Model(&entity.PersonFace{}).Where("id = ?", faceId).Update("PersonUID", person.PersonUID) + entity.Db().Model(&entity.Face{}).Where("id = ?", faceId).Update("PersonUID", person.PersonUID) } // Existing person? diff --git a/internal/query/people.go b/internal/query/people.go index 275b8f762..c0231fa68 100644 --- a/internal/query/people.go +++ b/internal/query/people.go @@ -18,8 +18,8 @@ func People(limit, offset int, embeddings bool) (result entity.People, err error return result, err } -// PeopleFaces finds a list of faces. -func PeopleFaces() (result entity.PeopleFaces, err error) { +// Faces finds a list of faces. +func Faces() (result entity.Faces, err error) { stmt := Db(). Order("id") @@ -31,6 +31,6 @@ func PeopleFaces() (result entity.PeopleFaces, err error) { // PurgeUnknownFaces removes unknown faces from the index. func PurgeUnknownFaces() error { return UnscopedDb().Delete( - entity.PersonFace{}, + entity.Face{}, "person_uid = '' AND updated_at < ?", entity.Yesterday()).Error } diff --git a/internal/query/people_test.go b/internal/query/people_test.go new file mode 100644 index 000000000..65ed82332 --- /dev/null +++ b/internal/query/people_test.go @@ -0,0 +1,36 @@ +package query + +import ( + "github.com/photoprism/photoprism/internal/entity" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestPeople(t *testing.T) { + results, err := People(3, 0, false) + + if err != nil { + t.Fatal(err) + } + + assert.GreaterOrEqual(t, 1, len(results)) + + for _, val := range results { + assert.IsType(t, entity.Person{}, val) + } +} + +func TestFaces(t *testing.T) { + results, err := Faces() + + if err != nil { + t.Fatal(err) + } + + assert.GreaterOrEqual(t, 1, len(results)) + + for _, val := range results { + assert.IsType(t, entity.Face{}, val) + } +}