Knex:嵌套原始查询,转义“?”特点

Knex : nested raw queries, escape the '?' character

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

postgresql和LTREE中的一个运算符是字符?,在knex.raw中,?字符用于绑定值(众所周知),所以有冲突.

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

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

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

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

太棒了!但是 myQuery 是由一个通用函数生成的,该函数在 SELECT EXISTS 的上下文中调用,但在没有 SELECT EXISTS 的上下文中调用,如果我只用一个 \\? 56=] (context without 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 删除了 \? 的第一个双 \ 和第二个 knex.raw .wrap 将等待绑定

您正在将查询构建器作为参数传递给 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(),这会转换查询builder 到纯 SQL 字符串,其中 ?-marks 已被转义。