mirror of
https://github.com/stashapp/stash.git
synced 2025-12-17 20:34:37 +03:00
Performer refactor (#3057)
* Separate performer model from sqlite model * Use GenderEnum for gender
This commit is contained in:
@@ -3,15 +3,17 @@ package sqlite
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/doug-martin/goqu/v9"
|
||||
"github.com/doug-martin/goqu/v9/exp"
|
||||
"github.com/jmoiron/sqlx"
|
||||
"github.com/stashapp/stash/pkg/models"
|
||||
"github.com/stashapp/stash/pkg/sliceutil/intslice"
|
||||
"github.com/stashapp/stash/pkg/utils"
|
||||
"gopkg.in/guregu/null.v4"
|
||||
"gopkg.in/guregu/null.v4/zero"
|
||||
)
|
||||
|
||||
const performerTable = "performers"
|
||||
@@ -19,82 +21,227 @@ const performerIDColumn = "performer_id"
|
||||
const performersTagsTable = "performers_tags"
|
||||
const performersImageTable = "performers_image" // performer cover image
|
||||
|
||||
var countPerformersForTagQuery = `
|
||||
SELECT tag_id AS id FROM performers_tags
|
||||
WHERE performers_tags.tag_id = ?
|
||||
GROUP BY performers_tags.performer_id
|
||||
`
|
||||
type performerRow struct {
|
||||
ID int `db:"id" goqu:"skipinsert"`
|
||||
Checksum string `db:"checksum"`
|
||||
Name zero.String `db:"name"`
|
||||
Gender zero.String `db:"gender"`
|
||||
URL zero.String `db:"url"`
|
||||
Twitter zero.String `db:"twitter"`
|
||||
Instagram zero.String `db:"instagram"`
|
||||
Birthdate models.SQLiteDate `db:"birthdate"`
|
||||
Ethnicity zero.String `db:"ethnicity"`
|
||||
Country zero.String `db:"country"`
|
||||
EyeColor zero.String `db:"eye_color"`
|
||||
Height zero.String `db:"height"`
|
||||
Measurements zero.String `db:"measurements"`
|
||||
FakeTits zero.String `db:"fake_tits"`
|
||||
CareerLength zero.String `db:"career_length"`
|
||||
Tattoos zero.String `db:"tattoos"`
|
||||
Piercings zero.String `db:"piercings"`
|
||||
Aliases zero.String `db:"aliases"`
|
||||
Favorite sql.NullBool `db:"favorite"`
|
||||
CreatedAt models.SQLiteTimestamp `db:"created_at"`
|
||||
UpdatedAt models.SQLiteTimestamp `db:"updated_at"`
|
||||
Rating null.Int `db:"rating"`
|
||||
Details zero.String `db:"details"`
|
||||
DeathDate models.SQLiteDate `db:"death_date"`
|
||||
HairColor zero.String `db:"hair_color"`
|
||||
Weight null.Int `db:"weight"`
|
||||
IgnoreAutoTag bool `db:"ignore_auto_tag"`
|
||||
}
|
||||
|
||||
type performerQueryBuilder struct {
|
||||
func (r *performerRow) fromPerformer(o models.Performer) {
|
||||
r.ID = o.ID
|
||||
r.Checksum = o.Checksum
|
||||
r.Name = zero.StringFrom(o.Name)
|
||||
if o.Gender.IsValid() {
|
||||
r.Gender = zero.StringFrom(o.Gender.String())
|
||||
}
|
||||
r.URL = zero.StringFrom(o.URL)
|
||||
r.Twitter = zero.StringFrom(o.Twitter)
|
||||
r.Instagram = zero.StringFrom(o.Instagram)
|
||||
if o.Birthdate != nil {
|
||||
_ = r.Birthdate.Scan(o.Birthdate.Time)
|
||||
}
|
||||
r.Ethnicity = zero.StringFrom(o.Ethnicity)
|
||||
r.Country = zero.StringFrom(o.Country)
|
||||
r.EyeColor = zero.StringFrom(o.EyeColor)
|
||||
r.Height = zero.StringFrom(o.Height)
|
||||
r.Measurements = zero.StringFrom(o.Measurements)
|
||||
r.FakeTits = zero.StringFrom(o.FakeTits)
|
||||
r.CareerLength = zero.StringFrom(o.CareerLength)
|
||||
r.Tattoos = zero.StringFrom(o.Tattoos)
|
||||
r.Piercings = zero.StringFrom(o.Piercings)
|
||||
r.Aliases = zero.StringFrom(o.Aliases)
|
||||
r.Favorite = sql.NullBool{Bool: o.Favorite, Valid: true}
|
||||
r.CreatedAt = models.SQLiteTimestamp{Timestamp: o.CreatedAt}
|
||||
r.UpdatedAt = models.SQLiteTimestamp{Timestamp: o.UpdatedAt}
|
||||
r.Rating = intFromPtr(o.Rating)
|
||||
r.Details = zero.StringFrom(o.Details)
|
||||
if o.DeathDate != nil {
|
||||
_ = r.DeathDate.Scan(o.DeathDate.Time)
|
||||
}
|
||||
r.HairColor = zero.StringFrom(o.HairColor)
|
||||
r.Weight = intFromPtr(o.Weight)
|
||||
r.IgnoreAutoTag = o.IgnoreAutoTag
|
||||
}
|
||||
|
||||
func (r *performerRow) resolve() *models.Performer {
|
||||
ret := &models.Performer{
|
||||
ID: r.ID,
|
||||
Checksum: r.Checksum,
|
||||
Name: r.Name.String,
|
||||
Gender: models.GenderEnum(r.Gender.String),
|
||||
URL: r.URL.String,
|
||||
Twitter: r.Twitter.String,
|
||||
Instagram: r.Instagram.String,
|
||||
Birthdate: r.Birthdate.DatePtr(),
|
||||
Ethnicity: r.Ethnicity.String,
|
||||
Country: r.Country.String,
|
||||
EyeColor: r.EyeColor.String,
|
||||
Height: r.Height.String,
|
||||
Measurements: r.Measurements.String,
|
||||
FakeTits: r.FakeTits.String,
|
||||
CareerLength: r.CareerLength.String,
|
||||
Tattoos: r.Tattoos.String,
|
||||
Piercings: r.Piercings.String,
|
||||
Aliases: r.Aliases.String,
|
||||
Favorite: r.Favorite.Bool,
|
||||
CreatedAt: r.CreatedAt.Timestamp,
|
||||
UpdatedAt: r.UpdatedAt.Timestamp,
|
||||
Rating: nullIntPtr(r.Rating),
|
||||
Details: r.Details.String,
|
||||
DeathDate: r.DeathDate.DatePtr(),
|
||||
HairColor: r.HairColor.String,
|
||||
Weight: nullIntPtr(r.Weight),
|
||||
IgnoreAutoTag: r.IgnoreAutoTag,
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
type performerRowRecord struct {
|
||||
updateRecord
|
||||
}
|
||||
|
||||
func (r *performerRowRecord) fromPartial(o models.PerformerPartial) {
|
||||
r.setNullString("checksum", o.Checksum)
|
||||
r.setNullString("name", o.Name)
|
||||
r.setNullString("gender", o.Gender)
|
||||
r.setNullString("url", o.URL)
|
||||
r.setNullString("twitter", o.Twitter)
|
||||
r.setNullString("instagram", o.Instagram)
|
||||
r.setSQLiteDate("birthdate", o.Birthdate)
|
||||
r.setNullString("ethnicity", o.Ethnicity)
|
||||
r.setNullString("country", o.Country)
|
||||
r.setNullString("eye_color", o.EyeColor)
|
||||
r.setNullString("height", o.Height)
|
||||
r.setNullString("measurements", o.Measurements)
|
||||
r.setNullString("fake_tits", o.FakeTits)
|
||||
r.setNullString("career_length", o.CareerLength)
|
||||
r.setNullString("tattoos", o.Tattoos)
|
||||
r.setNullString("piercings", o.Piercings)
|
||||
r.setNullString("aliases", o.Aliases)
|
||||
r.setBool("favorite", o.Favorite)
|
||||
r.setSQLiteTimestamp("created_at", o.CreatedAt)
|
||||
r.setSQLiteTimestamp("updated_at", o.UpdatedAt)
|
||||
r.setNullInt("rating", o.Rating)
|
||||
r.setNullString("details", o.Details)
|
||||
r.setSQLiteDate("death_date", o.DeathDate)
|
||||
r.setNullString("hair_color", o.HairColor)
|
||||
r.setNullInt("weight", o.Weight)
|
||||
r.setBool("ignore_auto_tag", o.IgnoreAutoTag)
|
||||
}
|
||||
|
||||
type PerformerStore struct {
|
||||
repository
|
||||
|
||||
tableMgr *table
|
||||
}
|
||||
|
||||
var PerformerReaderWriter = &performerQueryBuilder{
|
||||
repository{
|
||||
tableName: performerTable,
|
||||
idColumn: idColumn,
|
||||
},
|
||||
func NewPerformerStore() *PerformerStore {
|
||||
return &PerformerStore{
|
||||
repository: repository{
|
||||
tableName: performerTable,
|
||||
idColumn: idColumn,
|
||||
},
|
||||
tableMgr: performerTableMgr,
|
||||
}
|
||||
}
|
||||
|
||||
func (qb *performerQueryBuilder) Create(ctx context.Context, newObject models.Performer) (*models.Performer, error) {
|
||||
var ret models.Performer
|
||||
if err := qb.insertObject(ctx, newObject, &ret); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
func (qb *PerformerStore) Create(ctx context.Context, newObject *models.Performer) error {
|
||||
var r performerRow
|
||||
r.fromPerformer(*newObject)
|
||||
|
||||
return &ret, nil
|
||||
}
|
||||
|
||||
func (qb *performerQueryBuilder) Update(ctx context.Context, updatedObject models.PerformerPartial) (*models.Performer, error) {
|
||||
const partial = true
|
||||
if err := qb.update(ctx, updatedObject.ID, updatedObject, partial); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var ret models.Performer
|
||||
if err := qb.getByID(ctx, updatedObject.ID, &ret); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &ret, nil
|
||||
}
|
||||
|
||||
func (qb *performerQueryBuilder) UpdateFull(ctx context.Context, updatedObject models.Performer) (*models.Performer, error) {
|
||||
const partial = false
|
||||
if err := qb.update(ctx, updatedObject.ID, updatedObject, partial); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var ret models.Performer
|
||||
if err := qb.getByID(ctx, updatedObject.ID, &ret); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &ret, nil
|
||||
}
|
||||
|
||||
func (qb *performerQueryBuilder) Destroy(ctx context.Context, id int) error {
|
||||
// TODO - add on delete cascade to performers_scenes
|
||||
_, err := qb.tx.Exec(ctx, "DELETE FROM performers_scenes WHERE performer_id = ?", id)
|
||||
id, err := qb.tableMgr.insertID(ctx, r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
updated, err := qb.Find(ctx, id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("finding after create: %w", err)
|
||||
}
|
||||
|
||||
*newObject = *updated
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (qb *PerformerStore) UpdatePartial(ctx context.Context, id int, updatedObject models.PerformerPartial) (*models.Performer, error) {
|
||||
r := performerRowRecord{
|
||||
updateRecord{
|
||||
Record: make(exp.Record),
|
||||
},
|
||||
}
|
||||
|
||||
r.fromPartial(updatedObject)
|
||||
|
||||
if len(r.Record) > 0 {
|
||||
if err := qb.tableMgr.updateByID(ctx, id, r.Record); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return qb.Find(ctx, id)
|
||||
}
|
||||
|
||||
func (qb *PerformerStore) Update(ctx context.Context, updatedObject *models.Performer) error {
|
||||
var r performerRow
|
||||
r.fromPerformer(*updatedObject)
|
||||
|
||||
if err := qb.tableMgr.updateByID(ctx, updatedObject.ID, r); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (qb *PerformerStore) Destroy(ctx context.Context, id int) error {
|
||||
return qb.destroyExisting(ctx, []int{id})
|
||||
}
|
||||
|
||||
func (qb *performerQueryBuilder) Find(ctx context.Context, id int) (*models.Performer, error) {
|
||||
var ret models.Performer
|
||||
if err := qb.getByID(ctx, id, &ret); err != nil {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return &ret, nil
|
||||
func (qb *PerformerStore) table() exp.IdentifierExpression {
|
||||
return qb.tableMgr.table
|
||||
}
|
||||
|
||||
func (qb *performerQueryBuilder) FindMany(ctx context.Context, ids []int) ([]*models.Performer, error) {
|
||||
func (qb *PerformerStore) selectDataset() *goqu.SelectDataset {
|
||||
return dialect.From(qb.table()).Select(qb.table().All())
|
||||
}
|
||||
|
||||
func (qb *PerformerStore) Find(ctx context.Context, id int) (*models.Performer, error) {
|
||||
q := qb.selectDataset().Where(qb.tableMgr.byID(id))
|
||||
|
||||
ret, err := qb.get(ctx, q)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("getting scene by id %d: %w", id, err)
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (qb *PerformerStore) FindMany(ctx context.Context, ids []int) ([]*models.Performer, error) {
|
||||
tableMgr := performerTableMgr
|
||||
q := goqu.Select("*").From(tableMgr.table).Where(tableMgr.byIDInts(ids...))
|
||||
unsorted, err := qb.getMany(ctx, q)
|
||||
@@ -118,16 +265,31 @@ func (qb *performerQueryBuilder) FindMany(ctx context.Context, ids []int) ([]*mo
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (qb *performerQueryBuilder) getMany(ctx context.Context, q *goqu.SelectDataset) ([]*models.Performer, error) {
|
||||
func (qb *PerformerStore) get(ctx context.Context, q *goqu.SelectDataset) (*models.Performer, error) {
|
||||
ret, err := qb.getMany(ctx, q)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(ret) == 0 {
|
||||
return nil, sql.ErrNoRows
|
||||
}
|
||||
|
||||
return ret[0], nil
|
||||
}
|
||||
|
||||
func (qb *PerformerStore) getMany(ctx context.Context, q *goqu.SelectDataset) ([]*models.Performer, error) {
|
||||
const single = false
|
||||
var ret []*models.Performer
|
||||
if err := queryFunc(ctx, q, single, func(r *sqlx.Rows) error {
|
||||
var f models.Performer
|
||||
var f performerRow
|
||||
if err := r.StructScan(&f); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ret = append(ret, &f)
|
||||
s := f.resolve()
|
||||
|
||||
ret = append(ret, s)
|
||||
return nil
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
@@ -136,95 +298,126 @@ func (qb *performerQueryBuilder) getMany(ctx context.Context, q *goqu.SelectData
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (qb *performerQueryBuilder) FindBySceneID(ctx context.Context, sceneID int) ([]*models.Performer, error) {
|
||||
query := selectAll("performers") + `
|
||||
LEFT JOIN performers_scenes as scenes_join on scenes_join.performer_id = performers.id
|
||||
WHERE scenes_join.scene_id = ?
|
||||
`
|
||||
args := []interface{}{sceneID}
|
||||
return qb.queryPerformers(ctx, query, args)
|
||||
func (qb *PerformerStore) findBySubquery(ctx context.Context, sq *goqu.SelectDataset) ([]*models.Performer, error) {
|
||||
table := qb.table()
|
||||
|
||||
q := qb.selectDataset().Where(
|
||||
table.Col(idColumn).Eq(
|
||||
sq,
|
||||
),
|
||||
)
|
||||
|
||||
return qb.getMany(ctx, q)
|
||||
}
|
||||
|
||||
func (qb *performerQueryBuilder) FindByImageID(ctx context.Context, imageID int) ([]*models.Performer, error) {
|
||||
query := selectAll("performers") + `
|
||||
LEFT JOIN performers_images as images_join on images_join.performer_id = performers.id
|
||||
WHERE images_join.image_id = ?
|
||||
`
|
||||
args := []interface{}{imageID}
|
||||
return qb.queryPerformers(ctx, query, args)
|
||||
}
|
||||
func (qb *PerformerStore) FindBySceneID(ctx context.Context, sceneID int) ([]*models.Performer, error) {
|
||||
sq := dialect.From(scenesPerformersJoinTable).Select(scenesPerformersJoinTable.Col(performerIDColumn)).Where(
|
||||
scenesPerformersJoinTable.Col(sceneIDColumn).Eq(sceneID),
|
||||
)
|
||||
ret, err := qb.findBySubquery(ctx, sq)
|
||||
|
||||
func (qb *performerQueryBuilder) FindByGalleryID(ctx context.Context, galleryID int) ([]*models.Performer, error) {
|
||||
query := selectAll("performers") + `
|
||||
LEFT JOIN performers_galleries as galleries_join on galleries_join.performer_id = performers.id
|
||||
WHERE galleries_join.gallery_id = ?
|
||||
`
|
||||
args := []interface{}{galleryID}
|
||||
return qb.queryPerformers(ctx, query, args)
|
||||
}
|
||||
|
||||
func (qb *performerQueryBuilder) FindNamesBySceneID(ctx context.Context, sceneID int) ([]*models.Performer, error) {
|
||||
query := `
|
||||
SELECT performers.name FROM performers
|
||||
LEFT JOIN performers_scenes as scenes_join on scenes_join.performer_id = performers.id
|
||||
WHERE scenes_join.scene_id = ?
|
||||
`
|
||||
args := []interface{}{sceneID}
|
||||
return qb.queryPerformers(ctx, query, args)
|
||||
}
|
||||
|
||||
func (qb *performerQueryBuilder) FindByNames(ctx context.Context, names []string, nocase bool) ([]*models.Performer, error) {
|
||||
query := "SELECT * FROM performers WHERE name"
|
||||
if nocase {
|
||||
query += " COLLATE NOCASE"
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("getting performers for scene %d: %w", sceneID, err)
|
||||
}
|
||||
query += " IN " + getInBinding(len(names))
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (qb *PerformerStore) FindByImageID(ctx context.Context, imageID int) ([]*models.Performer, error) {
|
||||
sq := dialect.From(performersImagesJoinTable).Select(performersImagesJoinTable.Col(performerIDColumn)).Where(
|
||||
performersImagesJoinTable.Col(imageIDColumn).Eq(imageID),
|
||||
)
|
||||
ret, err := qb.findBySubquery(ctx, sq)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("getting performers for image %d: %w", imageID, err)
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (qb *PerformerStore) FindByGalleryID(ctx context.Context, galleryID int) ([]*models.Performer, error) {
|
||||
sq := dialect.From(performersGalleriesJoinTable).Select(performersGalleriesJoinTable.Col(performerIDColumn)).Where(
|
||||
performersGalleriesJoinTable.Col(galleryIDColumn).Eq(galleryID),
|
||||
)
|
||||
ret, err := qb.findBySubquery(ctx, sq)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("getting performers for gallery %d: %w", galleryID, err)
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (qb *PerformerStore) FindByNames(ctx context.Context, names []string, nocase bool) ([]*models.Performer, error) {
|
||||
clause := "name "
|
||||
if nocase {
|
||||
clause += "COLLATE NOCASE "
|
||||
}
|
||||
clause += "IN " + getInBinding(len(names))
|
||||
|
||||
var args []interface{}
|
||||
for _, name := range names {
|
||||
args = append(args, name)
|
||||
}
|
||||
return qb.queryPerformers(ctx, query, args)
|
||||
}
|
||||
|
||||
func (qb *performerQueryBuilder) CountByTagID(ctx context.Context, tagID int) (int, error) {
|
||||
args := []interface{}{tagID}
|
||||
return qb.runCountQuery(ctx, qb.buildCountQuery(countPerformersForTagQuery), args)
|
||||
}
|
||||
sq := qb.selectDataset().Prepared(true).Where(
|
||||
goqu.L(clause, args...),
|
||||
)
|
||||
ret, err := qb.getMany(ctx, sq)
|
||||
|
||||
func (qb *performerQueryBuilder) Count(ctx context.Context) (int, error) {
|
||||
return qb.runCountQuery(ctx, qb.buildCountQuery("SELECT performers.id FROM performers"), nil)
|
||||
}
|
||||
|
||||
func (qb *performerQueryBuilder) All(ctx context.Context) ([]*models.Performer, error) {
|
||||
return qb.queryPerformers(ctx, selectAll("performers")+qb.getPerformerSort(nil), nil)
|
||||
}
|
||||
|
||||
func (qb *performerQueryBuilder) QueryForAutoTag(ctx context.Context, words []string) ([]*models.Performer, error) {
|
||||
// TODO - Query needs to be changed to support queries of this type, and
|
||||
// this method should be removed
|
||||
query := selectAll(performerTable)
|
||||
|
||||
var whereClauses []string
|
||||
var args []interface{}
|
||||
|
||||
for _, w := range words {
|
||||
whereClauses = append(whereClauses, "name like ?")
|
||||
args = append(args, w+"%")
|
||||
// TODO - commented out until alias matching works both ways
|
||||
// whereClauses = append(whereClauses, "aliases like ?")
|
||||
// args = append(args, w+"%")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("getting performers by names: %w", err)
|
||||
}
|
||||
|
||||
whereOr := "(" + strings.Join(whereClauses, " OR ") + ")"
|
||||
where := strings.Join([]string{
|
||||
"ignore_auto_tag = 0",
|
||||
whereOr,
|
||||
}, " AND ")
|
||||
return qb.queryPerformers(ctx, query+" WHERE "+where, args)
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (qb *performerQueryBuilder) validateFilter(filter *models.PerformerFilterType) error {
|
||||
func (qb *PerformerStore) CountByTagID(ctx context.Context, tagID int) (int, error) {
|
||||
joinTable := performersTagsJoinTable
|
||||
|
||||
q := dialect.Select(goqu.COUNT("*")).From(joinTable).Where(joinTable.Col(tagIDColumn).Eq(tagID))
|
||||
return count(ctx, q)
|
||||
}
|
||||
|
||||
func (qb *PerformerStore) Count(ctx context.Context) (int, error) {
|
||||
q := dialect.Select(goqu.COUNT("*")).From(qb.table())
|
||||
return count(ctx, q)
|
||||
}
|
||||
|
||||
func (qb *PerformerStore) All(ctx context.Context) ([]*models.Performer, error) {
|
||||
return qb.getMany(ctx, qb.selectDataset())
|
||||
}
|
||||
|
||||
func (qb *PerformerStore) QueryForAutoTag(ctx context.Context, words []string) ([]*models.Performer, error) {
|
||||
// TODO - Query needs to be changed to support queries of this type, and
|
||||
// this method should be removed
|
||||
table := qb.table()
|
||||
sq := dialect.From(table).Select(table.Col(idColumn)).Where()
|
||||
|
||||
var whereClauses []exp.Expression
|
||||
|
||||
for _, w := range words {
|
||||
whereClauses = append(whereClauses, table.Col("name").Like(w+"%"))
|
||||
// TODO - commented out until alias matching works both ways
|
||||
// whereClauses = append(whereClauses, table.Col("aliases").Like(w+"%")
|
||||
}
|
||||
|
||||
sq = sq.Where(
|
||||
goqu.Or(whereClauses...),
|
||||
table.Col("ignore_auto_tag").Eq(0),
|
||||
)
|
||||
|
||||
ret, err := qb.findBySubquery(ctx, sq)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("getting performers for autotag: %w", err)
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (qb *PerformerStore) validateFilter(filter *models.PerformerFilterType) error {
|
||||
const and = "AND"
|
||||
const or = "OR"
|
||||
const not = "NOT"
|
||||
@@ -255,7 +448,7 @@ func (qb *performerQueryBuilder) validateFilter(filter *models.PerformerFilterTy
|
||||
return nil
|
||||
}
|
||||
|
||||
func (qb *performerQueryBuilder) makeFilter(ctx context.Context, filter *models.PerformerFilterType) *filterBuilder {
|
||||
func (qb *PerformerStore) makeFilter(ctx context.Context, filter *models.PerformerFilterType) *filterBuilder {
|
||||
query := &filterBuilder{}
|
||||
|
||||
if filter.And != nil {
|
||||
@@ -322,7 +515,7 @@ func (qb *performerQueryBuilder) makeFilter(ctx context.Context, filter *models.
|
||||
return query
|
||||
}
|
||||
|
||||
func (qb *performerQueryBuilder) Query(ctx context.Context, performerFilter *models.PerformerFilterType, findFilter *models.FindFilterType) ([]*models.Performer, int, error) {
|
||||
func (qb *PerformerStore) Query(ctx context.Context, performerFilter *models.PerformerFilterType, findFilter *models.FindFilterType) ([]*models.Performer, int, error) {
|
||||
if performerFilter == nil {
|
||||
performerFilter = &models.PerformerFilterType{}
|
||||
}
|
||||
@@ -359,7 +552,7 @@ func (qb *performerQueryBuilder) Query(ctx context.Context, performerFilter *mod
|
||||
return performers, countResult, nil
|
||||
}
|
||||
|
||||
func performerIsMissingCriterionHandler(qb *performerQueryBuilder, isMissing *string) criterionHandlerFunc {
|
||||
func performerIsMissingCriterionHandler(qb *PerformerStore, isMissing *string) criterionHandlerFunc {
|
||||
return func(ctx context.Context, f *filterBuilder) {
|
||||
if isMissing != nil && *isMissing != "" {
|
||||
switch *isMissing {
|
||||
@@ -400,7 +593,7 @@ func performerAgeFilterCriterionHandler(age *models.IntCriterionInput) criterion
|
||||
}
|
||||
}
|
||||
|
||||
func performerTagsCriterionHandler(qb *performerQueryBuilder, tags *models.HierarchicalMultiCriterionInput) criterionHandlerFunc {
|
||||
func performerTagsCriterionHandler(qb *PerformerStore, tags *models.HierarchicalMultiCriterionInput) criterionHandlerFunc {
|
||||
h := joinedHierarchicalMultiCriterionHandlerBuilder{
|
||||
tx: qb.tx,
|
||||
|
||||
@@ -417,7 +610,7 @@ func performerTagsCriterionHandler(qb *performerQueryBuilder, tags *models.Hiera
|
||||
return h.handler(tags)
|
||||
}
|
||||
|
||||
func performerTagCountCriterionHandler(qb *performerQueryBuilder, count *models.IntCriterionInput) criterionHandlerFunc {
|
||||
func performerTagCountCriterionHandler(qb *PerformerStore, count *models.IntCriterionInput) criterionHandlerFunc {
|
||||
h := countCriterionHandlerBuilder{
|
||||
primaryTable: performerTable,
|
||||
joinTable: performersTagsTable,
|
||||
@@ -427,7 +620,7 @@ func performerTagCountCriterionHandler(qb *performerQueryBuilder, count *models.
|
||||
return h.handler(count)
|
||||
}
|
||||
|
||||
func performerSceneCountCriterionHandler(qb *performerQueryBuilder, count *models.IntCriterionInput) criterionHandlerFunc {
|
||||
func performerSceneCountCriterionHandler(qb *PerformerStore, count *models.IntCriterionInput) criterionHandlerFunc {
|
||||
h := countCriterionHandlerBuilder{
|
||||
primaryTable: performerTable,
|
||||
joinTable: performersScenesTable,
|
||||
@@ -437,7 +630,7 @@ func performerSceneCountCriterionHandler(qb *performerQueryBuilder, count *model
|
||||
return h.handler(count)
|
||||
}
|
||||
|
||||
func performerImageCountCriterionHandler(qb *performerQueryBuilder, count *models.IntCriterionInput) criterionHandlerFunc {
|
||||
func performerImageCountCriterionHandler(qb *PerformerStore, count *models.IntCriterionInput) criterionHandlerFunc {
|
||||
h := countCriterionHandlerBuilder{
|
||||
primaryTable: performerTable,
|
||||
joinTable: performersImagesTable,
|
||||
@@ -447,7 +640,7 @@ func performerImageCountCriterionHandler(qb *performerQueryBuilder, count *model
|
||||
return h.handler(count)
|
||||
}
|
||||
|
||||
func performerGalleryCountCriterionHandler(qb *performerQueryBuilder, count *models.IntCriterionInput) criterionHandlerFunc {
|
||||
func performerGalleryCountCriterionHandler(qb *PerformerStore, count *models.IntCriterionInput) criterionHandlerFunc {
|
||||
h := countCriterionHandlerBuilder{
|
||||
primaryTable: performerTable,
|
||||
joinTable: performersGalleriesTable,
|
||||
@@ -457,7 +650,7 @@ func performerGalleryCountCriterionHandler(qb *performerQueryBuilder, count *mod
|
||||
return h.handler(count)
|
||||
}
|
||||
|
||||
func performerStudiosCriterionHandler(qb *performerQueryBuilder, studios *models.HierarchicalMultiCriterionInput) criterionHandlerFunc {
|
||||
func performerStudiosCriterionHandler(qb *PerformerStore, studios *models.HierarchicalMultiCriterionInput) criterionHandlerFunc {
|
||||
return func(ctx context.Context, f *filterBuilder) {
|
||||
if studios != nil {
|
||||
formatMaps := []utils.StrFormatMap{
|
||||
@@ -534,7 +727,7 @@ func performerStudiosCriterionHandler(qb *performerQueryBuilder, studios *models
|
||||
}
|
||||
}
|
||||
|
||||
func (qb *performerQueryBuilder) getPerformerSort(findFilter *models.FindFilterType) string {
|
||||
func (qb *PerformerStore) getPerformerSort(findFilter *models.FindFilterType) string {
|
||||
var sort string
|
||||
var direction string
|
||||
if findFilter == nil {
|
||||
@@ -561,16 +754,7 @@ func (qb *performerQueryBuilder) getPerformerSort(findFilter *models.FindFilterT
|
||||
return getSort(sort, direction, "performers")
|
||||
}
|
||||
|
||||
func (qb *performerQueryBuilder) queryPerformers(ctx context.Context, query string, args []interface{}) ([]*models.Performer, error) {
|
||||
var ret models.Performers
|
||||
if err := qb.query(ctx, query, args, &ret); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return []*models.Performer(ret), nil
|
||||
}
|
||||
|
||||
func (qb *performerQueryBuilder) tagsRepository() *joinRepository {
|
||||
func (qb *PerformerStore) tagsRepository() *joinRepository {
|
||||
return &joinRepository{
|
||||
repository: repository{
|
||||
tx: qb.tx,
|
||||
@@ -581,16 +765,16 @@ func (qb *performerQueryBuilder) tagsRepository() *joinRepository {
|
||||
}
|
||||
}
|
||||
|
||||
func (qb *performerQueryBuilder) GetTagIDs(ctx context.Context, id int) ([]int, error) {
|
||||
func (qb *PerformerStore) GetTagIDs(ctx context.Context, id int) ([]int, error) {
|
||||
return qb.tagsRepository().getIDs(ctx, id)
|
||||
}
|
||||
|
||||
func (qb *performerQueryBuilder) UpdateTags(ctx context.Context, id int, tagIDs []int) error {
|
||||
func (qb *PerformerStore) UpdateTags(ctx context.Context, id int, tagIDs []int) error {
|
||||
// Delete the existing joins and then create new ones
|
||||
return qb.tagsRepository().replace(ctx, id, tagIDs)
|
||||
}
|
||||
|
||||
func (qb *performerQueryBuilder) imageRepository() *imageRepository {
|
||||
func (qb *PerformerStore) imageRepository() *imageRepository {
|
||||
return &imageRepository{
|
||||
repository: repository{
|
||||
tx: qb.tx,
|
||||
@@ -601,19 +785,19 @@ func (qb *performerQueryBuilder) imageRepository() *imageRepository {
|
||||
}
|
||||
}
|
||||
|
||||
func (qb *performerQueryBuilder) GetImage(ctx context.Context, performerID int) ([]byte, error) {
|
||||
func (qb *PerformerStore) GetImage(ctx context.Context, performerID int) ([]byte, error) {
|
||||
return qb.imageRepository().get(ctx, performerID)
|
||||
}
|
||||
|
||||
func (qb *performerQueryBuilder) UpdateImage(ctx context.Context, performerID int, image []byte) error {
|
||||
func (qb *PerformerStore) UpdateImage(ctx context.Context, performerID int, image []byte) error {
|
||||
return qb.imageRepository().replace(ctx, performerID, image)
|
||||
}
|
||||
|
||||
func (qb *performerQueryBuilder) DestroyImage(ctx context.Context, performerID int) error {
|
||||
func (qb *PerformerStore) DestroyImage(ctx context.Context, performerID int) error {
|
||||
return qb.imageRepository().destroy(ctx, []int{performerID})
|
||||
}
|
||||
|
||||
func (qb *performerQueryBuilder) stashIDRepository() *stashIDRepository {
|
||||
func (qb *PerformerStore) stashIDRepository() *stashIDRepository {
|
||||
return &stashIDRepository{
|
||||
repository{
|
||||
tx: qb.tx,
|
||||
@@ -623,40 +807,51 @@ func (qb *performerQueryBuilder) stashIDRepository() *stashIDRepository {
|
||||
}
|
||||
}
|
||||
|
||||
func (qb *performerQueryBuilder) GetStashIDs(ctx context.Context, performerID int) ([]models.StashID, error) {
|
||||
func (qb *PerformerStore) GetStashIDs(ctx context.Context, performerID int) ([]models.StashID, error) {
|
||||
return qb.stashIDRepository().get(ctx, performerID)
|
||||
}
|
||||
|
||||
func (qb *performerQueryBuilder) UpdateStashIDs(ctx context.Context, performerID int, stashIDs []models.StashID) error {
|
||||
func (qb *PerformerStore) UpdateStashIDs(ctx context.Context, performerID int, stashIDs []models.StashID) error {
|
||||
return qb.stashIDRepository().replace(ctx, performerID, stashIDs)
|
||||
}
|
||||
|
||||
func (qb *performerQueryBuilder) FindByStashID(ctx context.Context, stashID models.StashID) ([]*models.Performer, error) {
|
||||
query := selectAll("performers") + `
|
||||
LEFT JOIN performer_stash_ids on performer_stash_ids.performer_id = performers.id
|
||||
WHERE performer_stash_ids.stash_id = ?
|
||||
AND performer_stash_ids.endpoint = ?
|
||||
`
|
||||
args := []interface{}{stashID.StashID, stashID.Endpoint}
|
||||
return qb.queryPerformers(ctx, query, args)
|
||||
}
|
||||
func (qb *PerformerStore) FindByStashID(ctx context.Context, stashID models.StashID) ([]*models.Performer, error) {
|
||||
sq := dialect.From(performersStashIDsJoinTable).Select(performersStashIDsJoinTable.Col(performerIDColumn)).Where(
|
||||
performersStashIDsJoinTable.Col("stash_id").Eq(stashID.StashID),
|
||||
performersStashIDsJoinTable.Col("endpoint").Eq(stashID.Endpoint),
|
||||
)
|
||||
ret, err := qb.findBySubquery(ctx, sq)
|
||||
|
||||
func (qb *performerQueryBuilder) FindByStashIDStatus(ctx context.Context, hasStashID bool, stashboxEndpoint string) ([]*models.Performer, error) {
|
||||
query := selectAll("performers") + `
|
||||
LEFT JOIN performer_stash_ids on performer_stash_ids.performer_id = performers.id
|
||||
`
|
||||
|
||||
if hasStashID {
|
||||
query += `
|
||||
WHERE performer_stash_ids.stash_id IS NOT NULL
|
||||
AND performer_stash_ids.endpoint = ?
|
||||
`
|
||||
} else {
|
||||
query += `
|
||||
WHERE performer_stash_ids.stash_id IS NULL
|
||||
`
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("getting performers for stash ID %s: %w", stashID.StashID, err)
|
||||
}
|
||||
|
||||
args := []interface{}{stashboxEndpoint}
|
||||
return qb.queryPerformers(ctx, query, args)
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (qb *PerformerStore) FindByStashIDStatus(ctx context.Context, hasStashID bool, stashboxEndpoint string) ([]*models.Performer, error) {
|
||||
table := qb.table()
|
||||
sq := dialect.From(table).LeftJoin(
|
||||
performersStashIDsJoinTable,
|
||||
goqu.On(table.Col(idColumn).Eq(performersStashIDsJoinTable.Col(performerIDColumn))),
|
||||
).Select(table.Col(idColumn))
|
||||
|
||||
if hasStashID {
|
||||
sq = sq.Where(
|
||||
performersStashIDsJoinTable.Col("stash_id").IsNotNull(),
|
||||
performersStashIDsJoinTable.Col("endpoint").Eq(stashboxEndpoint),
|
||||
)
|
||||
} else {
|
||||
sq = sq.Where(
|
||||
performersStashIDsJoinTable.Col("stash_id").IsNull(),
|
||||
)
|
||||
}
|
||||
|
||||
ret, err := qb.findBySubquery(ctx, sq)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("getting performers for stash-box endpoint %s: %w", stashboxEndpoint, err)
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user