From 25b1346a7bec6a0be2b4622343cf46d9427cca30 Mon Sep 17 00:00:00 2001 From: GlebMoskalev Date: Tue, 15 Oct 2024 17:06:24 +0500 Subject: [PATCH] done --- ConsoleApp/Program.cs | 16 ++++++++---- Game/Domain/GameEntity.cs | 12 +++++---- Game/Domain/MongoGameRepository.cs | 21 +++++++++++----- Game/Domain/MongoUserRepositoty.cs | 40 ++++++++++++++++++++++-------- Game/Domain/Player.cs | 5 +++- Game/Domain/UserEntity.cs | 2 +- db.sln.DotSettings | 5 ++++ 7 files changed, 72 insertions(+), 29 deletions(-) diff --git a/ConsoleApp/Program.cs b/ConsoleApp/Program.cs index cf39300..10b4f16 100644 --- a/ConsoleApp/Program.cs +++ b/ConsoleApp/Program.cs @@ -1,19 +1,25 @@ using System; using System.Linq; using Game.Domain; +using MongoDB.Driver; namespace ConsoleApp { class Program { - private readonly IUserRepository userRepo; - private readonly IGameRepository gameRepo; + private readonly MongoUserRepository userRepo; + private readonly MongoGameRepository gameRepo; private readonly Random random = new Random(); + [Obsolete("Obsolete")] private Program(string[] args) { - userRepo = new InMemoryUserRepository(); - gameRepo = new InMemoryGameRepository(); + var mongoConnectionString = Environment.GetEnvironmentVariable("PROJECT5100_MONGO_CONNECTION_STRING") + ?? "mongodb://localhost:27017"; + var mongoClient = new MongoClient(mongoConnectionString); + var db = mongoClient.GetDatabase("game-tests"); + userRepo = new MongoUserRepository(db); + gameRepo = new MongoGameRepository(db); } public static void Main(string[] args) @@ -184,4 +190,4 @@ private void ShowScore(GameEntity game) Console.WriteLine($"Score: {players[0].Name} {players[0].Score} : {players[1].Score} {players[1].Name}"); } } -} +} \ No newline at end of file diff --git a/Game/Domain/GameEntity.cs b/Game/Domain/GameEntity.cs index ec7b5ec..1caf691 100644 --- a/Game/Domain/GameEntity.cs +++ b/Game/Domain/GameEntity.cs @@ -1,11 +1,13 @@ using System; using System.Collections.Generic; using System.Linq; +using MongoDB.Bson.Serialization.Attributes; namespace Game.Domain { public class GameEntity { + [BsonElement] private readonly List players; public GameEntity(int turnsCount) @@ -13,6 +15,7 @@ public GameEntity(int turnsCount) { } + [BsonConstructor] public GameEntity(Guid id, GameStatus status, int turnsCount, int currentTurnIndex, List players) { Id = id; @@ -21,20 +24,19 @@ public GameEntity(Guid id, GameStatus status, int turnsCount, int currentTurnInd CurrentTurnIndex = currentTurnIndex; this.players = players; } - + [BsonElement] public Guid Id { get; // ReSharper disable once AutoPropertyCanBeMadeGetOnly.Local For MongoDB private set; } - public IReadOnlyList Players => players.AsReadOnly(); - + [BsonElement] public int TurnsCount { get; } - + [BsonElement] public int CurrentTurnIndex { get; private set; } - + [BsonElement] public GameStatus Status { get; private set; } public void AddPlayer(UserEntity user) diff --git a/Game/Domain/MongoGameRepository.cs b/Game/Domain/MongoGameRepository.cs index 86873d4..64eeb7b 100644 --- a/Game/Domain/MongoGameRepository.cs +++ b/Game/Domain/MongoGameRepository.cs @@ -8,38 +8,47 @@ namespace Game.Domain public class MongoGameRepository : IGameRepository { public const string CollectionName = "games"; + private readonly IMongoCollection gameCollection; public MongoGameRepository(IMongoDatabase db) { + gameCollection = db.GetCollection(CollectionName); } public GameEntity Insert(GameEntity game) { - throw new NotImplementedException(); + gameCollection.InsertOne(game); + return game; } public GameEntity FindById(Guid gameId) { - throw new NotImplementedException(); + return gameCollection + .Find(g => g.Id == gameId) + .FirstOrDefault(); } public void Update(GameEntity game) { - throw new NotImplementedException(); + gameCollection + .FindOneAndReplace(g => g.Id == game.Id, game); } // Возвращает не более чем limit игр со статусом GameStatus.WaitingToStart public IList FindWaitingToStart(int limit) { - //TODO: Используй Find и Limit - throw new NotImplementedException(); + return gameCollection + .Find(g => g.Status == GameStatus.WaitingToStart) + .Limit(limit) + .ToList(); } // Обновляет игру, если она находится в статусе GameStatus.WaitingToStart public bool TryUpdateWaitingToStart(GameEntity game) { //TODO: Для проверки успешности используй IsAcknowledged и ModifiedCount из результата - throw new NotImplementedException(); + var result = gameCollection.ReplaceOne(g => g.Id == game.Id && g.Status == GameStatus.WaitingToStart, game); + return result.IsAcknowledged && result.ModifiedCount != 0; } } } \ No newline at end of file diff --git a/Game/Domain/MongoUserRepositoty.cs b/Game/Domain/MongoUserRepositoty.cs index 51aeba5..8b1d82b 100644 --- a/Game/Domain/MongoUserRepositoty.cs +++ b/Game/Domain/MongoUserRepositoty.cs @@ -1,4 +1,5 @@ using System; +using MongoDB.Bson; using MongoDB.Driver; namespace Game.Domain @@ -8,46 +9,63 @@ public class MongoUserRepository : IUserRepository private readonly IMongoCollection userCollection; public const string CollectionName = "users"; + [Obsolete("Obsolete")] public MongoUserRepository(IMongoDatabase database) { userCollection = database.GetCollection(CollectionName); + var options = new CreateIndexOptions {Unique = true}; + userCollection.Indexes.CreateOne("{Login: 1}", options); } public UserEntity Insert(UserEntity user) { - //TODO: Ищи в документации InsertXXX. - throw new NotImplementedException(); + userCollection.InsertOne(user); + return user; } public UserEntity FindById(Guid id) { - //TODO: Ищи в документации FindXXX - throw new NotImplementedException(); + return userCollection + .Find(x => x.Id == id) + .FirstOrDefault(); } public UserEntity GetOrCreateByLogin(string login) { - //TODO: Это Find или Insert - throw new NotImplementedException(); + var userEntity = userCollection.Find(x => x.Login == login).FirstOrDefault(); + if (userEntity != null) + return userEntity; + userEntity = new UserEntity(Guid.NewGuid()) + { + Login = login + }; + userCollection.InsertOne(userEntity); + return userEntity; } public void Update(UserEntity user) { - //TODO: Ищи в документации ReplaceXXX - throw new NotImplementedException(); + userCollection + .FindOneAndReplace(x => x.Id == user.Id, user); } public void Delete(Guid id) { - throw new NotImplementedException(); + userCollection + .FindOneAndDelete(x => x.Id == id); } // Для вывода списка всех пользователей (упорядоченных по логину) // страницы нумеруются с единицы public PageList GetPage(int pageNumber, int pageSize) { - //TODO: Тебе понадобятся SortBy, Skip и Limit - throw new NotImplementedException(); + var pageList = userCollection + .Aggregate() + .SortBy(x => x.Login) + .Skip((pageNumber - 1) * pageSize) + .Limit(pageSize) + .ToList(); + return new PageList(pageList, userCollection.CountDocuments(x => true), pageNumber, pageSize); } // Не нужно реализовывать этот метод diff --git a/Game/Domain/Player.cs b/Game/Domain/Player.cs index 9c4f838..4156ea7 100644 --- a/Game/Domain/Player.cs +++ b/Game/Domain/Player.cs @@ -1,4 +1,5 @@ using System; +using MongoDB.Bson.Serialization.Attributes; namespace Game.Domain { @@ -7,17 +8,19 @@ namespace Game.Domain /// public class Player { + [BsonConstructor] public Player(Guid userId, string name) { UserId = userId; Name = name; } - + [BsonElement] public Guid UserId { get; } /// /// Снэпшот имени игрока на момент старта игры. Считайте, что это такое требование к игре. /// + [BsonElement] public string Name { get; } /// diff --git a/Game/Domain/UserEntity.cs b/Game/Domain/UserEntity.cs index 671510c..1d8dcf3 100644 --- a/Game/Domain/UserEntity.cs +++ b/Game/Domain/UserEntity.cs @@ -1,4 +1,5 @@ using System; +using MongoDB.Bson.Serialization.Attributes; namespace Game.Domain { @@ -13,7 +14,6 @@ public UserEntity(Guid id) { Id = id; } - public UserEntity(Guid id, string login, string lastName, string firstName, int gamesPlayed, Guid? currentGameId) { Id = id; diff --git a/db.sln.DotSettings b/db.sln.DotSettings index b5ef7ae..3744498 100644 --- a/db.sln.DotSettings +++ b/db.sln.DotSettings @@ -19,6 +19,10 @@ <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb"><ExtraRule Prefix="" Suffix="" Style="aaBb" /></Policy> <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb_AaBb" /> + <Policy><Descriptor Staticness="Static" AccessRightKinds="Private" Description="Static readonly fields (private)"><ElementKinds><Kind Name="READONLY_FIELD" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb"><ExtraRule Prefix="" Suffix="" Style="aaBb" /></Policy></Policy> + <Policy><Descriptor Staticness="Instance" AccessRightKinds="Private" Description="Instance fields (private)"><ElementKinds><Kind Name="FIELD" /><Kind Name="READONLY_FIELD" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /></Policy> + <Policy><Descriptor Staticness="Any" AccessRightKinds="Any" Description="Types and namespaces"><ElementKinds><Kind Name="NAMESPACE" /><Kind Name="CLASS" /><Kind Name="STRUCT" /><Kind Name="ENUM" /><Kind Name="DELEGATE" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb_AaBb" /></Policy> + <Policy><Descriptor Staticness="Static" AccessRightKinds="Private" Description="Static fields (private)"><ElementKinds><Kind Name="FIELD" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /></Policy> <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> @@ -69,4 +73,5 @@ True True True + True True \ No newline at end of file