parent
78c7372a0d
commit
c0b80696bc
@ -1,47 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Linq.Expressions;
|
|
||||||
using System.Reflection;
|
|
||||||
using Dapper;
|
|
||||||
using NzbDrone.Common.Reflection;
|
|
||||||
|
|
||||||
namespace NzbDrone.Core.Datastore
|
|
||||||
{
|
|
||||||
public static class MappingExtensions
|
|
||||||
{
|
|
||||||
public static PropertyInfo GetMemberName<T, TChild>(this Expression<Func<T, TChild>> member)
|
|
||||||
{
|
|
||||||
if (!(member.Body is MemberExpression memberExpression))
|
|
||||||
{
|
|
||||||
memberExpression = (member.Body as UnaryExpression).Operand as MemberExpression;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (PropertyInfo)memberExpression.Member;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool IsMappableProperty(this MemberInfo memberInfo)
|
|
||||||
{
|
|
||||||
var propertyInfo = memberInfo as PropertyInfo;
|
|
||||||
|
|
||||||
if (propertyInfo == null)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!propertyInfo.IsReadable() || !propertyInfo.IsWritable())
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is a bit of a hack but is the only way to see if a type has a handler set in Dapper
|
|
||||||
#pragma warning disable 618
|
|
||||||
SqlMapper.LookupDbType(propertyInfo.PropertyType, "", false, out var handler);
|
|
||||||
#pragma warning restore 618
|
|
||||||
if (propertyInfo.PropertyType.IsSimpleType() || handler != null)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,176 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Data;
|
|
||||||
using Dapper;
|
|
||||||
|
|
||||||
namespace NzbDrone.Core.Datastore
|
|
||||||
{
|
|
||||||
public static class SqlMapperExtensions
|
|
||||||
{
|
|
||||||
public static IEnumerable<T> Query<T>(this IDatabase db, string sql, object param = null)
|
|
||||||
{
|
|
||||||
using (var conn = db.OpenConnection())
|
|
||||||
{
|
|
||||||
var items = SqlMapper.Query<T>(conn, sql, param);
|
|
||||||
if (TableMapping.Mapper.LazyLoadList.TryGetValue(typeof(T), out var lazyProperties))
|
|
||||||
{
|
|
||||||
foreach (var item in items)
|
|
||||||
{
|
|
||||||
ApplyLazyLoad(db, item, lazyProperties);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return items;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IEnumerable<TReturn> Query<TFirst, TSecond, TReturn>(this IDatabase db, string sql, Func<TFirst, TSecond, TReturn> map, object param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null)
|
|
||||||
{
|
|
||||||
TReturn MapWithLazy(TFirst first, TSecond second)
|
|
||||||
{
|
|
||||||
ApplyLazyLoad(db, first);
|
|
||||||
ApplyLazyLoad(db, second);
|
|
||||||
return map(first, second);
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerable<TReturn> result = null;
|
|
||||||
using (var conn = db.OpenConnection())
|
|
||||||
{
|
|
||||||
result = SqlMapper.Query<TFirst, TSecond, TReturn>(conn, sql, MapWithLazy, param, transaction, buffered, splitOn, commandTimeout, commandType);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IEnumerable<TReturn> Query<TFirst, TSecond, TThird, TReturn>(this IDatabase db, string sql, Func<TFirst, TSecond, TThird, TReturn> map, object param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null)
|
|
||||||
{
|
|
||||||
TReturn MapWithLazy(TFirst first, TSecond second, TThird third)
|
|
||||||
{
|
|
||||||
ApplyLazyLoad(db, first);
|
|
||||||
ApplyLazyLoad(db, second);
|
|
||||||
ApplyLazyLoad(db, third);
|
|
||||||
return map(first, second, third);
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerable<TReturn> result = null;
|
|
||||||
using (var conn = db.OpenConnection())
|
|
||||||
{
|
|
||||||
result = SqlMapper.Query<TFirst, TSecond, TThird, TReturn>(conn, sql, MapWithLazy, param, transaction, buffered, splitOn, commandTimeout, commandType);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IEnumerable<TReturn> Query<TFirst, TSecond, TThird, TFourth, TReturn>(this IDatabase db, string sql, Func<TFirst, TSecond, TThird, TFourth, TReturn> map, object param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null)
|
|
||||||
{
|
|
||||||
TReturn MapWithLazy(TFirst first, TSecond second, TThird third, TFourth fourth)
|
|
||||||
{
|
|
||||||
ApplyLazyLoad(db, first);
|
|
||||||
ApplyLazyLoad(db, second);
|
|
||||||
ApplyLazyLoad(db, third);
|
|
||||||
ApplyLazyLoad(db, fourth);
|
|
||||||
return map(first, second, third, fourth);
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerable<TReturn> result = null;
|
|
||||||
using (var conn = db.OpenConnection())
|
|
||||||
{
|
|
||||||
result = SqlMapper.Query<TFirst, TSecond, TThird, TFourth, TReturn>(conn, sql, MapWithLazy, param, transaction, buffered, splitOn, commandTimeout, commandType);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IEnumerable<TReturn> Query<TFirst, TSecond, TThird, TFourth, TFifth, TReturn>(this IDatabase db, string sql, Func<TFirst, TSecond, TThird, TFourth, TFifth, TReturn> map, object param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null)
|
|
||||||
{
|
|
||||||
TReturn MapWithLazy(TFirst first, TSecond second, TThird third, TFourth fourth, TFifth fifth)
|
|
||||||
{
|
|
||||||
ApplyLazyLoad(db, first);
|
|
||||||
ApplyLazyLoad(db, second);
|
|
||||||
ApplyLazyLoad(db, third);
|
|
||||||
ApplyLazyLoad(db, fourth);
|
|
||||||
ApplyLazyLoad(db, fifth);
|
|
||||||
return map(first, second, third, fourth, fifth);
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerable<TReturn> result = null;
|
|
||||||
using (var conn = db.OpenConnection())
|
|
||||||
{
|
|
||||||
result = SqlMapper.Query<TFirst, TSecond, TThird, TFourth, TFifth, TReturn>(conn, sql, MapWithLazy, param, transaction, buffered, splitOn, commandTimeout, commandType);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IEnumerable<T> Query<T>(this IDatabase db, SqlBuilder builder)
|
|
||||||
{
|
|
||||||
var type = typeof(T);
|
|
||||||
var sql = builder.Select(type).AddSelectTemplate(type);
|
|
||||||
|
|
||||||
return db.Query<T>(sql.RawSql, sql.Parameters);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IEnumerable<T> QueryDistinct<T>(this IDatabase db, SqlBuilder builder)
|
|
||||||
{
|
|
||||||
var type = typeof(T);
|
|
||||||
var sql = builder.SelectDistinct(type).AddSelectTemplate(type);
|
|
||||||
|
|
||||||
return db.Query<T>(sql.RawSql, sql.Parameters);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IEnumerable<T> QueryJoined<T, T2>(this IDatabase db, SqlBuilder builder, Func<T, T2, T> mapper)
|
|
||||||
{
|
|
||||||
var type = typeof(T);
|
|
||||||
var sql = builder.Select(type, typeof(T2)).AddSelectTemplate(type);
|
|
||||||
|
|
||||||
return db.Query(sql.RawSql, mapper, sql.Parameters);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IEnumerable<T> QueryJoined<T, T2, T3>(this IDatabase db, SqlBuilder builder, Func<T, T2, T3, T> mapper)
|
|
||||||
{
|
|
||||||
var type = typeof(T);
|
|
||||||
var sql = builder.Select(type, typeof(T2), typeof(T3)).AddSelectTemplate(type);
|
|
||||||
|
|
||||||
return db.Query(sql.RawSql, mapper, sql.Parameters);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IEnumerable<T> QueryJoined<T, T2, T3, T4>(this IDatabase db, SqlBuilder builder, Func<T, T2, T3, T4, T> mapper)
|
|
||||||
{
|
|
||||||
var type = typeof(T);
|
|
||||||
var sql = builder.Select(type, typeof(T2), typeof(T3), typeof(T4)).AddSelectTemplate(type);
|
|
||||||
|
|
||||||
return db.Query(sql.RawSql, mapper, sql.Parameters);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IEnumerable<T> QueryJoined<T, T2, T3, T4, T5>(this IDatabase db, SqlBuilder builder, Func<T, T2, T3, T4, T5, T> mapper)
|
|
||||||
{
|
|
||||||
var type = typeof(T);
|
|
||||||
var sql = builder.Select(type, typeof(T2), typeof(T3), typeof(T4), typeof(T5)).AddSelectTemplate(type);
|
|
||||||
|
|
||||||
return db.Query(sql.RawSql, mapper, sql.Parameters);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void ApplyLazyLoad<TModel>(IDatabase db, TModel model)
|
|
||||||
{
|
|
||||||
if (TableMapping.Mapper.LazyLoadList.TryGetValue(typeof(TModel), out var lazyProperties))
|
|
||||||
{
|
|
||||||
ApplyLazyLoad(db, model, lazyProperties);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void ApplyLazyLoad<TModel>(IDatabase db, TModel model, List<LazyLoadedProperty> lazyProperties)
|
|
||||||
{
|
|
||||||
if (model == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var lazyProperty in lazyProperties)
|
|
||||||
{
|
|
||||||
var lazy = (ILazyLoaded)lazyProperty.LazyLoad.Clone();
|
|
||||||
lazy.Prepare(db, model);
|
|
||||||
lazyProperty.Property.SetValue(model, lazy);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,168 +0,0 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
using Dapper;
|
|
||||||
|
|
||||||
namespace NzbDrone.Core.Datastore
|
|
||||||
{
|
|
||||||
public class SqlBuilder
|
|
||||||
{
|
|
||||||
private readonly Dictionary<string, Clauses> _data = new Dictionary<string, Clauses>();
|
|
||||||
|
|
||||||
public int Sequence { get; private set; }
|
|
||||||
|
|
||||||
public Template AddTemplate(string sql, dynamic parameters = null) =>
|
|
||||||
new Template(this, sql, parameters);
|
|
||||||
|
|
||||||
public SqlBuilder Intersect(string sql, dynamic parameters = null) =>
|
|
||||||
AddClause("intersect", sql, parameters, "\nINTERSECT\n ", "\n ", "\n", false);
|
|
||||||
|
|
||||||
public SqlBuilder InnerJoin(string sql, dynamic parameters = null) =>
|
|
||||||
AddClause("innerjoin", sql, parameters, "\nINNER JOIN ", "\nINNER JOIN ", "\n", false);
|
|
||||||
|
|
||||||
public SqlBuilder LeftJoin(string sql, dynamic parameters = null) =>
|
|
||||||
AddClause("leftjoin", sql, parameters, "\nLEFT JOIN ", "\nLEFT JOIN ", "\n", false);
|
|
||||||
|
|
||||||
public SqlBuilder RightJoin(string sql, dynamic parameters = null) =>
|
|
||||||
AddClause("rightjoin", sql, parameters, "\nRIGHT JOIN ", "\nRIGHT JOIN ", "\n", false);
|
|
||||||
|
|
||||||
public SqlBuilder Where(string sql, dynamic parameters = null) =>
|
|
||||||
AddClause("where", sql, parameters, " AND ", "WHERE ", "\n", false);
|
|
||||||
|
|
||||||
public SqlBuilder OrWhere(string sql, dynamic parameters = null) =>
|
|
||||||
AddClause("where", sql, parameters, " OR ", "WHERE ", "\n", true);
|
|
||||||
|
|
||||||
public SqlBuilder OrderBy(string sql, dynamic parameters = null) =>
|
|
||||||
AddClause("orderby", sql, parameters, " , ", "ORDER BY ", "\n", false);
|
|
||||||
|
|
||||||
public SqlBuilder Select(string sql, dynamic parameters = null) =>
|
|
||||||
AddClause("select", sql, parameters, " , ", "", "\n", false);
|
|
||||||
|
|
||||||
public SqlBuilder AddParameters(dynamic parameters) =>
|
|
||||||
AddClause("--parameters", "", parameters, "", "", "", false);
|
|
||||||
|
|
||||||
public SqlBuilder Join(string sql, dynamic parameters = null) =>
|
|
||||||
AddClause("join", sql, parameters, "\nJOIN ", "\nJOIN ", "\n", false);
|
|
||||||
|
|
||||||
public SqlBuilder GroupBy(string sql, dynamic parameters = null) =>
|
|
||||||
AddClause("groupby", sql, parameters, " , ", "\nGROUP BY ", "\n", false);
|
|
||||||
|
|
||||||
public SqlBuilder Having(string sql, dynamic parameters = null) =>
|
|
||||||
AddClause("having", sql, parameters, "\nAND ", "HAVING ", "\n", false);
|
|
||||||
|
|
||||||
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 = sql, Parameters = parameters, IsInclusive = isInclusive });
|
|
||||||
Sequence++;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Template
|
|
||||||
{
|
|
||||||
private static readonly Regex _regex = new Regex(@"\/\*\*.+?\*\*\/", RegexOptions.Compiled | RegexOptions.Multiline);
|
|
||||||
|
|
||||||
private readonly string _sql;
|
|
||||||
private readonly SqlBuilder _builder;
|
|
||||||
private readonly object _initParams;
|
|
||||||
|
|
||||||
private int _dataSeq = -1; // Unresolved
|
|
||||||
private string _rawSql;
|
|
||||||
private object _parameters;
|
|
||||||
|
|
||||||
public Template(SqlBuilder builder, string sql, dynamic parameters)
|
|
||||||
{
|
|
||||||
_initParams = parameters;
|
|
||||||
_sql = sql;
|
|
||||||
_builder = builder;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string RawSql
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
ResolveSql();
|
|
||||||
return _rawSql;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public object Parameters
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
ResolveSql();
|
|
||||||
return _parameters;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ResolveSql()
|
|
||||||
{
|
|
||||||
if (_dataSeq != _builder.Sequence)
|
|
||||||
{
|
|
||||||
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.Sequence;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class Clause
|
|
||||||
{
|
|
||||||
public string Sql { get; set; }
|
|
||||||
public object Parameters { get; set; }
|
|
||||||
public bool IsInclusive { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
private class Clauses : List<Clause>
|
|
||||||
{
|
|
||||||
private readonly string _joiner;
|
|
||||||
private readonly string _prefix;
|
|
||||||
private readonly string _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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in new issue