1using System.Collections.Concurrent;
4using Dreamine.Database.Abstractions;
67 private static readonly ConcurrentDictionary<(Type, DatabaseProviderKind,
SqlKind),
string>
SqlCache =
new();
103 ArgumentException.ThrowIfNullOrWhiteSpace(connectionString);
115 public abstract DatabaseProviderKind
Kind {
get; }
178 await
OpenAsync(connection, cancellationToken).ConfigureAwait(
false);
307 CancellationToken cancellationToken =
default);
431 ArgumentException.ThrowIfNullOrWhiteSpace(sql);
434 return connection.Execute(sql, parameters);
495 object? parameters =
null,
496 CancellationToken cancellationToken =
default)
498 ArgumentException.ThrowIfNullOrWhiteSpace(sql);
501 await
OpenAsync(connection, cancellationToken).ConfigureAwait(
false);
502 return await connection.ExecuteAsync(
new CommandDefinition(sql, parameters, cancellationToken: cancellationToken))
503 .ConfigureAwait(
false);
564 ArgumentException.ThrowIfNullOrWhiteSpace(sql);
567 return connection.ExecuteScalar<T>(sql, parameters);
636 object? parameters =
null,
637 CancellationToken cancellationToken =
default)
639 ArgumentException.ThrowIfNullOrWhiteSpace(sql);
642 await
OpenAsync(connection, cancellationToken).ConfigureAwait(
false);
643 return await connection.ExecuteScalarAsync<T>(
644 new CommandDefinition(sql, parameters, cancellationToken: cancellationToken))
645 .ConfigureAwait(
false);
704 public IEnumerable<T>
Query<T>(
string sql,
object? parameters =
null)
706 ArgumentException.ThrowIfNullOrWhiteSpace(sql);
709 return connection.Query<T>(sql, parameters).ToArray();
778 object? parameters =
null,
779 CancellationToken cancellationToken =
default)
781 ArgumentException.ThrowIfNullOrWhiteSpace(sql);
784 await
OpenAsync(connection, cancellationToken).ConfigureAwait(
false);
785 var rows = await connection.QueryAsync<T>(
786 new CommandDefinition(sql, parameters, cancellationToken: cancellationToken))
787 .ConfigureAwait(
false);
788 return rows.ToArray();
833 ArgumentNullException.ThrowIfNull(entity);
887 public async Task<bool>
InsertAsync<T>(T entity, CancellationToken cancellationToken =
default)
889 ArgumentNullException.ThrowIfNull(entity);
892 await
OpenAsync(connection, cancellationToken).ConfigureAwait(
false);
893 return await connection.ExecuteAsync(
895 .ConfigureAwait(
false) > 0;
948 ArgumentNullException.ThrowIfNull(entity);
1010 public async Task<bool>
UpdateAsync<T>(T entity, CancellationToken cancellationToken =
default)
1012 ArgumentNullException.ThrowIfNull(entity);
1015 await
OpenAsync(connection, cancellationToken).ConfigureAwait(
false);
1016 return await connection.ExecuteAsync(
1018 .ConfigureAwait(
false) > 0;
1071 ArgumentNullException.ThrowIfNull(entity);
1133 public async Task<bool>
DeleteAsync<T>(T entity, CancellationToken cancellationToken =
default)
1135 ArgumentNullException.ThrowIfNull(entity);
1138 await
OpenAsync(connection, cancellationToken).ConfigureAwait(
false);
1139 return await connection.ExecuteAsync(
1141 .ConfigureAwait(
false) > 0;
1240 var columns = map.
Properties.Select(property =>
1242 var sql = $
"{QuoteIdentifier(property.ColumnName)} {GetSqlType(property)}";
1251 return $
"CREATE TABLE IF NOT EXISTS {QuoteIdentifier(map.TableName)} ({string.Join(",
", columns)})";
1281 var columns =
string.Join(
", ", properties.Select(x =>
QuoteIdentifier(x.ColumnName)));
1282 var values =
string.Join(
", ", properties.Select(x =>
ParameterPrefix + x.Property.Name));
1283 return $
"INSERT INTO {QuoteIdentifier(map.TableName)} ({columns}) VALUES ({values})";
1321 var assignments =
string.Join(
1323 map.
UpdatableProperties.Select(x => $
"{QuoteIdentifier(x.ColumnName)} = {ParameterPrefix}{x.Property.Name}"));
1324 return $
"UPDATE {QuoteIdentifier(map.TableName)} SET {assignments} WHERE {QuoteIdentifier(key.ColumnName)} = {ParameterPrefix}{key.Property.Name}";
1362 return $
"DELETE FROM {QuoteIdentifier(map.TableName)} WHERE {QuoteIdentifier(key.ColumnName)} = {ParameterPrefix}{key.Property.Name}";
1391 return " PRIMARY KEY";
1436 var key = (typeof(T),
Kind, kind);
1445 _ =>
throw new ArgumentOutOfRangeException(nameof(kind))
1505 private static async Task
OpenAsync(IDbConnection connection, CancellationToken cancellationToken)
1507 if (connection is System.Data.Common.DbConnection dbConnection)
1509 await dbConnection.OpenAsync(cancellationToken).ConfigureAwait(
false);
1513 cancellationToken.ThrowIfCancellationRequested();
1551 return map.Key ??
throw new InvalidOperationException(
1552 $
"Entity [{map.EntityType.FullName}] does not define a key. Add [DatabaseKey] or an Id property.");
IReadOnlyList< DatabasePropertyMap > UpdatableProperties
static DatabaseEntityMap Create(Type entityType)
IReadOnlyList< DatabasePropertyMap > InsertableProperties
IReadOnlyList< DatabasePropertyMap > Properties
virtual string BuildInsertSql(DatabaseEntityMap map)
async Task CreateTableAsync< T >(CancellationToken cancellationToken=default)
bool Insert< T >(T entity)
virtual async Task EnsureDatabaseExistsAsync(CancellationToken cancellationToken=default)
virtual string ParameterPrefix
async Task< IReadOnlyList< T > > QueryAsync< T >(string sql, object? parameters=null, CancellationToken cancellationToken=default)
virtual string BuildDeleteSql(DatabaseEntityMap map)
IEnumerable< T > Query< T >(string sql, object? parameters=null)
async Task< int > ExecuteNonQueryAsync(string sql, object? parameters=null, CancellationToken cancellationToken=default)
async Task< bool > UpdateAsync< T >(T entity, CancellationToken cancellationToken=default)
IDbConnection CreateConnection()
Task< bool > IsTableExistsAsync< T >(CancellationToken cancellationToken=default)
virtual void EnsureDatabaseExists()
DatabaseProviderKind Kind
virtual string BuildCreateTableSql(DatabaseEntityMap map)
IDbConnection CreateOpenedConnection()
static readonly ConcurrentDictionary<(Type, DatabaseProviderKind, SqlKind), string > SqlCache
string QuoteIdentifier(string identifier)
async Task< T?> ExecuteScalarAsync< T >(string sql, object? parameters=null, CancellationToken cancellationToken=default)
DatabaseProviderBase(string connectionString)
bool Update< T >(T entity)
virtual string BuildPrimaryKeySql(DatabasePropertyMap property)
T? ExecuteScalar< T >(string sql, object? parameters=null)
Task< bool > IsTableExistsAsync(string tableName, CancellationToken cancellationToken=default)
static async Task OpenAsync(IDbConnection connection, CancellationToken cancellationToken)
string GetOrBuildSql< T >(SqlKind kind)
virtual string BuildUpdateSql(DatabaseEntityMap map)
int ExecuteNonQuery(string sql, object? parameters=null)
static DatabasePropertyMap RequireKey(DatabaseEntityMap map)
bool Delete< T >(T entity)
async Task< bool > DeleteAsync< T >(T entity, CancellationToken cancellationToken=default)
string GetSqlType(DatabasePropertyMap property)
bool IsTableExists(string tableName)
bool IsTableExists< T >()
async Task< bool > InsertAsync< T >(T entity, CancellationToken cancellationToken=default)