]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame_incremental - server/initializers/database.ts
Merge branch 'release/2.3.0' into develop
[github/Chocobozzz/PeerTube.git] / server / initializers / database.ts
... / ...
CommitLineData
1import { QueryTypes, Transaction } from 'sequelize'
2import { Sequelize as SequelizeTypescript } from 'sequelize-typescript'
3import { AbuseModel } from '@server/models/abuse/abuse'
4import { VideoAbuseModel } from '@server/models/abuse/video-abuse'
5import { VideoCommentAbuseModel } from '@server/models/abuse/video-comment-abuse'
6import { isTestInstance } from '../helpers/core-utils'
7import { logger } from '../helpers/logger'
8import { AccountModel } from '../models/account/account'
9import { AccountBlocklistModel } from '../models/account/account-blocklist'
10import { AccountVideoRateModel } from '../models/account/account-video-rate'
11import { UserModel } from '../models/account/user'
12import { UserNotificationModel } from '../models/account/user-notification'
13import { UserNotificationSettingModel } from '../models/account/user-notification-setting'
14import { UserVideoHistoryModel } from '../models/account/user-video-history'
15import { ActorModel } from '../models/activitypub/actor'
16import { ActorFollowModel } from '../models/activitypub/actor-follow'
17import { ApplicationModel } from '../models/application/application'
18import { AvatarModel } from '../models/avatar/avatar'
19import { OAuthClientModel } from '../models/oauth/oauth-client'
20import { OAuthTokenModel } from '../models/oauth/oauth-token'
21import { VideoRedundancyModel } from '../models/redundancy/video-redundancy'
22import { PluginModel } from '../models/server/plugin'
23import { ServerModel } from '../models/server/server'
24import { ServerBlocklistModel } from '../models/server/server-blocklist'
25import { ScheduleVideoUpdateModel } from '../models/video/schedule-video-update'
26import { TagModel } from '../models/video/tag'
27import { ThumbnailModel } from '../models/video/thumbnail'
28import { VideoModel } from '../models/video/video'
29import { VideoBlacklistModel } from '../models/video/video-blacklist'
30import { VideoCaptionModel } from '../models/video/video-caption'
31import { VideoChangeOwnershipModel } from '../models/video/video-change-ownership'
32import { VideoChannelModel } from '../models/video/video-channel'
33import { VideoCommentModel } from '../models/video/video-comment'
34import { VideoFileModel } from '../models/video/video-file'
35import { VideoImportModel } from '../models/video/video-import'
36import { VideoPlaylistModel } from '../models/video/video-playlist'
37import { VideoPlaylistElementModel } from '../models/video/video-playlist-element'
38import { VideoShareModel } from '../models/video/video-share'
39import { VideoStreamingPlaylistModel } from '../models/video/video-streaming-playlist'
40import { VideoTagModel } from '../models/video/video-tag'
41import { VideoViewModel } from '../models/video/video-view'
42import { CONFIG } from './config'
43
44require('pg').defaults.parseInt8 = true // Avoid BIGINT to be converted to string
45
46const dbname = CONFIG.DATABASE.DBNAME
47const username = CONFIG.DATABASE.USERNAME
48const password = CONFIG.DATABASE.PASSWORD
49const host = CONFIG.DATABASE.HOSTNAME
50const port = CONFIG.DATABASE.PORT
51const poolMax = CONFIG.DATABASE.POOL.MAX
52
53const sequelizeTypescript = new SequelizeTypescript({
54 database: dbname,
55 dialect: 'postgres',
56 host,
57 port,
58 username,
59 password,
60 pool: {
61 max: poolMax
62 },
63 benchmark: isTestInstance(),
64 isolationLevel: Transaction.ISOLATION_LEVELS.SERIALIZABLE,
65 logging: (message: string, benchmark: number) => {
66 if (process.env.NODE_DB_LOG === 'false') return
67
68 let newMessage = message
69 if (isTestInstance() === true && benchmark !== undefined) {
70 newMessage += ' | ' + benchmark + 'ms'
71 }
72
73 logger.debug(newMessage)
74 }
75})
76
77async function initDatabaseModels (silent: boolean) {
78 sequelizeTypescript.addModels([
79 ApplicationModel,
80 ActorModel,
81 ActorFollowModel,
82 AvatarModel,
83 AccountModel,
84 OAuthClientModel,
85 OAuthTokenModel,
86 ServerModel,
87 TagModel,
88 AccountVideoRateModel,
89 UserModel,
90 AbuseModel,
91 VideoCommentAbuseModel,
92 VideoAbuseModel,
93 VideoModel,
94 VideoChangeOwnershipModel,
95 VideoChannelModel,
96 VideoShareModel,
97 VideoFileModel,
98 VideoCaptionModel,
99 VideoBlacklistModel,
100 VideoTagModel,
101 VideoCommentModel,
102 ScheduleVideoUpdateModel,
103 VideoImportModel,
104 VideoViewModel,
105 VideoRedundancyModel,
106 UserVideoHistoryModel,
107 AccountBlocklistModel,
108 ServerBlocklistModel,
109 UserNotificationModel,
110 UserNotificationSettingModel,
111 VideoStreamingPlaylistModel,
112 VideoPlaylistModel,
113 VideoPlaylistElementModel,
114 ThumbnailModel,
115 PluginModel
116 ])
117
118 // Check extensions exist in the database
119 await checkPostgresExtensions()
120
121 // Create custom PostgreSQL functions
122 await createFunctions()
123
124 if (!silent) logger.info('Database %s is ready.', dbname)
125}
126
127// ---------------------------------------------------------------------------
128
129export {
130 initDatabaseModels,
131 sequelizeTypescript
132}
133
134// ---------------------------------------------------------------------------
135
136async function checkPostgresExtensions () {
137 const promises = [
138 checkPostgresExtension('pg_trgm'),
139 checkPostgresExtension('unaccent')
140 ]
141
142 return Promise.all(promises)
143}
144
145async function checkPostgresExtension (extension: string) {
146 const query = `SELECT 1 FROM pg_available_extensions WHERE name = '${extension}' AND installed_version IS NOT NULL;`
147 const options = {
148 type: QueryTypes.SELECT as QueryTypes.SELECT,
149 raw: true
150 }
151
152 const res = await sequelizeTypescript.query<object>(query, options)
153
154 if (!res || res.length === 0) {
155 // Try to create the extension ourselves
156 try {
157 await sequelizeTypescript.query(`CREATE EXTENSION ${extension};`, { raw: true })
158
159 } catch {
160 const errorMessage = `You need to enable ${extension} extension in PostgreSQL. ` +
161 `You can do so by running 'CREATE EXTENSION ${extension};' as a PostgreSQL super user in ${CONFIG.DATABASE.DBNAME} database.`
162 throw new Error(errorMessage)
163 }
164 }
165}
166
167function createFunctions () {
168 const query = `CREATE OR REPLACE FUNCTION immutable_unaccent(text)
169 RETURNS text AS
170$func$
171SELECT public.unaccent('public.unaccent', $1::text)
172$func$ LANGUAGE sql IMMUTABLE;`
173
174 return sequelizeTypescript.query(query, { raw: true })
175}