Support OR and parenthesis in the compiler

The compiler should add support for OR and parenthesis in the query language. Currently only AND is supported.

Proposal

To support OR and parenthesis, we can do it in the following steps:

  1. Introduce a new LogicalOperator type, and move both AND and OR to that type.
  2. Implement OR and parenthesis in the parser. Similar to the JS logic in https://gitlab.com/himkp/glql_parser/-/blob/master/src/parser.js#L256.
  3. The optimizer module should try to convert any OR statements to IN statements to optimize the query.
  4. Introduce an expander module that expands a tree containing parenthesis and OR to several trees containing just AND. This can be done by distributing the terms using a cartesian product. See https://gitlab.com/himkp/glql_parser/-/blob/master/src/expander.js.
  5. Modify the code generator to handle multiple trees.
  6. Set a limit on the complexity of the queries. Reject any queries that expand to more than 10 separate queries (as an example).
  7. The final output would still be a single GraphQL call. GraphQL allows you to combine multiple queries in a single call.

Example:

Query: (project = "gitlab-org/gitlab" AND milestone = "17.4") OR (project = "gitlab-org/gitlab-query-language/gitlab-query-language" AND milestone = "0.0.5-rc2")

should be expanded to two queries: project = "gitlab-org/gitlab" AND milestone = "17.4" and project = "gitlab-org/gitlab-query-language/gitlab-query-language" AND milestone = "0.0.5-rc2"

Should return the following GraphQL query:

{
  project1: project(fullPath: "gitlab-org/gitlab") {
    issues(milestoneTitle: "17.4") {
      nodes {
        iid
        title
        webUrl
      }
    }
  }
  project2: project(
    fullPath: "gitlab-org/gitlab-query-language/gitlab-query-language"
  ) {
    issues(milestoneTitle: "0.0.5-rc2") {
      nodes {
        iid
        title
        webUrl
      }
    }
  }
}

For some cases, we could even simplify this to use the projects query:

Query: (project = "gitlab-org/gitlab" or project = "gitlab-org/gitlab-query-language/gitlab-query-language") and milestone = "17.4"

{
  projects(
    fullPaths: ["gitlab-org/gitlab", "gitlab-org/gitlab-query-language/gitlab-query-language"]
  ) {
    nodes {
      issues(milestoneTitle: "17.4") {
        nodes {
          iid
          title
          webUrl
        }
      }
    }
  }
}

Optional: Allow IN operator on more fields, since OR and IN are equivalent. So we could do: project in ("gitlab-org/gitlab", "gitlab-org/gitlab-query-language/gitlab-query-language") and milestone = "17.4" instead.

Open questions

  • How do we handle limits across OR operations?
  • How do we handle sort order and pagination across OR operations?
Edited by Himanshu Kapoor