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

Add Parser support for Type System Extensions #266

Conversation

jorge-vasquez-2301
Copy link
Contributor

closes #238

@jorge-vasquez-2301 jorge-vasquez-2301 changed the title Add support for Type System Extensions [WIP] Add support for Type System Extensions Mar 6, 2020
@jorge-vasquez-2301 jorge-vasquez-2301 force-pushed the Type_System_Extensions_Supported_By_Parser branch 2 times, most recently from 7247a3f to 8fb5a59 Compare March 6, 2020 12:36
@jorge-vasquez-2301 jorge-vasquez-2301 changed the title [WIP] Add support for Type System Extensions Add support for Type System Extensions Mar 6, 2020
@jorge-vasquez-2301 jorge-vasquez-2301 force-pushed the Type_System_Extensions_Supported_By_Parser branch from 8fb5a59 to a818c15 Compare March 6, 2020 13:33
@jorge-vasquez-2301 jorge-vasquez-2301 changed the title Add support for Type System Extensions Add Parser support for Type System Extensions Mar 6, 2020
Copy link
Owner

@ghostdogpr ghostdogpr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks very good! The only thing missing is the valid case where no field is provided but only directives/implements/etc. It'll make the parser a bit more complex unfortunately but we have to support all valid syntax 😄

@jorge-vasquez-2301
Copy link
Contributor Author

@ghostdogpr Thanks for looking into this! And yeah, I totally missed the alternative cases, so I'll make sure to add them 😀

@jorge-vasquez-2301 jorge-vasquez-2301 force-pushed the Type_System_Extensions_Supported_By_Parser branch 7 times, most recently from a75bf22 to e0bb285 Compare March 10, 2020 15:26
Copy link
Owner

@ghostdogpr ghostdogpr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While this is working well, I suggest modeling the parsers more strictly after the spec. In some cases (like object) it will be a little simpler, but the main benefit is that it's easier to find which code corresponds to which spec definition When specs will evolve in the future I think it might be easier to apply the changes if the code follows it closely. What do you think?

private def objectTypeExtension[_: P]: P[ObjectTypeExtension] =
P(
"extend type" ~/ (
objectTypeExtensionWithInterfacesAndOptionalFields |
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can reduce to 3 cases:

  • fields + optional interfaces + optional directives
  • no fields + directives + optional interfaces
  • no fields, no directives, interfaces

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ghostdogpr Yeah, actually my first attempt was modelling the Parser more strictly after the specs, like this:

private def objectTypeExtensionWithOptionalInterfacesOptionalDirectivesAndFields[_: P]: P[ObjectTypeExtension] =
    P(name ~ implements.? ~ directives.? ~ "{" ~ fieldDefinition.rep ~ "}").map {
      case (name, implements, directives, fields) =>
        ObjectTypeExtension(
          name,
          implements.getOrElse(Nil),
          directives.getOrElse(Nil),
          fields.toList
        )
    }

  private def objectTypeExtensionWithOptionalInterfacesAndDirectives[_: P]: P[ObjectTypeExtension] =
    P(name ~ implements.? ~ directives).map {
      case (name, implements, directives) =>
        ObjectTypeExtension(
          name,
          implements.getOrElse(Nil),
          directives,
          Nil
        )
    }

  private def objectTypeExtensionWithInterfaces[_: P]: P[ObjectTypeExtension] =
    P(name ~ implements).map {
      case (name, implements) =>
        ObjectTypeExtension(
          name,
          implements,
          Nil,
          Nil
        )
    }


  private def objectTypeExtension[_: P]: P[ObjectTypeExtension] =
    P(
      "extend type" ~/ (
        objectTypeExtensionWithOptionalInterfacesOptionalDirectivesAndFields |
          objectTypeExtensionWithOptionalInterfacesAndDirectives |
          objectTypeExtensionWithInterfaces
      )
    )

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

However, that didn't work as expected, when running unit tests I've got failures for some cases. Here are the error messages I got (I've enabled verboseFailures temporally):

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

 extend type with interfaces and directives
[info]     Fiber failed.
[info]     A checked error was not handled.
[info]     Parsing Error: Expected document:1:1 / objectTypeExtension:1:1 / objectTypeExtensionWithOptionalInterfacesOptionalDirectivesAndFields:1:13 / "{":1:58, found "" 

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

extend type with directives
[info]     Fiber failed.
[info]     A checked error was not handled.
[info]     Parsing Error: Expected document:1:1 / objectTypeExtension:1:1 / objectTypeExtensionWithOptionalInterfacesOptionalDirectivesAndFields:1:13 / "{":1:33, found "" 

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've tried other combinations as well, but none of them worked for all cases, that's why I had to implement the parser rules in a different way.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think @ghostdogpr? Maybe I'm missing something?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm that’s strange indeed. I can’t see anything wrong with the code at first sight but tomorrow I’ll get your branch and try to figure it out in debug.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And, I got similar issues when I tried to define parsers for the other type extension cases

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome, thanks for your help @ghostdogpr!

}

private def schemaExtension[_: P]: P[SchemaExtension] =
P("extend schema" ~/ (schemaExtensionWithDirectivesAndOptionalOperations | schemaExtensionWithOperations))
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about sticking to the spec definitions and have:

  • operations + optional directives
  • no operations, directives

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similarly to the above case, my first version was more like the spec definitions:

private def schemaExtensionWithOptionalDirectivesAndOperations[_: P]: P[SchemaExtension] =
    P(directives.? ~ "{" ~ rootOperationTypeDefinition.rep ~ "}").map {
      case (directives, ops) =>
        val opsMap = ops.toMap
        SchemaExtension(
          directives.getOrElse(Nil),
          opsMap.get(OperationType.Query).map(_.name),
          opsMap.get(OperationType.Mutation).map(_.name),
          opsMap.get(OperationType.Subscription).map(_.name)
        )
    }

  private def schemaExtensionWithDirectives[_: P]: P[SchemaExtension] =
    P(directives).map(SchemaExtension(_, None, None, None))

  private def schemaExtension[_: P]: P[SchemaExtension] =
    P("extend schema" ~/ (schemaExtensionWithOptionalDirectivesAndOperations | schemaExtensionWithDirectives))

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

However, this didn't work for all cases, I got an error for one of the unit tests:

extend schema with directives
[info]     Fiber failed.
[info]     A checked error was not handled.
[info]     Parsing Error: Expected document:1:1 / schemaExtension:1:1 / schemaExtensionWithOptionalDirectivesAndOperations:1:15 / "{":1:30, found "" 

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried other combinations that were more similar to the specs too, but none of them worked

@ghostdogpr
Copy link
Owner

@jorge-vasquez-2301 OK, I found the reason. You just need to change the ~/ into ~ in def directive. Otherwise it takes the first path and "cuts" which means it won't go back and try the other possibilities.

@jorge-vasquez-2301
Copy link
Contributor Author

Ohhhh, didn't realize that, thanks @ghostdogpr! I'll make the adjustments

@jorge-vasquez-2301 jorge-vasquez-2301 force-pushed the Type_System_Extensions_Supported_By_Parser branch from e0bb285 to 392af77 Compare March 12, 2020 12:23
Copy link
Owner

@ghostdogpr ghostdogpr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All good! Thanks for the contribution!

@ghostdogpr ghostdogpr merged commit 7d5ded8 into ghostdogpr:master Mar 12, 2020
@jorge-vasquez-2301 jorge-vasquez-2301 deleted the Type_System_Extensions_Supported_By_Parser branch March 12, 2020 15:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support type system extensions in Parser
2 participants