planetscale / database-js

A Fetch API-compatible PlanetScale database driver
https://planetscale.com/docs/tutorials/planetscale-serverless-driver
Apache License 2.0
1.17k stars 35 forks source link

feat: include formatted sql on DatabaseError for improved debugging #134

Closed hex2f closed 1 year ago

hex2f commented 1 year ago

What?

Adds an optional sql field to the DatabaseError which gets populated with the formatted sql statement in execute() if a database error is encountered (not errors rising from the postJSON function).

Why?

Today while writing an application using this driver, I ran into syntax error at position XXXX on a pretty big generated SQL query with user provided values (?). Debugging this in my code editor alone was quite tough, so I decided to open up DataGrip and pasted my generated query into its console for help. No luck. Syntax errors everywhere due to all the placeholder question marks. As a last resort, I dug into my node_modules folder and added console.log(sql) into execute() and got the full query that way. Pasted it into DataGrip, and bingo, it showed me exactly where the error was.

Point is, that was way more difficult than it needed to be. In that situation it would have been really awesome to just console.log(error.sql), or just a more general debug log option (future PR perhaps?)

Added a test for it as well so should be ready to merge if maintainers feel it's an appropriate addition.

dgraham commented 1 year ago

Thanks for the pull request with all of these details!

Including replacement argument values in error messages can leak personally identifiable info, passwords, tokens, etc. into logs. They can also appear in the user-facing app itself if the error message received from the server is displayed without modification.

Another way to do this for debugging is to wrap the format function with logging behavior.

import { connect, format } from '@planetscale/database'

function debugFormat(query, values) {
  const sql = format(query, values)
  console.log(sql)
  return sql
}

const config = {
  format: debugFormat,
  host: '<host>',
  username: '<user>',
  password: '<password>'
}

const conn = connect(config)
const results = await conn.execute('select 1 from dual where 1=?', [1])
console.log(results)