You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

155 lines
3.8 KiB

  1. const _ = require('lodash')
  2. const autoload = require('auto-load')
  3. const path = require('path')
  4. const Promise = require('bluebird')
  5. const Knex = require('knex')
  6. const Objection = require('objection')
  7. const migrationSource = require('../db/migrator-source')
  8. /* global WIKI */
  9. /**
  10. * ORM DB module
  11. */
  12. module.exports = {
  13. Objection,
  14. knex: null,
  15. /**
  16. * Initialize DB
  17. *
  18. * @return {Object} DB instance
  19. */
  20. init() {
  21. let self = this
  22. let dbClient = null
  23. let dbConfig = (!_.isEmpty(process.env.DATABASE_URL)) ? process.env.DATABASE_URL : {
  24. host: WIKI.config.db.host,
  25. user: WIKI.config.db.user,
  26. password: WIKI.config.db.pass,
  27. database: WIKI.config.db.db,
  28. port: WIKI.config.db.port
  29. }
  30. const dbUseSSL = (WIKI.config.db.ssl === true || WIKI.config.db.ssl === 'true' || WIKI.config.db.ssl === 1 || WIKI.config.db.ssl === '1')
  31. switch (WIKI.config.db.type) {
  32. case 'postgres':
  33. dbClient = 'pg'
  34. if (dbUseSSL && _.isPlainObject(dbConfig)) {
  35. dbConfig.ssl = true
  36. }
  37. break
  38. case 'mariadb':
  39. case 'mysql':
  40. dbClient = 'mysql2'
  41. if (dbUseSSL && _.isPlainObject(dbConfig)) {
  42. dbConfig.ssl = true
  43. }
  44. // Fix mysql boolean handling...
  45. dbConfig.typeCast = (field, next) => {
  46. if (field.type === 'TINY' && field.length === 1) {
  47. let value = field.string()
  48. return value ? (value === '1') : null
  49. }
  50. return next()
  51. }
  52. break
  53. case 'mssql':
  54. dbClient = 'mssql'
  55. if (_.isPlainObject(dbConfig)) {
  56. dbConfig.appName = 'Wiki.js'
  57. if (dbUseSSL) {
  58. dbConfig.encrypt = true
  59. }
  60. }
  61. break
  62. case 'sqlite':
  63. dbClient = 'sqlite3'
  64. dbConfig = { filename: WIKI.config.db.storage }
  65. break
  66. default:
  67. WIKI.logger.error('Invalid DB Type')
  68. process.exit(1)
  69. }
  70. this.knex = Knex({
  71. client: dbClient,
  72. useNullAsDefault: true,
  73. asyncStackTraces: WIKI.IS_DEBUG,
  74. connection: dbConfig,
  75. pool: {
  76. ...WIKI.config.pool,
  77. async afterCreate(conn, done) {
  78. // -> Set Connection App Name
  79. switch (WIKI.config.db.type) {
  80. case 'postgres':
  81. await conn.query(`set application_name = 'Wiki.js'`)
  82. done()
  83. break
  84. default:
  85. done()
  86. break
  87. }
  88. }
  89. },
  90. debug: WIKI.IS_DEBUG
  91. })
  92. Objection.Model.knex(this.knex)
  93. // Load DB Models
  94. const models = autoload(path.join(WIKI.SERVERPATH, 'models'))
  95. // Set init tasks
  96. let conAttempts = 0
  97. let initTasks = {
  98. // -> Migrate DB Schemas
  99. async syncSchemas() {
  100. return self.knex.migrate.latest({
  101. tableName: 'migrations',
  102. migrationSource
  103. })
  104. },
  105. // -> Attempt initial connection
  106. async connect() {
  107. try {
  108. WIKI.logger.info('Connecting to database...')
  109. await self.knex.raw('SELECT 1 + 1;')
  110. WIKI.logger.info('Database Connection Successful [ OK ]')
  111. } catch (err) {
  112. if (conAttempts < 10) {
  113. WIKI.logger.error(`Database Connection Error: ${err.code} ${err.address}:${err.port}`)
  114. WIKI.logger.warn(`Will retry in 3 seconds... [Attempt ${++conAttempts} of 10]`)
  115. await new Promise(resolve => setTimeout(resolve, 3000))
  116. await initTasks.connect()
  117. } else {
  118. throw err
  119. }
  120. }
  121. }
  122. }
  123. let initTasksQueue = (WIKI.IS_MASTER) ? [
  124. initTasks.connect,
  125. initTasks.syncSchemas
  126. ] : [
  127. () => { return Promise.resolve() }
  128. ]
  129. // Perform init tasks
  130. this.onReady = Promise.each(initTasksQueue, t => t()).return(true)
  131. return {
  132. ...this,
  133. ...models
  134. }
  135. }
  136. }