[
  {
    "path": ".gitignore",
    "content": "# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n\n# Runtime data\npids\n*.pid\n*.seed\n*.pid.lock\n\n# Directory for instrumented libs generated by jscoverage/JSCover\nlib-cov\n\n# Coverage directory used by tools like istanbul\ncoverage\ntest-coverage\n\n# nyc test coverage\n.nyc_output\n\n# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)\n.grunt\n\n# Bower dependency directory (https://bower.io/)\nbower_components\n\n# node-waf configuration\n.lock-wscript\n\n# Compiled binary addons (http://nodejs.org/api/addons.html)\nbuild/Release\n\n# Dependency directories\nnode_modules/\njspm_packages/\n\n# Typescript v1 declaration files\ntypings/\n\n# Optional npm cache directory\n.npm\n\n# Optional eslint cache\n.eslintcache\n\n# Optional REPL history\n.node_repl_history\n\n# Output of 'npm pack'\n*.tgz\n\n# Yarn Integrity file\n.yarn-integrity\n\n# dotenv environment variables file\n.env\n\n# vscode history directory\n.history\n\n# npm5 package lock\npackage-lock.json\n\n# gh-pages doc dir on my local setup\ndoc\n"
  },
  {
    "path": ".istanbul.yml",
    "content": "instrumentation:\n  excludes: ['lib/multi-require.js', 'lib/class-utils.js']\n\nreporting:\n  dir: ./test-coverage"
  },
  {
    "path": ".npmignore",
    "content": ".*\n*\n!lib/*\n"
  },
  {
    "path": ".prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"es5\",\n  \"arrowParens\": \"always\"\n}\n"
  },
  {
    "path": ".travis.yml",
    "content": "# .travis.yml\nlanguage: node_js\n\nnode_js:\n  - '10'\n  - '12'\n  - '14'\n\ndist: trusty\n\nafter_script:\n  - npm run-script coveralls\n\nnotifications:\n  email: false\n\nsudo: required\n\nbefore_install:\n  - docker-compose up -d\n  - sh wait-databases.sh\n\ninstall:\n  - npm install\n  - npm install knex\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Changelog\n\n### 0.7.0\n\n- Dropped node 8 and added node 14 to tests and fixed 0.6.2 changes\n\n### 0.6.2\n\n- NOTE: THIS WAS DEPRECATED FROM NPM DUE TO SOME BREAKING TESTS\n- Set seeding to sequential instead of parallel #89\n- Support for old-style seeding modules #88\n\n### 0.6.1\n\n- Added more files to gitignore to make package smaller\n\n### 0.6.0\n\n- Fixed special character escaping in password for postgresql\n- Updated dependencies\n- Added prettier config\n- Added CI testing for node 12\n\n#### Breaking changes\n\n- Moved knex from normal deps to peerDep, so now one has to npm install knex explicitly\n\n### 0.5.0\n\n- Fixed id sequence queries to work on postgresql 10 databases even when\n- Updated dependencies\n- Removed gatsby and started to use vuepress for docs\n- Added CI testing for node 8 and 10\n\n### 0.4.0\n\n- Fix allowing to create new databases even when multiple clients are connected to postgres server #36\n- Updated list of supported dialect aliases #33\n- Fixed npm repo to point Vincit #31\n- Updated various dependencies\n- Initial support for mysql #13, #30\n\n#### Breaking changes\n\n- truncateDb doesn't automatically leave migration table out #10\n- Add owner privileges for the database user after creating new database as super user #15\n\n### 0.3.0\n\n- Added documentation pages\n\n#### Breaking changes\n\n- Removed automatic ingnore of migrations table from truncate DB\n- Removed automatic testing / support for node < 4\n\n### 0.2.0\n\n- Initial changelog entry\n\n#### Breaking changes\n\n- All functionality\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Installing development environment\n\nTDB\n\n# Running tests\n\nTDB\n"
  },
  {
    "path": "LICENSE",
    "content": "Copyright (c) 2015, Sami Koskimäki\nCopyright (c) 2016, Mikael Lepistö\n\nPermission to use, copy, modify, and/or distribute this software for any purpose \nwith or without fee is hereby granted, provided that the above copyright notice \nand this permission notice appear in all copies.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD \nTO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. \nIN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR \nCONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA \nOR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, \nARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n\n"
  },
  {
    "path": "README.md",
    "content": "[![Build Status](https://travis-ci.org/Vincit/knex-db-manager.svg?branch=master)](https://travis-ci.org/Vincit/knex-db-manager)\n[![Coverage Status](https://coveralls.io/repos/github/Vincit/knex-db-manager/badge.svg?branch=master)](https://coveralls.io/github/Vincit/knex-db-manager?branch=master)\n[![Greenkeeper badge](https://badges.greenkeeper.io/Vincit/knex-db-manager.svg)](https://greenkeeper.io/)\n\nPretty useful when writing scripts to initialize database for fresh install or\ndropping / creating new database when running tests and for truncating database\nbetween tests.\n\nLibrary uses knex connection for non administrative queries, but also creates\npriviliged connection directly with driver with superuser privileges for creating\nand dropping databases / roles.\n\n## Supported Databases\n\n- PostgreSQL\n- MySQL\n- SQLite3 (partial support even though most of the functions won't make sense with this)\n- ~~Oracle DB Express (TBD)~~\n- ~~MSSQL (TBD if we can get integration tests to run automatically)~~\n\n## Install\n\nYou need to install `knex`, database driver and `knex-db-manager`\n\n```\nnpm install knex-db-manager knex pg pg-escape\n```\n\n## API & Usage\n\nDatabase manager is initialized with normal `knex` configuration and with\nsuperuser account which should be able to create / drop roles and databases.\n\n> Initialization:\n\n```js\nlet config = {\n  knex: {\n    // just the usual knex configuration\n    client: 'postgres',\n    connection: {\n      host: 'localhost',\n      database: 'appdb',\n      user: 'dbowneruser',\n      password: 'dbownerpassword',\n    },\n    pool: {\n      min: 0,\n      max: 10,\n    },\n    migrations: {\n      directory: __dirname + '/migrations',\n    },\n  },\n  dbManager: {\n    // db manager related configuration\n    collate: ['fi_FI.UTF-8', 'Finnish_Finland.1252'],\n    superUser: 'userwithrightstocreateusersanddatabases',\n    superPassword: 'privilegeduserpassword',\n    populatePathPattern: 'data/**/*.js', // glob format for searching seeds\n  },\n};\n\nlet dbManager = require('knex-db-manager').databaseManagerFactory(config);\n```\n\n### `createDbOwnerIfNotExist(): Promise<void>`\n\nCreates the user, which is described in `knex` configuration. This user is used as\nthe database owner when creating new databases.\n\n```js\nlet promise = dbManager.createDbOwnerIfNotExist();\n```\n\n### `createDb(dbName?: string): Promise<void>`\n\nCreates database described in `knex` configuration or by given name. Owner of the\ncreated database is set to be the `config.knex.connection.user`.\n\n`dbName` is the name of the database to be created, if not given the name is read\nfrom `config.knex.connection.database`.\n\n> Read database from `config.knex.connection.database`:\n\n```js\nlet promise = dbManager.createDb();\n```\n\n> By given name:\n\n```js\nlet promise = dbManager.createDb('brave-new-db');\n```\n\n### `dropDb(dbName?: string): Promise<void>`\n\nDrops database described in `knex` configuration or by given name. Note\nthat if there are any active connections to the database that is being\ndropped, the drop command might fail.\n\n`dbName` is the name of the database to be dropped, if not given the name\nis read from `config.knex.connection.database`.\n\n> Drop database `config.knex.connection.database`:\n\n```js\nlet promise = dbManager.dropDb();\n```\n\n> By specific name:\n\n```js\nlet promise = dbManager.dropDb('brave-new-db');\n```\n\n### `copyDb(fromDbName: string, toDbName: string): Promise<void>`\n\nClones database to another name remotely on db serverside (may be useful e.g.\nto make backup before running migrations).\n\nNew database `toDatabaseName` will be created containing a copy of `fromDbName`.\n\nNote: This method is not supported with MySQL (yet).\n\n> Making copy of DB:\n\n```js\nlet promise = dbManager.copyDb('brave-new-db', 'brave-new-db-copy');\n```\n\n### `truncateDb(ignoreTables?: string[]): Promise<void>`\n\nTruncate tables of the database and reset corresponding id sequences.\n\n`ignoreTables` list of tables names which should not be truncated.\n\n> Truncate database `config.knex.connection.database`:\n\n```js\nlet promise = dbManager.truncateDb();\n```\n\n> ignore certain tables:\n\n```js\nlet promise = dbManager.truncateDb(['migrations']);\n```\n\n### `updateIdSequences(): Promise<void>`\n\nUpdates all primary key id sequences to be biggest id in table + 1.\nSo after running this next `INSERT` to table will get valid id for\nthe row from the sequence.\n\nThis was motivated by some people who liked to create test data with\nhard coded ids, so this helps them to make app to work normally after\nadding rows to tables, which has not used id sequence to get ids.\n\nThe function assumes that the primary key for each table is called `id`.\n\nNote: This method is not supported with MySQL (yet).\n\n> Reset sequence of database `config.knex.connection.database`:\n\n```js\nlet promise = dbManager.updateIdSequences();\n```\n\n### `populateDb(glob: string): Promise<void>`\n\nFinds `knex` seed files by pattern and populate database with them.\n\n`glob` is a pattern to match files to be ran, if not given the name is\nread from `config.dbManager.populatePathPattern`.\n\n> Get database from `config.knex.connection.database` and pattern\n> from `config.dbManager.populatePathPattern`:\n\n```js\nlet promise = dbManager.populateDb();\n```\n\n> with pattern:\n\n```js\nlet promise = dbManager.populateDb(path.join(__dirname, 'seeds', 'test-*'));\n```\n\n### `migrateDb(): Promise<void>`\n\nRuns `knex` migrations configured in knex config.\n\n> Get database from `config.knex.connection.database`:\n\n```js\nlet promise = dbManager.migrateDb();\n```\n\n### `dbVersion(): Promise<string>`\n\nChecks which migrations has been ran to database.\n\nExpects that migration name starts with timestamp.\n\nIf no migrations has been run, promise resolves to `'none'`. Otherwise\nresolves to first numbers of latest migration file ran e.g. for\n`20141024070315_test_schema.js` version will be `'20141024070315'`.\n\n> Get database from `config.knex.connection.database`:\n\n```js\nlet promise = dbManager.dbVersion();\n```\n\n### `close(): Promise<void>`\n\nCloses the single privileged connection and all normal knex connections.\n\n> Kill database connection:\n\n```js\nlet promise = dbManager.close();\n```\n\n### `closeKnex(): Promise<void>`\n\nCloses knex connection which is made to the database for unprivileged\nqueries. Sometimes this is needed e.g. for being able to drop database.\n\n> Close knex connection\n\n```js\nlet promise = dbManager.closeKnex();\n```\n\n### `knexInstance(): QueryBuilder`\n\nReturns `knex` query builder bound to configured database.\n\n> Get database from `config.knex.connection.database`:\n\n```js\nlet knex = dbManager.knexInstance();\nknex('table')\n  .where('id', 1)\n  .then((rows) => {\n    console.log('Query was ran with db owner privileges', rows);\n  });\n```\n"
  },
  {
    "path": "docker-compose.yml",
    "content": "version: '3'\n\nservices:\n  mysql:\n    image: mysql:5.7\n    ports:\n      - '13306:3306'\n    environment:\n      - TZ=UTC\n      - MYSQL_ROOT_PASSWORD=mysqlrootpassword\n  postgresql:\n    image: mdillon/postgis:9.6\n    ports:\n      - '15432:5432'\n    environment:\n      - POSTGRES_PASSWORD=po\"st#gr%e!sr:oo;tpa@ss%word\n      - POSTGRES_USER=postgres\n  postgresql10:\n    image: mdillon/postgis:10\n    ports:\n      - '25432:5432'\n    environment:\n      - POSTGRES_PASSWORD=po\"st#gr%e!sr:oo;tpa@ss%word\n      - POSTGRES_USER=postgres\n#  mssql:\n#    image: microsoft/mssql-server-linux\n#    ports:\n#      - \"11433:1433\"\n#    environment:\n#      - ACCEPT_EULA=Y\n#      - SA_PASSWORD=mssqlpassword\n# Actually its better to install oracle directly on host to be\n# able to compile node-oracledb to connect the DB\n#  oracledbxe:\n#    image: wnameless/oracle-xe-11g\n#    ports:\n#      - \"11521:1521\"\n#    environment:\n#      - ORACLE_ALLOW_REMOTE=true\n"
  },
  {
    "path": "lib/DatabaseManager.js",
    "content": "var _ = require('lodash'),\n  Knex = require('knex'),\n  Promise = require('bluebird'),\n  multiRequire = require('./multi-require').multiRequire;\n\n/**\n * Base class for database managers.\n *\n * Database manager is used to create/drop databases, run migrations for them and doing other \"super user\" stuff.\n *\n * @constructor\n * @param {object} config\n *    Database configuration. See `index.js` for example config and `database` feature for further description.\n */\nfunction DatabaseManager(config) {\n  this.config = config;\n  this._knex = null;\n}\n\n/**\n * Creates user which is used to access the database described in knex configuration.\n *\n * @returns {Promise} Resolves if success reject if user could not be created for some reason.\n */\nDatabaseManager.prototype.createDbOwnerIfNotExist = function() {\n  throw new Error(this.constructor.name + '.createDbOwner not implemented');\n};\n\n/**\n * Creates and initializes a database `databaseName`.\n *\n * Rejects promise if databaseName already exists or could not\n * be created.\n *\n * @param {String=} databaseName if not given, database from knex config is used\n * @returns {Promise}\n */\nDatabaseManager.prototype.createDb = function(databaseName) {\n  throw new Error(this.constructor.name + '.initDb not implemented');\n};\n\n/**\n * Drops the database `databaseName`.\n *\n * @param {String=} databaseName\n * @returns {Promise}\n */\nDatabaseManager.prototype.dropDb = function(databaseName) {\n  throw new Error(this.constructor.name + '.dropDb not implemented');\n};\n\n/**\n * Makes copy of database.\n *\n * Good for backing up stuff before running migrations etc.\n *\n * @param {String} fromDatabaseName\n * @param {String} toDatabaseName\n * @returns {Promise}\n */\nDatabaseManager.prototype.copyDb = function(fromDatabaseName, toDatabaseName) {\n  throw new Error(this.constructor.name + '.copyDb not implemented');\n};\n\n/**\n * Truncates all tables in the database from knex configuration and also resets all\n * sequences.\n *\n * @returns {Promise}\n */\nDatabaseManager.prototype.truncateDb = function(ignoreTables) {\n  throw new Error(this.constructor.name + '.truncateDb not implemented');\n};\n\n/**\n * Updates the primary key sequences for all tables so that next insert selects\n * correct id (one that does not conflict with previous ids and is valid).\n *\n * This means that the next id will be greater (by 1) than currently largest\n * id in the table. If the table is empty, minimum value for the key sequence\n * will be used instead.\n *\n * This function assumes that the primary key for each table is called `id`.\n *\n * @returns {Promise}\n */\nDatabaseManager.prototype.updateIdSequences = function() {\n  throw new Error(this.constructor.name + '.updateIdSequences not implemented');\n};\n\n/**\n * Populate database.\n *\n * @param {String=} populatePathPattern\n * @returns {Promise}\n */\nDatabaseManager.prototype.populateDb = function(populatePathPattern) {\n  populatePathPattern = populatePathPattern || this.config.dbManager.populatePathPattern;\n\n  var knex = this.knexInstance();\n  var modules = multiRequire(populatePathPattern)\n    .filterModule(function(module) {\n      return _.isFunction(module) || (module && _.isFunction(module.seed))\n    })\n    .require();\n\n  return _.reduce(modules, function(res, module) {\n    return res.then(function() {\n      return knex.transaction(function(trx) {\n        if (_.isFunction(module.module)) {\n          return module.module(trx);\n        } else if (module.module && _.isFunction(module.module.seed)) {\n          return module.module.seed(trx);\n        }\n      });\n    });\n  }, Promise.resolve());\n};\n\n/**\n * Runs migrations for database in knex config.\n *\n * @returns {Promise}\n */\nDatabaseManager.prototype.migrateDb = function() {\n  var knex = this.knexInstance();\n  return knex.migrate.latest();\n};\n\n/**\n * Gets the migration version of the database of knex config.\n *\n * If no migrations run returns 'none'\n * Otherwise returns first numbers of latest migration file ran\n * e.g. for 20141024070315_test_schema.js version will be\n * '20141024070315'\n *\n * @returns {Promise}\n */\nDatabaseManager.prototype.dbVersion = function() {\n  var knex = this.knexInstance();\n  return knex.migrate.currentVersion();\n};\n\n/**\n * Closes all connections made by the the manager.\n *\n * @returns {Promise}\n */\nDatabaseManager.prototype.close = function() {\n  throw new Error(this.constructor.name + '.close not implemented');\n};\n\n/**\n * Closes connection made with knex directly to certain database\n */\nDatabaseManager.prototype.closeKnex = function() {\n  if (this._knex) {\n    knex = this._knex;\n    this._knex = null;\n    return knex.destroy();\n  }\n  return Promise.resolve();\n};\n\n/**\n * @return {QueryBuilder} Knex query builder for knex configuration.\n */\nDatabaseManager.prototype.knexInstance = function() {\n  if (!this._knex) {\n    this._knex = Knex(this.config.knex);\n  }\n  return this._knex;\n};\n\nmodule.exports = {\n  default: DatabaseManager,\n  DatabaseManager: DatabaseManager,\n};\n"
  },
  {
    "path": "lib/MySqlDatabaseManager.js",
    "content": "var DatabaseManager = require('./DatabaseManager').default,\n  classUtils = require('./class-utils'),\n  mysql = require('mysql'),\n  Promise = require('bluebird'),\n  _ = require('lodash');\n\n/**\n * @constructor\n * @extends DatabaseManager\n *\n * Notes:\n *   - Even though the method signature implicates that _masterConnectionUrl returns\n *     an URL string, it actually returns an object because MySQL node lib\n *     assumes that the database name is defined in the URL format.\n *\n */\nfunction MySqlDatabaseManager() {\n  DatabaseManager.apply(this, arguments);\n  this._masterClient = null;\n  this._cachedTableNames = null;\n}\n\nclassUtils.inherits(MySqlDatabaseManager, DatabaseManager);\n\n/**\n * @Override\n */\nMySqlDatabaseManager.prototype.createDbOwnerIfNotExist = function() {\n  return this._masterQuery(\"CREATE USER IF NOT EXISTS ?@'%' IDENTIFIED BY ?\", [\n    this.config.knex.connection.user,\n    this.config.knex.connection.password,\n  ]);\n};\n\n/**\n * @Override\n */\nMySqlDatabaseManager.prototype.createDb = function(databaseName) {\n  databaseName = databaseName || this.config.knex.connection.database;\n  var collate = this.config.dbManager.collate;\n  var owner = this.config.knex.connection.user;\n  var self = this;\n  var promise = Promise.reject(new Error());\n\n  if (_.isEmpty(collate)) {\n    promise = promise.catch(function() {\n      return self._masterQuery(\n        'CREATE DATABASE ?? DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci',\n        [databaseName]\n      );\n    });\n  } else {\n    // Try to create with each collate. Use the first one that works. This is kind of a hack\n    // but seems to be the only reliable way to make this work with both windows and unix.\n    _.each(collate, function(locale) {\n      promise = promise.catch(function() {\n        return self._masterQuery(\n          'CREATE DATABASE ?? DEFAULT CHARACTER SET utf8 DEFAULT COLLATE ?',\n          [databaseName, locale]\n        );\n      });\n    });\n  }\n\n  promise = promise.then(function() {\n    return self._masterQuery('GRANT ALL PRIVILEGES ON ??.* TO ??', [\n      databaseName,\n      owner,\n    ]);\n  });\n\n  return promise;\n};\n\n/**\n * Drops database with name if db exists.\n *\n * @Override\n */\nMySqlDatabaseManager.prototype.dropDb = function(databaseName) {\n  databaseName = databaseName || this.config.knex.connection.database;\n  return this._masterQuery('DROP DATABASE IF EXISTS ??', [databaseName]);\n};\n\n/**\n * @Override\n */\nMySqlDatabaseManager.prototype.truncateDb = function(ignoreTables) {\n  var knex = this.knexInstance();\n  var config = this.config;\n\n  if (!this._cachedTableNames) {\n    this._updateTableNameCache(knex, config);\n  }\n\n  return this._cachedTableNames.then(function(tableNames) {\n    if (!_.isEmpty(tableNames)) {\n      return knex.transaction(function(trx) {\n        return knex\n          .raw('SET FOREIGN_KEY_CHECKS = 0')\n          .transacting(trx)\n          .then(function() {\n            // ignore the tables based on `ignoreTables`\n            var filteredTables = _.differenceWith(\n              tableNames,\n              ignoreTables,\n              _.isEqual\n            );\n            return Promise.map(\n              filteredTables,\n              function(tableName) {\n                return knex\n                  .table(tableName)\n                  .truncate()\n                  .transacting(trx);\n              },\n              { concurrency: 1 }\n            );\n          });\n      });\n    }\n  });\n};\n\n/**\n * @private\n */\nMySqlDatabaseManager.prototype._updateTableNameCache = function(knex, config) {\n  this._cachedTableNames = knex('information_schema.tables')\n    .select('table_name')\n    .where('table_schema', config.knex.connection.database)\n    .then(function(tables) {\n      return _.without(\n        _.map(tables, 'table_name'),\n        config.knex.migrations.tableName\n      );\n    });\n};\n\n/**\n * @Override\n */\nMySqlDatabaseManager.prototype.close = function() {\n  var disconnectAll = [this.closeKnex()];\n  if (this._masterClient) {\n    disconnectAll.push(\n      this._masterClient.then(function(client) {\n        client.end();\n      })\n    );\n    this._masterClient = null;\n  }\n  return Promise.all(disconnectAll);\n};\n\n/**\n * @private\n * @returns {Promise}\n */\nMySqlDatabaseManager.prototype._masterQuery = function(query, params) {\n  var self = this;\n  if (!this._masterClient) {\n    this._masterClient = this.create_masterClient();\n  }\n  return this._masterClient.then(function(client) {\n    return self.perform_masterQuery(client, query, params);\n  });\n};\n\n/**\n * @private\n * @returns {Promise}\n */\nMySqlDatabaseManager.prototype.create_masterClient = function() {\n  var self = this;\n  return new Promise(function(resolve, reject) {\n    var client = mysql.createConnection(self._masterConnectionUrl());\n    client.connect(function(err) {\n      if (err) {\n        reject(err);\n      } else {\n        resolve(client);\n      }\n    });\n  });\n};\n\n/**\n * @private\n * @returns {Promise}\n */\nMySqlDatabaseManager.prototype.perform_masterQuery = function(\n  client,\n  query,\n  params\n) {\n  return new Promise(function(resolve, reject) {\n    if (params) {\n      query = mysql.format(query, params);\n    }\n    client.query(query, function(err, result) {\n      if (err) {\n        reject(err);\n      } else {\n        resolve(result);\n      }\n    });\n  });\n};\n\n/**\n * @private\n * @returns {String}\n */\nMySqlDatabaseManager.prototype._masterConnectionUrl = function() {\n  return {\n    host: this.config.knex.connection.host,\n    port: this.config.knex.connection.port || 3306,\n    user: this.config.dbManager.superUser,\n    password: this.config.dbManager.superPassword,\n  };\n};\n\nmodule.exports = {\n  default: MySqlDatabaseManager,\n  MySqlDatabaseManager: MySqlDatabaseManager,\n};\n"
  },
  {
    "path": "lib/PostgresDatabaseManager.js",
    "content": "var _ = require('lodash'),\n  pg = require('pg'),\n  escape = require('pg-escape'),\n  Promise = require('bluebird'),\n  classUtils = require('./class-utils'),\n  DatabaseManager = require('./DatabaseManager').default;\n\n/**\n * @constructor\n */\nfunction PostgresDatabaseManager() {\n  DatabaseManager.apply(this, arguments);\n  this._masterClient = null;\n  this._cachedTableNames = null;\n  this._cachedIdSequences = null;\n}\n\nclassUtils.inherits(PostgresDatabaseManager, DatabaseManager);\n\n/**\n * @Override\n */\nPostgresDatabaseManager.prototype.createDbOwnerIfNotExist = function() {\n  return this._masterQuery(\n    \"DO $body$ BEGIN CREATE ROLE %I LOGIN PASSWORD %L; EXCEPTION WHEN others THEN RAISE NOTICE 'User exists, not re-creating'; END $body$;\",\n    [this.config.knex.connection.user, this.config.knex.connection.password]\n  );\n};\n\n/**\n * @Override\n */\nPostgresDatabaseManager.prototype.createDb = function(databaseName) {\n  databaseName = databaseName || this.config.knex.connection.database;\n  var collate = this.config.dbManager.collate;\n  var owner = this.config.knex.connection.user;\n  var self = this;\n  var promise = Promise.reject(new Error());\n\n  if (_.isEmpty(collate)) {\n    promise = promise.catch(function() {\n      return self._masterQuery(\n        \"CREATE DATABASE %I OWNER = '%I' ENCODING = 'UTF-8' TEMPLATE template1\",\n        [databaseName, owner]\n      );\n    });\n  } else {\n    // Try to create with each collate. Use the first one that works. This is kind of a hack\n    // but seems to be the only reliable way to make this work with both windows and unix.\n    _.each(collate, function(locale) {\n      promise = promise.catch(function() {\n        return self._masterQuery(\n          \"CREATE DATABASE %I OWNER = '%I' ENCODING = 'UTF-8' LC_COLLATE = %L TEMPLATE template0\",\n          [databaseName, owner, locale]\n        );\n      });\n    });\n  }\n\n  return promise;\n};\n\n/**\n * Drops database with name if db exists.\n *\n * @Override\n */\nPostgresDatabaseManager.prototype.dropDb = function(databaseName) {\n  var self = this;\n  databaseName = databaseName || this.config.knex.connection.database;\n  return this.closeKnex().then(function() {\n    return self._masterQuery('DROP DATABASE IF EXISTS %I', [databaseName]);\n  });\n};\n\n/**\n * @Override\n */\nPostgresDatabaseManager.prototype.copyDb = function(\n  fromDatabaseName,\n  toDatabaseName\n) {\n  var self = this;\n  return this.closeKnex().then(function() {\n    return self._masterQuery('CREATE DATABASE %I template %I', [\n      toDatabaseName,\n      fromDatabaseName,\n    ]);\n  });\n};\n\n/**\n * @Override\n */\nPostgresDatabaseManager.prototype.truncateDb = function(ignoreTables) {\n  var knex = this.knexInstance();\n  var config = this.config;\n\n  if (!this._cachedTableNames) {\n    this._updateTableNameCache(knex, config);\n  }\n\n  return this._cachedTableNames.then(function(tableNames) {\n    var filteredTableNames = _.filter(tableNames, function(tableName) {\n      return !_.includes(ignoreTables || [], tableName);\n    });\n    if (!_.isEmpty(filteredTableNames)) {\n      return knex.raw(\n        'TRUNCATE TABLE \"' +\n          filteredTableNames.join('\",\"') +\n          '\" RESTART IDENTITY'\n      );\n    }\n  });\n};\n\n/**\n * @Override\n */\nPostgresDatabaseManager.prototype.updateIdSequences = function() {\n  var knex = this.knexInstance();\n  var config = this.config;\n\n  if (!this._cachedIdSequences) {\n    this._updateIdSequenceCache(knex, config);\n  }\n\n  // Set current value of id sequence for each table.\n  // If there are no rows in the table, the value will be set to sequence's minimum constraint.\n  // Otherwise, it will be set to max(id) + 1.\n  return this._cachedIdSequences.then(function(result) {\n    var query = _.map(result.rows, function(row) {\n      return escape(\n        'SELECT setval(\\'\"%s\"\\', GREATEST(coalesce(max(id),0) + 1, \\'%s\\'), false) FROM \"%I\"',\n        row.sequence,\n        row.min,\n        row.table\n      );\n    });\n\n    query = query.join(' UNION ALL ') + ';';\n    return knex.raw(query);\n  });\n};\n\n/**\n * @private\n */\nPostgresDatabaseManager.prototype._updateTableNameCache = function(\n  knex,\n  config\n) {\n  this._cachedTableNames = knex('pg_tables')\n    .select('tablename')\n    .where('schemaname', 'public')\n    .then(function(tables) {\n      return _.map(tables, 'tablename');\n    });\n};\n\n/**\n * Id sequence cache holds a Promise, that returns following objects:\n * {\n *   table: String, // Table that rest of the values target\n *   sequence: String, // Sequence for the primary key (which is assumed to be id)\n *   min: String // Minimum allowed value for the sequence\n * }\n *\n * These values are cached because they are not expected to change often,\n * and finding them is slow.\n *\n * @private\n */\nPostgresDatabaseManager.prototype._updateIdSequenceCache = function(\n  knex,\n  config\n) {\n  if (!this._cachedTableNames) {\n    this._updateTableNameCache(knex, config);\n  }\n\n  this._cachedIdSequences = this._cachedTableNames\n    .then(function(tableNames) {\n      // Skip tables without id column.\n      return knex('information_schema.columns')\n        .select('table_name')\n        .where('column_name', 'id')\n        .then(function(tables) {\n          return _.intersection(_.map(tables, 'table_name'), tableNames);\n        });\n      // Find name of the id sequence for each table.\n      // This is required for searching the minimum constraint for the sequence.\n    })\n    .then(function(idTableNames) {\n      var query = _.map(idTableNames, function(tableName) {\n        return escape(\n          \"SELECT '%I' AS table, substring(pg_get_serial_sequence('\\\"%I\\\"', 'id') from '\\\"\\\\?([^\\\".]+)\\\"\\\\?$') AS sequence, substring(pg_get_serial_sequence('\\\"%I\\\"', 'id') from '^\\\"\\\\?([^\\\".]+)\\\"\\\\?.') AS schema\",\n          tableName,\n          tableName,\n          tableName\n        );\n      });\n\n      query = query.join(' UNION ALL ') + ';';\n      return knex.raw(query);\n      // Find min constraint for each of the id sequences.\n    })\n    .then(function(result) {\n      var query = _.map(result.rows, function(row) {\n        return escape(\n          \"SELECT '%I' AS table, '%s' AS sequence, minimum_value AS min FROM information_schema.sequences where sequence_name = '%s' and sequence_schema = '%s'\",\n          row.table,\n          row.sequence,\n          row.sequence,\n          row.schema\n        );\n      });\n\n      query = query.join(' UNION ALL ') + ';';\n      return knex.raw(query);\n    });\n};\n\n/**\n * @Override\n */\nPostgresDatabaseManager.prototype.close = function() {\n  var disconnectAll = [this.closeKnex()];\n  if (this._masterClient) {\n    disconnectAll.push(\n      this._masterClient.then(function(client) {\n        client.end();\n      })\n    );\n    this._masterClient = null;\n  }\n  return Promise.all(disconnectAll);\n};\n\n/**\n * @private\n * @returns {Promise}\n */\nPostgresDatabaseManager.prototype._masterQuery = function(query, params) {\n  var self = this;\n  if (!this._masterClient) {\n    this._masterClient = this.create_masterClient();\n  }\n  return this._masterClient.then(function(client) {\n    return self.perform_masterQuery(client, query, params);\n  });\n};\n\n/**\n * @private\n * @returns {Promise}\n */\nPostgresDatabaseManager.prototype.create_masterClient = function() {\n  var self = this;\n  return new Promise(function(resolve, reject) {\n    var client = new pg.Client({\n      connectionString: self._masterConnectionUrl(),\n    });\n\n    client.connect(function(err) {\n      if (err) {\n        reject(err);\n      } else {\n        resolve(client);\n      }\n    });\n  });\n};\n\n/**\n * @private\n * @returns {Promise}\n */\nPostgresDatabaseManager.prototype.perform_masterQuery = function(\n  client,\n  query,\n  params\n) {\n  return new Promise(function(resolve, reject) {\n    if (params) {\n      var args = [query].concat(params);\n      query = escape.apply(global, args);\n    }\n    client.query(query, function(err, result) {\n      if (err) {\n        reject(err);\n      } else {\n        resolve(result);\n      }\n    });\n  });\n};\n\n/**\n * @private\n * @returns {String}\n */\nPostgresDatabaseManager.prototype._masterConnectionUrl = function() {\n  var url = 'postgres://';\n  if (this.config.dbManager.superUser) {\n    url += this.config.dbManager.superUser;\n  } else {\n    throw new Error('DatabaseManager: database config must have `superUser`');\n  }\n  if (this.config.dbManager.superPassword) {\n    url +=\n      ':' +\n      encodeURIComponent(this.config.dbManager.superPassword).replace(\n        /!/g,\n        '%21'\n      );\n  }\n  var port = this.config.knex.connection.port || 5432;\n  url += '@' + this.config.knex.connection.host + ':' + port + '/postgres';\n\n  return url;\n};\n\nmodule.exports = {\n  default: PostgresDatabaseManager,\n  PostgresDatabaseManager: PostgresDatabaseManager,\n};\n"
  },
  {
    "path": "lib/SqliteDatabaseManager.js",
    "content": "var DatabaseManager = require('./DatabaseManager').default,\n  classUtils = require('./class-utils');\n\n/**\n * @constructor\n * @extends DatabaseManager\n */\nfunction SqliteDatabaseManager() {\n  DatabaseManager.apply(this, arguments);\n}\n\nclassUtils.inherits(SqliteDatabaseManager, DatabaseManager);\n\nmodule.exports = {\n  default: SqliteDatabaseManager,\n  SqliteDatabaseManager: SqliteDatabaseManager\n};\n"
  },
  {
    "path": "lib/class-utils.js",
    "content": "var _ = require('lodash'),\n  util = require('util');\n\n/**\n * Makes the `Constructor` inherit `SuperConstructor`.\n *\n * Calls node.js `util.inherits` but also copies the \"static\" properties from\n * `SuperConstructor` to `Constructor`.\n *\n * @param {function} Constructor\n * @param {function} SuperConstructor\n */\nmodule.exports.inherits = function(Constructor, SuperConstructor) {\n  var keys = Object.keys(SuperConstructor);\n  for (var i = 0, l = keys.length; i < l; ++i) {\n    var key = keys[i];\n    Constructor[key] = SuperConstructor[key];\n  }\n  util.inherits(Constructor, SuperConstructor);\n  Constructor.super_ = SuperConstructor;\n};\n\n/**\n * Tests if a constructor function inherits another constructor function.\n *\n * @ignore\n * @param {Object} Constructor\n * @param {Object} SuperConstructor\n * @returns {boolean}\n */\nmodule.exports.isSubclassOf = function(Constructor, SuperConstructor) {\n  if (!_.isFunction(SuperConstructor)) {\n    return false;\n  }\n\n  while (_.isFunction(Constructor)) {\n    if (Constructor === SuperConstructor) return true;\n    var proto = Constructor.prototype.__proto__;\n    Constructor = proto && proto.constructor;\n  }\n\n  return false;\n};\n"
  },
  {
    "path": "lib/index.js",
    "content": "/**\n * Configuration is dodo-objection configuration.\n *\n * @param config Dodo-objection configuration.\n * @return {DatabaseManager}\n */\nmodule.exports = {\n  databaseManagerFactory: function databaseManagerFactory(config) {\n    // Prevent people from invoking this as a constructor.\n    if (this instanceof databaseManagerFactory) {\n      throw new Error('this is not a constructor');\n    }\n\n    switch (config.knex.client) {\n      case 'pg':\n      case 'postgresql':\n      case 'postgres': {\n        var PostgresDatabaseManager = require('./PostgresDatabaseManager')\n          .default;\n        return new PostgresDatabaseManager(config);\n      }\n      case 'maria':\n      case 'mariadb':\n      case 'mariasql':\n      case 'mysql': {\n        var MySqlDatabaseManager = require('./MySqlDatabaseManager').default;\n        return new MySqlDatabaseManager(config);\n      }\n      case 'sqlite3':\n      case 'sqlite': {\n        var SqliteDatabaseManager = require('./SqliteDatabaseManager').default;\n        return new SqliteDatabaseManager(config);\n      }\n      default:\n        throw new Error(\n          config.knex.client +\n            ' is not supported. Supported clients currently: postgres, mysql and sqlite'\n        );\n    }\n  },\n};\n"
  },
  {
    "path": "lib/multi-require.js",
    "content": "var _ = require('lodash'),\n  fs = require('fs'),\n  path = require('path'),\n  glob = require('glob');\n\n/**\n * Requires multiple modules from the given path pattern.\n *\n * The path pattern can be anything the node-glob library supports.\n *\n * ```js\n * var modules = multiRequire('some/path/**.js')\n *   .filterModule(_.isFunction)\n *   .require();\n * ```\n *\n * @param {String} pathPattern\n * @returns {MultiRequire}\n */\nmodule.exports.multiRequire = function(pathPattern) {\n  return new MultiRequire(pathPattern);\n};\n\n/**\n * @param {*} module\n * @param {String} filePath\n * @param {String} fileName\n * @param {String} fileExt\n * @constructor\n */\nfunction RequireResult(module, filePath, fileName, fileExt) {\n  this.module = module;\n  this.filePath = filePath;\n  this.fileName = fileName;\n  this.fileExt = fileExt;\n}\n\n/**\n * @param {String} pathPattern\n * @constructor\n */\nfunction MultiRequire(pathPattern) {\n  this.pathPattern_ = pathPattern;\n  this.folderModules_ = true;\n  this.filters_ = [];\n  this.moduleFilters_ = [];\n}\n\n/**\n * Are folders that contain an `index.js` file considered as single modules.\n *\n * Default is true.\n *\n * @param {Boolean} folderModules\n * @returns {MultiRequire}\n */\nMultiRequire.prototype.folderModules = function(folderModules) {\n  this.folderModules_ = folderModules;\n  return this;\n};\n\n/**\n * Filters the result by requiring the modules to have a certain property.\n *\n * Example:\n *\n * ```js\n * multiRequire(path)\n *   .hasProperty('prop1')\n *   .hasProperty(['prop2', 'prop3'])\n *   .hasProperty('prop4', 'prop5', 'prop6')\n *   .require();\n * ```\n *\n * @param {String|Array.<String>} property\n * @returns {MultiRequire}\n */\nMultiRequire.prototype.hasProperty = function(property) {\n  if (arguments.length > 1 || _.isArray(property)) {\n    var array = arguments.length > 1 ? arguments : property;\n    for (var i = 0; i < array.length; ++i) {\n      this.hasProperty(array[i]);\n    }\n  } else {\n    this.filterModule(function(module) {\n      return _.has(module, property);\n    });\n  }\n  return this;\n};\n\n/**\n * Adds a filter function.\n *\n * @param {function(RequireResult):Boolean} filter\n * @param {*=} context\n * @returns {MultiRequire}\n */\nMultiRequire.prototype.filter = function(filter, context) {\n  this.filters_.push({ func: filter, context: context });\n  return this;\n};\n\n/**\n * Adds a filter function that is passed the module instead of a `RequireResult`.\n *\n * @param {function(*):Boolean} filter\n * @param {*=} context\n * @returns {MultiRequire}\n */\nMultiRequire.prototype.filterModule = function(filter, context) {\n  this.moduleFilters_.push({ func: filter, context: context });\n  return this;\n};\n\n/**\n * Synchronously requires all modules that pass the filters.\n *\n * @param {function(RequireResult)=} callback\n * @returns {Array.<RequireResult>}\n */\nMultiRequire.prototype.require = function(callback) {\n  return this.doRequire_(callback);\n};\n\n/**\n * @param {function(RequireResult)=} callback\n * @returns {Array.<RequireResult>}\n * @private\n */\nMultiRequire.prototype.doRequire_ = function(callback) {\n  var files,\n    modules = [],\n    folderModules = [],\n    includeFolderModules = this.folderModules_,\n    filters = this.filters_,\n    moduleFilters = this.moduleFilters_;\n\n  files = glob.sync(this.pathPattern_);\n\n  _.each(files, function(filePath) {\n    var fileExt = path.extname(filePath),\n      fileName = path.basename(filePath, fileExt),\n      isDir = fs.statSync(filePath).isDirectory(),\n      hasIndex = isDir && fs.existsSync(path.join(filePath, 'index.js')),\n      insideFolderModule;\n\n    insideFolderModule = _.some(folderModules, function(folderModule) {\n      return filePath.indexOf(folderModule.filePath) == 0;\n    });\n\n    // filePath is inside a folder module that was already required. Skip it.\n    if (insideFolderModule) {\n      return;\n    }\n\n    if (!isDir || (isDir && includeFolderModules && hasIndex)) {\n      var module = require(filePath);\n      var result = new RequireResult(module, filePath, fileName, fileExt);\n\n      var filtersPass = _.every(filters, function(filter) {\n        return filter.func.call(filter.context, result);\n      });\n\n      var moduleFiltersPass = _.every(moduleFilters, function(filter) {\n        return filter.func.call(filter.context, result.module);\n      });\n\n      if (filtersPass && moduleFiltersPass) {\n        modules.push(result);\n\n        if (isDir) {\n          folderModules.push(result);\n        }\n\n        if (callback) {\n          callback(result);\n        }\n      }\n    }\n  });\n\n  return modules;\n};\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"knex-db-manager\",\n  \"version\": \"0.7.0\",\n  \"description\": \"Collection of administrative database operations for knex supported databases\",\n  \"main\": \"lib/index.js\",\n  \"scripts\": {\n    \"test\": \"node_modules/.bin/istanbul --config=.istanbul.yml cover _mocha -- --slow 10 --timeout 10000 --reporter spec --recursive tests\",\n    \"test-no-coverage\": \"node_modules/.bin/mocha --slow 10 --timeout 10000 --reporter spec --recursive tests\",\n    \"coveralls\": \"cat ./test-coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js\",\n    \"check\": \"node_modules/.bin/npm-check; node_modules/.bin/nsp check\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/Vincit/knex-db-manager.git\"\n  },\n  \"keywords\": [\n    \"knex\",\n    \"sql\",\n    \"admin\",\n    \"management\",\n    \"postgresql\",\n    \"mysql\"\n  ],\n  \"author\": \"Mikael Lepistö\",\n  \"license\": \"MIT\",\n  \"bugs\": {\n    \"url\": \"https://github.com/Vincit/knex-db-manager/issues\"\n  },\n  \"homepage\": \"https://github.com/Vincit/knex-db-manager#readme\",\n  \"devDependencies\": {\n    \"chai\": \"^4.1.2\",\n    \"coveralls\": \"^3.0.9\",\n    \"istanbul\": \"^0.4.5\",\n    \"mocha\": \"^7.1.1\",\n    \"mysql\": \"^2.13.0\",\n    \"npm-check\": \"^5.9.2\",\n    \"nsp\": \"^3.2.1\",\n    \"pg\": \"^8.3.2\",\n    \"pg-escape\": \"^0.2.0\",\n    \"sqlite3\": \"^4.1.1\"\n  },\n  \"dependencies\": {\n    \"bluebird\": \"^3.7.2\",\n    \"glob\": \"^7.1.6\",\n    \"lodash\": \"^4.17.15\"\n  },\n  \"peerDependencies\": {\n    \"knex\": \"0.x\"\n  },\n  \"engines\": {\n    \"node\": \">=8.0.0\"\n  }\n}\n"
  },
  {
    "path": "tests/database-manager.spec.js",
    "content": "var _ = require('lodash'),\n  expect = require('chai').expect,\n  dbManagerFactory = require('../lib').databaseManagerFactory,\n  Bluebird = require('bluebird'),\n  Knex = require('knex');\n\nBluebird.longStackTraces();\n\nvar connection = {\n  host: 'localhost',\n  database: 'dbmanger-test-database-deleteme',\n  user: 'knexdbmanagerdbowneruser',\n  password: 'knexdbmanagerdbowneruserpassword',\n};\n\nvar pool = {\n  min: 0,\n  max: 10,\n};\n\nvar migrations = {\n  directory: __dirname + '/migrations',\n  tableName: 'testmigrations',\n};\n\nvar postgresConf = {\n  knex: {\n    client: 'postgres',\n    connection: _.assign({}, connection, {\n      port: 15432,\n    }),\n    pool: pool,\n    migrations: migrations,\n  },\n  dbManager: {\n    collate: ['fi_FI.UTF-8', 'Finnish_Finland.1252', 'en_US.utf8', 'C.UTF-8'],\n    superUser: process.env.POSTGRES_SUPERUSER || 'postgres',\n    superPassword:\n      process.env.POSTGRES_SUPERUSER_PW || 'po\"st#gr%e!sr:oo;tpa@ss%word',\n  },\n};\n\nvar postgresConf10 = {\n  knex: {\n    client: 'postgres',\n    connection: _.assign({}, connection, {\n      port: 25432,\n    }),\n    pool: pool,\n    migrations: migrations,\n  },\n  dbManager: {\n    collate: ['fi_FI.UTF-8', 'Finnish_Finland.1252', 'en_US.utf8', 'C.UTF-8'],\n    superUser: process.env.POSTGRES_SUPERUSER || 'postgres',\n    superPassword:\n      process.env.POSTGRES_SUPERUSER_PW || 'po\"st#gr%e!sr:oo;tpa@ss%word',\n  },\n};\n\nvar mySqlConf = {\n  knex: {\n    client: 'mysql',\n    connection: _.assign({}, connection, {\n      port: 13306,\n    }),\n    pool: pool,\n    migrations: migrations,\n  },\n  dbManager: {\n    collate: ['utf8_swedish_ci'],\n    superUser: 'root',\n    superPassword: 'mysqlrootpassword',\n  },\n};\n\nvar sqliteConf = {\n  knex: {\n    client: 'sqlite',\n    connection: connection,\n    pool: pool,\n    migrations: migrations,\n  },\n  dbManager: {},\n};\n\n/**\n  wnameless/oracle-xe-11g\n  hostname: localhost\n  port: 11521\n  sid: xe\n  username: system\n  password: oracle\n  Password for SYS & SYSTEM\n */\nvar oracleConf = {\n  knex: {\n    client: 'oracledb',\n    connection: _.assign({}, connection, {\n      port: 1521,\n      connectString: 'localhost/XE',\n      stmtCacheSize: 0,\n    }),\n    pool: pool,\n    migrations: migrations,\n  },\n  dbManager: {\n    collate: ['fi_FI.UTF-8', 'Finnish_Finland.1252', 'en_US.utf8', 'C.UTF-8'],\n    superUser: process.env.ORACLE_SUPERUSER || 'sys',\n    superPassword: process.env.ORACLE_SUPERUSER_PW || 'oracle',\n  },\n};\n\nvar mssqlConf = {\n  knex: {\n    client: 'mssql',\n    connection: _.assign({}, connection, {\n      port: 11433,\n    }),\n    pool: pool,\n    migrations: migrations,\n  },\n  dbManager: {\n    collate: ['fi_FI.UTF-8', 'Finnish_Finland.1252', 'en_US.utf8', 'C.UTF-8'],\n    superUser: process.env.MSSQL_SUPERUSER || 'sa',\n    superPassword: process.env.MSSQL_SUPERUSER_PW || 'mssqlpassword',\n  },\n};\n\nfunction knexWithCustomDb(dbManager, dbName) {\n  var tempKnex = _.cloneDeep(dbManager.config.knex);\n  tempKnex.client.database = dbName;\n  return Knex(tempKnex);\n}\n\n/**\n * All tests depends that the ones ran earlier were success.\n */\nvar availableDatabases = [\n  {\n    name: 'PostgreSQL 9.6',\n    manager: dbManagerFactory(postgresConf),\n  },\n  {\n    name: 'PostgreSQL 10',\n    manager: dbManagerFactory(postgresConf10),\n  },\n  {\n    name: 'MySQL 5.7',\n    manager: dbManagerFactory(mySqlConf),\n    //  },{\n    //    name: 'SQLite',\n    //    manager: dbManagerFactory(sqliteConf)\n    //  },{\n    //    name: 'Oracle XE 11g',\n    //    manager: dbManagerFactory(oracleConf)\n    //  },{\n    //    name: 'SQL Server 2017',\n    //    manager: dbManagerFactory(mySqlConf)\n  },\n];\n\nvar dbCopyName = 'dbmanger-test-database-copy-deleteme';\n\n_.map(availableDatabases, function(db) {\n  let dbManager = db.manager;\n\n  describe('Testing ' + db.name, function() {\n    before(function() {\n      // Make sure that database does not exist\n      return dbManager.createDbOwnerIfNotExist().then(function() {\n        return Bluebird.all([\n          dbManager.dropDb(dbManager.config.knex.connection.database),\n          dbManager.dropDb(dbCopyName),\n        ]);\n      });\n    });\n\n    after(function() {\n      return dbManager.close();\n    });\n\n    it('#knexInstance should fail to create an instance with non existing db', function() {\n      var knex = dbManager.knexInstance();\n      return knex\n        .raw('SELECT 1')\n        .then(function() {\n          expect('Expected error from DB').to.fail();\n        })\n        .catch(function() {\n          expect('All good!').to.be.string;\n        });\n    });\n\n    it('#createDb should create a database', function() {\n      return dbManager\n        .createDb(dbManager.config.knex.connection.database)\n        .then(function() {\n          // connecting db should work\n          var knex = dbManager.knexInstance();\n          return knex.raw('SELECT 1');\n        });\n    });\n\n    it('#migrateDb should update version and run migrations', function() {\n      return dbManager\n        .dbVersion(dbManager.config.knex.connection.database)\n        .then(function(originalVersionInfo) {\n          expect(originalVersionInfo).to.equal('none');\n          return dbManager.migrateDb(dbManager.config.knex.connection.database);\n        })\n        .then(function(migrateResponse) {\n          expect(migrateResponse[0]).to.equal(1);\n          return dbManager.dbVersion(dbManager.config.knex.connection.database);\n        })\n        .then(function(versionInfo) {\n          expect(versionInfo).to.equal('20150623130922');\n          return dbManager.migrateDb(dbManager.config.knex.connection.database);\n        })\n        .then(function(migrateResponse) {\n          expect(migrateResponse[0]).to.equal(2);\n          return dbManager.migrateDb(dbManager.config.knex.connection.database);\n        })\n        .then(function(migrateResponse) {\n          expect(migrateResponse[0]).to.equal(2);\n          return dbManager.dbVersion(dbManager.config.knex.connection.database);\n        })\n        .then(function(versionInfo) {\n          expect(versionInfo).to.equal('20150623130922');\n          return dbManager.migrateDb(dbManager.config.knex.connection.database);\n        });\n    });\n\n    it('#populateDb should populate data from given directory', function() {\n      return dbManager\n        .populateDb(__dirname + '/populate/*-data.js')\n        .then(function() {\n          var knex = dbManager.knexInstance();\n          return knex\n            .select()\n            .from('User')\n            .then(function(result) {\n              expect(parseInt(result[0].id)).to.equal(1);\n            });\n        });\n    });\n\n    it('#populateDb should populate data from given directory with seeding old export', function() {\n      return dbManager\n        .populateDb(__dirname + '/populate/*-old.js')\n        .then(function() {\n          var knex = dbManager.knexInstance();\n          return Bluebird.all([\n            knex\n              .select()\n              .from('User')\n              .then(function(result) {\n                expect(parseInt(result[0].id)).to.equal(1);\n              }),\n            knex\n              .select()\n              .from('Pet')\n              .then(function(result) {\n                expect(parseInt(result[0].id)).to.equal(1);\n              }),\n          ]);\n        });\n    });\n\n    it('#copyDb should copy a database', function() {\n      // CopyDB not implemented on MySqlDatabaseManager yet...\n      if (dbManager.config.knex.client === 'mysql') {\n        return;\n      }\n      return dbManager\n        .copyDb(dbManager.config.knex.connection.database, dbCopyName)\n        .then(function() {\n          var knex = knexWithCustomDb(dbManager, dbCopyName);\n          return Bluebird.resolve(\n            knex\n              .select()\n              .from('User')\n              .then(function(result) {\n                expect(result[0].id).to.equal('1');\n              })\n          ).finally(function() {\n            knex.destroy();\n          });\n        });\n    });\n\n    it('#truncateDb should truncate a database', function() {\n      return dbManager\n        .truncateDb([migrations.tableName, 'Ignoreme'])\n        .then(function(result) {\n          var knex = dbManager.knexInstance();\n\n          return Bluebird.all([\n            knex\n              .select()\n              .from('User')\n              .then(function(result) {\n                expect(result.length).to.equal(0);\n              }),\n            knex\n              .select()\n              .from('Ignoreme')\n              .then(function(result) {\n                expect(result.length).to.equal(1);\n              }),\n            dbManager\n              .dbVersion(dbManager.config.knex.connection.database)\n              .then(function(ver) {\n                expect(ver).to.equal('20150623130922');\n              }),\n            knex('User')\n              .insert({\n                username: 'new',\n                email: 'imtadmin@fake.invalid',\n              })\n              .then(function() {\n                return knex.select().from('User');\n              })\n              .then(function(result) {\n                expect(parseInt(result[0].id)).to.equal(1);\n              }),\n          ]);\n        });\n    });\n\n    it('#updateIdSequences should update primary key sequences', function() {\n      // UpdateIdSequences not implemented on MySqlDatabaseManager yet...\n      if (dbManager.config.knex.client === 'mysql') {\n        return;\n      }\n\n      var knex = dbManager.knexInstance();\n\n      return knex('User')\n        .insert([\n          { id: 5, username: 'new1', email: 'new_1@example.com' },\n          { id: 6, username: 'new2', email: 'new_2@example.com' },\n          { id: 7, username: 'new3', email: 'new_3@example.com' },\n        ])\n        .then(function() {\n          return dbManager.updateIdSequences();\n        })\n        .then(function() {\n          return knex('User').insert({\n            username: 'new4',\n            email: 'new_4@example.com',\n          });\n        })\n        .then(function() {\n          return knex\n            .select()\n            .where('username', 'new4')\n            .from('User');\n        })\n        .then(function(users) {\n          expect(users.length).to.equal(1);\n          expect(users[0].id).to.equal('8');\n        });\n    });\n\n    it('#updateIdSequences should work with empty table and with minimum value other than 1', function() {\n      // UpdateIdSequences not implemented on MySqlDatabaseManager yet...\n      if (dbManager.config.knex.client === 'mysql') {\n        return;\n      }\n\n      var knex = dbManager.knexInstance();\n\n      return knex\n        .select()\n        .from('IdSeqTest')\n        .then(function(result) {\n          expect(result.length).to.equal(0);\n\n          // Set min value of sequence to other than 1 (100),\n          // and current value to some other value so we can detect that it has changed.\n          return knex.raw(\n            'ALTER SEQUENCE \"IdSeqTest_id_seq\" START 200 RESTART WITH 200 MINVALUE 100 '\n          );\n        })\n        .then(function() {\n          // DB manager caches the sequence names and min values,\n          // so the cache needs to be reset.\n          dbManager._cachedIdSequences = null;\n          return dbManager.updateIdSequences();\n        })\n        .then(function() {\n          return knex('IdSeqTest').insert({\n            value: 'foo',\n          });\n        })\n        .then(function() {\n          return knex.select().from('IdSeqTest');\n        })\n        .then(function(result) {\n          expect(result.length).to.equal(1);\n          expect(result[0].id).to.equal('100');\n        });\n    });\n\n    it('#dropDb should drop a database', function() {\n      return Bluebird.all([\n        dbManager.dropDb(dbManager.config.knex.connection.database),\n        dbManager.dropDb(dbCopyName),\n        dbManager.dropDb(dbCopyName), // this should not fail\n      ])\n        .then(function() {\n          // test db was dropped\n          var knex = dbManager.knexInstance();\n          return knex\n            .raw('SELECT 1')\n            .then(function() {\n              expect('Expected error from DB').to.fail();\n            })\n            .catch(function(err) {\n              expect('All good!').to.be.string;\n            });\n        })\n        .then(function() {\n          var knex = knexWithCustomDb(dbManager, dbCopyName);\n          return Bluebird.resolve(\n            knex\n              .raw('SELECT 1')\n              .then(function() {\n                expect('Expected error from DB').to.fail();\n              })\n              .catch(function() {\n                expect(!!'All good!').to.be.string;\n              })\n          ).finally(function() {\n            knex.destroy();\n          });\n        });\n    });\n\n    it('should reconnect if used after .close', function() {\n      return dbManager\n        .close()\n        .then(function() {\n          return dbManager.dropDb();\n        })\n        .then(function() {\n          return dbManager.createDb();\n        })\n        .then(function() {\n          return dbManager.migrateDb();\n        });\n    });\n\n    it('should create database with default collate', function() {\n      dbManager.config.dbManager.collate = null;\n      return dbManager.dropDb().then(function() {\n        return dbManager.createDb();\n      });\n    });\n  });\n});\n\ndescribe('Postgresql only tests', () => {\n  var manager1 = null;\n  var manager2 = null;\n\n  before(() => {\n    manager1 = dbManagerFactory(postgresConf);\n    manager2 = dbManagerFactory(postgresConf);\n  });\n\n  before(() => manager1.dropDb('testdb1'));\n  before(() => manager1.dropDb('testdb2'));\n\n  after(() => {\n    return Bluebird.all([\n      manager1.dropDb('testdb1'),\n      manager1.dropDb('testdb2'),\n    ]).then(() => {\n      return Bluebird.all([manager1.close(), manager2.close()]);\n    });\n  });\n\n  it('should be able to create 2 DBs with 2 clients at the same time', () => {\n    return Bluebird.all([\n      manager1.createDb('testdb1'),\n      manager2.createDb('testdb2'),\n    ]);\n  });\n});\n"
  },
  {
    "path": "tests/dialect-aliases.spec.js",
    "content": "const dbManagerFactory = require('../lib').databaseManagerFactory;\nconst expect = require('chai').expect;\n\ndescribe('Testing dialect aliases', function() {\n  const aliases = [\n    'pg',\n    'postgres',\n    'postgresql',\n    'mysql',\n    'maria',\n    'mariadb',\n    'mariasql',\n    'sqlite',\n    'sqlite3',\n  ];\n\n  aliases.forEach((dialect) => {\n    it(`should load client with alias \"${dialect}\"`, () => {\n      const manager = dbManagerFactory({\n        knex: {\n          client: dialect,\n        },\n      });\n    });\n  });\n\n  it(`should fail loading unknown client`, () => {\n    try {\n      const manager = dbManagerFactory({\n        knex: {\n          client: 'foobar',\n        },\n      });\n      expect('should have thrown an exception').to.equal(false);\n    } catch (err) {\n      expect(err.message).to.contains('is not supported');\n    }\n  });\n});\n"
  },
  {
    "path": "tests/migrations/20141024070315_test_schema.js",
    "content": "exports.up = function(knex) {\n  return knex.schema\n    .createTable('User', function(table) {\n      table.bigincrements('id').primary();\n      table\n        .string('username')\n        .index()\n        .unique()\n        .notNullable();\n      table.string('email');\n    })\n    .createTable('Pet', function(table) {\n      table.bigincrements('id').primary();\n      table.string('name');\n      table\n        .biginteger('userid')\n        .unsigned()\n        .notNullable();\n      table.foreign('userid').references('User.id');\n    })\n    .createTable('Ignoreme', function(table) {\n      table.bigincrements('id').primary();\n      table.string('description');\n    })\n    .then(function() {\n      return knex('Ignoreme').insert({ description: 'wat' });\n    });\n};\n\nexports.down = function(knex) {\n  return knex.schema\n    .dropTable('Pet')\n    .dropTable('User')\n    .dropTable('Ignoreme');\n};\n"
  },
  {
    "path": "tests/migrations/20150623130922_id_sequence_test_table.js",
    "content": "exports.up = function(knex) {\n  return knex.schema.createTable('IdSeqTest', function(table) {\n    table.bigincrements('id').primary();\n    table.string('value');\n  });\n};\n\nexports.down = function(knex) {\n  return knex.schema.dropTable('IdSeqTest');\n};\n"
  },
  {
    "path": "tests/populate/01-user-data.js",
    "content": "module.exports = function(knex) {\n  return new Promise(function(resolve) {\n    setTimeout(function() {\n      return knex('User')\n        .insert({\n          username: 'dummy',\n          email: 'lol@fake.invalid',\n        })\n        .then(resolve);\n    }, 100);\n  });\n};\n"
  },
  {
    "path": "tests/populate/02-pet-data.js",
    "content": "module.exports = function(knex) {\n  return knex('Pet').insert({\n    name: 'spot',\n    userid: '1',\n  });\n};\n"
  },
  {
    "path": "tests/populate/sample-data-old.js",
    "content": "exports.seed = function(knex) {\n  return knex('User').insert({\n    username: 'dummy-old',\n    email: 'lol-old@fake.invalid',\n  });\n};\n"
  },
  {
    "path": "wait-databases.sh",
    "content": "\n\nfor i in $(seq 60); do \n  docker-compose exec postgresql psql postgres://postgres:postgresrootpassword@localhost -c \"SELECT 1\" && break; \n  sleep 1; \ndone\n\nfor i in $(seq 60); do \n  docker-compose exec postgresql10 psql postgres://postgres:postgresrootpassword@localhost -c \"SELECT 1\" && break; \n  sleep 1; \ndone\n\nfor i in $(seq 60); do \n  docker-compose exec mysql mysql -hmysql -uroot -pmysqlrootpassword -e \"SELECT 1\" && break; \n  sleep 1; \ndone\n"
  }
]