Gathering detailed insights and metrics for mysql2-async
Gathering detailed insights and metrics for mysql2-async
Gathering detailed insights and metrics for mysql2-async
Gathering detailed insights and metrics for mysql2-async
A wrapper for mysql2 to add convenience, especially when developing with async/await and async iterables and inside docker containers.
npm install mysql2-async
Typescript
Module System
Node Version
NPM Version
TypeScript (98.63%)
JavaScript (0.73%)
Dockerfile (0.46%)
Shell (0.18%)
Total Downloads
0
Last Day
0
Last Week
0
Last Month
0
Last Year
0
MIT License
1 Stars
70 Commits
3 Forks
6 Watchers
1 Branches
2 Contributors
Updated on Jan 19, 2024
Latest Version
2.0.1
Package Id
mysql2-async@2.0.1
Unpacked Size
35.48 kB
Size
9.77 kB
File Count
12
NPM Version
10.2.4
Node Version
21.6.2
Published on
Mar 25, 2024
Cumulative downloads
Total Downloads
Last Day
0%
NaN
Compared to previous day
Last Week
0%
NaN
Compared to previous week
Last Month
0%
NaN
Compared to previous month
Last Year
0%
NaN
Compared to previous year
1
A wrapper for mysql2 to add convenience, especially when developing with async/await and async iterables.
This library has a few core principles:
Works just like creating a mysql2 pool. You will want to make a single pool and export it so that it can be imported all over your code.
1import Db from 'mysql2-async' 2export const db = new Db({ 3 host: 'yourhost', 4 ... 5}) 6 7async function main() { 8 const row = await db.getrow('SELECT ...') 9} 10main().catch(e => console.error(e))
When working in docker, it's common to keep database configuration in environment variables. In order to make that easy, this library provides a convenient way to import a pool instance that has already been created and configured with the following environment variables:
MYSQL_HOST (default 'localhost')
MYSQL_PORT (default '3306')
MYSQL_DATABASE (default 'default_database')
MYSQL_USER (default 'root')
MYSQL_PASS
MYSQL_POOL_SIZE (default is mysql2's default)
MYSQL_SKIPTZFIX (default false) // see below discussion of the timezone fix
This way, connecting is very simple, and you don't have to worry about creating and exporting the pool for the rest of your codebase:
1import db from 'mysql2-async/db' 2 3async function main() { 4 const row = await db.getrow('SELECT ...') 5} 6main().catch(e => console.error(e))
You must refer to .default
when importing with require
:
1const Db = require('mysql2-async').default 2// or the instance created with environment variables (see above) 3const db = require('mysql2-async/db').default
A lot of convenience methods are provided that allow you to specify the kind of operation you are about to do and the kind of return data you expect.
1const rows = await db.getall('SELECT name FROM mytable') 2console.log(rows) // [{ name: 'John' }, { name: 'Maria' }, ...] 3const row = await db.getrow('SELECT name FROM mytable WHERE name=?', ['John']) 4console.log(row) // { name: 'John' } 5const name = await db.getval('SELECT name FROM mytable WHERE name=?', ['John']) 6console.log(name) // John 7const names = await db.getvals('SELECT name FROM mytable WHERE name IN (:name1, :name2)', 8 { name1: 'John', name2: 'Maria' }) 9console.log(names) // ['John', 'Maria']
As you can see in the getvals
example in the previous section, mysql2's named parameter support works
here as well.
1const insertId = await db.insert('INSERT INTO mytable (name) VALUES (?)', ['Mike']) 2const rowsAffected = await db.update('UPDATE mytable SET name=? WHERE name=?', ['Johnny', 'John']) 3const success = await db.execute('CREATE TABLE anothertable ...')
Note that db.update
returns only rows affected, not rows changed. Affected is the number of rows
that matched the WHERE, while changed is the number of rows that actually changed after the SET. I
didn't want to complicate things by trying to return both, and you can always rewrite your query like
SET val=? WHERE val!=?
so that affected becomes the same as changed. And if you really don't want to,
you can use db.query
to get back result.changedRows
.
If the convenience methods are hiding something you need from mysql2, you can use .query() to get back whatever would have been returned by mysql2 (inside a promise, however).
1const result = await db.query('INSERT INTO mytable (name) VALUES (?)', ['Mike']) 2const insertId = result.insertId
Writing queries with IN
operators can be a little complicated, especially when using named parameters.
A helper is provided that takes your existing bound parameters array/object and an array to be used for the IN
.
It generates the SQL while also mutating your existing bound parameters, so that you can easily use it inline.
1const binds = { author: authorid } 2const rows = db.getall(` 3 SELECT * FROM mytable 4 WHERE author = :author 5 AND ( 6 genre IN (${db.in(binds, genres)}) OR 7 title IN (${db.in(binds, titles)}) 8 )`, binds)
The async iterable approach is by far the simplest. It works almost exactly like .getall()
, except
the advantage here is that it does not load the entire result set into memory at one time, which will help
you avoid out-of-memory issues when dealing with thousands or millions of rows.
1const stream = db.stream('SELECT name FROM mytable') 2for await (const row of stream) { 3 // work on the row 4}
for await
is very safe, as break
ing the loop or throwing an error inside the loop will clean up the stream appropriately.
Note that .stream()
returns a node Readable
in object mode, so you can easily do other things with
it like .pipe()
it to another stream processor. When using the stream without for await
, you must call stream.destroy
if you do not want to finish processing it and carefully use try {} finally {}
to destroy it in case your code throws an error. Failure to do so will leak a connection from the pool.
Another available approach is to use the iterator pattern directly. This is a standard javascript iterator that you would receive from anything that supports the async iterator pattern. Probably to be avoided unless you are working with multiple result sets at the same time (e.g. syncing two tables).
1const iterator1 = db.iterator('SELECT name FROM mytable') 2const iterator2 = db.iterator('SELECT * FROM anothertable') 3while (true) { 4 const { value: row1, done1 } = await iterator1.next() 5 const { value: row2, done2 } = await iterator2.next() 6 if (!done1 || !done2) { 7 try { 8 // do some work to sync the rows 9 } catch (e) { 10 await iterator1.return() 11 await iterator2.return() 12 throw e 13 } 14 } else { 15 break 16 } 17}
As illustrated above, an iterator needs to be cleaned up when your code is aborted before reaching the end, or it will leak a connection. Remember to await iterator.return()
if you are going to abandon the iterator, and inside try/catch/finally blocks in your row processing code. An SQL query error will show up on the first await iterator.next()
and does not need to be cleaned up.
A method is provided to support working inside a transaction. Since the core Db object is a mysql pool, you cannot send transaction commands without this method, as each command would end up on a different connection.
To start a transaction, provide a callback that MUST return a promise (just make it async). A new instance of
db
is provided to the callback; it represents a single connection, inside a transaction. Remember to pass this along to any other functions you call during the transaction - if you call a function that uses the global db
object its work will happen outside the transaction!
You do NOT send START TRANSACTION
, ROLLBACK
, or COMMIT
as these are handled automatically.
1await db.transaction(async db => { 2 // both of these queries happen in the same transaction 3 const row = await db.getrow('SELECT * FROM ...') 4 await db.update('UPDATE mytable SET ...') 5})
If you need to roll back, simply throw an error. Similarly, any query that throws an error will trigger a rollback.
1await db.transaction(async db => { 2 const id = await db.insert('INSERT INTO user ...') 3 throw new Error('oops!') 4}) // the INSERT will be rolled back and will not happen
db.transaction()
accepts an options
parameter allowing you to set a maximum number of retries allowed upon deadlock:
1await db.transaction(async db => { 2 const row = await db.getrow('SELECT * FROM ...') 3 await db.update('UPDATE mytable SET ...') 4}, { retries: 1 })
If this transaction is the loser of a deadlock, it will retry the whole transaction once, including refetching the getrow
statement.
Prepared statements are nearly automatic, you just need to notate which queries need it. It's desirable to carefully pick a few complicated queries because each unique SQL string that uses prepared statement support will use up a small amount of resources on both client and server.
1await db.getrow('SELECT m.*, o.* FROM mytable m, othertable o WHERE ...complicated...', 2 [ /* bind parameters */ ], 3 { saveAsPrepared: true } 4)
Now, future calls with this same SQL statement (before inserting bound parameters) will be able to skip the query planning stage on the mysql server and return data a little bit faster.
Note that this is just a pass-through to mysql2's prepared statement implementation, so you can refer to their documentation / code for more details.
Working with timezones can be very confusing. This library takes an opinionated approach and sets it up so
that all dates will be stored as UTC, whether the date is set automatically on the server through a
DEFAULT CURRENT_TIMESTAMP
setting, set with a server-side function such as NOW()
, or sent from the client
as a javascript Date() object.
Older versions of mysql (less than 5.1) may throw an error because of this. If you need to work with a server
running an old version of mysql, or an existing database that does not or has not stored dates as UTC in the past,
you may set the skiptzfix
configuration variable and then be very careful while handling dates.
1const db = new Db({ skiptzfix: true })
This library is written in typescript and provides its own types. For added convenience, methods that return rows or values will accept a generic so that you can specify the return type you expect:
1interface Book { 2 id: number 3 title: string 4 isbn: string 5} 6const row = await db.getrow<Book>('SELECT id, title, isbn FROM books WHERE id=?', [5]) 7// `row` is a `Book` 8const rows = await db.getall<Book>('SELECT id, title, isbn FROM books') 9// `rows` is a `Book[]` 10const stream = db.stream<Book>('SELECT id, title, isbn FROM books') 11for await (const row of stream) { 12 // `row` is a `Book` 13}
No vulnerabilities found.
Reason
no binaries found in the repo
Reason
license file detected
Details
Reason
branch protection is not maximal on development and all release branches
Details
Reason
no SAST tool detected
Details
Reason
Found 0/30 approved changesets -- score normalized to 0
Reason
0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0
Reason
no effort to earn an OpenSSF best practices badge detected
Reason
security policy file not detected
Details
Reason
project is not fuzzed
Details
Reason
dependency not pinned by hash detected -- score normalized to 0
Details
Reason
10 existing vulnerabilities detected
Details
Score
Last Scanned on 2025-07-07
The Open Source Security Foundation is a cross-industry collaboration to improve the security of open source software (OSS). The Scorecard provides security health metrics for open source projects.
Learn More