Files
hermes-server/Store/Internal/AutoSavedStore.cs

85 lines
3.3 KiB
C#

using System.Collections.Immutable;
using HermesSocketLibrary.db;
namespace HermesSocketServer.Store.Internal
{
public abstract class AutoSavedStore<K, V> : GroupSaveStore<K, V> where K : class where V : class
{
private readonly GroupSaveSqlGenerator<V> _generator;
private readonly DatabaseTable _table;
private readonly Database _database;
private readonly Serilog.ILogger _logger;
public AutoSavedStore(DatabaseTable table, Database database, Serilog.ILogger logger)
: base()
{
if (table.TypeMapping == null)
_generator = new GroupSaveSqlGenerator<V>(table.PropertyMapping, logger);
else
_generator = new GroupSaveSqlGenerator<V>(table.PropertyMapping, table.TypeMapping, logger);
_table = table;
_database = database;
_logger = logger;
}
public override async Task Save()
{
var allColumns = _table.KeyColumns.Union(_table.DataColumns).ToArray();
var typeMapping = _table.TypeMapping ?? new Dictionary<string, string>();
await GenerateQuery(_added,
(size) => _generator.GeneratePreparedInsertSql(_table.TableName, size, allColumns, typeMapping),
async (query, _, values) => await _generator.DoPreparedStatement(_database, query, values, allColumns));
await GenerateQuery(_modified,
(size) => _generator.GeneratePreparedUpdateSql(_table.TableName, size, _table.KeyColumns, _table.DataColumns, typeMapping),
async (query, _, values) => await _generator.DoPreparedStatement(_database, query, values, allColumns));
await GenerateQuery(_deleted,
(size) => _generator.GeneratePreparedDeleteSql(_table.TableName, size, _table.KeyColumns, typeMapping),
async (query, keys, _) => await _generator.DoPreparedStatementRaw(_database, query, keys, _table.KeyColumns));
}
private async Task GenerateQuery(IList<K> keys, Func<int, string> generate, Func<string, IEnumerable<K>, IEnumerable<V>, Task<int>> execute)
{
ImmutableList<K>? list = null;
_rwls.EnterUpgradeableReadLock();
try
{
if (!keys.Any())
return;
_rwls.EnterWriteLock();
try
{
list = keys.ToImmutableList();
keys.Clear();
}
finally
{
_rwls.ExitWriteLock();
}
}
finally
{
_rwls.ExitUpgradeableReadLock();
}
var query = generate(list.Count);
var values = list.Select(id => _store[id]).Where(v => v != null);
int rowsAffected = await execute(query, list, values);
if (rowsAffected != list.Count)
{
_logger.Error($"Rows affected in database ({rowsAffected}) and the number of items that should be modified ({list.Count}) do not match: {query}");
}
else
{
_logger.Information($"{rowsAffected} rows were affected by this query: {query}");
}
}
}
}