import { createSafeIn } from '@server/models/utils' ; import { MUserAccountId } from '@server/types/models' ; import validator from 'validator' ; import { AbstractRunQuery } from './abstract-run-query' ; import { VideoTableAttributes } from './video-table-attributes' ; /**
 *
 * Abstract builder to create SQL query and fetch video models
 *
 */ export class AbstractVideoQueryBuilder extends AbstractRunQuery { protected attributes : { [ key ] : string ; } = { } ; protected joins = '' ; protected where : string ; protected tables : VideoTableAttributes ; constructor ( protected readonly mode ) { super ( ) ; this . tables = new VideoTableAttributes ( this . mode ) ; } protected buildSelect ( ) { return 'SELECT ' + Object . keys ( this . attributes ) . map ( key => { const value = this . attributes [ key ] ; if ( value ) return `${ key } AS ${ value }` ; return key ; } ) . join ( ', ' ) ; } protected includeChannels ( ) { this . addJoin ( 'INNER JOIN "videoChannel" AS "VideoChannel" ON "video"."channelId" = "VideoChannel"."id"' ) ; this . addJoin ( 'INNER JOIN "actor" AS "VideoChannel->Actor" ON "VideoChannel"."actorId" = "VideoChannel->Actor"."id"' ) ; this . addJoin ( 'LEFT OUTER JOIN "server" AS "VideoChannel->Actor->Server" ON "VideoChannel->Actor"."serverId" = "VideoChannel->Actor->Server"."id"' ) ; this . addJoin ( 'LEFT OUTER JOIN "actorImage" AS "VideoChannel->Actor->Avatar" ' + 'ON "VideoChannel->Actor"."avatarId" = "VideoChannel->Actor->Avatar"."id"' ) ; this . attributes = { ... this . attributes , ... this . buildAttributesObject ( 'VideoChannel' , this . tables . getChannelAttributes ( ) ) , ... this . buildActorInclude ( 'VideoChannel->Actor' ) , ... this . buildAvatarInclude ( 'VideoChannel->Actor->Avatar' ) , ... this . buildServerInclude ( 'VideoChannel->Actor->Server' ) } ; } protected includeAccounts ( ) { this . addJoin ( 'INNER JOIN "account" AS "VideoChannel->Account" ON "VideoChannel"."accountId" = "VideoChannel->Account"."id"' ) ; this . addJoin ( 'INNER JOIN "actor" AS "VideoChannel->Account->Actor" ON "VideoChannel->Account"."actorId" = "VideoChannel->Account->Actor"."id"' ) ; this . addJoin ( 'LEFT OUTER JOIN "server" AS "VideoChannel->Account->Actor->Server" ' + 'ON "VideoChannel->Account->Actor"."serverId" = "VideoChannel->Account->Actor->Server"."id"' ) ; this . addJoin ( 'LEFT OUTER JOIN "actorImage" AS "VideoChannel->Account->Actor->Avatar" ' + 'ON "VideoChannel->Account->Actor"."avatarId" = "VideoChannel->Account->Actor->Avatar"."id"' ) ; this . attributes = { ... this . attributes , ... this . buildAttributesObject ( 'VideoChannel->Account' , this . tables . getAccountAttributes ( ) ) , ... this . buildActorInclude ( 'VideoChannel->Account->Actor' ) , ... this . buildAvatarInclude ( 'VideoChannel->Account->Actor->Avatar' ) , ... this . buildServerInclude ( 'VideoChannel->Account->Actor->Server' ) } ; } protected includeOwnerUser ( ) { this . addJoin ( 'INNER JOIN "videoChannel" AS "VideoChannel" ON "video"."channelId" = "VideoChannel"."id"' ) ; this . addJoin ( 'INNER JOIN "account" AS "VideoChannel->Account" ON "VideoChannel"."accountId" = "VideoChannel->Account"."id"' ) ; this . attributes = { ... this . attributes , ... this . buildAttributesObject ( 'VideoChannel' , this . tables . getChannelAttributes ( ) ) , ... this . buildAttributesObject ( 'VideoChannel->Account' , this . tables . getUserAccountAttributes ( ) ) } ; } protected includeThumbnails ( ) { this . addJoin ( 'LEFT OUTER JOIN "thumbnail" AS "Thumbnails" ON "video"."id" = "Thumbnails"."videoId"' ) ; this . attributes = { ... this . attributes , ... this . buildAttributesObject ( 'Thumbnails' , this . tables . getThumbnailAttributes ( ) ) } ; } protected includeWebtorrentFiles ( ) { this . addJoin ( 'LEFT JOIN "videoFile" AS "VideoFiles" ON "VideoFiles"."videoId" = "video"."id"' ) ; this . attributes = { ... this . attributes , ... this . buildAttributesObject ( 'VideoFiles' , this . tables . getFileAttributes ( ) ) } ; } protected includeStreamingPlaylistFiles ( ) { this . addJoin ( 'LEFT JOIN "videoStreamingPlaylist" AS "VideoStreamingPlaylists" ON "VideoStreamingPlaylists"."videoId" = "video"."id"' ) ; this . addJoin ( 'LEFT JOIN "videoFile" AS "VideoStreamingPlaylists->VideoFiles" ' + 'ON "VideoStreamingPlaylists->VideoFiles"."videoStreamingPlaylistId" = "VideoStreamingPlaylists"."id"' ) ; this . attributes = { ... this . attributes , ... this . buildAttributesObject ( 'VideoStreamingPlaylists' , this . tables . getStreamingPlaylistAttributes ( ) ) , ... this . buildAttributesObject ( 'VideoStreamingPlaylists->VideoFiles' , this . tables . getFileAttributes ( ) ) } ; } protected includeUserHistory ( userId ) { this . addJoin ( 'LEFT OUTER JOIN "userVideoHistory" ' + 'ON "video"."id" = "userVideoHistory"."videoId" AND "userVideoHistory"."userId" = :userVideoHistoryId' ) ; this . replacements . userVideoHistoryId = userId ; this . attributes = { ... this . attributes , ... this . buildAttributesObject ( 'userVideoHistory' , this . tables . getUserHistoryAttributes ( ) ) } ; } protected includePlaylist ( playlistId ) { this . addJoin ( 'INNER JOIN "videoPlaylistElement" as "VideoPlaylistElement" ON "videoPlaylistElement"."videoId" = "video"."id" ' + 'AND "VideoPlaylistElement"."videoPlaylistId" = :videoPlaylistId' ) ; this . replacements . videoPlaylistId = playlistId ; this . attributes = { ... this . attributes , ... this . buildAttributesObject ( 'VideoPlaylistElement' , this . tables . getPlaylistAttributes ( ) ) } ; } protected includeTags ( ) { this . addJoin ( 'LEFT OUTER JOIN (' + '"videoTag" AS "Tags->VideoTagModel" INNER JOIN "tag" AS "Tags" ON "Tags"."id" = "Tags->VideoTagModel"."tagId"' + ') ' + 'ON "video"."id" = "Tags->VideoTagModel"."videoId"' ) ; this . attributes = { ... this . attributes , ... this . buildAttributesObject ( 'Tags' , this . tables . getTagAttributes ( ) ) , ... this . buildAttributesObject ( 'Tags->VideoTagModel' , this . tables . getVideoTagAttributes ( ) ) } ; } protected includeBlacklisted ( ) { this . addJoin ( 'LEFT OUTER JOIN "videoBlacklist" AS "VideoBlacklist" ON "video"."id" = "VideoBlacklist"."videoId"' ) ; this . attributes = { ... this . attributes , ... this . buildAttributesObject ( 'VideoBlacklist' , this . tables . getBlacklistedAttributes ( ) ) } ; } protected includeBlockedOwnerAndServer ( serverAccountId , user ? ) { const blockerIds = [ serverAccountId ] ; if ( user ) blockerIds . push ( user . Account . id ) ; const inClause = createSafeIn ( this . sequelize , blockerIds ) ; this . addJoin ( 'LEFT JOIN "accountBlocklist" AS "VideoChannel->Account->AccountBlocklist" ' + 'ON "VideoChannel->Account"."id" = "VideoChannel->Account->AccountBlocklist"."targetAccountId" ' + 'AND "VideoChannel->Account->AccountBlocklist"."accountId" IN (' + inClause + ')' ) ; this . addJoin ( 'LEFT JOIN "serverBlocklist" AS "VideoChannel->Account->Actor->Server->ServerBlocklist" ' + 'ON "VideoChannel->Account->Actor->Server->ServerBlocklist"."targetServerId" = "VideoChannel->Account->Actor"."serverId" ' + 'AND "VideoChannel->Account->Actor->Server->ServerBlocklist"."accountId" IN (' + inClause + ') ' ) ; this . attributes = { ... this . attributes , ... this . buildAttributesObject ( 'VideoChannel->Account->AccountBlocklist' , this . tables . getBlocklistAttributes ( ) ) , ... this . buildAttributesObject ( 'VideoChannel->Account->Actor->Server->ServerBlocklist' , this . tables . getBlocklistAttributes ( ) ) } ; } protected includeScheduleUpdate ( ) { this . addJoin ( 'LEFT OUTER JOIN "scheduleVideoUpdate" AS "ScheduleVideoUpdate" ON "video"."id" = "ScheduleVideoUpdate"."videoId"' ) ; this . attributes = { ... this . attributes , ... this . buildAttributesObject ( 'ScheduleVideoUpdate' , this . tables . getScheduleUpdateAttributes ( ) ) } ; } protected includeLive ( ) { this . addJoin ( 'LEFT OUTER JOIN "videoLive" AS "VideoLive" ON "video"."id" = "VideoLive"."videoId"' ) ; this . attributes = { ... this . attributes , ... this . buildAttributesObject ( 'VideoLive' , this . tables . getLiveAttributes ( ) ) } ; } protected includeTrackers ( ) { this . addJoin ( 'LEFT OUTER JOIN (' + '"videoTracker" AS "Trackers->VideoTrackerModel" ' + 'INNER JOIN "tracker" AS "Trackers" ON "Trackers"."id" = "Trackers->VideoTrackerModel"."trackerId"' + ') ON "video"."id" = "Trackers->VideoTrackerModel"."videoId"' ) ; this . attributes = { ... this . attributes , ... this . buildAttributesObject ( 'Trackers' , this . tables . getTrackerAttributes ( ) ) , ... this . buildAttributesObject ( 'Trackers->VideoTrackerModel' , this . tables . getVideoTrackerAttributes ( ) ) } ; } protected includeWebTorrentRedundancies ( ) { this . addJoin ( 'LEFT OUTER JOIN "videoRedundancy" AS "VideoFiles->RedundancyVideos" ON ' + '"VideoFiles"."id" = "VideoFiles->RedundancyVideos"."videoFileId"' ) ; this . attributes = { ... this . attributes , ... this . buildAttributesObject ( 'VideoFiles->RedundancyVideos' , this . tables . getRedundancyAttributes ( ) ) } ; } protected includeStreamingPlaylistRedundancies ( ) { this . addJoin ( 'LEFT OUTER JOIN "videoRedundancy" AS "VideoStreamingPlaylists->RedundancyVideos" ' + 'ON "VideoStreamingPlaylists"."id" = "VideoStreamingPlaylists->RedundancyVideos"."videoStreamingPlaylistId"' ) ; this . attributes = { ... this . attributes , ... this . buildAttributesObject ( 'VideoStreamingPlaylists->RedundancyVideos' , this . tables . getRedundancyAttributes ( ) ) } ; } protected buildActorInclude ( prefixKey ) { return this . buildAttributesObject ( prefixKey , this . tables . getActorAttributes ( ) ) ; } protected buildAvatarInclude ( prefixKey ) { return this . buildAttributesObject ( prefixKey , this . tables . getAvatarAttributes ( ) ) ; } protected buildServerInclude ( prefixKey ) { return this . buildAttributesObject ( prefixKey , this . tables . getServerAttributes ( ) ) ; } protected buildAttributesObject ( prefixKey , attributeKeys ) { const result = { } ; const prefixValue = prefixKey . replace ( /->/g , '.' ) ; for ( const attribute of attributeKeys ) { result [ `"${ prefixKey }"."${ attribute }"` ] = `"${ prefixValue }.${ attribute }"` ; } return result ; } protected whereId ( options ) { if ( options . url ) { this . where = 'WHERE "video"."url" = :videoUrl' ; this . replacements . videoUrl = options . url ; return ; } if ( validator . isInt ( '' + options . id ) ) { this . where = 'WHERE "video".id = :videoId' ; } else { this . where = 'WHERE uuid = :videoId' ; } this . replacements . videoId = options . id ; } protected addJoin ( join ) { this . joins += join + ' ' ; } }