Fixed: Rename more than 999 movies in one go

Also pulls across Dapper improvements from Readarr.

Fixes Sentry RADARR-1V
Fixes #4359
This commit is contained in:
ta264
2020-05-10 22:01:07 +01:00
parent 93d27c70c4
commit 2c6b13dd11
16 changed files with 840 additions and 263 deletions

View File

@@ -14,12 +14,18 @@ namespace NzbDrone.Core.Datastore
{
public static class SqlBuilderExtensions
{
public static bool LogSql { get; set; }
private static readonly Logger Logger = NzbDroneLogger.GetLogger(typeof(SqlBuilderExtensions));
public static SqlBuilder SelectAll(this SqlBuilder builder)
public static bool LogSql { get; set; }
public static SqlBuilder Select(this SqlBuilder builder, params Type[] types)
{
return builder.Select("*");
return builder.Select(types.Select(x => TableMapping.Mapper.TableNameMapping(x) + ".*").Join(", "));
}
public static SqlBuilder SelectDistinct(this SqlBuilder builder, params Type[] types)
{
return builder.Select("DISTINCT " + types.Select(x => TableMapping.Mapper.TableNameMapping(x) + ".*").Join(", "));
}
public static SqlBuilder SelectCount(this SqlBuilder builder)
@@ -27,23 +33,30 @@ namespace NzbDrone.Core.Datastore
return builder.Select("COUNT(*)");
}
public static SqlBuilder SelectCountDistinct<TModel>(this SqlBuilder builder, Expression<Func<TModel, object>> property)
{
var table = TableMapping.Mapper.TableNameMapping(typeof(TModel));
var propName = property.GetMemberName().Name;
return builder.Select($"COUNT(DISTINCT \"{table}\".\"{propName}\")");
}
public static SqlBuilder Where<TModel>(this SqlBuilder builder, Expression<Func<TModel, bool>> filter)
{
var wb = new WhereBuilder(filter, true);
var wb = new WhereBuilder(filter, true, builder.Sequence);
return builder.Where(wb.ToString(), wb.Parameters);
}
public static SqlBuilder OrWhere<TModel>(this SqlBuilder builder, Expression<Func<TModel, bool>> filter)
{
var wb = new WhereBuilder(filter, true);
var wb = new WhereBuilder(filter, true, builder.Sequence);
return builder.OrWhere(wb.ToString(), wb.Parameters);
}
public static SqlBuilder Join<TLeft, TRight>(this SqlBuilder builder, Expression<Func<TLeft, TRight, bool>> filter)
{
var wb = new WhereBuilder(filter, false);
var wb = new WhereBuilder(filter, false, builder.Sequence);
var rightTable = TableMapping.Mapper.TableNameMapping(typeof(TRight));
@@ -52,41 +65,76 @@ namespace NzbDrone.Core.Datastore
public static SqlBuilder LeftJoin<TLeft, TRight>(this SqlBuilder builder, Expression<Func<TLeft, TRight, bool>> filter)
{
var wb = new WhereBuilder(filter, false);
var wb = new WhereBuilder(filter, false, builder.Sequence);
var rightTable = TableMapping.Mapper.TableNameMapping(typeof(TRight));
return builder.LeftJoin($"{rightTable} ON {wb.ToString()}");
}
public static SqlBuilder GroupBy<TModel>(this SqlBuilder builder, Expression<Func<TModel, object>> property)
{
var table = TableMapping.Mapper.TableNameMapping(typeof(TModel));
var propName = property.GetMemberName().Name;
return builder.GroupBy($"{table}.{propName}");
}
public static SqlBuilder.Template AddSelectTemplate(this SqlBuilder builder, Type type)
{
return builder.AddTemplate(TableMapping.Mapper.SelectTemplate(type)).LogQuery();
}
public static SqlBuilder.Template AddPageCountTemplate(this SqlBuilder builder, Type type)
{
return builder.AddTemplate(TableMapping.Mapper.PageCountTemplate(type)).LogQuery();
}
public static SqlBuilder.Template AddDeleteTemplate(this SqlBuilder builder, Type type)
{
return builder.AddTemplate(TableMapping.Mapper.DeleteTemplate(type)).LogQuery();
}
public static SqlBuilder.Template LogQuery(this SqlBuilder.Template template)
{
if (LogSql)
{
var sb = new StringBuilder();
sb.AppendLine();
sb.AppendLine("==== Begin Query Trace ====");
sb.AppendLine();
sb.AppendLine("QUERY TEXT:");
sb.AppendLine(template.RawSql);
sb.AppendLine();
sb.AppendLine("PARAMETERS:");
foreach (var p in ((DynamicParameters)template.Parameters).ToDictionary())
{
object val = (p.Value is string) ? string.Format("\"{0}\"", p.Value) : p.Value;
sb.AppendFormat("{0} = [{1}]", p.Key, val.ToJson() ?? "NULL").AppendLine();
}
sb.AppendLine();
sb.AppendLine("==== End Query Trace ====");
sb.AppendLine();
Logger.Trace(sb.ToString());
LogQuery(template.RawSql, (DynamicParameters)template.Parameters);
}
return template;
}
public static void LogQuery(string sql, object parameters)
{
if (LogSql)
{
LogQuery(sql, new DynamicParameters(parameters));
}
}
private static void LogQuery(string sql, DynamicParameters parameters)
{
var sb = new StringBuilder();
sb.AppendLine();
sb.AppendLine("==== Begin Query Trace ====");
sb.AppendLine();
sb.AppendLine("QUERY TEXT:");
sb.AppendLine(sql);
sb.AppendLine();
sb.AppendLine("PARAMETERS:");
foreach (var p in parameters.ToDictionary())
{
var val = (p.Value is string) ? string.Format("\"{0}\"", p.Value) : p.Value;
sb.AppendFormat("{0} = [{1}]", p.Key, val.ToJson() ?? "NULL").AppendLine();
}
sb.AppendLine();
sb.AppendLine("==== End Query Trace ====");
sb.AppendLine();
Logger.Trace(sb.ToString());
}
private static Dictionary<string, object> ToDictionary(this DynamicParameters dynamicParams)
{
var argsDictionary = new Dictionary<string, object>();
@@ -99,32 +147,21 @@ namespace NzbDrone.Core.Datastore
}
var templates = dynamicParams.GetType().GetField("templates", BindingFlags.NonPublic | BindingFlags.Instance);
if (templates != null)
if (templates != null && templates.GetValue(dynamicParams) is List<object> list)
{
var list = templates.GetValue(dynamicParams) as List<object>;
if (list != null)
foreach (var objProps in list.Select(obj => obj.GetPropertyValuePairs().ToList()))
{
foreach (var objProps in list.Select(obj => obj.GetPropertyValuePairs().ToList()))
{
objProps.ForEach(p => argsDictionary.Add(p.Key, p.Value));
}
objProps.ForEach(p => argsDictionary.Add(p.Key, p.Value));
}
}
return argsDictionary;
}
private static Dictionary<string, object> GetPropertyValuePairs(this object obj, string[] hidden = null)
private static Dictionary<string, object> GetPropertyValuePairs(this object obj)
{
var type = obj.GetType();
var pairs = hidden == null
? type.GetProperties()
.DistinctBy(propertyInfo => propertyInfo.Name)
.ToDictionary(
propertyInfo => propertyInfo.Name,
propertyInfo => propertyInfo.GetValue(obj, null))
: type.GetProperties()
.Where(it => !hidden.Contains(it.Name))
var pairs = type.GetProperties().Where(x => x.IsMappableProperty())
.DistinctBy(propertyInfo => propertyInfo.Name)
.ToDictionary(
propertyInfo => propertyInfo.Name,