Skip to content

Commit

Permalink
feat: greatly improve fetching, adding, updating galleries
Browse files Browse the repository at this point in the history
  • Loading branch information
CrescentKohana committed Mar 22, 2024
1 parent d6987a8 commit a06923d
Show file tree
Hide file tree
Showing 2 changed files with 116 additions and 151 deletions.
4 changes: 2 additions & 2 deletions pkg/api/gallery.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ func returnGallery(w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
galleryUUID := params["uuid"]

gallery, err := db.GetGallery(&galleryUUID, userUUID)
gallery, err := db.GetGallery(&galleryUUID, userUUID, nil)
if handleResult(w, gallery, err, false, r.RequestURI) {
return
}
Expand Down Expand Up @@ -193,7 +193,7 @@ func returnRandomGallery(w http.ResponseWriter, r *http.Request) {
return
}

gallery, err := db.GetGallery(nil, userUUID)
gallery, err := db.GetGallery(nil, userUUID, nil)
if handleResult(w, gallery, err, false, r.URL.Path) {
return
}
Expand Down
263 changes: 114 additions & 149 deletions pkg/db/gallery.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package db

import (
"database/sql"
"errors"
"github.com/Mangatsu/server/pkg/utils"
"math"
"math/rand/v2"
"time"
Expand Down Expand Up @@ -128,87 +130,50 @@ func UpdateGallery(gallery model.Gallery, tags []model.Tag, reference model.Refe
}
}

oldGallery, err := GetGallery(&gallery.UUID, nil)
prevGallery, err := GetGallery(&gallery.UUID, nil, &gallery.ArchivePath)
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
return errors.New("gallery not found")
}
return err
}

tx, err := db().Begin()
if err != nil {
return err
}
defer rollbackTx(tx)

committed := false
defer func() {
if !committed {
rollbackTx(tx)
}
}()

var updateGalleryStmt UpdateStatement

gallery.UpdatedAt = now
if internalScan {
galleryModel := model.Gallery{
Title: gallery.Title,
TitleNative: gallery.TitleNative,
TitleTranslated: gallery.TitleTranslated,
Category: gallery.Category,
Released: gallery.Released,
Series: gallery.Series,
Language: gallery.Language,
Translated: gallery.Translated,
Nsfw: gallery.Nsfw,
ImageCount: gallery.ImageCount,
ArchiveSize: gallery.ArchiveSize,
ArchiveHash: gallery.ArchiveHash,
UpdatedAt: now,
}
updateGalleryStmt = Gallery.UPDATE(
Gallery.Title,
Gallery.TitleNative,
Gallery.TitleTranslated,
Gallery.Category,
Gallery.Released,
Gallery.Series,
Gallery.Language,
Gallery.Translated,
Gallery.Nsfw,
Gallery.ImageCount,
Gallery.ArchiveSize,
Gallery.ArchiveHash,
Gallery.UpdatedAt,
).MODEL(galleryModel)

updateGalleryStmt = updateGalleryStmt.WHERE(Gallery.ArchivePath.EQ(String(gallery.ArchivePath))).RETURNING(Gallery.UUID)
galleryModel, galleryColumnList := ValidateGalleryInternal(prevGallery.Gallery, now)

updateGalleryStmt = Gallery.
UPDATE(galleryColumnList).
MODEL(galleryModel).
WHERE(Gallery.ArchivePath.EQ(String(gallery.ArchivePath))).
RETURNING(Gallery.UUID)
} else {
newGallery := ValidateGallery(oldGallery.Gallery, gallery)
updateGalleryStmt = Gallery.UPDATE(
Gallery.Title,
Gallery.TitleNative,
Gallery.TitleTranslated,
Gallery.Category,
Gallery.Released,
Gallery.Series,
Gallery.Language,
Gallery.Nsfw,
Gallery.Hidden,
Gallery.Translated,
Gallery.UpdatedAt,
).SET(
newGallery.Title,
newGallery.TitleNative,
newGallery.TitleTranslated,
newGallery.Category,
newGallery.Released,
newGallery.Series,
newGallery.Language,
newGallery.Nsfw,
newGallery.Hidden,
newGallery.Translated,
gallery.UpdatedAt,
).WHERE(Gallery.UUID.EQ(String(gallery.UUID))).RETURNING(Gallery.UUID)
galleryModel, galleryColumnList := ValidateGallery(prevGallery.Gallery, gallery, now)

updateGalleryStmt = Gallery.
UPDATE(galleryColumnList).
MODEL(galleryModel).
WHERE(Gallery.UUID.EQ(String(gallery.UUID))).
RETURNING(Gallery.UUID)
}

