aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/models/video/sql/shared
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2021-06-10 16:57:13 +0200
committerChocobozzz <me@florianbigard.com>2021-06-11 09:31:59 +0200
commit1d43c3a613c72d69f7360fee9e5bfe6f662d62f7 (patch)
treed4ba891ffdb1182e39620c06feff1503365d66b5 /server/models/video/sql/shared
parentd9bf974f5df787bbeaab5b04949ca91a2b3ca2a3 (diff)
downloadPeerTube-1d43c3a613c72d69f7360fee9e5bfe6f662d62f7.tar.gz
PeerTube-1d43c3a613c72d69f7360fee9e5bfe6f662d62f7.tar.zst
PeerTube-1d43c3a613c72d69f7360fee9e5bfe6f662d62f7.zip
Use separate queries for video files
Diffstat (limited to 'server/models/video/sql/shared')
-rw-r--r--server/models/video/sql/shared/abstract-videos-model-query-builder.ts65
-rw-r--r--server/models/video/sql/shared/abstract-videos-query-builder.ts6
-rw-r--r--server/models/video/sql/shared/video-attributes.ts6
-rw-r--r--server/models/video/sql/shared/video-file-query-builder.ts66
-rw-r--r--server/models/video/sql/shared/video-model-builder.ts37
5 files changed, 158 insertions, 22 deletions
diff --git a/server/models/video/sql/shared/abstract-videos-model-query-builder.ts b/server/models/video/sql/shared/abstract-videos-model-query-builder.ts
index bdf926cbe..8ed207eea 100644
--- a/server/models/video/sql/shared/abstract-videos-model-query-builder.ts
+++ b/server/models/video/sql/shared/abstract-videos-model-query-builder.ts
@@ -1,19 +1,24 @@
1import validator from 'validator'
1import { AbstractVideosQueryBuilder } from './abstract-videos-query-builder' 2import { AbstractVideosQueryBuilder } from './abstract-videos-query-builder'
2import { VideoAttributes } from './video-attributes' 3import { VideoAttributes } from './video-attributes'
3import { VideoModelBuilder } from './video-model-builder' 4
5/**
6 *
7 * Abstract builder to create SQL query and fetch video models
8 *
9 */
4 10
5export class AbstractVideosModelQueryBuilder extends AbstractVideosQueryBuilder { 11export class AbstractVideosModelQueryBuilder extends AbstractVideosQueryBuilder {
6 protected attributes: { [key: string]: string } = {} 12 protected attributes: { [key: string]: string } = {}
7 protected joins: string[] = [] 13 protected joins: string[] = []
14 protected where: string
8 15
9 protected videoAttributes: VideoAttributes 16 protected videoAttributes: VideoAttributes
10 protected videoModelBuilder: VideoModelBuilder
11 17
12 constructor (private readonly mode: 'list' | 'get') { 18 constructor (protected readonly mode: 'list' | 'get') {
13 super() 19 super()
14 20
15 this.videoAttributes = new VideoAttributes(this.mode) 21 this.videoAttributes = new VideoAttributes(this.mode)
16 this.videoModelBuilder = new VideoModelBuilder(this.mode, this.videoAttributes)
17 } 22 }
18 23
19 protected buildSelect () { 24 protected buildSelect () {
@@ -78,21 +83,30 @@ export class AbstractVideosModelQueryBuilder extends AbstractVideosQueryBuilder
78 } 83 }
79 } 84 }
80 85
81 protected includeFiles () { 86 protected includeWebtorrentFiles (required: boolean) {
82 this.joins.push( 87 const joinType = required ? 'INNER' : 'LEFT'
83 'LEFT JOIN "videoFile" AS "VideoFiles" ON "VideoFiles"."videoId" = "video"."id"', 88 this.joins.push(joinType + ' JOIN "videoFile" AS "VideoFiles" ON "VideoFiles"."videoId" = "video"."id"')
89
90 this.attributes = {
91 ...this.attributes,
92
93 ...this.buildAttributesObject('VideoFiles', this.videoAttributes.getFileAttributes())
94 }
95 }
96
97 protected includeStreamingPlaylistFiles (required: boolean) {
98 const joinType = required ? 'INNER' : 'LEFT'
84 99
85 'LEFT JOIN "videoStreamingPlaylist" AS "VideoStreamingPlaylists" ON "VideoStreamingPlaylists"."videoId" = "video"."id"', 100 this.joins.push(
101 joinType + ' JOIN "videoStreamingPlaylist" AS "VideoStreamingPlaylists" ON "VideoStreamingPlaylists"."videoId" = "video"."id"',
86 102
87 'LEFT JOIN "videoFile" AS "VideoStreamingPlaylists->VideoFiles" ' + 103 joinType + ' JOIN "videoFile" AS "VideoStreamingPlaylists->VideoFiles" ' +
88 'ON "VideoStreamingPlaylists->VideoFiles"."videoStreamingPlaylistId" = "VideoStreamingPlaylists"."id"' 104 'ON "VideoStreamingPlaylists->VideoFiles"."videoStreamingPlaylistId" = "VideoStreamingPlaylists"."id"'
89 ) 105 )
90 106
91 this.attributes = { 107 this.attributes = {
92 ...this.attributes, 108 ...this.attributes,
93 109
94 ...this.buildAttributesObject('VideoFiles', this.videoAttributes.getFileAttributes()),
95
96 ...this.buildAttributesObject('VideoStreamingPlaylists', this.videoAttributes.getStreamingPlaylistAttributes()), 110 ...this.buildAttributesObject('VideoStreamingPlaylists', this.videoAttributes.getStreamingPlaylistAttributes()),
97 ...this.buildAttributesObject('VideoStreamingPlaylists->VideoFiles', this.videoAttributes.getFileAttributes()) 111 ...this.buildAttributesObject('VideoStreamingPlaylists->VideoFiles', this.videoAttributes.getFileAttributes())
98 } 112 }
@@ -196,11 +210,8 @@ export class AbstractVideosModelQueryBuilder extends AbstractVideosQueryBuilder
196 } 210 }
197 } 211 }
198 212
199 protected includeRedundancies () { 213 protected includeWebTorrentRedundancies () {
200 this.joins.push( 214 this.joins.push(
201 'LEFT OUTER JOIN "videoRedundancy" AS "VideoStreamingPlaylists->RedundancyVideos" ' +
202 'ON "VideoStreamingPlaylists"."id" = "VideoStreamingPlaylists->RedundancyVideos"."videoStreamingPlaylistId"',
203
204 'LEFT OUTER JOIN "videoRedundancy" AS "VideoFiles->RedundancyVideos" ON ' + 215 'LEFT OUTER JOIN "videoRedundancy" AS "VideoFiles->RedundancyVideos" ON ' +
205 '"VideoFiles"."id" = "VideoFiles->RedundancyVideos"."videoFileId"' 216 '"VideoFiles"."id" = "VideoFiles->RedundancyVideos"."videoFileId"'
206 ) 217 )
@@ -208,7 +219,19 @@ export class AbstractVideosModelQueryBuilder extends AbstractVideosQueryBuilder
208 this.attributes = { 219 this.attributes = {
209 ...this.attributes, 220 ...this.attributes,
210 221
211 ...this.buildAttributesObject('VideoFiles->RedundancyVideos', this.videoAttributes.getRedundancyAttributes()), 222 ...this.buildAttributesObject('VideoFiles->RedundancyVideos', this.videoAttributes.getRedundancyAttributes())
223 }
224 }
225
226 protected includeStreamingPlaylistRedundancies () {
227 this.joins.push(
228 'LEFT OUTER JOIN "videoRedundancy" AS "VideoStreamingPlaylists->RedundancyVideos" ' +
229 'ON "VideoStreamingPlaylists"."id" = "VideoStreamingPlaylists->RedundancyVideos"."videoStreamingPlaylistId"'
230 )
231
232 this.attributes = {
233 ...this.attributes,
234
212 ...this.buildAttributesObject('VideoStreamingPlaylists->RedundancyVideos', this.videoAttributes.getRedundancyAttributes()) 235 ...this.buildAttributesObject('VideoStreamingPlaylists->RedundancyVideos', this.videoAttributes.getRedundancyAttributes())
213 } 236 }
214 } 237 }
@@ -236,4 +259,14 @@ export class AbstractVideosModelQueryBuilder extends AbstractVideosQueryBuilder
236 259
237 return result 260 return result
238 } 261 }
262
263 protected whereId (id: string | number) {
264 if (validator.isInt('' + id)) {
265 this.where = 'WHERE "video".id = :videoId'
266 } else {
267 this.where = 'WHERE uuid = :videoId'
268 }
269
270 this.replacements.videoId = id
271 }
239} 272}
diff --git a/server/models/video/sql/shared/abstract-videos-query-builder.ts b/server/models/video/sql/shared/abstract-videos-query-builder.ts
index 01694e691..c1bbeb71e 100644
--- a/server/models/video/sql/shared/abstract-videos-query-builder.ts
+++ b/server/models/video/sql/shared/abstract-videos-query-builder.ts
@@ -1,6 +1,12 @@
1import { QueryTypes, Sequelize, Transaction } from 'sequelize' 1import { QueryTypes, Sequelize, Transaction } from 'sequelize'
2import { logger } from '@server/helpers/logger' 2import { logger } from '@server/helpers/logger'
3 3
4/**
5 *
6 * Abstact builder to run video SQL queries
7 *
8 */
9
4export class AbstractVideosQueryBuilder { 10export class AbstractVideosQueryBuilder {
5 protected sequelize: Sequelize 11 protected sequelize: Sequelize
6 12
diff --git a/server/models/video/sql/shared/video-attributes.ts b/server/models/video/sql/shared/video-attributes.ts
index 1a1650dc7..e21b33c73 100644
--- a/server/models/video/sql/shared/video-attributes.ts
+++ b/server/models/video/sql/shared/video-attributes.ts
@@ -1,3 +1,9 @@
1
2/**
3 *
4 * Class to build video attributes we want to fetch from the database
5 *
6 */
1export class VideoAttributes { 7export class VideoAttributes {
2 8
3 constructor (readonly mode: 'get' | 'list') { 9 constructor (readonly mode: 'get' | 'list') {
diff --git a/server/models/video/sql/shared/video-file-query-builder.ts b/server/models/video/sql/shared/video-file-query-builder.ts
new file mode 100644
index 000000000..29b11a298
--- /dev/null
+++ b/server/models/video/sql/shared/video-file-query-builder.ts
@@ -0,0 +1,66 @@
1import { Sequelize } from 'sequelize'
2import { BuildVideoGetQueryOptions } from '../video-model-get-query-builder'
3import { AbstractVideosModelQueryBuilder } from './abstract-videos-model-query-builder'
4
5/**
6 *
7 * Fetch files (webtorrent and streaming playlist) according to a video
8 *
9 */
10
11export class VideoFileQueryBuilder extends AbstractVideosModelQueryBuilder {
12 protected attributes: { [key: string]: string }
13 protected joins: string[] = []
14
15 constructor (protected readonly sequelize: Sequelize) {
16 super('get')
17 }
18
19 queryWebTorrentVideos (options: BuildVideoGetQueryOptions) {
20 this.buildWebtorrentFilesQuery(options)
21
22 return this.runQuery(options.transaction, true)
23 }
24
25 queryStreamingPlaylistVideos (options: BuildVideoGetQueryOptions) {
26 this.buildVideoStreamingPlaylistFilesQuery(options)
27
28 return this.runQuery(options.transaction, true)
29 }
30
31 private buildWebtorrentFilesQuery (options: BuildVideoGetQueryOptions) {
32 this.attributes = {
33 '"video"."id"': ''
34 }
35
36 this.includeWebtorrentFiles(true)
37
38 if (options.forGetAPI === true) {
39 this.includeWebTorrentRedundancies()
40 }
41
42 this.whereId(options.id)
43
44 this.query = this.buildQuery()
45 }
46
47 private buildVideoStreamingPlaylistFilesQuery (options: BuildVideoGetQueryOptions) {
48 this.attributes = {
49 '"video"."id"': ''
50 }
51
52 this.includeStreamingPlaylistFiles(true)
53
54 if (options.forGetAPI === true) {
55 this.includeStreamingPlaylistRedundancies()
56 }
57
58 this.whereId(options.id)
59
60 this.query = this.buildQuery()
61 }
62
63 private buildQuery () {
64 return `${this.buildSelect()} FROM "video" ${this.joins.join(' ')} ${this.where}`
65 }
66}
diff --git a/server/models/video/sql/shared/video-model-builder.ts b/server/models/video/sql/shared/video-model-builder.ts
index 9719f6d2e..627ea6443 100644
--- a/server/models/video/sql/shared/video-model-builder.ts
+++ b/server/models/video/sql/shared/video-model-builder.ts
@@ -17,6 +17,12 @@ import { VideoLiveModel } from '../../video-live'
17import { VideoStreamingPlaylistModel } from '../../video-streaming-playlist' 17import { VideoStreamingPlaylistModel } from '../../video-streaming-playlist'
18import { VideoAttributes } from './video-attributes' 18import { VideoAttributes } from './video-attributes'
19 19
20/**
21 *
22 * Build video models from SQL rows
23 *
24 */
25
20export class VideoModelBuilder { 26export class VideoModelBuilder {
21 private videosMemo: { [ id: number ]: VideoModel } 27 private videosMemo: { [ id: number ]: VideoModel }
22 private videoStreamingPlaylistMemo: { [ id: number ]: VideoStreamingPlaylistModel } 28 private videoStreamingPlaylistMemo: { [ id: number ]: VideoStreamingPlaylistModel }
@@ -43,7 +49,7 @@ export class VideoModelBuilder {
43 49
44 } 50 }
45 51
46 buildVideosFromRows (rows: any[]) { 52 buildVideosFromRows (rows: any[], rowsWebtorrentFiles?: any[], rowsStreamingPlaylist?: any[]) {
47 this.reinit() 53 this.reinit()
48 54
49 for (const row of rows) { 55 for (const row of rows) {
@@ -53,10 +59,15 @@ export class VideoModelBuilder {
53 59
54 this.setUserHistory(row, videoModel) 60 this.setUserHistory(row, videoModel)
55 this.addThumbnail(row, videoModel) 61 this.addThumbnail(row, videoModel)
56 this.addWebTorrentFile(row, videoModel)
57 62
58 this.addStreamingPlaylist(row, videoModel) 63 if (!rowsWebtorrentFiles) {
59 this.addStreamingPlaylistFile(row) 64 this.addWebTorrentFile(row, videoModel)
65 }
66
67 if (!rowsStreamingPlaylist) {
68 this.addStreamingPlaylist(row, videoModel)
69 this.addStreamingPlaylistFile(row)
70 }
60 71
61 if (this.mode === 'get') { 72 if (this.mode === 'get') {
62 this.addTag(row, videoModel) 73 this.addTag(row, videoModel)
@@ -65,16 +76,30 @@ export class VideoModelBuilder {
65 this.setScheduleVideoUpdate(row, videoModel) 76 this.setScheduleVideoUpdate(row, videoModel)
66 this.setLive(row, videoModel) 77 this.setLive(row, videoModel)
67 78
68 if (row.VideoFiles.id) { 79 if (!rowsWebtorrentFiles && row.VideoFiles.id) {
69 this.addRedundancy(row.VideoFiles.RedundancyVideos, this.videoFileMemo[row.VideoFiles.id]) 80 this.addRedundancy(row.VideoFiles.RedundancyVideos, this.videoFileMemo[row.VideoFiles.id])
70 } 81 }
71 82
72 if (row.VideoStreamingPlaylists.id) { 83 if (!rowsStreamingPlaylist && row.VideoStreamingPlaylists.id) {
73 this.addRedundancy(row.VideoStreamingPlaylists.RedundancyVideos, this.videoStreamingPlaylistMemo[row.VideoStreamingPlaylists.id]) 84 this.addRedundancy(row.VideoStreamingPlaylists.RedundancyVideos, this.videoStreamingPlaylistMemo[row.VideoStreamingPlaylists.id])
74 } 85 }
75 } 86 }
76 } 87 }
77 88
89 for (const row of rowsWebtorrentFiles || []) {
90 const videoModel = this.videosMemo[row.id]
91 this.addWebTorrentFile(row, videoModel)
92 this.addRedundancy(row.VideoFiles.RedundancyVideos, this.videoFileMemo[row.VideoFiles.id])
93 }
94
95 for (const row of rowsStreamingPlaylist || []) {
96 const videoModel = this.videosMemo[row.id]
97
98 this.addStreamingPlaylist(row, videoModel)
99 this.addStreamingPlaylistFile(row)
100 this.addRedundancy(row.VideoStreamingPlaylists.RedundancyVideos, this.videoStreamingPlaylistMemo[row.VideoStreamingPlaylists.id])
101 }
102
78 return this.videos 103 return this.videos
79 } 104 }
80 105