Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom Select SQL where clause #313

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions src/Dommel/Select.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,27 @@ public static IEnumerable<TEntity> Select<TEntity>(this IDbConnection connection
return connection.Query<TEntity>(sql, parameters, transaction, buffered);
}

/// <summary>
/// Selects all the entities matching the specified where clause.
/// </summary>
/// <typeparam name="TEntity">The type of the entity.</typeparam>
/// <param name="connection">The connection to the database. This can either be open or closed.</param>
/// <param name="whereClause">The specified where clause applied to the query</param>
/// <param name="transaction">Optional transaction for the command.</param>
/// <param name="buffered">
/// A value indicating whether the result of the query should be executed directly,
/// or when the query is materialized (using <c>ToList()</c> for example).
/// </param>
/// <returns>
/// A collection of entities of type <typeparamref name="TEntity"/> matching the specified
/// </returns>
public static IEnumerable<TEntity> Select<TEntity>(this IDbConnection connection, string whereClause, IDbTransaction? transaction = null, bool buffered = true)
{
var sql = BuildSelectSql<TEntity>(connection, whereClause, false, out var parameters);
LogQuery<TEntity>(sql);
return connection.Query<TEntity>(sql, parameters, transaction, buffered);
}

/// <summary>
/// Selects all the entities matching the specified predicate.
/// </summary>
Expand All @@ -52,6 +73,24 @@ public static Task<IEnumerable<TEntity>> SelectAsync<TEntity>(this IDbConnection
return connection.QueryAsync<TEntity>(new CommandDefinition(sql, parameters, transaction: transaction, cancellationToken: cancellationToken));
}

/// <summary>
/// Selects all the entities matching the specified where clause.
/// </summary>
/// <typeparam name="TEntity">The type of the entity.</typeparam>
/// <param name="connection">The connection to the database. This can either be open or closed.</param>
/// <param name="whereClause">The specified where clause applied to the query</param>
/// <param name="transaction">Optional transaction for the command.</param>
/// <param name="cancellationToken">Optional cancellation token for the command.</param>
/// <returns>
/// A collection of entities of type <typeparamref name="TEntity"/> matching the specified
/// </returns>
public static Task<IEnumerable<TEntity>> SelectAsync<TEntity>(this IDbConnection connection, string whereClause, IDbTransaction? transaction = null, CancellationToken cancellationToken = default)
{
var sql = BuildSelectSql(connection, whereClause, false, out var parameters);
LogQuery<TEntity>(sql);
return connection.QueryAsync<TEntity>(new CommandDefinition(sql, parameters, transaction: transaction, cancellationToken: cancellationToken));
}

/// <summary>
/// Selects the first entity matching the specified predicate, or a default value if no entity matched.
/// </summary>
Expand Down Expand Up @@ -112,6 +151,28 @@ private static string BuildSelectSql<TEntity>(IDbConnection connection, Expressi

return sql;
}

private static string BuildSelectSql<TEntity>(IDbConnection connection, string whereClause, bool firstRecordOnly, out DynamicParameters parameters)
{
var type = typeof(TEntity);

// Build the select all part
var sql = BuildGetAllQuery(connection, type);

// Append the where statement
var sqlBuilder = GetSqlBuilder(connection);
var sqlExpression = CreateSqlExpression<TEntity>(sqlBuilder);

sql += sqlExpression.ToSql(out parameters);
sql += $" {whereClause.Trim()} ";

if (firstRecordOnly)
{
sql += $" {sqlBuilder.LimitClause(1)}";
}

return sql;
}

/// <summary>
/// Selects all the entities matching the specified predicate.
Expand Down
44 changes: 42 additions & 2 deletions test/Dommel.Json.IntegrationTests/SelectTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,16 @@ public void SelectAndStatement(DatabaseDriver database)
Assert.NotEmpty(leads);
}

[Theory]
[ClassData(typeof(JsonDatabaseTestData))]
public void SelectAndStatementWithWhereClause(DatabaseDriver database)
{
using var con = database.GetConnection();
var id = InsertLead(con);
var leads = con.Select<Lead>("WHERE FirstName = 'Foo' AND LastName = 'Bar' AND Email = '[email protected]'");
Assert.NotEmpty(leads);
}

[Theory]
[ClassData(typeof(JsonDatabaseTestData))]
public async Task SelectAndStatementAsync(DatabaseDriver database)
Expand All @@ -79,13 +89,33 @@ public async Task SelectAndStatementAsync(DatabaseDriver database)
Assert.NotEmpty(leads);
}

[Theory]
[ClassData(typeof(JsonDatabaseTestData))]
public async Task SelectAndStatementWithWhereClauseAsync(DatabaseDriver database)
{
using var con = database.GetConnection();
var id = await InsertLeadAsync(con);
var leads = await con.SelectAsync<Lead>("WHERE FirstName = 'Foo' AND LastName = 'Bar' AND Email = '[email protected]'");
Assert.NotEmpty(leads);
}

[Theory]
[ClassData(typeof(JsonDatabaseTestData))]
public void SelectOrStatement(DatabaseDriver database)
{
using var con = database.GetConnection();
var id = InsertLead(con);
var leads = con.Select<Lead>(p => p.Data!.FirstName == "Foo" && p.Data.LastName == "Bar" || p.Email == "[email protected]");
var leads = con.Select<Lead>(p => (p.Data!.FirstName == "Foo" && p.Data.LastName == "Bar") || p.Email == "[email protected]");
Assert.NotEmpty(leads);
}

[Theory]
[ClassData(typeof(JsonDatabaseTestData))]
public void SelectOrStatementWithWhere(DatabaseDriver database)
{
using var con = database.GetConnection();
var id = InsertLead(con);
var leads = con.Select<Lead>("WHERE FirstName = 'Foo' AND LastName = 'Bar' OR Email = '[email protected]'");
Assert.NotEmpty(leads);
}

Expand All @@ -95,7 +125,17 @@ public async Task SelectOrStatementAsync(DatabaseDriver database)
{
using var con = database.GetConnection();
var id = await InsertLeadAsync(con);
var leads = await con.SelectAsync<Lead>(p => p.Data!.FirstName == "Foo" && p.Data.LastName == "Bar" || p.Email == "[email protected]");
var leads = await con.SelectAsync<Lead>(p => (p.Data!.FirstName == "Foo" && p.Data.LastName == "Bar") || p.Email == "[email protected]");
Assert.NotEmpty(leads);
}

[Theory]
[ClassData(typeof(JsonDatabaseTestData))]
public async Task SelectOrStatementWithWhereAsync(DatabaseDriver database)
{
using var con = database.GetConnection();
var id = await InsertLeadAsync(con);
var leads = await con.SelectAsync<Lead>("WHERE FirstName = 'Foo' AND LastName = 'Bar' OR Email = '[email protected]'");
Assert.NotEmpty(leads);
}
}