How do you pass SET parameters using pyTigerGraph

I have a query that requires SET parameters for a NOT IN where clause. I’m having problems with sending that through pyTigerGraph. For instance the simple query

CREATE QUERY test_passing_parameters(SET<string> params) FOR GRAPH plustoken { 
  /* Write query logic here */ 
  PRINT params; 
}

from the GSQL client works as expected:

GSQL > run query test_passing_parameters(["hola", "mundo"])
{
  "error": false,
  "message": "",
  "version": {
    "schema": 2,
    "edition": "enterprise",
    "api": "v2"
  },
  "results": [{"params": [
    "mundo",
    "hola"
  ]}]
}

But that same query sent through pyTigerGraph:

conn.runInstalledQuery("test_passing_parameters", params={"params": ["hola", "mundo"]})

returns a list of a single string:

[{'params': ["['hola', 'mundo']"]}]

What is the right format for sending SET parameters in Python?

Hi,

I am not very familiar with pyTigerGraph, but I just took a look at the source code. It uses the urllib.parse module to parse parameters from dict to query strings and appends the query strings to the end of the URL. This means that {"params": ["hola", "mundo"]} becomes 'params=%5B%27hola%27%2C%20%27mundo%27%5D', which is ['hola', 'mundo'] when decoded.

When parameters are supplied in query strings, TigerGraph’s Run installed query REST endpoint needs sets and bags to be formatted as params=hola&params=mundo in order for RESTPP to parse the parameters correctly. See Query String Parameters, so ['hola', 'mundo'] won’t work.

What you can do is format your params as query strings to begin with. That way, pyTigerGraph won’t try to change it:
conn.runInstalledQuery("test_passing_parameters", params="params=hola&params=mundo")

I just tested it and it seems to work:
>>> conn.runInstalledQuery("setTest", params="params=hola&params=mundo") [{'params': ['mundo', 'hola']}]

Hope this helps!

Best,
Lenny

2 Likes

Thanks, it worked!! If I have time, this is a good candidate for a PR so I don’t need to remember this witchery.

Note that this technique doesn’t just apply to pyTigerGraph, but also applies to any API calls where you want to pass multiple values for a SET argument, here is another example

import requests 
graphQuery = 'zMarkTest?params=hola&params=mundo' 
myUrl = 'https://' + graphServer + ':' + graphPort + '/query/' + graphName + '/' + graphQuery  
response = requests.get(myUrl) 
print ("status = ", response.status_code, '\n') 
r = response.json()
1 Like

Just my 2 cents as a developer. If an API is exposing a set or bag and I’m working in Python I would expect those concepts to be mapped to set and list. Same thing if I’m doing Java, I would expect java.util.Set and java.util.List. Right now you are exposing the internal implementation to the API users, in fact the resolution of the issue involved digging into the HTTP calls in the code.

I would strongly encourage to make a more idiomatic API.

1 Like

@Mohamed_Zrouga @Jon_Herke - It would be great if we could get lists in the values of parameter dictionaries to be passed as a set of data into queries (especially for the data science library algos)

1 Like

The following solution has been developed for this:

When specifying parameter values in a dictionary:

  • For primitive parameter types use

    "key": value
    
  • For SET and BAG parameter types with primitive values, use

    "key": [value1, value2, ...]
    
  • For VERTEX<type> use

    "key": primary_id
    
  • For VERTEX (no vertex type specified) use

    "key": (primary_id, "vertex_type")
    
  • For SET<VERTEX<type>> use

    "key": [primary_id1, primary_id2, ...]
    
  • For SET<VERTEX> (no vertex type specified) use

    "key": [(primary_id1, "vertex_type1"), (primary_id2, "vertex_type2"), ...]
    

For example, if your query’s formal parameter list is like:

CREATE QUERY query4_all_param_types(
    INT                   p01_int
  , UINT                  p02_uint
  , FLOAT                 p03_float
  , DOUBLE                p04_double
  , STRING                p05_string
  , BOOL                  p06_bool
  , VERTEX                p07_vertex
  , VERTEX<vertex4>       p08_vertex_vertex4
  , DATETIME              p09_datetime
  , SET<INT>              p10_set_int
  , BAG<INT>              p11_bag_int
//, FILE                  p12_file
  , SET<VERTEX>           p13_set_vertex
  , SET<VERTEX<vertex4>>  p14_set_vertex_vertex4
) ...

…then you can call it from Python like this:

params = {
    "p01_int": 1,
    "p02_uint": 1,
    "p03_float": 1.1,
    "p04_double": 1.1,
    "p05_string": "test <>\"'`\\/{}[]()<>!@£$%^&*-_=+;:|,.§±~` árvíztűrő tükörfúrógép 👍",
    "p06_bool": True,
    "p07_vertex": (1, "vertex4"),
    "p08_vertex_vertex4": 1,
    "p09_datetime": datetime.now(),
    "p10_set_int": [1, 2, 3, 2, 3, 3],  # Intentionally bag-like, to see it behaving as set
    "p11_bag_int": [1, 2, 3, 2, 3, 3],
    "p13_set_vertex": [(1, "vertex4"), (2, "vertex4"), (3, "vertex4")],
    "p14_set_vertex_vertex4": [1, 2, 3]
}

conn.runInstalledQuery("query4_all_param_types", params)

Where vertex4 is (obviously) a vertex type.
This will be available soon (planned for pyTigerGraph v0.1).

3 Likes

Why is this solution client-specific?
It needs not be pyTigerGraph specific, but rather support any REST calls to the query.
In my case, I’m using JavaScript to construct the query call, and I cannot find a way to pass an array of strings: [“H1”,“H2”] to a SET parameter.
This is my query signature:

CREATE QUERY createCaseInvitation(VERTEX<ProblemCase> keyProblemCase, SET<STRING> helpersSet) FOR GRAPH SimplifyPilotADEV SYNTAX V1 { 
  FOREACH h IN helpersSet DO

  END;
}

I cannot pass an array that looks like this: [“H1”,“H2”] as the helpersSet parameter from my JavaScript app.