Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve handling of option-heavy input parameters (e.g. Hasura) #495

Open
Krever opened this issue Jul 10, 2020 · 0 comments
Open

Improve handling of option-heavy input parameters (e.g. Hasura) #495

Krever opened this issue Jul 10, 2020 · 0 comments
Labels
client GraphQL Client module enhancement New feature or request tools Issue related to Caliban tools like code generation or schema comparison

Comments

@Krever
Copy link
Contributor

Krever commented Jul 10, 2020

In my experiment of migrating existing codebase (relying on Hasura graphql engine) I found out that the current Caliban approach to code generation is a bit cumbersome to work with in this particular case.
For the following graphql query that we had before

  query checkUserQuestionnaireAccess($id: uuid!, $username: String!) {
    change_request_aggregate(where: {id: {_eq: $id}, form: {project: {projectMembers: {username: {_eq: $username}}}}}) {
      change_request {
        count
      }
    }
  }

we had a sbt-graphql-based client that allowed us to execute it like this:

graphqlClient.query(checkUserQuestionnaireAccess)(_.Variables(questionnaireId, username))

With caliban, the same call in trivial impl has a form of

  protected def checkUserQuestionnaireAccess(questionnaireId: Int, username: String) = {
    import com.sony.crow.dms.app.graphql.codegen.DmsHasuraClient._
    val query = query_root.change_request_aggregate(where =
      Some(
        change_request_bool_exp(
          id = Some(Int_comparison_exp(_eq = Some(questionnaireId))),
          form = Some(
            form_bool_exp(project =
              Some(
                project_bool_exp(projectMembers =
                  Some(project_member_bool_exp(username = Some(String_comparison_exp(_eq = username)))),
                ),
              ),
            ),
          ),
        ),
      ),
    ) {
      change_request_aggregate.aggregate {
        change_request_aggregate_fields.count()
      }
    }
    query.toRequest()
  }

The problem originates from option-heavy, machine-generated types coming out of hasura engine. Examples for reference:

  case class String_comparison_exp(
      _eq: Option[String] = None,
      _gt: Option[String] = None,
      _gte: Option[String] = None,
      _ilike: Option[String] = None,
      _in: Option[List[String]] = None,
      _is_null: Option[Boolean] = None,
      _like: Option[String] = None,
      _lt: Option[String] = None,
      _lte: Option[String] = None,
      _neq: Option[String] = None,
      _nilike: Option[String] = None,
      _nin: Option[List[String]] = None,
      _nlike: Option[String] = None,
      _nsimilar: Option[String] = None,
      _similar: Option[String] = None,
  )
  case class change_request_bool_exp(
      _and: Option[List[Option[change_request_bool_exp]]] = None,
      _not: Option[change_request_bool_exp] = None,
      _or: Option[List[Option[change_request_bool_exp]]] = None,
      change_request_submissions: Option[change_request_submission_bool_exp] = None,
      created_at: Option[timestamptz_comparison_exp] = None,
      created_by: Option[String_comparison_exp] = None,
      description: Option[String_comparison_exp] = None,
      form: Option[form_bool_exp] = None,
      form_id: Option[Int_comparison_exp] = None,
      id: Option[Int_comparison_exp] = None,
      name: Option[String_comparison_exp] = None,
      object_id: Option[Int_comparison_exp] = None,
      object_snapshot: Option[jsonb_comparison_exp] = None,
      resolution: Option[change_request_resolution_bool_exp] = None,
      updated_at: Option[timestamptz_comparison_exp] = None,
      updated_by: Option[String_comparison_exp] = None,
  )

So its significantly longer due to the fact that the query is constructed in scala and not graphql. This issue was originally discussed on discord channel and the following was mentioned:

  1. options can be handled by cats .some syntax
  2. some dsl for primitive types comparison can be implemented (eventually even in a form of library)
    Example
def eq(s: String): Option[String_comparison_exp] = String_comparison_exp(_eq = s).some

project_member_bool_exp(username = eq(username)).some
  1. for non-primitive types the builder-like helper could be generated
  2. options could be also eliminated by using implicit conversions (which is a bad idea propbably, but could be done)

So the goal could be to have an API similar to:

val query = query_root.change_request_aggregate(where =
  _.withId(_._eq(questionnaireId))
    .withForm(_.withProject(_.withProjectMemebers(_.withUsername(_.eq(username))))
) {
    change_request_aggregate.aggregate {
      change_request_aggregate_fields.count()
    }
  }

Leaving it here as a feedback and reference point for further discussions

@ghostdogpr ghostdogpr added client GraphQL Client module tools Issue related to Caliban tools like code generation or schema comparison labels Jul 10, 2020
@ghostdogpr ghostdogpr added the enhancement New feature or request label Sep 12, 2020
@ghostdogpr ghostdogpr changed the title Improve handling of option-heavy input parameters in general and hasura in particular Improve handling of option-heavy input parameters (e.g. Hasura) Sep 12, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
client GraphQL Client module enhancement New feature or request tools Issue related to Caliban tools like code generation or schema comparison
Projects
None yet
Development

No branches or pull requests

2 participants