Search code examples
javascriptarangodbaqlfoxx

aql.literal is not a fucntion in arangoDB Foxx


I have a Foxx route like the following

 const aql = require('@arangodb').aql;

    route.get('ABC'){function(req,res){
    //Do some stuffs
    var AnArray1=req.queryParams.AnArray1||[DefaulArray]
    var AnArray2=req.queryParams.AnArray2||[DefaulArray]

    //Turn them into segment to put into AQL
 var segment=aql.literal(AnArray1.length>0 ? 'AND  u.Code IN '+ JSON.stringify(AnArray1)  : '');

    }
    .queryParam('AnArray1', joi.any())
    .queryParam('AnArray2', joi.any())
    .response(['json/application'], 'Done task')

This throw back an aql.literal is not a function. This is very strange to me since I thought it is a built-in.The version of arango is 3.3.5

Where did I went wrong?


Solution

  • v3.3.5 is 8 months old (released 2018-03-28), aql.literal was added in v3.3.9 (2018-05-17):

    An update to the latest 3.3 version (currently v3.3.17 from 2018-10-04) should fix the problem.

    How you use aql.literal() doesn't look very safe in regards to AnArray1. There is no schema validation that would ensure that it's an array (joi.any()) and you don't test for the type at any later point. Strings would actually pass req.queryParams.AnArray1||[DefaulArray] and AnArray1.length>0, and you would end up with a query segment like AND u.Code IN "some string", which will always be false.

    The combination of aql.literal() and JSON.stringify is not recommended anymore. Starting with ArangoJS version 6.7.0 and ArangoDB v3.4.0-RC.2 in Foxx, nesting of AQL template strings is supported:

    var coll = db.collection('test')
    var AnArray1 = [ "foo", 2, -0.1, true, null, [ false, { bar: true } ] ]
    
    var segment = (
      Array.isArray(AnArray1) && AnArray1.length > 0
      ? aql`AND u.Code IN ${AnArray1}`
      : undefined
    )
    var fullQuery = aql`FOR u IN ${coll} FILTER u.attr == true ${segment} RETURN u`
    

    This results in fullQuery being:

    {
       query: 'FOR u IN @@value0 FILTER u.attr == true AND u.Code IN @value1 RETURN u',
       bindVars: {
         '@value0': 'test',
         value1: [ 'foo', 2, -0.1, true, null, [false, { bar: true } ] ]
       }
    }
    

    With var AnArray1 = "foo" you get this instead:

    {
      query: 'FOR u IN @@value0 FILTER u.attr == true  RETURN u',
      bindVars: { '@value0': 'test' }
    }
    

    As long as you want to AND combine FILTER criteria my suggestion would be to use

    aql`FILTER u.Code IN ${AnArray1}`
    

    because you can then use this segment as filter on its own, whereas AND ... might not be valid in the full query (FILTER AND ...).