Explore the unique approach of using dapper for performance and direct GraphQL operation translations into Raw SQL, providing out of the box features without adding any code, and giving full customisation and integrations based on every project needs.
Coffee beanery is a dynamic parser from GraphQL queries into raw SQL queries; the translation happens on the fly and all the features are available out of the box.
It only requires mappings between models and entities and a few annotations to signal the framework about the relationship between models or entities.
Also, the feature to have the means for using business transactions and add custom business code within the api. Makes a unique opportunity to do any integration possible.
“Actively developed. Currently a reference implementation and experimentation platform, it might be shipped as a Nuget package once it reaches maturity.
Any type of contribution and support will be extremely welcome. From proposals, feedback, or any other content that can help out to reach a a wider audience and maturity.”
Running example
- Clone repository
- Run entity framework migrations
- Compile and run api project
- Use nitro IDE to create any type of graphql operation.
- Validate data persistance and query result.
The following libraries are used to achieve all the features listed below:
- Dapper
- Hot Chocolate
- Automapper
- Entity Framework
- PostgreSQL
- FasterKV
- Configuration based for faster development.
- No N+1 problem since the entire query/mutation is batched and materialized by the database engine
- Complex domain models
- Hability to add any additional business logic or integration within the GraphQL API project.
- Custom and complex mapping between data entities and domain models
- Allows subgraph mutations and queries using the same endpoint and wrapper object.
- Data annotation based for creating relationships between Data entities and domain models.
- Leverage to a mapping framework the mapping between data entities and domain models
- Leverage generics to generate the column names based on the data entities.
- Can be customized and integrate with multiple GraphQL framework / libraries and databases.
- Node types are translated into Left joins between entities.
- Edge types are translated into joins between entities.
- Paging support
- Filtering support
- Sorting support
- Granular access by table/columns based on token-claims
- Data and column validations
- Query cache can be customized in multiple layers
- Query result handling can be fully customized
There are 3 types of annotations
Field that will be used to upsert the record
First argument table, Second argument database schema
[UpsertKey("Transaction","Lending")]
public Guid TransactionKey { get; set; }
Foreign key to join the child with parent
Note: all joins are done via Ids
- Transaction table (Child)
No setup required
- Account table Parent
First argument parent table, Second argument parent property to be joined
[LinkKey("Transaction","TransactionKey")]
[JoinKey("Account","Id")]
public List<Transaction>? Transaction { get; set; }
[LinkKey("Contract","Id")]
[JoinOneKey("Account","Id")]
public Contract? Contract { get; set; }
First argument child table, Second argument child property to be joined (mapped)
[LinkBusinessKey("Transaction","TransactionKey")]
public List<Transaction>? Transaction { get; set; }
Even though the query cannot be directly converted and translated during the tree processing, the library supports multiple caching and techniques; since queries need to be processed as a single statement for the entire tree
Support of multiple cache levels
1. key: main node string
Value: Calculated query
2. Where and Pagination are decoupled of the query, allowing a better cache plans
3. Query Result data: based on the requirements, the returning data result can be upserted and save into the cache
Mutations are not cached as they are directly converted and translated during the tree processing, since the upserts do not require to be combined within a single statement. Also, mutations are tightly couple with data so, there is not to much gain to cache the queries with specific values
1. Returning query cache techniques can be used in mutation result
- Add support to other database providers
- Allow complex joins between properties (currently supports Id columns)
Contains plain ef core entity models where a property schema and id are required for joining purposes.
Contains all util helpers and core implementations
Contains the custom model and attributes which will be exposed through the API.
- It does not need to map each data model property and naming
- The EF List/Entity one direction link is required for generating each entity tree
- Any property can be hidden to the GraphQL API
- BusinessKey data annotation is required to generate the tree graphs, column mappings, and mappings between Entity models and Data models
- BusinessSchema data annotation is required to register the schema which will be used by the table/columnn; bringing flexibility if there is a need to scale or split the GraphQL API into different database logic structures
- JoinKey data annotation is required for foreign keys and join keys
- Uses a wrapper entity model to allow multiple root entity upserts
- Contains main root entity query handler where customer logic and mapping can be applied after SQL statement execution
- Requires a basic mapping structure framework agnostic to translate column mappings between Entity models and Data models during the SQL query generation
- Further custom mapping can be added for root entity query handler
- Service Collection extension for adding the root entity query handler
- Contains basic setup for GraphQL API
- Supports any framework since it is not tightly couple to a vendor
Stitching frameworks like Apollo of Fusion can be used to integrate multiple graphQL api.
keeping cache can be challenging specially when multiple process are happening in the background.
From the example viewpoint each database schema can be split into microservices. And then stitching each context together
A readonly replica can be used to join every context together. And then make queries against the replica without N+1 problems.
To take advantage of each approach. A mix can be used. Stitching for mutations and replica for querying.
I would love a 100% colombian coffee!
