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:
Flashy78
2023-04-16 22:21:13 -07:00
committed by GitHub
parent e685f80e3d
commit 75f22042b7
19 changed files with 311 additions and 165 deletions

View File

@@ -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

View File

@@ -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 {

View File

@@ -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)

View File

@@ -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) {

View File

@@ -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 {

View File

@@ -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) {

View File

@@ -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

View File

@@ -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) {

View File

@@ -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) {