Updating sql Image structure to allow expiration of an image

Signed-off-by: Ethan Wellenreiter <ewellenreiter@gmail.com>
This commit is contained in:
Ethan Wellenreiter 2025-05-07 10:24:13 -04:00
parent c91c784338
commit 30b4292c4a
2 changed files with 31 additions and 8 deletions

View File

@ -52,6 +52,7 @@ Table images {
receiptid integer
created_at timestamp
path varchar
expiration timestamp
added bool [default: false]
}

View File

@ -3,17 +3,26 @@ package storage
import (
"context"
"database/sql"
"time"
)
type SQLImagesStore struct {
db *sql.DB
}
func (s SQLImagesStore) GetByID(ctx context.Context, id int64) (*Image, error) {
query := `SELECT id, receiptid, created_at, path FROM images WHERE id = $1`
const imgStoreCleanupTime = time.Hour * 12
func NewSQLImageStore(db *sql.DB) *SQLImagesStore {
imgstore := &SQLImagesStore{db}
go imgstore.cleanupDeadImages()
return imgstore
}
func (s *SQLImagesStore) GetByID(ctx context.Context, id int64) (*Image, error) {
query := `SELECT id, receiptid, created_at, path FROM images WHERE id = $1 AND added = $2`
image := &Image{}
err := s.db.QueryRowContext(ctx, query, id).Scan(&image.ID, &image.ReceiptID, &image.CreatedAt, &image.Path)
err := s.db.QueryRowContext(ctx, query, id, true).Scan(&image.ID, &image.ReceiptID, &image.CreatedAt, &image.Path)
if err != nil {
return nil, err
}
@ -21,10 +30,10 @@ func (s SQLImagesStore) GetByID(ctx context.Context, id int64) (*Image, error) {
return image, nil
}
func (s SQLImagesStore) Create(ctx context.Context, img *Image) error {
func (s *SQLImagesStore) Create(ctx context.Context, img *Image, exp time.Duration) error {
query := `
INSERT INTO images (receiptid, path)
VALUES ($1, $2) RETURNING id, created_at`
INSERT INTO images (receiptid, path, expiration)
VALUES ($1, $2, $3) RETURNING id, created_at`
ctx, cancel := context.WithTimeout(ctx, QueryTimeoutDuration)
defer cancel()
@ -34,6 +43,7 @@ func (s SQLImagesStore) Create(ctx context.Context, img *Image) error {
query,
img.ReceiptID,
img.Path, // might need to marshal or serialize this
time.Now().Add(exp),
).Scan(
&img.ID,
&img.CreatedAt,
@ -41,7 +51,7 @@ func (s SQLImagesStore) Create(ctx context.Context, img *Image) error {
return err
}
func (s SQLImagesStore) Delete(ctx context.Context, id int64) error {
func (s *SQLImagesStore) Delete(ctx context.Context, id int64) error {
query := `DELETE FROM images WHERE id = $1`
ctx, cancel := context.WithTimeout(ctx, QueryTimeoutDuration)
@ -64,7 +74,7 @@ func (s SQLImagesStore) Delete(ctx context.Context, id int64) error {
return nil
}
func (s SQLImagesStore) ActivateImage(ctx context.Context, id int64) error {
func (s *SQLImagesStore) ActivateImage(ctx context.Context, id int64) error {
query := `UPDATE images SET added = $1`
ctx, cancel := context.WithTimeout(ctx, QueryTimeoutDuration)
@ -77,3 +87,15 @@ func (s SQLImagesStore) ActivateImage(ctx context.Context, id int64) error {
return nil
}
func (s *SQLImagesStore) cleanupDeadImages(ctx context.Context) {
for range time.Tick(imgStoreCleanupTime) {
query := `DELETE FROM images WHERE added = false AND expiration < $1`
ctx, cancel := context.WithTimeout(ctx, QueryTimeoutDuration)
defer cancel()
s.db.ExecContext(ctx, query, time.Now())
}
// ignore any errors, just keep looping. Not much lost in a missed cleanup. A little extra temporary storage. Big woop. If it's an issue, decrease the cleanup period
}