arango Foxx 中的 AQL 模板不能正确处理数组

AQL template in arango Foxx does not work correctly with array

如果我使用数组,下面的查询将无法运行,但如果我们使用字符串来构造代码段,则可以正常运行。我是不是哪里弄错了,还是这是一个与arango相关的错误?

var array=["1","2"]
//Make a snippet depend on array.
var snippet=aql.literal(`FILTER u.id IN "${array}"`)

//Main query. Result is incorrect even though it runs
var query=db._query(aql`
For u in Collection
{$snippet}
RETURN u
`
)

使用字符串的正确查询示例

var string="1"
var snippet=aql.literal(`FILTER u.id == "${array}"`)

FILTER u.id IN "${array}" 产生 FILTER u.id IN "1,2"。请注意,IN 右侧的内容是一个字符串,不再是字符串数组。

字符串插值(反引号)使用了 array.toString() 的结果,即 1,2。周围的引号按字面意思接管,这可能不是您想要的。请参阅 Queries docs for ArangoJS.

最后的示例

即使数组表示形式是 ["1","2"],这些引号也会导致 "["1","2"]",这会给您带来语法错误。内部引号像 "[\"1\",\"2\"]" 一样转义,您将测试 u.id IN "some string",但 IN 运算符将 return false 上的任何字符串右侧(这里需要一个数组)。

RETURN "1" IN "1"       // false
RETURN "1" IN "[\"1\"]" // false
RETURN "1" IN ["1"]     // true

让我们尝试不同的使用方式aql.literal:

> aql.literal(`FILTER u.id IN ${array}`).toAQL()
'FILTER u.id IN 1,2'

有一个模板文字,它被评估 然后 作为参数传递给函数。该函数仅包装由模板文字生成的字符串,然后调用 toAQL() 再次将其解包。 toAQL() 通常由 aql 助手在内部调用。

> aql.literal`FILTER u.id IN ${array}`.toAQL()
'FILTER u.id IN ,'

这使用 aql.literal 作为标记模板,但它并不意味着是处理模板字符串的函数。输出没有用。

> aql.literal('FILTER u.id IN ${array}').toAQL()
'FILTER u.id IN ${array}'

引号中的字符串(不是模板文字!)作为参数传递给 aql.literal。结果与输入相同,带有美元符号和大括号。它实际上与输入相同。这是应该如何使用 aql.literal() 的预期方式。它不支持绑定参数

您可以依靠 JSON.stringify() 像这样正确地转义数组:

> aql.literal('FILTER u.id IN ' + JSON.stringify(array)).toAQL()
'FILTER u.id IN ["1","2"]'

用法示例:

> var snippet = aql.literal('FILTER u.id IN ' + JSON.stringify(array))
> aql`FOR u IN Collection ${snippet} RETURN u`.query
'FOR u IN Collection FILTER u.id IN ["1","2"] RETURN u'

然而,这不是很优雅,从 ArangoJS v6.7.0 开始,它实际上支持 aql 模板文字的嵌套:

>var snippet = aql`FILTER u.id IN ${array}`

>snippet // see what happens under the hood
{ query: 'FILTER u.id IN @value0',  // a bind parameter is used!
  bindVars: { value0: [ '1', '2' ] },
  _source: [Function: _source] }

> aql`FOR u IN Collection ${snippet} RETURN u`

{ query: 'FOR u IN Collection FILTER u.id IN @value0 RETURN u',
  bindVars: { value0: [ '1', '2' ] }, // still bind parameter with the snippet integrated!
  _source: [Function: _source] }

用法示例(针对 ArangoJS):

var array = [ "1", "2" ]
var snippet = aql`FILTER u.id IN ${array}`
var query = db.query(aql`
  FOR u IN Collection
    ${snippet}
    RETURN u
`)

您也可以在 Arangosh/Foxx (db._query()) 中使用 ArangoDB v3.4。

另见:ArangoJS Changelog