This is what PathQL does in one sentence:

PathQL allows grouping and nesting of the results of a complex SQL query using JSONPath notation in SQL column aliases

This is what PathQL does in one example:

select 
    posts.id as "$.posts[].id", 
    comments.id as "$.posts[].comments[].id" 
from 
    posts, 
    comments 
where 
    post_id = posts.id and
    posts.id = 1 

Without PathQL the results would be (wrong):

[
    {
      "$.posts[].id": 1,
      "$.posts[].comments[].id": 1
    },
    {
      "$.posts[].id": 1,
      "$.posts[].comments[].id": 2
    }
]

With PathQL the results will be (correct):

{
    "posts": [
        {
            "id": 1,
            "comments": [
                {
                    "id": 1
                },
                {
                    "id": 2
                }
            ]
        }
    ]
}

The rows have been merged into a tree according to the paths specified in the column aliases.

JSON path syntax

In JSONPath a language is defined for reading data from a path in a JSON document. We need a langauge to write data to a path in a JSON document and that is why we only use a subset of the JSONPath operators:

  • ”$” root element
  • ”.” object child operator
  • ”[]” array element operator

Note that the brackets should always be empty as the index in the array is determined by the path merging algorithm.

Base path

The path “$[].posts.id” consists of two parts “$[].posts” (the base path) and it’s last segment “id” (the property name). Only columns that have an alias starting with a “$” are defining a new base path. Any other alias or column name is treated as a property name.

The full path of a column can be constructed by combining the last specified base path with the property name. The initial base path for every query is “$[]”.

Thus queries without specified paths generate a simple object per result row:

SELECT * FROM posts;

[
    {
        "id": 1,
        "title": "Hello world!"
    },
    ...(more rows)...
]

Columns that follow a column with a specified path will inherit the base path:

SELECT id as "$[].post.id", title FROM posts;

[
    {
        "post": {
            "id": 1,
            "title": "Hello world!"
        }
    },
    ...(more rows)...
]

Note that duplicate and/or conflicting paths trigger an error message.

PathQL web API

A path engine implementation can be added to any DBAL. Before it is a PathQL web API you also need to implement the JSON conversion and HTTP handling.

Here is an example showing how to “speak” PathQL over HTTP(S). The request:

POST /pathql HTTP/1.1
Content-Type: application/json

{"query":"select posts.id as \"$.posts[].id\", comments.id as \"$.posts[].comments[].id\" 
from posts, comments where post_id = posts.id and posts.id = :id;","params":{"id":1}}

And the response:

Content-Type: application/json

{"posts":[{"id":1,"comments":[{"id":1},{"id":2}]}]}

As you can see you should make an endpoint named “pathql” that accepts and returns JSON. The request should be sent in the POST body as a JSON object with properties “query” and “params”, where “query” must be a (SQL) string with named parameters and “params” must be the set of named parameters that should be applied.