]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - server/initializers/database.ts
Translated using Weblate (Toki Pona (tok))
[github/Chocobozzz/PeerTube.git] / server / initializers / database.ts
CommitLineData
d95d1559 1import { QueryTypes, Transaction } from 'sequelize'
3fd3ab2d 2import { Sequelize as SequelizeTypescript } from 'sequelize-typescript'
b2111066 3import { ActorCustomPageModel } from '@server/models/account/actor-custom-page'
f4796856
C
4import { TrackerModel } from '@server/models/server/tracker'
5import { VideoTrackerModel } from '@server/models/server/video-tracker'
7d9ba5c0
C
6import { UserModel } from '@server/models/user/user'
7import { UserNotificationModel } from '@server/models/user/user-notification'
8import { UserVideoHistoryModel } from '@server/models/user/user-video-history'
b2111066 9import { VideoJobInfoModel } from '@server/models/video/video-job-info'
26e3e98f 10import { VideoLiveSessionModel } from '@server/models/video/video-live-session'
b2111066
C
11import { LocalVideoViewerModel } from '@server/models/view/local-video-viewer'
12import { LocalVideoViewerWatchSectionModel } from '@server/models/view/local-video-viewer-watch-section'
3fd3ab2d
C
13import { isTestInstance } from '../helpers/core-utils'
14import { logger } from '../helpers/logger'
c6c0fa6c
C
15import { AbuseModel } from '../models/abuse/abuse'
16import { AbuseMessageModel } from '../models/abuse/abuse-message'
17import { VideoAbuseModel } from '../models/abuse/video-abuse'
18import { VideoCommentAbuseModel } from '../models/abuse/video-comment-abuse'
3fd3ab2d 19import { AccountModel } from '../models/account/account'
d95d1559 20import { AccountBlocklistModel } from '../models/account/account-blocklist'
3fd3ab2d 21import { AccountVideoRateModel } from '../models/account/account-video-rate'
7d9ba5c0
C
22import { ActorModel } from '../models/actor/actor'
23import { ActorFollowModel } from '../models/actor/actor-follow'
24import { ActorImageModel } from '../models/actor/actor-image'
3fd3ab2d 25import { ApplicationModel } from '../models/application/application'
3fd3ab2d
C
26import { OAuthClientModel } from '../models/oauth/oauth-client'
27import { OAuthTokenModel } from '../models/oauth/oauth-token'
d95d1559
C
28import { VideoRedundancyModel } from '../models/redundancy/video-redundancy'
29import { PluginModel } from '../models/server/plugin'
3fd3ab2d 30import { ServerModel } from '../models/server/server'
d95d1559 31import { ServerBlocklistModel } from '../models/server/server-blocklist'
7d9ba5c0 32import { UserNotificationSettingModel } from '../models/user/user-notification-setting'
d95d1559 33import { ScheduleVideoUpdateModel } from '../models/video/schedule-video-update'
3fd3ab2d 34import { TagModel } from '../models/video/tag'
d95d1559 35import { ThumbnailModel } from '../models/video/thumbnail'
3fd3ab2d 36import { VideoModel } from '../models/video/video'
3fd3ab2d 37import { VideoBlacklistModel } from '../models/video/video-blacklist'
d95d1559
C
38import { VideoCaptionModel } from '../models/video/video-caption'
39import { VideoChangeOwnershipModel } from '../models/video/video-change-ownership'
3fd3ab2d 40import { VideoChannelModel } from '../models/video/video-channel'
6d852470 41import { VideoCommentModel } from '../models/video/video-comment'
3fd3ab2d 42import { VideoFileModel } from '../models/video/video-file'
fbad87b0 43import { VideoImportModel } from '../models/video/video-import'
c6c0fa6c 44import { VideoLiveModel } from '../models/video/video-live'
418d092a
C
45import { VideoPlaylistModel } from '../models/video/video-playlist'
46import { VideoPlaylistElementModel } from '../models/video/video-playlist-element'
d95d1559
C
47import { VideoShareModel } from '../models/video/video-share'
48import { VideoStreamingPlaylistModel } from '../models/video/video-streaming-playlist'
49import { VideoTagModel } from '../models/video/video-tag'
b2111066 50import { VideoViewModel } from '../models/view/video-view'
d95d1559 51import { CONFIG } from './config'
fdbda9e3 52
3fd3ab2d 53require('pg').defaults.parseInt8 = true // Avoid BIGINT to be converted to string
8c308c2b 54
65fcc311
C
55const dbname = CONFIG.DATABASE.DBNAME
56const username = CONFIG.DATABASE.USERNAME
57const password = CONFIG.DATABASE.PASSWORD
228077ef
C
58const host = CONFIG.DATABASE.HOSTNAME
59const port = CONFIG.DATABASE.PORT
1c3386e8 60const poolMax = CONFIG.DATABASE.POOL.MAX
8c308c2b 61
6bc672da
C
62let dialectOptions: any = {}
63
64if (CONFIG.DATABASE.SSL) {
65 dialectOptions = {
66 ssl: {
67 rejectUnauthorized: false
68 }
69 }
70}
71
3fd3ab2d
C
72const sequelizeTypescript = new SequelizeTypescript({
73 database: dbname,
feb4bdfd 74 dialect: 'postgres',
6bc672da 75 dialectOptions,
228077ef
C
76 host,
77 port,
3fd3ab2d
C
78 username,
79 password,
1c3386e8
RK
80 pool: {
81 max: poolMax
82 },
65fcc311 83 benchmark: isTestInstance(),
1735c825 84 isolationLevel: Transaction.ISOLATION_LEVELS.SERIALIZABLE,
075f16ca 85 logging: (message: string, benchmark: number) => {
165cdc75
C
86 if (process.env.NODE_DB_LOG === 'false') return
87
2a6cf69c 88 let newMessage = 'Executed SQL request'
769d3321 89 if (isTestInstance() === true && benchmark !== undefined) {
2a6cf69c 90 newMessage += ' in ' + benchmark + 'ms'
7920c273
C
91 }
92
452b3bea 93 logger.debug(newMessage, { sql: message, tags: [ 'sql' ] })
7920c273 94 }
feb4bdfd
C
95})
96
74055dc8
C
97function checkDatabaseConnectionOrDie () {
98 sequelizeTypescript.authenticate()
99 .then(() => logger.debug('Connection to PostgreSQL has been established successfully.'))
100 .catch(err => {
101
102 logger.error('Unable to connect to PostgreSQL database.', { err })
103 process.exit(-1)
104 })
105}
4f24f16e 106
91fea9fc 107async function initDatabaseModels (silent: boolean) {
3fd3ab2d
C
108 sequelizeTypescript.addModels([
109 ApplicationModel,
50d6de9c
C
110 ActorModel,
111 ActorFollowModel,
f4796856 112 ActorImageModel,
3fd3ab2d 113 AccountModel,
3fd3ab2d
C
114 OAuthClientModel,
115 OAuthTokenModel,
116 ServerModel,
117 TagModel,
118 AccountVideoRateModel,
3fd3ab2d 119 UserModel,
edbc9325 120 AbuseMessageModel,
d95d1559
C
121 AbuseModel,
122 VideoCommentAbuseModel,
3fd3ab2d 123 VideoAbuseModel,
b876eaf1 124 VideoModel,
74d63469 125 VideoChangeOwnershipModel,
3fd3ab2d 126 VideoChannelModel,
3fd3ab2d
C
127 VideoShareModel,
128 VideoFileModel,
40e87e9e 129 VideoCaptionModel,
3fd3ab2d
C
130 VideoBlacklistModel,
131 VideoTagModel,
2baea0c7 132 VideoCommentModel,
fbad87b0 133 ScheduleVideoUpdateModel,
6b616860 134 VideoImportModel,
c48e82b5 135 VideoViewModel,
6e46de09 136 VideoRedundancyModel,
7ad9b984 137 UserVideoHistoryModel,
c6c0fa6c 138 VideoLiveModel,
26e3e98f 139 VideoLiveSessionModel,
7ad9b984 140 AccountBlocklistModel,
cef534ed
C
141 ServerBlocklistModel,
142 UserNotificationModel,
09209296 143 UserNotificationSettingModel,
418d092a
C
144 VideoStreamingPlaylistModel,
145 VideoPlaylistModel,
e8bafea3 146 VideoPlaylistElementModel,
b2111066
C
147 LocalVideoViewerModel,
148 LocalVideoViewerWatchSectionModel,
f023a19c 149 ThumbnailModel,
d9a2a031
C
150 TrackerModel,
151 VideoTrackerModel,
2539932e 152 PluginModel,
0305db28
JB
153 ActorCustomPageModel,
154 VideoJobInfoModel
3fd3ab2d 155 ])
b769007f 156
57c36b27
C
157 // Check extensions exist in the database
158 await checkPostgresExtensions()
159
160 // Create custom PostgreSQL functions
161 await createFunctions()
162
f5028693 163 if (!silent) logger.info('Database %s is ready.', dbname)
b769007f 164}
65fcc311
C
165
166// ---------------------------------------------------------------------------
167
e02643f3 168export {
91fea9fc 169 initDatabaseModels,
74055dc8 170 checkDatabaseConnectionOrDie,
3fd3ab2d 171 sequelizeTypescript
74889a71 172}
57c36b27
C
173
174// ---------------------------------------------------------------------------
175
176async function checkPostgresExtensions () {
0b2f03d3
C
177 const promises = [
178 checkPostgresExtension('pg_trgm'),
179 checkPostgresExtension('unaccent')
57c36b27
C
180 ]
181
0b2f03d3
C
182 return Promise.all(promises)
183}
184
185async function checkPostgresExtension (extension: string) {
3acc5084 186 const query = `SELECT 1 FROM pg_available_extensions WHERE name = '${extension}' AND installed_version IS NOT NULL;`
1735c825
C
187 const options = {
188 type: QueryTypes.SELECT as QueryTypes.SELECT,
189 raw: true
190 }
191
3acc5084 192 const res = await sequelizeTypescript.query<object>(query, options)
57c36b27 193
3acc5084 194 if (!res || res.length === 0) {
1735c825 195 // Try to create the extension ourselves
0b2f03d3
C
196 try {
197 await sequelizeTypescript.query(`CREATE EXTENSION ${extension};`, { raw: true })
57c36b27 198
0b2f03d3
C
199 } catch {
200 const errorMessage = `You need to enable ${extension} extension in PostgreSQL. ` +
201 `You can do so by running 'CREATE EXTENSION ${extension};' as a PostgreSQL super user in ${CONFIG.DATABASE.DBNAME} database.`
202 throw new Error(errorMessage)
57c36b27
C
203 }
204 }
205}
206
f0ad4710 207function createFunctions () {
2cebd797
C
208 const query = `CREATE OR REPLACE FUNCTION immutable_unaccent(text)
209 RETURNS text AS
210$func$
211SELECT public.unaccent('public.unaccent', $1::text)
212$func$ LANGUAGE sql IMMUTABLE;`
57c36b27
C
213
214 return sequelizeTypescript.query(query, { raw: true })
215}