Skip to content

Commit

Permalink
Merge a3abef8 into 403901b
Browse files Browse the repository at this point in the history
  • Loading branch information
mf0zz13 authored Oct 17, 2024
2 parents 403901b + a3abef8 commit 7d2bd13
Show file tree
Hide file tree
Showing 11 changed files with 440 additions and 315 deletions.
106 changes: 50 additions & 56 deletions Src/CrispyWaffle.CouchDB/Cache/CouchDBCacheRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,16 @@ public CouchDBCacheRepository(CouchDBConnector connector)
/// Finally, it converts the filtered results to a list and returns the count of those documents.
/// This is useful for determining how many valid instances of a specific document type exist in the database.
/// </remarks>
public int GetDocCount<T>()
public async Task<int> GetDocCountAsync<T>()
where T : CouchDBCacheDocument
{
return ResolveDatabase<T>().Where(x => x.Id != null).ToList().Count;
return (await ResolveDatabaseAsync<T>()).Where(x => x.Id != null).ToList().Count;
}

/// <inheritdoc />
public void Clear()
public async Task ClearAsync()
{
Clear<CouchDBCacheDocument>();
await Task.Run(() => ClearAsync<CouchDBCacheDocument>());
}

/// <summary>
Expand All @@ -62,12 +62,12 @@ public void Clear()
/// This method does not return any value and modifies the state of the database by removing documents.
/// </remarks>
/// <exception cref="Exception">Thrown when an error occurs during the deletion process, unless exceptions are suppressed.</exception>
public void Clear<T>()
public async Task ClearAsync<T>()
where T : CouchDBCacheDocument
{
try
{
var db = ResolveDatabase<T>();
var db = await ResolveDatabaseAsync<T>();
var docs = db.Where(x => x.Id != null).ToList();
var tasks = new List<Task>(docs.Count);

Expand All @@ -76,7 +76,7 @@ public void Clear<T>()
tasks.Add(db.DeleteAsync(doc));
}

Task.WaitAll(tasks.ToArray());
await Task.Run(() => tasks.ToArray());
}
catch (Exception e)
{
Expand All @@ -90,14 +90,14 @@ public void Clear<T>()
}

/// <inheritdoc />
public T Get<T>(string key)
public async Task<T> GetAsync<T>(string key)
{
if (!typeof(CouchDBCacheDocument).IsAssignableFrom(typeof(T)))
{
return default;
}

return (T)(object)GetSpecific<CouchDBCacheDocument>(key);
return (T)(object)await GetSpecificAsync<CouchDBCacheDocument>(key);
}

/// <summary>
Expand All @@ -111,37 +111,38 @@ public T Get<T>(string key)
/// </returns>
/// <remarks>
/// This method checks if the specified type <typeparamref name="T"/> is assignable from <see cref="CouchDBCacheDocument"/>.
/// If it is, it calls the method <see cref="GetSpecific{CouchDBCacheDocument}"/> to retrieve the cached document associated with the provided keys.
/// If it is, it calls the method <see cref="GetSpecificAsync{CouchDBCacheDocument}"/> to retrieve the cached document associated with the provided keys.
/// If the type is not assignable, it returns the default value for that type, which could be null for reference types or zero for numeric types.
/// This method is useful for retrieving cached data in a type-safe manner, ensuring that only compatible types are processed.
/// </remarks>
public T Get<T>(string key, string subKey)
public async Task<T> GetAsync<T>(string key, string subKey)
{
if (!typeof(CouchDBCacheDocument).IsAssignableFrom(typeof(T)))
{
return default;
}

return (T)(object)GetSpecific<CouchDBCacheDocument>(key, subKey);
return (T)(object)await Task.FromResult(GetSpecificAsync<CouchDBCacheDocument>(key, subKey));
}


