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