Skip to content

Commit

Permalink
feat(builder) - Support to executions
Browse files Browse the repository at this point in the history
Adds summary documentation on all *.cs files
Adds Execution methods to performs execution on database with sql
Adds command timeout support
Allows the execution as a Stored Procedure
Adds to Query a way to returns an enumebrale result
  • Loading branch information
AugustoDeveloper committed Jan 29, 2023
1 parent 0c99682 commit f00335a
Show file tree
Hide file tree
Showing 7 changed files with 445 additions and 34 deletions.
21 changes: 10 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,17 @@ This package is a simple, easy and fluent way to execute SQL on database connect
You can install the package using one of the options bellow:
- Package Manager
```
PM> NuGet\Install-Package Dapper.FluentExecution -Version 0.1.1
PM> NuGet\Install-Package Dapper.FluentExecution -Version 0.2.0
```

- .NET CLI
```
dotnet add package Dapper.FluentExecution --version 0.1.1
dotnet add package Dapper.FluentExecution --version 0.2.0
```

- PackageReference
```
<PackageReference Include="Dapper.FluentExecution" Version="0.1.1" />
<PackageReference Include="Dapper.FluentExecution" Version="0.2.0" />
```

## Usage
Expand Down Expand Up @@ -49,14 +49,13 @@ public async Task<Person?> GetByIdAsync(int id, int? specificAddressId, Cancella
.WithParameter("@Id", id)
.QuerySingleOrDefaultAsync<Person>(cancellation);
```
## TODO - v0.2.0
- [ ] Add unit tests for `IExecutionBuilder` methods
- [ ] Add summary doc on all .cs files
- [ ] Add suport to `Execution` methods on `IExecutionBuilder`. E.g.: `Execute, ExecuteAsync, ExecuteScalar, ExecuteScalarAsync...`.
- [ ] Add support to dynamic parameter by dynamic object. E.g.: `new { Param1 = "1", Param2 = 2 }`
- [ ] Add support to set command timeout
- [ ] Add support to set query as an execution of stored procedure
- [ ] Add `QueryAsync, Query,...` an `IEnumerable<T>` result
## Release - v0.2.0
- Add summary doc on all .cs files
- Add suport to `Execution` methods on `IExecutionBuilder`. E.g.: `Execute, ExecuteAsync, ExecuteScalar, ExecuteScalarAsync...`.
- Add support to dynamic parameter by dynamic object. E.g.: `new { Param1 = "1", Param2 = 2 }`
- Add support to set command timeout
- Add support to set query as an execution of stored procedure
- Add `QueryAsync, Query,...` an `IEnumerable<T>` result

## Release - v0.1.1
- Fixing `csproj` documentation to Nuget.org
Expand Down
17 changes: 17 additions & 0 deletions src/fluent-execution/AsyncResult.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
namespace Dapper.FluentExecution;

///<summary>
///It's helper struct to allows returns a async result at fluent way
///</summary>
public struct AsyncResult<T>
{
private readonly Task<IEnumerable<T>> taskResult;
Expand All @@ -9,13 +12,27 @@ internal AsyncResult(Task<IEnumerable<T>> result)
this.taskResult = result;
}

///<summary>
///Performs an awaitable result as <see cref="IEnumerable{T}"/> of <typeparamref name="T"/>
///</summary>
///<returns>An IEnumerable of <typeparamref name="T"/></returns>
public async Task<IEnumerable<T>> GetResultAsync() => await taskResult;

///<summary>
///Performs awaitable result as a <see cref="List{T}"/> of <typeparamref name="T"/>
///</summary>
///<returns>A list of <typeparamref name="T"/></returns>
public async Task<List<T>> ToListAsync()
{
var newResult = await taskResult;

return newResult.ToList();
}

///<summary>
///Performs an awaitable result as an <see cref="Array"/> of <typeparamref name="T"/>
///</summary>
///<returns>An array of <typeparamref name="T"/></returns>
public async Task<T[]> ToArrayAsync()
{
var newResult = await taskResult;
Expand Down
2 changes: 1 addition & 1 deletion src/fluent-execution/Dapper.FluentExecution.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
<Authors>Augusto Mesquita</Authors>
<Company>Aucamana</Company>
<Owners>augustodeveloper</Owners>
<Version>0.1.1</Version>
<Version>0.2.0</Version>
<PackageId>Dapper.FluentExecution</PackageId>
<PackageTags>Dapper;Dapper.Fluent;Dapper.Query;Execution;Dapper.Execution</PackageTags>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
Expand Down
90 changes: 72 additions & 18 deletions src/fluent-execution/ExecutionSqlBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,16 @@ internal class ExecutionSqlBuilder : IExecutionBuilder
private readonly StringBuilder sqlBuilder;
private DynamicParameters? parameters;
private IDbTransaction? transaction;
private CommandType commandType;
private TimeSpan? commandTimeout;

private DynamicParameters Parameters => GetParameters();

protected ExecutionSqlBuilder(string rootSql, IDbConnection connection)
{
this.connection = connection;
this.sqlBuilder = new(rootSql);
this.commandType = CommandType.Text;
}

internal static IExecutionBuilder New(string? sql, IDbConnection? connection)
Expand All @@ -33,7 +36,6 @@ internal static IExecutionBuilder New(string? sql, IDbConnection? connection)
#else
ArgumentNullException.ThrowIfNull(connection);
#endif

return new ExecutionSqlBuilder(sql!, connection!);
}

Expand All @@ -47,8 +49,23 @@ private DynamicParameters GetParameters()
return parameters;
}

private int? GetCommandTimeout()
{
if (!commandTimeout.HasValue)
{
return null;
}

if (commandTimeout.Value.Seconds < 1)
{
return null;
}

return commandTimeout.Value.Seconds;
}

private CommandDefinition BuildCommandDefinition(CancellationToken cancellation = default)
=> new CommandDefinition(sqlBuilder.ToString(), parameters, transaction: transaction, cancellationToken: cancellation);
=> new CommandDefinition(sqlBuilder.ToString(), parameters, transaction, GetCommandTimeout(), commandType, cancellationToken: cancellation);

IExecutionBuilder IExecutionBuilder.WithTransaction(IDbTransaction transaction)
{
Expand All @@ -57,6 +74,16 @@ IExecutionBuilder IExecutionBuilder.WithTransaction(IDbTransaction transaction)
return this;
}

IExecutionBuilder IExecutionBuilder.AsStoredProcedure()
{
if (commandType != CommandType.StoredProcedure)
{
commandType = CommandType.StoredProcedure;
}

return this;
}

IExecutionBuilder IExecutionBuilder.AppendSql(bool condition, string sql)
{
if (condition)
Expand Down Expand Up @@ -118,6 +145,29 @@ IExecutionBuilder IExecutionBuilder.WithParameter(string parameterName, object v
return this;
}

IExecutionBuilder IExecutionBuilder.WithParameter(bool condition, object values)
{
if (condition)
{
Parameters.AddDynamicParams(values);
}

return this;
}

IExecutionBuilder IExecutionBuilder.WithParameter(object values)
{
Parameters.AddDynamicParams(values);

return this;
}

IExecutionBuilder IExecutionBuilder.WithCommandTimeout(TimeSpan timeout)
{
this.commandTimeout = timeout;
return this;
}

IEnumerable<dynamic> IExecutionBuilder.Query() => this.connection.Query<dynamic>(BuildCommandDefinition());

IEnumerable<T> IExecutionBuilder.Query<T>() => this.connection.Query<T>(BuildCommandDefinition());
Expand Down Expand Up @@ -158,15 +208,9 @@ AsyncResult<dynamic> IExecutionBuilder.QueryAsync(CancellationToken cancellation
return new(result);
}

async Task<dynamic> IExecutionBuilder.QuerySingleAsync(CancellationToken cancellation)
{
return await this.connection.QuerySingleAsync(BuildCommandDefinition(cancellation));
}
async Task<dynamic> IExecutionBuilder.QuerySingleAsync(CancellationToken cancellation) => await this.connection.QuerySingleAsync(BuildCommandDefinition(cancellation));

async Task<T> IExecutionBuilder.QuerySingleAsync<T>(CancellationToken cancellation)
{
return await this.connection.QuerySingleAsync<T>(BuildCommandDefinition(cancellation));
}
async Task<T> IExecutionBuilder.QuerySingleAsync<T>(CancellationToken cancellation) => await this.connection.QuerySingleAsync<T>(BuildCommandDefinition(cancellation));

async Task<dynamic?> IExecutionBuilder.QuerySingleOrDefaultAsync(CancellationToken cancellation)
{
Expand All @@ -193,15 +237,9 @@ async Task<T> IExecutionBuilder.QuerySingleAsync<T>(CancellationToken cancellati

}

async Task<dynamic> IExecutionBuilder.QueryFirstAsync(CancellationToken cancellation)
{
return await this.connection.QueryFirstAsync(BuildCommandDefinition(cancellation));
}
async Task<dynamic> IExecutionBuilder.QueryFirstAsync(CancellationToken cancellation) => await this.connection.QueryFirstAsync(BuildCommandDefinition(cancellation));

async Task<T> IExecutionBuilder.QueryFirstAsync<T>(CancellationToken cancellation)
{
return await this.connection.QueryFirstAsync<T>(BuildCommandDefinition(cancellation));
}
async Task<T> IExecutionBuilder.QueryFirstAsync<T>(CancellationToken cancellation) => await this.connection.QueryFirstAsync<T>(BuildCommandDefinition(cancellation));

async Task<dynamic?> IExecutionBuilder.QueryFirstOrDefaultAsync(CancellationToken cancellation)
{
Expand Down Expand Up @@ -232,4 +270,20 @@ async Task<T> IExecutionBuilder.QueryMultipleAsync<T>(Func<SqlMapper.GridReader,
using var gridReader = await this.connection.QueryMultipleAsync(BuildCommandDefinition(cancellation));
return await funcTask(gridReader);
}

int IExecutionBuilder.Execute() => this.connection.Execute(BuildCommandDefinition());

async Task<int> IExecutionBuilder.ExecuteAsync(CancellationToken cancellation) => await this.connection.ExecuteAsync(BuildCommandDefinition(cancellation));

object IExecutionBuilder.ExecuteScalar() => this.connection.ExecuteScalar(BuildCommandDefinition());

T IExecutionBuilder.ExecuteScalar<T>() => this.connection.ExecuteScalar<T>(BuildCommandDefinition());

async Task<object> IExecutionBuilder.ExecuteScalarAsync(CancellationToken cancellation) => await this.connection.ExecuteScalarAsync(BuildCommandDefinition(cancellation));

async Task<T> IExecutionBuilder.ExecuteScalarAsync<T>(CancellationToken cancellation) => await this.connection.ExecuteScalarAsync<T>(BuildCommandDefinition(cancellation));

IDataReader IExecutionBuilder.ExecuteDataReader() => this.connection.ExecuteReader(BuildCommandDefinition());

async Task<IDataReader> IExecutionBuilder.ExecuteDataReaderAsync(CancellationToken cancellation) => await this.connection.ExecuteReaderAsync(BuildCommandDefinition(cancellation));
}
13 changes: 13 additions & 0 deletions src/fluent-execution/StringExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,21 @@

namespace Dapper.FluentExecution;

///<summaru>
/// Extension class to able starts a fluent query execution
/// on connection
///</summary>
public static class StringExtensions
{
///<summaru>
/// Starts a fluent query execution from <paramref name="sql"/> sql string
/// by <paramref name="connection"/> that instantiate a <seealso cref="IExecutionBuilder"/>
///</summary>
///<param name="sql">SQL text to perform a query on connection</param>
///<param name="connection">Database connection that allows to perform query</param>
///<returns>An <see cref="IExecutionBuilder"/> instance</returns>
///<exception cref="ArgumentException">It could be throws if <paramref name="sql"/> is invalid as null, empty or whitespace value</exception>
///<exception cref="ArgumentNullException">It could be throws if <paramref name="connection"/> is invalid as null value<exception>
public static IExecutionBuilder On(this string? sql, IDbConnection? connection)
{
return ExecutionSqlBuilder.New(sql, connection);
Expand Down
Loading

0 comments on commit f00335a

Please sign in to comment.