blakeembrey / sql-template-tag

ES2015 tagged template string for preparing SQL statements, works with `pg`, `mysql`, and `sqlite`

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Enhancement: Support node-oracledb bind parameters

PhilippSalvisberg opened this issue · comments

Thanks for providing sql-template-tag. I very much like the idea of this module.

I tried to use it against an Oracle Database with node-oracledb bind parameters. It did not work since Oracle is using a colon to prefix its bind parameters. They also do not like the idea of supporting ? for bind variables. (see oracle/node-oracledb#109).

Here's a small example:

import sql from "sql-template-tag";

const v1 = 'Value 1';
const v2 = 'Value 2';
const query = sql`select * from t1 where c1 = ${v1} and c2 = ${v2}`;

// query.sql = "select * from t1 where c1 = ? and c2 = ?"
// query.text = "select * from t1 where c1 = $1 and c2 = $2"

For oracledb we would need a result similar to this:

// query.oratext = "select * from t1 where c1 = :1 and c2 = :2"

Is targeting the Oracle Database an option for you? I can also provide a PR if you like.

Do you have any documentation on oratext I should refer to? Otherwise I'd propose it being a "recipe" in the README like MSSQL, especially if it only accept (query, args) style like I'm seeing here: https://node-oracledb.readthedocs.io/en/latest/user_guide/bind.html#bind-parameters-for-prepared-statements

Do you have any documentation on oratext I should refer to?

No. oratext was just an idea of how to deal with the fact that oracledb does not support bind parameters ? nor $<pos>. It's similar to PostgreSQL but they use a : instead of a $. As a result you cannot use query.sql nor query.text.

Maybe I misunderstood something, but I currently do not see how you can deal with that by providing a "recipe" without replacing the $ by a : before passing the statement to oracledb.

Postgres and MySQL are supported automatically due to the fact that they accept an object that has { text: '' } or { sql: '' } respectively. We could add oratext but if there's no actual support for this in the oracledb library it might just be simpler to document how people can do this themselves. E.g.

function toQuery(sql) {
    let i = 1,
      value = sql.strings[0];
    while (i < sql.strings.length) value += `:${i}${sql.strings[i++]}`;
    return value;
}

.execute(toQuery(sql), sql.values)

It's not the most elegant, but it would work as a wrapper around the library.

Ok, I understand. The "recipe" is just a bit more extensive.

To simplify the usage the toQuery function could be provided by the module. I can imagine that it could be reused for PostgreSQL with a second, optional parameter defaulting to : to simplify the use for oracledb but allow the reuse for PostgreSQL internally by passing a $.

This would make the "recipe" an oneliner, similar to MSSQL.

That sounds reasonable. Alternatively (after giving it some thought, sorry), if we can come up with a better name for oratext, I think it's fine to add and then update the "recipes" with the one-liner. Some ideas for the name are: query, rawText, bindText, rawSql, rawText, etc.

By better, I'm mostly just thinking that it'd be re-usable for anyone using the : style binding.

Yes, naming is one of the difficult things in IT... Good thinking regarding : being used in other DBs than Oracle.

I think raw... is a bit misleading, it contains bind variables. query sounds good, but using query.query is strange. So based on the options you provided, I'd go with bindText or bindSql or just bind or stmt. I like the last one best (at the moment). Similar to sql it covers all kinds of SQL statements. The resulting recipe would look like this:

session.execute(query.stmt, query.values);

I love statement, I added a commit here using it: af8b4be. WDYT? Can you confirm it works with OracleDB before I release it? The docs imply it should work as-is.

Perfect. I've tested it successfully against an Oracle Database 23c Free instance. Thank you!

Awesome. Thank you for the confirmation. Just released as 5.2.