Knex:嵌套的原始查询,逃避'?'字符

时间:2018-06-01 14:47:20

标签: javascript postgresql knex.js ltree

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

postgresql和LTREE中的运算符是字符?,在knex.raw中,?字符用于绑定值(众所周知),因此存在冲突。

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

我的问题是我需要做一个“SELECT EXISTS'我的查询包含带有\\?字符的knex.raw,在knex中我使用:knex.raw(myQuery).wrap('SELECT EXISTS(', ')')来执行我的SELECT EXISTS。所以我有嵌套的原始查询,一个用于select存在,一个用于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删除\\的第一个双\\?,而.wrap的第二个knex.raw将等待绑定

1 个答案:

答案 0 :(得分:0)

您要将查询构建器作为参数传递给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, ...])

以下是运行工具包示例,该示例显示问号仍在逃脱https://runkit.com/embed/bbtfooz9o1yn

原始查询似乎起作用的原因可能是在某个时候,当将查询构建器作为第一个参数传递给knex.raw()时,会调用.toString(),这会将查询构建器转换为普通SQL字符串,其中?标记未转义。