首页 > 解决方案 > Knex:嵌套原始查询,转义“?” 特点

问题描述

我正在尝试将 Postgresql LTREE 与 knex 一起使用。
为了管理它,我必须使用 knex 的原始查询,因为显然 LTREE 在 knex 中不是本机的(它特定于 postgresql)

postgresql 和 LTREE 中的操作符是 character ?,在 knex.raw 中,?character 是用来绑定值的(众所周知),所以存在冲突。

再一次,这不是问题,因为我们可以使用它\\?来防止替换 knex?在原始查询中找到 a 的值。

我的问题是我需要对包含带有\\?字符的 knex.raw 的查询执行“SELECT EXISTS”,并且在 knex 中我使用 : knex.raw(myQuery).wrap('SELECT EXISTS(', ')')来执行我的 SELECT EXISTS。所以我嵌套了原始查询,一个用于选择存在,一个myQuery用于 postgresql ltree 条件。

在执行查询的过程中,第一个 knex.raw 将原来的\\?转换成 => ?是正常的,第二个 knex.raw 会做同样的工作,他会找到一个?并且想要绑定数据但我不给他数据所以 knex 抛出一个错误!

一个解决方案是用这个\\\\?代替\\?,第一个 knex.raw 将转换查询,\\?第二个 knex.raw 将转换最终查询,?这是我在 postgresql 中想要的(不尝试进行任何绑定)

这很棒!但是myQuery是由一个通用函数生成的,该函数在带有 SELECT EXISTS 的上下文中调用,但也在没有 SELECT EXISTS 的上下文中调用,如果我\\\\?只使用一个 knex.raw(没有 SELECT EXISTS 的上下文),它这次也会由 postgresql 引发错误(因为 postgresql 无法识别\\?)。

是否可以通过所有 knex.raw 转义 `?` 字符?

一个糟糕的解决方案(但一个可行的解决方案)是为生成查询的函数设置一个参数,以精确判断它是否是嵌套原始查询的上下文。

编辑 :

这是我们可以拥有的代码的简单示例:

const functionThatCreatesTheSubQuery = () => {
    const condition = knex.raw('columnWithLTree \\? array["Root.Noeud1"]::lquery[]');
    return this.where(condition);
};
knex.raw( 
    knex.select('property')
        .from('table') 
        .where(functionThatCreatesTheSubQuery())
).wrap('SELECT EXISTS (', ')');

这失败了,因为第一个 knex.raw 删除了第一个 double并且 .wrap\\\\?第二个 knex.raw 将等待绑定

标签: javascriptpostgresqlknex.jsltree

解决方案


您将查询生成器knex.raw(...)作为参数传递给

knex.raw( 
    // this is not valid parameter
    knex.select('property')
        .from('table') 
        .where(functionThatCreatesTheSubQuery())
).wrap('SELECT EXISTS (', ')');

它应该是这样的:

knex.raw('SELECT EXISTS (?)', [
    knex.select('property')
        .from('table') 
        .where(functionThatCreatesTheSubQuery())
]);

原始呼叫签名是knex.raw(String, [binding1, binding2, ...])

这是 runkit 示例,它显示问号仍然被转义https://runkit.com/embed/bbtfooz9o1yn

原始查询似乎起作用的原因可能是,当查询构建器knex.raw()作为第一个参数传递给它时.toString(),可能会调用它,它将查询构建器转换为纯 SQL 字符串,其中?-marks 已被取消转义。


推荐阅读