Skip to content
This repository was archived by the owner on Sep 3, 2021. It is now read-only.

Feature request: A 'cypher' template literal tag for @cypher statements #425

Closed
michaeldgraham opened this issue May 2, 2020 · 3 comments

Comments

@michaeldgraham
Copy link
Collaborator

michaeldgraham commented May 2, 2020

This issue requests support for a cypher template literal tag for use in writing the Cypher statement argument of @cypher directive fields. Using a cypher tag would result in support for Cypher syntax highlighting in any editor using an extension that provides highlighting support for it, such as the Cypher Query Langauge Tools for Neo4j extension for Visual Studio Code.

This would result in a smoother experience when reading and writing Cypher within a GraphQL schema using @cypher fields, especially for multi-line Cypher statements. A GraphQL block string is currently used to support a multi-line String type directive argument. This results in an absense of syntax highlighting support within such arguments. In the Federation example for the inventory service, the @cypher statement for the shippingEstimate field on the Product entity would normally be as follows:

Situation

shippingEstimate: Int
  @requires(fields: "weight price")
  @cypher(statement: """
    CALL apoc.when($price > 900,
      // free for expensive items
      'RETURN 0 AS value',
      // estimate is based on weight
      'RETURN $weight * 0.5 AS value',
      {
        price: $price,
        weight: $weight
      })
    YIELD value
    RETURN value.value
  """)

An implementation for a cypher tag template for the statement argument of a @cypher directive might look like:

Implementation

export const cypher = (statement, ...substitutions) => {
  // Get the array of string literals
  const literals = statement.raw;
  // Add each substitution inbetween all
  const composed = substitutions.reduce((composed, substitution, index) => {
    // Add the string literal
    composed.push(literals[index]);
    // Add the substitution proceeding it
    composed.push(substitution);
    return composed;
  }, []);
  // Add the last literal
  composed.push(literals[literals.length - 1]);
  // Return the Cypher statement string as a GraphQL block string
  // for the `@cypher` directive statement argument
  return `statement: """${composed.join('')}"""`;
};

Example

With the Cypher statement argument being provided as the result of the above cypher tag implementation, we could write the shippingEstimate's @cypher statement within another string literal with the tag, used as an embedded expression within the string literal containing the GraphQL schema SDL (which is the case when using a gql tag). The Cypher would then be appropriately highlighted in an editor with Cypher language support for the tag.

shippingEstimate: Int
  @requires(fields: "weight price")
  @cypher(${cypher`
    CALL apoc.when($price > 900,
      // free for expensive items
      'RETURN 0 AS value',
      // estimate is based on weight
      'RETURN $weight * 0.5 AS value',
      {
        price: $price,
        weight: $weight
      })
    YIELD value
    RETURN value.value
  `})

Using the Cypher Query Langauge Tools for Neo4j extension for Visual Studio Code:

image

Additional possibilities

  • Statements as variables

    The Cypher statement of a @cypher directive using a cypher tag could also be elevated to a
    variable, which could be imported.

matchUsers.js
import { cypher } from 'neo4j-graphql-js';

export MATCH_USERS = cypher`
  MATCH (users: User)
  RETURN users
`;
typeDefs.js
import { MATCH_USERS } from 'matchUsers.js';

const typeDefs = gql`
  type Query {
    Users: [User] @cypher(${
      MATCH_USERS
    })
  }
  type User {
    id: ID!
    name: String
  }
`;
  • Validation and analysis

    A Cypher statement using a cypher tag could be processed using additional behaviours added
    to its implementation, such as validation and analysis.

@benjamin-rood
Copy link

benjamin-rood commented May 3, 2020

@michaeldgraham Why did you close this? Sounds useful to me.

@michaeldgraham
Copy link
Collaborator Author

It's been implemented in the referenced PR :)

@benjamin-rood
Copy link

Yay!

# for free to subscribe to this conversation on GitHub. Already have an account? #.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants