2023-03-16 04:04:54 +00:00
|
|
|
package sqlite
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2023-06-15 02:46:09 +00:00
|
|
|
"database/sql"
|
|
|
|
"errors"
|
2023-03-16 04:04:54 +00:00
|
|
|
"fmt"
|
2024-10-29 00:26:23 +00:00
|
|
|
"slices"
|
2023-03-16 04:04:54 +00:00
|
|
|
|
2023-06-15 02:46:09 +00:00
|
|
|
"github.com/doug-martin/goqu/v9"
|
|
|
|
"github.com/doug-martin/goqu/v9/exp"
|
|
|
|
"github.com/jmoiron/sqlx"
|
|
|
|
|
2023-03-16 04:04:54 +00:00
|
|
|
"github.com/stashapp/stash/pkg/models"
|
2023-06-15 02:46:09 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
galleriesChaptersTable = "galleries_chapters"
|
2023-03-16 04:04:54 +00:00
|
|
|
)
|
|
|
|
|
2023-06-15 02:46:09 +00:00
|
|
|
type galleryChapterRow struct {
|
|
|
|
ID int `db:"id" goqu:"skipinsert"`
|
2023-07-28 01:22:43 +00:00
|
|
|
Title string `db:"title"` // TODO: make db schema (and gql schema) nullable
|
2023-06-15 02:46:09 +00:00
|
|
|
ImageIndex int `db:"image_index"`
|
|
|
|
GalleryID int `db:"gallery_id"`
|
|
|
|
CreatedAt Timestamp `db:"created_at"`
|
|
|
|
UpdatedAt Timestamp `db:"updated_at"`
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *galleryChapterRow) fromGalleryChapter(o models.GalleryChapter) {
|
|
|
|
r.ID = o.ID
|
|
|
|
r.Title = o.Title
|
|
|
|
r.ImageIndex = o.ImageIndex
|
|
|
|
r.GalleryID = o.GalleryID
|
|
|
|
r.CreatedAt = Timestamp{Timestamp: o.CreatedAt}
|
|
|
|
r.UpdatedAt = Timestamp{Timestamp: o.UpdatedAt}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *galleryChapterRow) resolve() *models.GalleryChapter {
|
|
|
|
ret := &models.GalleryChapter{
|
|
|
|
ID: r.ID,
|
|
|
|
Title: r.Title,
|
|
|
|
ImageIndex: r.ImageIndex,
|
|
|
|
GalleryID: r.GalleryID,
|
|
|
|
CreatedAt: r.CreatedAt.Timestamp,
|
|
|
|
UpdatedAt: r.UpdatedAt.Timestamp,
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret
|
|
|
|
}
|
|
|
|
|
2023-07-26 23:44:06 +00:00
|
|
|
type galleryChapterRowRecord struct {
|
|
|
|
updateRecord
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *galleryChapterRowRecord) fromPartial(o models.GalleryChapterPartial) {
|
2023-07-28 01:22:43 +00:00
|
|
|
// TODO: replace with setNullString after schema is made nullable
|
|
|
|
// r.setNullString("title", o.Title)
|
|
|
|
// saves a null input as the empty string
|
|
|
|
if o.Title.Set {
|
|
|
|
r.set("title", o.Title.Value)
|
|
|
|
}
|
2023-07-26 23:44:06 +00:00
|
|
|
r.setInt("image_index", o.ImageIndex)
|
|
|
|
r.setInt("gallery_id", o.GalleryID)
|
|
|
|
r.setTimestamp("created_at", o.CreatedAt)
|
|
|
|
r.setTimestamp("updated_at", o.UpdatedAt)
|
|
|
|
}
|
|
|
|
|
2023-06-15 02:46:09 +00:00
|
|
|
type GalleryChapterStore struct {
|
2023-03-16 04:04:54 +00:00
|
|
|
repository
|
2023-06-15 02:46:09 +00:00
|
|
|
|
|
|
|
tableMgr *table
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewGalleryChapterStore() *GalleryChapterStore {
|
|
|
|
return &GalleryChapterStore{
|
|
|
|
repository: repository{
|
|
|
|
tableName: galleriesChaptersTable,
|
|
|
|
idColumn: idColumn,
|
|
|
|
},
|
|
|
|
tableMgr: galleriesChaptersTableMgr,
|
|
|
|
}
|
2023-03-16 04:04:54 +00:00
|
|
|
}
|
|
|
|
|
2023-06-15 02:46:09 +00:00
|
|
|
func (qb *GalleryChapterStore) table() exp.IdentifierExpression {
|
|
|
|
return qb.tableMgr.table
|
2023-03-16 04:04:54 +00:00
|
|
|
}
|
|
|
|
|
2023-06-15 02:46:09 +00:00
|
|
|
func (qb *GalleryChapterStore) selectDataset() *goqu.SelectDataset {
|
|
|
|
return dialect.From(qb.table()).Select(qb.table().All())
|
|
|
|
}
|
|
|
|
|
|
|
|
func (qb *GalleryChapterStore) Create(ctx context.Context, newObject *models.GalleryChapter) error {
|
|
|
|
var r galleryChapterRow
|
|
|
|
r.fromGalleryChapter(*newObject)
|
|
|
|
|
|
|
|
id, err := qb.tableMgr.insertID(ctx, r)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
2023-03-16 04:04:54 +00:00
|
|
|
}
|
|
|
|
|
2023-06-15 02:46:09 +00:00
|
|
|
updated, err := qb.find(ctx, id)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("finding after create: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
*newObject = *updated
|
|
|
|
|
|
|
|
return nil
|
2023-03-16 04:04:54 +00:00
|
|
|
}
|
|
|
|
|
2023-06-15 02:46:09 +00:00
|
|
|
func (qb *GalleryChapterStore) Update(ctx context.Context, updatedObject *models.GalleryChapter) error {
|
|
|
|
var r galleryChapterRow
|
|
|
|
r.fromGalleryChapter(*updatedObject)
|
|
|
|
|
|
|
|
if err := qb.tableMgr.updateByID(ctx, updatedObject.ID, r); err != nil {
|
|
|
|
return err
|
2023-03-16 04:04:54 +00:00
|
|
|
}
|
|
|
|
|
2023-06-15 02:46:09 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-07-26 23:44:06 +00:00
|
|
|
func (qb *GalleryChapterStore) UpdatePartial(ctx context.Context, id int, partial models.GalleryChapterPartial) (*models.GalleryChapter, error) {
|
|
|
|
r := galleryChapterRowRecord{
|
|
|
|
updateRecord{
|
|
|
|
Record: make(exp.Record),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
r.fromPartial(partial)
|
|
|
|
|
|
|
|
if len(r.Record) > 0 {
|
|
|
|
if err := qb.tableMgr.updateByID(ctx, id, r.Record); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return qb.find(ctx, id)
|
|
|
|
}
|
|
|
|
|
2023-06-15 02:46:09 +00:00
|
|
|
func (qb *GalleryChapterStore) Destroy(ctx context.Context, id int) error {
|
|
|
|
return qb.destroyExisting(ctx, []int{id})
|
|
|
|
}
|
|
|
|
|
|
|
|
// returns nil, nil if not found
|
|
|
|
func (qb *GalleryChapterStore) Find(ctx context.Context, id int) (*models.GalleryChapter, error) {
|
|
|
|
ret, err := qb.find(ctx, id)
|
|
|
|
if errors.Is(err, sql.ErrNoRows) {
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
return ret, err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (qb *GalleryChapterStore) FindMany(ctx context.Context, ids []int) ([]*models.GalleryChapter, error) {
|
|
|
|
ret := make([]*models.GalleryChapter, len(ids))
|
|
|
|
|
|
|
|
table := qb.table()
|
|
|
|
q := qb.selectDataset().Prepared(true).Where(table.Col(idColumn).In(ids))
|
|
|
|
unsorted, err := qb.getMany(ctx, q)
|
|
|
|
if err != nil {
|
2023-03-16 04:04:54 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2023-06-15 02:46:09 +00:00
|
|
|
for _, s := range unsorted {
|
2024-10-29 00:26:23 +00:00
|
|
|
i := slices.Index(ids, s.ID)
|
2023-06-15 02:46:09 +00:00
|
|
|
ret[i] = s
|
|
|
|
}
|
|
|
|
|
|
|
|
for i := range ret {
|
|
|
|
if ret[i] == nil {
|
|
|
|
return nil, fmt.Errorf("gallery chapter with id %d not found", ids[i])
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret, nil
|
2023-03-16 04:04:54 +00:00
|
|
|
}
|
|
|
|
|
2023-06-15 02:46:09 +00:00
|
|
|
// returns nil, sql.ErrNoRows if not found
|
|
|
|
func (qb *GalleryChapterStore) find(ctx context.Context, id int) (*models.GalleryChapter, error) {
|
|
|
|
q := qb.selectDataset().Where(qb.tableMgr.byID(id))
|
|
|
|
|
|
|
|
ret, err := qb.get(ctx, q)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret, nil
|
2023-03-16 04:04:54 +00:00
|
|
|
}
|
|
|
|
|
2023-06-15 02:46:09 +00:00
|
|
|
// returns nil, sql.ErrNoRows if not found
|
|
|
|
func (qb *GalleryChapterStore) get(ctx context.Context, q *goqu.SelectDataset) (*models.GalleryChapter, error) {
|
|
|
|
ret, err := qb.getMany(ctx, q)
|
|
|
|
if err != nil {
|
2023-03-16 04:04:54 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
2023-06-15 02:46:09 +00:00
|
|
|
|
|
|
|
if len(ret) == 0 {
|
|
|
|
return nil, sql.ErrNoRows
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret[0], nil
|
2023-03-16 04:04:54 +00:00
|
|
|
}
|
|
|
|
|
2023-06-15 02:46:09 +00:00
|
|
|
func (qb *GalleryChapterStore) getMany(ctx context.Context, q *goqu.SelectDataset) ([]*models.GalleryChapter, error) {
|
|
|
|
const single = false
|
|
|
|
var ret []*models.GalleryChapter
|
|
|
|
if err := queryFunc(ctx, q, single, func(r *sqlx.Rows) error {
|
|
|
|
var f galleryChapterRow
|
|
|
|
if err := r.StructScan(&f); err != nil {
|
|
|
|
return err
|
2023-03-16 04:04:54 +00:00
|
|
|
}
|
|
|
|
|
2023-06-15 02:46:09 +00:00
|
|
|
s := f.resolve()
|
2023-03-16 04:04:54 +00:00
|
|
|
|
2023-06-15 02:46:09 +00:00
|
|
|
ret = append(ret, s)
|
|
|
|
return nil
|
|
|
|
}); err != nil {
|
|
|
|
return nil, err
|
2023-03-16 04:04:54 +00:00
|
|
|
}
|
|
|
|
|
2023-06-15 02:46:09 +00:00
|
|
|
return ret, nil
|
2023-03-16 04:04:54 +00:00
|
|
|
}
|
|
|
|
|
2023-06-15 02:46:09 +00:00
|
|
|
func (qb *GalleryChapterStore) FindByGalleryID(ctx context.Context, galleryID int) ([]*models.GalleryChapter, error) {
|
2023-03-16 04:04:54 +00:00
|
|
|
query := `
|
|
|
|
SELECT galleries_chapters.* FROM galleries_chapters
|
|
|
|
WHERE galleries_chapters.gallery_id = ?
|
|
|
|
GROUP BY galleries_chapters.id
|
|
|
|
ORDER BY galleries_chapters.image_index ASC
|
|
|
|
`
|
|
|
|
args := []interface{}{galleryID}
|
|
|
|
return qb.queryGalleryChapters(ctx, query, args)
|
|
|
|
}
|
|
|
|
|
2023-06-15 02:46:09 +00:00
|
|
|
func (qb *GalleryChapterStore) queryGalleryChapters(ctx context.Context, query string, args []interface{}) ([]*models.GalleryChapter, error) {
|
|
|
|
const single = false
|
|
|
|
var ret []*models.GalleryChapter
|
|
|
|
if err := qb.queryFunc(ctx, query, args, single, func(r *sqlx.Rows) error {
|
|
|
|
var f galleryChapterRow
|
|
|
|
if err := r.StructScan(&f); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
s := f.resolve()
|
|
|
|
|
|
|
|
ret = append(ret, s)
|
|
|
|
return nil
|
|
|
|
}); err != nil {
|
2023-03-16 04:04:54 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2023-06-15 02:46:09 +00:00
|
|
|
return ret, nil
|
2023-03-16 04:04:54 +00:00
|
|
|
}
|