我试图将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无法识别\\?
)。
一个糟糕的解决方案(但是一个工作的解决方案)是将参数设置为生成查询的函数,如果它是嵌套原始查询的上下文,则该参数是精确的。
这是我们可以拥有的代码的简单示例:
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将等待绑定
答案 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字符串,其中?
标记未转义。