/// <summary>
/// Gets from a class specified database instead of the general <see cref="CouchDBCacheDocument"/> database.
/// </summary>
/// <typeparam name="T">Type T with base type <see cref="CouchDBCacheDocument"/>.</typeparam>
/// <param name="key">A uniquely identifiable key to get document from the specified database.</param>
/// <returns>The document if found.</returns>
/// <exception cref="InvalidOperationException">Thrown in case the operation fails.</exception>
public T GetSpecific<T>(string key)
public async Task<T> GetSpecificAsync<T>(string key)
where T : CouchDBCacheDocument
{
try
{
var doc = ResolveDatabase<T>().Where(x => x.Key == key).FirstOrDefault();
var doc = (await ResolveDatabaseAsync<T>()).Where(x => x.Key == key).FirstOrDefault();

if (doc != default && doc.ExpiresAt != default && doc.ExpiresAt <= DateTime.UtcNow)
{
RemoveSpecific<T>(key);
await RemoveSpecificAsync<T>(key);
return default;
}

Expand Down Expand Up @@ -175,18 +176,16 @@ public T GetSpecific<T>(string key)
/// If no document is found and no exceptions are thrown, an <see cref="InvalidOperationException"/> is thrown indicating that the item could not be retrieved.
/// </remarks>
/// <exception cref="InvalidOperationException">Thrown when unable to retrieve the item with the specified key and sub key.</exception>
public T GetSpecific<T>(string key, string subKey)
public async Task<T> GetSpecificAsync<T>(string key, string subKey)
where T : CouchDBCacheDocument
{
try
{
var doc = ResolveDatabase<T>()
.Where(x => x.Key == key && x.SubKey == subKey)
.FirstOrDefault();
var doc = (await ResolveDatabaseAsync<T>()).Where(x => x.Key == key && x.SubKey == subKey).FirstOrDefault();

if (doc != default && doc.ExpiresAt != default && doc.ExpiresAt <= DateTime.UtcNow)
{
RemoveSpecific<T>(key, subKey);
await RemoveSpecificAsync<T>(key, subKey);
return default;
}

Expand All @@ -208,10 +207,7 @@ public T GetSpecific<T>(string key, string subKey)
}

/// <inheritdoc />
public void Remove(string key)
{
RemoveSpecific<CouchDBCacheDocument>(key);
}
public async Task RemoveAsync(string key) => await RemoveSpecificAsync<CouchDBCacheDocument>(key);

/// <summary>
/// Removes a specific entry from the cache based on the provided key and subKey.
Expand All @@ -224,17 +220,14 @@ public void Remove(string key)
/// It is important to ensure that both keys are correctly specified to successfully remove the intended entry from the cache.
/// If the specified entry does not exist, no action will be taken, and no exceptions will be thrown.
/// </remarks>
public void Remove(string key, string subKey)
{
RemoveSpecific<CouchDBCacheDocument>(key, subKey);
}
public async Task RemoveAsync(string key, string subKey) => await RemoveSpecificAsync<CouchDBCacheDocument>(key, subKey);

/// <summary>
/// Removes from a class specified database instead of the general <see cref="CouchDBCacheDocument"/> database.
/// </summary>
/// <typeparam name="T">Type T with base type <see cref="CouchDBCacheDocument"/>.</typeparam>
/// <param name="key">A uniquely identifiable key to remove document from the specified database.</param>
public void RemoveSpecific<T>(string key)
public async Task RemoveSpecificAsync<T>(string key)
where T : CouchDBCacheDocument
{
try
Expand All @@ -244,7 +237,7 @@ public void RemoveSpecific<T>(string key)

if (doc != default)
{
db.DeleteAsync(doc).Wait();
await db.DeleteAsync(doc);
}
}
catch (Exception e)
Expand All @@ -271,7 +264,7 @@ public void RemoveSpecific<T>(string key)
/// <see cref="ShouldPropagateExceptions"/>. If exceptions are not propagated, they are logged using the
/// <see cref="LogConsumer"/>. This method does not return any value.
/// </remarks>
public void RemoveSpecific<T>(string key, string subKey)
public async Task RemoveSpecificAsync<T>(string key, string subKey)
where T : CouchDBCacheDocument
{
try
Expand All @@ -281,7 +274,7 @@ public void RemoveSpecific<T>(string key, string subKey)

if (doc != default)
{
db.DeleteAsync(doc).Wait();
await db.DeleteAsync(doc);
}
}
catch (Exception e)
Expand All @@ -296,14 +289,14 @@ public void RemoveSpecific<T>(string key, string subKey)
}

/// <inheritdoc />
public void Set<T>(T value, string key, TimeSpan? ttl = null)
public async Task SetAsync<T>(T value, string key, TimeSpan? ttl = null)
{
if (!typeof(CouchDBCacheDocument).IsAssignableFrom(typeof(T)))
{
return;
}

SetSpecific((CouchDBCacheDocument)(object)value, key, ttl);
await SetSpecificAsync((CouchDBCacheDocument)(object)value, key, ttl);
}

/// <summary>
Expand All @@ -316,17 +309,17 @@ public void Set<T>(T value, string key, TimeSpan? ttl = null)
/// <remarks>
/// This method checks if the provided type <typeparamref name="T"/> is assignable from <see cref="CouchDBCacheDocument"/>.
/// If it is not, the method returns without performing any action.
/// If the type is valid, it calls the <see cref="SetSpecific"/> method to set the value in the cache.
/// If the type is valid, it calls the <see cref="SetSpecificAsync"/> method to set the value in the cache.
/// This allows for type-safe caching of documents that inherit from <see cref="CouchDBCacheDocument"/>.
/// </remarks>
public void Set<T>(T value, string key, string subKey)
public async Task SetAsync<T>(T value, string key, string subKey)
{
if (!typeof(CouchDBCacheDocument).IsAssignableFrom(typeof(T)))
{
return;
}

SetSpecific((CouchDBCacheDocument)(object)value, key, subKey);
await SetSpecificAsync((CouchDBCacheDocument)(object)value, key, subKey);
}

/// <summary>
Expand All @@ -336,7 +329,7 @@ public void Set<T>(T value, string key, string subKey)
/// <param name="value">The value of type T to be persisted.</param>
/// <param name="key">A uniquely identifiable key to remove document from the specified database.</param>
/// <param name="ttl">How long the value should be stored.</param>
public void SetSpecific<T>(T value, string key, TimeSpan? ttl = null)
public async Task SetSpecificAsync<T>(T value, string key, TimeSpan? ttl = null)
where T : CouchDBCacheDocument
{
try
Expand All @@ -349,7 +342,7 @@ public void SetSpecific<T>(T value, string key, TimeSpan? ttl = null)
value.ExpiresAt = DateTime.UtcNow.Add(ttl.Value);
}

ResolveDatabase<T>().CreateAsync(value).Wait();
await (await ResolveDatabaseAsync<T>()).CreateAsync(value);
}
catch (Exception e)
{
Expand Down Expand Up @@ -377,15 +370,15 @@ public void SetSpecific<T>(T value, string key, TimeSpan? ttl = null)
/// is rethrown; otherwise, it is logged using the LogConsumer.
/// </remarks>
/// <exception cref="Exception">Thrown when an error occurs during the database operation, unless exceptions are suppressed.</exception>
public void SetSpecific<T>(T value, string key, string subKey)
public async Task SetSpecificAsync<T>(T value, string key, string subKey)
where T : CouchDBCacheDocument
{
try
{
value.Key = key;
value.SubKey = subKey;

ResolveDatabase<T>().CreateOrUpdateAsync(value).Wait();
await (await ResolveDatabaseAsync<T>()).CreateOrUpdateAsync(value);
}
catch (Exception e)
{
Expand All @@ -399,18 +392,18 @@ public void SetSpecific<T>(T value, string key, string subKey)
}

/// <inheritdoc />
public bool TryGet<T>(string key, out T value)
public async Task<(bool Exists, T value)> TryGetAsync<T>(string key)
{
var get = Get<CouchDBCacheDocument>(key);

var get = await GetAsync<CouchDBCacheDocument>(key);
T value;
if (get != default)
{
value = (T)(object)get;
return true;
return (true, value);
}

value = default;
return false;
return (false, value);
}

/// <summary>
Expand All @@ -427,18 +420,18 @@ public bool TryGet<T>(string key, out T value)
/// If no document is found, <paramref name="value"/> is set to its default value, and the method returns false.
/// This is useful for safely attempting to retrieve values without throwing exceptions if the keys do not exist in the cache.
/// </remarks>
public bool TryGet<T>(string key, string subKey, out T value)
public async Task<(bool Exists, T value)> TryGetAsync<T>(string key, string subKey)
{
var get = Get<CouchDBCacheDocument>(key, subKey);

var get = await GetAsync<CouchDBCacheDocument>(key, subKey);
T value;
if (get != default)
{
value = (T)(object)get;
return true;
return (true, value);
}

value = default;
return false;
return (false, value);
}

/// <summary>
Expand All @@ -454,9 +447,10 @@ public bool TryGet<T>(string key, string subKey, out T value)
/// This method assumes that the key exists in the cache; if it does not, the behavior will depend
/// on the implementation of the Get method.
/// </remarks>
public TimeSpan TTL(string key)
public async Task<TimeSpan> TTLAsync(string key)
{
return Get<CouchDBCacheDocument>(key).TTL;
var result = await GetAsync<CouchDBCacheDocument>(key);
return result.TTL;
}

/// <summary>
Expand All @@ -471,16 +465,16 @@ public TimeSpan TTL(string key)
/// ensuring that it handles database creation and retrieval efficiently. The use of generics allows for flexibility in specifying the type of documents
/// that will be stored in the database, making this method suitable for various CouchDBCacheDocument types.
/// </remarks>
private CouchDatabase<T> ResolveDatabase<T>(string dbName = default)
private async Task<CouchDatabase<T>> ResolveDatabaseAsync<T>(string dbName = default)
where T : CouchDBCacheDocument
{
if (string.IsNullOrEmpty(dbName))
{
dbName = $"{typeof(T).Name.ToLowerInvariant()}s";
}

return !_connector.CouchDBClient.GetDatabasesNamesAsync().Result.Contains(dbName)
? _connector.CouchDBClient.CreateDatabaseAsync<T>().Result
return !(await _connector.CouchDBClient.GetDatabasesNamesAsync()).Contains(dbName)
? (await _connector.CouchDBClient.CreateDatabaseAsync<T>())
: _connector.CouchDBClient.GetDatabase<T>();
}

Expand Down
Loading

0 comments on commit 7d2bd13

Please sign in to comment.