Search code examples
node.jsrxjsnode-mysqlnode-mysql2

Cannot use bindNodeCallback with node-mysql connection.query


I'm trying to use bindNodeCallback to convert connection.query into a function that returns observable.

const mysql = require('mysql2');
const { bindNodeCallback } = require("rxjs");
const connection = mysql.createConnection({host:"servername", user: "u", password:"p", database:"mydb" });

connection.connect();
let q = 'SELECT 1 from dual';
//1.This works. Default api
connection.query(q, (err, v)=>console.log(v));

//2.this throws: TypeError: Cannot read property 'config' of undefined
//bindNodeCallback(connection.query)(q).subscribe(v=>console.log(v));

//3.This returns a two dimensional array where the first element contains an array with the results and the second an array of ColumnDefinition.
bindNodeCallback(connection.query).call(connection, q).subscribe(v=>console.log(v));


Statement 1 prints: [ TextRow { '1': 1 } ]

Statement 2 throws: TypeError: Cannot read property 'config' of undefined and after debugging the code I saw that it references this.config (inside Connection object) which according to the doc needs to be provided when calling the output function.

So I add this to statement 3 but for some reason I don't get what I expect:

Statement 3 prints: [[ TextRow { '1': 1 } ],[ColumnDefinition { _buf:..., _clientEncoding: 'utf-8'....]]

My question is, how should I use bindNodeCallback() to print the results that statement 1 prints?

Note: In case you want to test this issue with an older version of mysql you can use mysql instead of mysql2 where the same issue occurs just with differrent types TextRow=>RowDataPacket and ColumnDefinition=>FieldPacket


Solution

  • bindNodeCallback will create a function that returns an observable to which subscribing will stream one and only value containing:

    • the param passed to callback (if one)
    • array of params passed to callback (if more than one).

    mysql and mysql2 pass two parameters to the callback of query(): one is an array containing the results and the other is an array containing the column definitions.

    To verify call connection.query(q, (err, v, colDef)=>console.log(v, colDef)); to see that it will also print the column definitions.

    So since the parameters are two, the function passed to subscribe should receive an array, not a single param.

    "how should I use bindNodeCallback() to print the results that statement 1 prints?"

    Call it as you do now, just pass from map for getting only the first param (param at index 0 of the callback params array):

    bindNodeCallback(connection.query).call(connection,q)
    .pipe(map(arr=>arr[0])).subscribe(v=>console.log(v));