import { isBooleanValid, isDateValid, toArray } from '../../helpers/custom-validators/misc'
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('endDate').optional().custom(isDateValid).withMessage('Should have a valid end date'),
import { VideoTagModel } from './video-tag'
import { ScheduleVideoUpdateModel } from './schedule-video-update'
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
const indexes: Sequelize.DefineIndexesOptions[] = [
}
static async searchAndPopulateAccountAndServer (options: {
- search: string
+ search?: string
start?: number
count?: number
sort?: string
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> = {
attributes: {
- include: [ createSimilarityAttribute('VideoModel.name', options.search) ]
+ include: attributesInclude
},
offset: options.start,
limit: options.count,
await uploadVideo(server.url, server.accessToken, immutableAssign(attributes1, { tags: [ 'cccc', 'dddd' ] }))
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 () {
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 () {
const query = {
search: '9999',