From 62eb2dab6283a6d0e307554dc0ebd528e211d868 Mon Sep 17 00:00:00 2001 From: Diego Pereira Date: Sat, 3 Apr 2021 13:25:20 +0100 Subject: [PATCH] Refactor on repository and add mutations --- src/GraphQL.API.Tests/QueryTests.cs | 2 +- src/GraphQL.API/Mutations/CategoryMutation.cs | 10 ++++ src/GraphQL.API/Mutations/ProductMutation.cs | 18 +++++++ src/GraphQL.API/Queries/CategoryQuery.cs | 14 +++++ .../Queries/{Query.cs => ProductQuery.cs} | 4 +- src/GraphQL.API/Resolvers/CategoryResolver.cs | 3 +- src/GraphQL.API/Startup.cs | 9 +++- src/GraphQL.Core/Entities/Category.cs | 8 +-- src/GraphQL.Core/Entities/EntityBase.cs | 12 +++++ src/GraphQL.Core/Entities/Product.cs | 8 +-- .../Repositories/IBaseRepository.cs | 14 +++++ .../Repositories/ICategoryRepository.cs | 5 +- .../Repositories/IProductRepository.cs | 7 +-- .../Data/CatalogContext.cs | 16 +++--- .../Data/CatalogContextSeed.cs | 8 ++- .../Data/ICatalogContext.cs | 4 +- .../Repositories/BaseRepository.cs | 51 +++++++++++++++++++ .../Repositories/CategoryRepository.cs | 15 +----- .../Repositories/ProductRepository.cs | 22 +------- 19 files changed, 153 insertions(+), 77 deletions(-) create mode 100644 src/GraphQL.API/Mutations/CategoryMutation.cs create mode 100644 src/GraphQL.API/Mutations/ProductMutation.cs create mode 100644 src/GraphQL.API/Queries/CategoryQuery.cs rename src/GraphQL.API/Queries/{Query.cs => ProductQuery.cs} (79%) create mode 100644 src/GraphQL.Core/Entities/EntityBase.cs create mode 100644 src/GraphQL.Core/Repositories/IBaseRepository.cs create mode 100644 src/GraphQL.Infrastructure/Repositories/BaseRepository.cs diff --git a/src/GraphQL.API.Tests/QueryTests.cs b/src/GraphQL.API.Tests/QueryTests.cs index b2c46c3..4d68113 100644 --- a/src/GraphQL.API.Tests/QueryTests.cs +++ b/src/GraphQL.API.Tests/QueryTests.cs @@ -27,7 +27,7 @@ public async void Query_ReturnsProducts() .AddScoped() // Should be mocked .AddScoped() // Should be mocked .AddGraphQL() - .AddQueryType() + .AddQueryType() .AddType() .AddType() .BuildRequestExecutorAsync(); diff --git a/src/GraphQL.API/Mutations/CategoryMutation.cs b/src/GraphQL.API/Mutations/CategoryMutation.cs new file mode 100644 index 0000000..50f213f --- /dev/null +++ b/src/GraphQL.API/Mutations/CategoryMutation.cs @@ -0,0 +1,10 @@ +namespace GraphQL.API.Mutations +{ + using HotChocolate.Types; + + [ExtendObjectType(Name = "Mutation")] + public class CategoryMutation + { + // TODO: Create methods + } +} diff --git a/src/GraphQL.API/Mutations/ProductMutation.cs b/src/GraphQL.API/Mutations/ProductMutation.cs new file mode 100644 index 0000000..70fe813 --- /dev/null +++ b/src/GraphQL.API/Mutations/ProductMutation.cs @@ -0,0 +1,18 @@ +namespace GraphQL.API.Mutations +{ + using GraphQL.Core.Entities; + using GraphQL.Core.Repositories; + using HotChocolate; + using HotChocolate.Types; + using System.Threading.Tasks; + + [ExtendObjectType(Name = "Mutation")] + public class ProductMutation + { + public Task CreateProductAsync(Product product, [Service] IProductRepository productRepository) => + productRepository.InsertAsync(product); + + public Task RemoveProductAsync(string id, [Service] IProductRepository productRepository) => + productRepository.RemoveAsync(id); + } +} diff --git a/src/GraphQL.API/Queries/CategoryQuery.cs b/src/GraphQL.API/Queries/CategoryQuery.cs new file mode 100644 index 0000000..76c5337 --- /dev/null +++ b/src/GraphQL.API/Queries/CategoryQuery.cs @@ -0,0 +1,14 @@ +namespace GraphQL.API.Queries +{ + using HotChocolate.Types; + using System; + using System.Collections.Generic; + using System.Linq; + using System.Threading.Tasks; + + [ExtendObjectType(Name = "Query")] + public class CategoryQuery + { + // Create methods + } +} diff --git a/src/GraphQL.API/Queries/Query.cs b/src/GraphQL.API/Queries/ProductQuery.cs similarity index 79% rename from src/GraphQL.API/Queries/Query.cs rename to src/GraphQL.API/Queries/ProductQuery.cs index 3f1a7a3..474d1cd 100644 --- a/src/GraphQL.API/Queries/Query.cs +++ b/src/GraphQL.API/Queries/ProductQuery.cs @@ -6,12 +6,12 @@ using System.Collections.Generic; using System.Threading.Tasks; - public class Query + public class ProductQuery { public Task> GetProductsAsync([Service] IProductRepository productRepository) => productRepository.GetAllAsync(); - public Task GetProductById(string id, [Service] IProductRepository productRepository) => + public Task GetProductByIdAsync(string id, [Service] IProductRepository productRepository) => productRepository.GetByIdAsync(id); // Add any queries you want here.. diff --git a/src/GraphQL.API/Resolvers/CategoryResolver.cs b/src/GraphQL.API/Resolvers/CategoryResolver.cs index f895d1f..af7a9a5 100644 --- a/src/GraphQL.API/Resolvers/CategoryResolver.cs +++ b/src/GraphQL.API/Resolvers/CategoryResolver.cs @@ -9,6 +9,7 @@ [ExtendObjectType(Name = "Category")] public class CategoryResolver { - public Task GetCategoryAsync([Parent] Product product, [Service] ICategoryRepository categoryRepository) => categoryRepository.GetById(product.CategoryId); + public Task GetCategoryAsync([Parent] Product product, [Service] ICategoryRepository categoryRepository) => + categoryRepository.GetByIdAsync(product.CategoryId); } } diff --git a/src/GraphQL.API/Startup.cs b/src/GraphQL.API/Startup.cs index f2a79d8..9a87037 100644 --- a/src/GraphQL.API/Startup.cs +++ b/src/GraphQL.API/Startup.cs @@ -1,6 +1,7 @@ namespace GraphQL.API { using GraphQL.API.Configurations; + using GraphQL.API.Mutations; using GraphQL.API.Queries; using GraphQL.API.Resolvers; using GraphQL.API.Types; @@ -30,13 +31,19 @@ public void ConfigureServices(IServiceCollection services) // Repositories services.AddSingleton(); + services.AddScoped(typeof(IBaseRepository<>), typeof(BaseRepository<>)); services.AddScoped(); services.AddScoped(); // GraphQL services .AddGraphQLServer() - .AddQueryType() + .AddQueryType(d => d.Name("Query")) + .AddTypeExtension() + .AddTypeExtension() + .AddMutationType(d => d.Name("Mutation")) + .AddTypeExtension() + .AddTypeExtension() .AddType() .AddType(); } diff --git a/src/GraphQL.Core/Entities/Category.cs b/src/GraphQL.Core/Entities/Category.cs index 950d76d..2853951 100644 --- a/src/GraphQL.Core/Entities/Category.cs +++ b/src/GraphQL.Core/Entities/Category.cs @@ -1,13 +1,7 @@ namespace GraphQL.Core.Entities { - using MongoDB.Bson; - using MongoDB.Bson.Serialization.Attributes; - - public class Category + public class Category : EntityBase { - [BsonId] - [BsonRepresentation(BsonType.ObjectId)] - public string Id { get; set; } public string Description { get; set; } } } diff --git a/src/GraphQL.Core/Entities/EntityBase.cs b/src/GraphQL.Core/Entities/EntityBase.cs new file mode 100644 index 0000000..bca6b4b --- /dev/null +++ b/src/GraphQL.Core/Entities/EntityBase.cs @@ -0,0 +1,12 @@ +namespace GraphQL.Core.Entities +{ + using MongoDB.Bson; + using MongoDB.Bson.Serialization.Attributes; + + public class EntityBase + { + [BsonId] + [BsonRepresentation(BsonType.ObjectId)] + public string Id { get; set; } + } +} \ No newline at end of file diff --git a/src/GraphQL.Core/Entities/Product.cs b/src/GraphQL.Core/Entities/Product.cs index f1fa6b4..aec2e10 100644 --- a/src/GraphQL.Core/Entities/Product.cs +++ b/src/GraphQL.Core/Entities/Product.cs @@ -1,13 +1,7 @@ namespace GraphQL.Core.Entities { - using MongoDB.Bson; - using MongoDB.Bson.Serialization.Attributes; - - public class Product + public class Product : EntityBase { - [BsonId] - [BsonRepresentation(BsonType.ObjectId)] - public string Id { get; set; } public string Name { get; set; } public string Description { get; set; } public decimal Price { get; set; } diff --git a/src/GraphQL.Core/Repositories/IBaseRepository.cs b/src/GraphQL.Core/Repositories/IBaseRepository.cs new file mode 100644 index 0000000..c913456 --- /dev/null +++ b/src/GraphQL.Core/Repositories/IBaseRepository.cs @@ -0,0 +1,14 @@ +namespace GraphQL.Core.Repositories +{ + using GraphQL.Core.Entities; + using System.Collections.Generic; + using System.Threading.Tasks; + + public interface IBaseRepository where T : EntityBase + { + Task> GetAllAsync(); + Task GetByIdAsync(string id); + Task InsertAsync(T entity); + Task RemoveAsync(string id); + } +} diff --git a/src/GraphQL.Core/Repositories/ICategoryRepository.cs b/src/GraphQL.Core/Repositories/ICategoryRepository.cs index f55686f..231877c 100644 --- a/src/GraphQL.Core/Repositories/ICategoryRepository.cs +++ b/src/GraphQL.Core/Repositories/ICategoryRepository.cs @@ -1,10 +1,9 @@ namespace GraphQL.Core.Repositories { using GraphQL.Core.Entities; - using System.Threading.Tasks; - public interface ICategoryRepository + public interface ICategoryRepository : IBaseRepository { - Task GetById(string id); + } } diff --git a/src/GraphQL.Core/Repositories/IProductRepository.cs b/src/GraphQL.Core/Repositories/IProductRepository.cs index c3c242a..6374536 100644 --- a/src/GraphQL.Core/Repositories/IProductRepository.cs +++ b/src/GraphQL.Core/Repositories/IProductRepository.cs @@ -1,12 +1,9 @@ namespace GraphQL.Core.Repositories { using GraphQL.Core.Entities; - using System.Collections.Generic; - using System.Threading.Tasks; - public interface IProductRepository + public interface IProductRepository : IBaseRepository { - Task> GetAllAsync(); - Task GetByIdAsync(string id); + } } diff --git a/src/GraphQL.Infrastructure/Data/CatalogContext.cs b/src/GraphQL.Infrastructure/Data/CatalogContext.cs index 11ce9c6..1f2775e 100644 --- a/src/GraphQL.Infrastructure/Data/CatalogContext.cs +++ b/src/GraphQL.Infrastructure/Data/CatalogContext.cs @@ -1,26 +1,24 @@ namespace GraphQL.Infrastructure.Data { - using GraphQL.Core.Entities; using GraphQL.Infrastructure.Configurations; using MongoDB.Driver; public class CatalogContext : ICatalogContext { - private const string ProductCollectionName = "Products"; - private const string CategoryCollectionName = "Categories"; + private readonly IMongoDatabase database; public CatalogContext(MongoDbConfiguration mongoDbConfiguration) { var client = new MongoClient(mongoDbConfiguration.ConnectionString); - var database = client.GetDatabase(mongoDbConfiguration.Database); - this.Categories = database.GetCollection(CategoryCollectionName); - this.Products = database.GetCollection(ProductCollectionName); + this.database = client.GetDatabase(mongoDbConfiguration.Database); - CatalogContextSeed.SeedData(this.Categories, this.Products); + CatalogContextSeed.SeedData(this.database); } - public IMongoCollection Categories { get; } - public IMongoCollection Products { get; } + public IMongoCollection GetCollection(string name) + { + return this.database.GetCollection(name); + } } } diff --git a/src/GraphQL.Infrastructure/Data/CatalogContextSeed.cs b/src/GraphQL.Infrastructure/Data/CatalogContextSeed.cs index 5bf99d4..46b33f8 100644 --- a/src/GraphQL.Infrastructure/Data/CatalogContextSeed.cs +++ b/src/GraphQL.Infrastructure/Data/CatalogContextSeed.cs @@ -6,12 +6,10 @@ public class CatalogContextSeed { - public static void SeedData( - IMongoCollection categoryCollection, - IMongoCollection productCollection) + public static void SeedData(IMongoDatabase database) { - InsertCategories(categoryCollection); - InsertProducts(productCollection); + InsertCategories(database.GetCollection(nameof(Category))); + InsertProducts(database.GetCollection(nameof(Product))); } private static void InsertCategories(IMongoCollection categoryCollection) diff --git a/src/GraphQL.Infrastructure/Data/ICatalogContext.cs b/src/GraphQL.Infrastructure/Data/ICatalogContext.cs index e3a5709..dd75106 100644 --- a/src/GraphQL.Infrastructure/Data/ICatalogContext.cs +++ b/src/GraphQL.Infrastructure/Data/ICatalogContext.cs @@ -1,11 +1,9 @@ namespace GraphQL.Infrastructure.Data { - using GraphQL.Core.Entities; using MongoDB.Driver; public interface ICatalogContext { - IMongoCollection Categories { get; } - IMongoCollection Products { get; } + IMongoCollection GetCollection(string name); } } \ No newline at end of file diff --git a/src/GraphQL.Infrastructure/Repositories/BaseRepository.cs b/src/GraphQL.Infrastructure/Repositories/BaseRepository.cs new file mode 100644 index 0000000..a60fdef --- /dev/null +++ b/src/GraphQL.Infrastructure/Repositories/BaseRepository.cs @@ -0,0 +1,51 @@ +namespace GraphQL.Infrastructure.Repositories +{ + using GraphQL.Core.Entities; + using GraphQL.Core.Repositories; + using GraphQL.Infrastructure.Data; + using MongoDB.Driver; + using System; + using System.Collections.Generic; + using System.Threading.Tasks; + + public class BaseRepository : IBaseRepository where T : EntityBase + { + private readonly IMongoCollection collection; + + public BaseRepository(ICatalogContext catalogContext) + { + if (catalogContext == null) + { + throw new ArgumentNullException(nameof(catalogContext)); + } + + this.collection = catalogContext.GetCollection(typeof(T).Name); + } + + public async Task> GetAllAsync() + { + return await this.collection.Find(_ => true).ToListAsync(); + } + + public async Task GetByIdAsync(string id) + { + var filter = Builders.Filter.Eq(_ => _.Id, id); + + return await this.collection.Find(filter).FirstOrDefaultAsync(); + } + + public async Task InsertAsync(T entity) + { + await this.collection.InsertOneAsync(entity); + + return entity; + } + + public async Task RemoveAsync(string id) + { + var result = await this.collection.DeleteOneAsync(Builders.Filter.Eq(_ => _.Id, id)); + + return result.DeletedCount > 0; + } + } +} diff --git a/src/GraphQL.Infrastructure/Repositories/CategoryRepository.cs b/src/GraphQL.Infrastructure/Repositories/CategoryRepository.cs index c679962..bd26bed 100644 --- a/src/GraphQL.Infrastructure/Repositories/CategoryRepository.cs +++ b/src/GraphQL.Infrastructure/Repositories/CategoryRepository.cs @@ -3,23 +3,12 @@ using GraphQL.Core.Entities; using GraphQL.Core.Repositories; using GraphQL.Infrastructure.Data; - using MongoDB.Driver; - using System.Threading.Tasks; - public class CategoryRepository : ICategoryRepository + public class CategoryRepository : BaseRepository, ICategoryRepository { - private readonly ICatalogContext catalogContext; - - public CategoryRepository(ICatalogContext catalogContext) - { - this.catalogContext = catalogContext; - } - - public async Task GetById(string id) + public CategoryRepository(ICatalogContext catalogContext) : base(catalogContext) { - var filter = Builders.Filter.Eq(_ => _.Id, id); - return await this.catalogContext.Categories.Find(filter).FirstOrDefaultAsync(); } } } diff --git a/src/GraphQL.Infrastructure/Repositories/ProductRepository.cs b/src/GraphQL.Infrastructure/Repositories/ProductRepository.cs index 579c816..eb3ca6c 100644 --- a/src/GraphQL.Infrastructure/Repositories/ProductRepository.cs +++ b/src/GraphQL.Infrastructure/Repositories/ProductRepository.cs @@ -3,30 +3,12 @@ using GraphQL.Core.Entities; using GraphQL.Core.Repositories; using GraphQL.Infrastructure.Data; - using MongoDB.Driver; - using System; - using System.Collections.Generic; - using System.Threading.Tasks; - public class ProductRepository : IProductRepository + public class ProductRepository : BaseRepository, IProductRepository { - private readonly ICatalogContext catalogContext; - - public ProductRepository(ICatalogContext catalogContext) - { - this.catalogContext = catalogContext ?? throw new ArgumentNullException(nameof(catalogContext)); - } - - public async Task> GetAllAsync() - { - return await this.catalogContext.Products.Find(_ => true).ToListAsync(); - } - - public async Task GetByIdAsync(string id) + public ProductRepository(ICatalogContext catalogContext) : base(catalogContext) { - var filter = Builders.Filter.Eq(_ => _.Id, id); - return await this.catalogContext.Products.Find(filter).FirstOrDefaultAsync(); } } }