Skip to content

Commit

Permalink
Merge pull request #9 from calebjenkins/dev/feature-08-Remove-RemoveAll
Browse files Browse the repository at this point in the history
Version Bumb 0.5.0 - New Feature: Remove / Remove All
  • Loading branch information
calebjenkins committed Jan 8, 2024
2 parents 5cb08b8 + a150f4b commit a493878
Show file tree
Hide file tree
Showing 6 changed files with 153 additions and 14 deletions.
22 changes: 14 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,23 +35,29 @@ The package `version` is defined in the `KeyValueRepo.csproj` file, using .NET S
## Methods in IKeyValueRepo

- Get<T>(string Id)
- Get<T>(int Id) => Get<T>(string Id)
- Note: This method has a _default implementation_ that performs a `ToString()` on the Id and calls the `Get<T>(string Id)` method.
- GetAll<T>()
- Update<T>(string Id, T object)
- Update<T>(int Id, T object) => Update(string Id, T object)
- Note This method has a _default implementation_ that performs a `ToSTring()` on the int Id and calls the `Update<T>(string Id, T object)` method.
- GetMeta<T>(string Id)
- GetMetaAll<T>()
- GetHistory<T>(string Id)
- Remove<T>(string Id)
- RemoveAll<T>()

## Methods in included extension methods
- Get<T>(int Id) => Get<T>(string Id)
- Update<T>(int Id, T object) => Update(string Id, T object)
- Remove<T>(int Id) => Remove<T>(string Id)

