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