API Reference Source

lib/dialects/mariadb/connection-manager.js

  1. 'use strict';
  2.  
  3. const AbstractConnectionManager = require('../abstract/connection-manager');
  4. const SequelizeErrors = require('../../errors');
  5. const Promise = require('../../promise');
  6. const { logger } = require('../../utils/logger');
  7. const DataTypes = require('../../data-types').mariadb;
  8. const momentTz = require('moment-timezone');
  9. const debug = logger.debugContext('connection:mariadb');
  10. const parserStore = require('../parserStore')('mariadb');
  11.  
  12. /**
  13. * MariaDB Connection Manager
  14. *
  15. * Get connections, validate and disconnect them.
  16. * AbstractConnectionManager pooling use it to handle MariaDB specific connections
  17. * Use https://github.com/MariaDB/mariadb-connector-nodejs to connect with MariaDB server
  18. *
  19. * @extends AbstractConnectionManager
  20. * @returns Class<ConnectionManager>
  21. * @private
  22. */
  23.  
  24. class ConnectionManager extends AbstractConnectionManager {
  25. constructor(dialect, sequelize) {
  26. sequelize.config.port = sequelize.config.port || 3306;
  27. super(dialect, sequelize);
  28. this.lib = this._loadDialectModule('mariadb');
  29. this.refreshTypeParser(DataTypes);
  30. }
  31.  
  32. static _typecast(field, next) {
  33. if (parserStore.get(field.type)) {
  34. return parserStore.get(field.type)(field, this.sequelize.options, next);
  35. }
  36. return next();
  37. }
  38.  
  39. _refreshTypeParser(dataType) {
  40. parserStore.refresh(dataType);
  41. }
  42.  
  43. _clearTypeParser() {
  44. parserStore.clear();
  45. }
  46.  
  47. /**
  48. * Connect with MariaDB database based on config, Handle any errors in connection
  49. * Set the pool handlers on connection.error
  50. * Also set proper timezone once connection is connected.
  51. *
  52. * @param {Object} config
  53. * @returns {Promise<Connection>}
  54. * @private
  55. */
  56. connect(config) {
  57. // Named timezone is not supported in mariadb, convert to offset
  58. let tzOffset = this.sequelize.options.timezone;
  59. tzOffset = /\//.test(tzOffset) ? momentTz.tz(tzOffset).format('Z')
  60. : tzOffset;
  61.  
  62. const connectionConfig = {
  63. host: config.host,
  64. port: config.port,
  65. user: config.username,
  66. password: config.password,
  67. database: config.database,
  68. timezone: tzOffset,
  69. typeCast: ConnectionManager._typecast.bind(this),
  70. bigNumberStrings: false,
  71. supportBigNumbers: true,
  72. foundRows: false
  73. };
  74.  
  75. if (config.dialectOptions) {
  76. Object.assign(connectionConfig, config.dialectOptions);
  77. }
  78.  
  79. if (!this.sequelize.config.keepDefaultTimezone) {
  80. // set timezone for this connection
  81. if (connectionConfig.initSql) {
  82. if (!Array.isArray(
  83. connectionConfig.initSql)) {
  84. connectionConfig.initSql = [connectionConfig.initSql];
  85. }
  86. connectionConfig.initSql.push(`SET time_zone = '${tzOffset}'`);
  87. } else {
  88. connectionConfig.initSql = `SET time_zone = '${tzOffset}'`;
  89. }
  90. }
  91.  
  92. return this.lib.createConnection(connectionConfig)
  93. .then(connection => {
  94. this.sequelize.options.databaseVersion = connection.serverVersion();
  95. debug('connection acquired');
  96. connection.on('error', error => {
  97. switch (error.code) {
  98. case 'ESOCKET':
  99. case 'ECONNRESET':
  100. case 'EPIPE':
  101. case 'PROTOCOL_CONNECTION_LOST':
  102. this.pool.destroy(connection);
  103. }
  104. });
  105. return connection;
  106. })
  107. .catch(err => {
  108. switch (err.code) {
  109. case 'ECONNREFUSED':
  110. throw new SequelizeErrors.ConnectionRefusedError(err);
  111. case 'ER_ACCESS_DENIED_ERROR':
  112. case 'ER_ACCESS_DENIED_NO_PASSWORD_ERROR':
  113. throw new SequelizeErrors.AccessDeniedError(err);
  114. case 'ENOTFOUND':
  115. throw new SequelizeErrors.HostNotFoundError(err);
  116. case 'EHOSTUNREACH':
  117. case 'ENETUNREACH':
  118. case 'EADDRNOTAVAIL':
  119. throw new SequelizeErrors.HostNotReachableError(err);
  120. case 'EINVAL':
  121. throw new SequelizeErrors.InvalidConnectionError(err);
  122. default:
  123. throw new SequelizeErrors.ConnectionError(err);
  124. }
  125. });
  126. }
  127.  
  128. disconnect(connection) {
  129. // Don't disconnect connections with CLOSED state
  130. if (!connection.isValid()) {
  131. debug('connection tried to disconnect but was already at CLOSED state');
  132. return Promise.resolve();
  133. }
  134. //wrap native Promise into bluebird
  135. return Promise.resolve(connection.end());
  136. }
  137.  
  138. validate(connection) {
  139. return connection && connection.isValid();
  140. }
  141. }
  142.  
  143. module.exports = ConnectionManager;
  144. module.exports.ConnectionManager = ConnectionManager;
  145. module.exports.default = ConnectionManager;