Deprecated in favour https://www.npmjs.com/package/slonik.
A PostgreSQL client with strict types and assertions.
import {
createPool
} from 'mightyql';
const connection = createPool({
host: '127.0.0.1'
});
await connection.query('SELECT 1');
Mightyql will strip all comments and line-breaks from a query before processing it.
This makes logging of the queries easier.
The implication is that your query cannot contain values that include a newline character, e.g.
// Do not do this
connection.query(`INSERT INTO foo (bar) VALUES ('\n')`);
If you want to communicate a value that includes a multiline character, use value placeholder interpolation, e.g.
connection.query(`INSERT INTO foo (bar) VALUES (?)`, [
'\n'
]);
Mightyql enables use of question mark (?) value placeholders, e.g.
await connection.query('SELECT ?', [
1
]);
Question mark value placeholders are converted to positional value placeholders before they are passed to the pg driver, i.e. the above query becomes:
SELECT $1
Do not mix question mark and positional value placeholders in a single query.
A question mark is interpolated into a value set when the associated value is an array, e.g.
await connection.query('SELECT ?', [
[
1,
2,
3
]
]);
Produces:
SELECT ($1, $2, $3)
A question mark is interpolated into a list of value sets when the associated value is an array of arrays, e.g.
await connection.query('SELECT ?', [
[
[
1,
2,
3
],
[
1,
2,
3
]
]
]);
Produces:
SELECT ($1, $2, $3), ($4, $5, $6)
A :[a-zA-Z] regex is used to match named placeholders.
await connection.query('SELECT :foo', {
foo: 'FOO'
});
Produces:
SELECT $1
Query methods can be executed using sql tagged template literal, e.g.
import {
sql
} from 'mightyql'
connection.query(sql`INSERT INTO reservation_ticket (reservation_id, ticket_id) VALUES ${values}`);
Arguments of a tagged template literal invocation are replaced with an anonymous value placeholder, i.e. the latter query is equivalent to:
connection.query('INSERT INTO reservation_ticket (reservation_id, ticket_id) VALUES ?', [
values
]);
When using tagged template literals, it is easy to forget to add the sql tag, i.e.
Instead of:
connection.query(sql`INSERT INTO reservation_ticket (reservation_id, ticket_id) VALUES ${values}`);
Writing
connection.query(`INSERT INTO reservation_ticket (reservation_id, ticket_id) VALUES ${values}`);
This would expose your application to SQL injection.
Therefore, I recommend using eslint-plugin-sql no-unsafe-query rule. no-unsafe-query warns about use of SQL inside of template literals without the sql tag.
anyReturns result rows.
Similar to
#queryexcept that it returns rows without fields information.
Example:
const rows = await connection.any('SELECT foo');
anyFirstReturns value of the first column of every row in the result set.
DataIntegrityError if query returns multiple rows.Example:
const fooValues = await connection.any('SELECT foo');
insertDesigned to use when inserting 1 row.
The reason for using this method over
#queryis to leverage the strict types.#insertmethod result type isInsertResultType.
Example:
const {
insertId
} = await connection.insert('INSERT INTO foo SET bar="baz"');
manyReturns result rows.
NotFoundError if query returns no rows.Example:
const rows = await connection.many('SELECT foo');
manyFirstReturns value of the first column of every row in the result set.
NotFoundError if query returns no rows.DataIntegrityError if query returns multiple rows.Example:
const fooValues = await connection.many('SELECT foo');
maybeOneSelects the first row from the result.
null if row is not found.DataIntegrityError if query returns multiple rows.Example:
const row = await connection.maybeOne('SELECT foo');
// row.foo is the result of the `foo` column value of the first row.
maybeOneFirstReturns value of the first column from the first row.
null if row is not found.DataIntegrityError if query returns multiple rows.DataIntegrityError if query returns multiple columns.Example:
const foo = await connection.maybeOneFirst('SELECT foo');
// foo is the result of the `foo` column value of the first row.
oneSelects the first row from the result.
NotFoundError if query returns no rows.DataIntegrityError if query returns multiple rows.Example:
const row = await connection.one('SELECT foo');
// row.foo is the result of the `foo` column value of the first row.
Note:
I've got asked "How is this different from knex.js
knex('foo').limit(1)".knex('foo').limit(1)simply generates "SELECT * FROM foo LIMIT 1" query.knexis a query builder; it does not assert the value of the result. Mightyqloneadds assertions about the result of the query.
oneFirstReturns value of the first column from the first row.
NotFoundError if query returns no rows.DataIntegrityError if query returns multiple rows.DataIntegrityError if query returns multiple columns.Example:
const foo = await connection.oneFirst('SELECT foo');
// foo is the result of the `foo` column value of the first row.
queryAPI and the result shape are equivalent to pg#query.
Overriding the error constructor used by Mightyql allows you to map database layer errors to your application errors.
import {
createPool
} from 'mightyql';
class NotFoundError extends Error {};
createPool('postgres://', {
errors: {
NotFoundError
}
});
The following error types can be overridden:
NotFoundErrortransactiontransaction method is used wrap execution of queries in START TRANSACTION and COMMIT or ROLLBACK. COMMIT is called if the transaction handler returns a promise that resolves; ROLLBACK is called otherwise.
transaction method can be used together with createPool method. When used to create a transaction from an instance of a pool, a new connection is allocated for the duration of the transaction.
const result = await connection.transaction(async (transactionConnection) => {
transactionConnection.query(`INSERT INTO foo (bar) VALUES ('baz')`);
transactionConnection.query(`INSERT INTO qux (quux) VALUES ('quuz')`);
return 'FOO';
});
result === 'FOO';
NotFoundErrorTo handle the case where query returns less than one row, catch NotFoundError error.
import {
NotFoundError
} from 'mightyql';
let row;
try {
row = await connection.one('SELECT foo');
} catch (error) {
if (!(error instanceof NotFoundError)) {
throw error;
}
}
if (row) {
// row.foo is the result of the `foo` column value of the first row.
}
DataIntegrityErrorTo handle the case where the data result does not match the expectations, catch DataIntegrityError error.
import {
NotFoundError
} from 'mightyql';
let row;
try {
row = await connection.one('SELECT foo');
} catch (error) {
if (error instanceof DataIntegrityError) {
console.error('There is more than one row matching the select criteria.');
} else {
throw error;
}
}
UniqueViolationErrorUniqueViolationError is thrown when Postgres responds with unique_violation (23505) error.
This package is using Flow types.
Refer to ./src/types.js.
The public interface exports the following types:
DatabaseConnectionTypeDatabasePoolConnectionTypeDatabaseSingleConnectionTypeUse these types to annotate connection instance in your code base, e.g.
// @flow
import type {
DatabaseConnectionType
} from 'mightyql';
export default async (
connection: DatabaseConnectionType,
code: string
): Promise<number> => {
const row = await connection
.one('SELECT id FROM country WHERE code = ? LIMIT 2', [
code
]);
return Number(row.id);
};
Define DEBUG=mightyql* environment variable to enable logging.
Logging includes information about:
Here is the output example:
mightyql query execution time 196 ms +199ms
mightyql query returned 4 row(s) +0ms
mightyql query SELECT * FROM `movie` WHERE id IN (1000223) +3ms
mightyql values [ 'movie', [ 1000223 ] ] +0ms
mightyql query execution time 28 ms +29ms
mightyql query returned 1 row(s) +0ms
mightyql query SELECT * FROM `movie` WHERE id IN (1000292) +3ms
mightyql values [ 'movie', [ 1000292 ] ] +0ms
mightyql query execution time 24 ms +25ms
mightyql query returned 1 row(s) +0ms
mightyql query SELECT * FROM `movie` WHERE id IN (1000220) +1ms
mightyql values [ 'movie', [ 1000220 ] ] +0ms
mightyql query execution time 26 ms +27ms
mightyql query returned 1 row(s) +0ms
Using Atom IDE you can leverage the language-babel package in combination with the language-sql to enable highlighting of the SQL strings in the codebase.
To enable highlighting, you need to:
language-babel and language-sql packages.language-babel "JavaScript Tagged Template Literal Grammar Extensions" setting to use language-sql to highlight template literals with sql tag (configuration value: sql:source.sql).sql helper to construct the queries.For more information, refer to the JavaScript Tagged Template Literal Grammar Extensions documentation of language-babel package.