From 3fd3ab2d34d512b160a5e6084d7609be7b4f4452 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Tue, 12 Dec 2017 17:53:50 +0100 Subject: Move models to typescript-sequelize --- server/initializers/checker.ts | 20 +-- server/initializers/constants.ts | 14 +- server/initializers/database.ts | 186 ++++++--------------- server/initializers/installer.ts | 25 +-- .../migrations/0065-video-file-size.ts | 5 +- server/initializers/migrations/0100-activitypub.ts | 6 +- server/initializers/migrations/0105-server-mail.ts | 3 +- server/initializers/migrations/0110-server-key.ts | 3 +- .../initializers/migrations/0115-account-avatar.ts | 3 +- server/initializers/migrations/0120-video-null.ts | 3 +- server/initializers/migrator.ts | 21 ++- 11 files changed, 99 insertions(+), 190 deletions(-) (limited to 'server/initializers') diff --git a/server/initializers/checker.ts b/server/initializers/checker.ts index 317d59423..7e76990b5 100644 --- a/server/initializers/checker.ts +++ b/server/initializers/checker.ts @@ -1,8 +1,8 @@ import * as config from 'config' -import { promisify0 } from '../helpers/core-utils' -import { UserModel } from '../models/account/user-interface' -import { ApplicationModel } from '../models/application/application-interface' -import { OAuthClientModel } from '../models/oauth/oauth-client-interface' +import { promisify0 } from '../helpers' +import { UserModel } from '../models/account/user' +import { ApplicationModel } from '../models/application/application' +import { OAuthClientModel } from '../models/oauth/oauth-client' // Some checks on configuration files function checkConfig () { @@ -57,22 +57,22 @@ async function checkFFmpeg (CONFIG: { TRANSCODING: { ENABLED: boolean } }) { } // We get db by param to not import it in this file (import orders) -async function clientsExist (OAuthClient: OAuthClientModel) { - const totalClients = await OAuthClient.countTotal() +async function clientsExist () { + const totalClients = await OAuthClientModel.countTotal() return totalClients !== 0 } // We get db by param to not import it in this file (import orders) -async function usersExist (User: UserModel) { - const totalUsers = await User.countTotal() +async function usersExist () { + const totalUsers = await UserModel.countTotal() return totalUsers !== 0 } // We get db by param to not import it in this file (import orders) -async function applicationExist (Application: ApplicationModel) { - const totalApplication = await Application.countTotal() +async function applicationExist () { + const totalApplication = await ApplicationModel.countTotal() return totalApplication !== 0 } diff --git a/server/initializers/constants.ts b/server/initializers/constants.ts index 7be7a5f95..f539eb2ee 100644 --- a/server/initializers/constants.ts +++ b/server/initializers/constants.ts @@ -1,16 +1,10 @@ import * as config from 'config' import { join } from 'path' - +import { JobCategory, JobState, VideoRateType } from '../../shared/models' +import { FollowState } from '../../shared/models/accounts' +import { VideoPrivacy } from '../../shared/models/videos' // Do not use barrels, remain constants as independent as possible -import { root, isTestInstance } from '../helpers/core-utils' - -import { - VideoRateType, - JobState, - JobCategory -} from '../../shared/models' -import { VideoPrivacy } from '../../shared/models/videos/video-privacy.enum' -import { FollowState } from '../../shared/models/accounts/follow.model' +import { isTestInstance, root } from '../helpers/core-utils' // --------------------------------------------------------------------------- diff --git a/server/initializers/database.ts b/server/initializers/database.ts index bb95992e1..f9e24c6b8 100644 --- a/server/initializers/database.ts +++ b/server/initializers/database.ts @@ -1,72 +1,43 @@ -import { join } from 'path' -import { flattenDepth } from 'lodash' -require('pg').defaults.parseInt8 = true // Avoid BIGINT to be converted to string -import * as Sequelize from 'sequelize' -import { AvatarModel } from '../models/avatar' +import { Sequelize as SequelizeTypescript } from 'sequelize-typescript' +import { isTestInstance } from '../helpers/core-utils' +import { logger } from '../helpers/logger' +import { AccountModel } from '../models/account/account' +import { AccountFollowModel } from '../models/account/account-follow' +import { AccountVideoRateModel } from '../models/account/account-video-rate' +import { UserModel } from '../models/account/user' +import { ApplicationModel } from '../models/application/application' +import { AvatarModel } from '../models/avatar/avatar' +import { JobModel } from '../models/job/job' +import { OAuthClientModel } from '../models/oauth/oauth-client' +import { OAuthTokenModel } from '../models/oauth/oauth-token' +import { ServerModel } from '../models/server/server' +import { TagModel } from '../models/video/tag' +import { VideoModel } from '../models/video/video' +import { VideoAbuseModel } from '../models/video/video-abuse' +import { VideoBlacklistModel } from '../models/video/video-blacklist' +import { VideoChannelModel } from '../models/video/video-channel' +import { VideoChannelShareModel } from '../models/video/video-channel-share' +import { VideoFileModel } from '../models/video/video-file' +import { VideoShareModel } from '../models/video/video-share' +import { VideoTagModel } from '../models/video/video-tag' import { CONFIG } from './constants' -// Do not use barrel, we need to load database first -import { logger } from '../helpers/logger' -import { isTestInstance, readdirPromise } from '../helpers/core-utils' -import { VideoModel } from './../models/video/video-interface' -import { VideoTagModel } from './../models/video/video-tag-interface' -import { BlacklistedVideoModel } from './../models/video/video-blacklist-interface' -import { VideoFileModel } from './../models/video/video-file-interface' -import { VideoAbuseModel } from './../models/video/video-abuse-interface' -import { VideoChannelModel } from './../models/video/video-channel-interface' -import { UserModel } from '../models/account/user-interface' -import { AccountVideoRateModel } from '../models/account/account-video-rate-interface' -import { AccountFollowModel } from '../models/account/account-follow-interface' -import { TagModel } from './../models/video/tag-interface' -import { ServerModel } from '../models/server/server-interface' -import { OAuthTokenModel } from './../models/oauth/oauth-token-interface' -import { OAuthClientModel } from './../models/oauth/oauth-client-interface' -import { JobModel } from './../models/job/job-interface' -import { AccountModel } from './../models/account/account-interface' -import { ApplicationModel } from './../models/application/application-interface' -import { VideoChannelShareModel } from '../models/video/video-channel-share-interface' -import { VideoShareModel } from '../models/video/video-share-interface' +require('pg').defaults.parseInt8 = true // Avoid BIGINT to be converted to string const dbname = CONFIG.DATABASE.DBNAME const username = CONFIG.DATABASE.USERNAME const password = CONFIG.DATABASE.PASSWORD -export type PeerTubeDatabase = { - sequelize?: Sequelize.Sequelize, - init?: (silent: boolean) => Promise, - - Application?: ApplicationModel, - Avatar?: AvatarModel, - Account?: AccountModel, - Job?: JobModel, - OAuthClient?: OAuthClientModel, - OAuthToken?: OAuthTokenModel, - Server?: ServerModel, - Tag?: TagModel, - AccountVideoRate?: AccountVideoRateModel, - AccountFollow?: AccountFollowModel, - User?: UserModel, - VideoAbuse?: VideoAbuseModel, - VideoChannel?: VideoChannelModel, - VideoChannelShare?: VideoChannelShareModel, - VideoShare?: VideoShareModel, - VideoFile?: VideoFileModel, - BlacklistedVideo?: BlacklistedVideoModel, - VideoTag?: VideoTagModel, - Video?: VideoModel -} - -const database: PeerTubeDatabase = {} - -const sequelize = new Sequelize(dbname, username, password, { +const sequelizeTypescript = new SequelizeTypescript({ + database: dbname, dialect: 'postgres', - host: CONFIG.DATABASE.HOSTNAME, - port: CONFIG.DATABASE.PORT, + username, + password, + modelPaths: [__dirname + '/models'], benchmark: isTestInstance(), - isolationLevel: Sequelize.Transaction.ISOLATION_LEVELS.SERIALIZABLE, + isolationLevel: SequelizeTypescript.Transaction.ISOLATION_LEVELS.SERIALIZABLE, operatorsAliases: false, - logging: (message: string, benchmark: number) => { if (process.env.NODE_DB_LOG === 'false') return @@ -79,34 +50,28 @@ const sequelize = new Sequelize(dbname, username, password, { } }) -database.sequelize = sequelize - -database.init = async (silent: boolean) => { - const modelDirectory = join(__dirname, '..', 'models') - - const filePaths = await getModelFiles(modelDirectory) - - for (const filePath of filePaths) { - try { - const model = sequelize.import(filePath) - - database[model['name']] = model - } catch (err) { - logger.error('Cannot import database model %s.', filePath, err) - process.exit(0) - } - } - - for (const modelName of Object.keys(database)) { - if ('associate' in database[modelName]) { - try { - database[modelName].associate(database) - } catch (err) { - logger.error('Cannot associate model %s.', modelName, err) - process.exit(0) - } - } - } +async function initDatabase (silent: boolean) { + sequelizeTypescript.addModels([ + ApplicationModel, + AvatarModel, + AccountModel, + JobModel, + OAuthClientModel, + OAuthTokenModel, + ServerModel, + TagModel, + AccountVideoRateModel, + AccountFollowModel, + UserModel, + VideoAbuseModel, + VideoChannelModel, + VideoChannelShareModel, + VideoShareModel, + VideoFileModel, + VideoBlacklistModel, + VideoTagModel, + VideoModel + ]) if (!silent) logger.info('Database %s is ready.', dbname) @@ -116,51 +81,6 @@ database.init = async (silent: boolean) => { // --------------------------------------------------------------------------- export { - database -} - -// --------------------------------------------------------------------------- - -async function getModelFiles (modelDirectory: string) { - const files = await readdirPromise(modelDirectory) - const directories = files.filter(directory => { - // Find directories - if ( - directory.endsWith('.js.map') || - directory === 'index.js' || directory === 'index.ts' || - directory === 'utils.js' || directory === 'utils.ts' - ) return false - - return true - }) - - const tasks: Promise[] = [] - - // For each directory we read it and append model in the modelFilePaths array - for (const directory of directories) { - const modelDirectoryPath = join(modelDirectory, directory) - - const promise = readdirPromise(modelDirectoryPath) - .then(files => { - const filteredFiles = files - .filter(file => { - if ( - file === 'index.js' || file === 'index.ts' || - file === 'utils.js' || file === 'utils.ts' || - file.endsWith('-interface.js') || file.endsWith('-interface.ts') || - file.endsWith('.js.map') - ) return false - - return true - }) - .map(file => join(modelDirectoryPath, file)) - - return filteredFiles - }) - - tasks.push(promise) - } - - const filteredFilesArray: string[][] = await Promise.all(tasks) - return flattenDepth(filteredFilesArray, 1) + initDatabase, + sequelizeTypescript } diff --git a/server/initializers/installer.ts b/server/initializers/installer.ts index 954516057..5452743b6 100644 --- a/server/initializers/installer.ts +++ b/server/initializers/installer.ts @@ -1,16 +1,17 @@ import * as passwordGenerator from 'password-generator' import { UserRole } from '../../shared' -import { logger, mkdirpPromise, rimrafPromise } from '../helpers' -import { createUserAccountAndChannel } from '../lib' -import { createLocalAccountWithoutKeys } from '../lib/user' +import { createPrivateAndPublicKeys, logger, mkdirpPromise, rimrafPromise } from '../helpers' +import { createLocalAccountWithoutKeys, createUserAccountAndChannel } from '../lib' +import { UserModel } from '../models/account/user' +import { ApplicationModel } from '../models/application/application' +import { OAuthClientModel } from '../models/oauth/oauth-client' import { applicationExist, clientsExist, usersExist } from './checker' import { CACHE, CONFIG, LAST_MIGRATION_VERSION, SERVER_ACCOUNT_NAME } from './constants' -import { database as db } from './database' -import { createPrivateAndPublicKeys } from '../helpers/peertube-crypto' +import { sequelizeTypescript } from './database' async function installApplication () { try { - await db.sequelize.sync() + await sequelizeTypescript.sync() await removeCacheDirectories() await createDirectoriesIfNotExist() await createApplicationIfNotExist() @@ -64,7 +65,7 @@ function createDirectoriesIfNotExist () { } async function createOAuthClientIfNotExist () { - const exist = await clientsExist(db.OAuthClient) + const exist = await clientsExist() // Nothing to do, clients already exist if (exist === true) return undefined @@ -72,7 +73,7 @@ async function createOAuthClientIfNotExist () { const id = passwordGenerator(32, false, /[a-z0-9]/) const secret = passwordGenerator(32, false, /[a-zA-Z0-9]/) - const client = db.OAuthClient.build({ + const client = new OAuthClientModel({ clientId: id, clientSecret: secret, grants: [ 'password', 'refresh_token' ], @@ -87,7 +88,7 @@ async function createOAuthClientIfNotExist () { } async function createOAuthAdminIfNotExist () { - const exist = await usersExist(db.User) + const exist = await usersExist() // Nothing to do, users already exist if (exist === true) return undefined @@ -120,7 +121,7 @@ async function createOAuthAdminIfNotExist () { role, videoQuota: -1 } - const user = db.User.build(userData) + const user = new UserModel(userData) await createUserAccountAndChannel(user, validatePassword) logger.info('Username: ' + username) @@ -128,12 +129,12 @@ async function createOAuthAdminIfNotExist () { } async function createApplicationIfNotExist () { - const exist = await applicationExist(db.Application) + const exist = await applicationExist() // Nothing to do, application already exist if (exist === true) return undefined logger.info('Creating Application table.') - const applicationInstance = await db.Application.create({ migrationVersion: LAST_MIGRATION_VERSION }) + const applicationInstance = await ApplicationModel.create({ migrationVersion: LAST_MIGRATION_VERSION }) logger.info('Creating application account.') diff --git a/server/initializers/migrations/0065-video-file-size.ts b/server/initializers/migrations/0065-video-file-size.ts index 58f8f3bcc..4e2075f8b 100644 --- a/server/initializers/migrations/0065-video-file-size.ts +++ b/server/initializers/migrations/0065-video-file-size.ts @@ -1,8 +1,7 @@ import * as Sequelize from 'sequelize' import * as Promise from 'bluebird' import { stat } from 'fs' - -import { VideoInstance } from '../../models' +import { VideoModel } from '../../models/video/video' function up (utils: { transaction: Sequelize.Transaction, @@ -11,7 +10,7 @@ function up (utils: { db: any }): Promise { return utils.db.Video.listOwnedAndPopulateAuthorAndTags() - .then((videos: VideoInstance[]) => { + .then((videos: VideoModel[]) => { const tasks: Promise[] = [] videos.forEach(video => { diff --git a/server/initializers/migrations/0100-activitypub.ts b/server/initializers/migrations/0100-activitypub.ts index 50a0adc14..fb42e1d57 100644 --- a/server/initializers/migrations/0100-activitypub.ts +++ b/server/initializers/migrations/0100-activitypub.ts @@ -4,14 +4,14 @@ import { createPrivateAndPublicKeys } from '../../helpers/peertube-crypto' import { shareVideoByServer } from '../../lib/activitypub/share' import { getVideoActivityPubUrl, getVideoChannelActivityPubUrl } from '../../lib/activitypub/url' import { createLocalAccountWithoutKeys } from '../../lib/user' +import { ApplicationModel } from '../../models/application/application' import { JOB_CATEGORIES, SERVER_ACCOUNT_NAME } from '../constants' -import { PeerTubeDatabase } from '../database' async function up (utils: { transaction: Sequelize.Transaction, queryInterface: Sequelize.QueryInterface, sequelize: Sequelize.Sequelize, - db: PeerTubeDatabase + db: any }): Promise { const q = utils.queryInterface const db = utils.db @@ -65,7 +65,7 @@ async function up (utils: { // Create application account { - const applicationInstance = await db.Application.findOne() + const applicationInstance = await ApplicationModel.findOne() const accountCreated = await createLocalAccountWithoutKeys(SERVER_ACCOUNT_NAME, null, applicationInstance.id, undefined) const { publicKey, privateKey } = await createPrivateAndPublicKeys() diff --git a/server/initializers/migrations/0105-server-mail.ts b/server/initializers/migrations/0105-server-mail.ts index 5836992d5..4b9600e91 100644 --- a/server/initializers/migrations/0105-server-mail.ts +++ b/server/initializers/migrations/0105-server-mail.ts @@ -1,11 +1,10 @@ import * as Sequelize from 'sequelize' -import { PeerTubeDatabase } from '../database' async function up (utils: { transaction: Sequelize.Transaction, queryInterface: Sequelize.QueryInterface, sequelize: Sequelize.Sequelize, - db: PeerTubeDatabase + db: any }): Promise { await utils.queryInterface.removeColumn('Servers', 'email') } diff --git a/server/initializers/migrations/0110-server-key.ts b/server/initializers/migrations/0110-server-key.ts index 560353945..5ff6daf69 100644 --- a/server/initializers/migrations/0110-server-key.ts +++ b/server/initializers/migrations/0110-server-key.ts @@ -1,11 +1,10 @@ import * as Sequelize from 'sequelize' -import { PeerTubeDatabase } from '../database' async function up (utils: { transaction: Sequelize.Transaction, queryInterface: Sequelize.QueryInterface, sequelize: Sequelize.Sequelize, - db: PeerTubeDatabase + db: any }): Promise { await utils.queryInterface.removeColumn('Servers', 'publicKey') } diff --git a/server/initializers/migrations/0115-account-avatar.ts b/server/initializers/migrations/0115-account-avatar.ts index 2b947ceda..b318e8163 100644 --- a/server/initializers/migrations/0115-account-avatar.ts +++ b/server/initializers/migrations/0115-account-avatar.ts @@ -1,11 +1,10 @@ import * as Sequelize from 'sequelize' -import { PeerTubeDatabase } from '../database' async function up (utils: { transaction: Sequelize.Transaction, queryInterface: Sequelize.QueryInterface, sequelize: Sequelize.Sequelize, - db: PeerTubeDatabase + db: any }): Promise { await utils.db.Avatar.sync() diff --git a/server/initializers/migrations/0120-video-null.ts b/server/initializers/migrations/0120-video-null.ts index 9130d10ee..63f3984dd 100644 --- a/server/initializers/migrations/0120-video-null.ts +++ b/server/initializers/migrations/0120-video-null.ts @@ -1,12 +1,11 @@ import * as Sequelize from 'sequelize' import { CONSTRAINTS_FIELDS } from '../constants' -import { PeerTubeDatabase } from '../database' async function up (utils: { transaction: Sequelize.Transaction, queryInterface: Sequelize.QueryInterface, sequelize: Sequelize.Sequelize, - db: PeerTubeDatabase + db: any }): Promise { { diff --git a/server/initializers/migrator.ts b/server/initializers/migrator.ts index 187c9be6e..f3a05cc8c 100644 --- a/server/initializers/migrator.ts +++ b/server/initializers/migrator.ts @@ -1,19 +1,19 @@ import * as path from 'path' - -import { database as db } from './database' -import { LAST_MIGRATION_VERSION } from './constants' import { logger, readdirPromise } from '../helpers' +import { ApplicationModel } from '../models/application/application' +import { LAST_MIGRATION_VERSION } from './constants' +import { sequelizeTypescript } from './database' async function migrate () { - const tables = await db.sequelize.getQueryInterface().showAllTables() + const tables = await sequelizeTypescript.getQueryInterface().showAllTables() // No tables, we don't need to migrate anything // The installer will do that if (tables.length === 0) return - let actualVersion = await db.Application.loadMigrationVersion() + let actualVersion = await ApplicationModel.loadMigrationVersion() if (actualVersion === null) { - await db.Application.create({ migrationVersion: 0 }) + await ApplicationModel.create({ migrationVersion: 0 }) actualVersion = 0 } @@ -78,17 +78,16 @@ async function executeMigration (actualVersion: number, entity: { version: strin const migrationScript = require(path.join(__dirname, 'migrations', migrationScriptName)) - await db.sequelize.transaction(async t => { + await sequelizeTypescript.transaction(async t => { const options = { transaction: t, - queryInterface: db.sequelize.getQueryInterface(), - sequelize: db.sequelize, - db + queryInterface: sequelizeTypescript.getQueryInterface(), + sequelize: sequelizeTypescript } await migrationScript.up(options) // Update the new migration version - await db.Application.updateMigrationVersion(versionScript, t) + await ApplicationModel.updateMigrationVersion(versionScript, t) }) } -- cgit v1.2.3