Add findFiles and findFile graphql queries (#5941)

* Add findFile and findFiles
* Add parent folder and zip file fields to file graphql types
* Add parent_folder, zip_file fields to Folder graphql type
* Add format to ImageFile type
* Add format filter fields to image/video file filters
This commit is contained in:
WithoutPants
2025-06-24 13:05:17 +10:00
committed by GitHub
parent 8d78fd682d
commit 704041d5e0
26 changed files with 1293 additions and 45 deletions

View File

@@ -275,6 +275,43 @@ func (r fileQueryRows) resolve() []models.File {
return ret
}
type fileRepositoryType struct {
repository
scenes joinRepository
images joinRepository
galleries joinRepository
}
var (
fileRepository = fileRepositoryType{
repository: repository{
tableName: sceneTable,
idColumn: idColumn,
},
scenes: joinRepository{
repository: repository{
tableName: scenesFilesTable,
idColumn: fileIDColumn,
},
fkColumn: sceneIDColumn,
},
images: joinRepository{
repository: repository{
tableName: imagesFilesTable,
idColumn: fileIDColumn,
},
fkColumn: imageIDColumn,
},
galleries: joinRepository{
repository: repository{
tableName: galleriesFilesTable,
idColumn: fileIDColumn,
},
fkColumn: galleryIDColumn,
},
}
)
type FileStore struct {
repository
@@ -830,9 +867,11 @@ func (qb *FileStore) makeFilter(ctx context.Context, fileFilter *models.FileFilt
query.not(qb.makeFilter(ctx, fileFilter.Not))
}
query.handleCriterion(ctx, pathCriterionHandler(fileFilter.Path, "folders.path", "files.basename", nil))
filter := filterBuilderFromHandler(ctx, &fileFilterHandler{
fileFilter: fileFilter,
})
return query
return filter
}
func (qb *FileStore) Query(ctx context.Context, options models.FileQueryOptions) (*models.FileQueryResult, error) {
@@ -890,7 +929,7 @@ func (qb *FileStore) Query(ctx context.Context, options models.FileQueryOptions)
}
func (qb *FileStore) queryGroupedFields(ctx context.Context, options models.FileQueryOptions, query queryBuilder) (*models.FileQueryResult, error) {
if !options.Count {
if !options.Count && !options.TotalDuration && !options.Megapixels && !options.TotalSize {
// nothing to do - return empty result
return models.NewFileQueryResult(qb), nil
}
@@ -898,14 +937,43 @@ func (qb *FileStore) queryGroupedFields(ctx context.Context, options models.File
aggregateQuery := qb.newQuery()
if options.Count {
aggregateQuery.addColumn("COUNT(temp.id) as total")
aggregateQuery.addColumn("COUNT(DISTINCT temp.id) as total")
}
if options.TotalDuration {
query.addJoins(
join{
table: videoFileTable,
onClause: "files.id = video_files.file_id",
},
)
query.addColumn("COALESCE(video_files.duration, 0) as duration")
aggregateQuery.addColumn("COALESCE(SUM(temp.duration), 0) as duration")
}
if options.Megapixels {
query.addJoins(
join{
table: imageFileTable,
onClause: "files.id = image_files.file_id",
},
)
query.addColumn("COALESCE(image_files.width, 0) * COALESCE(image_files.height, 0) as megapixels")
aggregateQuery.addColumn("COALESCE(SUM(temp.megapixels), 0) / 1000000 as megapixels")
}
if options.TotalSize {
query.addColumn("COALESCE(files.size, 0) as size")
aggregateQuery.addColumn("COALESCE(SUM(temp.size), 0) as size")
}
const includeSortPagination = false
aggregateQuery.from = fmt.Sprintf("(%s) as temp", query.toSQL(includeSortPagination))
out := struct {
Total int
Total int
Duration float64
Megapixels float64
Size int64
}{}
if err := qb.repository.queryStruct(ctx, aggregateQuery.toSQL(includeSortPagination), query.args, &out); err != nil {
return nil, err
@@ -913,6 +981,9 @@ func (qb *FileStore) queryGroupedFields(ctx context.Context, options models.File
ret := models.NewFileQueryResult(qb)
ret.Count = out.Total
ret.Megapixels = out.Megapixels
ret.TotalDuration = out.Duration
ret.TotalSize = out.Size
return ret, nil
}