Шаблон AQL в arango Foxx некорректно работает с массивом

Приведенный ниже запрос не сработал бы, если бы я использовал массив, но работал бы нормально, если бы мы использовали строку для построения фрагмента. Я где-то ошибся или это ошибка, связанная с аранго?

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}"`)

person Loredra L    schedule 24.10.2018    source источник


Ответы (1)


FILTER u.id IN "${array}" производит FILTER u.id IN "1,2". Обратите внимание, что справа от IN находится строка, а не массив строк.

Что происходит, так это то, что интерполяция строк (обратные кавычки) использует результат array.toString(), который равен 1,2. Окружающие кавычки берутся буквально, что, вероятно, не то, что вам нужно. См. пример в самом конце Запрашивает документы для ArangoJS.

Даже если бы представление массива было ["1","2"], эти кавычки привели бы к "["1","2"]", что вызвало бы синтаксическую ошибку. С экранированными внутренними кавычками, такими как "[\"1\",\"2\"]", вы бы проверили u.id IN "some string", но оператор IN вернет 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'

Однако это не очень изящно, и, начиная с версии 6.7.0 ArangoJS, он фактически поддерживает вложенность литералов шаблона 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

person CodeManX    schedule 24.10.2018