Restructure data layer (#2532)

* Add new txn manager interface
* Add txn management to sqlite
* Rename get to getByID
* Add contexts to repository methods
* Update query builders
* Add context to reader writer interfaces
* Use repository in resolver
* Tighten interfaces
* Tighten interfaces in dlna
* Tighten interfaces in match package
* Tighten interfaces in scraper package
* Tighten interfaces in scan code
* Tighten interfaces on autotag package
* Remove ReaderWriter usage
* Merge database package into sqlite
This commit is contained in:
WithoutPants
2022-05-19 17:49:32 +10:00
parent 7b5bd80515
commit 964b559309
244 changed files with 7377 additions and 6699 deletions

View File

@@ -1,6 +1,7 @@
package sqlite
import (
"context"
"database/sql"
"errors"
"fmt"
@@ -20,62 +21,59 @@ type galleryQueryBuilder struct {
repository
}
func NewGalleryReaderWriter(tx dbi) *galleryQueryBuilder {
return &galleryQueryBuilder{
repository{
tx: tx,
tableName: galleryTable,
idColumn: idColumn,
},
}
var GalleryReaderWriter = &galleryQueryBuilder{
repository{
tableName: galleryTable,
idColumn: idColumn,
},
}
func (qb *galleryQueryBuilder) Create(newObject models.Gallery) (*models.Gallery, error) {
func (qb *galleryQueryBuilder) Create(ctx context.Context, newObject models.Gallery) (*models.Gallery, error) {
var ret models.Gallery
if err := qb.insertObject(newObject, &ret); err != nil {
if err := qb.insertObject(ctx, newObject, &ret); err != nil {
return nil, err
}
return &ret, nil
}
func (qb *galleryQueryBuilder) Update(updatedObject models.Gallery) (*models.Gallery, error) {
func (qb *galleryQueryBuilder) Update(ctx context.Context, updatedObject models.Gallery) (*models.Gallery, error) {
const partial = false
if err := qb.update(updatedObject.ID, updatedObject, partial); err != nil {
if err := qb.update(ctx, updatedObject.ID, updatedObject, partial); err != nil {
return nil, err
}
return qb.Find(updatedObject.ID)
return qb.Find(ctx, updatedObject.ID)
}
func (qb *galleryQueryBuilder) UpdatePartial(updatedObject models.GalleryPartial) (*models.Gallery, error) {
func (qb *galleryQueryBuilder) UpdatePartial(ctx context.Context, updatedObject models.GalleryPartial) (*models.Gallery, error) {
const partial = true
if err := qb.update(updatedObject.ID, updatedObject, partial); err != nil {
if err := qb.update(ctx, updatedObject.ID, updatedObject, partial); err != nil {
return nil, err
}
return qb.Find(updatedObject.ID)
return qb.Find(ctx, updatedObject.ID)
}
func (qb *galleryQueryBuilder) UpdateChecksum(id int, checksum string) error {
return qb.updateMap(id, map[string]interface{}{
func (qb *galleryQueryBuilder) UpdateChecksum(ctx context.Context, id int, checksum string) error {
return qb.updateMap(ctx, id, map[string]interface{}{
"checksum": checksum,
})
}
func (qb *galleryQueryBuilder) UpdateFileModTime(id int, modTime models.NullSQLiteTimestamp) error {
return qb.updateMap(id, map[string]interface{}{
func (qb *galleryQueryBuilder) UpdateFileModTime(ctx context.Context, id int, modTime models.NullSQLiteTimestamp) error {
return qb.updateMap(ctx, id, map[string]interface{}{
"file_mod_time": modTime,
})
}
func (qb *galleryQueryBuilder) Destroy(id int) error {
return qb.destroyExisting([]int{id})
func (qb *galleryQueryBuilder) Destroy(ctx context.Context, id int) error {
return qb.destroyExisting(ctx, []int{id})
}
func (qb *galleryQueryBuilder) Find(id int) (*models.Gallery, error) {
func (qb *galleryQueryBuilder) Find(ctx context.Context, id int) (*models.Gallery, error) {
var ret models.Gallery
if err := qb.get(id, &ret); err != nil {
if err := qb.getByID(ctx, id, &ret); err != nil {
if errors.Is(err, sql.ErrNoRows) {
return nil, nil
}
@@ -84,10 +82,10 @@ func (qb *galleryQueryBuilder) Find(id int) (*models.Gallery, error) {
return &ret, nil
}
func (qb *galleryQueryBuilder) FindMany(ids []int) ([]*models.Gallery, error) {
func (qb *galleryQueryBuilder) FindMany(ctx context.Context, ids []int) ([]*models.Gallery, error) {
var galleries []*models.Gallery
for _, id := range ids {
gallery, err := qb.Find(id)
gallery, err := qb.Find(ctx, id)
if err != nil {
return nil, err
}
@@ -102,61 +100,61 @@ func (qb *galleryQueryBuilder) FindMany(ids []int) ([]*models.Gallery, error) {
return galleries, nil
}
func (qb *galleryQueryBuilder) FindByChecksum(checksum string) (*models.Gallery, error) {
func (qb *galleryQueryBuilder) FindByChecksum(ctx context.Context, checksum string) (*models.Gallery, error) {
query := "SELECT * FROM galleries WHERE checksum = ? LIMIT 1"
args := []interface{}{checksum}
return qb.queryGallery(query, args)
return qb.queryGallery(ctx, query, args)
}
func (qb *galleryQueryBuilder) FindByChecksums(checksums []string) ([]*models.Gallery, error) {
func (qb *galleryQueryBuilder) FindByChecksums(ctx context.Context, checksums []string) ([]*models.Gallery, error) {
query := "SELECT * FROM galleries WHERE checksum IN " + getInBinding(len(checksums))
var args []interface{}
for _, checksum := range checksums {
args = append(args, checksum)
}
return qb.queryGalleries(query, args)
return qb.queryGalleries(ctx, query, args)
}
func (qb *galleryQueryBuilder) FindByPath(path string) (*models.Gallery, error) {
func (qb *galleryQueryBuilder) FindByPath(ctx context.Context, path string) (*models.Gallery, error) {
query := "SELECT * FROM galleries WHERE path = ? LIMIT 1"
args := []interface{}{path}
return qb.queryGallery(query, args)
return qb.queryGallery(ctx, query, args)
}
func (qb *galleryQueryBuilder) FindBySceneID(sceneID int) ([]*models.Gallery, error) {
func (qb *galleryQueryBuilder) FindBySceneID(ctx context.Context, sceneID int) ([]*models.Gallery, error) {
query := selectAll(galleryTable) + `
LEFT JOIN scenes_galleries as scenes_join on scenes_join.gallery_id = galleries.id
WHERE scenes_join.scene_id = ?
GROUP BY galleries.id
`
args := []interface{}{sceneID}
return qb.queryGalleries(query, args)
return qb.queryGalleries(ctx, query, args)
}
func (qb *galleryQueryBuilder) FindByImageID(imageID int) ([]*models.Gallery, error) {
func (qb *galleryQueryBuilder) FindByImageID(ctx context.Context, imageID int) ([]*models.Gallery, error) {
query := selectAll(galleryTable) + `
INNER JOIN galleries_images as images_join on images_join.gallery_id = galleries.id
WHERE images_join.image_id = ?
GROUP BY galleries.id
`
args := []interface{}{imageID}
return qb.queryGalleries(query, args)
return qb.queryGalleries(ctx, query, args)
}
func (qb *galleryQueryBuilder) CountByImageID(imageID int) (int, error) {
func (qb *galleryQueryBuilder) CountByImageID(ctx context.Context, imageID int) (int, error) {
query := `SELECT image_id FROM galleries_images
WHERE image_id = ?
GROUP BY gallery_id`
args := []interface{}{imageID}
return qb.runCountQuery(qb.buildCountQuery(query), args)
return qb.runCountQuery(ctx, qb.buildCountQuery(query), args)
}
func (qb *galleryQueryBuilder) Count() (int, error) {
return qb.runCountQuery(qb.buildCountQuery("SELECT galleries.id FROM galleries"), nil)
func (qb *galleryQueryBuilder) Count(ctx context.Context) (int, error) {
return qb.runCountQuery(ctx, qb.buildCountQuery("SELECT galleries.id FROM galleries"), nil)
}
func (qb *galleryQueryBuilder) All() ([]*models.Gallery, error) {
return qb.queryGalleries(selectAll("galleries")+qb.getGallerySort(nil), nil)
func (qb *galleryQueryBuilder) All(ctx context.Context) ([]*models.Gallery, error) {
return qb.queryGalleries(ctx, selectAll("galleries")+qb.getGallerySort(nil), nil)
}
func (qb *galleryQueryBuilder) validateFilter(galleryFilter *models.GalleryFilterType) error {
@@ -190,43 +188,43 @@ func (qb *galleryQueryBuilder) validateFilter(galleryFilter *models.GalleryFilte
return nil
}
func (qb *galleryQueryBuilder) makeFilter(galleryFilter *models.GalleryFilterType) *filterBuilder {
func (qb *galleryQueryBuilder) makeFilter(ctx context.Context, galleryFilter *models.GalleryFilterType) *filterBuilder {
query := &filterBuilder{}
if galleryFilter.And != nil {
query.and(qb.makeFilter(galleryFilter.And))
query.and(qb.makeFilter(ctx, galleryFilter.And))
}
if galleryFilter.Or != nil {
query.or(qb.makeFilter(galleryFilter.Or))
query.or(qb.makeFilter(ctx, galleryFilter.Or))
}
if galleryFilter.Not != nil {
query.not(qb.makeFilter(galleryFilter.Not))
query.not(qb.makeFilter(ctx, galleryFilter.Not))
}
query.handleCriterion(stringCriterionHandler(galleryFilter.Title, "galleries.title"))
query.handleCriterion(stringCriterionHandler(galleryFilter.Details, "galleries.details"))
query.handleCriterion(stringCriterionHandler(galleryFilter.Checksum, "galleries.checksum"))
query.handleCriterion(boolCriterionHandler(galleryFilter.IsZip, "galleries.zip"))
query.handleCriterion(stringCriterionHandler(galleryFilter.Path, "galleries.path"))
query.handleCriterion(intCriterionHandler(galleryFilter.Rating, "galleries.rating"))
query.handleCriterion(stringCriterionHandler(galleryFilter.URL, "galleries.url"))
query.handleCriterion(boolCriterionHandler(galleryFilter.Organized, "galleries.organized"))
query.handleCriterion(galleryIsMissingCriterionHandler(qb, galleryFilter.IsMissing))
query.handleCriterion(galleryTagsCriterionHandler(qb, galleryFilter.Tags))
query.handleCriterion(galleryTagCountCriterionHandler(qb, galleryFilter.TagCount))
query.handleCriterion(galleryPerformersCriterionHandler(qb, galleryFilter.Performers))
query.handleCriterion(galleryPerformerCountCriterionHandler(qb, galleryFilter.PerformerCount))
query.handleCriterion(galleryStudioCriterionHandler(qb, galleryFilter.Studios))
query.handleCriterion(galleryPerformerTagsCriterionHandler(qb, galleryFilter.PerformerTags))
query.handleCriterion(galleryAverageResolutionCriterionHandler(qb, galleryFilter.AverageResolution))
query.handleCriterion(galleryImageCountCriterionHandler(qb, galleryFilter.ImageCount))
query.handleCriterion(galleryPerformerFavoriteCriterionHandler(galleryFilter.PerformerFavorite))
query.handleCriterion(galleryPerformerAgeCriterionHandler(galleryFilter.PerformerAge))
query.handleCriterion(ctx, stringCriterionHandler(galleryFilter.Title, "galleries.title"))
query.handleCriterion(ctx, stringCriterionHandler(galleryFilter.Details, "galleries.details"))
query.handleCriterion(ctx, stringCriterionHandler(galleryFilter.Checksum, "galleries.checksum"))
query.handleCriterion(ctx, boolCriterionHandler(galleryFilter.IsZip, "galleries.zip"))
query.handleCriterion(ctx, stringCriterionHandler(galleryFilter.Path, "galleries.path"))
query.handleCriterion(ctx, intCriterionHandler(galleryFilter.Rating, "galleries.rating"))
query.handleCriterion(ctx, stringCriterionHandler(galleryFilter.URL, "galleries.url"))
query.handleCriterion(ctx, boolCriterionHandler(galleryFilter.Organized, "galleries.organized"))
query.handleCriterion(ctx, galleryIsMissingCriterionHandler(qb, galleryFilter.IsMissing))
query.handleCriterion(ctx, galleryTagsCriterionHandler(qb, galleryFilter.Tags))
query.handleCriterion(ctx, galleryTagCountCriterionHandler(qb, galleryFilter.TagCount))
query.handleCriterion(ctx, galleryPerformersCriterionHandler(qb, galleryFilter.Performers))
query.handleCriterion(ctx, galleryPerformerCountCriterionHandler(qb, galleryFilter.PerformerCount))
query.handleCriterion(ctx, galleryStudioCriterionHandler(qb, galleryFilter.Studios))
query.handleCriterion(ctx, galleryPerformerTagsCriterionHandler(qb, galleryFilter.PerformerTags))
query.handleCriterion(ctx, galleryAverageResolutionCriterionHandler(qb, galleryFilter.AverageResolution))
query.handleCriterion(ctx, galleryImageCountCriterionHandler(qb, galleryFilter.ImageCount))
query.handleCriterion(ctx, galleryPerformerFavoriteCriterionHandler(galleryFilter.PerformerFavorite))
query.handleCriterion(ctx, galleryPerformerAgeCriterionHandler(galleryFilter.PerformerAge))
return query
}
func (qb *galleryQueryBuilder) makeQuery(galleryFilter *models.GalleryFilterType, findFilter *models.FindFilterType) (*queryBuilder, error) {
func (qb *galleryQueryBuilder) makeQuery(ctx context.Context, galleryFilter *models.GalleryFilterType, findFilter *models.FindFilterType) (*queryBuilder, error) {
if galleryFilter == nil {
galleryFilter = &models.GalleryFilterType{}
}
@@ -245,7 +243,7 @@ func (qb *galleryQueryBuilder) makeQuery(galleryFilter *models.GalleryFilterType
if err := qb.validateFilter(galleryFilter); err != nil {
return nil, err
}
filter := qb.makeFilter(galleryFilter)
filter := qb.makeFilter(ctx, galleryFilter)
query.addFilter(filter)
@@ -254,20 +252,20 @@ func (qb *galleryQueryBuilder) makeQuery(galleryFilter *models.GalleryFilterType
return &query, nil
}
func (qb *galleryQueryBuilder) Query(galleryFilter *models.GalleryFilterType, findFilter *models.FindFilterType) ([]*models.Gallery, int, error) {
query, err := qb.makeQuery(galleryFilter, findFilter)
func (qb *galleryQueryBuilder) Query(ctx context.Context, galleryFilter *models.GalleryFilterType, findFilter *models.FindFilterType) ([]*models.Gallery, int, error) {
query, err := qb.makeQuery(ctx, galleryFilter, findFilter)
if err != nil {
return nil, 0, err
}
idsResult, countResult, err := query.executeFind()
idsResult, countResult, err := query.executeFind(ctx)
if err != nil {
return nil, 0, err
}
var galleries []*models.Gallery
for _, id := range idsResult {
gallery, err := qb.Find(id)
gallery, err := qb.Find(ctx, id)
if err != nil {
return nil, 0, err
}
@@ -278,17 +276,17 @@ func (qb *galleryQueryBuilder) Query(galleryFilter *models.GalleryFilterType, fi
return galleries, countResult, nil
}
func (qb *galleryQueryBuilder) QueryCount(galleryFilter *models.GalleryFilterType, findFilter *models.FindFilterType) (int, error) {
query, err := qb.makeQuery(galleryFilter, findFilter)
func (qb *galleryQueryBuilder) QueryCount(ctx context.Context, galleryFilter *models.GalleryFilterType, findFilter *models.FindFilterType) (int, error) {
query, err := qb.makeQuery(ctx, galleryFilter, findFilter)
if err != nil {
return 0, err
}
return query.executeCount()
return query.executeCount(ctx)
}
func galleryIsMissingCriterionHandler(qb *galleryQueryBuilder, isMissing *string) criterionHandlerFunc {
return func(f *filterBuilder) {
return func(ctx context.Context, f *filterBuilder) {
if isMissing != nil && *isMissing != "" {
switch *isMissing {
case "scenes":
@@ -389,7 +387,7 @@ func galleryStudioCriterionHandler(qb *galleryQueryBuilder, studios *models.Hier
}
func galleryPerformerTagsCriterionHandler(qb *galleryQueryBuilder, tags *models.HierarchicalMultiCriterionInput) criterionHandlerFunc {
return func(f *filterBuilder) {
return func(ctx context.Context, f *filterBuilder) {
if tags != nil {
if tags.Modifier == models.CriterionModifierIsNull || tags.Modifier == models.CriterionModifierNotNull {
var notClause string
@@ -408,7 +406,7 @@ func galleryPerformerTagsCriterionHandler(qb *galleryQueryBuilder, tags *models.
return
}
valuesClause := getHierarchicalValues(qb.tx, tags.Value, tagTable, "tags_relations", "", tags.Depth)
valuesClause := getHierarchicalValues(ctx, qb.tx, tags.Value, tagTable, "tags_relations", "", tags.Depth)
f.addWith(`performer_tags AS (
SELECT pg.gallery_id, t.column1 AS root_tag_id FROM performers_galleries pg
@@ -424,7 +422,7 @@ INNER JOIN (` + valuesClause + `) t ON t.column2 = pt.tag_id
}
func galleryPerformerFavoriteCriterionHandler(performerfavorite *bool) criterionHandlerFunc {
return func(f *filterBuilder) {
return func(ctx context.Context, f *filterBuilder) {
if performerfavorite != nil {
f.addLeftJoin("performers_galleries", "", "galleries.id = performers_galleries.gallery_id")
@@ -444,7 +442,7 @@ GROUP BY performers_galleries.gallery_id HAVING SUM(performers.favorite) = 0)`,
}
func galleryPerformerAgeCriterionHandler(performerAge *models.IntCriterionInput) criterionHandlerFunc {
return func(f *filterBuilder) {
return func(ctx context.Context, f *filterBuilder) {
if performerAge != nil {
f.addInnerJoin("performers_galleries", "", "galleries.id = performers_galleries.gallery_id")
f.addInnerJoin("performers", "", "performers_galleries.performer_id = performers.id")
@@ -461,7 +459,7 @@ func galleryPerformerAgeCriterionHandler(performerAge *models.IntCriterionInput)
}
func galleryAverageResolutionCriterionHandler(qb *galleryQueryBuilder, resolution *models.ResolutionCriterionInput) criterionHandlerFunc {
return func(f *filterBuilder) {
return func(ctx context.Context, f *filterBuilder) {
if resolution != nil && resolution.Value.IsValid() {
qb.imagesRepository().join(f, "images_join", "galleries.id")
f.addLeftJoin("images", "", "images_join.image_id = images.id")
@@ -505,17 +503,17 @@ func (qb *galleryQueryBuilder) getGallerySort(findFilter *models.FindFilterType)
}
}
func (qb *galleryQueryBuilder) queryGallery(query string, args []interface{}) (*models.Gallery, error) {
results, err := qb.queryGalleries(query, args)
func (qb *galleryQueryBuilder) queryGallery(ctx context.Context, query string, args []interface{}) (*models.Gallery, error) {
results, err := qb.queryGalleries(ctx, query, args)
if err != nil || len(results) < 1 {
return nil, err
}
return results[0], nil
}
func (qb *galleryQueryBuilder) queryGalleries(query string, args []interface{}) ([]*models.Gallery, error) {
func (qb *galleryQueryBuilder) queryGalleries(ctx context.Context, query string, args []interface{}) ([]*models.Gallery, error) {
var ret models.Galleries
if err := qb.query(query, args, &ret); err != nil {
if err := qb.query(ctx, query, args, &ret); err != nil {
return nil, err
}
@@ -533,13 +531,13 @@ func (qb *galleryQueryBuilder) performersRepository() *joinRepository {
}
}
func (qb *galleryQueryBuilder) GetPerformerIDs(galleryID int) ([]int, error) {
return qb.performersRepository().getIDs(galleryID)
func (qb *galleryQueryBuilder) GetPerformerIDs(ctx context.Context, galleryID int) ([]int, error) {
return qb.performersRepository().getIDs(ctx, galleryID)
}
func (qb *galleryQueryBuilder) UpdatePerformers(galleryID int, performerIDs []int) error {
func (qb *galleryQueryBuilder) UpdatePerformers(ctx context.Context, galleryID int, performerIDs []int) error {
// Delete the existing joins and then create new ones
return qb.performersRepository().replace(galleryID, performerIDs)
return qb.performersRepository().replace(ctx, galleryID, performerIDs)
}
func (qb *galleryQueryBuilder) tagsRepository() *joinRepository {
@@ -553,13 +551,13 @@ func (qb *galleryQueryBuilder) tagsRepository() *joinRepository {
}
}
func (qb *galleryQueryBuilder) GetTagIDs(galleryID int) ([]int, error) {
return qb.tagsRepository().getIDs(galleryID)
func (qb *galleryQueryBuilder) GetTagIDs(ctx context.Context, galleryID int) ([]int, error) {
return qb.tagsRepository().getIDs(ctx, galleryID)
}
func (qb *galleryQueryBuilder) UpdateTags(galleryID int, tagIDs []int) error {
func (qb *galleryQueryBuilder) UpdateTags(ctx context.Context, galleryID int, tagIDs []int) error {
// Delete the existing joins and then create new ones
return qb.tagsRepository().replace(galleryID, tagIDs)
return qb.tagsRepository().replace(ctx, galleryID, tagIDs)
}
func (qb *galleryQueryBuilder) imagesRepository() *joinRepository {
@@ -573,13 +571,13 @@ func (qb *galleryQueryBuilder) imagesRepository() *joinRepository {
}
}
func (qb *galleryQueryBuilder) GetImageIDs(galleryID int) ([]int, error) {
return qb.imagesRepository().getIDs(galleryID)
func (qb *galleryQueryBuilder) GetImageIDs(ctx context.Context, galleryID int) ([]int, error) {
return qb.imagesRepository().getIDs(ctx, galleryID)
}
func (qb *galleryQueryBuilder) UpdateImages(galleryID int, imageIDs []int) error {
func (qb *galleryQueryBuilder) UpdateImages(ctx context.Context, galleryID int, imageIDs []int) error {
// Delete the existing joins and then create new ones
return qb.imagesRepository().replace(galleryID, imageIDs)
return qb.imagesRepository().replace(ctx, galleryID, imageIDs)
}
func (qb *galleryQueryBuilder) scenesRepository() *joinRepository {
@@ -593,11 +591,11 @@ func (qb *galleryQueryBuilder) scenesRepository() *joinRepository {
}
}
func (qb *galleryQueryBuilder) GetSceneIDs(galleryID int) ([]int, error) {
return qb.scenesRepository().getIDs(galleryID)
func (qb *galleryQueryBuilder) GetSceneIDs(ctx context.Context, galleryID int) ([]int, error) {
return qb.scenesRepository().getIDs(ctx, galleryID)
}
func (qb *galleryQueryBuilder) UpdateScenes(galleryID int, sceneIDs []int) error {
func (qb *galleryQueryBuilder) UpdateScenes(ctx context.Context, galleryID int, sceneIDs []int) error {
// Delete the existing joins and then create new ones
return qb.scenesRepository().replace(galleryID, sceneIDs)
return qb.scenesRepository().replace(ctx, galleryID, sceneIDs)
}