lens @ 024da3e546e98cbaeea5f7bc86af12b671996f41

  1package sql
  2
  3import (
  4	"context"
  5	"time"
  6
  7	"gorm.io/gorm"
  8
  9	"git.sr.ht/~gabrielgio/img/pkg/components/media"
 10	"git.sr.ht/~gabrielgio/img/pkg/list"
 11)
 12
 13type (
 14	Media struct {
 15		gorm.Model
 16		Name     string `gorm:"not null"`
 17		Path     string `gorm:"not null;unique"`
 18		PathHash string `gorm:"not null;unique"`
 19		MIMEType string `gorm:"not null"`
 20	}
 21
 22	MediaEXIF struct {
 23		gorm.Model
 24		Width           *float64
 25		Height          *float64
 26		MediaID         uint
 27		Media           Media
 28		Description     *string
 29		Camera          *string
 30		Maker           *string
 31		Lens            *string
 32		DateShot        *time.Time
 33		Exposure        *float64
 34		Aperture        *float64
 35		Iso             *int64
 36		FocalLength     *float64
 37		Flash           *int64
 38		Orientation     *int64
 39		ExposureProgram *int64
 40		GPSLatitude     *float64
 41		GPSLongitude    *float64
 42	}
 43
 44	MediaRepository struct {
 45		db *gorm.DB
 46	}
 47)
 48
 49var _ media.Repository = &MediaRepository{}
 50
 51func (self *Media) ToModel() *media.Media {
 52	return &media.Media{
 53		ID:       self.ID,
 54		Path:     self.Path,
 55		PathHash: self.PathHash,
 56		Name:     self.Name,
 57		MIMEType: self.MIMEType,
 58	}
 59}
 60
 61func (m *MediaEXIF) ToModel() *media.MediaEXIF {
 62	return &media.MediaEXIF{
 63		Height:          m.Height,
 64		Width:           m.Width,
 65		Description:     m.Description,
 66		Camera:          m.Camera,
 67		Maker:           m.Maker,
 68		Lens:            m.Lens,
 69		DateShot:        m.DateShot,
 70		Exposure:        m.Exposure,
 71		Aperture:        m.Aperture,
 72		Iso:             m.Iso,
 73		FocalLength:     m.FocalLength,
 74		Flash:           m.Flash,
 75		Orientation:     m.Orientation,
 76		ExposureProgram: m.ExposureProgram,
 77		GPSLatitude:     m.GPSLatitude,
 78		GPSLongitude:    m.GPSLongitude,
 79	}
 80}
 81
 82func NewMediaRepository(db *gorm.DB) *MediaRepository {
 83	return &MediaRepository{
 84		db: db,
 85	}
 86}
 87
 88func (self *MediaRepository) Create(ctx context.Context, createMedia *media.CreateMedia) error {
 89	media := &Media{
 90		Name:     createMedia.Name,
 91		Path:     createMedia.Path,
 92		PathHash: createMedia.PathHash,
 93		MIMEType: createMedia.MIMEType,
 94	}
 95
 96	result := self.db.
 97		WithContext(ctx).
 98		Create(media)
 99	if result.Error != nil {
100		return result.Error
101	}
102
103	return nil
104}
105
106func (self *MediaRepository) Exists(ctx context.Context, path string) (bool, error) {
107	var exists bool
108	result := self.db.
109		WithContext(ctx).
110		Model(&Media{}).
111		Select("count(id) > 0").
112		Where("path_hash = ?", path).
113		Find(&exists)
114
115	if result.Error != nil {
116		return false, result.Error
117	}
118
119	return exists, nil
120}
121
122func (self *MediaRepository) List(ctx context.Context, pagination *media.Pagination) ([]*media.Media, error) {
123	medias := make([]*Media, 0)
124	result := self.db.
125		WithContext(ctx).
126		Model(&Media{}).
127		Offset(pagination.Page * pagination.Size).
128		Limit(pagination.Size).
129		Order("created_at DESC").
130		Find(&medias)
131
132	if result.Error != nil {
133		return nil, result.Error
134	}
135
136	m := list.Map(medias, func(s *Media) *media.Media {
137		return s.ToModel()
138	})
139
140	return m, nil
141}
142
143func (self *MediaRepository) Get(ctx context.Context, pathHash string) (*media.Media, error) {
144	m := &Media{}
145	result := self.db.
146		WithContext(ctx).
147		Model(&Media{}).
148		Where("path_hash = ?", pathHash).
149		Limit(1).
150		Take(m)
151
152	if result.Error != nil {
153		return nil, result.Error
154	}
155
156	return m.ToModel(), nil
157}
158
159func (self *MediaRepository) GetPath(ctx context.Context, pathHash string) (string, error) {
160	var path string
161	result := self.db.
162		WithContext(ctx).
163		Model(&Media{}).
164		Select("path").
165		Where("path_hash = ?", pathHash).
166		Limit(1).
167		Find(&path)
168
169	if result.Error != nil {
170		return "", result.Error
171	}
172
173	return path, nil
174}
175
176func (m *MediaRepository) GetEXIF(ctx context.Context, mediaID uint) (*media.MediaEXIF, error) {
177	exif := &MediaEXIF{}
178	result := m.db.
179		WithContext(ctx).
180		Model(&Media{}).
181		Where("media_id = ?", mediaID).
182		Limit(1).
183		Take(m)
184
185	if result.Error != nil {
186		return nil, result.Error
187	}
188
189	return exif.ToModel(), nil
190}
191
192func (s *MediaRepository) CreateEXIF(ctx context.Context, id uint, info *media.MediaEXIF) error {
193	media := &MediaEXIF{
194		MediaID:         id,
195		Width:           info.Width,
196		Height:          info.Height,
197		Description:     info.Description,
198		Camera:          info.Camera,
199		Maker:           info.Maker,
200		Lens:            info.Lens,
201		DateShot:        info.DateShot,
202		Exposure:        info.Exposure,
203		Aperture:        info.Aperture,
204		Iso:             info.Iso,
205		FocalLength:     info.FocalLength,
206		Flash:           info.Flash,
207		Orientation:     info.Orientation,
208		ExposureProgram: info.ExposureProgram,
209		GPSLatitude:     info.GPSLatitude,
210		GPSLongitude:    info.GPSLongitude,
211	}
212
213	result := s.db.
214		WithContext(ctx).
215		Create(media)
216	if result.Error != nil {
217		return result.Error
218	}
219
220	return nil
221}
222
223func (r *MediaRepository) GetEmptyEXIF(ctx context.Context, pagination *media.Pagination) ([]*media.Media, error) {
224	medias := make([]*Media, 0)
225	result := r.db.
226		WithContext(ctx).
227		Model(&Media{}).
228		Joins("left join media_exifs on media.id = media_exifs.media_id").
229		Where("media_exifs.media_id IS NULL").
230		Offset(pagination.Page * pagination.Size).
231		Limit(pagination.Size).
232		Order("media.created_at DESC").
233		Find(&medias)
234
235	if result.Error != nil {
236		return nil, result.Error
237	}
238
239	m := list.Map(medias, func(s *Media) *media.Media {
240		return s.ToModel()
241	})
242
243	return m, nil
244}