diff --git a/TableTopInc.API/TableTopInc.API.Engine.AzureStorage/Helpers/TableEntityMappingHelper.cs b/TableTopInc.API/TableTopInc.API.Engine.AzureStorage/Helpers/TableEntityMappingHelper.cs index 3787afb..2fe064d 100644 --- a/TableTopInc.API/TableTopInc.API.Engine.AzureStorage/Helpers/TableEntityMappingHelper.cs +++ b/TableTopInc.API/TableTopInc.API.Engine.AzureStorage/Helpers/TableEntityMappingHelper.cs @@ -1,22 +1,27 @@ +using System; using AutoMapper; using TableTopInc.API.Engine.AzureStorage.Models.General; +using TableTopInc.API.Engine.Models.Base; using TableTopInc.API.Engine.Models.General; namespace TableTopInc.API.Engine.AzureStorage.Helpers { - public static class TableEntityMappingHelper + internal static class TableEntityMappingHelper { - static TableEntityMappingHelper() + private static readonly Lazy ObjMapper = new Lazy(() => { - Mapper.Initialize(config => + var config = new MapperConfiguration(cfg => { - config.CreateMap(); + cfg.CreateMap(); + cfg.CreateMap(); }); - } - public static GameTableEntity ToTableEntity(this IGameModel model) + return config.CreateMapper(); + }); + + internal static T ToTableEntity(this IEntityModel model) { - return Mapper.Map(model); + return ObjMapper.Value.Map(model); } } } \ No newline at end of file diff --git a/TableTopInc.API/TableTopInc.API.Engine.AzureStorage/Models/Base/EntityBase.cs b/TableTopInc.API/TableTopInc.API.Engine.AzureStorage/Models/Base/EntityBase.cs index 58f5c47..0f0a574 100644 --- a/TableTopInc.API/TableTopInc.API.Engine.AzureStorage/Models/Base/EntityBase.cs +++ b/TableTopInc.API/TableTopInc.API.Engine.AzureStorage/Models/Base/EntityBase.cs @@ -6,7 +6,7 @@ namespace TableTopInc.API.Engine.AzureStorage.Models.Base public abstract class EntityBase : TableEntity, IEntityModel { public const string DefaultPartitionKey = "__shared"; - + [IgnoreProperty] public string Id { diff --git a/TableTopInc.API/TableTopInc.API.Engine.AzureStorage/Models/General/GameDesignerRoleTableEntity.cs b/TableTopInc.API/TableTopInc.API.Engine.AzureStorage/Models/General/GameDesignerRoleTableEntity.cs index abff033..9e5dbea 100644 --- a/TableTopInc.API/TableTopInc.API.Engine.AzureStorage/Models/General/GameDesignerRoleTableEntity.cs +++ b/TableTopInc.API/TableTopInc.API.Engine.AzureStorage/Models/General/GameDesignerRoleTableEntity.cs @@ -1,10 +1,16 @@ -using TableTopInc.API.Engine.AzureStorage.Models.Base; +using TableTopInc.API.Engine.AzureStorage.Helpers; +using TableTopInc.API.Engine.AzureStorage.Models.Base; using TableTopInc.API.Engine.Models.General; namespace TableTopInc.API.Engine.AzureStorage.Models.General { public class GameDesignerRoleTableEntity : EntityBase, IGameDesignerRoleModel { + public static GameDesignerRoleTableEntity Create(IGameDesignerRoleModel model) + { + return model.ToTableEntity(); + } + public string Title { get; set; } } } diff --git a/TableTopInc.API/TableTopInc.API.Engine.AzureStorage/Models/General/GameTableEntity.cs b/TableTopInc.API/TableTopInc.API.Engine.AzureStorage/Models/General/GameTableEntity.cs index 8aae5c3..fa69c63 100644 --- a/TableTopInc.API/TableTopInc.API.Engine.AzureStorage/Models/General/GameTableEntity.cs +++ b/TableTopInc.API/TableTopInc.API.Engine.AzureStorage/Models/General/GameTableEntity.cs @@ -8,7 +8,7 @@ public class GameTableEntity : EntityBase, IGameModel { public static GameTableEntity Create(IGameModel model) { - return model.ToTableEntity(); + return model.ToTableEntity(); } public string Title { get; set; } diff --git a/TableTopInc.API/TableTopInc.API.Engine.AzureStorage/Azure/AzureTableService.cs b/TableTopInc.API/TableTopInc.API.Engine.AzureStorage/Services/Base/AzureTableService.cs similarity index 67% rename from TableTopInc.API/TableTopInc.API.Engine.AzureStorage/Azure/AzureTableService.cs rename to TableTopInc.API/TableTopInc.API.Engine.AzureStorage/Services/Base/AzureTableService.cs index 33854a6..11a56d3 100644 --- a/TableTopInc.API/TableTopInc.API.Engine.AzureStorage/Azure/AzureTableService.cs +++ b/TableTopInc.API/TableTopInc.API.Engine.AzureStorage/Services/Base/AzureTableService.cs @@ -3,10 +3,16 @@ using System.Linq; using System.Threading.Tasks; using Microsoft.WindowsAzure.Storage.Table; +using TableTopInc.API.Engine.AzureStorage.Helpers; +using TableTopInc.API.Engine.AzureStorage.Models.Base; +using TableTopInc.API.Engine.Models.Base; +using TableTopInc.API.Engine.Services.Base; -namespace TableTopInc.API.Engine.AzureStorage.Azure +namespace TableTopInc.API.Engine.AzureStorage.Services.Base { - public class AzureTableService where T : TableEntity, new() + public abstract class AzureTableService : IEntityService + where TableModel : EntityBase, ITableEntity + where EntityModel : class, IEntityModel { public const int BatchMaxSize = 100; public const int QueryMaxParams = 15; @@ -18,7 +24,7 @@ namespace TableTopInc.API.Engine.AzureStorage.Azure protected readonly CloudTable Table; protected readonly string EntitiesOwnerId; - internal AzureTableService(CloudTable table, string entitiesOwnerId) + internal AzureTableService(CloudTable table, string entitiesOwnerId = EntityBase.DefaultPartitionKey) { Table = table; EntitiesOwnerId = entitiesOwnerId; @@ -26,48 +32,57 @@ internal AzureTableService(CloudTable table, string entitiesOwnerId) #region public - public static string ToRowKey(Guid id) + public async Task> SaveAsync(params EntityModel[] entities) { - return id.ToString("N"); - } + foreach (var entity in entities.Where(x => string.IsNullOrWhiteSpace(x.Id))) + { + entity.Id = ToRowKey(Guid.NewGuid()); + } + + await ExecuteBatchAsync(entities.Select(x => x.ToTableEntity()), TableOperation.InsertOrReplace); - public async Task> GetAllAsync() - { - return await GetByFilterAsync(string.Empty); + return entities; } - - public virtual async Task> GetByIdsAsync(params Guid[] ids) + + public async Task DeleteByIdsAsync(params string[] ids) { var keys = ids .Select(x => new KeyValuePair( EntitiesOwnerId, - ToRowKey(x))) + x)) .ToArray(); - return await GetByKeysAsync(keys); + await DeleteByKeysAsync(keys); } - - public virtual async Task DeleteByIdsAsync(params Guid[] ids) + + public async Task> GetAllAsync() + { + return (await GetByFilterAsync(string.Empty)) + .Cast(); + } + + public async Task> GetByIdsAsync(params string[] ids) { var keys = ids .Select(x => new KeyValuePair( EntitiesOwnerId, - ToRowKey(x))) + x)) .ToArray(); - await DeleteByKeysAsync(keys); - } - - public async Task SaveAsync(params T[] entities) - { - await ExecuteBatchAsync(entities, TableOperation.InsertOrReplace); + return (await GetByKeysAsync(keys)) + .Cast(); } - + #endregion #region protected - protected async Task ExecuteBatchAsync(IEnumerable entities, Func func) + protected static string ToRowKey(Guid id) + { + return id.ToString("N"); + } + + protected async Task ExecuteBatchAsync(IEnumerable entities, Func func) { var groups = entities .GroupBy(x => x.PartitionKey, (key, items) => items.ToList()); @@ -97,12 +112,12 @@ protected async Task DeleteByKeysAsync(params KeyValuePair[] key await ExecuteBatchAsync(entities, TableOperation.Delete); } - protected async Task> GetByKeysAsync(params KeyValuePair[] keys) + protected async Task> GetByKeysAsync(params KeyValuePair[] keys) { var partitions = keys .GroupBy(x => x.Key, (key, values) => values.ToList()); - var tasks = new List>>(); + var tasks = new List>>(); foreach (var rowKeys in partitions) { var chunks = Math.Ceiling((decimal)rowKeys.Count / QueryMaxParamsForSinglePartition); @@ -134,17 +149,17 @@ protected async Task> GetByKeysAsync(params KeyValuePair x.Result); } - protected async Task> GetByFilterAsync(string filter) + protected async Task> GetByFilterAsync(string filter) { - var query = new TableQuery().Where(filter); - var results = new List(); + var query = new TableQuery().Where(filter); + var results = new List(); TableContinuationToken token = null; do { var segment = await Table.ExecuteQuerySegmentedAsync(query, token); token = segment.ContinuationToken; - results.AddRange(segment.Results); + results.AddRange(segment.Results.Cast()); } while (token != null); @@ -152,5 +167,6 @@ protected async Task> GetByFilterAsync(string filter) } #endregion + } } \ No newline at end of file diff --git a/TableTopInc.API/TableTopInc.API.Engine.AzureStorage/Services/Base/EntityServiceBase.cs b/TableTopInc.API/TableTopInc.API.Engine.AzureStorage/Services/Base/EntityServiceBase.cs deleted file mode 100644 index 4511b55..0000000 --- a/TableTopInc.API/TableTopInc.API.Engine.AzureStorage/Services/Base/EntityServiceBase.cs +++ /dev/null @@ -1,40 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using Microsoft.WindowsAzure.Storage.Table; -using TableTopInc.API.Engine.AzureStorage.Azure; -using TableTopInc.API.Engine.AzureStorage.Models.Base; -using TableTopInc.API.Engine.Services.Base; - -namespace TableTopInc.API.Engine.AzureStorage.Services.Base -{ - public abstract class EntityServiceBase : IEntityService where T : EntityBase, new() - { - internal AzureTableService AzureTableService; - - protected EntityServiceBase(CloudTable table) - { - AzureTableService = new AzureTableService(table, EntityBase.DefaultPartitionKey); - } - - public async Task SaveAsync(params T[] entities) - { - await AzureTableService.SaveAsync(entities); - } - - public async Task DeleteByIdsAsync(params Guid[] ids) - { - await AzureTableService.DeleteByIdsAsync(ids); - } - - public async Task> GetAllAsync() - { - return await AzureTableService.GetAllAsync(); - } - - public async Task> GetByIdsAsync(params Guid[] ids) - { - return await AzureTableService.GetByIdsAsync(ids); - } - } -} \ No newline at end of file diff --git a/TableTopInc.API/TableTopInc.API.Engine.AzureStorage/Services/General/GameDesignerRoleService.cs b/TableTopInc.API/TableTopInc.API.Engine.AzureStorage/Services/General/GameDesignerRoleService.cs index 41b198e..3aeff54 100644 --- a/TableTopInc.API/TableTopInc.API.Engine.AzureStorage/Services/General/GameDesignerRoleService.cs +++ b/TableTopInc.API/TableTopInc.API.Engine.AzureStorage/Services/General/GameDesignerRoleService.cs @@ -1,11 +1,15 @@ using Microsoft.WindowsAzure.Storage.Table; using TableTopInc.API.Engine.AzureStorage.Models.General; using TableTopInc.API.Engine.AzureStorage.Services.Base; +using TableTopInc.API.Engine.Models.General; +using TableTopInc.API.Engine.Services.General; namespace TableTopInc.API.Engine.AzureStorage.Services.General { - public class GameDesignerRoleService : EntityServiceBase + public class GameDesignerRoleService : AzureTableService, IGameDesignerRoleService { + public const string TableName = "GameDesignerRoles"; + public GameDesignerRoleService(CloudTable table) : base(table) { diff --git a/TableTopInc.API/TableTopInc.API.Engine.AzureStorage/Services/General/GameDesignerService.cs b/TableTopInc.API/TableTopInc.API.Engine.AzureStorage/Services/General/GameDesignerService.cs index e0fdada..a51dcbf 100644 --- a/TableTopInc.API/TableTopInc.API.Engine.AzureStorage/Services/General/GameDesignerService.cs +++ b/TableTopInc.API/TableTopInc.API.Engine.AzureStorage/Services/General/GameDesignerService.cs @@ -1,10 +1,12 @@ using Microsoft.WindowsAzure.Storage.Table; using TableTopInc.API.Engine.AzureStorage.Models.General; using TableTopInc.API.Engine.AzureStorage.Services.Base; +using TableTopInc.API.Engine.Models.General; +using TableTopInc.API.Engine.Services.General; namespace TableTopInc.API.Engine.AzureStorage.Services.General { - public class GameDesignerService : EntityServiceBase + public class GameDesignerService : AzureTableService, IGameDesignerService { public GameDesignerService(CloudTable table) : base(table) diff --git a/TableTopInc.API/TableTopInc.API.Engine.AzureStorage/Services/General/GameService.cs b/TableTopInc.API/TableTopInc.API.Engine.AzureStorage/Services/General/GameService.cs index 6301706..a34646d 100644 --- a/TableTopInc.API/TableTopInc.API.Engine.AzureStorage/Services/General/GameService.cs +++ b/TableTopInc.API/TableTopInc.API.Engine.AzureStorage/Services/General/GameService.cs @@ -1,10 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; using Microsoft.WindowsAzure.Storage.Table; using TableTopInc.API.Engine.AzureStorage.Models.General; using TableTopInc.API.Engine.AzureStorage.Services.Base; +using TableTopInc.API.Engine.Models.General; +using TableTopInc.API.Engine.Services.General; namespace TableTopInc.API.Engine.AzureStorage.Services.General { - public class GameService : EntityServiceBase + public class GameService : AzureTableService, IGameService { public const string TableName = "Games"; @@ -12,5 +17,15 @@ public GameService(CloudTable table) : base(table) { } + + public async Task> GetGamesByTagsAsync(params string[] tags) + { + throw new NotImplementedException(); + } + + public async Task> GetGamesByGameDesignersAsync(params string[] authors) + { + throw new NotImplementedException(); + } } } \ No newline at end of file diff --git a/TableTopInc.API/TableTopInc.API.Engine.AzureStorage/Services/General/TagService.cs b/TableTopInc.API/TableTopInc.API.Engine.AzureStorage/Services/General/TagService.cs index 68c023b..d3626a0 100644 --- a/TableTopInc.API/TableTopInc.API.Engine.AzureStorage/Services/General/TagService.cs +++ b/TableTopInc.API/TableTopInc.API.Engine.AzureStorage/Services/General/TagService.cs @@ -1,10 +1,12 @@ using Microsoft.WindowsAzure.Storage.Table; using TableTopInc.API.Engine.AzureStorage.Models.General; using TableTopInc.API.Engine.AzureStorage.Services.Base; +using TableTopInc.API.Engine.Models.General; +using TableTopInc.API.Engine.Services.General; namespace TableTopInc.API.Engine.AzureStorage.Services.General { - public class TagService : EntityServiceBase + public class TagService : AzureTableService, ITagService { public TagService(CloudTable table) : base(table) diff --git a/TableTopInc.API/TableTopInc.API.Engine/Services/Base/IEntityService.cs b/TableTopInc.API/TableTopInc.API.Engine/Services/Base/IEntityService.cs index 9b84d0f..167cae3 100644 --- a/TableTopInc.API/TableTopInc.API.Engine/Services/Base/IEntityService.cs +++ b/TableTopInc.API/TableTopInc.API.Engine/Services/Base/IEntityService.cs @@ -7,10 +7,10 @@ namespace TableTopInc.API.Engine.Services.Base { public interface IEntityService where T : IEntityModel { - Task SaveAsync(params T[] entities); - Task DeleteByIdsAsync(params Guid[] ids); + Task> SaveAsync(params T[] entities); + Task DeleteByIdsAsync(params string[] ids); Task> GetAllAsync(); - Task> GetByIdsAsync(params Guid[] ids); + Task> GetByIdsAsync(params string[] ids); } } \ No newline at end of file diff --git a/TableTopInc.API/TableTopInc.API.Engine/Services/General/IGameDesignerRoleService.cs b/TableTopInc.API/TableTopInc.API.Engine/Services/General/IGameDesignerRoleService.cs index 18f1adf..4617800 100644 --- a/TableTopInc.API/TableTopInc.API.Engine/Services/General/IGameDesignerRoleService.cs +++ b/TableTopInc.API/TableTopInc.API.Engine/Services/General/IGameDesignerRoleService.cs @@ -3,7 +3,7 @@ namespace TableTopInc.API.Engine.Services.General { - public interface IGameDesignerRoleService : IEntityService + public interface IGameDesignerRoleService : IEntityService { } diff --git a/TableTopInc.API/TableTopInc.API.Engine/Services/General/IGameService.cs b/TableTopInc.API/TableTopInc.API.Engine/Services/General/IGameService.cs index 1c48716..ae48ecc 100644 --- a/TableTopInc.API/TableTopInc.API.Engine/Services/General/IGameService.cs +++ b/TableTopInc.API/TableTopInc.API.Engine/Services/General/IGameService.cs @@ -9,6 +9,6 @@ namespace TableTopInc.API.Engine.Services.General public interface IGameService : IEntityService { Task> GetGamesByTagsAsync(params string[] tags); - Task> GetGamesByGameDesignersAsync(params Guid[] authors); + Task> GetGamesByGameDesignersAsync(params string[] authors); } } \ No newline at end of file diff --git a/TableTopInc.API/TableTopInc.API.Mock/Services/GameServiceMock.cs b/TableTopInc.API/TableTopInc.API.Mock/Services/GameServiceMock.cs deleted file mode 100644 index e1e2876..0000000 --- a/TableTopInc.API/TableTopInc.API.Mock/Services/GameServiceMock.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using TableTopInc.API.Engine.Models.General; -using TableTopInc.API.Engine.Services.General; - -namespace TableTopInc.API.Mock.Services -{ - public class GameServiceMock : IGameService - { - private readonly List _storage = new List(); - - public async Task SaveAsync(params IGameModel[] entities) - { - _storage.AddRange(entities); - } - - public Task DeleteByIdsAsync(params Guid[] ids) - { - throw new NotImplementedException(); - } - - public async Task> GetAllAsync() - { - return await Task.FromResult(_storage); - } - - public Task> GetByIdsAsync(params Guid[] ids) - { - throw new NotImplementedException(); - } - - public Task> GetGamesByTagsAsync(params string[] tags) - { - throw new NotImplementedException(); - } - - public Task> GetGamesByGameDesignersAsync(params Guid[] authors) - { - throw new NotImplementedException(); - } - } -} \ No newline at end of file diff --git a/TableTopInc.API/TableTopInc.API.Public/Const.cs b/TableTopInc.API/TableTopInc.API.Public/Const.cs new file mode 100644 index 0000000..29c518e --- /dev/null +++ b/TableTopInc.API/TableTopInc.API.Public/Const.cs @@ -0,0 +1,7 @@ +namespace TableTopInc.API.Public +{ + public static class Const + { + public const string StorageAccountConnectionName = "Storage"; + } +} \ No newline at end of file diff --git a/TableTopInc.API/TableTopInc.API.Public/Functions/General/GameDesignerRoleFunction.cs b/TableTopInc.API/TableTopInc.API.Public/Functions/General/GameDesignerRoleFunction.cs new file mode 100644 index 0000000..e9a46bf --- /dev/null +++ b/TableTopInc.API/TableTopInc.API.Public/Functions/General/GameDesignerRoleFunction.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Azure.WebJobs; +using Microsoft.Azure.WebJobs.Extensions.Http; +using Microsoft.Extensions.Logging; +using Microsoft.WindowsAzure.Storage.Table; +using TableTopInc.API.Engine.AzureStorage.Models.General; +using TableTopInc.API.Engine.AzureStorage.Services.General; +using TableTopInc.API.Engine.Services.General; +using TableTopInc.API.Public.Helpers; +using TableTopInc.API.Public.Models; + +namespace TableTopInc.API.Public.Functions.General +{ + public class GameDesignerRoleFunction + { + private const string Prefix = "GameDesignerRoles"; + + public static Func ResolveService = table => new GameDesignerRoleService(table); + + [FunctionName(Prefix + "-GetAll")] + public static async Task> GetAllAsync( + [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = Prefix)] + HttpRequest req, + [Table(GameDesignerRoleService.TableName, Connection = Const.StorageAccountConnectionName)]CloudTable table, + ILogger log) + { + var service = ResolveService(table); + + var entities = (await service.GetAllAsync()) + .Select(DtoMappingHelper.ToDto); + + return entities; + } + + [FunctionName(Prefix + "-GetById")] + public static async Task GetByIdAsync( + [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = Prefix + "/{id}")] + HttpRequest req, + string id, + [Table(GameDesignerRoleService.TableName, Connection = Const.StorageAccountConnectionName)]CloudTable table, + ILogger log) + { + var service = ResolveService(table); + + var entity = (await service.GetByIdsAsync(id)) + .SingleOrDefault(); + + return entity.ToDto(); + } + + [FunctionName(Prefix + "-Save")] + public static async Task SaveAsync( + [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = Prefix)] + [FromBody]GameDesignerRoleDto model, + [Table(GameDesignerRoleService.TableName, Connection = Const.StorageAccountConnectionName)]CloudTable table, + ILogger log) + { + var service = ResolveService(table); + + var entity = (await service.SaveAsync(GameDesignerRoleTableEntity.Create(model))) + .Single(); + + return entity.ToDto(); + } + + [FunctionName(Prefix + "-DeleteById")] + public static async Task DeleteByIdAsync( + [HttpTrigger(AuthorizationLevel.Anonymous, "delete", Route = Prefix + "/{id}")] + HttpRequest req, + string id, + [Table(GameDesignerRoleService.TableName, Connection = Const.StorageAccountConnectionName)]CloudTable table, + ILogger log) + { + var service = ResolveService(table); + + await service.DeleteByIdsAsync(id); + } + } +} \ No newline at end of file diff --git a/TableTopInc.API/TableTopInc.API.Public/Functions/General/GamesFunction.cs b/TableTopInc.API/TableTopInc.API.Public/Functions/General/GamesFunction.cs index 8cec746..16674d8 100644 --- a/TableTopInc.API/TableTopInc.API.Public/Functions/General/GamesFunction.cs +++ b/TableTopInc.API/TableTopInc.API.Public/Functions/General/GamesFunction.cs @@ -8,9 +8,9 @@ using Microsoft.Azure.WebJobs.Extensions.Http; using Microsoft.Extensions.Logging; using Microsoft.WindowsAzure.Storage.Table; -using TableTopInc.API.Engine.AzureStorage.Azure; using TableTopInc.API.Engine.AzureStorage.Models.General; using TableTopInc.API.Engine.AzureStorage.Services.General; +using TableTopInc.API.Engine.Services.General; using TableTopInc.API.Public.Helpers; using TableTopInc.API.Public.Models; @@ -18,77 +18,65 @@ namespace TableTopInc.API.Public.Functions.General { public static class GamesFunction { - private const string Prefix = "games"; + private const string Prefix = "Games"; - [FunctionName("Games-GetAll")] + public static Func ResolveService = table => new GameService(table); + + [FunctionName(Prefix + "-GetAll")] public static async Task> GetAllAsync( [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = Prefix)] HttpRequest req, - [Table(GameService.TableName, Connection = "Storage")]CloudTable gamesTable, + [Table(GameService.TableName, Connection = Const.StorageAccountConnectionName)]CloudTable table, ILogger log) { - var service = new GameService(gamesTable); + var service = ResolveService(table); - var games = (await service.GetAllAsync()) + var entities = (await service.GetAllAsync()) .Select(DtoMappingHelper.ToDto); - return games; + return entities; } - [FunctionName("Games-GetById")] + [FunctionName(Prefix + "-GetById")] public static async Task GetByIdAsync( - [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = Prefix + "/{gameId}")] + [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = Prefix + "/{id}")] HttpRequest req, - string gameId, - [Table(GameService.TableName, Connection = "Storage")]CloudTable gamesTable, + string id, + [Table(GameService.TableName, Connection = Const.StorageAccountConnectionName)]CloudTable table, ILogger log) { - if (!Guid.TryParse(gameId, out var id)) - { - throw new ArgumentException(nameof(gameId)); - } - - var service = new GameService(gamesTable); + var service = ResolveService(table); - var game = (await service.GetByIdsAsync(id)) + var entity = (await service.GetByIdsAsync(id)) .SingleOrDefault(); - return game.ToDto(); + return entity.ToDto(); } - [FunctionName("Games-Save")] + [FunctionName(Prefix + "-Save")] public static async Task SaveAsync( [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = Prefix)] [FromBody]GameDto model, - [Table(GameService.TableName, Connection = "Storage")]CloudTable gamesTable, + [Table(GameService.TableName, Connection = Const.StorageAccountConnectionName)]CloudTable table, ILogger log) { - if (string.IsNullOrWhiteSpace(model.Id)) - { - model.Id = AzureTableService.ToRowKey(Guid.NewGuid()); - } - - var service = new GameService(gamesTable); + var service = ResolveService(table); - await service.SaveAsync(GameTableEntity.Create(model)); + var entity = (await service.SaveAsync(GameTableEntity.Create(model))) + .Single(); - return model; + return entity.ToDto(); } - [FunctionName("Games-DeleteById")] + [FunctionName(Prefix + "-DeleteById")] public static async Task DeleteByIdAsync( - [HttpTrigger(AuthorizationLevel.Anonymous, "delete", Route = Prefix + "/{gameId}")] + [HttpTrigger(AuthorizationLevel.Anonymous, "delete", Route = Prefix + "/{id}")] HttpRequest req, - string gameId, - [Table(GameService.TableName, Connection = "Storage")]CloudTable gamesTable, + string id, + [Table(GameService.TableName, Connection = Const.StorageAccountConnectionName)]CloudTable table, ILogger log) { - if (!Guid.TryParse(gameId, out var id)) - { - throw new ArgumentException(nameof(gameId)); - } - - var service = new GameService(gamesTable); + var service = ResolveService(table); await service.DeleteByIdsAsync(id); } diff --git a/TableTopInc.API/TableTopInc.API.Public/Helpers/DtoMappingHelper.cs b/TableTopInc.API/TableTopInc.API.Public/Helpers/DtoMappingHelper.cs index 9636036..46c27f0 100644 --- a/TableTopInc.API/TableTopInc.API.Public/Helpers/DtoMappingHelper.cs +++ b/TableTopInc.API/TableTopInc.API.Public/Helpers/DtoMappingHelper.cs @@ -1,22 +1,31 @@ +using System; using AutoMapper; using TableTopInc.API.Engine.Models.General; using TableTopInc.API.Public.Models; namespace TableTopInc.API.Public.Helpers { - public static class DtoMappingHelper + internal static class DtoMappingHelper { - static DtoMappingHelper() + private static readonly Lazy ObjMapper = new Lazy(() => { - Mapper.Initialize(config => + var config = new MapperConfiguration(cfg => { - config.CreateMap(); + cfg.CreateMap(); + cfg.CreateMap(); }); - } - public static GameDto ToDto(this IGameModel model) + return config.CreateMapper(); + }); + + internal static GameDto ToDto(this IGameModel model) + { + return ObjMapper.Value.Map(model); + } + + internal static GameDesignerRoleDto ToDto(this IGameDesignerRoleModel model) { - return Mapper.Map(model); + return ObjMapper.Value.Map(model); } } } \ No newline at end of file diff --git a/TableTopInc.API/TableTopInc.API.Public/Models/GameDesignerRoleDto.cs b/TableTopInc.API/TableTopInc.API.Public/Models/GameDesignerRoleDto.cs new file mode 100644 index 0000000..4f53e73 --- /dev/null +++ b/TableTopInc.API/TableTopInc.API.Public/Models/GameDesignerRoleDto.cs @@ -0,0 +1,10 @@ +using TableTopInc.API.Engine.Models.General; + +namespace TableTopInc.API.Public.Models +{ + public class GameDesignerRoleDto : IGameDesignerRoleModel + { + public string Id { get; set; } + public string Title { get; set; } + } +} \ No newline at end of file diff --git a/TableTopInc.API/TableTopInc.API.Public/TableTopInc.API.Public.csproj b/TableTopInc.API/TableTopInc.API.Public/TableTopInc.API.Public.csproj index a623552..2f46d26 100644 --- a/TableTopInc.API/TableTopInc.API.Public/TableTopInc.API.Public.csproj +++ b/TableTopInc.API/TableTopInc.API.Public/TableTopInc.API.Public.csproj @@ -25,6 +25,5 @@ - \ No newline at end of file diff --git a/TableTopInc.API/TableTopInc.API.Test/Mock/Services/GameServiceMock.cs b/TableTopInc.API/TableTopInc.API.Test/Mock/Services/GameServiceMock.cs new file mode 100644 index 0000000..886070b --- /dev/null +++ b/TableTopInc.API/TableTopInc.API.Test/Mock/Services/GameServiceMock.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using TableTopInc.API.Engine.Models.General; +using TableTopInc.API.Engine.Services.General; + +namespace TableTopInc.API.Test.Mock.Services +{ + internal class GameServiceMock : IGameService + { + private List _storage = new List(); + + public async Task> SaveAsync(params IGameModel[] entities) + { + foreach (var entity in entities.Where(x => string.IsNullOrWhiteSpace(x.Id))) + { + entity.Id = Guid.NewGuid().ToString("N"); + } + + _storage.AddRange(entities); + + return entities; + } + + public async Task DeleteByIdsAsync(params string[] ids) + { + _storage = _storage + .Where(x => !ids.Contains(x.Id)) + .ToList(); + } + + public async Task> GetAllAsync() + { + return await Task.FromResult(_storage); + } + + public async Task> GetByIdsAsync(params string[] ids) + { + var data = _storage.Where(x => ids.Contains(x.Id)); + + return await Task.FromResult(data); + } + + public Task> GetGamesByTagsAsync(params string[] tags) + { + throw new NotImplementedException(); + } + + public Task> GetGamesByGameDesignersAsync(params string[] authors) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/TableTopInc.API/TableTopInc.API.Test/Public/Functions/General/GamesFunctionTest.cs b/TableTopInc.API/TableTopInc.API.Test/Public/Functions/General/GamesFunctionTest.cs new file mode 100644 index 0000000..c73dec3 --- /dev/null +++ b/TableTopInc.API/TableTopInc.API.Test/Public/Functions/General/GamesFunctionTest.cs @@ -0,0 +1,51 @@ +using System.Linq; +using System.Threading.Tasks; +using TableTopInc.API.Public.Functions.General; +using TableTopInc.API.Public.Models; +using TableTopInc.API.Test.Mock.Services; +using Xunit; + +namespace TableTopInc.API.Test.Public.Functions.General +{ + public class GamesFunctionTest + { + [Fact] + public async Task GetAllTest() + { + // given + var mock = new GameServiceMock(); + await mock.SaveAsync(new GameDto()); + + GamesFunction.ResolveService = table => mock; + + // when + var entities = await GamesFunction.GetAllAsync(null, null, null); + + // then + Assert.Equal(1, entities.Count()); + } + + [Fact] + public async Task SaveTest() + { + // given + var mock = new GameServiceMock(); + + GamesFunction.ResolveService = table => mock; + + // when 1 + var entities = await GamesFunction.GetAllAsync(null, null, null); + + // then 1 + Assert.Equal(0, entities.Count()); + + // when 2 + var entity = await GamesFunction.SaveAsync(new GameDto(), null, null); + entities = await GamesFunction.GetAllAsync(null, null, null); + + // then 2 + Assert.False(string.IsNullOrWhiteSpace(entity.Id)); + Assert.Equal(1, entities.Count()); + } + } +} \ No newline at end of file diff --git a/TableTopInc.API/TableTopInc.API.Test/Public/Functions/General/GamesTest.cs b/TableTopInc.API/TableTopInc.API.Test/Public/Functions/General/GamesTest.cs deleted file mode 100644 index 692cdc8..0000000 --- a/TableTopInc.API/TableTopInc.API.Test/Public/Functions/General/GamesTest.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.Threading.Tasks; -using Xunit; - -namespace TableTopInc.API.Test.Public.Functions.General -{ - public class GamesTest - { - [Fact] - public async Task GamesShouldReturnData() - { -// var data = await Games.GetAllAsync(null, null); -// -// Assert.True(data.Any()); - } - } -} \ No newline at end of file diff --git a/TableTopInc.API/TableTopInc.API.Test/TableTopInc.API.Test.csproj b/TableTopInc.API/TableTopInc.API.Test/TableTopInc.API.Test.csproj index 9ebe2d8..e490c0f 100644 --- a/TableTopInc.API/TableTopInc.API.Test/TableTopInc.API.Test.csproj +++ b/TableTopInc.API/TableTopInc.API.Test/TableTopInc.API.Test.csproj @@ -13,7 +13,12 @@ + + + + + diff --git a/TableTopInc.API/TableTopInc.API.sln b/TableTopInc.API/TableTopInc.API.sln index 699f9ca..829b91c 100644 --- a/TableTopInc.API/TableTopInc.API.sln +++ b/TableTopInc.API/TableTopInc.API.sln @@ -15,8 +15,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TableTopInc.API.Engine.Azur EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TableTopInc.API.Test", "TableTopInc.API.Test\TableTopInc.API.Test.csproj", "{ED564784-5862-4DCC-8780-ADF2434C47D5}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TableTopInc.API.Mock", "TableTopInc.API.Mock\TableTopInc.API.Mock.csproj", "{84270209-8375-413E-A488-02FEC86273C8}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -39,9 +37,5 @@ Global {ED564784-5862-4DCC-8780-ADF2434C47D5}.Debug|Any CPU.Build.0 = Debug|Any CPU {ED564784-5862-4DCC-8780-ADF2434C47D5}.Release|Any CPU.ActiveCfg = Release|Any CPU {ED564784-5862-4DCC-8780-ADF2434C47D5}.Release|Any CPU.Build.0 = Release|Any CPU - {84270209-8375-413E-A488-02FEC86273C8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {84270209-8375-413E-A488-02FEC86273C8}.Debug|Any CPU.Build.0 = Debug|Any CPU - {84270209-8375-413E-A488-02FEC86273C8}.Release|Any CPU.ActiveCfg = Release|Any CPU - {84270209-8375-413E-A488-02FEC86273C8}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal diff --git a/azure-pipelines.yml b/azure-pipelines.yml index f132a61..1ead3be 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -1,6 +1,9 @@ trigger: - master +pr: +- master + pool: vmImage: 'Ubuntu-16.04'