## Release History & Development Goals
- 0.1.0 - initial release (in Memory)
- 0.2.0 - added SqlLite Implementation
- ✔ SQLite [Nuget Package](https://www.nuget.org/packages/Calebs.KeyValueRepo.SQLite/)
- ✔ SQLite [Nuget Package](https://www.nuget.org/packages/Calebs.KeyValueRepo.SQLite/)
- ✔ Base (InMemory) Unit Test [Nuget Package](https://www.nuget.org/packages/Calebs.KeyValueRepoTests/)
- 0.3.0 - Added Meta Objects
- 0.4.0 - Completed SQLite Package with Meta Objects
- 0.5.0 - Added: Remove<T>(id) and RemoveAll<T> to IKeyValueRepo
### Future Goals
---
- In Progress: 0.3.0 - New Feature: KV Meta Objects
- In Progress: Seperate and publish base unit tests
- Considering: 0.4.0 - New Feature: Remove / RemoveAll methods
- New Repo: Azure Tables Implementation
- New Repo: Sql Server Implementation
- New Repo: Azure CosmoDB Implementation
2 changes: 2 additions & 0 deletions src/KeyValueRepo/IKeyValueRepo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,6 @@ public interface IKeyValueRepo
Task<MetaObject<T>?> GetMeta<T>(string key) where T : class;
Task<IList<MetaObject<T>>> GetHistory<T>(string key) where T : class;
Task<IList<MetaObject<T>>> GetMetaAll<T>() where T : class;
Task Remove<T>(string key) where T : class;
Task RemoveAll<T>() where T : class;
}
24 changes: 23 additions & 1 deletion src/KeyValueRepo/KeyValueInMemory.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@

/// <summary>
/// Recomend Running IKeyValueRepo as Singleton
/// </summary>
public class KeyValueInMemory : IKeyValueRepo
{
// Note a lot of "await Task.Run(".. etc in here, since this is InMemory, Tasks/Await not really needed, but the interface is designed for networked databases where that is generally preffered.
// Using in Memeory JSON formating (string)
// Recomend Running IKeyValueRepo as Singleton
Dictionary<string, Dictionary<string, string>> _data = new Dictionary<string, Dictionary<string, string>>();

public async Task<T?> Get<T>(string key) where T : class
Expand Down Expand Up @@ -105,6 +109,24 @@ public class KeyValueInMemory : IKeyValueRepo
return null;
}

public async Task Remove<T>(string key) where T : class
{
string typeKey = typeof(T).ToString();
if (_data.ContainsKey(typeKey) && _data[typeKey].ContainsKey(key))
{
await Task.Run(()=> _data[typeKey].Remove(key));
}
}

public async Task RemoveAll<T>() where T : class
{
string typeKey = typeof(T).ToString();
if (_data.ContainsKey(typeKey))
{
await Task.Run(() => _data.Remove(typeKey));
}
}

public async Task Update<T>(string key, T value) where T : class
{
var ident = Thread.CurrentPrincipal?.Identity?.Name ?? "";
Expand All @@ -120,7 +142,7 @@ public class KeyValueInMemory : IKeyValueRepo
UpdatedOn = now
};

// Create type dictionary if does now exist
// Create type dictionary if does not exist
if (!_data.ContainsKey(typeKey))
{
var newDict = new Dictionary<string, string>();
Expand Down
3 changes: 1 addition & 2 deletions src/KeyValueRepo/KeyValueRepo.csproj
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net6.0;</TargetFrameworks>
<Configurations>Debug;Release;</Configurations>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<RootNamespace>Calebs.Data.KeyValueRepo</RootNamespace>
<AssemblyName>Calebs.KeyValueRepo</AssemblyName>
<Version>0.4.0</Version>
<Version>0.5.0</Version>
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
<IsPackable>true</IsPackable>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
Expand Down
1 change: 1 addition & 0 deletions src/KeyValueRepo/KeyValueRepoExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ public static class KeyValueRepoExtensions
public static Task<T?> Get<T>(this IKeyValueRepo repo, int key) where T : class => repo.Get<T>(key.ToString());
public static Task<IList<MetaObject<T>>?> GetHistory<T>(this IKeyValueRepo repo, int key) where T : class => repo.GetHistory<T>(key.ToString());

Check warning on line 7 in src/KeyValueRepo/KeyValueRepoExtensions.cs

View workflow job for this annotation

GitHub Actions / build

Nullability of reference types in value of type 'Task<IList<MetaObject<T>>>' doesn't match target type 'Task<IList<MetaObject<T>>?>'.

Check warning on line 7 in src/KeyValueRepo/KeyValueRepoExtensions.cs

View workflow job for this annotation

GitHub Actions / build

Nullability of reference types in value of type 'Task<IList<MetaObject<T>>>' doesn't match target type 'Task<IList<MetaObject<T>>?>'.

Check warning on line 7 in src/KeyValueRepo/KeyValueRepoExtensions.cs

View workflow job for this annotation

GitHub Actions / build

Nullability of reference types in value of type 'Task<IList<MetaObject<T>>>' doesn't match target type 'Task<IList<MetaObject<T>>?>'.
public static Task Update<T>(this IKeyValueRepo repo, int key, T value) where T : class => repo.Update<T>(key.ToString(), value);
public static Task Remove<T>(this IKeyValueRepo repo, int key) where T : class => repo.Remove<T>(key.ToString());
}
115 changes: 112 additions & 3 deletions src/KeyValueRepoTests/InMemoryTests.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@


using System.Security.Principal;

namespace Calebs.Data.KeyValueRepoTests;
Expand All @@ -12,13 +11,18 @@ public virtual IKeyValueRepo GetNewRepo()
return new KeyValueInMemory();
}

private async Task<IKeyValueRepo> getRepoWithRecords(Person p, string TestName)
internal string getRandomId()
{
return Guid.NewGuid().ToString().Substring(0, 8);
}

private async Task<IKeyValueRepo> getRepoWithRecords(Person p, string TestName = "TestName")
{
var people = new List<Person>() { p };
return await getRepoWithRecords(people, TestName);
}

private async Task<IKeyValueRepo> getRepoWithRecords(IList<Person> People, string TestName)
private async Task<IKeyValueRepo> getRepoWithRecords(IList<Person> People, string TestName = "TestName")
{
IKeyValueRepo repo = GetNewRepo();

Expand Down Expand Up @@ -46,6 +50,8 @@ public async Task Update_PopulatesMetaInfo()
var result = await repo.GetMeta<Person>(p.Id);
result?.CreatedBy.Should().Be(TEST_Name);
result?.UpdatedBy.Should().Be(TEST_Name);
result?.CreatedOn.Should<DateTime>().NotBeNull();
result?.UpdatedOn.Should<DateTime>().NotBeNull();

result?.Value?.Last.Should().Be(p.Last);
result?.Value?.First.Should().Be(p.First);
Expand Down Expand Up @@ -79,11 +85,14 @@ public async Task GetHistory_ShouldReturnMetaList()
IKeyValueRepo repo = await getRepoWithRecords(p, TEST_Name);

var results = await repo.GetHistory<Person>(p.Id);

results?.Count.Should().BeGreaterThan(0);
results?.First()?.Value?.First.Should().Be(p.First);
results?.First()?.Value?.Last.Should().Be(p.Last);
results?.First()?.CreatedBy.Should().Be(TEST_Name);
results?.First()?.CreatedOn.Should<DateTime>().NotBeNull();
results?.First()?.UpdatedBy.Should().Be(TEST_Name);
results?.First()?.UpdatedOn.Should<DateTime>().NotBeNull();
}

[Fact]
Expand Down Expand Up @@ -224,6 +233,106 @@ public async Task GetMetaAll_ShouldReturnAllInstances()
people.Count().Should().BeGreaterThanOrEqualTo(4);
locals.Count().Should().BeGreaterThanOrEqualTo(2);
}

