mirror of
https://github.com/stashapp/stash.git
synced 2025-12-17 04:14:39 +03:00
SQLite model refactoring (#3791)
* Remove ID from PerformerPartial * Separate studio model from sqlite model * Separate movie model from sqlite model * Separate tag model from sqlite model * Separate saved filter model from sqlite model * Separate scene marker model from sqlite model * Separate gallery chapter model from sqlite model * Move ErrNoRows checks into sqlite, improve empty result error messages * Move SQLiteDate and SQLiteTimestamp to sqlite * Use changesetTranslator everywhere, refactor for consistency * Make PerformerStore.DestroyImage private * Fix rating on movie create
This commit is contained in:
@@ -3,6 +3,7 @@ package sqlite
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -28,37 +29,37 @@ const (
|
||||
)
|
||||
|
||||
type performerRow struct {
|
||||
ID int `db:"id" goqu:"skipinsert"`
|
||||
Name string `db:"name"`
|
||||
Disambigation zero.String `db:"disambiguation"`
|
||||
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 null.Int `db:"height"`
|
||||
Measurements zero.String `db:"measurements"`
|
||||
FakeTits zero.String `db:"fake_tits"`
|
||||
PenisLength null.Float `db:"penis_length"`
|
||||
Circumcised zero.String `db:"circumcised"`
|
||||
CareerLength zero.String `db:"career_length"`
|
||||
Tattoos zero.String `db:"tattoos"`
|
||||
Piercings zero.String `db:"piercings"`
|
||||
Favorite sql.NullBool `db:"favorite"`
|
||||
CreatedAt models.SQLiteTimestamp `db:"created_at"`
|
||||
UpdatedAt models.SQLiteTimestamp `db:"updated_at"`
|
||||
ID int `db:"id" goqu:"skipinsert"`
|
||||
Name string `db:"name"`
|
||||
Disambigation zero.String `db:"disambiguation"`
|
||||
Gender zero.String `db:"gender"`
|
||||
URL zero.String `db:"url"`
|
||||
Twitter zero.String `db:"twitter"`
|
||||
Instagram zero.String `db:"instagram"`
|
||||
Birthdate NullDate `db:"birthdate"`
|
||||
Ethnicity zero.String `db:"ethnicity"`
|
||||
Country zero.String `db:"country"`
|
||||
EyeColor zero.String `db:"eye_color"`
|
||||
Height null.Int `db:"height"`
|
||||
Measurements zero.String `db:"measurements"`
|
||||
FakeTits zero.String `db:"fake_tits"`
|
||||
PenisLength null.Float `db:"penis_length"`
|
||||
Circumcised zero.String `db:"circumcised"`
|
||||
CareerLength zero.String `db:"career_length"`
|
||||
Tattoos zero.String `db:"tattoos"`
|
||||
Piercings zero.String `db:"piercings"`
|
||||
Favorite bool `db:"favorite"`
|
||||
CreatedAt Timestamp `db:"created_at"`
|
||||
UpdatedAt Timestamp `db:"updated_at"`
|
||||
// expressed as 1-100
|
||||
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"`
|
||||
Rating null.Int `db:"rating"`
|
||||
Details zero.String `db:"details"`
|
||||
DeathDate NullDate `db:"death_date"`
|
||||
HairColor zero.String `db:"hair_color"`
|
||||
Weight null.Int `db:"weight"`
|
||||
IgnoreAutoTag bool `db:"ignore_auto_tag"`
|
||||
|
||||
// not used for resolution
|
||||
// not used in resolution or updates
|
||||
ImageBlob zero.String `db:"image_blob"`
|
||||
}
|
||||
|
||||
@@ -72,9 +73,7 @@ func (r *performerRow) fromPerformer(o models.Performer) {
|
||||
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.Birthdate = NullDateFromDatePtr(o.Birthdate)
|
||||
r.Ethnicity = zero.StringFrom(o.Ethnicity)
|
||||
r.Country = zero.StringFrom(o.Country)
|
||||
r.EyeColor = zero.StringFrom(o.EyeColor)
|
||||
@@ -88,14 +87,12 @@ func (r *performerRow) fromPerformer(o models.Performer) {
|
||||
r.CareerLength = zero.StringFrom(o.CareerLength)
|
||||
r.Tattoos = zero.StringFrom(o.Tattoos)
|
||||
r.Piercings = zero.StringFrom(o.Piercings)
|
||||
r.Favorite = sql.NullBool{Bool: o.Favorite, Valid: true}
|
||||
r.CreatedAt = models.SQLiteTimestamp{Timestamp: o.CreatedAt}
|
||||
r.UpdatedAt = models.SQLiteTimestamp{Timestamp: o.UpdatedAt}
|
||||
r.Favorite = o.Favorite
|
||||
r.CreatedAt = Timestamp{Timestamp: o.CreatedAt}
|
||||
r.UpdatedAt = Timestamp{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.DeathDate = NullDateFromDatePtr(o.DeathDate)
|
||||
r.HairColor = zero.StringFrom(o.HairColor)
|
||||
r.Weight = intFromPtr(o.Weight)
|
||||
r.IgnoreAutoTag = o.IgnoreAutoTag
|
||||
@@ -120,7 +117,7 @@ func (r *performerRow) resolve() *models.Performer {
|
||||
CareerLength: r.CareerLength.String,
|
||||
Tattoos: r.Tattoos.String,
|
||||
Piercings: r.Piercings.String,
|
||||
Favorite: r.Favorite.Bool,
|
||||
Favorite: r.Favorite,
|
||||
CreatedAt: r.CreatedAt.Timestamp,
|
||||
UpdatedAt: r.UpdatedAt.Timestamp,
|
||||
// expressed as 1-100
|
||||
@@ -156,7 +153,7 @@ func (r *performerRowRecord) fromPartial(o models.PerformerPartial) {
|
||||
r.setNullString("url", o.URL)
|
||||
r.setNullString("twitter", o.Twitter)
|
||||
r.setNullString("instagram", o.Instagram)
|
||||
r.setSQLiteDate("birthdate", o.Birthdate)
|
||||
r.setNullDate("birthdate", o.Birthdate)
|
||||
r.setNullString("ethnicity", o.Ethnicity)
|
||||
r.setNullString("country", o.Country)
|
||||
r.setNullString("eye_color", o.EyeColor)
|
||||
@@ -169,11 +166,11 @@ func (r *performerRowRecord) fromPartial(o models.PerformerPartial) {
|
||||
r.setNullString("tattoos", o.Tattoos)
|
||||
r.setNullString("piercings", o.Piercings)
|
||||
r.setBool("favorite", o.Favorite)
|
||||
r.setSQLiteTimestamp("created_at", o.CreatedAt)
|
||||
r.setSQLiteTimestamp("updated_at", o.UpdatedAt)
|
||||
r.setTimestamp("created_at", o.CreatedAt)
|
||||
r.setTimestamp("updated_at", o.UpdatedAt)
|
||||
r.setNullInt("rating", o.Rating)
|
||||
r.setNullString("details", o.Details)
|
||||
r.setSQLiteDate("death_date", o.DeathDate)
|
||||
r.setNullDate("death_date", o.DeathDate)
|
||||
r.setNullString("hair_color", o.HairColor)
|
||||
r.setNullInt("weight", o.Weight)
|
||||
r.setBool("ignore_auto_tag", o.IgnoreAutoTag)
|
||||
@@ -200,6 +197,14 @@ func NewPerformerStore(blobStore *BlobStore) *PerformerStore {
|
||||
}
|
||||
}
|
||||
|
||||
func (qb *PerformerStore) table() exp.IdentifierExpression {
|
||||
return qb.tableMgr.table
|
||||
}
|
||||
|
||||
func (qb *PerformerStore) selectDataset() *goqu.SelectDataset {
|
||||
return dialect.From(qb.table()).Select(qb.table().All())
|
||||
}
|
||||
|
||||
func (qb *PerformerStore) Create(ctx context.Context, newObject *models.Performer) error {
|
||||
var r performerRow
|
||||
r.fromPerformer(*newObject)
|
||||
@@ -227,7 +232,7 @@ func (qb *PerformerStore) Create(ctx context.Context, newObject *models.Performe
|
||||
}
|
||||
}
|
||||
|
||||
updated, err := qb.Find(ctx, id)
|
||||
updated, err := qb.find(ctx, id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("finding after create: %w", err)
|
||||
}
|
||||
@@ -269,7 +274,7 @@ func (qb *PerformerStore) UpdatePartial(ctx context.Context, id int, partial mod
|
||||
}
|
||||
}
|
||||
|
||||
return qb.Find(ctx, id)
|
||||
return qb.find(ctx, id)
|
||||
}
|
||||
|
||||
func (qb *PerformerStore) Update(ctx context.Context, updatedObject *models.Performer) error {
|
||||
@@ -303,30 +308,20 @@ func (qb *PerformerStore) Update(ctx context.Context, updatedObject *models.Perf
|
||||
|
||||
func (qb *PerformerStore) Destroy(ctx context.Context, id int) error {
|
||||
// must handle image checksums manually
|
||||
if err := qb.DestroyImage(ctx, id); err != nil {
|
||||
if err := qb.destroyImage(ctx, id); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return qb.destroyExisting(ctx, []int{id})
|
||||
}
|
||||
|
||||
func (qb *PerformerStore) table() exp.IdentifierExpression {
|
||||
return qb.tableMgr.table
|
||||
}
|
||||
|
||||
func (qb *PerformerStore) selectDataset() *goqu.SelectDataset {
|
||||
return dialect.From(qb.table()).Select(qb.table().All())
|
||||
}
|
||||
|
||||
// returns nil, nil if not found
|
||||
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)
|
||||
ret, err := qb.find(ctx, id)
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
return ret, err
|
||||
}
|
||||
|
||||
func (qb *PerformerStore) FindMany(ctx context.Context, ids []int) ([]*models.Performer, error) {
|
||||
@@ -359,6 +354,31 @@ func (qb *PerformerStore) FindMany(ctx context.Context, ids []int) ([]*models.Pe
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// returns nil, sql.ErrNoRows if not found
|
||||
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, err
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
// returns nil, sql.ErrNoRows if not found
|
||||
func (qb *PerformerStore) get(ctx context.Context, q *goqu.SelectDataset) (*models.Performer, error) {
|
||||
ret, err := qb.getMany(ctx, q)
|
||||
if err != nil {
|
||||
@@ -392,18 +412,6 @@ func (qb *PerformerStore) getMany(ctx context.Context, q *goqu.SelectDataset) ([
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
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 *PerformerStore) FindBySceneID(ctx context.Context, sceneID int) ([]*models.Performer, error) {
|
||||
sq := dialect.From(scenesPerformersJoinTable).Select(scenesPerformersJoinTable.Col(performerIDColumn)).Where(
|
||||
scenesPerformersJoinTable.Col(sceneIDColumn).Eq(sceneID),
|
||||
@@ -1046,7 +1054,7 @@ func (qb *PerformerStore) UpdateImage(ctx context.Context, performerID int, imag
|
||||
return qb.blobJoinQueryBuilder.UpdateImage(ctx, performerID, performerImageBlobColumn, image)
|
||||
}
|
||||
|
||||
func (qb *PerformerStore) DestroyImage(ctx context.Context, performerID int) error {
|
||||
func (qb *PerformerStore) destroyImage(ctx context.Context, performerID int) error {
|
||||
return qb.blobJoinQueryBuilder.DestroyImage(ctx, performerID, performerImageBlobColumn)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user