ChilliCream / graphql-platform

Welcome to the home of the Hot Chocolate GraphQL server for .NET, the Strawberry Shake GraphQL client for .NET and Banana Cake Pop the awesome Monaco based GraphQL IDE.
https://chillicream.com
MIT License
5.27k stars 748 forks source link

F# Record and Purecode First schema Generation #2143

Closed aammfe closed 1 year ago

aammfe commented 4 years ago

Describe the bug While using F# Record in Purecode First schema Generation Hot throw following exception HotChocolate.SchemaException: 'Unable to infer or resolve a schema type from the type reference Input: System.Collections.IEqualityComparer.'

image

To Reproduce Steps to reproduce the behavior:

  1. F# code type Article = {ArticleId:string; Name:string }
  2. Repository

    public class BookService
        {
            private readonly IMongoCollection<Article> _articles;
    
            public BookService(IBookstoreDatabaseSettings settings)
            {
                var client = new MongoClient(settings.ConnectionString);
                var database = client.GetDatabase(settings.DatabaseName);
    
                _articles = database.GetCollection<Article>("Article");
            }
    
            public IQueryable<Article> GetArticles() => _articles.AsQueryable();
    }
  3. Query

    public class QueryType
        {
            private readonly BookService bookService;
    
            public QueryType(BookService bookService)
            {
                this.bookService = bookService;
            }
    
            [UseFiltering]
            public IQueryable<Article> GetArticles()
            {
                return bookService.GetArticles();
            }
        }
  4. Startup.cs

    services.AddGraphQL(sp => SchemaBuilder.New()
                .AddQueryType<QueryType>()
                .Create());

Expected behavior HotChoclate Should work with any .net type as it does with C#

michaelstaib commented 4 years ago

We will have a look at it although it will take a while since at the moment we are focusing on the next major version of hot chocolate. If you want to try to implement this please go ahead.

landy commented 3 years ago

Hello, I would like to help with this but I'm really lost in the codebase and don't know where to start. Are there any pointers or something that would help me to try to implement this?

michaelstaib commented 3 years ago

HI @landy,

we can help. Are you on our slack channel?

timotheegloerfeld commented 3 years ago

For anyone tripping over this, it is possible to work around this by using [\<ReferenceEquality>] on your records

sep2 commented 3 years ago

For anyone tripping over this, it is possible to work around this by using [] on your records

@timotheegloerfeld Did you find a way to represent non-nullable type in F# record?

sep2 commented 3 years ago

For anyone tripping over this, it is possible to work around this by using [] on your records

@timotheegloerfeld Did you find a way to represent non-nullable type in F# record?

Never mind, I found this [<GraphQLNonNullType>] attribute is exactly what I want.

wonbyte commented 3 years ago

For anyone tripping over this, it is possible to work around this by using [] on your records

@timotheegloerfeld I noticed that if my Record type contains an option then the equality error still occurs. Have you encountered this?

timotheegloerfeld commented 3 years ago

Yes I have encountered this too. Options don't seem to work as of now. Unfortunately I didn't have much time lately to investigate or setup unit tests as suggested in #2103

wonbyte commented 3 years ago

@landy I am beginning work on this if you want to help out!

AlexeyRaga commented 3 years ago

@wonbyte Do you have a branch and/or a set of tasks that are to be done? Potentially my colleagues an I may be able to dedicate some time to it and help

michaelstaib commented 3 years ago

@AlexeyRaga we did not get started on this so of you want to help just jump in. I can update the current sharp branch. What we need are test cases first. Essentially schema snapshot tests so that we see various sharp constructs to build a schema. Once we have the tests we can fix how things are inferred.

AlexeyRaga commented 3 years ago

@michaelstaib sounds good! Can you point me to an example of such a test? I assume that you should have plenty of them for C#, so I can follow the same pattern?

michaelstaib commented 3 years ago

In this case we are interested in schema snapshot tests, which are simple to write. Essentially we setup a new service collection and configure our GraphQL server, at the end we use the extension method BuildSchemaAsync to create a schema from our configuration. We are using snapshooter to create a SDL representation of the schema MatchSnapshot. Essentially if this test succeeds it creates a schema representation that can be reviewed and every new test run validates against this snapshot.

[Fact]
public async Task EnsureThatFieldsWithDifferentCasingAreNotMerged()
{
    await new ServiceCollection()
        .AddGraphQL()
        .AddQueryType<QueryFieldCasing>()
        .BuildSchemaAsync()
        .MatchSnapshotAsync();
}
michaelstaib commented 3 years ago

