Files
Marc Gravell aecffecae1 attempt NRT makeover (#1928)
* attempt NRT makeover

- annotate NRTs on GridReader API
- add protected access to some of the GridReader internals
- switch GridReader callbacks to be more type-independent

docs

lib updates; deal with yellow warnings and test failures (SQL server certs and cancellation surfacing differently)

fix break

simplify proposed GridReader changes to protected OnBeforeGrid and OnAfterGrid[Async]

Builds: Bump library versions (#1935)

Tests: Upgrade dependencies for Dependabot (#1936)

I'll do a pass at all of these later, but getting CVE versions out of the pipe.

Resolving 4 alerts here: https://github.com/DapperLib/Dapper/security/dependabot

merge and lib updates

allow Identity to be constructed on-the-fly inside GridReader

fix build warnings

include readme

rev minor

- enable [SkipLocalsInit] everywhere
- use NET5_0_OR_GREATER
 for remoting check

# Conflicts:
#	Dapper/CommandDefinition.cs
#	Dapper/DefaultTypeMap.cs
#	Dapper/SqlMapper.Async.cs
#	Dapper/SqlMapper.IDataReader.cs
#	Dapper/SqlMapper.Link.cs
#	Dapper/SqlMapper.cs
#	Directory.Build.props

* shipped, not unshipped

* fixup SqlBuilder; use is null / is not null

* use central package management (#1949)

* Nullable test tweaks

* Nuget: let's just remove it!

* 2 test fixes from review

* fix FindExplicitConstructor

* add GetPropertySetterOrThrow

* fix NRT on FindConstructor

* DapperRow: value is object?

* use NotNullWhen

* make constructor problem more obvious

* test fixes

---------

Co-authored-by: Nick Craver <nrcraver@gmail.com>
2023-09-12 15:58:49 +01:00

165 lines
6.4 KiB
C#

using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Text.RegularExpressions;
namespace Dapper
{
public class SqlBuilder
{
private readonly Dictionary<string, Clauses> _data = new Dictionary<string, Clauses>();
private int _seq;
private class Clause
{
public Clause(string sql, object? parameters, bool isInclusive)
{
Sql = sql;
Parameters = parameters;
IsInclusive = isInclusive;
}
public string Sql { get; }
public object? Parameters { get; }
public bool IsInclusive { get; }
}
private class Clauses : List<Clause>
{
private readonly string _joiner, _prefix, _postfix;
public Clauses(string joiner, string prefix = "", string postfix = "")
{
_joiner = joiner;
_prefix = prefix;
_postfix = postfix;
}
public string ResolveClauses(DynamicParameters p)
{
foreach (var item in this)
{
p.AddDynamicParams(item.Parameters);
}
return this.Any(a => a.IsInclusive)
? _prefix +
string.Join(_joiner,
this.Where(a => !a.IsInclusive)
.Select(c => c.Sql)
.Union(new[]
{
" ( " +
string.Join(" OR ", this.Where(a => a.IsInclusive).Select(c => c.Sql).ToArray()) +
" ) "
}).ToArray()) + _postfix
: _prefix + string.Join(_joiner, this.Select(c => c.Sql).ToArray()) + _postfix;
}
}
public class Template
{
private readonly string _sql;
private readonly SqlBuilder _builder;
private readonly object? _initParams;
private int _dataSeq = -1; // Unresolved
public Template(SqlBuilder builder, string sql, dynamic? parameters)
{
_initParams = parameters;
_sql = sql;
_builder = builder;
}
private static readonly Regex _regex = new Regex(@"\/\*\*.+?\*\*\/", RegexOptions.Compiled | RegexOptions.Multiline);
private void ResolveSql()
{
if (_dataSeq != _builder._seq)
{
var p = new DynamicParameters(_initParams);
rawSql = _sql;
foreach (var pair in _builder._data)
{
rawSql = rawSql.Replace("/**" + pair.Key + "**/", pair.Value.ResolveClauses(p));
}
parameters = p;
// replace all that is left with empty
rawSql = _regex.Replace(rawSql, "");
_dataSeq = _builder._seq;
}
}
private string? rawSql;
private object? parameters;
public string RawSql
{
get { ResolveSql(); return rawSql!; }
}
public object? Parameters
{
get { ResolveSql(); return parameters; }
}
}
public Template AddTemplate(string sql, dynamic? parameters = null) =>
new Template(this, sql, (object?)parameters);
protected SqlBuilder AddClause(string name, string sql, object? parameters, string joiner, string prefix = "", string postfix = "", bool isInclusive = false)
{
if (!_data.TryGetValue(name, out var clauses))
{
clauses = new Clauses(joiner, prefix, postfix);
_data[name] = clauses;
}
clauses.Add(new Clause(sql, parameters, isInclusive));
_seq++;
return this;
}
public SqlBuilder Intersect(string sql, dynamic? parameters = null) =>
AddClause("intersect", sql, (object?)parameters, "\nINTERSECT\n ", "\n ", "\n", false);
public SqlBuilder InnerJoin(string sql, dynamic? parameters = null) =>
AddClause("innerjoin", sql, (object?)parameters, "\nINNER JOIN ", "\nINNER JOIN ", "\n", false);
public SqlBuilder LeftJoin(string sql, dynamic? parameters = null) =>
AddClause("leftjoin", sql, (object?)parameters, "\nLEFT JOIN ", "\nLEFT JOIN ", "\n", false);
public SqlBuilder RightJoin(string sql, dynamic? parameters = null) =>
AddClause("rightjoin", sql, (object?)parameters, "\nRIGHT JOIN ", "\nRIGHT JOIN ", "\n", false);
public SqlBuilder Where(string sql, dynamic? parameters = null) =>
AddClause("where", sql, (object?)parameters, " AND ", "WHERE ", "\n", false);
public SqlBuilder OrWhere(string sql, dynamic? parameters = null) =>
AddClause("where", sql, (object?)parameters, " OR ", "WHERE ", "\n", true);
public SqlBuilder OrderBy(string sql, dynamic? parameters = null) =>
AddClause("orderby", sql, (object?)parameters, " , ", "ORDER BY ", "\n", false);
public SqlBuilder Select(string sql, dynamic? parameters = null) =>
AddClause("select", sql, (object?)parameters, " , ", "", "\n", false);
public SqlBuilder AddParameters(dynamic parameters) =>
AddClause("--parameters", "", (object?)parameters, "", "", "", false);
public SqlBuilder Join(string sql, dynamic? parameters = null) =>
AddClause("join", sql, (object?)parameters, "\nJOIN ", "\nJOIN ", "\n", false);
public SqlBuilder GroupBy(string sql, dynamic? parameters = null) =>
AddClause("groupby", sql, (object?)parameters, " , ", "\nGROUP BY ", "\n", false);
public SqlBuilder Having(string sql, dynamic? parameters = null) =>
AddClause("having", sql, (object?)parameters, "\nAND ", "HAVING ", "\n", false);
public SqlBuilder Set(string sql, dynamic? parameters = null) =>
AddClause("set", sql, (object?)parameters, " , ", "SET ", "\n", false);
}
}