FSharp.Data.GraphQL
FSharp.Data.GraphQL copied to clipboard
Q: Print AST to string?
Description
Question: is it possible to print the AST to a string (latest master)? The ToString() impl primarily prints x.name + "!". I'm trying to build a F# to GraphQL generating using your Shared lib.
OT: can you split the Shared lib to a separate nuget please? That way I don't have to reference either the client or server to work with the object model.
Similarly, why are the Ast constructors internal? I would prefer to be able to do a 1-1 mapping from F#'s AST to the GQL AST without going through the builders (I think).
Hi @haf
Can you clarify as to which constructors are internal?
Thanks, John
@johnberzy-bazinga It was FieldDefinition, ScalarDefinition, etc, but I moved the TypeDefinitions to the Ast module (see #249) and then I can use them.
@haf Is your plan to generate code based on GraphQL SDL documents? if that's the case, would you consider modifying our existing parser to do that? We have a use case for that in our client provider so we're planning to eventually support SDL documents.
@johnberzy-bazinga Actually I'm going the other way, from F# to SDL right now.
I've written a basic transpiler from F# to GraphQL SDL based on the F# compiler services and I'm using the AST in both languages, and I've written an GQL AST -> text printer. This is a currently passing test:
let interfaces = [
let humanBoyA = parseFSharp """
/// All humans are of type Human
type Human =
/// They have names...
abstract name: string
/// A boy is a human with a name and a birthdate
type Boy =
/// A boy has no name?
{ name: string
/// When?
born: Instant }
interface Human with
member x.name = x.name
"""
yield testCaseAsync "transpile interface" <|
async {
let! xs = humanBoyA
xs
|> GraphQL.encodeTypeDefinitions
|> Expect.sequenceEqual "Should create one interface and one object" [
let ifFields = [ FD.create ("name", NN (N "String"), "They have names...") ]
yield InterfaceTypeDefinition (ITD.create ("Human", ifFields, "All humans are of type Human"))
let objFields = [
FD.create ("name", NN (N "String"), "A boy has no name?")
FD.create ("born", NN (N "DateTime"), "When?")
]
let objIfs = [ "Human" ]
yield OTD.create ("Boy", objFields, "A boy is a human with a name and a birthdate", objIfs)
|> ObjectTypeDefinition
]
}
yield testCaseAsync "print interface and type" <|
async {
let! xs = humanBoyA
let str =
xs
|> GraphQL.encodeTypeDefinitions
|> Seq.map GraphQL.mapToString |> String.concat "\n"
let expected = """
"All humans are of type Human"
type Human {
"They have names..."
name: String!
}
"A boy is a human with a name and a birthdate"
type Boy implements Human {
"A boy has no name?"
name: String!
"When?"
born: DateTime!
}
"""
str
|> Expect.stringContains "Should have the expected contents" (expected.Trim([| '\n' |]))
}
]
I'll consider sending it back, if you reciprocate by cleaning up the pull requests that have been lingering; that way I can rebase my changes on top of the latest features and bugfixes.
@haf That's pretty cool. We have had similar ideas to introduce a reflection-based schema with the use of attributes for metadata such as descriptions. Your approach is nice since you can just extract the comments from source. Do you have a bit of time to join our gitter for a chat? We're working on some changes for 2.0 release that will have some breaking changes. Would be good to coordinate with you.
@johnberzy-bazinga I've joined now