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 已被转义。
我正在尝试将 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 已被转义。