lens @ 249ee195ce52ee4a4defeb67a33ef353919d3a11

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