var galleries []model.Gallery
if err = updateGalleryStmt.Query(tx, &galleries); err != nil {
return err
}

if len(galleries) == 0 {
return nil
}
Expand All @@ -219,107 +184,51 @@ func UpdateGallery(gallery model.Gallery, tags []model.Tag, reference model.Refe
insertTagGalleryStmt := GalleryTag.
INSERT(GalleryTag.TagID, GalleryTag.GalleryUUID).
VALUES(tagID, galleries[0].UUID).
ON_CONFLICT(GalleryTag.TagID, GalleryTag.GalleryUUID).DO_NOTHING()
ON_CONFLICT(GalleryTag.TagID, GalleryTag.GalleryUUID).
DO_NOTHING()

if _, err = insertTagGalleryStmt.Exec(tx); err != nil {
return err
}
}
}

// Inserts reference
if internalScan && reference != (model.Reference{}) {
var metaPath string
var metaMatch int32
var exhGid int32
var exhToken string
var urls string
if reference.MetaPath != nil {
metaPath = *reference.MetaPath
}
if reference.MetaMatch != nil {
metaMatch = *reference.MetaMatch
}
if reference.ExhGid != nil {
exhGid = *reference.ExhGid
}
if reference.ExhToken != nil {
exhToken = *reference.ExhToken
}
if reference.Urls != nil {
urls = *reference.Urls
}
// Used for skipping title parsing if it's already done
titleHash := utils.HashStringSHA1(gallery.Title)
reference.MetaTitleHash = &titleHash

newReference := model.Reference{
GalleryUUID: galleries[0].UUID,
MetaPath: reference.MetaPath,
MetaInternal: reference.MetaInternal,
MetaMatch: reference.MetaMatch,
ExhGid: reference.ExhGid,
ExhToken: reference.ExhToken,
Urls: reference.Urls,
}
// Inserts or updates reference
referenceModel := model.Reference{}

insertRefStmt := Reference.
INSERT(Reference.AllColumns).
MODEL(newReference).
ON_CONFLICT(Reference.GalleryUUID).DO_UPDATE(
SET(
Reference.MutableColumns.SET(ROW(
String(metaPath),
Bool(reference.MetaInternal),
Int32(metaMatch),
Int32(exhGid),
String(exhToken),
String(urls)),
),
),
)
if _, err = insertRefStmt.Exec(tx); err != nil {
return err
}
} else if reference != (model.Reference{}) {
oldReference, err := GetReference(gallery.UUID)
if err != nil {
return err
}
newReference := ValidateReference(oldReference, reference)
var exhGid int32
var exhToken string
var anilistID int32
var urls string
if newReference.ExhGid != nil {
exhGid = *newReference.ExhGid
}
if newReference.ExhToken != nil {
exhToken = *newReference.ExhToken
}
if newReference.AnilistID != nil {
anilistID = *newReference.AnilistID
}
if newReference.Urls != nil {
urls = *newReference.Urls
}
if internalScan {
referenceModel = ValidateReferenceInternal(reference)
} else {
referenceModel = ValidateReference(reference)
}

referenceModel.GalleryUUID = galleries[0].UUID

insertRefStmt := Reference.
INSERT(Reference.AllColumns).
MODEL(newReference).
ON_CONFLICT(Reference.GalleryUUID).DO_UPDATE(
SET(
ColumnList{Reference.ExhGid, Reference.ExhToken, Reference.AnilistID, Reference.Urls}.SET(ROW(
Int32(exhGid),
String(exhToken),
Int32(anilistID),
String(urls)),
),
rowValues, referenceUpdateColumnList, err := ConstructExpressions(referenceModel)
if err != nil {
log.Z.Debug("could not construct expressions", zap.String("err", err.Error()))
return err
}

insertRefStmt := Reference.
INSERT(referenceUpdateColumnList).
MODEL(referenceModel).
ON_CONFLICT(Reference.GalleryUUID).
DO_UPDATE(
SET(referenceUpdateColumnList.
SET(ROW(rowValues...)),
),
)
if _, err = insertRefStmt.Exec(tx); err != nil {
return err
}
if _, err = insertRefStmt.Exec(tx); err != nil {
return err
}

// Commits transaction. Rollbacks on error.
committed = true
err = tx.Commit()
return err
}
Expand Down Expand Up @@ -653,7 +562,31 @@ func GetGalleries(filters Filters, hidden bool, userUUID *string) ([]CombinedMet
}

// GetGallery returns a gallery based on the given UUID. If no UUID is given, a random gallery is returned.
func GetGallery(galleryUUID *string, userUUID *string) (CombinedMetadata, error) {
func GetGallery(galleryUUID *string, userUUID *string, archivePath *string) (CombinedMetadata, error) {
if (galleryUUID == nil || *galleryUUID == "") && (archivePath == nil || *archivePath == "") {
return CombinedMetadata{}, errors.New("either galleryUUID or archivePath must be provided")
}

// If archivePath is provided, galleryUUID is fetched from the database.
if (galleryUUID == nil || *galleryUUID == "") && (archivePath != nil && *archivePath != "") {
stmt := SELECT(Gallery.UUID).FROM(Gallery).WHERE(Gallery.ArchivePath.EQ(String(*archivePath)))
var galleries []model.Gallery
if err := stmt.Query(db(), &galleries); err != nil {
log.Z.Debug("could not get gallery",
zap.Stringp("archivePath", archivePath),
zap.String("err", err.Error()))
return CombinedMetadata{}, err
}

if len(galleries) == 0 {
log.Z.Debug("no gallery found", zap.Stringp("archivePath", archivePath))
return CombinedMetadata{}, sql.ErrNoRows
}

galleryUUID = &galleries[0].UUID
}

// If userUUID is provided, a new user gallery entry is created.
if userUUID != nil && galleryUUID != nil {
if err := NewGalleryPref(*galleryUUID, *userUUID); err != nil {
log.Z.Debug("could not add user gallery entry",
Expand Down Expand Up @@ -719,6 +652,7 @@ func GetGallery(galleryUUID *string, userUUID *string) (CombinedMetadata, error)
}

if len(galleries) == 0 {
log.Z.Debug("no gallery found", zap.Stringp("uuid", galleryUUID))
return CombinedMetadata{}, sql.ErrNoRows
}

Expand Down Expand Up @@ -797,6 +731,37 @@ func GetSeries() ([]string, error) {
return series, err
}

// TitleHashMatch returns true if the title hash of the gallery matches the stored hash.
func TitleHashMatch(galleryUUID string) bool {
stmt := SELECT(Gallery.UUID, Gallery.Title, Reference.MetaTitleHash).
FROM(Gallery.Table.
LEFT_JOIN(Reference, Reference.GalleryUUID.EQ(String(galleryUUID))),
).
WHERE(Gallery.UUID.EQ(String(galleryUUID))).
LIMIT(1)

var galleries []struct {
UUID string
Title string
MetaTitleHash *string
}
err := stmt.Query(db(), &galleries)
if err != nil {
log.Z.Debug("failed to query for title hash",
zap.String("uuid", galleryUUID),
zap.String("err", err.Error()))
return false
}

if galleries == nil || galleries[0].MetaTitleHash == nil {
return false
}

titleHash := utils.HashStringSHA1(galleries[0].Title)

return titleHash == *galleries[0].MetaTitleHash
}

// NeedsUpdate returns true if the gallery needs to be updated. Currently only the timestamp is checked.
func NeedsUpdate(archivePath string, updatedAt time.Time) (bool, string) {
// TODO: Possibly also check for ArchiveSize and ArchiveHash?
Expand Down

0 comments on commit a06923d

Please sign in to comment.