I will update the F# branch and you can do a PR to the branch.

AlexeyRaga commented 3 years ago

@michaelstaib awaiting for the branch to be rebased

Ciantic commented 3 years ago

I know this is not implemented yet, but I suspect I got a same problem, when trying to use CliMutable records, e.g.:

Unable to infer or resolve a schema type from the type reference Input: IEqualityComparer. (HotChocolate.Types.ObjectType<.Program.Person>)

Here is an easy repro:

With F#:

open System
open Microsoft.AspNetCore.Builder
open Microsoft.Extensions.Hosting
open Microsoft.Extensions.DependencyInjection
open Microsoft.EntityFrameworkCore 
open HotChocolate.Types 
open HotChocolate.Data
open HotChocolate;

[<CLIMutable>]
type Person =
    { Id : Guid
      FirstName : string
      LastName : string
      Address : string
      City : string}

type AppDbContext(opts) =
    inherit DbContext(opts)
    member this.Persons = this.Set<Person>()

type Query() =
    [<UsePaging>]
    [<UseProjection>]
    [<UseFiltering>]
    [<UseSorting>]
    member this.Persons ([<Service>] dbContext: AppDbContext) =
        dbContext.Persons

[<EntryPoint>]
let main args =

    let builder = WebApplication.CreateBuilder(args)

    builder.Services
            .AddDbContext<AppDbContext>(
                fun opts -> opts.UseSqlite("Data Source=foo.sqlite") |> ignore
            )
            .AddGraphQLServer()
            .AddQueryType<Query>()
            .AddFiltering()
            .AddSorting()
            .AddProjections() |> ignore

    let app = builder.Build()

    app.UseDeveloperExceptionPage() |> ignore
    app.UseRouting() |> ignore
    app.MapGraphQL() |> ignore

    let createDb =
        use scope = app.Services.CreateScope()
        let db = scope.ServiceProvider.GetRequiredService<AppDbContext>()
        db.Database.EnsureDeleted() |> Console.WriteLine
        db.Database.EnsureCreated() |> Console.WriteLine

    createDb

    app.Run()

    0 // Exit code
  <ItemGroup>
    <PackageReference Include="EntityFrameworkCore.FSharp" Version="6.0.2" />
    <PackageReference Include="HotChocolate.AspNetCore" Version="12.2.1" />
    <PackageReference Include="HotChocolate.Data" Version="12.3.0" />
    <PackageReference Include="HotChocolate.Data.EntityFramework" Version="12.3.0" />
    <PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.0" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="6.0.0" />
  </ItemGroup>
Junocaen commented 3 years ago

The f# records are just .net classes, but with more interfaces implemented by default to gain amongst other the value equality. I suspect a C# class with IEqualityComparer implemented might generate the same exception. Maybe Hot Choco does not support any interface implementation for graphql types?

Disable both comparison and equality on your F# types like below. That might solve the issue for you too.

// disable f# equality since Hotchocolate 12.0.0-preview.27 will throw the error below
// Unable to infer or resolve a schema type from the type reference `Input: IEqualityComparer`. (HotChocolate.Types.ObjectType<ConferencePlanner.GraphQL.Data.AddSpeakerPayload>)
[<NoComparison; NoEquality>]
type AddSpeakerPayload = { Speaker: Speaker; Errors: Errors }
adelarsq commented 2 years ago

I am interested on this. Send some love for F# :)

adelarsq commented 2 years ago

It's there any work on this issue?

AlexeyRaga commented 2 years ago

Looks like there is none :(

michaelstaib commented 2 years ago

@AlexeyRaga we need a couple of F# natives to help us. If there is interest join us on slack and lets get started.

https://slack.chillicream.com

AlexeyRaga commented 1 year ago

Looks like the work is being done here: https://github.com/ChilliCream/graphql-platform/pull/5595

glen-84 commented 1 year ago

@AlexeyRaga @michaelstaib Was this resolved by #5973?

AlexeyRaga commented 1 year ago

@glen-84 Partially, yes. We should be OK now for the equality stuff, and we should be able to use Option.

More work is required to make it a nice F# experience, though, for example:

When these two are done, I'll call it a decent F# support :)

glen-84 commented 1 year ago

Thanks for the summary, though I'm asking more specifically about this particular issue – has the error in the OP been resolved? If so, I'll go ahead and close this issue. 🙂