{"id":26243469,"url":"https://github.com/landmarkhw/dapper.graphql","last_synced_at":"2025-04-07T06:11:30.892Z","repository":{"id":45732269,"uuid":"110851540","full_name":"landmarkhw/Dapper.GraphQL","owner":"landmarkhw","description":"A .NET Core library designed to integrate the Dapper and graphql-dotnet projects with ease-of-use in mind and performance as the primary concern.","archived":false,"fork":false,"pushed_at":"2024-05-10T17:09:55.000Z","size":150,"stargazers_count":290,"open_issues_count":12,"forks_count":50,"subscribers_count":19,"default_branch":"master","last_synced_at":"2025-04-07T06:11:26.310Z","etag":null,"topics":["dapper","dotnet-core","graphql","graphql-dotnet"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/landmarkhw.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2017-11-15T15:32:07.000Z","updated_at":"2024-11-19T04:03:59.000Z","dependencies_parsed_at":"2024-01-05T20:52:05.903Z","dependency_job_id":"bab3494f-77d4-4b2b-ba03-96b46dd56a37","html_url":"https://github.com/landmarkhw/Dapper.GraphQL","commit_stats":null,"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/landmarkhw%2FDapper.GraphQL","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/landmarkhw%2FDapper.GraphQL/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/landmarkhw%2FDapper.GraphQL/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/landmarkhw%2FDapper.GraphQL/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/landmarkhw","download_url":"https://codeload.github.com/landmarkhw/Dapper.GraphQL/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247601448,"owners_count":20964864,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dapper","dotnet-core","graphql","graphql-dotnet"],"created_at":"2025-03-13T10:20:32.275Z","updated_at":"2025-04-07T06:11:30.877Z","avatar_url":"https://github.com/landmarkhw.png","language":"C#","readme":"# Dapper.GraphQL\nA library designed to integrate the Dapper and graphql-dotnet projects with ease-of-use in mind and performance as the primary concern.\n\n# Design\nDapper.GraphQL combines the ideas that come out-of-the-box with graphql-dotnet, and adds the following concepts:\n\n1. Query builders\n2. Entity mapper\n\n## Query Builders\n\nQuery builders are used to build dynamic queries based on what the client asked for in their GraphQL query.  For example, given this\nGraphQL query:\n\n```graphql\nquery {\n    people {\n        id\n        firstName\n        lastName\n    }\n}\n```\n\nA proper query builder will generate a SQL query that looks something like this:\n\n```sql\nSELECT id, firstName, lastName\nFROM Person\n```\n\nUsing the same query builder, and given the following GraphQL:\n\n```graphql\nquery {\n    people {\n        id\n        firstName\n        lastName\n        emails {\n            id\n            address\n        }\n        phones {\n            id\n            number\n            type\n        }\n    }\n}\n```\n\nA more complex query should be generated, something like:\n\n```sql\nSELECT\n  person.Id, person.firstName, person.lastName,\n  email.id, email.address,\n  phone.id, phone.number, phone.type  \nFROM Person person \nLEFT OUTER JOIN Email email ON person.Id = email.PersonId \nLEFT OUTER JOIN Phone phone ON person.Id = phone.PersonId\n```\n\n## Entity Mappers\n\nEntity mappers are used to map entities to Dapper from query results.  Since a single entity can be composed of multiple rows of a query result, an entity mapper is designed to quickly merge multiple rows of output SQL into a single hierarchy of entities.\n\nSee the `PersonEntityMapper.cs` class in the test project for an example.\n\n# Usage\n\n## Setup\n\nDapper.GraphQL uses Microsoft's standard DI container, IServiceCollection, to manage all of the Dapper and GraphQL interactions.\nIf you're developing in ASP.NET Core, you can add this to the ConfigureServices() method:\n\n```csharp\nserviceCollection.AddDapperGraphQL(options =\u003e\n{\n    // Add GraphQL types\n    options.AddType\u003cCompanyType\u003e();\n    options.AddType\u003cEmailType\u003e();\n    options.AddType\u003cPersonType\u003e();\n    options.AddType\u003cGraphQL.PhoneType\u003e();\n    options.AddType\u003cPersonQuery\u003e();\n\n    // Add the GraphQL schema\n    options.AddSchema\u003cPersonSchema\u003e();\n\n    // Add query builders for dapper\n    options.AddQueryBuilder\u003cCompany, CompanyQueryBuilder\u003e();\n    options.AddQueryBuilder\u003cEmail, EmailQueryBuilder\u003e();\n    options.AddQueryBuilder\u003cPerson, PersonQueryBuilder\u003e();\n    options.AddQueryBuilder\u003cPhone, PhoneQueryBuilder\u003e();\n});\n```\n\n## Queries\n\nWhen creating a SQL query based on a GraphQL query, you need 2 things to build the query properly:  A *query builder* and *entity mapper*.\n\n### Query builder\n\nEach entity in a system should have its own query builder, so any GraphQL queries that interact with those entities can be automatically\nhandled, even when nested within other entities.\n\nIn the above setup, the `Email` query builder looks like this:\n\n```csharp\npublic class EmailQueryBuilder :\n    IQueryBuilder\u003cEmail\u003e\n{\n    public SqlQueryContext Build(SqlQueryContext query, IHaveSelectionSet context, string alias)\n    {\n        // Always get the ID of the email\n        query.Select($\"{alias}.Id\");\n        // Tell Dapper where the Email class begins (at the Id we just selected)\n        query.SplitOn\u003cEmail\u003e(\"Id\");\n\n        var fields = context.GetSelectedFields();\n        if (fields.ContainsKey(\"address\"))\n        {\n            query.Select($\"{alias}.Address\");\n        }\n\n        return query;\n    }\n}\n```\n\n#### Arguments\n\n* The `query` represents the SQL query that's been generated so far.\n* The `context` is the GraphQL context - it contains the GraphQL query and what data has been requested.\n* The `alias` is what SQL alias the current table has.  Since entities can be used more than once (multiple entities can have an `Email`, for example), it's important that our aliases are unique.\n\n#### `Build()` method\n\nLet's break down what's happening in the `Build()` method:\n\n1. `query.Select($\"{alias}.Id\");` - select the Id of the entity.  This is good practice, so that even if the GraphQL query didn't include the `id`, we always include it.\n2. `query.SplitOn\u003cEmail\u003e(\"Id\");` - tell Dapper that the `Id` marks the beginning of the `Email` class.\n3. `var fields = context.GetSelectedFields();` - Gets a list of fields that have been selected from GraphQL.\n4. `case \"address\": query.Select($\"{alias}.Address\");` - When `address` is found in the GraphQL query, add the `Address` to the SQL SELECT clause.\n\n#### Query builder chaining\n\nQuery builders are intended to chain, as our entities tend to have a hierarchical relationship.  See the [PersonQueryBuilder.cs](https://github.com/landmarkhw/Dapper.GraphQL/blob/master/Dapper.GraphQL.Test/QueryBuilders/PersonQueryBuilder.cs) file in the test project for a good example of chaining.\n\n## GraphQL integration\n\nHere's an example of a query definition in `graphql-dotnet`:\n\n```csharp\nField\u003cListGraphType\u003cPersonType\u003e\u003e(\n    \"people\",\n    description: \"A list of people.\",\n    resolve: context =\u003e\n    {\n        // Create an alias for the 'Person' table.\n        var alias = \"person\";\n        // Add the 'Person' table to the FROM clause in SQL\n        var query = SqlBuilder.From($\"Person {alias}\");\n        // Build the query, using the GraphQL query and SQL table alias.\n        query = personQueryBuilder.Build(query, context.FieldAst, alias);\n\n        // Create a mapper that understands how to map the 'Person' class.\n        var personMapper = new PersonEntityMapper();\n\n        // Open a connection to the database\n        using (var connection = serviceProvider.GetRequiredService\u003cIDbConnection\u003e())\n        {\n            // Execute the query with the person mapper\n            var results = query.Execute(connection, personMapper, context.FieldAst);\n            \n            // `results` contains a list of people.\n            return results;\n        }\n    }\n);\n```\n\n# Mapping objects of the same type\n\nThe test project contains an example of how to handle this scenario.  See [PersonEntityMapper.cs](https://github.com/landmarkhw/Dapper.GraphQL/blob/master/Dapper.GraphQL.Test/EntityMappers/PersonEntityMapper.cs).\n\n# Examples\n\nSee the Dapper.GraphQL.Test project for a full set of examples, including how *query builders* and *entity mappers* are designed.\n\n# Development \u0026 Testing\n\nTo run unit tests, you must have PostgreSQL running locally on your machine.  The easiest way to\naccomplish this is to install Docker and run PostgreSQL from the official Docker container:\n\nFrom a command line, run a Postgres image from docker as follows:\n\n```\ndocker run --name dapper-graphql-test -e POSTGRES_PASSWORD=dapper-graphql -d -p 5432:5432 postgres\n```\n\nThen, unit tests should function as expected.\n\n# Roadmap\n\n* Fluent-style pagination\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flandmarkhw%2Fdapper.graphql","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flandmarkhw%2Fdapper.graphql","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flandmarkhw%2Fdapper.graphql/lists"}