Install
First mark your desired database drivers as dependencies in your app.
List of currently-supported database drivers:
- mariadb for MariaDB.
- mysql2 for MySQL.
- pg for PostgreSQL.
- pglite for PGlite.
- better-sqlite3 for SQLite.
Then mark the multi-db-driver npm package as a dependency in your app as well. Multi-DB Driver is generally designed to work with the latest version of each supported database driver.
Then you can configure Multi-DB Driver and connect to your database.
Connect to a database using Multi-DB Driver
const db = await require('multi-db-driver')(config)If you do not supply a config object in the constructor, Multi-DB Driver will attempt to load your config from a .multi-db-driver-config.json file that should most commonly be placed in the root directory of your app.
Multi-DB Driver will look for that file in up to 3 directories above where the Multi-DB Driver module is located (e.g. looking at parent directories starting with node_modules). You can change this behavior by setting the MULTI_DB_DRIVER_CONFIG_FILE_SEARCH_ATTEMPTS environment variable to a number other than 3. The default value of 3 will in most circumstances include the root directory of your app as one of the locations that will be searched for your Multi-DB Driver config, which is why it's the default value.
If you want to set a location for the config file manually, then set the MULTI_DB_DRIVER_CONFIG_LOCATION environment variable to the absolute path on your filesystem to where your config is.
It is recommended that you add .multi-db-driver-config.json to your .gitignore as well because it will typically contain database credentials.
See "Configuration" for information about how to set up a Multi-DB Driver config.
Performing database queries
The below examples show how to use Multi-DB Driver to query your database(s) from the simplest usage to the most complex, demonstrating how this module focuses on adding complexity only when needed as a progressive enhancement atop simpler, more concise syntax.
Example of one universal query that works with any database you set in your config
const simpleQuery = await db.query('select * from some_table')This usage is basically as concise as any standalone database driver would be, except it will work with any database that uses the same SQL syntax for this specific query and similar basic ones.
Universal query but with parameters
const noNormalizingNeeded = await db.query('select * from some_table where something = ?', ['some value'])The second argument is optional if you don't need params.
Universal query with parameters and a callback function for post-processing
const normalizedDataUniversalQuery = await db.query('select * from some_table where something = ?', ['some value'], function (db, result) {
switch (db) {
case 'mysql':
// do stuff if it was a mysql query
return result
default:
// do stuff if it was a query to any other kind of database
return result
}
})The third argument is optional if you don't need a post-processing function.
The post-processing function is useful if you need to call out specific post-processing behaviors for certain databases.
Default query with special query for a specific database
const normalizedDataMultipleQueries = await db.query(
// queries object
{
default: 'select * from some_table where something = ?',
mysql: 'some mysql-specific version of the query where something = ?'
},
// values array
['some value'],
// postprocess function
function (db, result) {
switch (db) {
case 'mysql':
// do stuff if it was a mysql query
return result
default:
// do stuff if it was any other kind of query
return result
}
})This supplies an object instead of a string to the query argument.
It also combines all the other above features too, showing a maximally featureful and flexible version of the query method.
By default Multi-DB Driver will rewrite the query under the hood to use $1 instead of ? for queries being executed against PostgreSQL and PGlite. You can disable this behavior by setting questionMarkParamsForPostgres to false in your Multi-DB Driver config, or by setting disableQuestionMarkParamsForPostgres to true at the query level in the query object.
CLI scripts
This module also comes with a cli.js file to automate common database setup and teardown tasks. It will load your Multi-DB Driver config and connect to the database using the adminConfig to perform these tasks.
The cli.js file supports the following commands:
cli.js --create: Creates the user and database specified in your config if it does not already exist.cli.js --destroy: Drops the user and database specified in your config.cli.js --file file.sql: Executes the SQL statements in the specified SQL file. Will attempt to do so using the regular less privileged config by default and will escalate to the admin config only if the less privileged config is unable to connect.cli.js --dump-schema path/to/schema.sql: Dumps the connected database's schema to specified SQL file path. Will create file in specified path if it does not already exist.cli.js --dump-data path/to/schema.sql: Dumps the connected database's schema and data to specified SQL file path. Will create file in specified path if it does not already exist.
For the dump commands to work, you will need to ensure pg_dump, mysqldump, and sqlite3 are in your PATH.
Options
- Skip the prompts with
--yes. - Suppress logs and warnings with
--suppress-logs. - Suppress errors with
--suppress-errors. - Enable verbose logging with
--enable-verbose.
Integrating the CLI scripts into your app
It is recommended that you create npm scripts in your app's package.json file to run those commands. Example usage of those scripts if you create them would look something like this:
npm run create-db: Executesnode [...]/cli.js --create.npm run destroy-db: Executesnode [...]/cli.js --destroy.npm run db-file -- file.sql: Executesnode [...]/cli.js --file file.sql.npm run db-schema-dump -- path/to/schema.sql: Executesnode [...]/cli.js --dump-schema path/to/schema.sql.npm run db-data-dump -- path/to/schema.sql: Executesnode [...]/cli.js --dump-data path/to/schema.sql.
Replace the [...] part in the above examples with the path to where your copy of this module resides, e.g. in node_modules, lib, git_modules, or wherever it happens to be in your app.