connection-manager.js 3.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. 'use strict';
  2. const AbstractConnectionManager = require('../abstract/connection-manager');
  3. const Promise = require('../../promise');
  4. const { logger } = require('../../utils/logger');
  5. const debug = logger.debugContext('connection:sqlite');
  6. const dataTypes = require('../../data-types').sqlite;
  7. const sequelizeErrors = require('../../errors');
  8. const parserStore = require('../parserStore')('sqlite');
  9. class ConnectionManager extends AbstractConnectionManager {
  10. constructor(dialect, sequelize) {
  11. super(dialect, sequelize);
  12. // We attempt to parse file location from a connection uri
  13. // but we shouldn't match sequelize default host.
  14. if (this.sequelize.options.host === 'localhost') {
  15. delete this.sequelize.options.host;
  16. }
  17. this.connections = {};
  18. this.lib = this._loadDialectModule('sqlite3').verbose();
  19. this.refreshTypeParser(dataTypes);
  20. }
  21. _onProcessExit() {
  22. const promises = Object.getOwnPropertyNames(this.connections)
  23. .map(connection => Promise.fromCallback(callback => this.connections[connection].close(callback)));
  24. return Promise
  25. .all(promises)
  26. .then(() => super._onProcessExit.call(this));
  27. }
  28. // Expose this as a method so that the parsing may be updated when the user has added additional, custom types
  29. _refreshTypeParser(dataType) {
  30. parserStore.refresh(dataType);
  31. }
  32. _clearTypeParser() {
  33. parserStore.clear();
  34. }
  35. getConnection(options) {
  36. options = options || {};
  37. options.uuid = options.uuid || 'default';
  38. options.inMemory = (this.sequelize.options.storage || this.sequelize.options.host || ':memory:') === ':memory:' ? 1 : 0;
  39. const dialectOptions = this.sequelize.options.dialectOptions;
  40. options.readWriteMode = dialectOptions && dialectOptions.mode;
  41. if (this.connections[options.inMemory || options.uuid]) {
  42. return Promise.resolve(this.connections[options.inMemory || options.uuid]);
  43. }
  44. return new Promise((resolve, reject) => {
  45. this.connections[options.inMemory || options.uuid] = new this.lib.Database(
  46. this.sequelize.options.storage || this.sequelize.options.host || ':memory:',
  47. options.readWriteMode || this.lib.OPEN_READWRITE | this.lib.OPEN_CREATE, // default mode
  48. err => {
  49. if (err) return reject(new sequelizeErrors.ConnectionError(err));
  50. debug(`connection acquired ${options.uuid}`);
  51. resolve(this.connections[options.inMemory || options.uuid]);
  52. }
  53. );
  54. }).tap(connection => {
  55. if (this.sequelize.config.password) {
  56. // Make it possible to define and use password for sqlite encryption plugin like sqlcipher
  57. connection.run(`PRAGMA KEY=${this.sequelize.escape(this.sequelize.config.password)}`);
  58. }
  59. if (this.sequelize.options.foreignKeys !== false) {
  60. // Make it possible to define and use foreign key constraints unless
  61. // explicitly disallowed. It's still opt-in per relation
  62. connection.run('PRAGMA FOREIGN_KEYS=ON');
  63. }
  64. });
  65. }
  66. releaseConnection(connection, force) {
  67. if (connection.filename === ':memory:' && force !== true) return;
  68. if (connection.uuid) {
  69. connection.close();
  70. debug(`connection released ${connection.uuid}`);
  71. delete this.connections[connection.uuid];
  72. }
  73. }
  74. }
  75. module.exports = ConnectionManager;
  76. module.exports.ConnectionManager = ConnectionManager;
  77. module.exports.default = ConnectionManager;