[Fact]
public async Task Remove_ShouldRemoveOnlySpecifiedRecord()
{
var p1 = new Person("Kelly", "Burkhardt", 1);
var p2 = new Person("Drew", "Wu", 2);
var p3 = new Person("Monroe", "", 3);
var people = new List<Person>() { p1, p2, p3 };
var TEST_USER = "test name";
var repo = await getRepoWithRecords(people, TEST_USER);

var allPeople = await repo.GetAll<Person>();

var peopleCount = allPeople.Count();
peopleCount.Should().BeGreaterThan(2);
var drew = await repo.Get<Person>(p2.Id);
drew.Should().NotBeNull();

await repo.Remove<Person>(p2.Id);
var nullDrew = await repo.Get<Person>(p2.Id);
nullDrew.Should().BeNull();

allPeople = await repo.GetAll<Person>();
allPeople.Count.Should().Be(peopleCount - 1);
}

[Fact]
public async Task Remove_MissingIdShouldNotThrowAnError()
{
var p1 = new Person("Kelly", "Burkhardt", 1);
var p2 = new Person("Drew", "Wu", 2);
var p3 = new Person("Monroe", "", 3);
var people = new List<Person>() { p1, p2, p3 };
var repo = await getRepoWithRecords(people);

try {
await repo.Remove<Person>(4);
true.Should().BeTrue();
}
catch (Exception ex) {
ex.Should().BeNull();
}
}

[Fact]
public async Task RemoveAll_ShouldRemoveAllSpecifiedTypes()
{
var repo = GetNewRepo();

await repo.Update(1, new Person("Kelly", "Burkhardt", 1));
await repo.Update("1", new Location("1", "123 Main", "Portland"));
await repo.Update("2", new Location("2", "123 Main", "Fort Worth"));
await repo.Update(2, new Person("Drew", "Wu", 2));
await repo.Update(3, new Person("Monroe", "", 3));
await repo.Update("3", new Location("3", "123 Main", "Dallas"));
await repo.Update("4", new Location("4", "123 Main Street", "Salem"));

var people = await repo.GetAll<Person>();
people.Count.Should().BeGreaterThan(2);

var places = await repo.GetAll<Location>();
places.Count.Should().BeGreaterThan(3);

await repo.RemoveAll<Person>();

people = await repo.GetAll<Person>();
people.Count.Should().Be(0);

places = await repo.GetAll<Location>();
places.Count.Should().BeGreaterThan(3);
}

[Fact]
public async Task RemoveAll_MissingTypeShouldNotThrowAnError()
{
var repo = GetNewRepo();

await repo.Update(1, new Person("Kelly", "Burkhardt", 1));
await repo.Update("1", new Location("1", "123 Main", "Portland"));
await repo.Update("2", new Location("2", "123 Main", "Fort Worth"));
await repo.Update(2, new Person("Drew", "Wu", 2));
await repo.Update(3, new Person("Monroe", "", 3));
await repo.Update("3", new Location("3", "123 Main", "Dallas"));
await repo.Update("4", new Location("4", "123 Main Street", "Salem"));

var people = await repo.GetAll<Person>();
people.Count.Should().BeGreaterThan(2);

var places = await repo.GetAll<Location>();
places.Count.Should().BeGreaterThan(3);

try
{
await repo.RemoveAll<UnusedType>();
true.Should().BeTrue();
} catch (Exception ex)
{
ex.Should().BeNull();
}
}
}

public record Person(string First, string Last, int Id);
Expand Down

0 comments on commit a493878

Please sign in to comment.