Add ability to only filter in the search endpoint
This commit is contained in:
parent
cddf450353
commit
d411245096
|
@ -6,7 +6,7 @@ import { isNumberArray, isStringArray, isNSFWQueryValid } from '../../helpers/cu
|
||||||
import { isBooleanValid, isDateValid, toArray } from '../../helpers/custom-validators/misc'
|
import { isBooleanValid, isDateValid, toArray } from '../../helpers/custom-validators/misc'
|
||||||
|
|
||||||
const searchValidator = [
|
const searchValidator = [
|
||||||
query('search').not().isEmpty().withMessage('Should have a valid search'),
|
query('search').optional().not().isEmpty().withMessage('Should have a valid search'),
|
||||||
|
|
||||||
query('startDate').optional().custom(isDateValid).withMessage('Should have a valid start date'),
|
query('startDate').optional().custom(isDateValid).withMessage('Should have a valid start date'),
|
||||||
query('endDate').optional().custom(isDateValid).withMessage('Should have a valid end date'),
|
query('endDate').optional().custom(isDateValid).withMessage('Should have a valid end date'),
|
||||||
|
|
|
@ -93,7 +93,6 @@ import { VideoShareModel } from './video-share'
|
||||||
import { VideoTagModel } from './video-tag'
|
import { VideoTagModel } from './video-tag'
|
||||||
import { ScheduleVideoUpdateModel } from './schedule-video-update'
|
import { ScheduleVideoUpdateModel } from './schedule-video-update'
|
||||||
import { VideoCaptionModel } from './video-caption'
|
import { VideoCaptionModel } from './video-caption'
|
||||||
import { VideosSearchQuery } from '../../../shared/models/search'
|
|
||||||
|
|
||||||
// FIXME: Define indexes here because there is an issue with TS and Sequelize.literal when called directly in the annotation
|
// FIXME: Define indexes here because there is an issue with TS and Sequelize.literal when called directly in the annotation
|
||||||
const indexes: Sequelize.DefineIndexesOptions[] = [
|
const indexes: Sequelize.DefineIndexesOptions[] = [
|
||||||
|
@ -848,7 +847,7 @@ export class VideoModel extends Model<VideoModel> {
|
||||||
}
|
}
|
||||||
|
|
||||||
static async searchAndPopulateAccountAndServer (options: {
|
static async searchAndPopulateAccountAndServer (options: {
|
||||||
search: string
|
search?: string
|
||||||
start?: number
|
start?: number
|
||||||
count?: number
|
count?: number
|
||||||
sort?: string
|
sort?: string
|
||||||
|
@ -883,11 +882,41 @@ export class VideoModel extends Model<VideoModel> {
|
||||||
whereAnd.push({ duration: durationRange })
|
whereAnd.push({ duration: durationRange })
|
||||||
}
|
}
|
||||||
|
|
||||||
whereAnd.push(createSearchTrigramQuery('VideoModel.name', options.search))
|
const attributesInclude = []
|
||||||
|
if (options.search) {
|
||||||
|
whereAnd.push(
|
||||||
|
{
|
||||||
|
[ Sequelize.Op.or ]: [
|
||||||
|
createSearchTrigramQuery('VideoModel.name', options.search),
|
||||||
|
|
||||||
|
{
|
||||||
|
id: {
|
||||||
|
[ Sequelize.Op.in ]: Sequelize.literal(
|
||||||
|
'(' +
|
||||||
|
'SELECT "video"."id" FROM "video" LEFT JOIN "videoTag" ON "videoTag"."videoId" = "video"."id" ' +
|
||||||
|
'INNER JOIN "tag" ON "tag"."id" = "videoTag"."tagId" ' +
|
||||||
|
'WHERE "tag"."name" = ' + VideoModel.sequelize.escape(options.search) +
|
||||||
|
')'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
attributesInclude.push(createSimilarityAttribute('VideoModel.name', options.search))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cannot search on similarity if we don't have a search
|
||||||
|
if (!options.search) {
|
||||||
|
attributesInclude.push(
|
||||||
|
Sequelize.literal('0 as similarity')
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
const query: IFindOptions<VideoModel> = {
|
const query: IFindOptions<VideoModel> = {
|
||||||
attributes: {
|
attributes: {
|
||||||
include: [ createSimilarityAttribute('VideoModel.name', options.search) ]
|
include: attributesInclude
|
||||||
},
|
},
|
||||||
offset: options.start,
|
offset: options.start,
|
||||||
limit: options.count,
|
limit: options.count,
|
||||||
|
|
|
@ -103,6 +103,15 @@ describe('Test a videos search', function () {
|
||||||
await uploadVideo(server.url, server.accessToken, immutableAssign(attributes1, { tags: [ 'cccc', 'dddd' ] }))
|
await uploadVideo(server.url, server.accessToken, immutableAssign(attributes1, { tags: [ 'cccc', 'dddd' ] }))
|
||||||
await uploadVideo(server.url, server.accessToken, immutableAssign(attributes1, { tags: [ 'eeee', 'ffff' ] }))
|
await uploadVideo(server.url, server.accessToken, immutableAssign(attributes1, { tags: [ 'eeee', 'ffff' ] }))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const attributes1 = {
|
||||||
|
name: 'aaaa 2',
|
||||||
|
category: 1
|
||||||
|
}
|
||||||
|
await uploadVideo(server.url, server.accessToken, attributes1)
|
||||||
|
await uploadVideo(server.url, server.accessToken, immutableAssign(attributes1, { category: 2 }))
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Should make a simple search and not have results', async function () {
|
it('Should make a simple search and not have results', async function () {
|
||||||
|
@ -125,6 +134,52 @@ describe('Test a videos search', function () {
|
||||||
expect(videos[1].name).to.equal('3333 4444 5555')
|
expect(videos[1].name).to.equal('3333 4444 5555')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('Should make a search on tags too, and have results', async function () {
|
||||||
|
const query = {
|
||||||
|
search: 'aaaa',
|
||||||
|
categoryOneOf: [ 1 ]
|
||||||
|
}
|
||||||
|
const res = await advancedVideosSearch(server.url, query)
|
||||||
|
|
||||||
|
expect(res.body.total).to.equal(2)
|
||||||
|
|
||||||
|
const videos = res.body.data
|
||||||
|
expect(videos).to.have.lengthOf(2)
|
||||||
|
|
||||||
|
// bestmatch
|
||||||
|
expect(videos[0].name).to.equal('aaaa 2')
|
||||||
|
expect(videos[1].name).to.equal('9999')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Should filter on tags without a search', async function () {
|
||||||
|
const query = {
|
||||||
|
tagsAllOf: [ 'bbbb' ]
|
||||||
|
}
|
||||||
|
const res = await advancedVideosSearch(server.url, query)
|
||||||
|
|
||||||
|
expect(res.body.total).to.equal(2)
|
||||||
|
|
||||||
|
const videos = res.body.data
|
||||||
|
expect(videos).to.have.lengthOf(2)
|
||||||
|
|
||||||
|
expect(videos[0].name).to.equal('9999')
|
||||||
|
expect(videos[1].name).to.equal('9999')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Should filter on category without a search', async function () {
|
||||||
|
const query = {
|
||||||
|
categoryOneOf: [ 3 ]
|
||||||
|
}
|
||||||
|
const res = await advancedVideosSearch(server.url, query)
|
||||||
|
|
||||||
|
expect(res.body.total).to.equal(1)
|
||||||
|
|
||||||
|
const videos = res.body.data
|
||||||
|
expect(videos).to.have.lengthOf(1)
|
||||||
|
|
||||||
|
expect(videos[0].name).to.equal('6666 7777 8888')
|
||||||
|
})
|
||||||
|
|
||||||
it('Should search by tags (one of)', async function () {
|
it('Should search by tags (one of)', async function () {
|
||||||
const query = {
|
const query = {
|
||||||
search: '9999',
|
search: '9999',
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { NSFWQuery } from './nsfw-query.model'
|
import { NSFWQuery } from './nsfw-query.model'
|
||||||
|
|
||||||
export interface VideosSearchQuery {
|
export interface VideosSearchQuery {
|
||||||
search: string
|
search?: string
|
||||||
|
|
||||||
start?: number
|
start?: number
|
||||||
count?: number
|
count?: number
|
||||||
|
|
Loading…
Reference in New Issue