mirror of
https://github.com/stashapp/stash.git
synced 2025-12-18 04:44:37 +03:00
Sort case insensitive, date by newest first (#3560)
* Case insensitive search * Fix not adding extra sort when no sort specified. * Using newer version of fvbommel/sortorder package
This commit is contained in:
@@ -5,7 +5,7 @@ import (
|
||||
"database/sql/driver"
|
||||
"fmt"
|
||||
|
||||
"github.com/fvbommel/sortorder"
|
||||
"github.com/fvbommel/sortorder/casefolded"
|
||||
sqlite3 "github.com/mattn/go-sqlite3"
|
||||
)
|
||||
|
||||
@@ -37,9 +37,9 @@ func (d *CustomSQLiteDriver) Open(dsn string) (driver.Conn, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// COLLATE NATURAL_CS - Case sensitive natural sort
|
||||
err := conn.RegisterCollation("NATURAL_CS", func(s string, s2 string) int {
|
||||
if sortorder.NaturalLess(s, s2) {
|
||||
// COLLATE NATURAL_CI - Case insensitive natural sort
|
||||
err := conn.RegisterCollation("NATURAL_CI", func(s string, s2 string) int {
|
||||
if casefolded.NaturalLess(s, s2) {
|
||||
return -1
|
||||
} else {
|
||||
return 1
|
||||
|
||||
@@ -1128,7 +1128,7 @@ func (qb *GalleryStore) setGallerySort(query *queryBuilder, findFilter *models.F
|
||||
// special handling for path
|
||||
addFileTable()
|
||||
addFolderTable()
|
||||
query.sortAndPagination += fmt.Sprintf(" ORDER BY folders.path %s, file_folder.path %[1]s, files.basename %[1]s", direction)
|
||||
query.sortAndPagination += fmt.Sprintf(" ORDER BY COALESCE(folders.path, '') || COALESCE(file_folder.path, '') || COALESCE(files.basename, '') COLLATE NATURAL_CI %s", direction)
|
||||
case "file_mod_time":
|
||||
sort = "mod_time"
|
||||
addFileTable()
|
||||
@@ -1136,10 +1136,13 @@ func (qb *GalleryStore) setGallerySort(query *queryBuilder, findFilter *models.F
|
||||
case "title":
|
||||
addFileTable()
|
||||
addFolderTable()
|
||||
query.sortAndPagination += " ORDER BY COALESCE(galleries.title, files.basename, basename(COALESCE(folders.path, ''))) COLLATE NATURAL_CS " + direction + ", file_folder.path " + direction
|
||||
query.sortAndPagination += " ORDER BY COALESCE(galleries.title, files.basename, basename(COALESCE(folders.path, ''))) COLLATE NATURAL_CI " + direction + ", file_folder.path COLLATE NATURAL_CI " + direction
|
||||
default:
|
||||
query.sortAndPagination += getSort(sort, direction, "galleries")
|
||||
}
|
||||
|
||||
// Whatever the sorting, always use title/id as a final sort
|
||||
query.sortAndPagination += ", COALESCE(galleries.title, galleries.id) COLLATE NATURAL_CI ASC"
|
||||
}
|
||||
|
||||
func (qb *GalleryStore) filesRepository() *filesRepository {
|
||||
|
||||
@@ -1026,7 +1026,7 @@ func (qb *ImageStore) setImageSortAndPagination(q *queryBuilder, findFilter *mod
|
||||
case "path":
|
||||
addFilesJoin()
|
||||
addFolderJoin()
|
||||
sortClause = " ORDER BY folders.path " + direction + ", files.basename " + direction
|
||||
sortClause = " ORDER BY COALESCE(folders.path, '') || COALESCE(files.basename, '') COLLATE NATURAL_CI " + direction
|
||||
case "file_count":
|
||||
sortClause = getCountSort(imageTable, imagesFilesTable, imageIDColumn, direction)
|
||||
case "tag_count":
|
||||
@@ -1039,10 +1039,13 @@ func (qb *ImageStore) setImageSortAndPagination(q *queryBuilder, findFilter *mod
|
||||
case "title":
|
||||
addFilesJoin()
|
||||
addFolderJoin()
|
||||
sortClause = " ORDER BY COALESCE(images.title, files.basename) COLLATE NATURAL_CS " + direction + ", folders.path " + direction
|
||||
sortClause = " ORDER BY COALESCE(images.title, files.basename) COLLATE NATURAL_CI " + direction + ", folders.path COLLATE NATURAL_CI " + direction
|
||||
default:
|
||||
sortClause = getSort(sort, direction, "images")
|
||||
}
|
||||
|
||||
// Whatever the sorting, always use title/id as a final sort
|
||||
sortClause += ", COALESCE(images.title, images.id) COLLATE NATURAL_CI ASC"
|
||||
}
|
||||
|
||||
q.sortAndPagination = sortClause + getPagination(findFilter)
|
||||
|
||||
@@ -310,14 +310,17 @@ func (qb *movieQueryBuilder) getMovieSort(findFilter *models.FindFilterType) str
|
||||
direction = findFilter.GetDirection()
|
||||
}
|
||||
|
||||
sortQuery := ""
|
||||
switch sort {
|
||||
case "name": // #943 - override name sorting to use natural sort
|
||||
return " ORDER BY " + getColumn("movies", sort) + " COLLATE NATURAL_CS " + direction
|
||||
case "scenes_count": // generic getSort won't work for this
|
||||
return getCountSort(movieTable, moviesScenesTable, movieIDColumn, direction)
|
||||
sortQuery += getCountSort(movieTable, moviesScenesTable, movieIDColumn, direction)
|
||||
default:
|
||||
return getSort(sort, direction, "movies")
|
||||
sortQuery += getSort(sort, direction, "movies")
|
||||
}
|
||||
|
||||
// Whatever the sorting, always use name/id as a final sort
|
||||
sortQuery += ", COALESCE(movies.name, movies.id) COLLATE NATURAL_CI ASC"
|
||||
return sortQuery
|
||||
}
|
||||
|
||||
func (qb *movieQueryBuilder) queryMovie(ctx context.Context, query string, args []interface{}) (*models.Movie, error) {
|
||||
|
||||
@@ -893,20 +893,23 @@ func (qb *PerformerStore) getPerformerSort(findFilter *models.FindFilterType) st
|
||||
direction = findFilter.GetDirection()
|
||||
}
|
||||
|
||||
if sort == "tag_count" {
|
||||
return getCountSort(performerTable, performersTagsTable, performerIDColumn, direction)
|
||||
}
|
||||
if sort == "scenes_count" {
|
||||
return getCountSort(performerTable, performersScenesTable, performerIDColumn, direction)
|
||||
}
|
||||
if sort == "images_count" {
|
||||
return getCountSort(performerTable, performersImagesTable, performerIDColumn, direction)
|
||||
}
|
||||
if sort == "galleries_count" {
|
||||
return getCountSort(performerTable, performersGalleriesTable, performerIDColumn, direction)
|
||||
sortQuery := ""
|
||||
switch sort {
|
||||
case "tag_count":
|
||||
sortQuery += getCountSort(performerTable, performersTagsTable, performerIDColumn, direction)
|
||||
case "scenes_count":
|
||||
sortQuery += getCountSort(performerTable, performersScenesTable, performerIDColumn, direction)
|
||||
case "images_count":
|
||||
sortQuery += getCountSort(performerTable, performersImagesTable, performerIDColumn, direction)
|
||||
case "galleries_count":
|
||||
sortQuery += getCountSort(performerTable, performersGalleriesTable, performerIDColumn, direction)
|
||||
default:
|
||||
sortQuery += getSort(sort, direction, "performers")
|
||||
}
|
||||
|
||||
return getSort(sort, direction, "performers")
|
||||
// Whatever the sorting, always use name/id as a final sort
|
||||
sortQuery += ", COALESCE(performers.name, performers.id) COLLATE NATURAL_CI ASC"
|
||||
return sortQuery
|
||||
}
|
||||
|
||||
func (qb *PerformerStore) tagsRepository() *joinRepository {
|
||||
|
||||
@@ -1435,7 +1435,7 @@ func (qb *SceneStore) setSceneSort(query *queryBuilder, findFilter *models.FindF
|
||||
// special handling for path
|
||||
addFileTable()
|
||||
addFolderTable()
|
||||
query.sortAndPagination += fmt.Sprintf(" ORDER BY folders.path %s, files.basename %[1]s", direction)
|
||||
query.sortAndPagination += fmt.Sprintf(" ORDER BY COALESCE(folders.path, '') || COALESCE(files.basename, '') COLLATE NATURAL_CI %s", direction)
|
||||
case "perceptual_similarity":
|
||||
// special handling for phash
|
||||
addFileTable()
|
||||
@@ -1472,13 +1472,16 @@ func (qb *SceneStore) setSceneSort(query *queryBuilder, findFilter *models.FindF
|
||||
case "title":
|
||||
addFileTable()
|
||||
addFolderTable()
|
||||
query.sortAndPagination += " ORDER BY COALESCE(scenes.title, files.basename) COLLATE NATURAL_CS " + direction + ", folders.path " + direction
|
||||
query.sortAndPagination += " ORDER BY COALESCE(scenes.title, files.basename) COLLATE NATURAL_CI " + direction + ", folders.path COLLATE NATURAL_CI " + direction
|
||||
case "play_count":
|
||||
// handle here since getSort has special handling for _count suffix
|
||||
query.sortAndPagination += " ORDER BY scenes.play_count " + direction
|
||||
default:
|
||||
query.sortAndPagination += getSort(sort, direction, "scenes")
|
||||
}
|
||||
|
||||
// Whatever the sorting, always use title/id as a final sort
|
||||
query.sortAndPagination += ", COALESCE(scenes.title, scenes.id) COLLATE NATURAL_CI ASC"
|
||||
}
|
||||
|
||||
func (qb *SceneStore) getPlayCount(ctx context.Context, id int) (int, error) {
|
||||
|
||||
@@ -82,10 +82,10 @@ func getSort(sort string, direction string, tableName string) string {
|
||||
colName = sort
|
||||
}
|
||||
if strings.Compare(sort, "name") == 0 {
|
||||
return " ORDER BY " + colName + " COLLATE NOCASE " + direction
|
||||
return " ORDER BY " + colName + " COLLATE NATURAL_CI " + direction
|
||||
}
|
||||
if strings.Compare(sort, "title") == 0 {
|
||||
return " ORDER BY " + colName + " COLLATE NATURAL_CS " + direction
|
||||
return " ORDER BY " + colName + " COLLATE NATURAL_CI " + direction
|
||||
}
|
||||
|
||||
return " ORDER BY " + colName + " " + direction
|
||||
|
||||
@@ -414,16 +414,21 @@ func (qb *studioQueryBuilder) getStudioSort(findFilter *models.FindFilterType) s
|
||||
direction = findFilter.GetDirection()
|
||||
}
|
||||
|
||||
sortQuery := ""
|
||||
switch sort {
|
||||
case "scenes_count":
|
||||
return getCountSort(studioTable, sceneTable, studioIDColumn, direction)
|
||||
sortQuery += getCountSort(studioTable, sceneTable, studioIDColumn, direction)
|
||||
case "images_count":
|
||||
return getCountSort(studioTable, imageTable, studioIDColumn, direction)
|
||||
sortQuery += getCountSort(studioTable, imageTable, studioIDColumn, direction)
|
||||
case "galleries_count":
|
||||
return getCountSort(studioTable, galleryTable, studioIDColumn, direction)
|
||||
sortQuery += getCountSort(studioTable, galleryTable, studioIDColumn, direction)
|
||||
default:
|
||||
return getSort(sort, direction, "studios")
|
||||
sortQuery += getSort(sort, direction, "studios")
|
||||
}
|
||||
|
||||
// Whatever the sorting, always use name/id as a final sort
|
||||
sortQuery += ", COALESCE(studios.name, studios.id) COLLATE NATURAL_CI ASC"
|
||||
return sortQuery
|
||||
}
|
||||
|
||||
func (qb *studioQueryBuilder) queryStudio(ctx context.Context, query string, args []interface{}) (*models.Studio, error) {
|
||||
|
||||
@@ -609,22 +609,25 @@ func (qb *tagQueryBuilder) getTagSort(query *queryBuilder, findFilter *models.Fi
|
||||
direction = findFilter.GetDirection()
|
||||
}
|
||||
|
||||
if findFilter.Sort != nil {
|
||||
switch *findFilter.Sort {
|
||||
case "scenes_count":
|
||||
return getCountSort(tagTable, scenesTagsTable, tagIDColumn, direction)
|
||||
case "scene_markers_count":
|
||||
return fmt.Sprintf(" ORDER BY (SELECT COUNT(*) FROM scene_markers_tags WHERE tags.id = scene_markers_tags.tag_id)+(SELECT COUNT(*) FROM scene_markers WHERE tags.id = scene_markers.primary_tag_id) %s", getSortDirection(direction))
|
||||
case "images_count":
|
||||
return getCountSort(tagTable, imagesTagsTable, tagIDColumn, direction)
|
||||
case "galleries_count":
|
||||
return getCountSort(tagTable, galleriesTagsTable, tagIDColumn, direction)
|
||||
case "performers_count":
|
||||
return getCountSort(tagTable, performersTagsTable, tagIDColumn, direction)
|
||||
}
|
||||
sortQuery := ""
|
||||
switch sort {
|
||||
case "scenes_count":
|
||||
sortQuery += getCountSort(tagTable, scenesTagsTable, tagIDColumn, direction)
|
||||
case "scene_markers_count":
|
||||
sortQuery += fmt.Sprintf(" ORDER BY (SELECT COUNT(*) FROM scene_markers_tags WHERE tags.id = scene_markers_tags.tag_id)+(SELECT COUNT(*) FROM scene_markers WHERE tags.id = scene_markers.primary_tag_id) %s", getSortDirection(direction))
|
||||
case "images_count":
|
||||
sortQuery += getCountSort(tagTable, imagesTagsTable, tagIDColumn, direction)
|
||||
case "galleries_count":
|
||||
sortQuery += getCountSort(tagTable, galleriesTagsTable, tagIDColumn, direction)
|
||||
case "performers_count":
|
||||
sortQuery += getCountSort(tagTable, performersTagsTable, tagIDColumn, direction)
|
||||
default:
|
||||
sortQuery += getSort(sort, direction, "tags")
|
||||
}
|
||||
|
||||
return getSort(sort, direction, "tags")
|
||||
// Whatever the sorting, always use name/id as a final sort
|
||||
sortQuery += ", COALESCE(tags.name, tags.id) COLLATE NATURAL_CI ASC"
|
||||
return sortQuery
|
||||
}
|
||||
|
||||
func (qb *tagQueryBuilder) queryTag(ctx context.Context, query string, args []interface{}) (*models.Tag, error) {
|
||||
|
||||
Reference in New Issue
Block a user