-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #56 from rengenesio/hotfix/table-cache
Change cache to be indexed by connection string and table name
- Loading branch information
Showing
6 changed files
with
151 additions
and
25 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,34 +1,34 @@ | ||
using System; | ||
using System.Collections.Concurrent; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
|
||
namespace StrangerData.Utils | ||
{ | ||
public static class MemoryCache | ||
{ | ||
private static IDictionary<string, object> _cache; | ||
private static IDictionary<Tuple<string, string>, object> _cache; | ||
|
||
private static IDictionary<string, object> Cache | ||
private static IDictionary<Tuple<string, string>, object> Cache | ||
{ | ||
get | ||
{ | ||
if (_cache == null) | ||
_cache = new Dictionary<string, object>(); | ||
_cache = new ConcurrentDictionary<Tuple<string, string>, object>(); | ||
return _cache; | ||
} | ||
} | ||
|
||
public static T TryGetFromCache<T>(string key, Func<object> getValue) | ||
public static T TryGetFromCache<T>(string primaryKey, string secondaryKey, Func<object> getValue) | ||
where T : class | ||
{ | ||
if (!Cache.ContainsKey(key)) | ||
Tuple<string, string> compositeKey = new Tuple<string, string>(primaryKey, secondaryKey); | ||
|
||
if (!Cache.ContainsKey(compositeKey)) | ||
{ | ||
Cache[key] = getValue(); | ||
Cache[compositeKey] = getValue(); | ||
} | ||
|
||
return Cache[key] as T; | ||
return Cache[compositeKey] as T; | ||
} | ||
} | ||
} |
58 changes: 58 additions & 0 deletions
58
test/StrangerData.UnitTests/Generator/TableGeneratorTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
using Moq; | ||
using StrangerData.Generator; | ||
using Xunit; | ||
|
||
namespace StrangerData.UnitTests.Generator | ||
{ | ||
public class TableGeneratorTests | ||
{ | ||
[Fact] | ||
public void Constructor_TablesFromDatabasesWithDifferentConnectionString_GetTableSchemaInfoFromBothDatabases() | ||
{ | ||
// Arrange | ||
Mock<IDbDialect> databaseOneDialectMock = new Mock<IDbDialect>(); | ||
databaseOneDialectMock.Setup(d => d.ConnectionString) | ||
.Returns(Any.String()); | ||
|
||
Mock<IDbDialect> databaseTwoDialectMock = new Mock<IDbDialect>(); | ||
databaseTwoDialectMock.Setup(d => d.ConnectionString) | ||
.Returns(Any.String()); | ||
|
||
string tableName = Any.String(); | ||
|
||
TableGenerator databaseOneTableGenerator = new TableGenerator(databaseOneDialectMock.Object, tableName); | ||
|
||
// Act | ||
TableGenerator databaseTwoTableGenerator = new TableGenerator(databaseTwoDialectMock.Object, tableName); | ||
|
||
// Assert | ||
databaseOneDialectMock.Verify(d => d.GetTableSchemaInfo(tableName), Times.Once); | ||
databaseTwoDialectMock.Verify(d => d.GetTableSchemaInfo(tableName), Times.Once); | ||
} | ||
|
||
[Fact] | ||
public void Constructor_TablesFromDifferentDialectsWithSameConnectionString_GetTableSchemaInfoFromCache() | ||
{ | ||
// Arrange | ||
string connectionString = Any.String(); | ||
string tableName = Any.String(); | ||
|
||
Mock<IDbDialect> databaseOneDialectMock = new Mock<IDbDialect>(); | ||
databaseOneDialectMock.Setup(d => d.ConnectionString) | ||
.Returns(connectionString); | ||
|
||
Mock<IDbDialect> databaseTwoDialectMock = new Mock<IDbDialect>(); | ||
databaseTwoDialectMock.Setup(d => d.ConnectionString) | ||
.Returns(connectionString); | ||
|
||
TableGenerator databaseOneTableGenerator = new TableGenerator(databaseOneDialectMock.Object, tableName); | ||
|
||
// Act | ||
TableGenerator databaseTwoTableGenerator = new TableGenerator(databaseTwoDialectMock.Object, tableName); | ||
|
||
// Assert | ||
databaseOneDialectMock.Verify(d => d.GetTableSchemaInfo(tableName), Times.Once); | ||
databaseTwoDialectMock.Verify(d => d.GetTableSchemaInfo(tableName), Times.Never); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
using FluentAssertions; | ||
using Moq; | ||
using StrangerData.Utils; | ||
using System; | ||
using Xunit; | ||
|
||
namespace StrangerData.UnitTests.Utils | ||
{ | ||
public class MemoryCacheTests | ||
{ | ||
[Fact] | ||
public void TryGetFromCache_BothKeysNotExists_InvokeFuncAndReturnFuncValue() | ||
{ | ||
// Arrange | ||
string expected = Any.String(); | ||
|
||
Mock<Func<object>> funcMock = new Mock<Func<object>>(); | ||
funcMock.Setup(f => f()).Returns(expected); | ||
|
||
string nonExistentPrimaryKey = Any.String(); | ||
string nonExistentSecondaryKey = Any.String(); | ||
|
||
// Act | ||
string actual = MemoryCache.TryGetFromCache<string>(nonExistentPrimaryKey, nonExistentSecondaryKey, funcMock.Object); | ||
|
||
// Assert | ||
actual.Should().Be(expected); | ||
funcMock.Verify(f => f(), Times.Once); | ||
} | ||
|
||
[Fact] | ||
public void TryGetFromCache_SecondaryKeyNotExists_InvokeFuncAndReturnFuncValue() | ||
{ | ||
// Arrange | ||
string expected = Any.String(); | ||
|
||
Mock<Func<object>> funcMock = new Mock<Func<object>>(); | ||
funcMock.Setup(f => f()).Returns(expected); | ||
|
||
string primaryKey = Any.String(); | ||
MemoryCache.TryGetFromCache<string>(primaryKey, Any.String(), () => Any.String()); | ||
|
||
string nonExistentSecondaryKey = Any.String(); | ||
|
||
// Act | ||
string actual = MemoryCache.TryGetFromCache<string>(primaryKey, nonExistentSecondaryKey, funcMock.Object); | ||
|
||
// Assert | ||
actual.Should().Be(expected); | ||
funcMock.Verify(f => f(), Times.Once); | ||
} | ||
|
||
[Fact] | ||
public void TryGetFromCache_BothKeysExists_NotInvokeFuncAndReturnExistentValue() | ||
{ | ||
// Arrange | ||
Mock<Func<object>> funcMock = new Mock<Func<object>>(); | ||
funcMock.Setup(f => f()).Returns(Any.String()); | ||
|
||
string primaryKey = Any.String(); | ||
string secondaryKey = Any.String(); | ||
string expected = Any.String(); | ||
MemoryCache.TryGetFromCache<string>(primaryKey, secondaryKey, () => expected); | ||
|
||
// Act | ||
string actual = MemoryCache.TryGetFromCache<string>(primaryKey, secondaryKey, funcMock.Object); | ||
|
||
// Assert | ||
actual.Should().Be(expected); | ||
funcMock.Verify(f => f(), Times.Never); | ||
} | ||
} | ||
} |