From b66785bdba0ffaa1cda229c79ccfe1e714d00494 Mon Sep 17 00:00:00 2001 From: LP Date: Wed, 23 Feb 2022 16:10:16 +0000 Subject: [PATCH 1/4] Moved to use a newer repository approach This would be a breaking change but makes things a bit more re-usable and type safe, only problem is LocaleRepository doesnt slot in nicely. --- .../DatabaseDataSource.cs | 23 +++++++++++ .../IDatabaseDataSource.cs | 7 ++++ .../OpenRpg.Data.Database.csproj | 24 +++++++++++ .../Builder/InMemoryDataSourceBuilder.cs | 40 +++++++++++++++++++ .../IInMemoryDataSource.cs | 7 ++++ .../InMemoryDataSource.cs | 32 +++++++++++++++ .../OpenRpg.Data.InMemory.csproj | 19 +++++++++ .../Extensions/RepositoryDataExtensions.cs | 20 ++++++++++ .../Extensions/RepositoryExtensions.cs | 22 ++++++++++ .../Conventions/Queries/CreateEntityQuery.cs | 20 ++++++++++ .../Conventions/Queries/DeleteEntityQuery.cs | 13 ++++++ .../Conventions/Queries/EntityExistsQuery.cs | 13 ++++++ .../Conventions/Queries/GetEntityQuery.cs | 13 ++++++ .../{ => Conventions}/Queries/IFindQuery.cs | 9 +++-- .../Conventions/Queries/UpdateEntityQuery.cs | 20 ++++++++++ src/OpenRpg.Data/DefaultRepository.cs | 12 ++++++ .../Defaults/InMemoryDataRepository.cs | 22 ---------- .../Defaults/InMemoryRepository.cs | 38 ------------------ .../Queries/Common/DynamicGetAllQuery.cs | 16 -------- .../Defaults/Queries/Common/GetAllQuery.cs | 10 ----- .../Defaults/Queries/Common/GetCountQuery.cs | 10 ----- .../Defaults/Queries/ExecuteInMemoryQuery.cs | 13 ------ .../Defaults/Queries/FindAllInMemoryQuery.cs | 13 ------ .../Defaults/Queries/FindInMemoryQuery.cs | 13 ------ src/OpenRpg.Data/IDataSource.cs | 16 ++++++++ src/OpenRpg.Data/IQuery.cs | 7 ++++ src/OpenRpg.Data/IRepository.cs | 9 +++++ src/OpenRpg.Data/Queries/IExecuteQuery.cs | 10 ----- src/OpenRpg.Data/Queries/IFindAllQuery.cs | 11 ----- .../Repositories/IDataRepository.cs | 7 ---- .../Repositories/IReadDataRepository.cs | 7 ---- .../Repositories/IReadRepository.cs | 13 ------ src/OpenRpg.Data/Repositories/IRepository.cs | 5 --- .../Repositories/IWriteDataRepository.cs | 7 ---- .../Repositories/IWriteRepository.cs | 13 ------ .../Queries/GetBatchLocalesQuery.cs | 21 ---------- .../Queries/ILocaleQuery.cs | 5 +++ .../Repositories/ILocaleRepository.cs | 7 ++-- .../Repositories/LocaleRepository.cs | 13 +----- src/OpenRpg.sln | 20 +++++++++- 40 files changed, 351 insertions(+), 249 deletions(-) create mode 100644 src/OpenRpg.Data.Database/DatabaseDataSource.cs create mode 100644 src/OpenRpg.Data.Database/IDatabaseDataSource.cs create mode 100644 src/OpenRpg.Data.Database/OpenRpg.Data.Database.csproj create mode 100644 src/OpenRpg.Data.InMemory/Builder/InMemoryDataSourceBuilder.cs create mode 100644 src/OpenRpg.Data.InMemory/IInMemoryDataSource.cs create mode 100644 src/OpenRpg.Data.InMemory/InMemoryDataSource.cs create mode 100644 src/OpenRpg.Data.InMemory/OpenRpg.Data.InMemory.csproj create mode 100644 src/OpenRpg.Data/Conventions/Extensions/RepositoryDataExtensions.cs create mode 100644 src/OpenRpg.Data/Conventions/Extensions/RepositoryExtensions.cs create mode 100644 src/OpenRpg.Data/Conventions/Queries/CreateEntityQuery.cs create mode 100644 src/OpenRpg.Data/Conventions/Queries/DeleteEntityQuery.cs create mode 100644 src/OpenRpg.Data/Conventions/Queries/EntityExistsQuery.cs create mode 100644 src/OpenRpg.Data/Conventions/Queries/GetEntityQuery.cs rename src/OpenRpg.Data/{ => Conventions}/Queries/IFindQuery.cs (60%) create mode 100644 src/OpenRpg.Data/Conventions/Queries/UpdateEntityQuery.cs create mode 100644 src/OpenRpg.Data/DefaultRepository.cs delete mode 100644 src/OpenRpg.Data/Defaults/InMemoryDataRepository.cs delete mode 100644 src/OpenRpg.Data/Defaults/InMemoryRepository.cs delete mode 100644 src/OpenRpg.Data/Defaults/Queries/Common/DynamicGetAllQuery.cs delete mode 100644 src/OpenRpg.Data/Defaults/Queries/Common/GetAllQuery.cs delete mode 100644 src/OpenRpg.Data/Defaults/Queries/Common/GetCountQuery.cs delete mode 100644 src/OpenRpg.Data/Defaults/Queries/ExecuteInMemoryQuery.cs delete mode 100644 src/OpenRpg.Data/Defaults/Queries/FindAllInMemoryQuery.cs delete mode 100644 src/OpenRpg.Data/Defaults/Queries/FindInMemoryQuery.cs create mode 100644 src/OpenRpg.Data/IDataSource.cs create mode 100644 src/OpenRpg.Data/IQuery.cs create mode 100644 src/OpenRpg.Data/IRepository.cs delete mode 100644 src/OpenRpg.Data/Queries/IExecuteQuery.cs delete mode 100644 src/OpenRpg.Data/Queries/IFindAllQuery.cs delete mode 100644 src/OpenRpg.Data/Repositories/IDataRepository.cs delete mode 100644 src/OpenRpg.Data/Repositories/IReadDataRepository.cs delete mode 100644 src/OpenRpg.Data/Repositories/IReadRepository.cs delete mode 100644 src/OpenRpg.Data/Repositories/IRepository.cs delete mode 100644 src/OpenRpg.Data/Repositories/IWriteDataRepository.cs delete mode 100644 src/OpenRpg.Data/Repositories/IWriteRepository.cs delete mode 100644 src/OpenRpg.Localization/Queries/GetBatchLocalesQuery.cs create mode 100644 src/OpenRpg.Localization/Queries/ILocaleQuery.cs diff --git a/src/OpenRpg.Data.Database/DatabaseDataSource.cs b/src/OpenRpg.Data.Database/DatabaseDataSource.cs new file mode 100644 index 0000000..caf26d8 --- /dev/null +++ b/src/OpenRpg.Data.Database/DatabaseDataSource.cs @@ -0,0 +1,23 @@ +using System.Collections.Generic; +using System.Data; +using Dapper; + +namespace OpenRpg.Data.Database +{ + public class DatabaseDataSource : IDatabaseDataSource + { + public IDbConnection Connection { get; } + + public object NativeSource => Connection; + + public DatabaseDataSource(IDbConnection connection) + { Connection = connection; } + + public T Get(object key) => Connection.Get(key); + public IEnumerable GetAll() => Connection.GetList(); + public void Create(T data, object key = null) => Connection.Insert(data); + public void Update(T data, object key) => Connection.Update(data); + public bool Delete(object key) => Connection.Delete(key) > 0; + public bool Exists(object key) => Get(key) != null; + } +} \ No newline at end of file diff --git a/src/OpenRpg.Data.Database/IDatabaseDataSource.cs b/src/OpenRpg.Data.Database/IDatabaseDataSource.cs new file mode 100644 index 0000000..fdd5e7c --- /dev/null +++ b/src/OpenRpg.Data.Database/IDatabaseDataSource.cs @@ -0,0 +1,7 @@ +namespace OpenRpg.Data.Database +{ + public interface IDatabaseDataSource : IDataSource + { + + } +} \ No newline at end of file diff --git a/src/OpenRpg.Data.Database/OpenRpg.Data.Database.csproj b/src/OpenRpg.Data.Database/OpenRpg.Data.Database.csproj new file mode 100644 index 0000000..ad38ce9 --- /dev/null +++ b/src/OpenRpg.Data.Database/OpenRpg.Data.Database.csproj @@ -0,0 +1,24 @@ + + + + 0.0.0 + net461;netstandard2.0 + OpenRpg.Data.Database + Grofit (LP) + https://github.com/openrpg/OpenRpg/blob/master/LICENSE + https://github.com/openrpg/OpenRpg + An SQL database implementation of the OpenRpg data layer using Dapper + rpg game-development repository data xna monogame unity godot + + + + + + + + + + + + + diff --git a/src/OpenRpg.Data.InMemory/Builder/InMemoryDataSourceBuilder.cs b/src/OpenRpg.Data.InMemory/Builder/InMemoryDataSourceBuilder.cs new file mode 100644 index 0000000..db5130d --- /dev/null +++ b/src/OpenRpg.Data.InMemory/Builder/InMemoryDataSourceBuilder.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace OpenRpg.Data.InMemory.Builder +{ + public class InMemoryDataSourceBuilder + { + private readonly Dictionary> Database; + + protected InMemoryDataSourceBuilder(Dictionary> database) + { + Database = database; + } + + public static InMemoryDataSourceBuilder Create() + { return new InMemoryDataSourceBuilder(new Dictionary>()); } + + public InMemoryDataSourceBuilder WithData(IEnumerable data, Func keySelector) + { + var typeOfT = typeof(T); + if (!Database.ContainsKey(typeOfT)) + { + var contents = data.ToDictionary(keySelector, x => (object)x); + Database.Add(typeOfT, contents); + return this; + } + + var typeContainer = Database[typeOfT]; + + foreach(var element in data) + { typeContainer.Add(keySelector(element), element); } + + return this; + } + + public IDataSource Build() + { return new InMemoryDataSource(Database); } + } +} \ No newline at end of file diff --git a/src/OpenRpg.Data.InMemory/IInMemoryDataSource.cs b/src/OpenRpg.Data.InMemory/IInMemoryDataSource.cs new file mode 100644 index 0000000..3638f3d --- /dev/null +++ b/src/OpenRpg.Data.InMemory/IInMemoryDataSource.cs @@ -0,0 +1,7 @@ +namespace OpenRpg.Data.InMemory +{ + public interface IInMemoryDataSource : IDataSource + { + + } +} \ No newline at end of file diff --git a/src/OpenRpg.Data.InMemory/InMemoryDataSource.cs b/src/OpenRpg.Data.InMemory/InMemoryDataSource.cs new file mode 100644 index 0000000..68c61b5 --- /dev/null +++ b/src/OpenRpg.Data.InMemory/InMemoryDataSource.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace OpenRpg.Data.InMemory +{ + public class InMemoryDataSource : IInMemoryDataSource + { + public Dictionary> Database { get; } + + public object NativeSource => Database; + + public InMemoryDataSource(Dictionary> database = null) + { Database = database ?? new Dictionary>(); } + + public T Get(object key) => (T)Database[typeof(T)][key]; + + public IEnumerable GetAll() => Database[typeof(T)].Values.Cast(); + + public void Create(T data, object key = null) + { + if(key == null) { throw new ArgumentNullException(nameof(key), "In Memory DB Requires explicit keys on creation"); } + Database[typeof(T)].Add(key, data); + } + + public void Update(T data, object key) => Database[typeof(T)][key] = data; + + public bool Delete(object key) => Database[typeof(T)].Remove(key); + + public bool Exists(object key) => Database[typeof(T)].ContainsKey(key); + } +} \ No newline at end of file diff --git a/src/OpenRpg.Data.InMemory/OpenRpg.Data.InMemory.csproj b/src/OpenRpg.Data.InMemory/OpenRpg.Data.InMemory.csproj new file mode 100644 index 0000000..2cf977d --- /dev/null +++ b/src/OpenRpg.Data.InMemory/OpenRpg.Data.InMemory.csproj @@ -0,0 +1,19 @@ + + + + 0.0.0 + netstandard2.0;net46 + OpenRpg.Data.InMemory + Grofit (LP) + https://github.com/openrpg/OpenRpg/blob/master/LICENSE + https://github.com/openrpg/OpenRpg + An in memory implementation of the OpenRpg data layer + rpg game-development repository data xna monogame unity godot + + + + + + + + diff --git a/src/OpenRpg.Data/Conventions/Extensions/RepositoryDataExtensions.cs b/src/OpenRpg.Data/Conventions/Extensions/RepositoryDataExtensions.cs new file mode 100644 index 0000000..1f34705 --- /dev/null +++ b/src/OpenRpg.Data/Conventions/Extensions/RepositoryDataExtensions.cs @@ -0,0 +1,20 @@ +using OpenRpg.Core.Common; +using OpenRpg.Data.Conventions.Queries; + +namespace OpenRpg.Data.Conventions.Extensions +{ + public static class RepositoryDataExtensions + { + public static T Create(this IRepository repository, T entity) where T : class, IHasDataId + { return repository.Query(new CreateEntityQuery(entity, entity.Id)); } + + public static T Update(this IRepository repository, T entity) where T : class, IHasDataId + { return repository.Query(new UpdateEntityQuery(entity, entity.Id)); } + + public static bool Delete(this IRepository repository, T entity) where T : class, IHasDataId + { return repository.Query(new DeleteEntityQuery(entity.Id)); } + + public static bool Exists(this IRepository repository, T entity) where T : class, IHasDataId + { return repository.Query(new EntityExistsQuery(entity.Id)); } + } +} \ No newline at end of file diff --git a/src/OpenRpg.Data/Conventions/Extensions/RepositoryExtensions.cs b/src/OpenRpg.Data/Conventions/Extensions/RepositoryExtensions.cs new file mode 100644 index 0000000..7de3c74 --- /dev/null +++ b/src/OpenRpg.Data/Conventions/Extensions/RepositoryExtensions.cs @@ -0,0 +1,22 @@ +using OpenRpg.Data.Conventions.Queries; + +namespace OpenRpg.Data.Conventions.Extensions +{ + public static class RepositoryExtensions + { + public static T Create(this IRepository repository, T entity, object key = null) where T : class + { return repository.Query(new CreateEntityQuery(entity, key)); } + + public static T Get(this IRepository repository, object key) where T : class + { return repository.Query(new GetEntityQuery(key)); } + + public static T Update(this IRepository repository, T entity, object key) where T : class + { return repository.Query(new UpdateEntityQuery(entity, key)); } + + public static bool Delete(this IRepository repository, object key) where T : class + { return repository.Query(new DeleteEntityQuery(key)); } + + public static bool Exists(this IRepository repository, object key) where T : class + { return repository.Query(new EntityExistsQuery(key)); } + } +} \ No newline at end of file diff --git a/src/OpenRpg.Data/Conventions/Queries/CreateEntityQuery.cs b/src/OpenRpg.Data/Conventions/Queries/CreateEntityQuery.cs new file mode 100644 index 0000000..69f8591 --- /dev/null +++ b/src/OpenRpg.Data/Conventions/Queries/CreateEntityQuery.cs @@ -0,0 +1,20 @@ +namespace OpenRpg.Data.Conventions.Queries +{ + public class CreateEntityQuery : IQuery + { + public T Entity { get; } + public object Key { get; } + + public CreateEntityQuery(T entity, object key = null) + { + Entity = entity; + Key = key; + } + + public T Execute(IDataSource dataSource) + { + dataSource.Create(Entity, Key); + return Entity; + } + } +} \ No newline at end of file diff --git a/src/OpenRpg.Data/Conventions/Queries/DeleteEntityQuery.cs b/src/OpenRpg.Data/Conventions/Queries/DeleteEntityQuery.cs new file mode 100644 index 0000000..8ff4104 --- /dev/null +++ b/src/OpenRpg.Data/Conventions/Queries/DeleteEntityQuery.cs @@ -0,0 +1,13 @@ +namespace OpenRpg.Data.Conventions.Queries +{ + public class DeleteEntityQuery : IQuery + { + public object Key { get; } + + public DeleteEntityQuery(object key) + { Key = key; } + + public bool Execute(IDataSource dataSource) + { return dataSource.Delete(Key); } + } +} \ No newline at end of file diff --git a/src/OpenRpg.Data/Conventions/Queries/EntityExistsQuery.cs b/src/OpenRpg.Data/Conventions/Queries/EntityExistsQuery.cs new file mode 100644 index 0000000..bc4dc09 --- /dev/null +++ b/src/OpenRpg.Data/Conventions/Queries/EntityExistsQuery.cs @@ -0,0 +1,13 @@ +namespace OpenRpg.Data.Conventions.Queries +{ + public class EntityExistsQuery : IQuery + { + public object Key { get; } + + public EntityExistsQuery(object key) + { Key = key; } + + public bool Execute(IDataSource dataSource) + { return dataSource.Exists(Key); } + } +} \ No newline at end of file diff --git a/src/OpenRpg.Data/Conventions/Queries/GetEntityQuery.cs b/src/OpenRpg.Data/Conventions/Queries/GetEntityQuery.cs new file mode 100644 index 0000000..eff068c --- /dev/null +++ b/src/OpenRpg.Data/Conventions/Queries/GetEntityQuery.cs @@ -0,0 +1,13 @@ +namespace OpenRpg.Data.Conventions.Queries +{ + public class GetEntityQuery : IQuery + { + public object Key { get; } + + public GetEntityQuery(object key) + { Key = key; } + + public T Execute(IDataSource dataSource) + { return dataSource.Get(Key); } + } +} \ No newline at end of file diff --git a/src/OpenRpg.Data/Queries/IFindQuery.cs b/src/OpenRpg.Data/Conventions/Queries/IFindQuery.cs similarity index 60% rename from src/OpenRpg.Data/Queries/IFindQuery.cs rename to src/OpenRpg.Data/Conventions/Queries/IFindQuery.cs index 2ae3a2e..15f8f8a 100644 --- a/src/OpenRpg.Data/Queries/IFindQuery.cs +++ b/src/OpenRpg.Data/Conventions/Queries/IFindQuery.cs @@ -1,12 +1,13 @@ -namespace OpenRpg.Data.Queries +using System.Collections.Generic; + +namespace OpenRpg.Data.Conventions.Queries { /// - /// The find query represents a query that finds something specific from the database, it a specific + /// The find query represents a query that finds something specific from the data source, it a specific /// /// Specific Type to return /// This is meant as a way to return types different to the repository type - public interface IFindQuery + public interface IFindQuery : IQuery> { - T Execute(object dataSource); } } \ No newline at end of file diff --git a/src/OpenRpg.Data/Conventions/Queries/UpdateEntityQuery.cs b/src/OpenRpg.Data/Conventions/Queries/UpdateEntityQuery.cs new file mode 100644 index 0000000..f3502a6 --- /dev/null +++ b/src/OpenRpg.Data/Conventions/Queries/UpdateEntityQuery.cs @@ -0,0 +1,20 @@ +namespace OpenRpg.Data.Conventions.Queries +{ + public class UpdateEntityQuery : IQuery + { + public T Entity { get; } + public object Key { get; } + + public UpdateEntityQuery(T entity, object key) + { + Entity = entity; + Key = key; + } + + public T Execute(IDataSource dataSource) + { + dataSource.Update(Entity, Key); + return Entity; + } + } +} \ No newline at end of file diff --git a/src/OpenRpg.Data/DefaultRepository.cs b/src/OpenRpg.Data/DefaultRepository.cs new file mode 100644 index 0000000..72ee5bb --- /dev/null +++ b/src/OpenRpg.Data/DefaultRepository.cs @@ -0,0 +1,12 @@ +namespace OpenRpg.Data +{ + public class DefaultRepository : IRepository + { + public IDataSource DataSource { get; } + + public DefaultRepository(IDataSource dataSource) + { DataSource = dataSource; } + + public T Query(IQuery query) => query.Execute(DataSource); + } +} \ No newline at end of file diff --git a/src/OpenRpg.Data/Defaults/InMemoryDataRepository.cs b/src/OpenRpg.Data/Defaults/InMemoryDataRepository.cs deleted file mode 100644 index f7c8fdc..0000000 --- a/src/OpenRpg.Data/Defaults/InMemoryDataRepository.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System.Collections.Generic; -using OpenRpg.Core.Common; -using OpenRpg.Data.Repositories; - -namespace OpenRpg.Data.Defaults -{ - /// - /// This is a layer on top of the InMemoryRepository that has awareness of the IHasDataId for Id lookup purposes - /// - /// - public class InMemoryDataRepository : InMemoryRepository, IDataRepository - where T : IHasDataId - { - protected override int GetKeyFromEntity(T entity) => entity.Id; - - public InMemoryDataRepository(IEnumerable data) : base(data) - {} - - protected InMemoryDataRepository() - {} - } -} \ No newline at end of file diff --git a/src/OpenRpg.Data/Defaults/InMemoryRepository.cs b/src/OpenRpg.Data/Defaults/InMemoryRepository.cs deleted file mode 100644 index f3283ba..0000000 --- a/src/OpenRpg.Data/Defaults/InMemoryRepository.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using OpenRpg.Data.Queries; -using OpenRpg.Data.Repositories; - -namespace OpenRpg.Data.Defaults -{ - /// - /// A simple implementation of a repository - /// - /// - /// It is expected that you would provide a populated enumerable to the constructor for most use cases here as the - /// data source, however you can extend it and built up the data internally if required for hard coded scenarios. - /// - /// Entity type - public abstract class InMemoryRepository : IRepository - { - public List Data { get; protected set; } - - public InMemoryRepository(IEnumerable data) - { Data = data.ToList(); } - - protected InMemoryRepository() - { Data = new List(); } - - protected abstract K GetKeyFromEntity(T entity); - - public void Create(T entry) => Data.Add(entry); - public T Retrieve(K id) => Data.SingleOrDefault(x => GetKeyFromEntity(x).Equals(id)); - public void Update(T entry) {} - public void Delete(T entry) => Data.Remove(entry); - - public IEnumerable FindAll(IFindAllQuery dataQuery) => dataQuery.Execute(Data); - public T2 Find(IFindQuery dataQuery) => dataQuery.Execute(Data); - public object Execute(IExecuteQuery query) => query.Execute(Data); - } -} \ No newline at end of file diff --git a/src/OpenRpg.Data/Defaults/Queries/Common/DynamicGetAllQuery.cs b/src/OpenRpg.Data/Defaults/Queries/Common/DynamicGetAllQuery.cs deleted file mode 100644 index 66e968e..0000000 --- a/src/OpenRpg.Data/Defaults/Queries/Common/DynamicGetAllQuery.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace OpenRpg.Data.Defaults.Queries.Common -{ - public class DynamicGetAllQuery : FindAllInMemoryQuery - { - public Func,IEnumerable> Filter { get; } - - public DynamicGetAllQuery(Func,IEnumerable> filter) - { Filter = filter; } - - public override IEnumerable Execute(List dataSource) - { return Filter(dataSource); } - } -} \ No newline at end of file diff --git a/src/OpenRpg.Data/Defaults/Queries/Common/GetAllQuery.cs b/src/OpenRpg.Data/Defaults/Queries/Common/GetAllQuery.cs deleted file mode 100644 index 7487b70..0000000 --- a/src/OpenRpg.Data/Defaults/Queries/Common/GetAllQuery.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System.Collections.Generic; - -namespace OpenRpg.Data.Defaults.Queries.Common -{ - public class GetAllQuery : FindAllInMemoryQuery - { - public override IEnumerable Execute(List dataSource) - { return dataSource; } - } -} \ No newline at end of file diff --git a/src/OpenRpg.Data/Defaults/Queries/Common/GetCountQuery.cs b/src/OpenRpg.Data/Defaults/Queries/Common/GetCountQuery.cs deleted file mode 100644 index f03eb6a..0000000 --- a/src/OpenRpg.Data/Defaults/Queries/Common/GetCountQuery.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System.Collections.Generic; - -namespace OpenRpg.Data.Defaults.Queries.Common -{ - public class GetCountQuery : FindInMemoryQuery - { - public override int Execute(List dataSource) - { return dataSource.Count; } - } -} \ No newline at end of file diff --git a/src/OpenRpg.Data/Defaults/Queries/ExecuteInMemoryQuery.cs b/src/OpenRpg.Data/Defaults/Queries/ExecuteInMemoryQuery.cs deleted file mode 100644 index 2383763..0000000 --- a/src/OpenRpg.Data/Defaults/Queries/ExecuteInMemoryQuery.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.Collections.Generic; -using OpenRpg.Data.Queries; - -namespace OpenRpg.Data.Defaults.Queries -{ - public abstract class ExecuteInMemoryQuery : IExecuteQuery - { - public object Execute(object dataSource) - { return Execute((List) dataSource); } - - public abstract object Execute(List dataSource); - } -} \ No newline at end of file diff --git a/src/OpenRpg.Data/Defaults/Queries/FindAllInMemoryQuery.cs b/src/OpenRpg.Data/Defaults/Queries/FindAllInMemoryQuery.cs deleted file mode 100644 index f821fa7..0000000 --- a/src/OpenRpg.Data/Defaults/Queries/FindAllInMemoryQuery.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.Collections.Generic; -using OpenRpg.Data.Queries; - -namespace OpenRpg.Data.Defaults.Queries -{ - public abstract class FindAllInMemoryQuery : IFindAllQuery - { - public IEnumerable Execute(object dataSource) - { return Execute((List) dataSource); } - - public abstract IEnumerable Execute(List dataSource); - } -} \ No newline at end of file diff --git a/src/OpenRpg.Data/Defaults/Queries/FindInMemoryQuery.cs b/src/OpenRpg.Data/Defaults/Queries/FindInMemoryQuery.cs deleted file mode 100644 index a883588..0000000 --- a/src/OpenRpg.Data/Defaults/Queries/FindInMemoryQuery.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.Collections.Generic; -using OpenRpg.Data.Queries; - -namespace OpenRpg.Data.Defaults.Queries -{ - public abstract class FindInMemoryQuery : IFindQuery - { - public T Execute(object dataSource) - { return Execute((List) dataSource); } - - public abstract T Execute(List dataSource); - } -} \ No newline at end of file diff --git a/src/OpenRpg.Data/IDataSource.cs b/src/OpenRpg.Data/IDataSource.cs new file mode 100644 index 0000000..786f246 --- /dev/null +++ b/src/OpenRpg.Data/IDataSource.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; + +namespace OpenRpg.Data +{ + public interface IDataSource + { + object NativeSource { get; } + + T Get(object key); + IEnumerable GetAll(); + void Create(T data, object key = null); + void Update(T data, object key); + bool Delete(object key); + bool Exists(object key); + } +} \ No newline at end of file diff --git a/src/OpenRpg.Data/IQuery.cs b/src/OpenRpg.Data/IQuery.cs new file mode 100644 index 0000000..8279544 --- /dev/null +++ b/src/OpenRpg.Data/IQuery.cs @@ -0,0 +1,7 @@ +namespace OpenRpg.Data +{ + public interface IQuery + { + T Execute(IDataSource dataSource); + } +} \ No newline at end of file diff --git a/src/OpenRpg.Data/IRepository.cs b/src/OpenRpg.Data/IRepository.cs new file mode 100644 index 0000000..7a1542b --- /dev/null +++ b/src/OpenRpg.Data/IRepository.cs @@ -0,0 +1,9 @@ +namespace OpenRpg.Data +{ + public interface IRepository + { + IDataSource DataSource { get; } + + T Query(IQuery query); + } +} \ No newline at end of file diff --git a/src/OpenRpg.Data/Queries/IExecuteQuery.cs b/src/OpenRpg.Data/Queries/IExecuteQuery.cs deleted file mode 100644 index d771c2a..0000000 --- a/src/OpenRpg.Data/Queries/IExecuteQuery.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace OpenRpg.Data.Queries -{ - /// - /// Execute queries are for altering data in the repository such as mass updates or deletions - /// - public interface IExecuteQuery - { - object Execute(object dataSource); - } -} \ No newline at end of file diff --git a/src/OpenRpg.Data/Queries/IFindAllQuery.cs b/src/OpenRpg.Data/Queries/IFindAllQuery.cs deleted file mode 100644 index 07297a1..0000000 --- a/src/OpenRpg.Data/Queries/IFindAllQuery.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Collections.Generic; - -namespace OpenRpg.Data.Queries -{ - /// - /// The FindAll Query is meant to represent a way to get a list of results back from the repository - /// - /// The data type to return - public interface IFindAllQuery : IFindQuery> - { } -} \ No newline at end of file diff --git a/src/OpenRpg.Data/Repositories/IDataRepository.cs b/src/OpenRpg.Data/Repositories/IDataRepository.cs deleted file mode 100644 index a080818..0000000 --- a/src/OpenRpg.Data/Repositories/IDataRepository.cs +++ /dev/null @@ -1,7 +0,0 @@ -using OpenRpg.Core.Common; - -namespace OpenRpg.Data.Repositories -{ - public interface IDataRepository : IReadDataRepository, IWriteDataRepository where T : IHasDataId - {} -} \ No newline at end of file diff --git a/src/OpenRpg.Data/Repositories/IReadDataRepository.cs b/src/OpenRpg.Data/Repositories/IReadDataRepository.cs deleted file mode 100644 index fb4f638..0000000 --- a/src/OpenRpg.Data/Repositories/IReadDataRepository.cs +++ /dev/null @@ -1,7 +0,0 @@ -using OpenRpg.Core.Common; - -namespace OpenRpg.Data.Repositories -{ - public interface IReadDataRepository : IReadRepository where T : IHasDataId - {} -} \ No newline at end of file diff --git a/src/OpenRpg.Data/Repositories/IReadRepository.cs b/src/OpenRpg.Data/Repositories/IReadRepository.cs deleted file mode 100644 index f57c518..0000000 --- a/src/OpenRpg.Data/Repositories/IReadRepository.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.Collections.Generic; -using OpenRpg.Data.Queries; - -namespace OpenRpg.Data.Repositories -{ - public interface IReadRepository - { - T Retrieve(K id); - - IEnumerable FindAll(IFindAllQuery query); - T2 Find(IFindQuery query); - } -} \ No newline at end of file diff --git a/src/OpenRpg.Data/Repositories/IRepository.cs b/src/OpenRpg.Data/Repositories/IRepository.cs deleted file mode 100644 index e24cd0b..0000000 --- a/src/OpenRpg.Data/Repositories/IRepository.cs +++ /dev/null @@ -1,5 +0,0 @@ -namespace OpenRpg.Data.Repositories -{ - public interface IRepository : IReadRepository, IWriteRepository - {} -} \ No newline at end of file diff --git a/src/OpenRpg.Data/Repositories/IWriteDataRepository.cs b/src/OpenRpg.Data/Repositories/IWriteDataRepository.cs deleted file mode 100644 index b6b8a8e..0000000 --- a/src/OpenRpg.Data/Repositories/IWriteDataRepository.cs +++ /dev/null @@ -1,7 +0,0 @@ -using OpenRpg.Core.Common; - -namespace OpenRpg.Data.Repositories -{ - public interface IWriteDataRepository : IWriteRepository where T : IHasDataId - {} -} \ No newline at end of file diff --git a/src/OpenRpg.Data/Repositories/IWriteRepository.cs b/src/OpenRpg.Data/Repositories/IWriteRepository.cs deleted file mode 100644 index 04879c7..0000000 --- a/src/OpenRpg.Data/Repositories/IWriteRepository.cs +++ /dev/null @@ -1,13 +0,0 @@ -using OpenRpg.Data.Queries; - -namespace OpenRpg.Data.Repositories -{ - public interface IWriteRepository - { - object Execute(IExecuteQuery query); - - void Create(T entry); - void Update(T entry); - void Delete(T entry); - } -} \ No newline at end of file diff --git a/src/OpenRpg.Localization/Queries/GetBatchLocalesQuery.cs b/src/OpenRpg.Localization/Queries/GetBatchLocalesQuery.cs deleted file mode 100644 index abcaabe..0000000 --- a/src/OpenRpg.Localization/Queries/GetBatchLocalesQuery.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System.Collections.Generic; -using OpenRpg.Data.Queries; - -namespace OpenRpg.Localization.Queries -{ - public class GetBatchLocalesQuery : IFindAllQuery - { - public IReadOnlyList Ids { get;} - - public GetBatchLocalesQuery(IReadOnlyList ids) - { Ids = ids; } - - public IEnumerable Execute(object dataSource) - { - var localeStore = dataSource as LocaleDataset; - - for (var i = 0; i < Ids.Count; i++) - { yield return localeStore.LocaleData[Ids[i]]; } - } - } -} \ No newline at end of file diff --git a/src/OpenRpg.Localization/Queries/ILocaleQuery.cs b/src/OpenRpg.Localization/Queries/ILocaleQuery.cs new file mode 100644 index 0000000..370cfd3 --- /dev/null +++ b/src/OpenRpg.Localization/Queries/ILocaleQuery.cs @@ -0,0 +1,5 @@ +using OpenRpg.Data; + +namespace OpenRpg.Localization.Queries +{ +} \ No newline at end of file diff --git a/src/OpenRpg.Localization/Repositories/ILocaleRepository.cs b/src/OpenRpg.Localization/Repositories/ILocaleRepository.cs index 29aeb40..218eecc 100644 --- a/src/OpenRpg.Localization/Repositories/ILocaleRepository.cs +++ b/src/OpenRpg.Localization/Repositories/ILocaleRepository.cs @@ -1,15 +1,16 @@ -using OpenRpg.Data.Repositories; - namespace OpenRpg.Localization.Repositories { - public interface ILocaleRepository : IReadRepository + public interface ILocaleRepository { string LocaleCode { get; } + string Get(string id); void ChangeLocale(LocaleDataset dataset); bool Has(string id); void Create(string id, string text); void Update(string id, string text); void Delete(string id); + + } } \ No newline at end of file diff --git a/src/OpenRpg.Localization/Repositories/LocaleRepository.cs b/src/OpenRpg.Localization/Repositories/LocaleRepository.cs index 46108ac..562083c 100644 --- a/src/OpenRpg.Localization/Repositories/LocaleRepository.cs +++ b/src/OpenRpg.Localization/Repositories/LocaleRepository.cs @@ -1,6 +1,3 @@ -using System.Collections.Generic; -using OpenRpg.Data.Queries; - namespace OpenRpg.Localization.Repositories { public class LocaleRepository : ILocaleRepository @@ -11,7 +8,7 @@ public class LocaleRepository : ILocaleRepository public LocaleRepository(LocaleDataset localeDataset) { LocaleDataset = localeDataset; } - public string Retrieve(string id) + public string Get(string id) { return LocaleDataset.LocaleData[id]; } public void ChangeLocale(LocaleDataset dataset) @@ -19,13 +16,7 @@ public void ChangeLocale(LocaleDataset dataset) public bool Has(string id) { return LocaleDataset.LocaleData.ContainsKey(id); } - - public IEnumerable FindAll(IFindAllQuery query) - { return query.Execute(LocaleDataset); } - - public T2 Find(IFindQuery query) - { return query.Execute(LocaleDataset); } - + public void Create(string id, string text) { LocaleDataset.LocaleData.Add(id, text); } diff --git a/src/OpenRpg.sln b/src/OpenRpg.sln index e0522d1..f155a39 100644 --- a/src/OpenRpg.sln +++ b/src/OpenRpg.sln @@ -28,6 +28,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Scaling", "Scaling", "{1566 EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenRpg.CurveFunctions", "OpenRpg.CurveFunctions\OpenRpg.CurveFunctions.csproj", "{91C35205-4EB6-4204-964E-D94427D362AA}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Data", "Data", "{8468364A-996C-4E7C-AB45-FEE8AEA6ABDE}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenRpg.Data.InMemory", "OpenRpg.Data.InMemory\OpenRpg.Data.InMemory.csproj", "{ADD47427-9A25-46AB-9414-100D29A3C74E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenRpg.Data.Database", "OpenRpg.Data.Database\OpenRpg.Data.Database.csproj", "{BAB3772D-236C-4872-BA89-469866F56CBB}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -66,15 +72,25 @@ Global {91C35205-4EB6-4204-964E-D94427D362AA}.Debug|Any CPU.Build.0 = Debug|Any CPU {91C35205-4EB6-4204-964E-D94427D362AA}.Release|Any CPU.ActiveCfg = Release|Any CPU {91C35205-4EB6-4204-964E-D94427D362AA}.Release|Any CPU.Build.0 = Release|Any CPU + {ADD47427-9A25-46AB-9414-100D29A3C74E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {ADD47427-9A25-46AB-9414-100D29A3C74E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {ADD47427-9A25-46AB-9414-100D29A3C74E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {ADD47427-9A25-46AB-9414-100D29A3C74E}.Release|Any CPU.Build.0 = Release|Any CPU + {BAB3772D-236C-4872-BA89-469866F56CBB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BAB3772D-236C-4872-BA89-469866F56CBB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BAB3772D-236C-4872-BA89-469866F56CBB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BAB3772D-236C-4872-BA89-469866F56CBB}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution {86FD715B-0B33-40EB-B8AC-25EE62398A66} = {6BE3D2A4-F53A-4879-868E-A7522A445FE9} - {BB417DEC-B2C9-4F60-9E87-2E674ACAD06F} = {6BE3D2A4-F53A-4879-868E-A7522A445FE9} - {5C2FF42D-8E29-4EDE-84D0-47D24FFFFBB9} = {6BE3D2A4-F53A-4879-868E-A7522A445FE9} {AB5563B9-CE48-49A4-BE3C-793351C7377F} = {7C187634-FF6B-4A6E-AAD2-FCA3C97C1E5A} {8D5C52B0-B68B-4539-9D2F-DA22C825B923} = {56A39779-8FA4-499E-8EF9-4757765CC230} {754A79DD-AC13-4EC1-9DDA-AF5D5F6DABCE} = {98CD79A9-0E41-49CE-8246-3A32C1A2E004} {2A8FA13E-2E89-457B-9457-46C345768495} = {C5E5EB5E-7F08-4CF4-B4DF-F20434DE2930} {91C35205-4EB6-4204-964E-D94427D362AA} = {1566BC2E-78DC-4998-BEC8-65CEC3EC9A88} + {BB417DEC-B2C9-4F60-9E87-2E674ACAD06F} = {8468364A-996C-4E7C-AB45-FEE8AEA6ABDE} + {5C2FF42D-8E29-4EDE-84D0-47D24FFFFBB9} = {8468364A-996C-4E7C-AB45-FEE8AEA6ABDE} + {ADD47427-9A25-46AB-9414-100D29A3C74E} = {8468364A-996C-4E7C-AB45-FEE8AEA6ABDE} + {BAB3772D-236C-4872-BA89-469866F56CBB} = {8468364A-996C-4E7C-AB45-FEE8AEA6ABDE} EndGlobalSection EndGlobal From 74333db55b8f53e5bcd49f0a32ddf960d9aa6567 Mon Sep 17 00:00:00 2001 From: LP Date: Thu, 24 Mar 2022 13:36:48 +0000 Subject: [PATCH 2/4] Couldn't align locales as easily as hoped This at least will give us some sort of improvements while keeping a similar interface as the core repositories, maybe one day they can be aligned better. --- appveyor.yml | 2 +- .../DatabaseDataSource.cs | 10 +++---- .../InMemoryDataSource.cs | 20 +++++-------- .../Extensions/RepositoryExtensions.cs | 20 ++++++------- .../Conventions/Queries/CreateEntityQuery.cs | 8 ++--- .../Conventions/Queries/DeleteEntityQuery.cs | 8 ++--- .../Conventions/Queries/EntityExistsQuery.cs | 8 ++--- .../Conventions/Queries/GetEntityQuery.cs | 8 ++--- .../Conventions/Queries/UpdateEntityQuery.cs | 8 ++--- src/OpenRpg.Data/IDataSource.cs | 10 +++---- .../Data/DataSources/ILocaleDataSource.cs | 12 ++++++++ .../DataSources/InMemoryLocaleDataSource.cs | 23 +++++++++++++++ .../Data/Extensions/RepositoryExtensions.cs | 27 +++++++++++++++++ .../Queries/Conventions/CreateLocaleQuery.cs | 22 ++++++++++++++ .../Queries/Conventions/DeleteLocaleQuery.cs | 18 ++++++++++++ .../Queries/Conventions/GetAllLocalesQuery.cs | 17 +++++++++++ .../Queries/Conventions/GetLocaleQuery.cs | 15 ++++++++++ .../Queries/Conventions/LocaleExistsQuery.cs | 15 ++++++++++ .../Queries/Conventions/UpdateLocaleQuery.cs | 22 ++++++++++++++ .../Data/Queries/ILocaleQuery.cs | 9 ++++++ .../Data/Repositories/ILocaleRepository.cs | 15 ++++++++++ .../Data/Repositories/LocaleRepository.cs | 22 ++++++++++++++ .../Queries/ILocaleQuery.cs | 5 ---- .../Repositories/ILocaleRepository.cs | 16 ---------- .../Repositories/LocaleRepository.cs | 29 ------------------- 25 files changed, 266 insertions(+), 103 deletions(-) create mode 100644 src/OpenRpg.Localization/Data/DataSources/ILocaleDataSource.cs create mode 100644 src/OpenRpg.Localization/Data/DataSources/InMemoryLocaleDataSource.cs create mode 100644 src/OpenRpg.Localization/Data/Extensions/RepositoryExtensions.cs create mode 100644 src/OpenRpg.Localization/Data/Queries/Conventions/CreateLocaleQuery.cs create mode 100644 src/OpenRpg.Localization/Data/Queries/Conventions/DeleteLocaleQuery.cs create mode 100644 src/OpenRpg.Localization/Data/Queries/Conventions/GetAllLocalesQuery.cs create mode 100644 src/OpenRpg.Localization/Data/Queries/Conventions/GetLocaleQuery.cs create mode 100644 src/OpenRpg.Localization/Data/Queries/Conventions/LocaleExistsQuery.cs create mode 100644 src/OpenRpg.Localization/Data/Queries/Conventions/UpdateLocaleQuery.cs create mode 100644 src/OpenRpg.Localization/Data/Queries/ILocaleQuery.cs create mode 100644 src/OpenRpg.Localization/Data/Repositories/ILocaleRepository.cs create mode 100644 src/OpenRpg.Localization/Data/Repositories/LocaleRepository.cs delete mode 100644 src/OpenRpg.Localization/Queries/ILocaleQuery.cs delete mode 100644 src/OpenRpg.Localization/Repositories/ILocaleRepository.cs delete mode 100644 src/OpenRpg.Localization/Repositories/LocaleRepository.cs diff --git a/appveyor.yml b/appveyor.yml index 2575913..5dc6c5a 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -27,7 +27,7 @@ deploy: APPVEYOR_REPO_TAG: true server: api_key: - secure: 0yJPCmw0EEE6ea73EEvaB8+TjIhUs0A8wG0dR60FEAu+B/i6x33b0GweDBVyz0PE + secure: ZBJLq3pN+Q0n1I99/r9rVbdWuCfAiv7bobV9WYDiMR3ebjIx/3d/AVcYK27zC3vm skip_symbols: true symbol_server: artifact: /.*\.nupkg/ diff --git a/src/OpenRpg.Data.Database/DatabaseDataSource.cs b/src/OpenRpg.Data.Database/DatabaseDataSource.cs index caf26d8..f90a060 100644 --- a/src/OpenRpg.Data.Database/DatabaseDataSource.cs +++ b/src/OpenRpg.Data.Database/DatabaseDataSource.cs @@ -13,11 +13,11 @@ public class DatabaseDataSource : IDatabaseDataSource public DatabaseDataSource(IDbConnection connection) { Connection = connection; } - public T Get(object key) => Connection.Get(key); + public T Get(object id) => Connection.Get(id); public IEnumerable GetAll() => Connection.GetList(); - public void Create(T data, object key = null) => Connection.Insert(data); - public void Update(T data, object key) => Connection.Update(data); - public bool Delete(object key) => Connection.Delete(key) > 0; - public bool Exists(object key) => Get(key) != null; + public void Create(T data, object id = null) => Connection.Insert(data); + public void Update(T data, object id) => Connection.Update(data); + public bool Delete(object id) => Connection.Delete(id) > 0; + public bool Exists(object id) => Get(id) != null; } } \ No newline at end of file diff --git a/src/OpenRpg.Data.InMemory/InMemoryDataSource.cs b/src/OpenRpg.Data.InMemory/InMemoryDataSource.cs index 68c61b5..9a8476a 100644 --- a/src/OpenRpg.Data.InMemory/InMemoryDataSource.cs +++ b/src/OpenRpg.Data.InMemory/InMemoryDataSource.cs @@ -13,20 +13,16 @@ public class InMemoryDataSource : IInMemoryDataSource public InMemoryDataSource(Dictionary> database = null) { Database = database ?? new Dictionary>(); } - public T Get(object key) => (T)Database[typeof(T)][key]; - + public T Get(object id) => (T)Database[typeof(T)][id]; public IEnumerable GetAll() => Database[typeof(T)].Values.Cast(); - - public void Create(T data, object key = null) + public void Update(T data, object id) => Database[typeof(T)][id] = data; + public bool Delete(object id) => Database[typeof(T)].Remove(id); + public bool Exists(object id) => Database[typeof(T)].ContainsKey(id); + + public void Create(T data, object id = null) { - if(key == null) { throw new ArgumentNullException(nameof(key), "In Memory DB Requires explicit keys on creation"); } - Database[typeof(T)].Add(key, data); + if(id == null) { throw new ArgumentNullException(nameof(id), "In Memory DB Requires explicit keys on creation"); } + Database[typeof(T)].Add(id, data); } - - public void Update(T data, object key) => Database[typeof(T)][key] = data; - - public bool Delete(object key) => Database[typeof(T)].Remove(key); - - public bool Exists(object key) => Database[typeof(T)].ContainsKey(key); } } \ No newline at end of file diff --git a/src/OpenRpg.Data/Conventions/Extensions/RepositoryExtensions.cs b/src/OpenRpg.Data/Conventions/Extensions/RepositoryExtensions.cs index 7de3c74..25b7dde 100644 --- a/src/OpenRpg.Data/Conventions/Extensions/RepositoryExtensions.cs +++ b/src/OpenRpg.Data/Conventions/Extensions/RepositoryExtensions.cs @@ -4,19 +4,19 @@ namespace OpenRpg.Data.Conventions.Extensions { public static class RepositoryExtensions { - public static T Create(this IRepository repository, T entity, object key = null) where T : class - { return repository.Query(new CreateEntityQuery(entity, key)); } + public static T Create(this IRepository repository, T entity, object id = null) where T : class + { return repository.Query(new CreateEntityQuery(entity, id)); } - public static T Get(this IRepository repository, object key) where T : class - { return repository.Query(new GetEntityQuery(key)); } + public static T Get(this IRepository repository, object id) where T : class + { return repository.Query(new GetEntityQuery(id)); } - public static T Update(this IRepository repository, T entity, object key) where T : class - { return repository.Query(new UpdateEntityQuery(entity, key)); } + public static T Update(this IRepository repository, T entity, object id) where T : class + { return repository.Query(new UpdateEntityQuery(entity, id)); } - public static bool Delete(this IRepository repository, object key) where T : class - { return repository.Query(new DeleteEntityQuery(key)); } + public static bool Delete(this IRepository repository, object id) where T : class + { return repository.Query(new DeleteEntityQuery(id)); } - public static bool Exists(this IRepository repository, object key) where T : class - { return repository.Query(new EntityExistsQuery(key)); } + public static bool Exists(this IRepository repository, object id) where T : class + { return repository.Query(new EntityExistsQuery(id)); } } } \ No newline at end of file diff --git a/src/OpenRpg.Data/Conventions/Queries/CreateEntityQuery.cs b/src/OpenRpg.Data/Conventions/Queries/CreateEntityQuery.cs index 69f8591..1067527 100644 --- a/src/OpenRpg.Data/Conventions/Queries/CreateEntityQuery.cs +++ b/src/OpenRpg.Data/Conventions/Queries/CreateEntityQuery.cs @@ -3,17 +3,17 @@ namespace OpenRpg.Data.Conventions.Queries public class CreateEntityQuery : IQuery { public T Entity { get; } - public object Key { get; } + public object Id { get; } - public CreateEntityQuery(T entity, object key = null) + public CreateEntityQuery(T entity, object id = null) { Entity = entity; - Key = key; + Id = id; } public T Execute(IDataSource dataSource) { - dataSource.Create(Entity, Key); + dataSource.Create(Entity, Id); return Entity; } } diff --git a/src/OpenRpg.Data/Conventions/Queries/DeleteEntityQuery.cs b/src/OpenRpg.Data/Conventions/Queries/DeleteEntityQuery.cs index 8ff4104..182e52f 100644 --- a/src/OpenRpg.Data/Conventions/Queries/DeleteEntityQuery.cs +++ b/src/OpenRpg.Data/Conventions/Queries/DeleteEntityQuery.cs @@ -2,12 +2,12 @@ namespace OpenRpg.Data.Conventions.Queries { public class DeleteEntityQuery : IQuery { - public object Key { get; } + public object Id { get; } - public DeleteEntityQuery(object key) - { Key = key; } + public DeleteEntityQuery(object id) + { Id = id; } public bool Execute(IDataSource dataSource) - { return dataSource.Delete(Key); } + { return dataSource.Delete(Id); } } } \ No newline at end of file diff --git a/src/OpenRpg.Data/Conventions/Queries/EntityExistsQuery.cs b/src/OpenRpg.Data/Conventions/Queries/EntityExistsQuery.cs index bc4dc09..fa49b58 100644 --- a/src/OpenRpg.Data/Conventions/Queries/EntityExistsQuery.cs +++ b/src/OpenRpg.Data/Conventions/Queries/EntityExistsQuery.cs @@ -2,12 +2,12 @@ namespace OpenRpg.Data.Conventions.Queries { public class EntityExistsQuery : IQuery { - public object Key { get; } + public object Id { get; } - public EntityExistsQuery(object key) - { Key = key; } + public EntityExistsQuery(object id) + { Id = id; } public bool Execute(IDataSource dataSource) - { return dataSource.Exists(Key); } + { return dataSource.Exists(Id); } } } \ No newline at end of file diff --git a/src/OpenRpg.Data/Conventions/Queries/GetEntityQuery.cs b/src/OpenRpg.Data/Conventions/Queries/GetEntityQuery.cs index eff068c..62d54a5 100644 --- a/src/OpenRpg.Data/Conventions/Queries/GetEntityQuery.cs +++ b/src/OpenRpg.Data/Conventions/Queries/GetEntityQuery.cs @@ -2,12 +2,12 @@ namespace OpenRpg.Data.Conventions.Queries { public class GetEntityQuery : IQuery { - public object Key { get; } + public object Id { get; } - public GetEntityQuery(object key) - { Key = key; } + public GetEntityQuery(object id) + { Id = id; } public T Execute(IDataSource dataSource) - { return dataSource.Get(Key); } + { return dataSource.Get(Id); } } } \ No newline at end of file diff --git a/src/OpenRpg.Data/Conventions/Queries/UpdateEntityQuery.cs b/src/OpenRpg.Data/Conventions/Queries/UpdateEntityQuery.cs index f3502a6..1cbca40 100644 --- a/src/OpenRpg.Data/Conventions/Queries/UpdateEntityQuery.cs +++ b/src/OpenRpg.Data/Conventions/Queries/UpdateEntityQuery.cs @@ -3,17 +3,17 @@ namespace OpenRpg.Data.Conventions.Queries public class UpdateEntityQuery : IQuery { public T Entity { get; } - public object Key { get; } + public object Id { get; } - public UpdateEntityQuery(T entity, object key) + public UpdateEntityQuery(T entity, object id) { Entity = entity; - Key = key; + Id = id; } public T Execute(IDataSource dataSource) { - dataSource.Update(Entity, Key); + dataSource.Update(Entity, Id); return Entity; } } diff --git a/src/OpenRpg.Data/IDataSource.cs b/src/OpenRpg.Data/IDataSource.cs index 786f246..33dc99c 100644 --- a/src/OpenRpg.Data/IDataSource.cs +++ b/src/OpenRpg.Data/IDataSource.cs @@ -6,11 +6,11 @@ public interface IDataSource { object NativeSource { get; } - T Get(object key); + T Get(object id); IEnumerable GetAll(); - void Create(T data, object key = null); - void Update(T data, object key); - bool Delete(object key); - bool Exists(object key); + void Create(T data, object id = null); + void Update(T data, object id); + bool Delete(object id); + bool Exists(object id); } } \ No newline at end of file diff --git a/src/OpenRpg.Localization/Data/DataSources/ILocaleDataSource.cs b/src/OpenRpg.Localization/Data/DataSources/ILocaleDataSource.cs new file mode 100644 index 0000000..67fbbb9 --- /dev/null +++ b/src/OpenRpg.Localization/Data/DataSources/ILocaleDataSource.cs @@ -0,0 +1,12 @@ +namespace OpenRpg.Localization.Data.DataSources +{ + public interface ILocaleDataSource + { + object NativeSource { get; } + string Get(string localeCode, string key); + void Create(string localeCode, string text, string key); + void Update(string localeCode, string text, string key); + bool Delete(string localeCode, string key); + bool Exists(string localeCode, string key); + } +} \ No newline at end of file diff --git a/src/OpenRpg.Localization/Data/DataSources/InMemoryLocaleDataSource.cs b/src/OpenRpg.Localization/Data/DataSources/InMemoryLocaleDataSource.cs new file mode 100644 index 0000000..6239de2 --- /dev/null +++ b/src/OpenRpg.Localization/Data/DataSources/InMemoryLocaleDataSource.cs @@ -0,0 +1,23 @@ +using System.Collections.Generic; +using System.Linq; + +namespace OpenRpg.Localization.Data.DataSources +{ + public class InMemoryLocaleDataSource : ILocaleDataSource + { + public Dictionary LocaleDatasets { get; } + public object NativeSource => LocaleDatasets; + + public InMemoryLocaleDataSource(IEnumerable localeDatasets = null) + { + LocaleDatasets = localeDatasets?.ToDictionary(x => x.LocaleCode, x => x) ?? + new Dictionary(); + } + + public string Get(string localeCode, string key) => LocaleDatasets[localeCode].LocaleData[key]; + public void Create(string localeCode, string text, string key) => LocaleDatasets[localeCode].LocaleData.Add(key, text); + public void Update(string localeCode, string text, string key) => LocaleDatasets[localeCode].LocaleData[key] = text; + public bool Delete(string localeCode, string key) => LocaleDatasets[localeCode].LocaleData.Remove(key); + public bool Exists(string localeCode, string key) => LocaleDatasets[localeCode].LocaleData.ContainsKey(key); + } +} \ No newline at end of file diff --git a/src/OpenRpg.Localization/Data/Extensions/RepositoryExtensions.cs b/src/OpenRpg.Localization/Data/Extensions/RepositoryExtensions.cs new file mode 100644 index 0000000..a33b996 --- /dev/null +++ b/src/OpenRpg.Localization/Data/Extensions/RepositoryExtensions.cs @@ -0,0 +1,27 @@ +using System.Collections.Generic; +using OpenRpg.Localization.Data.Queries.Conventions; +using OpenRpg.Localization.Data.Repositories; + +namespace OpenRpg.Localization.Data.Extensions +{ + public static class LocaleRepositoryExtensions + { + public static string Create(this ILocaleRepository repository, string text, string id) + { return repository.Query(new CreateLocaleQuery(text, id)); } + + public static string Get(this ILocaleRepository repository, string id) + { return repository.Query(new GetLocaleQuery(id)); } + + public static IEnumerable GetAll(this ILocaleRepository repository, params string[] ids) + { return repository.Query(new GetAllLocalesQuery(ids)); } + + public static string Update(this ILocaleRepository repository, string text, string id) + { return repository.Query(new UpdateLocaleQuery(text, id)); } + + public static bool Delete(this ILocaleRepository repository, string id) + { return repository.Query(new DeleteLocaleQuery(id)); } + + public static bool Exists(this ILocaleRepository repository, string id) + { return repository.Query(new LocaleExistsQuery(id)); } + } +} \ No newline at end of file diff --git a/src/OpenRpg.Localization/Data/Queries/Conventions/CreateLocaleQuery.cs b/src/OpenRpg.Localization/Data/Queries/Conventions/CreateLocaleQuery.cs new file mode 100644 index 0000000..ce2716b --- /dev/null +++ b/src/OpenRpg.Localization/Data/Queries/Conventions/CreateLocaleQuery.cs @@ -0,0 +1,22 @@ +using OpenRpg.Localization.Data.DataSources; + +namespace OpenRpg.Localization.Data.Queries.Conventions +{ + public class CreateLocaleQuery : ILocaleQuery + { + public string Text { get; } + public string Id { get; } + + public CreateLocaleQuery(string text, string id) + { + Text = text; + Id = id; + } + + public string Execute(string localeCode, ILocaleDataSource dataSource) + { + dataSource.Create(localeCode, Text, Id); + return Id; + } + } +} \ No newline at end of file diff --git a/src/OpenRpg.Localization/Data/Queries/Conventions/DeleteLocaleQuery.cs b/src/OpenRpg.Localization/Data/Queries/Conventions/DeleteLocaleQuery.cs new file mode 100644 index 0000000..8792d69 --- /dev/null +++ b/src/OpenRpg.Localization/Data/Queries/Conventions/DeleteLocaleQuery.cs @@ -0,0 +1,18 @@ +using OpenRpg.Localization.Data.DataSources; + +namespace OpenRpg.Localization.Data.Queries.Conventions +{ + public class DeleteLocaleQuery : ILocaleQuery + { + public string Id { get; } + + public DeleteLocaleQuery(string id) + { Id = id; } + + public bool Execute(string localeCode, ILocaleDataSource dataSource) + { + dataSource.Delete(localeCode, Id); + return true; + } + } +} \ No newline at end of file diff --git a/src/OpenRpg.Localization/Data/Queries/Conventions/GetAllLocalesQuery.cs b/src/OpenRpg.Localization/Data/Queries/Conventions/GetAllLocalesQuery.cs new file mode 100644 index 0000000..291868d --- /dev/null +++ b/src/OpenRpg.Localization/Data/Queries/Conventions/GetAllLocalesQuery.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; +using System.Linq; +using OpenRpg.Localization.Data.DataSources; + +namespace OpenRpg.Localization.Data.Queries.Conventions +{ + public class GetAllLocalesQuery : ILocaleQuery> + { + public string[] Ids { get; } + + public GetAllLocalesQuery(params string[] ids) + { Ids = ids; } + + public IEnumerable Execute(string locale, ILocaleDataSource dataSource) + { return Ids.Select(x => dataSource.Get(locale, x)); } + } +} \ No newline at end of file diff --git a/src/OpenRpg.Localization/Data/Queries/Conventions/GetLocaleQuery.cs b/src/OpenRpg.Localization/Data/Queries/Conventions/GetLocaleQuery.cs new file mode 100644 index 0000000..aebd983 --- /dev/null +++ b/src/OpenRpg.Localization/Data/Queries/Conventions/GetLocaleQuery.cs @@ -0,0 +1,15 @@ +using OpenRpg.Localization.Data.DataSources; + +namespace OpenRpg.Localization.Data.Queries.Conventions +{ + public class GetLocaleQuery : ILocaleQuery + { + public string Id { get; } + + public GetLocaleQuery(string id) + { Id = id; } + + public string Execute(string locale, ILocaleDataSource dataSource) + { return dataSource.Get(locale, Id); } + } +} \ No newline at end of file diff --git a/src/OpenRpg.Localization/Data/Queries/Conventions/LocaleExistsQuery.cs b/src/OpenRpg.Localization/Data/Queries/Conventions/LocaleExistsQuery.cs new file mode 100644 index 0000000..015d635 --- /dev/null +++ b/src/OpenRpg.Localization/Data/Queries/Conventions/LocaleExistsQuery.cs @@ -0,0 +1,15 @@ +using OpenRpg.Localization.Data.DataSources; + +namespace OpenRpg.Localization.Data.Queries.Conventions +{ + public class LocaleExistsQuery : ILocaleQuery + { + public string Id { get; } + + public LocaleExistsQuery(string id) + { Id = id; } + + public bool Execute(string locale, ILocaleDataSource dataSource) + { return dataSource.Exists(locale, Id); } + } +} \ No newline at end of file diff --git a/src/OpenRpg.Localization/Data/Queries/Conventions/UpdateLocaleQuery.cs b/src/OpenRpg.Localization/Data/Queries/Conventions/UpdateLocaleQuery.cs new file mode 100644 index 0000000..77531b9 --- /dev/null +++ b/src/OpenRpg.Localization/Data/Queries/Conventions/UpdateLocaleQuery.cs @@ -0,0 +1,22 @@ +using OpenRpg.Localization.Data.DataSources; + +namespace OpenRpg.Localization.Data.Queries.Conventions +{ + public class UpdateLocaleQuery : ILocaleQuery + { + public string Text { get; } + public string Key { get; } + + public UpdateLocaleQuery(string text, string key) + { + Text = text; + Key = key; + } + + public string Execute(string locale, ILocaleDataSource dataSource) + { + dataSource.Update(locale, Text, Key); + return Key; + } + } +} \ No newline at end of file diff --git a/src/OpenRpg.Localization/Data/Queries/ILocaleQuery.cs b/src/OpenRpg.Localization/Data/Queries/ILocaleQuery.cs new file mode 100644 index 0000000..7bf82e2 --- /dev/null +++ b/src/OpenRpg.Localization/Data/Queries/ILocaleQuery.cs @@ -0,0 +1,9 @@ +using OpenRpg.Localization.Data.DataSources; + +namespace OpenRpg.Localization.Data.Queries +{ + public interface ILocaleQuery + { + T Execute(string locale, ILocaleDataSource dataSource); + } +} \ No newline at end of file diff --git a/src/OpenRpg.Localization/Data/Repositories/ILocaleRepository.cs b/src/OpenRpg.Localization/Data/Repositories/ILocaleRepository.cs new file mode 100644 index 0000000..8d1b702 --- /dev/null +++ b/src/OpenRpg.Localization/Data/Repositories/ILocaleRepository.cs @@ -0,0 +1,15 @@ +using OpenRpg.Localization.Data.DataSources; +using OpenRpg.Localization.Data.Queries; + +namespace OpenRpg.Localization.Data.Repositories +{ + public interface ILocaleRepository + { + string CurrentLocaleCode { get; } + void ChangeLocale(string localeCode); + + ILocaleDataSource DataSource { get; } + + T Query(ILocaleQuery query); + } +} \ No newline at end of file diff --git a/src/OpenRpg.Localization/Data/Repositories/LocaleRepository.cs b/src/OpenRpg.Localization/Data/Repositories/LocaleRepository.cs new file mode 100644 index 0000000..7ba6ebb --- /dev/null +++ b/src/OpenRpg.Localization/Data/Repositories/LocaleRepository.cs @@ -0,0 +1,22 @@ +using OpenRpg.Localization.Data.DataSources; +using OpenRpg.Localization.Data.Queries; + +namespace OpenRpg.Localization.Data.Repositories +{ + public class LocaleRepository : ILocaleRepository + { + public string CurrentLocaleCode { get; private set; } + public ILocaleDataSource DataSource { get; } + + public LocaleRepository(ILocaleDataSource dataSource, string localeCodeToUse) + { + DataSource = dataSource; + CurrentLocaleCode = localeCodeToUse; + } + + public void ChangeLocale(string localeCode) + { CurrentLocaleCode = localeCode; } + + public T Query(ILocaleQuery query) => query.Execute(CurrentLocaleCode, DataSource); + } +} \ No newline at end of file diff --git a/src/OpenRpg.Localization/Queries/ILocaleQuery.cs b/src/OpenRpg.Localization/Queries/ILocaleQuery.cs deleted file mode 100644 index 370cfd3..0000000 --- a/src/OpenRpg.Localization/Queries/ILocaleQuery.cs +++ /dev/null @@ -1,5 +0,0 @@ -using OpenRpg.Data; - -namespace OpenRpg.Localization.Queries -{ -} \ No newline at end of file diff --git a/src/OpenRpg.Localization/Repositories/ILocaleRepository.cs b/src/OpenRpg.Localization/Repositories/ILocaleRepository.cs deleted file mode 100644 index 218eecc..0000000 --- a/src/OpenRpg.Localization/Repositories/ILocaleRepository.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace OpenRpg.Localization.Repositories -{ - public interface ILocaleRepository - { - string LocaleCode { get; } - - string Get(string id); - void ChangeLocale(LocaleDataset dataset); - bool Has(string id); - void Create(string id, string text); - void Update(string id, string text); - void Delete(string id); - - - } -} \ No newline at end of file diff --git a/src/OpenRpg.Localization/Repositories/LocaleRepository.cs b/src/OpenRpg.Localization/Repositories/LocaleRepository.cs deleted file mode 100644 index 562083c..0000000 --- a/src/OpenRpg.Localization/Repositories/LocaleRepository.cs +++ /dev/null @@ -1,29 +0,0 @@ -namespace OpenRpg.Localization.Repositories -{ - public class LocaleRepository : ILocaleRepository - { - public string LocaleCode => LocaleDataset.LocaleCode; - public LocaleDataset LocaleDataset { get; protected set; } - - public LocaleRepository(LocaleDataset localeDataset) - { LocaleDataset = localeDataset; } - - public string Get(string id) - { return LocaleDataset.LocaleData[id]; } - - public void ChangeLocale(LocaleDataset dataset) - { LocaleDataset = dataset; } - - public bool Has(string id) - { return LocaleDataset.LocaleData.ContainsKey(id); } - - public void Create(string id, string text) - { LocaleDataset.LocaleData.Add(id, text); } - - public void Update(string id, string text) - { LocaleDataset.LocaleData[id] = text; } - - public void Delete(string id) - { LocaleDataset.LocaleData.Remove(id); } - } -} \ No newline at end of file From 75a16d4e28b6db342630c78ea089bca53cbe8ddd Mon Sep 17 00:00:00 2001 From: LP Date: Thu, 24 Mar 2022 13:37:43 +0000 Subject: [PATCH 3/4] Started adding tests around some bits with logic Historically there was so little logic in OpenRPG it didn't really warrent testing, but now there are some logical bits so adding some tests in for those bits we do have. --- src/OpenRpg.Core/Utils/DefaultRandomizer.cs | 8 +- src/OpenRpg.Core/Utils/IRandomizer.cs | 2 +- ...unction.cs => PassThroughCurveFunction.cs} | 2 +- .../Extensions/ICurveFunctionExtensions.cs | 3 +- .../Extensions/IRandomizerExtensions.cs | 31 +++++++ .../OpenRpg.CurveFunctions.csproj | 4 + src/OpenRpg.CurveFunctions/PresetCurves.cs | 2 +- .../Framework/DefaultKeyedVariablesTests.cs | 93 +++++++++++++++++++ .../OpenRpg.UnitTests.csproj | 28 ++++++ .../Scaling/CurveExtensionTests.cs | 28 ++++++ .../Scaling/CurveFunctionTests.cs | 90 ++++++++++++++++++ .../Scaling/RandomizerExtensionTests.cs | 47 ++++++++++ src/OpenRpg.sln | 13 ++- 13 files changed, 341 insertions(+), 10 deletions(-) rename src/OpenRpg.CurveFunctions/Curves/{PassThroughlCurveFunction.cs => PassThroughCurveFunction.cs} (66%) create mode 100644 src/OpenRpg.CurveFunctions/Extensions/IRandomizerExtensions.cs create mode 100644 src/OpenRpg.UnitTests/Framework/DefaultKeyedVariablesTests.cs create mode 100644 src/OpenRpg.UnitTests/OpenRpg.UnitTests.csproj create mode 100644 src/OpenRpg.UnitTests/Scaling/CurveExtensionTests.cs create mode 100644 src/OpenRpg.UnitTests/Scaling/CurveFunctionTests.cs create mode 100644 src/OpenRpg.UnitTests/Scaling/RandomizerExtensionTests.cs diff --git a/src/OpenRpg.Core/Utils/DefaultRandomizer.cs b/src/OpenRpg.Core/Utils/DefaultRandomizer.cs index 2c68fa6..435db65 100644 --- a/src/OpenRpg.Core/Utils/DefaultRandomizer.cs +++ b/src/OpenRpg.Core/Utils/DefaultRandomizer.cs @@ -2,15 +2,15 @@ namespace OpenRpg.Core.Utils { public class DefaultRandomizer : IRandomizer { - private System.Random _random; + public System.Random NativeRandomizer { get; } public DefaultRandomizer(System.Random random) - { _random = random; } + { NativeRandomizer = random; } public int Random(int min, int max) - { return _random.Next(min, max + 1); } + { return NativeRandomizer.Next(min, max + 1); } public float Random(float min, float max) - { return (float)_random.NextDouble() * (max - min) + min; } + { return (float)NativeRandomizer.NextDouble() * (max - min) + min; } } } \ No newline at end of file diff --git a/src/OpenRpg.Core/Utils/IRandomizer.cs b/src/OpenRpg.Core/Utils/IRandomizer.cs index f8b355c..4b14c7e 100644 --- a/src/OpenRpg.Core/Utils/IRandomizer.cs +++ b/src/OpenRpg.Core/Utils/IRandomizer.cs @@ -3,6 +3,6 @@ namespace OpenRpg.Core.Utils public interface IRandomizer { int Random(int min, int max); - float Random(float min, float max); + float Random(float min = 0, float max = 1.0f); } } \ No newline at end of file diff --git a/src/OpenRpg.CurveFunctions/Curves/PassThroughlCurveFunction.cs b/src/OpenRpg.CurveFunctions/Curves/PassThroughCurveFunction.cs similarity index 66% rename from src/OpenRpg.CurveFunctions/Curves/PassThroughlCurveFunction.cs rename to src/OpenRpg.CurveFunctions/Curves/PassThroughCurveFunction.cs index 7f7b392..a3de47d 100644 --- a/src/OpenRpg.CurveFunctions/Curves/PassThroughlCurveFunction.cs +++ b/src/OpenRpg.CurveFunctions/Curves/PassThroughCurveFunction.cs @@ -1,6 +1,6 @@ namespace OpenRpg.CurveFunctions.Curves { - public class PassThroughlCurveFunction : ICurveFunction + public class PassThroughCurveFunction : ICurveFunction { public float Plot(float value) { return value; } diff --git a/src/OpenRpg.CurveFunctions/Extensions/ICurveFunctionExtensions.cs b/src/OpenRpg.CurveFunctions/Extensions/ICurveFunctionExtensions.cs index 0743602..275510f 100644 --- a/src/OpenRpg.CurveFunctions/Extensions/ICurveFunctionExtensions.cs +++ b/src/OpenRpg.CurveFunctions/Extensions/ICurveFunctionExtensions.cs @@ -16,8 +16,7 @@ public static float SanitizeValue(this ICurveFunction curve, float value) /// The denormalized value from the curve public static float ScaledPlot(this ICurveFunction curve, float value, float maxValue) { - if (value == 0) { return 0; } - var normalizedValue = value / maxValue; + var normalizedValue = (value + float.Epsilon) / maxValue; var normalizedOutput = curve.Plot(normalizedValue); return normalizedOutput * maxValue; } diff --git a/src/OpenRpg.CurveFunctions/Extensions/IRandomizerExtensions.cs b/src/OpenRpg.CurveFunctions/Extensions/IRandomizerExtensions.cs new file mode 100644 index 0000000..9c8f230 --- /dev/null +++ b/src/OpenRpg.CurveFunctions/Extensions/IRandomizerExtensions.cs @@ -0,0 +1,31 @@ +using System; +using OpenRpg.Core.Utils; + +namespace OpenRpg.CurveFunctions.Extensions +{ + public static class IRandomizerExtensions + { + public static float Random(this IRandomizer randomizer, ICurveFunction curve) + { + var randomNumber = randomizer.Random(); + return curve.Plot(randomNumber); + } + + public static float Random(this IRandomizer randomizer, ICurveFunction curve, float minValue, float maxValue) + { + var randomNumber = randomizer.Random(minValue, maxValue); + var isNegative = minValue < 0; + if (isNegative) + { + randomNumber = Math.Abs(randomNumber); + maxValue = Math.Abs(minValue); + } + + var result = curve.ScaledPlot(randomNumber, maxValue); + return isNegative ? -result : result; + } + + public static int Random(this IRandomizer randomizer, ICurveFunction curve, int minValue, int maxValue) + { return (int)Random(randomizer, curve, minValue, (float)maxValue); } + } +} \ No newline at end of file diff --git a/src/OpenRpg.CurveFunctions/OpenRpg.CurveFunctions.csproj b/src/OpenRpg.CurveFunctions/OpenRpg.CurveFunctions.csproj index 2cdc0f0..2a9b06b 100644 --- a/src/OpenRpg.CurveFunctions/OpenRpg.CurveFunctions.csproj +++ b/src/OpenRpg.CurveFunctions/OpenRpg.CurveFunctions.csproj @@ -11,4 +11,8 @@ rpg game-development xna monogame unity godot + + + + diff --git a/src/OpenRpg.CurveFunctions/PresetCurves.cs b/src/OpenRpg.CurveFunctions/PresetCurves.cs index a227582..8bbb5c6 100644 --- a/src/OpenRpg.CurveFunctions/PresetCurves.cs +++ b/src/OpenRpg.CurveFunctions/PresetCurves.cs @@ -23,6 +23,6 @@ public class PresetCurves public static SineCurveFunction InverseSineWave = new SineCurveFunction(-1.0f, 0, 0); public static StepCurveFunction GreaterThanHalf = new StepCurveFunction(0.5f); public static StepCurveFunction LessThanHalf = new StepCurveFunction(0.5f, 1.0f, 0.0f); - public static PassThroughlCurveFunction PassThrough = new PassThroughlCurveFunction(); + public static PassThroughCurveFunction PassThrough = new PassThroughCurveFunction(); } } \ No newline at end of file diff --git a/src/OpenRpg.UnitTests/Framework/DefaultKeyedVariablesTests.cs b/src/OpenRpg.UnitTests/Framework/DefaultKeyedVariablesTests.cs new file mode 100644 index 0000000..350e2cc --- /dev/null +++ b/src/OpenRpg.UnitTests/Framework/DefaultKeyedVariablesTests.cs @@ -0,0 +1,93 @@ +using System.Collections.Generic; +using OpenRpg.Core.Variables; +using Xunit; + +namespace OpenRpg.UnitTests.Framework; + +public class DefaultKeyedVariablesTests +{ + [Fact] + public void should_correctly_raise_add_event_on_adding_variables() + { + var expectedArgs = new VariableEventArgs(1, default, 10); + VariableEventArgs actualArgs = null; + + var variables = new DefaultKeyedVariables(); + variables.OnAdded += (sender, args) => actualArgs = args; + + variables.AddVariable(expectedArgs.VariableType, expectedArgs.NewValue); + + Assert.NotNull(actualArgs); + Assert.Equal(expectedArgs.VariableType, actualArgs.VariableType); + Assert.Equal(expectedArgs.OldValue, actualArgs.OldValue); + Assert.Equal(expectedArgs.NewValue, actualArgs.NewValue); + + Assert.Equal(expectedArgs.NewValue, variables.InternalVariables[expectedArgs.VariableType]); + } + + [Fact] + public void should_correctly_raise_change_event_on_updating_variables() + { + var expectedArgs = new VariableEventArgs(1, 10, 100); + VariableEventArgs actualArgs = null; + + var variables = new DefaultKeyedVariables(new Dictionary { {1, 10} }); + variables.OnChanged += (sender, args) => actualArgs = args; + + variables[expectedArgs.VariableType] = expectedArgs.NewValue; + + Assert.NotNull(actualArgs); + Assert.Equal(expectedArgs.VariableType, actualArgs.VariableType); + Assert.Equal(expectedArgs.OldValue, actualArgs.OldValue); + Assert.Equal(expectedArgs.NewValue, actualArgs.NewValue); + + Assert.Equal(expectedArgs.NewValue, variables.InternalVariables[expectedArgs.VariableType]); + } + + [Fact] + public void should_correctly_raise_remove_event_on_removing_variables() + { + var expectedArgs = new VariableEventArgs(1, 10, default); + VariableEventArgs actualArgs = null; + + var variables = new DefaultKeyedVariables(new Dictionary { {1, 10} }); + variables.OnRemoved += (sender, args) => actualArgs = args; + + variables.Remove(expectedArgs.VariableType); + + Assert.NotNull(actualArgs); + Assert.Equal(expectedArgs.VariableType, actualArgs.VariableType); + Assert.Equal(expectedArgs.OldValue, actualArgs.OldValue); + Assert.Equal(expectedArgs.NewValue, actualArgs.NewValue); + + Assert.False(variables.InternalVariables.ContainsKey(expectedArgs.VariableType)); + } + + [Fact] + public void should_do_insert_on_key_update_if_key_doesnt_exist() + { + var expectedAddArgs = new VariableEventArgs(1, default, 10); + var expectedChangeArgs = new VariableEventArgs(1, 10, 100); + VariableEventArgs actualAddArgs = null; + VariableEventArgs actualChangedArgs = null; + + var variables = new DefaultKeyedVariables(); + variables.OnAdded += (sender, args) => actualAddArgs = args; + variables.OnChanged += (sender, args) => actualChangedArgs = args; + + variables[expectedAddArgs.VariableType] = expectedAddArgs.NewValue; + variables[expectedChangeArgs.VariableType] = expectedChangeArgs.NewValue; + + Assert.NotNull(actualAddArgs); + Assert.Equal(expectedAddArgs.VariableType, actualAddArgs.VariableType); + Assert.Equal(expectedAddArgs.OldValue, actualAddArgs.OldValue); + Assert.Equal(expectedAddArgs.NewValue, actualAddArgs.NewValue); + + Assert.NotNull(actualChangedArgs); + Assert.Equal(expectedChangeArgs.VariableType, actualChangedArgs.VariableType); + Assert.Equal(expectedChangeArgs.OldValue, actualChangedArgs.OldValue); + Assert.Equal(expectedChangeArgs.NewValue, actualChangedArgs.NewValue); + + Assert.Equal(expectedChangeArgs.NewValue, variables.InternalVariables[expectedChangeArgs.VariableType]); + } +} \ No newline at end of file diff --git a/src/OpenRpg.UnitTests/OpenRpg.UnitTests.csproj b/src/OpenRpg.UnitTests/OpenRpg.UnitTests.csproj new file mode 100644 index 0000000..14075f4 --- /dev/null +++ b/src/OpenRpg.UnitTests/OpenRpg.UnitTests.csproj @@ -0,0 +1,28 @@ + + + + net6.0 + enable + + false + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + diff --git a/src/OpenRpg.UnitTests/Scaling/CurveExtensionTests.cs b/src/OpenRpg.UnitTests/Scaling/CurveExtensionTests.cs new file mode 100644 index 0000000..7ea1dd1 --- /dev/null +++ b/src/OpenRpg.UnitTests/Scaling/CurveExtensionTests.cs @@ -0,0 +1,28 @@ +using System.Collections.Generic; +using OpenRpg.CurveFunctions; +using OpenRpg.CurveFunctions.Extensions; +using Xunit; + +namespace OpenRpg.UnitTests.Scaling; + +public class CurveExtensionTests +{ + public static IEnumerable TestData() + { + yield return new object[] { PresetCurves.Linear, 10, 100, 10 }; + yield return new object[] { PresetCurves.Linear, 50, 100, 50 }; + yield return new object[] { PresetCurves.InverseLinear, 50, 100, 50 }; + yield return new object[] { PresetCurves.InverseLinear, 10, 100, 90 }; + yield return new object[] { PresetCurves.InverseLinear, 10, 100000, 99990 }; + yield return new object[] { PresetCurves.InverseLinear, 0, 10, 10 }; + yield return new object[] { PresetCurves.BellCurve, 5, 10, 10 }; + } + + [Theory] + [MemberData(nameof(TestData))] + public void should_scale_plot_correctly(ICurveFunction curve, float inputValue, float maxValue, float expectedValue) + { + var actualValue = curve.ScaledPlot(inputValue, maxValue); + Assert.Equal(expectedValue, actualValue); + } +} \ No newline at end of file diff --git a/src/OpenRpg.UnitTests/Scaling/CurveFunctionTests.cs b/src/OpenRpg.UnitTests/Scaling/CurveFunctionTests.cs new file mode 100644 index 0000000..92bccf1 --- /dev/null +++ b/src/OpenRpg.UnitTests/Scaling/CurveFunctionTests.cs @@ -0,0 +1,90 @@ +using OpenRpg.CurveFunctions.Curves; +using Xunit; + +namespace OpenRpg.UnitTests.Scaling; + +public class CurveFunctionTests +{ + [Theory] + [InlineData(1.0f, 0f, 0.0f, 1.0f, 5.0f, 1.0f)] // Doesnt go over 1 + [InlineData(1.0f, 0f, 0.0f, 1.0f, -10.0f, 0.0f)] // Doesnt go below 0 + [InlineData(1.0f, 0f, 0.0f, 1.0f, 0.4f, 0.27f)] + [InlineData(1.0f, 0f, 0.0f, 1.0f, 1.0f, 0.99f)] + [InlineData(1.0f, 0f, 1.0f, 1.0f, 1.0f, 1.0f)] + public void should_correctly_calculate_logistic_curve_value(float slope, float xShift, float yShift, float verticalSize, float inputValue, float expectedValue) + { + var curve = new LogisticCurveFunction(slope, xShift, yShift, verticalSize); + var actualValue = curve.Plot(inputValue); + Assert.Equal(expectedValue.ToString("F"), actualValue.ToString("F")); + } + + [Theory] + [InlineData(2.0f, 0f, 2.0f, 0.5f, 1.0f)] // Doesnt go over 1 + [InlineData(1.0f, 0f, 0.0f, -10.0f, 0.0f)] // Doesnt go below 0 + [InlineData(1.0f, 0f, 0.0f, 0.4f, 0.42f)] + [InlineData(1.0f, 0f, 0.0f, 1.0f, 0.0f)] + [InlineData(1.0f, 0f, 1.0f, 1.0f, 0.0f)] + public void should_correctly_calculate_logit_curve_value(float slope, float xShift, float yShift, float inputValue, float expectedValue) + { + var curve = new LogitCurveFunction(slope, xShift, yShift); + var actualValue = curve.Plot(inputValue); + Assert.Equal(expectedValue.ToString("F"), actualValue.ToString("F")); + } + + [Theory] + [InlineData(2.0f, 0.2f, 2.0f, 2.0f, 0.5f, 1.0f)] // Doesnt go over 1 + [InlineData(1.0f, 0f, 0.0f, 1.0f, -10.0f, 0.0f)] // Doesnt go below 0 + [InlineData(1.0f, 0f, 0.0f, 1.0f, 0.4f, 0.74f)] + [InlineData(1.0f, 0f, 0.0f, 1.0f, 1.0f, 0)] + [InlineData(1.0f, 0.2f, 1.0f, 1.0f, 1.0f, 1.0f)] + public void should_correctly_calculate_normal_curve_value(float slope, float xShift, float yShift, float verticalSize, float inputValue, float expectedValue) + { + var curve = new NormalCurveFunction(slope, xShift, yShift, verticalSize); + var actualValue = curve.Plot(inputValue); + Assert.Equal(expectedValue.ToString("F"), actualValue.ToString("F")); + } + + [Theory] + [InlineData(1.0f, 0f, 0.0f, 1.0f, 5.0f, 1.0f)] // Doesnt go over 1 + [InlineData(1.0f, 0f, 0.0f, 1.0f, -10.0f, 0.0f)] // Doesnt go below 0 + [InlineData(1.0f, 0f, 0.0f, 1.0f, 0.4f, 0.4f)] + [InlineData(-1.0f, 0f, 1.0f, 4.0f, 0.5f, 0.94f)] + [InlineData(1.0f, 0f, 1.0f, 1.0f, 1.0f, 1.0f)] + public void should_correctly_calculate_polynomial_curve_value(float slope, float xShift, float yShift, float verticalSize, float inputValue, float expectedValue) + { + var curve = new PolynomialCurveFunction(slope, xShift, yShift, verticalSize); + var actualValue = curve.Plot(inputValue); + Assert.Equal(expectedValue.ToString("F"), actualValue.ToString("F")); + } + + [Theory] + [InlineData(1.0f, 0, 2.0f, 0.5f, 1.0f)] // Doesnt go over 1 + [InlineData(1.0f, 0, -0.1f, 0.8f, 0.0f)] // Doesnt go below 0 + [InlineData(1.0f, 0, 0, 0.4f, 0.79f)] + public void should_correctly_calculate_sine_curve_value(float slope, float xShift, float yShift, float inputValue, float expectedValue) + { + var curve = new SineCurveFunction(slope, xShift, yShift); + var actualValue = curve.Plot(inputValue); + Assert.Equal(expectedValue.ToString("F"), actualValue.ToString("F")); + } + + [Theory] + [InlineData(1.0f, 0, 2.0f, 1.0f, 1.0f)] // Doesnt go over 1 + [InlineData(1.0f, 0, -0.1f, 0.8f, 0.0f)] // Doesnt go below 0 + [InlineData(0.5f, 1.0f, 0.0f, 0.45f, 1.0f)] + public void should_correctly_calculate_step_curve_value(float slope, float xShift, float yShift, float inputValue, float expectedValue) + { + var curve = new StepCurveFunction(slope, xShift, yShift); + var actualValue = curve.Plot(inputValue); + Assert.Equal(expectedValue.ToString("F"), actualValue.ToString("F")); + } + + [Theory] + [InlineData(0.5f, 0.5f)] // Passes through + public void should_correctly_pass_through_curve_value(float inputValue, float expectedValue) + { + var curve = new PassThroughCurveFunction(); + var actualValue = curve.Plot(inputValue); + Assert.Equal(expectedValue.ToString("F"), actualValue.ToString("F")); + } +} \ No newline at end of file diff --git a/src/OpenRpg.UnitTests/Scaling/RandomizerExtensionTests.cs b/src/OpenRpg.UnitTests/Scaling/RandomizerExtensionTests.cs new file mode 100644 index 0000000..f4a1063 --- /dev/null +++ b/src/OpenRpg.UnitTests/Scaling/RandomizerExtensionTests.cs @@ -0,0 +1,47 @@ +using Moq; +using OpenRpg.Core.Utils; +using OpenRpg.CurveFunctions; +using OpenRpg.CurveFunctions.Extensions; +using Xunit; + +namespace OpenRpg.UnitTests.Scaling; + +public class RandomizerExtensionTests +{ + [Fact] + public void should_correctly_plot_random_number_using_float_curve_extension() + { + var expectedResult = 1f; + + var mockRandomizer = new Mock(); + mockRandomizer.Setup(x => x.Random(0.0f, 1.0f)).Returns(0.5f); + var actualResult = mockRandomizer.Object.Random(PresetCurves.BellCurve); + + Assert.Equal(expectedResult, actualResult); + } + + [Fact] + public void should_correctly_plot_random_number_using_curve_extension_with_min_max_floats() + { + var expectedResult = 10.0f; + + var mockRandomizer = new Mock(); + mockRandomizer.Setup(x => x.Random(0.0f, 10.0f)).Returns(5.0f); + var actualResult = mockRandomizer.Object.Random(PresetCurves.BellCurve, 0.0f, 10.0f); + + Assert.Equal(expectedResult, actualResult); + } + + + [Fact] + public void should_correctly_plot_random_number_using_curve_extension_with_negative_min_max_floats() + { + var expectedResult = -10.0f; + + var mockRandomizer = new Mock(); + mockRandomizer.Setup(x => x.Random(-10.0f, 0.0f)).Returns(-5.0f); + var actualResult = mockRandomizer.Object.Random(PresetCurves.BellCurve, -10.0f, 0.0f); + + Assert.Equal(expectedResult, actualResult); + } +} \ No newline at end of file diff --git a/src/OpenRpg.sln b/src/OpenRpg.sln index f155a39..48e9709 100644 --- a/src/OpenRpg.sln +++ b/src/OpenRpg.sln @@ -34,6 +34,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenRpg.Data.InMemory", "Op EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenRpg.Data.Database", "OpenRpg.Data.Database\OpenRpg.Data.Database.csproj", "{BAB3772D-236C-4872-BA89-469866F56CBB}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{B374DC71-CEDE-42CC-A6E2-5D35577B08BA}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenRpg.UnitTests", "OpenRpg.UnitTests\OpenRpg.UnitTests.csproj", "{A3AACDFF-0D4B-4B4C-801E-6369BA9C8B6B}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Localization", "Localization", "{167FBCA2-476D-4BA4-818A-FA4ED80E6197}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -80,6 +86,10 @@ Global {BAB3772D-236C-4872-BA89-469866F56CBB}.Debug|Any CPU.Build.0 = Debug|Any CPU {BAB3772D-236C-4872-BA89-469866F56CBB}.Release|Any CPU.ActiveCfg = Release|Any CPU {BAB3772D-236C-4872-BA89-469866F56CBB}.Release|Any CPU.Build.0 = Release|Any CPU + {A3AACDFF-0D4B-4B4C-801E-6369BA9C8B6B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A3AACDFF-0D4B-4B4C-801E-6369BA9C8B6B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A3AACDFF-0D4B-4B4C-801E-6369BA9C8B6B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A3AACDFF-0D4B-4B4C-801E-6369BA9C8B6B}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution {86FD715B-0B33-40EB-B8AC-25EE62398A66} = {6BE3D2A4-F53A-4879-868E-A7522A445FE9} @@ -89,8 +99,9 @@ Global {2A8FA13E-2E89-457B-9457-46C345768495} = {C5E5EB5E-7F08-4CF4-B4DF-F20434DE2930} {91C35205-4EB6-4204-964E-D94427D362AA} = {1566BC2E-78DC-4998-BEC8-65CEC3EC9A88} {BB417DEC-B2C9-4F60-9E87-2E674ACAD06F} = {8468364A-996C-4E7C-AB45-FEE8AEA6ABDE} - {5C2FF42D-8E29-4EDE-84D0-47D24FFFFBB9} = {8468364A-996C-4E7C-AB45-FEE8AEA6ABDE} {ADD47427-9A25-46AB-9414-100D29A3C74E} = {8468364A-996C-4E7C-AB45-FEE8AEA6ABDE} {BAB3772D-236C-4872-BA89-469866F56CBB} = {8468364A-996C-4E7C-AB45-FEE8AEA6ABDE} + {A3AACDFF-0D4B-4B4C-801E-6369BA9C8B6B} = {B374DC71-CEDE-42CC-A6E2-5D35577B08BA} + {5C2FF42D-8E29-4EDE-84D0-47D24FFFFBB9} = {167FBCA2-476D-4BA4-818A-FA4ED80E6197} EndGlobalSection EndGlobal From 1f6c94a08faa2da23da301574e69127856124f7f Mon Sep 17 00:00:00 2001 From: LP Date: Fri, 25 Mar 2022 09:53:10 +0000 Subject: [PATCH 4/4] Bumped version as this will have breaking changes --- appveyor.yml | 2 +- src/OpenRpg.UnitTests/Scaling/RandomizerExtensionTests.cs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 5dc6c5a..1e21d8d 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: 0.18.{build} +version: 0.19.{build} branches: only: - master diff --git a/src/OpenRpg.UnitTests/Scaling/RandomizerExtensionTests.cs b/src/OpenRpg.UnitTests/Scaling/RandomizerExtensionTests.cs index f4a1063..98dc643 100644 --- a/src/OpenRpg.UnitTests/Scaling/RandomizerExtensionTests.cs +++ b/src/OpenRpg.UnitTests/Scaling/RandomizerExtensionTests.cs @@ -32,7 +32,6 @@ public void should_correctly_plot_random_number_using_curve_extension_with_min_m Assert.Equal(expectedResult, actualResult); } - [Fact] public void should_correctly_plot_random_number_using_curve_extension_with_negative_min_max_floats() {