Optimize SQL requests of watch page API endpoints
This commit is contained in:
parent
e972e046db
commit
627621c1e8
|
@ -25,7 +25,7 @@ run()
|
|||
async function run () {
|
||||
await initDatabaseModels(true)
|
||||
|
||||
const video = await VideoModel.loadByUUID(program['video'])
|
||||
const video = await VideoModel.loadByUUIDWithFile(program['video'])
|
||||
if (!video) throw new Error('Video not found.')
|
||||
if (video.isOwned() === false) throw new Error('Cannot import files of a non owned video.')
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ run()
|
|||
async function run () {
|
||||
await initDatabaseModels(true)
|
||||
|
||||
const video = await VideoModel.loadByUUID(program['video'])
|
||||
const video = await VideoModel.loadByUUIDWithFile(program['video'])
|
||||
if (!video) throw new Error('Video not found.')
|
||||
|
||||
const dataInput = {
|
||||
|
|
|
@ -56,7 +56,7 @@ async function pruneDirectory (directory: string) {
|
|||
const uuid = getUUIDFromFilename(file)
|
||||
let video: VideoModel
|
||||
|
||||
if (uuid) video = await VideoModel.loadByUUID(uuid)
|
||||
if (uuid) video = await VideoModel.loadByUUIDWithFile(uuid)
|
||||
|
||||
if (!uuid || !video) toDelete.push(join(directory, file))
|
||||
}
|
||||
|
|
|
@ -293,7 +293,7 @@ async function getUserVideoQuotaUsed (req: express.Request, res: express.Respons
|
|||
}
|
||||
|
||||
async function getUserVideoRating (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
const videoId = +req.params.videoId
|
||||
const videoId = res.locals.video.id
|
||||
const accountId = +res.locals.oauth.token.User.Account.id
|
||||
|
||||
const ratingObj = await AccountVideoRateModel.load(accountId, videoId, null)
|
||||
|
|
|
@ -86,7 +86,7 @@ async function listVideoThreadComments (req: express.Request, res: express.Respo
|
|||
let resultList: ResultList<VideoCommentModel>
|
||||
|
||||
if (video.commentsEnabled === true) {
|
||||
resultList = await VideoCommentModel.listThreadCommentsForApi(res.locals.video.id, res.locals.videoCommentThread.id)
|
||||
resultList = await VideoCommentModel.listThreadCommentsForApi(video.id, res.locals.videoCommentThread.id)
|
||||
} else {
|
||||
resultList = {
|
||||
total: 0,
|
||||
|
|
|
@ -152,13 +152,15 @@ function checkUserCanManageVideo (user: UserModel, video: VideoModel, right: Use
|
|||
return true
|
||||
}
|
||||
|
||||
async function isVideoExist (id: string, res: Response) {
|
||||
async function isVideoExist (id: string, res: Response, fetchType: 'all' | 'only-video' | 'id' | 'none' = 'all') {
|
||||
let video: VideoModel | null
|
||||
|
||||
if (validator.isInt(id)) {
|
||||
video = await VideoModel.loadAndPopulateAccountAndServerAndTags(+id)
|
||||
} else { // UUID
|
||||
video = await VideoModel.loadByUUIDAndPopulateAccountAndServerAndTags(id)
|
||||
if (fetchType === 'all') {
|
||||
video = await VideoModel.loadAndPopulateAccountAndServerAndTags(id)
|
||||
} else if (fetchType === 'only-video') {
|
||||
video = await VideoModel.load(id)
|
||||
} else if (fetchType === 'id' || fetchType === 'none') {
|
||||
video = await VideoModel.loadOnlyId(id)
|
||||
}
|
||||
|
||||
if (video === null) {
|
||||
|
@ -169,7 +171,7 @@ async function isVideoExist (id: string, res: Response) {
|
|||
return false
|
||||
}
|
||||
|
||||
res.locals.video = video
|
||||
if (fetchType !== 'none') res.locals.video = video
|
||||
return true
|
||||
}
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ class VideosCaptionCache extends AbstractVideoStaticFileCache <GetPathParam> {
|
|||
if (videoCaption.isOwned()) throw new Error('Cannot load remote caption of owned video.')
|
||||
|
||||
// Used to fetch the path
|
||||
const video = await VideoModel.loadByUUIDAndPopulateAccountAndServerAndTags(videoId)
|
||||
const video = await VideoModel.loadAndPopulateAccountAndServerAndTags(videoId)
|
||||
if (!video) return undefined
|
||||
|
||||
const remoteStaticPath = videoCaption.getCaptionStaticPath()
|
||||
|
|
|
@ -16,7 +16,7 @@ class VideosPreviewCache extends AbstractVideoStaticFileCache <string> {
|
|||
}
|
||||
|
||||
async getFilePath (videoUUID: string) {
|
||||
const video = await VideoModel.loadByUUID(videoUUID)
|
||||
const video = await VideoModel.loadByUUIDWithFile(videoUUID)
|
||||
if (!video) return undefined
|
||||
|
||||
if (video.isOwned()) return join(CONFIG.STORAGE.PREVIEWS_DIR, video.getPreviewName())
|
||||
|
@ -25,7 +25,7 @@ class VideosPreviewCache extends AbstractVideoStaticFileCache <string> {
|
|||
}
|
||||
|
||||
protected async loadRemoteFile (key: string) {
|
||||
const video = await VideoModel.loadByUUIDAndPopulateAccountAndServerAndTags(key)
|
||||
const video = await VideoModel.loadAndPopulateAccountAndServerAndTags(key)
|
||||
if (!video) return undefined
|
||||
|
||||
if (video.isOwned()) throw new Error('Cannot load remote preview of owned video.')
|
||||
|
|
|
@ -39,10 +39,8 @@ export class ClientHtml {
|
|||
let videoPromise: Bluebird<VideoModel>
|
||||
|
||||
// Let Angular application handle errors
|
||||
if (validator.isUUID(videoId, 4)) {
|
||||
videoPromise = VideoModel.loadByUUIDAndPopulateAccountAndServerAndTags(videoId)
|
||||
} else if (validator.isInt(videoId)) {
|
||||
videoPromise = VideoModel.loadAndPopulateAccountAndServerAndTags(+videoId)
|
||||
if (validator.isInt(videoId) || validator.isUUID(videoId, 4)) {
|
||||
videoPromise = VideoModel.loadAndPopulateAccountAndServerAndTags(videoId)
|
||||
} else {
|
||||
return ClientHtml.getIndexHTML(req, res)
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ async function processVideoFileImport (job: Bull.Job) {
|
|||
const payload = job.data as VideoFileImportPayload
|
||||
logger.info('Processing video file import in job %d.', job.id)
|
||||
|
||||
const video = await VideoModel.loadByUUIDAndPopulateAccountAndServerAndTags(payload.videoUUID)
|
||||
const video = await VideoModel.loadAndPopulateAccountAndServerAndTags(payload.videoUUID)
|
||||
// No video, maybe deleted?
|
||||
if (!video) {
|
||||
logger.info('Do not process job %d, video does not exist.', job.id)
|
||||
|
@ -43,7 +43,7 @@ async function processVideoFile (job: Bull.Job) {
|
|||
const payload = job.data as VideoFilePayload
|
||||
logger.info('Processing video file in job %d.', job.id)
|
||||
|
||||
const video = await VideoModel.loadByUUIDAndPopulateAccountAndServerAndTags(payload.videoUUID)
|
||||
const video = await VideoModel.loadAndPopulateAccountAndServerAndTags(payload.videoUUID)
|
||||
// No video, maybe deleted?
|
||||
if (!video) {
|
||||
logger.info('Do not process job %d, video does not exist.', job.id)
|
||||
|
@ -69,7 +69,7 @@ async function onVideoFileTranscoderOrImportSuccess (video: VideoModel) {
|
|||
|
||||
return sequelizeTypescript.transaction(async t => {
|
||||
// Maybe the video changed in database, refresh it
|
||||
let videoDatabase = await VideoModel.loadByUUIDAndPopulateAccountAndServerAndTags(video.uuid, t)
|
||||
let videoDatabase = await VideoModel.loadAndPopulateAccountAndServerAndTags(video.uuid, t)
|
||||
// Video does not exist anymore
|
||||
if (!videoDatabase) return undefined
|
||||
|
||||
|
@ -99,7 +99,7 @@ async function onVideoFileOptimizerSuccess (video: VideoModel, isNewVideo: boole
|
|||
|
||||
return sequelizeTypescript.transaction(async t => {
|
||||
// Maybe the video changed in database, refresh it
|
||||
const videoDatabase = await VideoModel.loadByUUIDAndPopulateAccountAndServerAndTags(video.uuid, t)
|
||||
const videoDatabase = await VideoModel.loadAndPopulateAccountAndServerAndTags(video.uuid, t)
|
||||
// Video does not exist anymore
|
||||
if (!videoDatabase) return undefined
|
||||
|
||||
|
|
|
@ -183,7 +183,7 @@ async function processFile (downloader: () => Promise<string>, videoImport: Vide
|
|||
const videoUpdated = await video.save({ transaction: t })
|
||||
|
||||
// Now we can federate the video (reload from database, we need more attributes)
|
||||
const videoForFederation = await VideoModel.loadByUUIDAndPopulateAccountAndServerAndTags(video.uuid, t)
|
||||
const videoForFederation = await VideoModel.loadAndPopulateAccountAndServerAndTags(video.uuid, t)
|
||||
await federateVideoIfNeeded(videoForFederation, true, t)
|
||||
|
||||
// Update video import object
|
||||
|
|
|
@ -172,7 +172,7 @@ const usersVideoRatingValidator = [
|
|||
logger.debug('Checking usersVideoRating parameters', { parameters: req.params })
|
||||
|
||||
if (areValidationErrors(req, res)) return
|
||||
if (!await isVideoExist(req.params.videoId, res)) return
|
||||
if (!await isVideoExist(req.params.videoId, res, 'id')) return
|
||||
|
||||
return next()
|
||||
}
|
||||
|
|
|
@ -58,7 +58,7 @@ const listVideoCaptionsValidator = [
|
|||
logger.debug('Checking listVideoCaptions parameters', { parameters: req.params })
|
||||
|
||||
if (areValidationErrors(req, res)) return
|
||||
if (!await isVideoExist(req.params.videoId, res)) return
|
||||
if (!await isVideoExist(req.params.videoId, res, 'id')) return
|
||||
|
||||
return next()
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ const listVideoCommentThreadsValidator = [
|
|||
logger.debug('Checking listVideoCommentThreads parameters.', { parameters: req.params })
|
||||
|
||||
if (areValidationErrors(req, res)) return
|
||||
if (!await isVideoExist(req.params.videoId, res)) return
|
||||
if (!await isVideoExist(req.params.videoId, res, 'only-video')) return
|
||||
|
||||
return next()
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ const listVideoThreadCommentsValidator = [
|
|||
logger.debug('Checking listVideoThreadComments parameters.', { parameters: req.params })
|
||||
|
||||
if (areValidationErrors(req, res)) return
|
||||
if (!await isVideoExist(req.params.videoId, res)) return
|
||||
if (!await isVideoExist(req.params.videoId, res, 'only-video')) return
|
||||
if (!await isVideoCommentThreadExist(req.params.threadId, res.locals.video, res)) return
|
||||
|
||||
return next()
|
||||
|
|
|
@ -91,6 +91,7 @@ import {
|
|||
videoModelToFormattedDetailsJSON,
|
||||
videoModelToFormattedJSON
|
||||
} from './video-format-utils'
|
||||
import * as validator from 'validator'
|
||||
|
||||
// FIXME: Define indexes here because there is an issue with TS and Sequelize.literal when called directly in the annotation
|
||||
const indexes: Sequelize.DefineIndexesOptions[] = [
|
||||
|
@ -466,6 +467,7 @@ type AvailableForListIDsOptions = {
|
|||
required: false,
|
||||
include: [
|
||||
{
|
||||
attributes: [ 'fileUrl' ],
|
||||
model: () => VideoRedundancyModel.unscoped(),
|
||||
required: false
|
||||
}
|
||||
|
@ -1062,8 +1064,26 @@ export class VideoModel extends Model<VideoModel> {
|
|||
return VideoModel.getAvailableForApi(query, queryOptions)
|
||||
}
|
||||
|
||||
static load (id: number, t?: Sequelize.Transaction) {
|
||||
return VideoModel.findById(id, { transaction: t })
|
||||
static load (id: number | string, t?: Sequelize.Transaction) {
|
||||
const where = VideoModel.buildWhereIdOrUUID(id)
|
||||
const options = {
|
||||
where,
|
||||
transaction: t
|
||||
}
|
||||
|
||||
return VideoModel.findOne(options)
|
||||
}
|
||||
|
||||
static loadOnlyId (id: number | string, t?: Sequelize.Transaction) {
|
||||
const where = VideoModel.buildWhereIdOrUUID(id)
|
||||
|
||||
const options = {
|
||||
attributes: [ 'id' ],
|
||||
where,
|
||||
transaction: t
|
||||
}
|
||||
|
||||
return VideoModel.findOne(options)
|
||||
}
|
||||
|
||||
static loadWithFile (id: number, t?: Sequelize.Transaction, logging?: boolean) {
|
||||
|
@ -1071,6 +1091,18 @@ export class VideoModel extends Model<VideoModel> {
|
|||
.findById(id, { transaction: t, logging })
|
||||
}
|
||||
|
||||
static loadByUUIDWithFile (uuid: string) {
|
||||
const options = {
|
||||
where: {
|
||||
uuid
|
||||
}
|
||||
}
|
||||
|
||||
return VideoModel
|
||||
.scope([ ScopeNames.WITH_FILES ])
|
||||
.findOne(options)
|
||||
}
|
||||
|
||||
static loadByUrlAndPopulateAccount (url: string, t?: Sequelize.Transaction) {
|
||||
const query: IFindOptions<VideoModel> = {
|
||||
where: {
|
||||
|
@ -1083,40 +1115,12 @@ export class VideoModel extends Model<VideoModel> {
|
|||
return VideoModel.scope([ ScopeNames.WITH_ACCOUNT_DETAILS, ScopeNames.WITH_FILES ]).findOne(query)
|
||||
}
|
||||
|
||||
static loadAndPopulateAccountAndServerAndTags (id: number) {
|
||||
const options = {
|
||||
order: [ [ 'Tags', 'name', 'ASC' ] ]
|
||||
}
|
||||
static loadAndPopulateAccountAndServerAndTags (id: number | string, t?: Sequelize.Transaction) {
|
||||
const where = VideoModel.buildWhereIdOrUUID(id)
|
||||
|
||||
return VideoModel
|
||||
.scope([
|
||||
ScopeNames.WITH_TAGS,
|
||||
ScopeNames.WITH_BLACKLISTED,
|
||||
ScopeNames.WITH_FILES,
|
||||
ScopeNames.WITH_ACCOUNT_DETAILS,
|
||||
ScopeNames.WITH_SCHEDULED_UPDATE
|
||||
])
|
||||
.findById(id, options)
|
||||
}
|
||||
|
||||
static loadByUUID (uuid: string) {
|
||||
const options = {
|
||||
where: {
|
||||
uuid
|
||||
}
|
||||
}
|
||||
|
||||
return VideoModel
|
||||
.scope([ ScopeNames.WITH_FILES ])
|
||||
.findOne(options)
|
||||
}
|
||||
|
||||
static loadByUUIDAndPopulateAccountAndServerAndTags (uuid: string, t?: Sequelize.Transaction) {
|
||||
const options = {
|
||||
order: [ [ 'Tags', 'name', 'ASC' ] ],
|
||||
where: {
|
||||
uuid
|
||||
},
|
||||
where,
|
||||
transaction: t
|
||||
}
|
||||
|
||||
|
@ -1277,6 +1281,10 @@ export class VideoModel extends Model<VideoModel> {
|
|||
return VIDEO_STATES[ id ] || 'Unknown'
|
||||
}
|
||||
|
||||
static buildWhereIdOrUUID (id: number | string) {
|
||||
return validator.isInt('' + id) ? { id } : { uuid: id }
|
||||
}
|
||||
|
||||
getOriginalFile () {
|
||||
if (Array.isArray(this.VideoFiles) === false) return undefined
|
||||
|
||||
|
|
Loading…
Reference in New Issue