Skip to content

Commit

Permalink
#1044 Support of the cache to the ExecuteQueryMultiple operation.
Browse files Browse the repository at this point in the history
  • Loading branch information
mikependon committed Sep 6, 2022
1 parent 0b1b147 commit a9c6073
Show file tree
Hide file tree
Showing 4 changed files with 243 additions and 63 deletions.
24 changes: 22 additions & 2 deletions RepoDb.Core/RepoDb/CacheItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,11 @@ public CacheItem(string key,
#region Methods

/// <summary>
/// Updates the value of the current item based from the source item.
/// Updates the properties of the current item based from the passed item.
/// </summary>
/// <param name="item">The source item.</param>
/// <param name="throwException">Throws an exception if the operation has failed to update an item.</param>
internal void UpdateFrom(CacheItem<T> item,
internal void Update(CacheItem<T> item,
bool throwException = true)
{
if (!IsExpired() && throwException)
Expand All @@ -62,6 +62,26 @@ internal void UpdateFrom(CacheItem<T> item,
Expiration = CreatedDate.AddMinutes(item.CacheItemExpiration ?? Constant.DefaultCacheItemExpirationInMinutes);
}

/// <summary>
/// Updates the value of the current item.
/// </summary>
/// <param name="value">The actual value.</param>
/// <param name="cacheItemExpiration">The expiration in minutes of the cache item.</param>
/// <param name="throwException">Throws an exception if the operation has failed to update an item.</param>
internal void Update(T value,
int? cacheItemExpiration = Constant.DefaultCacheItemExpirationInMinutes,
bool throwException = true)
{
if (!IsExpired() && throwException)
{
throw new InvalidOperationException($"Cannot update the item that is not yet expired.");
}

Value = value;
CreatedDate = DateTime.UtcNow;
Expiration = CreatedDate.AddMinutes(cacheItemExpiration.Value);
}

#endregion

#region Properties
Expand Down
114 changes: 87 additions & 27 deletions RepoDb.Core/RepoDb/Extensions/DbConnectionExtension.cs
Original file line number Diff line number Diff line change
Expand Up @@ -885,55 +885,85 @@ private static async Task<IEnumerable<TResult>> ExecuteQueryAsyncInternalForType
/// <see cref="ExpandoObject"/>, <see cref="QueryField"/>, <see cref="QueryGroup"/> and an enumerable of <see cref="QueryField"/> objects.
/// </param>
/// <param name="commandType">The command type to be used.</param>
/// <param name="cacheKey">
/// The key to the cache item. By setting this argument, it will return the item from the cache if present, otherwise it will query the database.
/// This will only work if the 'cache' argument is set.
/// </param>
/// <param name="cacheItemExpiration">The expiration in minutes of the cache item.</param>
/// <param name="commandTimeout">The command timeout in seconds to be used.</param>
/// <param name="transaction">The transaction to be used.</param>
/// <param name="cache">The cache object to be used.</param>
/// <returns>An instance of <see cref="QueryMultipleExtractor"/> used to extract the results.</returns>
public static QueryMultipleExtractor ExecuteQueryMultiple(this IDbConnection connection,
string commandText,
object param = null,
CommandType? commandType = null,
string cacheKey = null,
int? cacheItemExpiration = Constant.DefaultCacheItemExpirationInMinutes,
int? commandTimeout = null,
IDbTransaction transaction = null) =>
IDbTransaction transaction = null,
ICache cache = null) =>
ExecuteQueryMultipleInternal(connection,
commandText,
param,
commandType,
cacheKey,
cacheItemExpiration,
commandTimeout,
transaction,
cache,
false);

/// <summary>
///
///
/// </summary>
/// <param name="connection"></param>
/// <param name="commandText"></param>
/// <param name="param"></param>
/// <param name="commandType"></param>
/// <param name="cacheKey"></param>
/// <param name="cacheItemExpiration"></param>
/// <param name="commandTimeout"></param>
/// <param name="transaction"></param>
/// <param name="cache"></param>
/// <param name="isDisposeConnection"></param>
/// <returns></returns>
internal static QueryMultipleExtractor ExecuteQueryMultipleInternal(this IDbConnection connection,
string commandText,
object param = null,
CommandType? commandType = null,
string cacheKey = null,
int? cacheItemExpiration = Constant.DefaultCacheItemExpirationInMinutes,
int? commandTimeout = null,
IDbTransaction transaction = null,
ICache cache = null,
bool isDisposeConnection = false)
{
// Call
var reader = ExecuteReaderInternal(connection: connection,
commandText: commandText,
param: param,
commandType: commandType,
commandTimeout: commandTimeout,
transaction: transaction,
entityType: null,
dbFields: null,
skipCommandArrayParametersCheck: false);
IDataReader reader = null;

// Get Cache
if (cacheKey == null || cache?.Contains(cacheKey) != true)
{
// Call
reader = ExecuteReaderInternal(connection: connection,
commandText: commandText,
param: param,
commandType: commandType,
commandTimeout: commandTimeout,
transaction: transaction,
entityType: null,
dbFields: null,
skipCommandArrayParametersCheck: false);
}

// Return
return new QueryMultipleExtractor((DbConnection)connection, (DbDataReader)reader, isDisposeConnection, param);
return new QueryMultipleExtractor((DbConnection)connection,
(DbDataReader)reader,
param,
cacheKey,
cacheItemExpiration,
cache,
isDisposeConnection);
}

#endregion
Expand All @@ -950,62 +980,92 @@ internal static QueryMultipleExtractor ExecuteQueryMultipleInternal(this IDbConn
/// <see cref="ExpandoObject"/>, <see cref="QueryField"/>, <see cref="QueryGroup"/> and an enumerable of <see cref="QueryField"/> objects.
/// </param>
/// <param name="commandType">The command type to be used.</param>
/// <param name="cacheKey">
/// The key to the cache item. By setting this argument, it will return the item from the cache if present, otherwise it will query the database.
/// This will only work if the 'cache' argument is set.
/// </param>
/// <param name="cacheItemExpiration">The expiration in minutes of the cache item.</param>
/// <param name="commandTimeout">The command timeout in seconds to be used.</param>
/// <param name="transaction">The transaction to be used.</param>
/// <param name="cache">The cache object to be used.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> object to be used during the asynchronous operation.</param>
/// <returns>An instance of <see cref="QueryMultipleExtractor"/> used to extract the results.</returns>
public static Task<QueryMultipleExtractor> ExecuteQueryMultipleAsync(this IDbConnection connection,
string commandText,
object param = null,
CommandType? commandType = null,
string cacheKey = null,
int? cacheItemExpiration = Constant.DefaultCacheItemExpirationInMinutes,
int? commandTimeout = null,
IDbTransaction transaction = null,
ICache cache = null,
CancellationToken cancellationToken = default) =>
ExecuteQueryMultipleAsyncInternal(connection,
commandText,
param,
commandType,
cacheKey,
cacheItemExpiration,
commandTimeout,
transaction,
cache,
false,
cancellationToken);

/// <summary>
///
///
/// </summary>
/// <param name="connection"></param>
/// <param name="commandText"></param>
/// <param name="param"></param>
/// <param name="commandType"></param>
/// <param name="cacheKey"></param>
/// <param name="cacheItemExpiration"></param>
/// <param name="commandTimeout"></param>
/// <param name="transaction"></param>
/// <param name="cache"></param>
/// <param name="isDisposeConnection"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
internal static async Task<QueryMultipleExtractor> ExecuteQueryMultipleAsyncInternal(this IDbConnection connection,
string commandText,
object param = null,
CommandType? commandType = null,
string cacheKey = null,
int? cacheItemExpiration = Constant.DefaultCacheItemExpirationInMinutes,
int? commandTimeout = null,
IDbTransaction transaction = null,
ICache cache = null,
bool isDisposeConnection = false,
CancellationToken cancellationToken = default)
{
// Call
var reader = await ExecuteReaderAsyncInternal(connection: connection,
commandText: commandText,
param: param,
commandType: commandType,
commandTimeout: commandTimeout,
transaction: transaction,
cancellationToken: cancellationToken,
entityType: null,
dbFields: null,
skipCommandArrayParametersCheck: false);
IDataReader reader = null;

// Get Cache
if (cacheKey == null || cache?.Contains(cacheKey) != true)
{
// Call
reader = await ExecuteReaderAsyncInternal(connection: connection,
commandText: commandText,
param: param,
commandType: commandType,
commandTimeout: commandTimeout,
transaction: transaction,
cancellationToken: cancellationToken,
entityType: null,
dbFields: null,
skipCommandArrayParametersCheck: false);
}

// Return
return new QueryMultipleExtractor((DbConnection)connection, (DbDataReader)reader,
isDisposeConnection, param, cancellationToken);
return new QueryMultipleExtractor((DbConnection)connection,
(DbDataReader)reader,
param,
cacheKey,
cacheItemExpiration,
cache,
isDisposeConnection,
cancellationToken);
}

#endregion
Expand Down
2 changes: 1 addition & 1 deletion RepoDb.Core/RepoDb/MemoryCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public void Add<T>(CacheItem<T> item,
{
throw new MappingExistsException($"An existing cache for key '{item.Key}' already exists.");
}
cacheItem.UpdateFrom(item, throwException);
cacheItem.Update(item, throwException);
}
}

Expand Down
Loading

0 comments on commit a9c6073

Please sign in to comment.