mirror of
https://github.com/Radarr/Radarr.git
synced 2024-09-11 20:12:41 +02:00
Swap to dapper and system.text.json for database backend
This commit is contained in:
parent
7b17c3e36c
commit
d2065bfa1b
@ -1,13 +1,11 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Nancy;
|
||||
using Radarr.Http.Extensions;
|
||||
using NzbDrone.Api.Movies;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.History;
|
||||
using Radarr.Http;
|
||||
using Radarr.Http.REST;
|
||||
using NzbDrone.Core.DecisionEngine.Specifications;
|
||||
|
||||
namespace NzbDrone.Api.History
|
||||
@ -37,7 +35,7 @@ protected HistoryResource MapToResource(Core.History.History model)
|
||||
|
||||
if (model.Movie != null)
|
||||
{
|
||||
resource.QualityCutoffNotMet = _qualityUpgradableSpecification.CutoffNotMet(model.Movie.Profile.Value, model.Quality);
|
||||
resource.QualityCutoffNotMet = _qualityUpgradableSpecification.CutoffNotMet(model.Movie.Profile, model.Quality);
|
||||
}
|
||||
|
||||
return resource;
|
||||
|
@ -29,7 +29,7 @@ protected virtual ReleaseResource MapDecision(DownloadDecision decision, int ini
|
||||
if (decision.RemoteMovie.Movie != null)
|
||||
{
|
||||
release.QualityWeight = decision.RemoteMovie.Movie
|
||||
.Profile.Value
|
||||
.Profile
|
||||
.Items.FindIndex(v => v.Quality == release.Quality.Quality) * 100;
|
||||
}
|
||||
|
||||
|
@ -1,19 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Marr.Data;
|
||||
using Nancy;
|
||||
using NzbDrone.Api;
|
||||
using NzbDrone.Common.Cache;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.MediaCover;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.MediaFiles.MovieImport;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.MetadataSource;
|
||||
using NzbDrone.Core.MetadataSource.RadarrAPI;
|
||||
using NzbDrone.Core.Movies.AlternativeTitles;
|
||||
using NzbDrone.Core.RootFolders;
|
||||
using NzbDrone.Core.Movies;
|
||||
using NzbDrone.Core.Movies.Events;
|
||||
using Radarr.Http;
|
||||
|
@ -1,20 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Marr.Data;
|
||||
using Nancy;
|
||||
using NzbDrone.Api;
|
||||
using NzbDrone.Common.Cache;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Common.Messaging;
|
||||
using NzbDrone.Core.MediaCover;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.MediaFiles.MovieImport;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.MetadataSource;
|
||||
using NzbDrone.Core.MetadataSource.RadarrAPI;
|
||||
using NzbDrone.Core.Movies.AlternativeTitles;
|
||||
using NzbDrone.Core.RootFolders;
|
||||
using NzbDrone.Core.Movies;
|
||||
using NzbDrone.Core.Movies.Events;
|
||||
using Radarr.Http;
|
||||
|
@ -1,12 +1,10 @@
|
||||
using System.Collections.Generic;
|
||||
using Nancy;
|
||||
using Radarr.Http.Extensions;
|
||||
using NzbDrone.Core.MediaCover;
|
||||
using NzbDrone.Core.MetadataSource;
|
||||
using NzbDrone.Core.Parser;
|
||||
using System.Linq;
|
||||
using System;
|
||||
using Marr.Data;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
|
@ -7,6 +7,8 @@
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using Radarr.Host;
|
||||
using NzbDrone.Test.Common;
|
||||
using NzbDrone.Core.CustomFormats;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace NzbDrone.Common.Test
|
||||
{
|
||||
@ -20,6 +22,11 @@ public void event_handlers_should_be_unique()
|
||||
container.Register<IMainDatabase>(new MainDatabase(null));
|
||||
container.Resolve<IAppFolderFactory>().Register();
|
||||
|
||||
// A dummy custom format repository since this isn't a DB test
|
||||
var mockCustomFormat = Mocker.GetMock<ICustomFormatRepository>();
|
||||
mockCustomFormat.Setup(x => x.All()).Returns(new List<CustomFormatDefinition>());
|
||||
container.Register<ICustomFormatRepository>(mockCustomFormat.Object);
|
||||
|
||||
Mocker.SetConstant(container);
|
||||
|
||||
var handlers = Subject.BuildAll<IHandle<ApplicationStartedEvent>>()
|
||||
@ -28,4 +35,4 @@ public void event_handlers_should_be_unique()
|
||||
handlers.Should().OnlyHaveUniqueItems();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -133,10 +133,6 @@ private static IEnumerable<T> InternalDropLast<T>(IEnumerable<T> source, int n)
|
||||
yield return buffer.Dequeue();
|
||||
}
|
||||
}
|
||||
public static bool In<T>(this T source, List<T> list)
|
||||
{
|
||||
return list.Contains(source);
|
||||
}
|
||||
|
||||
public static string ConcatToString<TSource>(this IEnumerable<TSource> source, string separator = ", ")
|
||||
{
|
||||
|
@ -5,71 +5,76 @@
|
||||
using NzbDrone.Core.Organizer;
|
||||
using NzbDrone.Core.Movies;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.Movies.Events;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace NzbDrone.Core.Test.BulkImport
|
||||
{
|
||||
[TestFixture]
|
||||
public class AddMultiMoviesFixture : CoreTest<MovieService>
|
||||
{
|
||||
private List<Movie> fakeMovies;
|
||||
[TestFixture]
|
||||
public class AddMultiMoviesFixture : CoreTest<MovieService>
|
||||
{
|
||||
private List<Movie> fakeMovies;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
fakeMovies = Builder<Movie>.CreateListOfSize(3).BuildList();
|
||||
fakeMovies.ForEach(m =>
|
||||
{
|
||||
m.Path = null;
|
||||
m.RootFolderPath = @"C:\Test\TV";
|
||||
});
|
||||
}
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
fakeMovies = Builder<Movie>.CreateListOfSize(3).BuildList();
|
||||
fakeMovies.ForEach(m =>
|
||||
{
|
||||
m.Path = null;
|
||||
m.RootFolderPath = @"C:\Test\TV";
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void movies_added_event_should_have_proper_path()
|
||||
{
|
||||
Mocker.GetMock<IBuildFileNames>()
|
||||
.Setup(s => s.GetMovieFolder(It.IsAny<Movie>(), null))
|
||||
.Returns((Movie m, NamingConfig n) => m.Title);
|
||||
[Test]
|
||||
public void movies_added_event_should_have_proper_path()
|
||||
{
|
||||
Mocker.GetMock<IBuildFileNames>()
|
||||
.Setup(s => s.GetMovieFolder(It.IsAny<Movie>(), null))
|
||||
.Returns((Movie m, NamingConfig n) => m.Title);
|
||||
|
||||
var movies = Subject.AddMovies(fakeMovies);
|
||||
Mocker.GetMock<IMovieRepository>().Setup(s => s.FindByTmdbId(It.IsAny<List<int>>()))
|
||||
.Returns(new List<Movie>());
|
||||
|
||||
foreach (Movie movie in movies)
|
||||
{
|
||||
movie.Path.Should().NotBeNullOrEmpty();
|
||||
}
|
||||
var movies = Subject.AddMovies(fakeMovies);
|
||||
|
||||
//Subject.GetAllMovies().Should().HaveCount(3);
|
||||
}
|
||||
foreach (Movie movie in movies)
|
||||
{
|
||||
movie.Path.Should().NotBeNullOrEmpty();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void movies_added_should_ignore_already_added()
|
||||
{
|
||||
Mocker.GetMock<IBuildFileNames>()
|
||||
.Setup(s => s.GetMovieFolder(It.IsAny<Movie>(), null))
|
||||
.Returns((Movie m, NamingConfig n) => m.Title);
|
||||
// Subject.GetAllMovies().Should().HaveCount(3);
|
||||
}
|
||||
|
||||
Mocker.GetMock<IMovieRepository>().Setup(s => s.All()).Returns(new List<Movie> { fakeMovies[0] });
|
||||
[Test]
|
||||
public void movies_added_should_ignore_already_added()
|
||||
{
|
||||
Mocker.GetMock<IBuildFileNames>()
|
||||
.Setup(s => s.GetMovieFolder(It.IsAny<Movie>(), null))
|
||||
.Returns((Movie m, NamingConfig n) => m.Title);
|
||||
|
||||
var movies = Subject.AddMovies(fakeMovies);
|
||||
Mocker.GetMock<IMovieRepository>().Setup(s => s.FindByTmdbId(It.IsAny<List<int>>()))
|
||||
.Returns(new List<Movie> { fakeMovies[0] });
|
||||
|
||||
Mocker.GetMock<IMovieRepository>().Verify(v => v.InsertMany(It.Is<List<Movie>>(l => l.Count == 2)));
|
||||
}
|
||||
var movies = Subject.AddMovies(fakeMovies);
|
||||
|
||||
[Test]
|
||||
public void movies_added_should_ignore_duplicates()
|
||||
{
|
||||
Mocker.GetMock<IBuildFileNames>()
|
||||
.Setup(s => s.GetMovieFolder(It.IsAny<Movie>(), null))
|
||||
.Returns((Movie m, NamingConfig n) => m.Title);
|
||||
Mocker.GetMock<IMovieRepository>().Verify(v => v.InsertMany(It.Is<List<Movie>>(l => l.Count == 2)));
|
||||
}
|
||||
|
||||
fakeMovies[2].TmdbId = fakeMovies[0].TmdbId;
|
||||
[Test]
|
||||
public void movies_added_should_ignore_duplicates()
|
||||
{
|
||||
Mocker.GetMock<IBuildFileNames>()
|
||||
.Setup(s => s.GetMovieFolder(It.IsAny<Movie>(), null))
|
||||
.Returns((Movie m, NamingConfig n) => m.Title);
|
||||
|
||||
var movies = Subject.AddMovies(fakeMovies);
|
||||
Mocker.GetMock<IMovieRepository>().Setup(s => s.FindByTmdbId(It.IsAny<List<int>>()))
|
||||
.Returns(new List<Movie>());
|
||||
|
||||
Mocker.GetMock<IMovieRepository>().Verify(v => v.InsertMany(It.Is<List<Movie>>(l => l.Count == 2)));
|
||||
}
|
||||
fakeMovies[2].TmdbId = fakeMovies[0].TmdbId;
|
||||
|
||||
}
|
||||
}
|
||||
var movies = Subject.AddMovies(fakeMovies);
|
||||
|
||||
Mocker.GetMock<IMovieRepository>().Verify(v => v.InsertMany(It.Is<List<Movie>>(l => l.Count == 2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using FizzWare.NBuilder;
|
||||
using FluentAssertions;
|
||||
@ -15,7 +16,7 @@ public class
|
||||
BasicRepositoryFixture : DbTest<BasicRepository<ScheduledTask>, ScheduledTask>
|
||||
{
|
||||
private ScheduledTask _basicType;
|
||||
|
||||
private List<ScheduledTask> _basicList;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
@ -25,15 +26,28 @@ public void Setup()
|
||||
.With(c => c.Id = 0)
|
||||
.With(c => c.LastExecution = DateTime.UtcNow)
|
||||
.Build();
|
||||
|
||||
_basicList = Builder<ScheduledTask>
|
||||
.CreateListOfSize(5)
|
||||
.All()
|
||||
.With(x => x.Id = 0)
|
||||
.BuildList();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_be_able_to_add()
|
||||
public void should_be_able_to_insert()
|
||||
{
|
||||
Subject.Insert(_basicType);
|
||||
Subject.All().Should().HaveCount(1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_be_able_to_insert_many()
|
||||
{
|
||||
Subject.InsertMany(_basicList);
|
||||
Subject.All().Should().HaveCount(5);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void purge_should_delete_all()
|
||||
{
|
||||
@ -47,7 +61,6 @@ public void purge_should_delete_all()
|
||||
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void should_be_able_to_delete_model()
|
||||
{
|
||||
@ -58,6 +71,16 @@ public void should_be_able_to_delete_model()
|
||||
Subject.All().Should().BeEmpty();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_be_able_to_delete_many()
|
||||
{
|
||||
Subject.InsertMany(_basicList);
|
||||
Subject.All().Should().HaveCount(5);
|
||||
|
||||
Subject.DeleteMany(_basicList.Take(2).ToList());
|
||||
Subject.All().Should().HaveCount(3);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_be_able_to_find_by_id()
|
||||
{
|
||||
@ -67,6 +90,64 @@ public void should_be_able_to_find_by_id()
|
||||
storeObject.Should().BeEquivalentTo(_basicType, o=>o.IncludingAllRuntimeProperties());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_be_able_to_find_by_multiple_id()
|
||||
{
|
||||
Subject.InsertMany(_basicList);
|
||||
var storeObject = Subject.Get(_basicList.Take(2).Select(x => x.Id));
|
||||
storeObject.Should().HaveCount(2);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_be_able_to_update()
|
||||
{
|
||||
Subject.Insert(_basicType);
|
||||
_basicType.Interval = 999;
|
||||
|
||||
Subject.Update(_basicType);
|
||||
|
||||
Subject.All().First().Interval.Should().Be(999);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_be_able_to_update_many()
|
||||
{
|
||||
Subject.InsertMany(_basicList);
|
||||
_basicList.ForEach(x => x.Interval = 999);
|
||||
|
||||
Subject.UpdateMany(_basicList);
|
||||
|
||||
Subject.All().All(x => x.Interval == 999);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_be_able_to_update_single_field()
|
||||
{
|
||||
Subject.Insert(_basicType);
|
||||
_basicType.Interval = 999;
|
||||
_basicType.LastExecution = DateTime.UtcNow;
|
||||
|
||||
Subject.SetFields(_basicType, x => x.Interval);
|
||||
|
||||
var dbValue = Subject.Single();
|
||||
dbValue.Interval.Should().Be(999);
|
||||
dbValue.LastExecution.Should().NotBe(_basicType.LastExecution);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_be_able_to_update_many_single_field()
|
||||
{
|
||||
Subject.InsertMany(_basicList);
|
||||
_basicList.ForEach(x => x.Interval = 999);
|
||||
_basicList.ForEach(x => x.LastExecution = DateTime.UtcNow);
|
||||
|
||||
Subject.SetFields(_basicList, x => x.Interval);
|
||||
|
||||
var dbValue = Subject.All().First();
|
||||
dbValue.Interval.Should().Be(999);
|
||||
dbValue.LastExecution.Should().NotBe(_basicType.LastExecution);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_be_able_to_get_single()
|
||||
{
|
||||
@ -86,7 +167,6 @@ public void getting_model_with_invalid_id_should_throw()
|
||||
Assert.Throws<ModelNotFoundException>(() => Subject.Get(12));
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void get_all_with_empty_db_should_return_empty_list()
|
||||
{
|
||||
@ -98,7 +178,6 @@ public void get_all_with_empty_db_should_return_empty_list()
|
||||
public void should_be_able_to_call_ToList_on_empty_quariable()
|
||||
{
|
||||
Subject.All().ToList().Should().BeEmpty();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,59 +0,0 @@
|
||||
using System;
|
||||
using FluentAssertions;
|
||||
using Marr.Data.Converters;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
|
||||
namespace NzbDrone.Core.Test.Datastore.Converters
|
||||
{
|
||||
[TestFixture]
|
||||
public class BooleanIntConverterFixture : CoreTest<Core.Datastore.Converters.BooleanIntConverter>
|
||||
{
|
||||
[TestCase(true, 1)]
|
||||
[TestCase(false, 0)]
|
||||
public void should_return_int_when_saving_boolean_to_db(bool input, int expected)
|
||||
{
|
||||
Subject.ToDB(input).Should().Be(expected);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_db_null_for_null_value_when_saving_to_db()
|
||||
{
|
||||
Subject.ToDB(null).Should().Be(DBNull.Value);
|
||||
}
|
||||
|
||||
[TestCase(1, true)]
|
||||
[TestCase(0, false)]
|
||||
public void should_return_bool_when_getting_int_from_db(int input, bool expected)
|
||||
{
|
||||
var context = new ConverterContext
|
||||
{
|
||||
DbValue = (long)input
|
||||
};
|
||||
|
||||
Subject.FromDB(context).Should().Be(expected);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_db_null_for_null_value_when_getting_from_db()
|
||||
{
|
||||
var context = new ConverterContext
|
||||
{
|
||||
DbValue = DBNull.Value
|
||||
};
|
||||
|
||||
Subject.FromDB(context).Should().Be(DBNull.Value);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_throw_for_non_boolean_equivalent_number_value_when_getting_from_db()
|
||||
{
|
||||
var context = new ConverterContext
|
||||
{
|
||||
DbValue = (long)2
|
||||
};
|
||||
|
||||
Assert.Throws<ConversionException>(() => Subject.FromDB(context));
|
||||
}
|
||||
}
|
||||
}
|
@ -1,64 +1,51 @@
|
||||
using System;
|
||||
using System.Data;
|
||||
using FluentAssertions;
|
||||
using Marr.Data.Converters;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Common.Serializer;
|
||||
using NzbDrone.Core.Datastore.Converters;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.Movies.Commands;
|
||||
using NUnit.Framework;
|
||||
using FluentAssertions;
|
||||
using System.Data.SQLite;
|
||||
|
||||
namespace NzbDrone.Core.Test.Datastore.Converters
|
||||
{
|
||||
[TestFixture]
|
||||
public class CommandConverterFixture : CoreTest<CommandConverter>
|
||||
{
|
||||
SQLiteParameter param;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
param = new SQLiteParameter();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_json_string_when_saving_boolean_to_db()
|
||||
{
|
||||
var command = new RefreshMovieCommand();
|
||||
|
||||
Subject.ToDB(command).Should().BeOfType<string>();
|
||||
Subject.SetValue(param, command);
|
||||
param.Value.Should().BeOfType<string>();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_null_for_null_value_when_saving_to_db()
|
||||
{
|
||||
Subject.ToDB(null).Should().Be(null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_db_null_for_db_null_value_when_saving_to_db()
|
||||
{
|
||||
Subject.ToDB(DBNull.Value).Should().Be(DBNull.Value);
|
||||
Subject.SetValue(param, null);
|
||||
param.Value.Should().BeNull();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_command_when_getting_json_from_db()
|
||||
{
|
||||
var dataRecordMock = new Mock<IDataRecord>();
|
||||
dataRecordMock.Setup(s => s.GetOrdinal("Name")).Returns(0);
|
||||
dataRecordMock.Setup(s => s.GetString(0)).Returns("RefreshMovie");
|
||||
var data = "{\"name\": \"RefreshMovie\"}";
|
||||
|
||||
var context = new ConverterContext
|
||||
{
|
||||
DataRecord = dataRecordMock.Object,
|
||||
DbValue = new RefreshMovieCommand().ToJson()
|
||||
};
|
||||
|
||||
Subject.FromDB(context).Should().BeOfType<RefreshMovieCommand>();
|
||||
Subject.Parse(data).Should().BeOfType<RefreshMovieCommand>();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_null_for_null_value_when_getting_from_db()
|
||||
{
|
||||
var context = new ConverterContext
|
||||
{
|
||||
DbValue = DBNull.Value
|
||||
};
|
||||
|
||||
Subject.FromDB(context).Should().Be(null);
|
||||
Subject.Parse(null).Should().BeNull();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,41 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SQLite;
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Datastore.Converters;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
|
||||
namespace NzbDrone.Core.Test.Datastore.Converters
|
||||
{
|
||||
[TestFixture]
|
||||
public class DictionaryConverterFixture : CoreTest<EmbeddedDocumentConverter<Dictionary<string, string>>>
|
||||
{
|
||||
SQLiteParameter param;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
param = new SQLiteParameter();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_serialize_in_camel_case()
|
||||
{
|
||||
var dict = new Dictionary<string, string>
|
||||
{
|
||||
{ "Data", "Should be lowercased" },
|
||||
{ "CamelCase", "Should be cameled" }
|
||||
};
|
||||
|
||||
Subject.SetValue(param, dict);
|
||||
|
||||
var result = (string)param.Value;
|
||||
|
||||
result.Should().Contain("data");
|
||||
result.Should().NotContain("Data");
|
||||
|
||||
result.Should().Contain("camelCase");
|
||||
result.Should().NotContain("CamelCase");
|
||||
}
|
||||
}
|
||||
}
|
@ -1,70 +0,0 @@
|
||||
using System;
|
||||
using FluentAssertions;
|
||||
using Marr.Data.Converters;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Datastore.Converters;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
|
||||
namespace NzbDrone.Core.Test.Datastore.Converters
|
||||
{
|
||||
[TestFixture]
|
||||
public class DoubleConverterFixture : CoreTest<DoubleConverter>
|
||||
{
|
||||
[Test]
|
||||
public void should_return_double_when_saving_double_to_db()
|
||||
{
|
||||
var input = 10.5D;
|
||||
|
||||
Subject.ToDB(input).Should().Be(input);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_null_for_null_value_when_saving_to_db()
|
||||
{
|
||||
Subject.ToDB(null).Should().Be(null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_db_null_for_db_null_value_when_saving_to_db()
|
||||
{
|
||||
Subject.ToDB(DBNull.Value).Should().Be(DBNull.Value);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_double_when_getting_double_from_db()
|
||||
{
|
||||
var expected = 10.5D;
|
||||
|
||||
var context = new ConverterContext
|
||||
{
|
||||
DbValue = expected
|
||||
};
|
||||
|
||||
Subject.FromDB(context).Should().Be(expected);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_double_when_getting_string_from_db()
|
||||
{
|
||||
var expected = 10.5D;
|
||||
|
||||
var context = new ConverterContext
|
||||
{
|
||||
DbValue = $"{expected}"
|
||||
};
|
||||
|
||||
Subject.FromDB(context).Should().Be(expected);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_null_for_null_value_when_getting_from_db()
|
||||
{
|
||||
var context = new ConverterContext
|
||||
{
|
||||
DbValue = DBNull.Value
|
||||
};
|
||||
|
||||
Subject.FromDB(context).Should().Be(DBNull.Value);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,58 +0,0 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using FluentAssertions;
|
||||
using Marr.Data.Converters;
|
||||
using Marr.Data.Mapping;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.Movies;
|
||||
using NzbDrone.Core.Download.Pending;
|
||||
|
||||
namespace NzbDrone.Core.Test.Datastore.Converters
|
||||
{
|
||||
[TestFixture]
|
||||
public class EnumIntConverterFixture : CoreTest<Core.Datastore.Converters.EnumIntConverter>
|
||||
{
|
||||
[Test]
|
||||
public void should_return_int_when_saving_enum_to_db()
|
||||
{
|
||||
Subject.ToDB(PendingReleaseReason.Delay).Should().Be((int)PendingReleaseReason.Delay);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_db_null_for_null_value_when_saving_to_db()
|
||||
{
|
||||
Subject.ToDB(null).Should().Be(DBNull.Value);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_enum_when_getting_int_from_db()
|
||||
{
|
||||
var mockMemberInfo = new Mock<MemberInfo>();
|
||||
mockMemberInfo.SetupGet(s => s.DeclaringType).Returns(typeof(PendingRelease));
|
||||
mockMemberInfo.SetupGet(s => s.Name).Returns("Reason");
|
||||
|
||||
var expected = PendingReleaseReason.Delay;
|
||||
|
||||
var context = new ConverterContext
|
||||
{
|
||||
ColumnMap = new ColumnMap(mockMemberInfo.Object) { FieldType = typeof(PendingReleaseReason) },
|
||||
DbValue = (long)expected
|
||||
};
|
||||
|
||||
Subject.FromDB(context).Should().Be(expected);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_null_for_null_value_when_getting_from_db()
|
||||
{
|
||||
var context = new ConverterContext
|
||||
{
|
||||
DbValue = DBNull.Value
|
||||
};
|
||||
|
||||
Subject.FromDB(context).Should().Be(null);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
using System;
|
||||
using System.Data.SQLite;
|
||||
using FluentAssertions;
|
||||
using Marr.Data.Converters;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Datastore.Converters;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
@ -10,18 +10,21 @@ namespace NzbDrone.Core.Test.Datastore.Converters
|
||||
[TestFixture]
|
||||
public class GuidConverterFixture : CoreTest<GuidConverter>
|
||||
{
|
||||
SQLiteParameter param;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
param = new SQLiteParameter();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_string_when_saving_guid_to_db()
|
||||
{
|
||||
var guid = Guid.NewGuid();
|
||||
|
||||
Subject.ToDB(guid).Should().Be(guid.ToString());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_db_null_for_null_value_when_saving_to_db()
|
||||
{
|
||||
Subject.ToDB(null).Should().Be(DBNull.Value);
|
||||
Subject.SetValue(param, guid);
|
||||
param.Value.Should().Be(guid.ToString());
|
||||
}
|
||||
|
||||
[Test]
|
||||
@ -29,23 +32,13 @@ public void should_return_guid_when_getting_string_from_db()
|
||||
{
|
||||
var guid = Guid.NewGuid();
|
||||
|
||||
var context = new ConverterContext
|
||||
{
|
||||
DbValue = guid.ToString()
|
||||
};
|
||||
|
||||
Subject.FromDB(context).Should().Be(guid);
|
||||
Subject.Parse(guid.ToString()).Should().Be(guid);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_empty_guid_for_db_null_value_when_getting_from_db()
|
||||
{
|
||||
var context = new ConverterContext
|
||||
{
|
||||
DbValue = DBNull.Value
|
||||
};
|
||||
|
||||
Subject.FromDB(context).Should().Be(Guid.Empty);
|
||||
Subject.Parse(null).Should().Be(Guid.Empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,58 +0,0 @@
|
||||
using System;
|
||||
using FluentAssertions;
|
||||
using Marr.Data.Converters;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Datastore.Converters;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
|
||||
namespace NzbDrone.Core.Test.Datastore.Converters
|
||||
{
|
||||
[TestFixture]
|
||||
public class Int32ConverterFixture : CoreTest<Int32Converter>
|
||||
{
|
||||
[Test]
|
||||
public void should_return_int_when_saving_int_to_db()
|
||||
{
|
||||
var i = 5;
|
||||
|
||||
Subject.ToDB(i).Should().Be(i);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_int_when_getting_int_from_db()
|
||||
{
|
||||
var i = 5;
|
||||
|
||||
var context = new ConverterContext
|
||||
{
|
||||
DbValue = i
|
||||
};
|
||||
|
||||
Subject.FromDB(context).Should().Be(i);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_int_when_getting_string_from_db()
|
||||
{
|
||||
var i = 5;
|
||||
|
||||
var context = new ConverterContext
|
||||
{
|
||||
DbValue = i.ToString()
|
||||
};
|
||||
|
||||
Subject.FromDB(context).Should().Be(i);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_db_null_for_db_null_value_when_getting_from_db()
|
||||
{
|
||||
var context = new ConverterContext
|
||||
{
|
||||
DbValue = DBNull.Value
|
||||
};
|
||||
|
||||
Subject.FromDB(context).Should().Be(DBNull.Value);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.Data.SQLite;
|
||||
using FluentAssertions;
|
||||
using Marr.Data.Converters;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Common.Disk;
|
||||
using NzbDrone.Core.Datastore.Converters;
|
||||
@ -12,13 +11,22 @@ namespace NzbDrone.Core.Test.Datastore.Converters
|
||||
[TestFixture]
|
||||
public class OsPathConverterFixture : CoreTest<OsPathConverter>
|
||||
{
|
||||
SQLiteParameter param;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
param = new SQLiteParameter();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_string_when_saving_os_path_to_db()
|
||||
{
|
||||
var path = @"C:\Test\TV".AsOsAgnostic();
|
||||
var osPath = new OsPath(path);
|
||||
|
||||
Subject.ToDB(osPath).Should().Be(path);
|
||||
Subject.SetValue(param, osPath);
|
||||
param.Value.Should().Be(path);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@ -27,23 +35,13 @@ public void should_return_os_path_when_getting_string_from_db()
|
||||
var path = @"C:\Test\TV".AsOsAgnostic();
|
||||
var osPath = new OsPath(path);
|
||||
|
||||
var context = new ConverterContext
|
||||
{
|
||||
DbValue = path
|
||||
};
|
||||
|
||||
Subject.FromDB(context).Should().Be(osPath);
|
||||
Subject.Parse(path).Should().Be(osPath);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_db_null_for_db_null_value_when_getting_from_db()
|
||||
public void should_return_empty_for_null_value_when_getting_from_db()
|
||||
{
|
||||
var context = new ConverterContext
|
||||
{
|
||||
DbValue = DBNull.Value
|
||||
};
|
||||
|
||||
Subject.FromDB(context).Should().Be(DBNull.Value);
|
||||
Subject.Parse(null).IsEmpty.Should().BeTrue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.Data.SQLite;
|
||||
using FluentAssertions;
|
||||
using Marr.Data.Converters;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Datastore.Converters;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
@ -8,32 +7,29 @@
|
||||
|
||||
namespace NzbDrone.Core.Test.Datastore.Converters
|
||||
{
|
||||
[Ignore("To reinstate once dapper changes worked out")]
|
||||
[TestFixture]
|
||||
public class ProviderSettingConverterFixture : CoreTest<ProviderSettingConverter>
|
||||
{
|
||||
SQLiteParameter param;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
param = new SQLiteParameter();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_null_config_if_config_is_null()
|
||||
{
|
||||
var result = Subject.FromDB(new ConverterContext()
|
||||
{
|
||||
DbValue = DBNull.Value
|
||||
});
|
||||
|
||||
|
||||
result.Should().Be(NullConfig.Instance);
|
||||
Subject.Parse(null).Should().Be(NullConfig.Instance);
|
||||
}
|
||||
|
||||
[TestCase(null)]
|
||||
[TestCase("")]
|
||||
public void should_return_null_config_if_config_is_empty(object dbValue)
|
||||
{
|
||||
var result = Subject.FromDB(new ConverterContext()
|
||||
{
|
||||
DbValue = dbValue
|
||||
});
|
||||
|
||||
|
||||
result.Should().Be(NullConfig.Instance);
|
||||
Subject.Parse(dbValue).Should().Be(NullConfig.Instance);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.Data.SQLite;
|
||||
using FluentAssertions;
|
||||
using Marr.Data.Converters;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Datastore.Converters;
|
||||
using NzbDrone.Core.Qualities;
|
||||
@ -9,26 +8,30 @@
|
||||
namespace NzbDrone.Core.Test.Datastore.Converters
|
||||
{
|
||||
[TestFixture]
|
||||
public class QualityIntConverterFixture : CoreTest<QualityIntConverter>
|
||||
public class QualityIntConverterFixture : CoreTest<DapperQualityIntConverter>
|
||||
{
|
||||
SQLiteParameter param;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
param = new SQLiteParameter();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_int_when_saving_quality_to_db()
|
||||
{
|
||||
var quality = Quality.Bluray1080p;
|
||||
|
||||
Subject.ToDB(quality).Should().Be(quality.Id);
|
||||
Subject.SetValue(param, quality);
|
||||
param.Value.Should().Be(quality.Id);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_0_when_saving_db_null_to_db()
|
||||
{
|
||||
Subject.ToDB(DBNull.Value).Should().Be(0);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_throw_when_saving_another_object_to_db()
|
||||
{
|
||||
Assert.Throws<InvalidOperationException>(() => Subject.ToDB("Not a quality"));
|
||||
Subject.SetValue(param, null);
|
||||
param.Value.Should().Be(0);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@ -36,23 +39,13 @@ public void should_return_quality_when_getting_string_from_db()
|
||||
{
|
||||
var quality = Quality.Bluray1080p;
|
||||
|
||||
var context = new ConverterContext
|
||||
{
|
||||
DbValue = quality.Id
|
||||
};
|
||||
|
||||
Subject.FromDB(context).Should().Be(quality);
|
||||
Subject.Parse(quality.Id).Should().Be(quality);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_db_null_for_db_null_value_when_getting_from_db()
|
||||
public void should_return_unknown_for_null_value_when_getting_from_db()
|
||||
{
|
||||
var context = new ConverterContext
|
||||
{
|
||||
DbValue = DBNull.Value
|
||||
};
|
||||
|
||||
Subject.FromDB(context).Should().Be(Quality.Unknown);
|
||||
Subject.Parse(null).Should().Be(Quality.Unknown);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,65 +0,0 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using FluentAssertions;
|
||||
using Marr.Data.Converters;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Datastore.Converters;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
|
||||
namespace NzbDrone.Core.Test.Datastore.Converters
|
||||
{
|
||||
[TestFixture]
|
||||
public class TimeSpanConverterFixture : CoreTest<TimeSpanConverter>
|
||||
{
|
||||
[Test]
|
||||
public void should_return_string_when_saving_timespan_to_db()
|
||||
{
|
||||
var timeSpan = TimeSpan.FromMinutes(5);
|
||||
|
||||
Subject.ToDB(timeSpan).Should().Be(timeSpan.ToString("c", CultureInfo.InvariantCulture));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_null_when_saving_empty_string_to_db()
|
||||
{
|
||||
Subject.ToDB("").Should().Be(null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_time_span_when_getting_time_span_from_db()
|
||||
{
|
||||
var timeSpan = TimeSpan.FromMinutes(5);
|
||||
|
||||
var context = new ConverterContext
|
||||
{
|
||||
DbValue = timeSpan
|
||||
};
|
||||
|
||||
Subject.FromDB(context).Should().Be(timeSpan);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_time_span_when_getting_string_from_db()
|
||||
{
|
||||
var timeSpan = TimeSpan.FromMinutes(5);
|
||||
|
||||
var context = new ConverterContext
|
||||
{
|
||||
DbValue = timeSpan.ToString("c", CultureInfo.InvariantCulture)
|
||||
};
|
||||
|
||||
Subject.FromDB(context).Should().Be(timeSpan);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_time_span_zero_for_db_null_value_when_getting_from_db()
|
||||
{
|
||||
var context = new ConverterContext
|
||||
{
|
||||
DbValue = DBNull.Value
|
||||
};
|
||||
|
||||
Subject.FromDB(context).Should().Be(TimeSpan.Zero);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
using System;
|
||||
using System.Data.SQLite;
|
||||
using FluentAssertions;
|
||||
using Marr.Data.Converters;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Datastore.Converters;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
@ -8,20 +8,23 @@
|
||||
namespace NzbDrone.Core.Test.Datastore.Converters
|
||||
{
|
||||
[TestFixture]
|
||||
public class UtcConverterFixture : CoreTest<UtcConverter>
|
||||
public class UtcConverterFixture : CoreTest<DapperUtcConverter>
|
||||
{
|
||||
SQLiteParameter param;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
param = new SQLiteParameter();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_date_time_when_saving_date_time_to_db()
|
||||
{
|
||||
var dateTime = DateTime.Now;
|
||||
|
||||
Subject.ToDB(dateTime).Should().Be(dateTime.ToUniversalTime());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_db_null_when_saving_db_null_to_db()
|
||||
{
|
||||
Subject.ToDB(DBNull.Value).Should().Be(DBNull.Value);
|
||||
Subject.SetValue(param, dateTime);
|
||||
param.Value.Should().Be(dateTime.ToUniversalTime());
|
||||
}
|
||||
|
||||
[Test]
|
||||
@ -29,23 +32,7 @@ public void should_return_time_span_when_getting_time_span_from_db()
|
||||
{
|
||||
var dateTime = DateTime.Now.ToUniversalTime();
|
||||
|
||||
var context = new ConverterContext
|
||||
{
|
||||
DbValue = dateTime
|
||||
};
|
||||
|
||||
Subject.FromDB(context).Should().Be(dateTime);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_db_null_for_db_null_value_when_getting_from_db()
|
||||
{
|
||||
var context = new ConverterContext
|
||||
{
|
||||
DbValue = DBNull.Value
|
||||
};
|
||||
|
||||
Subject.FromDB(context).Should().Be(DBNull.Value);
|
||||
Subject.Parse(dateTime).Should().Be(dateTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,11 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Dapper;
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.Movies;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
|
||||
namespace NzbDrone.Core.Test.Datastore
|
||||
{
|
||||
@ -14,15 +15,15 @@ public class DatabaseFixture : DbTest
|
||||
public void SingleOrDefault_should_return_null_on_empty_db()
|
||||
{
|
||||
Mocker.Resolve<IDatabase>()
|
||||
.GetDataMapper().Query<Movie>()
|
||||
.SingleOrDefault(c => c.CleanTitle == "SomeTitle")
|
||||
.OpenConnection().Query<Movie>("SELECT * FROM Movies")
|
||||
.SingleOrDefault()
|
||||
.Should()
|
||||
.BeNull();
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void vaccume()
|
||||
public void vacuum()
|
||||
{
|
||||
Mocker.Resolve<IDatabase>().Vacuum();
|
||||
}
|
||||
|
@ -2,10 +2,8 @@
|
||||
using FizzWare.NBuilder;
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.Movies;
|
||||
using System.Collections.Generic;
|
||||
using NzbDrone.Core.Languages;
|
||||
|
||||
@ -20,48 +18,6 @@ public void Setup()
|
||||
// This is kinda hacky here, since we are kinda testing if the QualityDef converter works as well.
|
||||
}
|
||||
|
||||
[Ignore("MovieFile isnt lazy loaded anymore so this will fail.")]
|
||||
[Test]
|
||||
//TODO: Update this!
|
||||
public void one_to_one()
|
||||
{
|
||||
var episodeFile = Builder<MovieFile>.CreateNew()
|
||||
.With(c => c.Quality = new QualityModel())
|
||||
.BuildNew();
|
||||
|
||||
Db.Insert(episodeFile);
|
||||
|
||||
var episode = Builder<Movie>.CreateNew()
|
||||
.With(c => c.MovieFileId = episodeFile.Id)
|
||||
.BuildNew();
|
||||
|
||||
Db.Insert(episode);
|
||||
|
||||
var loadedEpisode = Db.Single<Movie>();
|
||||
var loadedEpisodeFile = loadedEpisode.MovieFile;
|
||||
|
||||
loadedEpisodeFile.Should().NotBeNull();
|
||||
loadedEpisodeFile.Should().BeEquivalentTo(episodeFile,
|
||||
options => options
|
||||
.IncludingAllRuntimeProperties()
|
||||
.Excluding(c => c.DateAdded)
|
||||
.Excluding(c => c.Path)
|
||||
.Excluding(c => c.Movie));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void one_to_one_should_not_query_db_if_foreign_key_is_zero()
|
||||
{
|
||||
var episode = Builder<Movie>.CreateNew()
|
||||
.With(c => c.MovieFileId = 0)
|
||||
.BuildNew();
|
||||
|
||||
Db.Insert(episode);
|
||||
|
||||
Db.Single<Movie>().MovieFile.Should().BeNull();
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void embedded_document_as_json()
|
||||
{
|
||||
|
@ -1,55 +0,0 @@
|
||||
using FizzWare.NBuilder;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.Profiles;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.Movies;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
|
||||
namespace NzbDrone.Core.Test.Datastore
|
||||
{
|
||||
|
||||
[TestFixture]
|
||||
public class MarrDataLazyLoadingFixture : DbTest
|
||||
{
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
var profile = new Profile
|
||||
{
|
||||
Name = "Test",
|
||||
Cutoff = Quality.WEBDL720p.Id,
|
||||
Items = Qualities.QualityFixture.GetDefaultQualities()
|
||||
};
|
||||
|
||||
|
||||
profile = Db.Insert(profile);
|
||||
|
||||
var series = Builder<Movie>.CreateListOfSize(1)
|
||||
.All()
|
||||
.With(v => v.ProfileId = profile.Id)
|
||||
.BuildListOfNew();
|
||||
|
||||
Db.InsertMany(series);
|
||||
|
||||
var episodeFiles = Builder<MovieFile>.CreateListOfSize(1)
|
||||
.All()
|
||||
.With(v => v.MovieId = series[0].Id)
|
||||
.With(v => v.Quality = new QualityModel())
|
||||
.BuildListOfNew();
|
||||
|
||||
Db.InsertMany(episodeFiles);
|
||||
|
||||
var episodes = Builder<Movie>.CreateListOfSize(10)
|
||||
.All()
|
||||
.With(v => v.Monitored = true)
|
||||
.With(v => v.MovieFileId = episodeFiles[0].Id)
|
||||
.BuildListOfNew();
|
||||
|
||||
Db.InsertMany(episodes);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.Datastore.Extensions;
|
||||
using NzbDrone.Core.Movies;
|
||||
|
||||
namespace NzbDrone.Core.Test.Datastore.PagingSpecExtensionsTests
|
||||
{
|
||||
public class PagingOffsetFixture
|
||||
{
|
||||
[TestCase(1, 10, 0)]
|
||||
[TestCase(2, 10, 10)]
|
||||
[TestCase(3, 20, 40)]
|
||||
[TestCase(1, 100, 0)]
|
||||
public void should_calcuate_expected_offset(int page, int pageSize, int expected)
|
||||
{
|
||||
var pagingSpec = new PagingSpec<Movie>
|
||||
{
|
||||
Page = page,
|
||||
PageSize = pageSize,
|
||||
SortDirection = SortDirection.Ascending,
|
||||
SortKey = "AirDate"
|
||||
};
|
||||
|
||||
pagingSpec.PagingOffset().Should().Be(expected);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.Datastore.Extensions;
|
||||
using NzbDrone.Core.Movies;
|
||||
|
||||
namespace NzbDrone.Core.Test.Datastore.PagingSpecExtensionsTests
|
||||
{
|
||||
public class ToSortDirectionFixture
|
||||
{
|
||||
[Test]
|
||||
public void should_convert_default_to_asc()
|
||||
{
|
||||
var pagingSpec = new PagingSpec<Movie>
|
||||
{
|
||||
Page = 1,
|
||||
PageSize = 10,
|
||||
SortDirection = SortDirection.Default,
|
||||
SortKey = "AirDate"
|
||||
};
|
||||
|
||||
pagingSpec.ToSortDirection().Should().Be(Marr.Data.QGen.SortDirection.Asc);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_convert_ascending_to_asc()
|
||||
{
|
||||
var pagingSpec = new PagingSpec<Movie>
|
||||
{
|
||||
Page = 1,
|
||||
PageSize = 10,
|
||||
SortDirection = SortDirection.Ascending,
|
||||
SortKey = "AirDate"
|
||||
};
|
||||
|
||||
pagingSpec.ToSortDirection().Should().Be(Marr.Data.QGen.SortDirection.Asc);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_convert_descending_to_desc()
|
||||
{
|
||||
var pagingSpec = new PagingSpec<Movie>
|
||||
{
|
||||
Page = 1,
|
||||
PageSize = 10,
|
||||
SortDirection = SortDirection.Descending,
|
||||
SortKey = "AirDate"
|
||||
};
|
||||
|
||||
pagingSpec.ToSortDirection().Should().Be(Marr.Data.QGen.SortDirection.Desc);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace NzbDrone.Core.Test.Datastore.ReflectionStrategyFixture
|
||||
{
|
||||
[TestFixture]
|
||||
public class Benchmarks
|
||||
{
|
||||
/* private const int iterations = 5000000;
|
||||
private object _target;
|
||||
private IReflectionStrategy _simpleReflectionStrategy;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
// _simpleReflectionStrategy = new DelegateReflectionStrategy();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void clr_reflection_test()
|
||||
{
|
||||
_target = new Series();
|
||||
|
||||
var del = _simpleReflectionStrategy.BuildSetter(typeof(Series), "Title");
|
||||
|
||||
for (int i = 0; i < iterations; i++)
|
||||
{
|
||||
del(_target, "TestTile");
|
||||
//_simpleReflectionStrategy.SetFieldValue(_target, "Title", "TestTile");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void SetField()
|
||||
{
|
||||
|
||||
|
||||
}*/
|
||||
|
||||
}
|
||||
}
|
@ -1,16 +1,15 @@
|
||||
using System.Collections.Generic;
|
||||
using Dapper;
|
||||
using FluentAssertions;
|
||||
using Marr.Data;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.Datastore.Converters;
|
||||
using NzbDrone.Core.Datastore.Extensions;
|
||||
using NzbDrone.Core.Movies;
|
||||
|
||||
namespace NzbDrone.Core.Test.Datastore
|
||||
{
|
||||
[TestFixture]
|
||||
public class MappingExtensionFixture
|
||||
public class TableMapperFixture
|
||||
{
|
||||
|
||||
public class EmbeddedType : IEmbeddedDocument
|
||||
@ -39,19 +38,16 @@ public class TypeWithNoMappableProperties
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
MapRepository.Instance.RegisterTypeConverter(typeof(List<EmbeddedType>), new EmbeddedDocumentConverter());
|
||||
MapRepository.Instance.RegisterTypeConverter(typeof(EmbeddedType), new EmbeddedDocumentConverter());
|
||||
MapRepository.Instance.RegisterTypeConverter(typeof(int), new Int32Converter());
|
||||
|
||||
SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter<List<EmbeddedType>>());
|
||||
SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter<EmbeddedType>());
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void test_mappable_types()
|
||||
{
|
||||
var properties = typeof(TypeWithAllMappableProperties).GetProperties();
|
||||
properties.Should().NotBeEmpty();
|
||||
properties.Should().OnlyContain(c => MappingExtensions.IsMappableProperty(c));
|
||||
properties.Should().OnlyContain(c => ColumnMapper<int>.IsMappableProperty(c));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@ -59,7 +55,7 @@ public void test_un_mappable_types()
|
||||
{
|
||||
var properties = typeof(TypeWithNoMappableProperties).GetProperties();
|
||||
properties.Should().NotBeEmpty();
|
||||
properties.Should().NotContain(c => MappingExtensions.IsMappableProperty(c));
|
||||
properties.Should().NotContain(c => ColumnMapper<int>.IsMappableProperty(c));
|
||||
}
|
||||
}
|
||||
}
|
125
src/NzbDrone.Core.Test/Datastore/WhereBuilderFixture.cs
Normal file
125
src/NzbDrone.Core.Test/Datastore/WhereBuilderFixture.cs
Normal file
@ -0,0 +1,125 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.Movies;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
|
||||
namespace NzbDrone.Core.Test.Datastore
|
||||
{
|
||||
[TestFixture]
|
||||
public class WhereBuilderFixture : CoreTest
|
||||
{
|
||||
private WhereBuilder Subject;
|
||||
|
||||
[OneTimeSetUp]
|
||||
public void MapTables()
|
||||
{
|
||||
// Generate table mapping
|
||||
Mocker.Resolve<DbFactory>();
|
||||
}
|
||||
|
||||
private WhereBuilder Where(Expression<Func<Movie, bool>> filter)
|
||||
{
|
||||
return new WhereBuilder(filter);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void where_equal_const()
|
||||
{
|
||||
Subject = Where(x => x.Id == 10);
|
||||
|
||||
var name = Subject.Parameters.ParameterNames.First();
|
||||
Subject.ToString().Should().Be($"(\"Movies\".\"Id\" = @{name})");
|
||||
Subject.Parameters.Get<int>(name).Should().Be(10);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void where_equal_variable()
|
||||
{
|
||||
var id = 10;
|
||||
Subject = Where(x => x.Id == id);
|
||||
|
||||
var name = Subject.Parameters.ParameterNames.First();
|
||||
Subject.ToString().Should().Be($"(\"Movies\".\"Id\" = @{name})");
|
||||
Subject.Parameters.Get<int>(name).Should().Be(id);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void where_column_contains_string()
|
||||
{
|
||||
var test = "small";
|
||||
Subject = Where(x => x.CleanTitle.Contains(test));
|
||||
|
||||
var name = Subject.Parameters.ParameterNames.First();
|
||||
Subject.ToString().Should().Be($"(\"Movies\".\"CleanTitle\" LIKE '%' || @{name} || '%')");
|
||||
Subject.Parameters.Get<string>(name).Should().Be(test);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void where_string_contains_column()
|
||||
{
|
||||
var test = "small";
|
||||
Subject = Where(x => test.Contains(x.CleanTitle));
|
||||
|
||||
var name = Subject.Parameters.ParameterNames.First();
|
||||
Subject.ToString().Should().Be($"(@{name} LIKE '%' || \"Movies\".\"CleanTitle\" || '%')");
|
||||
Subject.Parameters.Get<string>(name).Should().Be(test);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void where_in_list()
|
||||
{
|
||||
var list = new List<int> {1, 2, 3};
|
||||
Subject = Where(x => list.Contains(x.Id));
|
||||
|
||||
var name = Subject.Parameters.ParameterNames.First();
|
||||
Subject.ToString().Should().Be($"(\"Movies\".\"Id\" IN @{name})");
|
||||
|
||||
var param = Subject.Parameters.Get<List<int>>(name);
|
||||
param.Should().BeEquivalentTo(list);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void where_in_list_2()
|
||||
{
|
||||
var list = new List<int> {1, 2, 3};
|
||||
Subject = Where(x => x.CleanTitle == "test" && list.Contains(x.Id));
|
||||
|
||||
var names = Subject.Parameters.ParameterNames.ToList();
|
||||
Subject.ToString().Should().Be($"((\"Movies\".\"CleanTitle\" = @{names[0]}) AND (\"Movies\".\"Id\" IN @{names[1]}))");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void enum_as_int()
|
||||
{
|
||||
Subject = Where(x => x.PathState == MoviePathState.Static);
|
||||
|
||||
var name = Subject.Parameters.ParameterNames.First();
|
||||
Subject.ToString().Should().Be($"(\"Movies\".\"PathState\" = @{name})");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void enum_in_list()
|
||||
{
|
||||
var allowed = new List<MoviePathState> { MoviePathState.Dynamic, MoviePathState.Static };
|
||||
Subject = Where(x => allowed.Contains(x.PathState));
|
||||
|
||||
var name = Subject.Parameters.ParameterNames.First();
|
||||
Subject.ToString().Should().Be($"(\"Movies\".\"PathState\" IN @{name})");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void enum_in_array()
|
||||
{
|
||||
var allowed = new MoviePathState[] { MoviePathState.Dynamic, MoviePathState.Static };
|
||||
Subject = Where(x => allowed.Contains(x.PathState));
|
||||
|
||||
var name = Subject.Parameters.ParameterNames.First();
|
||||
Subject.ToString().Should().Be($"(\"Movies\".\"PathState\" IN @{name})");
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using FizzWare.NBuilder;
|
||||
using FluentAssertions;
|
||||
using Marr.Data;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.DecisionEngine.Specifications;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
@ -33,7 +32,7 @@ public void Setup()
|
||||
|
||||
|
||||
var fakeSeries = Builder<Movie>.CreateNew()
|
||||
.With(c => c.Profile = (LazyLoaded<Profile>)new Profile { Cutoff = Quality.Bluray1080p.Id })
|
||||
.With(c => c.Profile = new Profile { Cutoff = Quality.Bluray1080p.Id })
|
||||
.Build();
|
||||
|
||||
remoteMovie = new RemoteMovie
|
||||
@ -49,7 +48,7 @@ public void Setup()
|
||||
public void should_allow_if_format_is_defined_in_profile()
|
||||
{
|
||||
remoteMovie.ParsedMovieInfo.Quality.CustomFormats = new List<CustomFormats.CustomFormat> {_format1};
|
||||
remoteMovie.Movie.Profile.Value.FormatItems = CustomFormatsFixture.GetSampleFormatItems(_format1.Name);
|
||||
remoteMovie.Movie.Profile.FormatItems = CustomFormatsFixture.GetSampleFormatItems(_format1.Name);
|
||||
|
||||
Subject.IsSatisfiedBy(remoteMovie, null).Accepted.Should().BeTrue();
|
||||
}
|
||||
@ -58,7 +57,7 @@ public void should_allow_if_format_is_defined_in_profile()
|
||||
public void should_deny_if_format_is_defined_in_profile()
|
||||
{
|
||||
remoteMovie.ParsedMovieInfo.Quality.CustomFormats = new List<CustomFormats.CustomFormat> {_format2};
|
||||
remoteMovie.Movie.Profile.Value.FormatItems = CustomFormatsFixture.GetSampleFormatItems(_format1.Name);
|
||||
remoteMovie.Movie.Profile.FormatItems = CustomFormatsFixture.GetSampleFormatItems(_format1.Name);
|
||||
|
||||
Subject.IsSatisfiedBy(remoteMovie, null).Accepted.Should().BeFalse();
|
||||
}
|
||||
@ -67,7 +66,7 @@ public void should_deny_if_format_is_defined_in_profile()
|
||||
public void should_deny_if_one_format_is_defined_in_profile()
|
||||
{
|
||||
remoteMovie.ParsedMovieInfo.Quality.CustomFormats = new List<CustomFormats.CustomFormat> {_format2, _format1};
|
||||
remoteMovie.Movie.Profile.Value.FormatItems = CustomFormatsFixture.GetSampleFormatItems(_format1.Name);
|
||||
remoteMovie.Movie.Profile.FormatItems = CustomFormatsFixture.GetSampleFormatItems(_format1.Name);
|
||||
|
||||
Subject.IsSatisfiedBy(remoteMovie, null).Accepted.Should().BeFalse();
|
||||
}
|
||||
@ -76,7 +75,7 @@ public void should_deny_if_one_format_is_defined_in_profile()
|
||||
public void should_allow_if_all_format_is_defined_in_profile()
|
||||
{
|
||||
remoteMovie.ParsedMovieInfo.Quality.CustomFormats = new List<CustomFormats.CustomFormat> {_format2, _format1};
|
||||
remoteMovie.Movie.Profile.Value.FormatItems = CustomFormatsFixture.GetSampleFormatItems(_format1.Name, _format2.Name);
|
||||
remoteMovie.Movie.Profile.FormatItems = CustomFormatsFixture.GetSampleFormatItems(_format1.Name, _format2.Name);
|
||||
|
||||
Subject.IsSatisfiedBy(remoteMovie, null).Accepted.Should().BeTrue();
|
||||
}
|
||||
@ -85,7 +84,7 @@ public void should_allow_if_all_format_is_defined_in_profile()
|
||||
public void should_deny_if_no_format_was_parsed_and_none_not_in_profile()
|
||||
{
|
||||
remoteMovie.ParsedMovieInfo.Quality.CustomFormats = new List<CustomFormats.CustomFormat> {};
|
||||
remoteMovie.Movie.Profile.Value.FormatItems = CustomFormatsFixture.GetSampleFormatItems(_format1.Name, _format2.Name);
|
||||
remoteMovie.Movie.Profile.FormatItems = CustomFormatsFixture.GetSampleFormatItems(_format1.Name, _format2.Name);
|
||||
|
||||
Subject.IsSatisfiedBy(remoteMovie, null).Accepted.Should().BeFalse();
|
||||
}
|
||||
@ -94,7 +93,7 @@ public void should_deny_if_no_format_was_parsed_and_none_not_in_profile()
|
||||
public void should_allow_if_no_format_was_parsed_and_none_in_profile()
|
||||
{
|
||||
remoteMovie.ParsedMovieInfo.Quality.CustomFormats = new List<CustomFormats.CustomFormat> {};
|
||||
remoteMovie.Movie.Profile.Value.FormatItems = CustomFormatsFixture.GetSampleFormatItems(CustomFormats.CustomFormat.None.Name, _format1.Name, _format2.Name);
|
||||
remoteMovie.Movie.Profile.FormatItems = CustomFormatsFixture.GetSampleFormatItems(CustomFormats.CustomFormat.None.Name, _format1.Name, _format2.Name);
|
||||
|
||||
Subject.IsSatisfiedBy(remoteMovie, null).Accepted.Should().BeTrue();
|
||||
}
|
||||
|
@ -1,9 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using FluentAssertions;
|
||||
using Marr.Data;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.DecisionEngine.Specifications;
|
||||
using NzbDrone.Core.Parser;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Profiles;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
@ -29,10 +27,10 @@ public void Setup()
|
||||
},
|
||||
Movie = new Movie
|
||||
{
|
||||
Profile = new LazyLoaded<Profile>(new Profile
|
||||
{
|
||||
Language = Language.English
|
||||
})
|
||||
Profile = new Profile
|
||||
{
|
||||
Language = Language.English
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -66,10 +64,10 @@ public void should_return_false_if_language_is_german()
|
||||
[Test]
|
||||
public void should_return_true_if_allowed_language_any()
|
||||
{
|
||||
_remoteMovie.Movie.Profile = new LazyLoaded<Profile>(new Profile
|
||||
_remoteMovie.Movie.Profile = new Profile
|
||||
{
|
||||
Language = Language.Any
|
||||
});
|
||||
};
|
||||
|
||||
WithGermanRelease();
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
using FizzWare.NBuilder;
|
||||
using FluentAssertions;
|
||||
using Marr.Data;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.DecisionEngine.Specifications;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
@ -35,7 +34,7 @@ public class QualityAllowedByProfileSpecificationFixture : CoreTest<QualityAllow
|
||||
public void Setup()
|
||||
{
|
||||
var fakeSeries = Builder<Movie>.CreateNew()
|
||||
.With(c => c.Profile = (LazyLoaded<Profile>)new Profile { Cutoff = Quality.Bluray1080p.Id })
|
||||
.With(c => c.Profile = new Profile { Cutoff = Quality.Bluray1080p.Id })
|
||||
.Build();
|
||||
|
||||
remoteMovie = new RemoteMovie
|
||||
@ -49,7 +48,7 @@ public void Setup()
|
||||
public void should_allow_if_quality_is_defined_in_profile(Quality qualityType)
|
||||
{
|
||||
remoteMovie.ParsedMovieInfo.Quality.Quality = qualityType;
|
||||
remoteMovie.Movie.Profile.Value.Items = Qualities.QualityFixture.GetDefaultQualities(Quality.DVD, Quality.HDTV720p, Quality.Bluray1080p);
|
||||
remoteMovie.Movie.Profile.Items = Qualities.QualityFixture.GetDefaultQualities(Quality.DVD, Quality.HDTV720p, Quality.Bluray1080p);
|
||||
|
||||
Subject.IsSatisfiedBy(remoteMovie, null).Accepted.Should().BeTrue();
|
||||
}
|
||||
@ -58,7 +57,7 @@ public void should_allow_if_quality_is_defined_in_profile(Quality qualityType)
|
||||
public void should_not_allow_if_quality_is_not_defined_in_profile(Quality qualityType)
|
||||
{
|
||||
remoteMovie.ParsedMovieInfo.Quality.Quality = qualityType;
|
||||
remoteMovie.Movie.Profile.Value.Items = Qualities.QualityFixture.GetDefaultQualities(Quality.DVD, Quality.HDTV720p, Quality.Bluray1080p);
|
||||
remoteMovie.Movie.Profile.Items = Qualities.QualityFixture.GetDefaultQualities(Quality.DVD, Quality.HDTV720p, Quality.Bluray1080p);
|
||||
|
||||
Subject.IsSatisfiedBy(remoteMovie, null).Accepted.Should().BeFalse();
|
||||
}
|
||||
|
@ -83,7 +83,7 @@ public void should_return_true_when_movie_doesnt_match()
|
||||
[Test]
|
||||
public void should_return_true_when_quality_in_queue_is_lower()
|
||||
{
|
||||
_movie.Profile.Value.Cutoff = Quality.Bluray1080p.Id;
|
||||
_movie.Profile.Cutoff = Quality.Bluray1080p.Id;
|
||||
|
||||
var remoteMovie = Builder<RemoteMovie>.CreateNew()
|
||||
.With(r => r.Movie = _movie)
|
||||
@ -115,7 +115,7 @@ public void should_return_false_when_qualities_are_the_same()
|
||||
[Test]
|
||||
public void should_return_false_when_quality_in_queue_is_better()
|
||||
{
|
||||
_movie.Profile.Value.Cutoff = Quality.Bluray1080p.Id;
|
||||
_movie.Profile.Cutoff = Quality.Bluray1080p.Id;
|
||||
|
||||
var remoteMovie = Builder<RemoteMovie>.CreateNew()
|
||||
.With(r => r.Movie = _movie)
|
||||
@ -132,7 +132,7 @@ public void should_return_false_when_quality_in_queue_is_better()
|
||||
[Test]
|
||||
public void should_return_false_if_quality_in_queue_meets_cutoff()
|
||||
{
|
||||
_movie.Profile.Value.Cutoff = _remoteMovie.ParsedMovieInfo.Quality.Quality.Id;
|
||||
_movie.Profile.Cutoff = _remoteMovie.ParsedMovieInfo.Quality.Quality.Id;
|
||||
|
||||
var remoteMovie = Builder<RemoteMovie>.CreateNew()
|
||||
.With(r => r.Movie = _movie)
|
||||
@ -151,8 +151,8 @@ public void should_return_false_if_quality_in_queue_meets_cutoff()
|
||||
[Test]
|
||||
public void should_return_false_when_quality_is_better_and_upgrade_allowed_is_false_for_quality_profile()
|
||||
{
|
||||
_movie.Profile.Value.Cutoff = Quality.Bluray1080p.Id;
|
||||
_movie.Profile.Value.UpgradeAllowed = false;
|
||||
_movie.Profile.Cutoff = Quality.Bluray1080p.Id;
|
||||
_movie.Profile.UpgradeAllowed = false;
|
||||
|
||||
var remoteMovie = Builder<RemoteMovie>.CreateNew()
|
||||
.With(r => r.Movie = _movie)
|
||||
|
@ -1,9 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using FizzWare.NBuilder;
|
||||
using FluentAssertions;
|
||||
using Marr.Data;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.DecisionEngine.Specifications;
|
||||
@ -78,7 +76,7 @@ private void GivenExistingFile(QualityModel quality)
|
||||
// Quality = quality
|
||||
// });
|
||||
|
||||
_remoteEpisode.Movie.MovieFile = new LazyLoaded<MovieFile>(new MovieFile { Quality = quality });
|
||||
_remoteEpisode.Movie.MovieFile = new MovieFile { Quality = quality };
|
||||
}
|
||||
|
||||
private void GivenUpgradeForExistingFile()
|
||||
|
@ -50,8 +50,8 @@ public void SetUp()
|
||||
private void GivenMovies(params Movie[] movies)
|
||||
{
|
||||
Mocker.GetMock<IMovieService>()
|
||||
.Setup(v => v.GetAllMovies())
|
||||
.Returns(movies.ToList());
|
||||
.Setup(v => v.AllMoviePaths())
|
||||
.Returns(movies.Select(x => x.Path).ToList());
|
||||
}
|
||||
|
||||
private void GivenExistingFolder(string folder)
|
||||
|
@ -1,13 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using FizzWare.NBuilder;
|
||||
using Marr.Data;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.Download.Pending;
|
||||
using NzbDrone.Core.Parser;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Profiles;
|
||||
using NzbDrone.Core.Qualities;
|
||||
@ -46,7 +44,7 @@ public void Setup()
|
||||
},
|
||||
};
|
||||
|
||||
_movie.Profile = new LazyLoaded<Profile>(_profile);
|
||||
_movie.Profile = _profile;
|
||||
|
||||
_release = Builder<ReleaseInfo>.CreateNew().Build();
|
||||
|
||||
|
@ -1,19 +1,17 @@
|
||||
using System.Collections.Generic;
|
||||
using FizzWare.NBuilder;
|
||||
using Marr.Data;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.Download.Pending;
|
||||
using NzbDrone.Core.Parser;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Profiles;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.Movies;
|
||||
using System.Linq;
|
||||
using FizzWare.NBuilder;
|
||||
using Moq;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace NzbDrone.Core.Test.Download.Pending.PendingReleaseServiceTests
|
||||
{
|
||||
@ -46,7 +44,7 @@ public void Setup()
|
||||
},
|
||||
};
|
||||
|
||||
_movie.Profile = new LazyLoaded<Profile>(_profile);
|
||||
_movie.Profile = _profile;
|
||||
|
||||
_release = Builder<ReleaseInfo>.CreateNew().Build();
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using FizzWare.NBuilder;
|
||||
using Marr.Data;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Common.Extensions;
|
||||
@ -47,7 +46,7 @@ public void Setup()
|
||||
},
|
||||
};
|
||||
|
||||
_movie.Profile = new LazyLoaded<Profile>(_profile);
|
||||
_movie.Profile = _profile;
|
||||
|
||||
_release = Builder<ReleaseInfo>.CreateNew().Build();
|
||||
|
||||
|
@ -1,10 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SQLite;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using FluentMigrator.Runner;
|
||||
using Marr.Data;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using NUnit.Framework;
|
||||
@ -111,7 +108,7 @@ protected void SetupContainer()
|
||||
Mocker.SetConstant<IConnectionStringFactory>(Mocker.Resolve<ConnectionStringFactory>());
|
||||
Mocker.SetConstant<IMigrationController>(Mocker.Resolve<MigrationController>());
|
||||
|
||||
MapRepository.Instance.EnableTraceLogging = true;
|
||||
SqlBuilderExtensions.LogSql = true;
|
||||
}
|
||||
|
||||
[SetUp]
|
||||
|
@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Data.Common;
|
||||
using System.Linq;
|
||||
using NzbDrone.Common.Serializer;
|
||||
using NzbDrone.Core.Datastore;
|
||||
@ -16,27 +15,16 @@ public interface IDirectDataMapper
|
||||
|
||||
public class DirectDataMapper : IDirectDataMapper
|
||||
{
|
||||
private readonly DbProviderFactory _providerFactory;
|
||||
private readonly string _connectionString;
|
||||
private readonly IDatabase _database;
|
||||
|
||||
public DirectDataMapper(IDatabase database)
|
||||
{
|
||||
var dataMapper = database.GetDataMapper();
|
||||
_providerFactory = dataMapper.ProviderFactory;
|
||||
_connectionString = dataMapper.ConnectionString;
|
||||
_database = database;
|
||||
}
|
||||
|
||||
private DbConnection OpenConnection()
|
||||
{
|
||||
var connection = _providerFactory.CreateConnection();
|
||||
connection.ConnectionString = _connectionString;
|
||||
connection.Open();
|
||||
return connection;
|
||||
}
|
||||
|
||||
public DataTable GetDataTable(string sql)
|
||||
{
|
||||
using (var connection = OpenConnection())
|
||||
using (var connection = _database.OpenConnection())
|
||||
{
|
||||
using (var cmd = connection.CreateCommand())
|
||||
{
|
||||
|
@ -20,8 +20,8 @@ private void GivenMissingRootFolder()
|
||||
.ToList();
|
||||
|
||||
Mocker.GetMock<IMovieService>()
|
||||
.Setup(s => s.GetAllMovies())
|
||||
.Returns(movies);
|
||||
.Setup(s => s.AllMoviePaths())
|
||||
.Returns(movies.Select(x => x.Path).ToList());
|
||||
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Setup(s => s.GetParentFolder(movies.First().Path))
|
||||
@ -36,8 +36,8 @@ private void GivenMissingRootFolder()
|
||||
public void should_not_return_error_when_no_movie()
|
||||
{
|
||||
Mocker.GetMock<IMovieService>()
|
||||
.Setup(s => s.GetAllMovies())
|
||||
.Returns(new List<Movie>());
|
||||
.Setup(s => s.AllMoviePaths())
|
||||
.Returns(new List<string>());
|
||||
|
||||
Subject.Check().ShouldBeOk();
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
using FizzWare.NBuilder;
|
||||
using System;
|
||||
using FizzWare.NBuilder;
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Authentication;
|
||||
@ -14,7 +15,11 @@ public class CleanupAdditionalUsersFixture : DbTest<CleanupAdditionalUsers, User
|
||||
public void should_delete_additional_users()
|
||||
{
|
||||
var specs = Builder<User>.CreateListOfSize(5)
|
||||
.BuildListOfNew();
|
||||
.All()
|
||||
.With(x => x.Id = 0)
|
||||
.BuildListOfNew();
|
||||
|
||||
specs.ForEach(x => x.Identifier = Guid.NewGuid());
|
||||
|
||||
Db.InsertMany(specs);
|
||||
|
||||
@ -26,7 +31,9 @@ public void should_delete_additional_users()
|
||||
public void should_not_delete_if_only_one_user()
|
||||
{
|
||||
var spec = Builder<User>.CreateNew()
|
||||
.BuildNew();
|
||||
.With(x => x.Id = 0)
|
||||
.With(x => x.Identifier = Guid.NewGuid())
|
||||
.BuildNew();
|
||||
|
||||
Db.Insert(spec);
|
||||
|
||||
@ -34,4 +41,4 @@ public void should_not_delete_if_only_one_user()
|
||||
AllStoredModels.Should().HaveCount(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,10 @@ public class CleanupUnusedTagsFixture : DbTest<CleanupUnusedTags, Tag>
|
||||
[Test]
|
||||
public void should_delete_unused_tags()
|
||||
{
|
||||
var tags = Builder<Tag>.CreateListOfSize(2).BuildList();
|
||||
var tags = Builder<Tag>.CreateListOfSize(2)
|
||||
.All()
|
||||
.With(x => x.Id = 0)
|
||||
.BuildList();
|
||||
|
||||
Db.InsertMany(tags);
|
||||
Subject.Clean();
|
||||
@ -24,11 +27,15 @@ public void should_delete_unused_tags()
|
||||
[Test]
|
||||
public void should_not_delete_used_tags()
|
||||
{
|
||||
var tags = Builder<Tag>.CreateListOfSize(2).BuildList();
|
||||
var tags = Builder<Tag>.CreateListOfSize(2)
|
||||
.All()
|
||||
.With(x => x.Id = 0)
|
||||
.BuildList();
|
||||
Db.InsertMany(tags);
|
||||
|
||||
var restrictions = Builder<Restriction>.CreateListOfSize(2)
|
||||
.All()
|
||||
.With(v => v.Id = 0)
|
||||
.With(v => v.Tags.Add(tags[0].Id))
|
||||
.BuildList();
|
||||
Db.InsertMany(restrictions);
|
||||
|
@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using FluentAssertions;
|
||||
using Marr.Data;
|
||||
using NLog;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Common.Instrumentation;
|
||||
@ -10,7 +9,6 @@
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Test.Common;
|
||||
using NzbDrone.Test.Common.Categories;
|
||||
|
||||
namespace NzbDrone.Core.Test.InstrumentationTests
|
||||
{
|
||||
@ -64,23 +62,6 @@ public void write_long_log()
|
||||
VerifyLog(StoredModel, LogLevel.Info);
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
[Explicit]
|
||||
[ManualTest]
|
||||
public void perf_test()
|
||||
{
|
||||
MapRepository.Instance.EnableTraceLogging = false;
|
||||
for (int i = 0; i < 1000; i++)
|
||||
{
|
||||
_logger.Info(Guid.NewGuid());
|
||||
}
|
||||
|
||||
Thread.Sleep(1000);
|
||||
|
||||
MapRepository.Instance.EnableTraceLogging = true;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void write_log_exception()
|
||||
{
|
||||
|
@ -1,7 +1,5 @@
|
||||
using System.Linq;
|
||||
using FizzWare.NBuilder;
|
||||
using FluentAssertions;
|
||||
using Marr.Data;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.MediaFiles.MovieImport.Specifications;
|
||||
@ -39,11 +37,11 @@ public void should_be_accepted_if_file_size_is_different()
|
||||
{
|
||||
_localMovie.Movie = Builder<Movie>.CreateNew()
|
||||
.With(e => e.MovieFileId = 1)
|
||||
.With(e => e.MovieFile = new LazyLoaded<MovieFile>(
|
||||
.With(e => e.MovieFile =
|
||||
new MovieFile
|
||||
{
|
||||
Size = _localMovie.Size + 100.Megabytes()
|
||||
}))
|
||||
})
|
||||
.Build();
|
||||
|
||||
Subject.IsSatisfiedBy(_localMovie, null).Accepted.Should().BeTrue();
|
||||
@ -54,11 +52,11 @@ public void should_be_reject_if_file_size_is_the_same()
|
||||
{
|
||||
_localMovie.Movie = Builder<Movie>.CreateNew()
|
||||
.With(e => e.MovieFileId = 1)
|
||||
.With(e => e.MovieFile = new LazyLoaded<MovieFile>(
|
||||
.With(e => e.MovieFile =
|
||||
new MovieFile
|
||||
{
|
||||
Size = _localMovie.Size
|
||||
}))
|
||||
})
|
||||
.Build();
|
||||
|
||||
Subject.IsSatisfiedBy(_localMovie, null).Accepted.Should().BeFalse();
|
||||
@ -69,7 +67,7 @@ public void should_be_accepted_if_file_cannot_be_fetched()
|
||||
{
|
||||
_localMovie.Movie = Builder<Movie>.CreateNew()
|
||||
.With(e => e.MovieFileId = 1)
|
||||
.With(e => e.MovieFile = new LazyLoaded<MovieFile>((MovieFile)null))
|
||||
.With(e => e.MovieFile = null)
|
||||
.Build();
|
||||
|
||||
Subject.IsSatisfiedBy(_localMovie, null).Accepted.Should().BeTrue();
|
||||
|
@ -1,7 +1,5 @@
|
||||
using System.Linq;
|
||||
using FizzWare.NBuilder;
|
||||
using FluentAssertions;
|
||||
using Marr.Data;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.MediaFiles.MovieImport.Specifications;
|
||||
@ -48,13 +46,11 @@ public void should_return_true_if_upgrade_for_existing_episodeFile()
|
||||
{
|
||||
|
||||
_localMovie.Movie.MovieFileId = 1;
|
||||
_localMovie.Movie.MovieFile = new LazyLoaded<MovieFile>(
|
||||
_localMovie.Movie.MovieFile =
|
||||
new MovieFile
|
||||
{
|
||||
Quality = new QualityModel(Quality.SDTV, new Revision(version: 1))
|
||||
}
|
||||
);
|
||||
|
||||
};
|
||||
|
||||
Subject.IsSatisfiedBy(_localMovie, null).Accepted.Should().BeTrue();
|
||||
}
|
||||
@ -64,12 +60,11 @@ public void should_return_true_if_upgrade_for_existing_episodeFile()
|
||||
public void should_return_false_if_not_an_upgrade_for_existing_episodeFile()
|
||||
{
|
||||
_localMovie.Movie.MovieFileId = 1;
|
||||
_localMovie.Movie.MovieFile = new LazyLoaded<MovieFile>(
|
||||
_localMovie.Movie.MovieFile =
|
||||
new MovieFile
|
||||
{
|
||||
Quality = new QualityModel(Quality.Bluray720p, new Revision(version: 1))
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
Subject.IsSatisfiedBy(_localMovie, null).Accepted.Should().BeFalse();
|
||||
}
|
||||
|
@ -1,7 +1,5 @@
|
||||
using System.Linq;
|
||||
using FizzWare.NBuilder;
|
||||
using FluentAssertions;
|
||||
using Marr.Data;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Common.Disk;
|
||||
|
@ -5,6 +5,8 @@
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.Movies;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace NzbDrone.Core.Test.MovieTests.MovieRepositoryTests
|
||||
{
|
||||
@ -12,13 +14,17 @@ namespace NzbDrone.Core.Test.MovieTests.MovieRepositoryTests
|
||||
|
||||
public class MovieRepositoryFixture : DbTest<MovieRepository, Movie>
|
||||
{
|
||||
private IProfileRepository _profileRepository;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_profileRepository = Mocker.Resolve<ProfileRepository>();
|
||||
Mocker.SetConstant<IProfileRepository>(_profileRepository);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_lazyload_quality_profile()
|
||||
public void should_load_quality_profile()
|
||||
{
|
||||
var profile = new Profile
|
||||
{
|
||||
@ -29,16 +35,14 @@ public void should_lazyload_quality_profile()
|
||||
Name = "TestProfile"
|
||||
};
|
||||
|
||||
|
||||
Mocker.Resolve<ProfileRepository>().Insert(profile);
|
||||
_profileRepository.Insert(profile);
|
||||
|
||||
var movie = Builder<Movie>.CreateNew().BuildNew();
|
||||
movie.ProfileId = profile.Id;
|
||||
|
||||
Subject.Insert(movie);
|
||||
|
||||
|
||||
StoredModel.Profile.Should().NotBeNull();
|
||||
Subject.All().Single().Profile.Should().NotBeNull();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using FizzWare.NBuilder;
|
||||
using FluentAssertions;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||
using NzbDrone.Core.Movies.AlternativeTitles;
|
||||
using NzbDrone.Core.Parser;
|
||||
@ -36,7 +34,7 @@ public void Setup()
|
||||
.With(m => m.Title = "Fack Ju Göthe 2")
|
||||
.With(m => m.CleanTitle = "fackjugoethe2")
|
||||
.With(m => m.Year = 2015)
|
||||
.With(m => m.AlternativeTitles = new LazyList<AlternativeTitle>( new List<AlternativeTitle> {new AlternativeTitle("Fack Ju Göthe 2: Same same")}))
|
||||
.With(m => m.AlternativeTitles = new List<AlternativeTitle> {new AlternativeTitle("Fack Ju Göthe 2: Same same")})
|
||||
.Build();
|
||||
|
||||
_parsedMovieInfo = new ParsedMovieInfo
|
||||
|
@ -7,6 +7,7 @@
|
||||
<PackageReference Include="NUnit" Version="3.12.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.15.1" />
|
||||
<PackageReference Include="NunitXml.TestLogger" Version="2.1.41" />
|
||||
<PackageReference Include="Dapper" Version="2.0.30" />
|
||||
<PackageReference Include="NBuilder" Version="6.0.1" />
|
||||
<PackageReference Include="System.Data.SQLite.Core.Lidarr" Version="1.0.111.0-5" />
|
||||
</ItemGroup>
|
||||
|
@ -20,12 +20,12 @@ public UserRepository(IMainDatabase database, IEventAggregator eventAggregator)
|
||||
|
||||
public User FindUser(string username)
|
||||
{
|
||||
return Query.Where(u => u.Username == username).SingleOrDefault();
|
||||
return Query(x => x.Username == username).SingleOrDefault();
|
||||
}
|
||||
|
||||
public User FindUser(Guid identifier)
|
||||
{
|
||||
return Query.Where(u => u.Identifier == identifier).SingleOrDefault();
|
||||
return Query(x => x.Identifier == identifier).SingleOrDefault();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ public MakeDatabaseBackup(Logger logger)
|
||||
public void BackupDatabase(IDatabase database, string targetDirectory)
|
||||
{
|
||||
var sourceConnectionString = "";
|
||||
using (var db = database.GetDataMapper())
|
||||
using (var db = database.OpenConnection())
|
||||
{
|
||||
sourceConnectionString = db.ConnectionString;
|
||||
}
|
||||
|
@ -1,7 +1,8 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Dapper;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using Marr.Data.QGen;
|
||||
using NzbDrone.Core.Movies;
|
||||
|
||||
namespace NzbDrone.Core.Blacklisting
|
||||
@ -22,26 +23,35 @@ public BlacklistRepository(IMainDatabase database, IEventAggregator eventAggrega
|
||||
|
||||
public List<Blacklist> BlacklistedByTitle(int movieId, string sourceTitle)
|
||||
{
|
||||
return Query.Where(e => e.MovieId == movieId)
|
||||
.AndWhere(e => e.SourceTitle.Contains(sourceTitle)).ToList();
|
||||
return Query(x => x.MovieId == movieId && x.SourceTitle.Contains(sourceTitle));
|
||||
}
|
||||
|
||||
public List<Blacklist> BlacklistedByTorrentInfoHash(int movieId, string torrentInfoHash)
|
||||
{
|
||||
return Query.Where(e => e.MovieId == movieId)
|
||||
.AndWhere(e => e.TorrentInfoHash.Contains(torrentInfoHash)).ToList();
|
||||
return Query(x => x.MovieId == movieId && x.TorrentInfoHash.Contains(torrentInfoHash));
|
||||
}
|
||||
|
||||
public List<Blacklist> BlacklistedByMovie(int movieId)
|
||||
{
|
||||
return Query.Where(b => b.MovieId == movieId).ToList();
|
||||
return Query(x => x.MovieId == movieId);
|
||||
}
|
||||
|
||||
protected override SortBuilder<Blacklist> GetPagedQuery(QueryBuilder<Blacklist> query, PagingSpec<Blacklist> pagingSpec)
|
||||
private IEnumerable<Blacklist> SelectJoined(SqlBuilder.Template sql)
|
||||
{
|
||||
var baseQuery = query.Join<Blacklist, Movie>(JoinType.Inner, h => h.Movie, (h, s) => h.MovieId == s.Id);
|
||||
|
||||
return base.GetPagedQuery(baseQuery, pagingSpec);
|
||||
using (var conn = _database.OpenConnection())
|
||||
{
|
||||
return conn.Query<Blacklist, Movie, Blacklist>(
|
||||
sql.RawSql,
|
||||
(bl, movie) => {
|
||||
bl.Movie = movie;
|
||||
return bl;
|
||||
},
|
||||
sql.Parameters)
|
||||
.ToList();
|
||||
}
|
||||
}
|
||||
|
||||
protected override SqlBuilder PagedBuilder() => new SqlBuilder().Join("Movies ON Movies.Id = Blacklist.MovieId");
|
||||
protected override IEnumerable<Blacklist> PagedSelector(SqlBuilder.Template sql) => SelectJoined(sql);
|
||||
}
|
||||
}
|
||||
|
@ -18,10 +18,9 @@ public ConfigRepository(IMainDatabase database, IEventAggregator eventAggregator
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
public Config Get(string key)
|
||||
{
|
||||
return Query.Where(c => c.Key == key).SingleOrDefault();
|
||||
return Query(c => c.Key == key).SingleOrDefault();
|
||||
}
|
||||
|
||||
public Config Upsert(string key, string value)
|
||||
|
@ -7,6 +7,10 @@ namespace NzbDrone.Core.CustomFormats
|
||||
{
|
||||
public class CustomFormat : ModelBase, IEquatable<CustomFormat>
|
||||
{
|
||||
public string Name { get; set; }
|
||||
|
||||
public List<FormatTag> FormatTags { get; set; }
|
||||
|
||||
public CustomFormat()
|
||||
{
|
||||
|
||||
@ -18,9 +22,7 @@ public CustomFormat(string name, params string[] tags)
|
||||
FormatTags = tags.Select(t => new FormatTag(t)).ToList();
|
||||
}
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
public List<FormatTag> FormatTags { get; set; }
|
||||
public static implicit operator CustomFormatDefinition(CustomFormat format) => new CustomFormatDefinition { Id = format.Id, Name = format.Name, FormatTags = format.FormatTags };
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
|
14
src/NzbDrone.Core/CustomFormats/CustomFormatDefinition.cs
Normal file
14
src/NzbDrone.Core/CustomFormats/CustomFormatDefinition.cs
Normal file
@ -0,0 +1,14 @@
|
||||
using System.Collections.Generic;
|
||||
using NzbDrone.Core.Datastore;
|
||||
|
||||
namespace NzbDrone.Core.CustomFormats
|
||||
{
|
||||
public class CustomFormatDefinition : ModelBase
|
||||
{
|
||||
public string Name { get; set; }
|
||||
|
||||
public List<FormatTag> FormatTags { get; set; }
|
||||
|
||||
public static implicit operator CustomFormat(CustomFormatDefinition def) => new CustomFormat { Id = def.Id, Name = def.Name, FormatTags = def.FormatTags };
|
||||
}
|
||||
}
|
@ -3,12 +3,12 @@
|
||||
|
||||
namespace NzbDrone.Core.CustomFormats
|
||||
{
|
||||
public interface ICustomFormatRepository : IBasicRepository<CustomFormat>
|
||||
public interface ICustomFormatRepository : IBasicRepository<CustomFormatDefinition>
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public class CustomFormatRepository : BasicRepository<CustomFormat>, ICustomFormatRepository
|
||||
public class CustomFormatRepository : BasicRepository<CustomFormatDefinition>, ICustomFormatRepository
|
||||
{
|
||||
public CustomFormatRepository(IMainDatabase database, IEventAggregator eventAggregator)
|
||||
: base(database, eventAggregator)
|
||||
|
@ -7,9 +7,7 @@
|
||||
using NzbDrone.Core.Blacklisting;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.History;
|
||||
using NzbDrone.Core.Lifecycle;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.Profiles;
|
||||
|
||||
namespace NzbDrone.Core.CustomFormats
|
||||
@ -23,8 +21,7 @@ public interface ICustomFormatService
|
||||
void Delete(int id);
|
||||
}
|
||||
|
||||
|
||||
public class CustomFormatService : ICustomFormatService, IHandle<ApplicationStartedEvent>
|
||||
public class CustomFormatService : ICustomFormatService
|
||||
{
|
||||
private readonly ICustomFormatRepository _formatRepository;
|
||||
private IProfileService _profileService;
|
||||
@ -58,6 +55,9 @@ public CustomFormatService(ICustomFormatRepository formatRepository, ICacheManag
|
||||
_cache = cacheManager.GetCache<Dictionary<int, CustomFormat>>(typeof(CustomFormat), "formats");
|
||||
_historyService = historyService;
|
||||
_logger = logger;
|
||||
|
||||
// Fill up the cache for subsequent DB lookups
|
||||
All();
|
||||
}
|
||||
|
||||
public void Update(CustomFormat customFormat)
|
||||
@ -144,7 +144,7 @@ private Dictionary<int, CustomFormat> AllDictionary()
|
||||
{
|
||||
return _cache.Get("all", () =>
|
||||
{
|
||||
var all = _formatRepository.All().ToDictionary(m => m.Id);
|
||||
var all = _formatRepository.All().Select(x => (CustomFormat)x).ToDictionary(m => m.Id);
|
||||
AllCustomFormats = all;
|
||||
return all;
|
||||
});
|
||||
@ -194,11 +194,5 @@ public static Dictionary<string, List<CustomFormat>> Templates
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public void Handle(ApplicationStartedEvent message)
|
||||
{
|
||||
// Fillup cache for DataMapper.
|
||||
All();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,11 +3,10 @@
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using Marr.Data;
|
||||
using Marr.Data.QGen;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using Dapper;
|
||||
using NzbDrone.Core.Datastore.Events;
|
||||
using NzbDrone.Core.Datastore.Extensions;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
|
||||
namespace NzbDrone.Core.Datastore
|
||||
@ -31,43 +30,89 @@ namespace NzbDrone.Core.Datastore
|
||||
bool HasItems();
|
||||
void DeleteMany(IEnumerable<int> ids);
|
||||
void SetFields(TModel model, params Expression<Func<TModel, object>>[] properties);
|
||||
void SetFields(IList<TModel> models, params Expression<Func<TModel, object>>[] properties);
|
||||
TModel Single();
|
||||
PagingSpec<TModel> GetPaged(PagingSpec<TModel> pagingSpec);
|
||||
}
|
||||
|
||||
public class BasicRepository<TModel> : IBasicRepository<TModel> where TModel : ModelBase, new()
|
||||
{
|
||||
private readonly IDatabase _database;
|
||||
private readonly IEventAggregator _eventAggregator;
|
||||
private readonly PropertyInfo _keyProperty;
|
||||
private readonly List<PropertyInfo> _properties;
|
||||
private readonly string _updateSql;
|
||||
private readonly string _insertSql;
|
||||
|
||||
protected IDataMapper DataMapper => _database.GetDataMapper();
|
||||
protected readonly IDatabase _database;
|
||||
protected readonly string _table;
|
||||
protected string _selectTemplate;
|
||||
protected string _deleteTemplate;
|
||||
|
||||
public BasicRepository(IDatabase database, IEventAggregator eventAggregator)
|
||||
{
|
||||
_database = database;
|
||||
_eventAggregator = eventAggregator;
|
||||
|
||||
var type = typeof(TModel);
|
||||
|
||||
_table = TableMapping.Mapper.TableNameMapping(type);
|
||||
_keyProperty = type.GetProperty(nameof(ModelBase.Id));
|
||||
|
||||
var excluded = TableMapping.Mapper.ExcludeProperties(type).Select(x => x.Name).ToList();
|
||||
excluded.Add(_keyProperty.Name);
|
||||
_properties = type.GetProperties().Where(x => !excluded.Contains(x.Name)).ToList();
|
||||
|
||||
_insertSql = GetInsertSql();
|
||||
_updateSql = GetUpdateSql(_properties);
|
||||
|
||||
_selectTemplate = $"SELECT /**select**/ FROM {_table} /**join**/ /**innerjoin**/ /**leftjoin**/ /**where**/ /**orderby**/";
|
||||
_deleteTemplate = $"DELETE FROM {_table} /**where**/";
|
||||
}
|
||||
|
||||
protected QueryBuilder<TModel> Query => AddJoinQueries(DataMapper.Query<TModel>());
|
||||
protected virtual SqlBuilder BuilderBase() => new SqlBuilder();
|
||||
protected virtual SqlBuilder Builder() => BuilderBase().SelectAll();
|
||||
|
||||
protected void Delete(Expression<Func<TModel, bool>> filter)
|
||||
protected virtual IEnumerable<TModel> GetResults(SqlBuilder.Template sql)
|
||||
{
|
||||
DataMapper.Delete(filter);
|
||||
using (var conn = _database.OpenConnection())
|
||||
{
|
||||
return conn.Query<TModel>(sql.RawSql, sql.Parameters);
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<TModel> All()
|
||||
protected List<TModel> Query(Expression<Func<TModel, bool>> where)
|
||||
{
|
||||
return AddJoinQueries(DataMapper.Query<TModel>()).ToList();
|
||||
return Query(Builder().Where<TModel>(where));
|
||||
}
|
||||
|
||||
protected List<TModel> Query(SqlBuilder builder)
|
||||
{
|
||||
return Query(builder, GetResults);
|
||||
}
|
||||
|
||||
protected List<TModel> Query(SqlBuilder builder, Func<SqlBuilder.Template, IEnumerable<TModel>> queryFunc)
|
||||
{
|
||||
var sql = builder.AddTemplate(_selectTemplate).LogQuery();
|
||||
|
||||
return queryFunc(sql).ToList();
|
||||
}
|
||||
|
||||
public int Count()
|
||||
{
|
||||
return DataMapper.Query<TModel>().GetRowCount();
|
||||
using (var conn = _database.OpenConnection())
|
||||
{
|
||||
return conn.ExecuteScalar<int>($"SELECT COUNT(*) FROM {_table}");
|
||||
}
|
||||
}
|
||||
|
||||
public virtual IEnumerable<TModel> All()
|
||||
{
|
||||
return Query(Builder());
|
||||
}
|
||||
|
||||
public TModel Get(int id)
|
||||
{
|
||||
var model = Query.Where(c => c.Id == id).SingleOrDefault();
|
||||
var model = Query(x => x.Id == id).FirstOrDefault();
|
||||
|
||||
if (model == null)
|
||||
{
|
||||
@ -79,13 +124,16 @@ public TModel Get(int id)
|
||||
|
||||
public IEnumerable<TModel> Get(IEnumerable<int> ids)
|
||||
{
|
||||
var idList = ids.ToList();
|
||||
var query = string.Format("Id IN ({0})", string.Join(",", idList));
|
||||
var result = Query.Where(m => m.Id.In(idList)).ToList();
|
||||
|
||||
if (result.Count != idList.Count())
|
||||
if (!ids.Any())
|
||||
{
|
||||
throw new ApplicationException($"Expected query to return {idList.Count} rows but returned {result.Count}");
|
||||
return new List<TModel>();
|
||||
}
|
||||
|
||||
var result = Query(x => ids.Contains(x.Id));
|
||||
|
||||
if (result.Count != ids.Count())
|
||||
{
|
||||
throw new ApplicationException($"Expected query to return {ids.Count()} rows but returned {result.Count}");
|
||||
}
|
||||
|
||||
return result;
|
||||
@ -108,13 +156,70 @@ public TModel Insert(TModel model)
|
||||
throw new InvalidOperationException("Can't insert model with existing ID " + model.Id);
|
||||
}
|
||||
|
||||
DataMapper.Insert(model);
|
||||
using (var conn = _database.OpenConnection())
|
||||
{
|
||||
model = Insert(conn, null, model);
|
||||
}
|
||||
|
||||
ModelCreated(model);
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
private string GetInsertSql()
|
||||
{
|
||||
var sbColumnList = new StringBuilder(null);
|
||||
for (var i = 0; i < _properties.Count; i++)
|
||||
{
|
||||
var property = _properties[i];
|
||||
sbColumnList.AppendFormat("\"{0}\"", property.Name);
|
||||
if (i < _properties.Count - 1)
|
||||
sbColumnList.Append(", ");
|
||||
}
|
||||
|
||||
var sbParameterList = new StringBuilder(null);
|
||||
for (var i = 0; i < _properties.Count; i++)
|
||||
{
|
||||
var property = _properties[i];
|
||||
sbParameterList.AppendFormat("@{0}", property.Name);
|
||||
if (i < _properties.Count - 1)
|
||||
sbParameterList.Append(", ");
|
||||
}
|
||||
|
||||
return $"INSERT INTO {_table} ({sbColumnList.ToString()}) VALUES ({sbParameterList.ToString()}); SELECT last_insert_rowid() id";
|
||||
}
|
||||
|
||||
private TModel Insert(IDbConnection connection, IDbTransaction transaction, TModel model)
|
||||
{
|
||||
|
||||
var multi = connection.QueryMultiple(_insertSql, model, transaction);
|
||||
var id = (int)multi.Read().First().id;
|
||||
_keyProperty.SetValue(model, id);
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
public void InsertMany(IList<TModel> models)
|
||||
{
|
||||
if (models.Any(x => x.Id != 0))
|
||||
{
|
||||
throw new InvalidOperationException("Can't insert model with existing ID != 0");
|
||||
}
|
||||
|
||||
using (var conn = _database.OpenConnection())
|
||||
{
|
||||
using (IDbTransaction tran = conn.BeginTransaction(IsolationLevel.ReadCommitted))
|
||||
{
|
||||
foreach (var model in models)
|
||||
{
|
||||
Insert(conn, tran, model);
|
||||
}
|
||||
|
||||
tran.Commit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public TModel Update(TModel model)
|
||||
{
|
||||
if (model.Id == 0)
|
||||
@ -122,52 +227,59 @@ public TModel Update(TModel model)
|
||||
throw new InvalidOperationException("Can't update model with ID 0");
|
||||
}
|
||||
|
||||
DataMapper.Update(model, c => c.Id == model.Id);
|
||||
using (var conn = _database.OpenConnection())
|
||||
{
|
||||
UpdateFields(conn, null, model, _properties);
|
||||
}
|
||||
|
||||
ModelUpdated(model);
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
public void Delete(TModel model)
|
||||
public void UpdateMany(IList<TModel> models)
|
||||
{
|
||||
Delete(model.Id);
|
||||
}
|
||||
|
||||
public void InsertMany(IList<TModel> models)
|
||||
{
|
||||
using (var unitOfWork = new UnitOfWork(() => DataMapper))
|
||||
if (models.Any(x => x.Id == 0))
|
||||
{
|
||||
unitOfWork.BeginTransaction(IsolationLevel.ReadCommitted);
|
||||
throw new InvalidOperationException("Can't update model with ID 0");
|
||||
}
|
||||
|
||||
foreach (var model in models)
|
||||
{
|
||||
unitOfWork.DB.Insert(model);
|
||||
}
|
||||
|
||||
unitOfWork.Commit();
|
||||
using (var conn = _database.OpenConnection())
|
||||
{
|
||||
UpdateFields(conn, null, models, _properties);
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateMany(IList<TModel> models)
|
||||
protected void Delete(Expression<Func<TModel, bool>> where)
|
||||
{
|
||||
using (var unitOfWork = new UnitOfWork(() => DataMapper))
|
||||
Delete(Builder().Where<TModel>(where));
|
||||
}
|
||||
|
||||
protected void Delete(SqlBuilder builder)
|
||||
{
|
||||
var sql = builder.AddTemplate(_deleteTemplate).LogQuery();
|
||||
|
||||
using (var conn = _database.OpenConnection())
|
||||
{
|
||||
unitOfWork.BeginTransaction(IsolationLevel.ReadCommitted);
|
||||
conn.Execute(sql.RawSql, sql.Parameters);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var model in models)
|
||||
{
|
||||
var localModel = model;
|
||||
public void Delete(TModel model)
|
||||
{
|
||||
Delete(x => x.Id == model.Id);
|
||||
}
|
||||
|
||||
if (model.Id == 0)
|
||||
{
|
||||
throw new InvalidOperationException("Can't update model with ID 0");
|
||||
}
|
||||
public void Delete(int id)
|
||||
{
|
||||
Delete(x => x.Id == id);
|
||||
}
|
||||
|
||||
unitOfWork.DB.Update(model, c => c.Id == localModel.Id);
|
||||
}
|
||||
|
||||
unitOfWork.Commit();
|
||||
public void DeleteMany(IEnumerable<int> ids)
|
||||
{
|
||||
if (ids.Any())
|
||||
{
|
||||
Delete(x => ids.Contains(x.Id));
|
||||
}
|
||||
}
|
||||
|
||||
@ -187,31 +299,13 @@ public TModel Upsert(TModel model)
|
||||
return model;
|
||||
}
|
||||
|
||||
public void Delete(int id)
|
||||
{
|
||||
DataMapper.Delete<TModel>(c => c.Id == id);
|
||||
}
|
||||
|
||||
public void DeleteMany(IEnumerable<int> ids)
|
||||
{
|
||||
using (var unitOfWork = new UnitOfWork(() => DataMapper))
|
||||
{
|
||||
unitOfWork.BeginTransaction(IsolationLevel.ReadCommitted);
|
||||
|
||||
foreach (var id in ids)
|
||||
{
|
||||
var localId = id;
|
||||
|
||||
unitOfWork.DB.Delete<TModel>(c => c.Id == localId);
|
||||
}
|
||||
|
||||
unitOfWork.Commit();
|
||||
}
|
||||
}
|
||||
|
||||
public void Purge(bool vacuum = false)
|
||||
{
|
||||
DataMapper.Delete<TModel>(c => c.Id > -1);
|
||||
using (var conn = _database.OpenConnection())
|
||||
{
|
||||
conn.Execute($"DELETE FROM [{_table}]");
|
||||
}
|
||||
|
||||
if (vacuum)
|
||||
{
|
||||
Vacuum();
|
||||
@ -232,43 +326,115 @@ public void SetFields(TModel model, params Expression<Func<TModel, object>>[] pr
|
||||
{
|
||||
if (model.Id == 0)
|
||||
{
|
||||
throw new InvalidOperationException("Attempted to updated model without ID");
|
||||
throw new InvalidOperationException("Attempted to update model without ID");
|
||||
}
|
||||
|
||||
DataMapper.Update<TModel>()
|
||||
.Where(c => c.Id == model.Id)
|
||||
.ColumnsIncluding(properties)
|
||||
.Entity(model)
|
||||
.Execute();
|
||||
var propertiesToUpdate = properties.Select(x => x.GetMemberName()).ToList();
|
||||
|
||||
using (var conn = _database.OpenConnection())
|
||||
{
|
||||
UpdateFields(conn, null, model, propertiesToUpdate);
|
||||
}
|
||||
|
||||
ModelUpdated(model);
|
||||
}
|
||||
|
||||
public void SetFields(IList<TModel> models, params Expression<Func<TModel, object>>[] properties)
|
||||
{
|
||||
if (models.Any(x => x.Id == 0))
|
||||
{
|
||||
throw new InvalidOperationException("Attempted to update model without ID");
|
||||
}
|
||||
|
||||
var propertiesToUpdate = properties.Select(x => x.GetMemberName()).ToList();
|
||||
|
||||
using (var conn = _database.OpenConnection())
|
||||
{
|
||||
UpdateFields(conn, null, models, propertiesToUpdate);
|
||||
}
|
||||
|
||||
foreach(var model in models)
|
||||
{
|
||||
ModelUpdated(model);
|
||||
}
|
||||
}
|
||||
|
||||
private string GetUpdateSql(List<PropertyInfo> propertiesToUpdate)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendFormat("update {0} set ", _table);
|
||||
|
||||
for (var i = 0; i < propertiesToUpdate.Count; i++)
|
||||
{
|
||||
var property = propertiesToUpdate[i];
|
||||
sb.AppendFormat("\"{0}\" = @{1}", property.Name, property.Name);
|
||||
if (i < propertiesToUpdate.Count - 1)
|
||||
sb.Append(", ");
|
||||
}
|
||||
|
||||
sb.Append($" where \"{_keyProperty.Name}\" = @{_keyProperty.Name}");
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
private void UpdateFields(IDbConnection connection, IDbTransaction transaction, TModel model, List<PropertyInfo> propertiesToUpdate)
|
||||
{
|
||||
var sql = propertiesToUpdate == _properties ? _updateSql : GetUpdateSql(propertiesToUpdate);
|
||||
|
||||
connection.Execute(sql, model, transaction: transaction);
|
||||
}
|
||||
|
||||
private void UpdateFields(IDbConnection connection, IDbTransaction transaction, IList<TModel> models, List<PropertyInfo> propertiesToUpdate)
|
||||
{
|
||||
var sql = propertiesToUpdate == _properties ? _updateSql : GetUpdateSql(propertiesToUpdate);
|
||||
|
||||
connection.Execute(sql, models, transaction: transaction);
|
||||
}
|
||||
|
||||
protected virtual SqlBuilder PagedBuilder() => BuilderBase();
|
||||
protected virtual IEnumerable<TModel> PagedSelector(SqlBuilder.Template sql) => GetResults(sql);
|
||||
|
||||
public virtual PagingSpec<TModel> GetPaged(PagingSpec<TModel> pagingSpec)
|
||||
{
|
||||
pagingSpec.Records = GetPagedQuery(Query, pagingSpec).ToList();
|
||||
pagingSpec.TotalRecords = GetPagedQuery(Query, pagingSpec).GetRowCount();
|
||||
pagingSpec.Records = GetPagedRecords(PagedBuilder().SelectAll(), pagingSpec, PagedSelector);
|
||||
pagingSpec.TotalRecords = GetPagedRecordCount(PagedBuilder().SelectCount(), pagingSpec);
|
||||
|
||||
return pagingSpec;
|
||||
}
|
||||
|
||||
protected virtual SortBuilder<TModel> GetPagedQuery(QueryBuilder<TModel> query, PagingSpec<TModel> pagingSpec)
|
||||
private void AddFilters(SqlBuilder builder, PagingSpec<TModel> pagingSpec)
|
||||
{
|
||||
var filterExpressions = pagingSpec.FilterExpressions;
|
||||
var sortQuery = query.Where(filterExpressions.FirstOrDefault());
|
||||
var filters = pagingSpec.FilterExpressions;
|
||||
|
||||
if (filterExpressions.Count > 1)
|
||||
foreach (var filter in filters)
|
||||
{
|
||||
// Start at the second item for the AndWhere clauses
|
||||
for (var i = 1; i < filterExpressions.Count; i++)
|
||||
{
|
||||
sortQuery.AndWhere(filterExpressions[i]);
|
||||
}
|
||||
builder.Where<TModel>(filter);
|
||||
}
|
||||
}
|
||||
|
||||
return sortQuery.OrderBy(pagingSpec.OrderByClause(), pagingSpec.ToSortDirection())
|
||||
.Skip(pagingSpec.PagingOffset())
|
||||
.Take(pagingSpec.PageSize);
|
||||
protected List<TModel> GetPagedRecords(SqlBuilder builder, PagingSpec<TModel> pagingSpec, Func<SqlBuilder.Template, IEnumerable<TModel>> queryFunc)
|
||||
{
|
||||
AddFilters(builder, pagingSpec);
|
||||
|
||||
var sortDirection = pagingSpec.SortDirection == SortDirection.Descending ? "DESC" : "ASC";
|
||||
var pagingOffset = (pagingSpec.Page - 1)*pagingSpec.PageSize;
|
||||
builder.OrderBy($"{pagingSpec.SortKey} {sortDirection} LIMIT {pagingSpec.PageSize} OFFSET {pagingOffset}");
|
||||
|
||||
var sql = builder.AddTemplate(_selectTemplate).LogQuery();
|
||||
|
||||
return queryFunc(sql).ToList();
|
||||
}
|
||||
|
||||
protected int GetPagedRecordCount(SqlBuilder builder, PagingSpec<TModel> pagingSpec)
|
||||
{
|
||||
AddFilters(builder, pagingSpec);
|
||||
|
||||
var sql = builder.AddTemplate(_selectTemplate).LogQuery();
|
||||
|
||||
using (var conn = _database.OpenConnection())
|
||||
{
|
||||
return conn.ExecuteScalar<int>(sql.RawSql, sql.Parameters);
|
||||
}
|
||||
}
|
||||
|
||||
protected void ModelCreated(TModel model)
|
||||
@ -294,11 +460,6 @@ private void PublishModelEvent(TModel model, ModelAction action)
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual QueryBuilder<TActual> AddJoinQueries<TActual>(QueryBuilder<TActual> baseQuery)
|
||||
{
|
||||
return baseQuery;
|
||||
}
|
||||
|
||||
protected virtual bool PublishModelEvents => false;
|
||||
}
|
||||
}
|
||||
|
@ -1,51 +0,0 @@
|
||||
using System;
|
||||
using Marr.Data.Converters;
|
||||
using Marr.Data.Mapping;
|
||||
|
||||
namespace NzbDrone.Core.Datastore.Converters
|
||||
{
|
||||
public class BooleanIntConverter : IConverter
|
||||
{
|
||||
public object FromDB(ConverterContext context)
|
||||
{
|
||||
if (context.DbValue == DBNull.Value)
|
||||
{
|
||||
return DBNull.Value;
|
||||
}
|
||||
|
||||
var val = (long)context.DbValue;
|
||||
|
||||
switch (val)
|
||||
{
|
||||
case 1:
|
||||
return true;
|
||||
case 0:
|
||||
return false;
|
||||
default:
|
||||
throw new ConversionException(string.Format("The BooleanCharConverter could not convert the value '{0}' to a Boolean.", context.DbValue));
|
||||
}
|
||||
}
|
||||
|
||||
public object FromDB(ColumnMap map, object dbValue)
|
||||
{
|
||||
return FromDB(new ConverterContext { ColumnMap = map, DbValue = dbValue });
|
||||
}
|
||||
|
||||
public object ToDB(object clrValue)
|
||||
{
|
||||
var val = (Nullable<bool>)clrValue;
|
||||
|
||||
switch (val)
|
||||
{
|
||||
case true:
|
||||
return 1;
|
||||
case false:
|
||||
return 0;
|
||||
default:
|
||||
return DBNull.Value;
|
||||
}
|
||||
}
|
||||
|
||||
public Type DbType => typeof(int);
|
||||
}
|
||||
}
|
@ -1,30 +1,28 @@
|
||||
using System;
|
||||
using Marr.Data.Converters;
|
||||
using System.Data;
|
||||
using System.Text.Json;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Common.Reflection;
|
||||
using NzbDrone.Common.Serializer;
|
||||
using NzbDrone.Core.Messaging.Commands;
|
||||
|
||||
namespace NzbDrone.Core.Datastore.Converters
|
||||
{
|
||||
public class CommandConverter : EmbeddedDocumentConverter
|
||||
public class CommandConverter : EmbeddedDocumentConverter<Command>
|
||||
{
|
||||
public override object FromDB(ConverterContext context)
|
||||
public override Command Parse(object value)
|
||||
{
|
||||
if (context.DbValue == DBNull.Value)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var stringValue = (string)context.DbValue;
|
||||
var stringValue = (string) value;
|
||||
|
||||
if (stringValue.IsNullOrWhiteSpace())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var ordinal = context.DataRecord.GetOrdinal("Name");
|
||||
var contract = context.DataRecord.GetString(ordinal);
|
||||
string contract;
|
||||
using (JsonDocument body = JsonDocument.Parse(stringValue))
|
||||
{
|
||||
contract = body.RootElement.GetProperty("name").GetString();
|
||||
}
|
||||
|
||||
var impType = typeof (Command).Assembly.FindTypeByName(contract + "Command");
|
||||
|
||||
if (impType == null)
|
||||
@ -32,7 +30,12 @@ public override object FromDB(ConverterContext context)
|
||||
throw new CommandNotFoundException(contract);
|
||||
}
|
||||
|
||||
return Json.Deserialize(stringValue, impType);
|
||||
return (Command) JsonSerializer.Deserialize(stringValue, impType, SerializerSettings);
|
||||
}
|
||||
|
||||
public override void SetValue(IDbDataParameter parameter, Command value)
|
||||
{
|
||||
parameter.Value = value == null ? null : JsonSerializer.Serialize(value, SerializerSettings);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,91 +1,57 @@
|
||||
using System;
|
||||
using System.ServiceModel;
|
||||
using Marr.Data.Converters;
|
||||
using Marr.Data.Mapping;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using Newtonsoft.Json;
|
||||
using System.Data;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using Dapper;
|
||||
using NzbDrone.Common.Serializer;
|
||||
using NzbDrone.Core.CustomFormats;
|
||||
|
||||
namespace NzbDrone.Core.Datastore.Converters
|
||||
{
|
||||
public class CustomFormatIntConverter : JsonConverter, IConverter
|
||||
public class DapperCustomFormatIntConverter : SqlMapper.TypeHandler<CustomFormat>
|
||||
{
|
||||
//TODO think of something better.
|
||||
public object FromDB(ConverterContext context)
|
||||
public override void SetValue(IDbDataParameter parameter, CustomFormat value)
|
||||
{
|
||||
if (context.DbValue == DBNull.Value)
|
||||
parameter.Value = value.Id;
|
||||
}
|
||||
|
||||
public override CustomFormat Parse(object value)
|
||||
{
|
||||
Console.WriteLine(value.ToJson());
|
||||
|
||||
if (value is DBNull)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var val = Convert.ToInt32(context.DbValue);
|
||||
var val = Convert.ToInt32(value);
|
||||
|
||||
if (val == 0)
|
||||
{
|
||||
return CustomFormat.None;
|
||||
}
|
||||
|
||||
if (CustomFormatService.AllCustomFormats == null)
|
||||
{
|
||||
throw new Exception("***FATAL*** WE TRIED ACCESSING ALL CUSTOM FORMATS BEFORE IT WAS INITIALIZED. PLEASE SAVE THIS LOG AND OPEN AN ISSUE ON GITHUB.");
|
||||
}
|
||||
|
||||
return CustomFormatService.AllCustomFormats[val];
|
||||
}
|
||||
}
|
||||
|
||||
public object FromDB(ColumnMap map, object dbValue)
|
||||
public class CustomFormatIntConverter : JsonConverter<CustomFormat>
|
||||
{
|
||||
public override CustomFormat Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
return FromDB(new ConverterContext { ColumnMap = map, DbValue = dbValue });
|
||||
}
|
||||
|
||||
public object ToDB(object clrValue)
|
||||
{
|
||||
if(clrValue == DBNull.Value) return null;
|
||||
|
||||
if(!(clrValue is CustomFormat))
|
||||
{
|
||||
throw new InvalidOperationException("Attempted to save a quality definition that isn't really a quality definition");
|
||||
}
|
||||
|
||||
var quality = (CustomFormat) clrValue;
|
||||
|
||||
if (CustomFormatService.AllCustomFormats?.ContainsKey(quality.Id) == false)
|
||||
{
|
||||
//throw new Exception("Attempted to save an unknown custom format! Make sure you do not have stale custom formats lying around!");
|
||||
}
|
||||
|
||||
return quality.Id;
|
||||
}
|
||||
|
||||
public Type DbType => typeof(int);
|
||||
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return objectType == typeof(CustomFormat);
|
||||
}
|
||||
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
{
|
||||
var item = reader.Value;
|
||||
|
||||
var val = Convert.ToInt32(item);
|
||||
var val = reader.GetInt32();
|
||||
|
||||
if (val == 0)
|
||||
{
|
||||
return CustomFormat.None;
|
||||
}
|
||||
|
||||
if (CustomFormatService.AllCustomFormats == null)
|
||||
{
|
||||
throw new Exception("***FATAL*** WE TRIED ACCESSING ALL CUSTOM FORMATS BEFORE IT WAS INITIALIZED. PLEASE SAVE THIS LOG AND OPEN AN ISSUE ON GITHUB.");
|
||||
}
|
||||
|
||||
return CustomFormatService.AllCustomFormats[val];
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
public override void Write(Utf8JsonWriter writer, CustomFormat value, JsonSerializerOptions options)
|
||||
{
|
||||
writer.WriteValue(ToDB(value));
|
||||
writer.WriteNumberValue(value.Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,46 +0,0 @@
|
||||
using System;
|
||||
using Marr.Data.Converters;
|
||||
using Marr.Data.Mapping;
|
||||
|
||||
namespace NzbDrone.Core.Datastore.Converters
|
||||
{
|
||||
public class DoubleConverter : IConverter
|
||||
{
|
||||
public object FromDB(ConverterContext context)
|
||||
{
|
||||
if (context.DbValue == DBNull.Value)
|
||||
{
|
||||
return DBNull.Value;
|
||||
}
|
||||
|
||||
if (context.DbValue is double)
|
||||
{
|
||||
return context.DbValue;
|
||||
}
|
||||
|
||||
return Convert.ToDouble(context.DbValue);
|
||||
}
|
||||
|
||||
public object FromDB(ColumnMap map, object dbValue)
|
||||
{
|
||||
if (dbValue == DBNull.Value)
|
||||
{
|
||||
return DBNull.Value;
|
||||
}
|
||||
|
||||
if (dbValue is double)
|
||||
{
|
||||
return dbValue;
|
||||
}
|
||||
|
||||
return Convert.ToDouble(dbValue);
|
||||
}
|
||||
|
||||
public object ToDB(object clrValue)
|
||||
{
|
||||
return clrValue;
|
||||
}
|
||||
|
||||
public Type DbType { get; private set; }
|
||||
}
|
||||
}
|
@ -1,65 +1,49 @@
|
||||
using System;
|
||||
using Marr.Data.Converters;
|
||||
using Marr.Data.Mapping;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
using Newtonsoft.Json.Converters;
|
||||
using System.Data;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using Dapper;
|
||||
|
||||
namespace NzbDrone.Core.Datastore.Converters
|
||||
{
|
||||
public class EmbeddedDocumentConverter : IConverter
|
||||
public class EmbeddedDocumentConverter<T> : SqlMapper.TypeHandler<T>
|
||||
{
|
||||
private readonly JsonSerializerSettings SerializerSetting;
|
||||
protected readonly JsonSerializerOptions SerializerSettings;
|
||||
|
||||
public EmbeddedDocumentConverter(params JsonConverter[] converters)
|
||||
public EmbeddedDocumentConverter()
|
||||
{
|
||||
SerializerSetting = new JsonSerializerSettings
|
||||
var serializerSettings = new JsonSerializerOptions
|
||||
{
|
||||
DateTimeZoneHandling = DateTimeZoneHandling.Utc,
|
||||
NullValueHandling = NullValueHandling.Ignore,
|
||||
Formatting = Formatting.Indented,
|
||||
DefaultValueHandling = DefaultValueHandling.Include,
|
||||
ContractResolver = new CamelCasePropertyNamesContractResolver()
|
||||
AllowTrailingCommas = true,
|
||||
IgnoreNullValues = false,
|
||||
PropertyNameCaseInsensitive = true,
|
||||
DictionaryKeyPolicy = JsonNamingPolicy.CamelCase,
|
||||
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
||||
WriteIndented = true
|
||||
};
|
||||
|
||||
SerializerSetting.Converters.Add(new StringEnumConverter { NamingStrategy = new CamelCaseNamingStrategy() });
|
||||
SerializerSetting.Converters.Add(new VersionConverter());
|
||||
serializerSettings.Converters.Add(new NoFlagsStringEnumConverter());
|
||||
serializerSettings.Converters.Add(new TimeSpanConverter());
|
||||
serializerSettings.Converters.Add(new UtcConverter());
|
||||
|
||||
SerializerSettings = serializerSettings;
|
||||
}
|
||||
|
||||
public EmbeddedDocumentConverter(params JsonConverter[] converters) : this()
|
||||
{
|
||||
foreach (var converter in converters)
|
||||
{
|
||||
SerializerSetting.Converters.Add(converter);
|
||||
SerializerSettings.Converters.Add(converter);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual object FromDB(ConverterContext context)
|
||||
public override void SetValue(IDbDataParameter parameter, T value)
|
||||
{
|
||||
if (context.DbValue == DBNull.Value)
|
||||
{
|
||||
return DBNull.Value;
|
||||
}
|
||||
|
||||
var stringValue = (string)context.DbValue;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(stringValue))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return JsonConvert.DeserializeObject(stringValue, context.ColumnMap.FieldType, SerializerSetting);
|
||||
parameter.Value = JsonSerializer.Serialize(value, SerializerSettings);
|
||||
}
|
||||
|
||||
public object FromDB(ColumnMap map, object dbValue)
|
||||
public override T Parse(object value)
|
||||
{
|
||||
return FromDB(new ConverterContext { ColumnMap = map, DbValue = dbValue });
|
||||
return JsonSerializer.Deserialize<T>((string) value, SerializerSettings);
|
||||
}
|
||||
|
||||
public object ToDB(object clrValue)
|
||||
{
|
||||
if (clrValue == null) return null;
|
||||
if (clrValue == DBNull.Value) return DBNull.Value;
|
||||
|
||||
return JsonConvert.SerializeObject(clrValue, SerializerSetting);
|
||||
}
|
||||
|
||||
public Type DbType => typeof(string);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,36 +0,0 @@
|
||||
using System;
|
||||
using Marr.Data.Converters;
|
||||
using Marr.Data.Mapping;
|
||||
|
||||
namespace NzbDrone.Core.Datastore.Converters
|
||||
{
|
||||
public class EnumIntConverter : IConverter
|
||||
{
|
||||
public Type DbType => typeof(int);
|
||||
|
||||
public object FromDB(ConverterContext context)
|
||||
{
|
||||
if (context.DbValue != null && context.DbValue != DBNull.Value)
|
||||
{
|
||||
return Enum.ToObject(context.ColumnMap.FieldType, (long)context.DbValue);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public object FromDB(ColumnMap map, object dbValue)
|
||||
{
|
||||
return FromDB(new ConverterContext { ColumnMap = map, DbValue = dbValue });
|
||||
}
|
||||
|
||||
public object ToDB(object clrValue)
|
||||
{
|
||||
if (clrValue != null)
|
||||
{
|
||||
return (int)clrValue;
|
||||
}
|
||||
|
||||
return DBNull.Value;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,40 +1,24 @@
|
||||
using System;
|
||||
using Marr.Data.Converters;
|
||||
using Marr.Data.Mapping;
|
||||
using System.Data;
|
||||
using Dapper;
|
||||
|
||||
namespace NzbDrone.Core.Datastore.Converters
|
||||
{
|
||||
public class GuidConverter : IConverter
|
||||
public class GuidConverter : SqlMapper.TypeHandler<Guid>
|
||||
{
|
||||
public object FromDB(ConverterContext context)
|
||||
public override Guid Parse(object value)
|
||||
{
|
||||
if (context.DbValue == DBNull.Value)
|
||||
if (value == null)
|
||||
{
|
||||
return Guid.Empty;
|
||||
}
|
||||
|
||||
var value = (string)context.DbValue;
|
||||
|
||||
return new Guid(value);
|
||||
return new Guid((string)value);
|
||||
}
|
||||
|
||||
public object FromDB(ColumnMap map, object dbValue)
|
||||
public override void SetValue(IDbDataParameter parameter, Guid value)
|
||||
{
|
||||
return FromDB(new ConverterContext { ColumnMap = map, DbValue = dbValue });
|
||||
parameter.Value = value.ToString();
|
||||
}
|
||||
|
||||
public object ToDB(object clrValue)
|
||||
{
|
||||
if (clrValue == null)
|
||||
{
|
||||
return DBNull.Value;
|
||||
}
|
||||
|
||||
var value = clrValue;
|
||||
|
||||
return value.ToString();
|
||||
}
|
||||
|
||||
public Type DbType => typeof(string);
|
||||
}
|
||||
}
|
||||
|
@ -1,36 +0,0 @@
|
||||
using System;
|
||||
using Marr.Data.Converters;
|
||||
using Marr.Data.Mapping;
|
||||
|
||||
namespace NzbDrone.Core.Datastore.Converters
|
||||
{
|
||||
public class Int32Converter : IConverter
|
||||
{
|
||||
public object FromDB(ConverterContext context)
|
||||
{
|
||||
if (context.DbValue == DBNull.Value)
|
||||
{
|
||||
return DBNull.Value;
|
||||
}
|
||||
|
||||
if (context.DbValue is int)
|
||||
{
|
||||
return context.DbValue;
|
||||
}
|
||||
|
||||
return Convert.ToInt32(context.DbValue);
|
||||
}
|
||||
|
||||
public object FromDB(ColumnMap map, object dbValue)
|
||||
{
|
||||
return FromDB(new ConverterContext { ColumnMap = map, DbValue = dbValue });
|
||||
}
|
||||
|
||||
public object ToDB(object clrValue)
|
||||
{
|
||||
return clrValue;
|
||||
}
|
||||
|
||||
public Type DbType { get; private set; }
|
||||
}
|
||||
}
|
@ -1,65 +1,48 @@
|
||||
using System;
|
||||
using Marr.Data.Converters;
|
||||
using Marr.Data.Mapping;
|
||||
using Newtonsoft.Json;
|
||||
using System.Data;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using Dapper;
|
||||
using NzbDrone.Core.Languages;
|
||||
|
||||
namespace NzbDrone.Core.Datastore.Converters
|
||||
{
|
||||
public class LanguageIntConverter : JsonConverter, IConverter
|
||||
public class DapperLanguageIntConverter : SqlMapper.TypeHandler<Language>
|
||||
{
|
||||
public object FromDB(ConverterContext context)
|
||||
public override void SetValue(IDbDataParameter parameter, Language value)
|
||||
{
|
||||
if (context.DbValue == DBNull.Value)
|
||||
if (value == null)
|
||||
{
|
||||
throw new InvalidOperationException("Attempted to save a language that isn't really a language");
|
||||
}
|
||||
else
|
||||
{
|
||||
parameter.Value = (int) value;
|
||||
}
|
||||
}
|
||||
|
||||
public override Language Parse(object value)
|
||||
{
|
||||
if (value == null || value is DBNull)
|
||||
{
|
||||
return Language.Unknown;
|
||||
}
|
||||
|
||||
var val = Convert.ToInt32(context.DbValue);
|
||||
|
||||
return (Language)val;
|
||||
}
|
||||
|
||||
public object FromDB(ColumnMap map, object dbValue)
|
||||
{
|
||||
return FromDB(new ConverterContext { ColumnMap = map, DbValue = dbValue });
|
||||
}
|
||||
|
||||
public object ToDB(object clrValue)
|
||||
{
|
||||
if (clrValue == DBNull.Value) return 0;
|
||||
|
||||
if (clrValue as Language == null)
|
||||
{
|
||||
throw new InvalidOperationException("Attempted to save a language that isn't really a language");
|
||||
}
|
||||
|
||||
var language = clrValue as Language;
|
||||
return (int)language;
|
||||
}
|
||||
|
||||
public Type DbType
|
||||
{
|
||||
get
|
||||
{
|
||||
return typeof(int);
|
||||
}
|
||||
}
|
||||
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return objectType == typeof(Language);
|
||||
}
|
||||
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
{
|
||||
var item = reader.Value;
|
||||
return (Language)Convert.ToInt32(item);
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
{
|
||||
writer.WriteValue(ToDB(value));
|
||||
return (Language) Convert.ToInt32(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class LanguageIntConverter : JsonConverter<Language>
|
||||
{
|
||||
public override Language Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
var item = reader.GetInt32();
|
||||
return (Language)item;
|
||||
}
|
||||
|
||||
public override void Write(Utf8JsonWriter writer, Language value, JsonSerializerOptions options)
|
||||
{
|
||||
writer.WriteNumberValue((int) value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace NzbDrone.Core.Datastore.Converters
|
||||
{
|
||||
public class NoFlagsStringEnumConverter : JsonConverterFactory
|
||||
{
|
||||
private static JsonStringEnumConverter s_stringEnumConverter = new JsonStringEnumConverter(JsonNamingPolicy.CamelCase, false);
|
||||
|
||||
public override bool CanConvert(Type typeToConvert)
|
||||
=> typeToConvert.IsEnum && !typeToConvert.IsDefined(typeof(FlagsAttribute), inherit: false);
|
||||
|
||||
public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options)
|
||||
=> s_stringEnumConverter.CreateConverter(typeToConvert, options);
|
||||
}
|
||||
}
|
@ -1,36 +1,25 @@
|
||||
using System;
|
||||
using Marr.Data.Converters;
|
||||
using Marr.Data.Mapping;
|
||||
using System.Data;
|
||||
using Dapper;
|
||||
using NzbDrone.Common.Disk;
|
||||
|
||||
namespace NzbDrone.Core.Datastore.Converters
|
||||
{
|
||||
public class OsPathConverter : IConverter
|
||||
public class OsPathConverter : SqlMapper.TypeHandler<OsPath>
|
||||
{
|
||||
public object FromDB(ConverterContext context)
|
||||
public override void SetValue(IDbDataParameter parameter, OsPath value)
|
||||
{
|
||||
if (context.DbValue == DBNull.Value)
|
||||
parameter.Value = value.FullPath;
|
||||
}
|
||||
|
||||
public override OsPath Parse(object value)
|
||||
{
|
||||
if (value == null || value is DBNull)
|
||||
{
|
||||
return DBNull.Value;
|
||||
return new OsPath(null);
|
||||
}
|
||||
|
||||
var value = (string)context.DbValue;
|
||||
|
||||
return new OsPath(value);
|
||||
return new OsPath((string) value);
|
||||
}
|
||||
|
||||
public object FromDB(ColumnMap map, object dbValue)
|
||||
{
|
||||
return FromDB(new ConverterContext { ColumnMap = map, DbValue = dbValue });
|
||||
}
|
||||
|
||||
public object ToDB(object clrValue)
|
||||
{
|
||||
var value = (OsPath)clrValue;
|
||||
|
||||
return value.FullPath;
|
||||
}
|
||||
|
||||
public Type DbType => typeof(string);
|
||||
}
|
||||
}
|
||||
|
@ -1,40 +1,23 @@
|
||||
using System;
|
||||
using Marr.Data.Converters;
|
||||
using NzbDrone.Common.Reflection;
|
||||
using NzbDrone.Common.Serializer;
|
||||
using System.Data;
|
||||
using System.Text.Json;
|
||||
using NzbDrone.Core.ThingiProvider;
|
||||
|
||||
namespace NzbDrone.Core.Datastore.Converters
|
||||
{
|
||||
public class ProviderSettingConverter : EmbeddedDocumentConverter
|
||||
public class ProviderSettingConverter : EmbeddedDocumentConverter<IProviderConfig>
|
||||
{
|
||||
public override object FromDB(ConverterContext context)
|
||||
public override IProviderConfig Parse(object value)
|
||||
{
|
||||
if (context.DbValue == DBNull.Value)
|
||||
{
|
||||
return NullConfig.Instance;
|
||||
}
|
||||
// We can't deserialize based on another column, happens in ProviderRepository instead
|
||||
return null;
|
||||
}
|
||||
|
||||
var stringValue = (string)context.DbValue;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(stringValue))
|
||||
{
|
||||
return NullConfig.Instance;
|
||||
}
|
||||
|
||||
var ordinal = context.DataRecord.GetOrdinal("ConfigContract");
|
||||
var contract = context.DataRecord.GetString(ordinal);
|
||||
|
||||
|
||||
var impType = typeof (IProviderConfig).Assembly.FindTypeByName(contract);
|
||||
|
||||
if (impType == null)
|
||||
{
|
||||
throw new ConfigContractNotFoundException(contract);
|
||||
}
|
||||
|
||||
return Json.Deserialize(stringValue, impType);
|
||||
public override void SetValue(IDbDataParameter parameter, IProviderConfig value)
|
||||
{
|
||||
// Cast to object to get all properties written out
|
||||
// https://github.com/dotnet/corefx/issues/38650
|
||||
parameter.Value = JsonSerializer.Serialize((object)value, SerializerSettings);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,59 +1,37 @@
|
||||
using System;
|
||||
using Marr.Data.Converters;
|
||||
using Marr.Data.Mapping;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using Newtonsoft.Json;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using Dapper;
|
||||
using System.Data;
|
||||
|
||||
namespace NzbDrone.Core.Datastore.Converters
|
||||
{
|
||||
public class QualityIntConverter : JsonConverter, IConverter
|
||||
public class QualityIntConverter : JsonConverter<Quality>
|
||||
{
|
||||
public object FromDB(ConverterContext context)
|
||||
public override Quality Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
if (context.DbValue == DBNull.Value)
|
||||
{
|
||||
return Quality.Unknown;
|
||||
}
|
||||
|
||||
var val = Convert.ToInt32(context.DbValue);
|
||||
|
||||
return (Quality)val;
|
||||
var item = reader.GetInt32();
|
||||
return (Quality)item;
|
||||
}
|
||||
|
||||
public object FromDB(ColumnMap map, object dbValue)
|
||||
public override void Write(Utf8JsonWriter writer, Quality value, JsonSerializerOptions options)
|
||||
{
|
||||
return FromDB(new ConverterContext { ColumnMap = map, DbValue = dbValue });
|
||||
}
|
||||
|
||||
public object ToDB(object clrValue)
|
||||
{
|
||||
if (clrValue == DBNull.Value) return 0;
|
||||
|
||||
if (clrValue as Quality == null)
|
||||
{
|
||||
throw new InvalidOperationException("Attempted to save a quality that isn't really a quality");
|
||||
}
|
||||
|
||||
var quality = clrValue as Quality;
|
||||
return (int)quality;
|
||||
}
|
||||
|
||||
public Type DbType => typeof(int);
|
||||
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return objectType == typeof(Quality);
|
||||
}
|
||||
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
{
|
||||
var item = reader.Value;
|
||||
return (Quality)Convert.ToInt32(item);
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
{
|
||||
writer.WriteValue(ToDB(value));
|
||||
writer.WriteNumberValue((int) value);
|
||||
}
|
||||
}
|
||||
|
||||
public class DapperQualityIntConverter : SqlMapper.TypeHandler<Quality>
|
||||
{
|
||||
public override void SetValue(IDbDataParameter parameter, Quality value)
|
||||
{
|
||||
parameter.Value = value == null ? 0 : (int) value;
|
||||
}
|
||||
|
||||
public override Quality Parse(object value)
|
||||
{
|
||||
return (Quality) Convert.ToInt32(value);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,60 +1,41 @@
|
||||
using System;
|
||||
using Marr.Data.Converters;
|
||||
using Marr.Data.Mapping;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using Newtonsoft.Json;
|
||||
using NzbDrone.Core.CustomFormats;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Text.Json;
|
||||
using Dapper;
|
||||
using System.Data;
|
||||
|
||||
namespace NzbDrone.Core.Datastore.Converters
|
||||
{
|
||||
public class QualityTagStringConverter : JsonConverter, IConverter
|
||||
public class DapperQualityTagStringConverter : SqlMapper.TypeHandler<FormatTag>
|
||||
{
|
||||
public object FromDB(ConverterContext context)
|
||||
public override void SetValue(IDbDataParameter parameter, FormatTag value)
|
||||
{
|
||||
if (context.DbValue == DBNull.Value)
|
||||
parameter.Value = value.Raw;
|
||||
}
|
||||
|
||||
public override FormatTag Parse(object value)
|
||||
{
|
||||
if (value == null || value is DBNull)
|
||||
{
|
||||
return new FormatTag(""); //Will throw argument exception!
|
||||
}
|
||||
|
||||
var val = Convert.ToString(context.DbValue);
|
||||
|
||||
return new FormatTag(val);
|
||||
return new FormatTag(Convert.ToString(value));
|
||||
}
|
||||
}
|
||||
|
||||
public object FromDB(ColumnMap map, object dbValue)
|
||||
public class QualityTagStringConverter : JsonConverter<FormatTag>
|
||||
{
|
||||
public override FormatTag Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
return FromDB(new ConverterContext { ColumnMap = map, DbValue = dbValue });
|
||||
}
|
||||
|
||||
public object ToDB(object clrValue)
|
||||
{
|
||||
if(clrValue == DBNull.Value) return 0;
|
||||
|
||||
if(!(clrValue is FormatTag))
|
||||
{
|
||||
throw new InvalidOperationException("Attempted to save a quality tag that isn't really a quality tag");
|
||||
}
|
||||
|
||||
var quality = (FormatTag) clrValue;
|
||||
return quality.Raw;
|
||||
}
|
||||
|
||||
public Type DbType => typeof(string);
|
||||
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return objectType == typeof(FormatTag);
|
||||
}
|
||||
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
{
|
||||
var item = reader.Value;
|
||||
var item = reader.GetString();
|
||||
return new FormatTag(Convert.ToString(item));
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
public override void Write(Utf8JsonWriter writer, FormatTag value, JsonSerializerOptions options)
|
||||
{
|
||||
writer.WriteValue(ToDB(value));
|
||||
writer.WriteStringValue(value.Raw);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,43 +1,19 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using Marr.Data.Converters;
|
||||
using Marr.Data.Mapping;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace NzbDrone.Core.Datastore.Converters
|
||||
{
|
||||
public class TimeSpanConverter : IConverter
|
||||
public class TimeSpanConverter : JsonConverter<TimeSpan>
|
||||
{
|
||||
public object FromDB(ConverterContext context)
|
||||
public override TimeSpan Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
if (context.DbValue == DBNull.Value)
|
||||
{
|
||||
return TimeSpan.Zero;
|
||||
}
|
||||
|
||||
if (context.DbValue is TimeSpan)
|
||||
{
|
||||
return context.DbValue;
|
||||
}
|
||||
|
||||
return TimeSpan.Parse(context.DbValue.ToString(), CultureInfo.InvariantCulture);
|
||||
return TimeSpan.Parse(reader.GetString());
|
||||
}
|
||||
|
||||
public object FromDB(ColumnMap map, object dbValue)
|
||||
public override void Write(Utf8JsonWriter writer, TimeSpan value, JsonSerializerOptions options)
|
||||
{
|
||||
return FromDB(new ConverterContext { ColumnMap = map, DbValue = dbValue });
|
||||
writer.WriteStringValue(value.ToString());
|
||||
}
|
||||
|
||||
public object ToDB(object clrValue)
|
||||
{
|
||||
if (clrValue.ToString().IsNullOrWhiteSpace())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return ((TimeSpan)clrValue).ToString("c", CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
public Type DbType { get; private set; }
|
||||
}
|
||||
}
|
||||
|
@ -1,32 +1,34 @@
|
||||
using System;
|
||||
using Marr.Data.Converters;
|
||||
using Marr.Data.Mapping;
|
||||
using System;
|
||||
using System.Data;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using Dapper;
|
||||
|
||||
namespace NzbDrone.Core.Datastore.Converters
|
||||
{
|
||||
public class UtcConverter : IConverter
|
||||
public class DapperUtcConverter : SqlMapper.TypeHandler<DateTime>
|
||||
{
|
||||
public object FromDB(ConverterContext context)
|
||||
public override void SetValue(IDbDataParameter parameter, DateTime value)
|
||||
{
|
||||
return context.DbValue;
|
||||
parameter.Value = value.ToUniversalTime();
|
||||
}
|
||||
|
||||
public object FromDB(ColumnMap map, object dbValue)
|
||||
public override DateTime Parse(object value)
|
||||
{
|
||||
return FromDB(new ConverterContext { ColumnMap = map, DbValue = dbValue });
|
||||
return DateTime.SpecifyKind((DateTime)value, DateTimeKind.Utc);
|
||||
}
|
||||
|
||||
public object ToDB(object clrValue)
|
||||
{
|
||||
if (clrValue == DBNull.Value)
|
||||
{
|
||||
return clrValue;
|
||||
}
|
||||
|
||||
var dateTime = (DateTime)clrValue;
|
||||
return dateTime.ToUniversalTime();
|
||||
}
|
||||
|
||||
public Type DbType => typeof(DateTime);
|
||||
}
|
||||
}
|
||||
|
||||
public class UtcConverter : JsonConverter<DateTime>
|
||||
{
|
||||
public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
return DateTime.Parse(reader.GetString());
|
||||
}
|
||||
|
||||
public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
|
||||
{
|
||||
writer.WriteStringValue(value.ToUniversalTime().ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ssZ"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using Marr.Data;
|
||||
using System.Data;
|
||||
using Dapper;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Instrumentation;
|
||||
|
||||
@ -7,7 +8,7 @@ namespace NzbDrone.Core.Datastore
|
||||
{
|
||||
public interface IDatabase
|
||||
{
|
||||
IDataMapper GetDataMapper();
|
||||
IDbConnection OpenConnection();
|
||||
Version Version { get; }
|
||||
int Migration { get; }
|
||||
void Vacuum();
|
||||
@ -16,17 +17,17 @@ public interface IDatabase
|
||||
public class Database : IDatabase
|
||||
{
|
||||
private readonly string _databaseName;
|
||||
private readonly Func<IDataMapper> _datamapperFactory;
|
||||
private readonly Func<IDbConnection> _datamapperFactory;
|
||||
|
||||
private readonly Logger _logger = NzbDroneLogger.GetLogger(typeof(Database));
|
||||
|
||||
public Database(string databaseName, Func<IDataMapper> datamapperFactory)
|
||||
public Database(string databaseName, Func<IDbConnection> datamapperFactory)
|
||||
{
|
||||
_databaseName = databaseName;
|
||||
_datamapperFactory = datamapperFactory;
|
||||
}
|
||||
|
||||
public IDataMapper GetDataMapper()
|
||||
public IDbConnection OpenConnection()
|
||||
{
|
||||
return _datamapperFactory();
|
||||
}
|
||||
@ -37,7 +38,7 @@ public Version Version
|
||||
{
|
||||
using (var db = _datamapperFactory())
|
||||
{
|
||||
var version = db.ExecuteScalar("SELECT sqlite_version()").ToString();
|
||||
var version = db.QueryFirstOrDefault<string>("SELECT sqlite_version()");
|
||||
return new Version(version);
|
||||
}
|
||||
}
|
||||
@ -47,9 +48,10 @@ public int Migration
|
||||
{
|
||||
get
|
||||
{
|
||||
var migration = _datamapperFactory()
|
||||
.ExecuteScalar("SELECT version from VersionInfo ORDER BY version DESC LIMIT 1").ToString();
|
||||
return Convert.ToInt32(migration);
|
||||
using (var db = _datamapperFactory())
|
||||
{
|
||||
return db.QueryFirstOrDefault<int>("SELECT version from VersionInfo ORDER BY version DESC LIMIT 1");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -60,7 +62,7 @@ public void Vacuum()
|
||||
_logger.Info("Vacuuming {0} database", _databaseName);
|
||||
using (var db = _datamapperFactory())
|
||||
{
|
||||
db.ExecuteNonQuery("Vacuum;");
|
||||
db.Execute("Vacuum;");
|
||||
}
|
||||
_logger.Info("{0} database compressed", _databaseName);
|
||||
}
|
||||
|
@ -1,7 +1,5 @@
|
||||
using System;
|
||||
using System.Data.SQLite;
|
||||
using Marr.Data;
|
||||
using Marr.Data.Reflection;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Composition;
|
||||
using NzbDrone.Common.Disk;
|
||||
@ -31,7 +29,6 @@ static DbFactory()
|
||||
{
|
||||
InitializeEnvironment();
|
||||
|
||||
MapRepository.Instance.ReflectionStrategy = new SimpleReflectionStrategy();
|
||||
TableMapping.Map();
|
||||
}
|
||||
|
||||
@ -98,12 +95,11 @@ public IDatabase Create(MigrationContext migrationContext)
|
||||
|
||||
var db = new Database(migrationContext.MigrationType.ToString(), () =>
|
||||
{
|
||||
var dataMapper = new DataMapper(SQLiteFactory.Instance, connectionString)
|
||||
{
|
||||
SqlMode = SqlModes.Text,
|
||||
};
|
||||
var conn = SQLiteFactory.Instance.CreateConnection();
|
||||
conn.ConnectionString = connectionString;
|
||||
conn.Open();
|
||||
|
||||
return dataMapper;
|
||||
return conn;
|
||||
});
|
||||
|
||||
return db;
|
||||
|
146
src/NzbDrone.Core/Datastore/ExpressionVisitor.cs
Normal file
146
src/NzbDrone.Core/Datastore/ExpressionVisitor.cs
Normal file
@ -0,0 +1,146 @@
|
||||
/* This class was copied from Mehfuz's LinqExtender project, which is available from github.
|
||||
* http://mehfuzh.github.com/LinqExtender/
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace NzbDrone.Core.Datastore
|
||||
{
|
||||
///<summary>
|
||||
/// Expression visitor
|
||||
///</summary>
|
||||
public class ExpressionVisitor
|
||||
{
|
||||
/// <summary>
|
||||
/// Visits expression and delegates call to different to branch.
|
||||
/// </summary>
|
||||
/// <param name="expression"></param>
|
||||
/// <returns></returns>
|
||||
protected virtual Expression Visit(Expression expression)
|
||||
{
|
||||
if (expression == null)
|
||||
return null;
|
||||
|
||||
switch (expression.NodeType)
|
||||
{
|
||||
case ExpressionType.Lambda:
|
||||
return VisitLamda((LambdaExpression)expression);
|
||||
case ExpressionType.ArrayLength:
|
||||
case ExpressionType.Convert:
|
||||
case ExpressionType.ConvertChecked:
|
||||
case ExpressionType.Negate:
|
||||
case ExpressionType.UnaryPlus:
|
||||
case ExpressionType.NegateChecked:
|
||||
case ExpressionType.Not:
|
||||
case ExpressionType.Quote:
|
||||
case ExpressionType.TypeAs:
|
||||
return VisitUnary((UnaryExpression)expression);
|
||||
case ExpressionType.Add:
|
||||
case ExpressionType.AddChecked:
|
||||
case ExpressionType.And:
|
||||
case ExpressionType.AndAlso:
|
||||
case ExpressionType.ArrayIndex:
|
||||
case ExpressionType.Coalesce:
|
||||
case ExpressionType.Divide:
|
||||
case ExpressionType.Equal:
|
||||
case ExpressionType.ExclusiveOr:
|
||||
case ExpressionType.GreaterThan:
|
||||
case ExpressionType.GreaterThanOrEqual:
|
||||
case ExpressionType.LeftShift:
|
||||
case ExpressionType.LessThan:
|
||||
case ExpressionType.LessThanOrEqual:
|
||||
case ExpressionType.Modulo:
|
||||
case ExpressionType.Multiply:
|
||||
case ExpressionType.MultiplyChecked:
|
||||
case ExpressionType.NotEqual:
|
||||
case ExpressionType.Or:
|
||||
case ExpressionType.OrElse:
|
||||
case ExpressionType.Power:
|
||||
case ExpressionType.RightShift:
|
||||
case ExpressionType.Subtract:
|
||||
case ExpressionType.SubtractChecked:
|
||||
return VisitBinary((BinaryExpression)expression);
|
||||
case ExpressionType.Call:
|
||||
return VisitMethodCall((MethodCallExpression)expression);
|
||||
case ExpressionType.Constant:
|
||||
return VisitConstant((ConstantExpression)expression);
|
||||
case ExpressionType.MemberAccess:
|
||||
return VisitMemberAccess((MemberExpression)expression);
|
||||
case ExpressionType.Parameter:
|
||||
return VisitParameter((ParameterExpression)expression);
|
||||
|
||||
}
|
||||
throw new ArgumentOutOfRangeException("expression", expression.NodeType.ToString());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Visits the constance expression. To be implemented by user.
|
||||
/// </summary>
|
||||
/// <param name="expression"></param>
|
||||
/// <returns></returns>
|
||||
protected virtual Expression VisitConstant(ConstantExpression expression)
|
||||
{
|
||||
return expression;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Visits the memeber access expression. To be implemented by user.
|
||||
/// </summary>
|
||||
/// <param name="expression"></param>
|
||||
/// <returns></returns>
|
||||
protected virtual Expression VisitMemberAccess(MemberExpression expression)
|
||||
{
|
||||
return expression;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Visits the method call expression. To be implemented by user.
|
||||
/// </summary>
|
||||
/// <param name="expression"></param>
|
||||
/// <returns></returns>
|
||||
protected virtual Expression VisitMethodCall(MethodCallExpression expression)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Visits the binary expression.
|
||||
/// </summary>
|
||||
/// <param name="expression"></param>
|
||||
/// <returns></returns>
|
||||
protected virtual Expression VisitBinary(BinaryExpression expression)
|
||||
{
|
||||
Visit(expression.Left);
|
||||
Visit(expression.Right);
|
||||
return expression;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Visits the unary expression.
|
||||
/// </summary>
|
||||
/// <param name="expression"></param>
|
||||
/// <returns></returns>
|
||||
protected virtual Expression VisitUnary(UnaryExpression expression)
|
||||
{
|
||||
Visit(expression.Operand);
|
||||
return expression;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Visits the lamda expression.
|
||||
/// </summary>
|
||||
/// <param name="lambdaExpression"></param>
|
||||
/// <returns></returns>
|
||||
protected virtual Expression VisitLamda(LambdaExpression lambdaExpression)
|
||||
{
|
||||
Visit(lambdaExpression.Body);
|
||||
return lambdaExpression;
|
||||
}
|
||||
|
||||
private Expression VisitParameter(ParameterExpression expression)
|
||||
{
|
||||
return expression;
|
||||
}
|
||||
}
|
||||
}
|
114
src/NzbDrone.Core/Datastore/Extensions/BuilderExtensions.cs
Normal file
114
src/NzbDrone.Core/Datastore/Extensions/BuilderExtensions.cs
Normal file
@ -0,0 +1,114 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using Dapper;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Common.Serializer;
|
||||
|
||||
namespace NzbDrone.Core.Datastore
|
||||
{
|
||||
public static class SqlBuilderExtensions
|
||||
{
|
||||
public static bool LogSql { get; set; }
|
||||
|
||||
public static SqlBuilder SelectAll(this SqlBuilder builder)
|
||||
{
|
||||
return builder.Select("*");
|
||||
}
|
||||
|
||||
public static SqlBuilder SelectCount(this SqlBuilder builder)
|
||||
{
|
||||
return builder.Select("COUNT(*)");
|
||||
}
|
||||
|
||||
public static SqlBuilder Where<TModel>(this SqlBuilder builder, Expression<Func<TModel, bool>> filter)
|
||||
{
|
||||
var wb = new WhereBuilder(filter);
|
||||
|
||||
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);
|
||||
|
||||
return builder.OrWhere(wb.ToString(), wb.Parameters);
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
Trace.Write(sb.ToString());
|
||||
}
|
||||
|
||||
return template;
|
||||
}
|
||||
|
||||
private static Dictionary<string, object> ToDictionary(this DynamicParameters dynamicParams)
|
||||
{
|
||||
var argsDictionary = new Dictionary<string, object>();
|
||||
var iLookup = (SqlMapper.IParameterLookup) dynamicParams;
|
||||
|
||||
foreach (var paramName in dynamicParams.ParameterNames)
|
||||
{
|
||||
var value = iLookup[paramName];
|
||||
argsDictionary.Add(paramName, value);
|
||||
}
|
||||
|
||||
var templates = dynamicParams.GetType().GetField("templates", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
if (templates != null)
|
||||
{
|
||||
var list = templates.GetValue(dynamicParams) as List<Object>;
|
||||
if (list != null)
|
||||
{
|
||||
foreach (var objProps in list.Select(obj => obj.GetPropertyValuePairs().ToList()))
|
||||
{
|
||||
objProps.ForEach(p => argsDictionary.Add(p.Key, p.Value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return argsDictionary;
|
||||
}
|
||||
|
||||
private static Dictionary<string, object> GetPropertyValuePairs(this object obj, String[] hidden = null)
|
||||
{
|
||||
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))
|
||||
.DistinctBy(propertyInfo => propertyInfo.Name)
|
||||
.ToDictionary(
|
||||
propertyInfo => propertyInfo.Name,
|
||||
propertyInfo => propertyInfo.GetValue(obj, null));
|
||||
return pairs;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,63 +0,0 @@
|
||||
using System.Reflection;
|
||||
using Marr.Data;
|
||||
using Marr.Data.Mapping;
|
||||
using NzbDrone.Common.Reflection;
|
||||
using NzbDrone.Core.ThingiProvider;
|
||||
|
||||
namespace NzbDrone.Core.Datastore.Extensions
|
||||
{
|
||||
public static class MappingExtensions
|
||||
{
|
||||
|
||||
public static ColumnMapBuilder<T> MapResultSet<T>(this FluentMappings.MappingsFluentEntity<T> mapBuilder) where T : ResultSet, new()
|
||||
{
|
||||
return mapBuilder
|
||||
.Columns
|
||||
.AutoMapPropertiesWhere(IsMappableProperty);
|
||||
}
|
||||
|
||||
public static ColumnMapBuilder<T> RegisterDefinition<T>(this FluentMappings.MappingsFluentEntity<T> mapBuilder, string tableName = null) where T : ProviderDefinition, new()
|
||||
{
|
||||
return RegisterModel(mapBuilder, tableName).Ignore(c => c.ImplementationName);
|
||||
}
|
||||
|
||||
public static ColumnMapBuilder<T> RegisterModel<T>(this FluentMappings.MappingsFluentEntity<T> mapBuilder, string tableName = null) where T : ModelBase, new()
|
||||
{
|
||||
return mapBuilder.Table.MapTable(tableName)
|
||||
.Columns
|
||||
.AutoMapPropertiesWhere(IsMappableProperty)
|
||||
.PrefixAltNames(string.Format("{0}_", typeof(T).Name))
|
||||
.For(c => c.Id)
|
||||
.SetPrimaryKey()
|
||||
.SetReturnValue()
|
||||
.SetAutoIncrement();
|
||||
}
|
||||
|
||||
public static RelationshipBuilder<T> AutoMapChildModels<T>(this ColumnMapBuilder<T> mapBuilder)
|
||||
{
|
||||
return mapBuilder.Relationships.AutoMapPropertiesWhere(m =>
|
||||
m.MemberType == MemberTypes.Property &&
|
||||
typeof(ModelBase).IsAssignableFrom(((PropertyInfo) m).PropertyType));
|
||||
}
|
||||
|
||||
public static bool IsMappableProperty(MemberInfo memberInfo)
|
||||
{
|
||||
var propertyInfo = memberInfo as PropertyInfo;
|
||||
|
||||
if (propertyInfo == null) return false;
|
||||
|
||||
|
||||
if (!propertyInfo.IsReadable() || !propertyInfo.IsWritable())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (propertyInfo.PropertyType.IsSimpleType() || MapRepository.Instance.TypeConverters.ContainsKey(propertyInfo.PropertyType))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace NzbDrone.Core.Datastore.Extensions
|
||||
{
|
||||
public static class PagingSpecExtensions
|
||||
{
|
||||
public static Expression<Func<TModel, object>> OrderByClause<TModel>(this PagingSpec<TModel> pagingSpec)
|
||||
{
|
||||
return CreateExpression<TModel>(pagingSpec.SortKey);
|
||||
}
|
||||
|
||||
public static int PagingOffset<TModel>(this PagingSpec<TModel> pagingSpec)
|
||||
{
|
||||
return (pagingSpec.Page - 1)*pagingSpec.PageSize;
|
||||
}
|
||||
|
||||
public static Marr.Data.QGen.SortDirection ToSortDirection<TModel>(this PagingSpec<TModel> pagingSpec)
|
||||
{
|
||||
if (pagingSpec.SortDirection == SortDirection.Descending) return Marr.Data.QGen.SortDirection.Desc;
|
||||
|
||||
return Marr.Data.QGen.SortDirection.Asc;
|
||||
}
|
||||
|
||||
private static Expression<Func<TModel, object>> CreateExpression<TModel>(string propertyName)
|
||||
{
|
||||
Type type = typeof(TModel);
|
||||
ParameterExpression parameterExpression = Expression.Parameter(type, "x");
|
||||
Expression expressionBody = parameterExpression;
|
||||
|
||||
var splitPropertyName = propertyName.Split('.').ToList();
|
||||
|
||||
foreach (var property in splitPropertyName)
|
||||
{
|
||||
expressionBody = Expression.Property(expressionBody, property);
|
||||
}
|
||||
|
||||
expressionBody = Expression.Convert(expressionBody, typeof(object));
|
||||
return Expression.Lambda<Func<TModel, object>>(expressionBody, parameterExpression);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,51 +0,0 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using Marr.Data;
|
||||
using Marr.Data.Mapping;
|
||||
|
||||
namespace NzbDrone.Core.Datastore.Extensions
|
||||
{
|
||||
public static class RelationshipExtensions
|
||||
{
|
||||
public static RelationshipBuilder<TParent> HasOne<TParent, TChild>(this RelationshipBuilder<TParent> relationshipBuilder, Expression<Func<TParent, LazyLoaded<TChild>>> portalExpression, Func<TParent, int> childIdSelector)
|
||||
where TParent : ModelBase
|
||||
where TChild : ModelBase
|
||||
{
|
||||
return relationshipBuilder.For(portalExpression.GetMemberName())
|
||||
.LazyLoad(
|
||||
condition: parent => childIdSelector(parent) > 0,
|
||||
query: (db, parent) =>
|
||||
{
|
||||
var id = childIdSelector(parent);
|
||||
return db.Query<TChild>().Where(c => c.Id == id).SingleOrDefault();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public static RelationshipBuilder<TParent> Relationship<TParent>(this ColumnMapBuilder<TParent> mapBuilder)
|
||||
{
|
||||
return mapBuilder.Relationships.AutoMapComplexTypeProperties<ILazyLoaded>();
|
||||
}
|
||||
|
||||
public static RelationshipBuilder<TParent> HasMany<TParent, TChild>(this RelationshipBuilder<TParent> relationshipBuilder, Expression<Func<TParent, LazyList<TChild>>> portalExpression, Func<TChild, int> parentIdSelector)
|
||||
where TParent : ModelBase
|
||||
where TChild : ModelBase
|
||||
{
|
||||
return relationshipBuilder.For(portalExpression.GetMemberName())
|
||||
.LazyLoad((db, parent) => db.Query<TChild>().Where(c => parentIdSelector(c) == parent.Id).ToList());
|
||||
}
|
||||
|
||||
private static string GetMemberName<T, TMember>(this Expression<Func<T, TMember>> member)
|
||||
{
|
||||
var expression = member.Body as MemberExpression;
|
||||
|
||||
if (expression == null)
|
||||
{
|
||||
expression = (MemberExpression)((UnaryExpression)member.Body).Operand;
|
||||
}
|
||||
|
||||
return expression.Member.Name;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using Marr.Data;
|
||||
|
||||
namespace NzbDrone.Core.Datastore
|
||||
{
|
||||
public class LazyList<T> : LazyLoaded<List<T>>
|
||||
{
|
||||
public LazyList()
|
||||
: this(new List<T>())
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public LazyList(IEnumerable<T> items)
|
||||
: base(new List<T>(items))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public static implicit operator LazyList<T>(List<T> val)
|
||||
{
|
||||
return new LazyList<T>(val);
|
||||
}
|
||||
|
||||
public static implicit operator List<T>(LazyList<T> lazy)
|
||||
{
|
||||
return lazy.Value;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
using System;
|
||||
using Marr.Data;
|
||||
using System.Data;
|
||||
|
||||
namespace NzbDrone.Core.Datastore
|
||||
{
|
||||
@ -17,9 +17,9 @@ public LogDatabase(IDatabase database)
|
||||
_database = database;
|
||||
}
|
||||
|
||||
public IDataMapper GetDataMapper()
|
||||
public IDbConnection OpenConnection()
|
||||
{
|
||||
return _database.GetDataMapper();
|
||||
return _database.OpenConnection();
|
||||
}
|
||||
|
||||
public Version Version => _database.Version;
|
||||
|
@ -1,5 +1,5 @@
|
||||
using System;
|
||||
using Marr.Data;
|
||||
using System.Data;
|
||||
|
||||
namespace NzbDrone.Core.Datastore
|
||||
{
|
||||
@ -17,9 +17,9 @@ public MainDatabase(IDatabase database)
|
||||
_database = database;
|
||||
}
|
||||
|
||||
public IDataMapper GetDataMapper()
|
||||
public IDbConnection OpenConnection()
|
||||
{
|
||||
return _database.GetDataMapper();
|
||||
return _database.OpenConnection();
|
||||
}
|
||||
|
||||
public Version Version => _database.Version;
|
||||
|
@ -26,7 +26,7 @@ protected override void MainDbUpgrade()
|
||||
|
||||
private void ConvertQualityProfiles(IDbConnection conn, IDbTransaction tran)
|
||||
{
|
||||
var qualityProfileItemConverter = new EmbeddedDocumentConverter(new QualityIntConverter());
|
||||
var qualityProfileItemConverter = new EmbeddedDocumentConverter<List<ProfileQualityItem>>(new QualityIntConverter());
|
||||
|
||||
// Convert 'Allowed' column in QualityProfiles from Json List<object> to Json List<int> (int = Quality)
|
||||
using (IDbCommand qualityProfileCmd = conn.CreateCommand())
|
||||
@ -44,13 +44,12 @@ private void ConvertQualityProfiles(IDbConnection conn, IDbTransaction tran)
|
||||
|
||||
var items = Quality.DefaultQualityDefinitions.OrderBy(v => v.Weight).Select(v => new ProfileQualityItem { Quality = v.Quality, Allowed = allowed.Contains(v.Quality) }).ToList();
|
||||
|
||||
var allowedNewJson = qualityProfileItemConverter.ToDB(items);
|
||||
|
||||
using (IDbCommand updateCmd = conn.CreateCommand())
|
||||
{
|
||||
updateCmd.Transaction = tran;
|
||||
updateCmd.CommandText = "UPDATE QualityProfiles SET Items = ? WHERE Id = ?";
|
||||
updateCmd.AddParameter(allowedNewJson);
|
||||
var param = updateCmd.CreateParameter();
|
||||
qualityProfileItemConverter.SetValue(param, items);
|
||||
updateCmd.AddParameter(id);
|
||||
|
||||
updateCmd.ExecuteNonQuery();
|
||||
@ -70,7 +69,7 @@ private void ConvertQualityModels(IDbConnection conn, IDbTransaction tran)
|
||||
|
||||
private void ConvertQualityModel(IDbConnection conn, IDbTransaction tran, string tableName)
|
||||
{
|
||||
var qualityModelConverter = new EmbeddedDocumentConverter(new QualityIntConverter());
|
||||
var qualityModelConverter = new EmbeddedDocumentConverter<DestinationQualityModel036>(new QualityIntConverter());
|
||||
|
||||
using (IDbCommand qualityModelCmd = conn.CreateCommand())
|
||||
{
|
||||
@ -89,17 +88,18 @@ private void ConvertQualityModel(IDbConnection conn, IDbTransaction tran, string
|
||||
continue;
|
||||
}
|
||||
|
||||
var qualityNewJson = qualityModelConverter.ToDB(new DestinationQualityModel036
|
||||
{
|
||||
Quality = sourceQuality.Quality.Id,
|
||||
Proper = sourceQuality.Proper
|
||||
});
|
||||
var qualityNew = new DestinationQualityModel036
|
||||
{
|
||||
Quality = sourceQuality.Quality.Id,
|
||||
Proper = sourceQuality.Proper
|
||||
};
|
||||
|
||||
using (IDbCommand updateCmd = conn.CreateCommand())
|
||||
{
|
||||
updateCmd.Transaction = tran;
|
||||
updateCmd.CommandText = "UPDATE " + tableName + " SET Quality = ? WHERE Quality = ?";
|
||||
updateCmd.AddParameter(qualityNewJson);
|
||||
var param = updateCmd.CreateParameter();
|
||||
qualityModelConverter.SetValue(param, qualityNew);
|
||||
updateCmd.AddParameter(qualityJson);
|
||||
|
||||
updateCmd.ExecuteNonQuery();
|
||||
|
@ -1,9 +1,5 @@
|
||||
using FluentMigrator;
|
||||
using Marr.Data.Mapping;
|
||||
using NzbDrone.Core.Datastore.Migration.Framework;
|
||||
using NzbDrone.Core.Movies;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.Datastore.Extensions;
|
||||
|
||||
namespace NzbDrone.Core.Datastore.Migration
|
||||
{
|
||||
|
@ -1,13 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using FluentMigrator;
|
||||
using Marr.Data.QGen;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Common.Serializer;
|
||||
using System.Data;
|
||||
using FluentMigrator;
|
||||
using NzbDrone.Core.Datastore.Migration.Framework;
|
||||
using NzbDrone.Core.Qualities;
|
||||
|
||||
namespace NzbDrone.Core.Datastore.Migration
|
||||
{
|
||||
|
@ -31,7 +31,7 @@ protected override void MainDbUpgrade()
|
||||
|
||||
private void UpdateLanguage(IDbConnection conn, IDbTransaction tran)
|
||||
{
|
||||
var LanguageConverter = new EmbeddedDocumentConverter(new LanguageIntConverter());
|
||||
var LanguageConverter = new EmbeddedDocumentConverter<List<Language>>(new LanguageIntConverter());
|
||||
|
||||
var profileLanguages = new Dictionary<int, int>();
|
||||
using (IDbCommand getProfileCmd = conn.CreateCommand())
|
||||
@ -77,7 +77,7 @@ private void UpdateLanguage(IDbConnection conn, IDbTransaction tran)
|
||||
|
||||
foreach (var group in movieLanguages.GroupBy(v => v.Value, v => v.Key))
|
||||
{
|
||||
var languageJson = LanguageConverter.ToDB(new List<Language> { Language.FindById(group.Key) });
|
||||
var language = new List<Language> { Language.FindById(group.Key) };
|
||||
|
||||
var movieIds = group.Select(v => v.ToString()).Join(",");
|
||||
|
||||
@ -85,7 +85,8 @@ private void UpdateLanguage(IDbConnection conn, IDbTransaction tran)
|
||||
{
|
||||
updateMovieFilesCmd.Transaction = tran;
|
||||
updateMovieFilesCmd.CommandText = $"UPDATE MovieFiles SET Languages = ? WHERE MovieId IN ({movieIds})";
|
||||
updateMovieFilesCmd.AddParameter(languageJson);
|
||||
var param = updateMovieFilesCmd.CreateParameter();
|
||||
LanguageConverter.SetValue(param, language);
|
||||
|
||||
updateMovieFilesCmd.ExecuteNonQuery();
|
||||
}
|
||||
@ -94,7 +95,8 @@ private void UpdateLanguage(IDbConnection conn, IDbTransaction tran)
|
||||
{
|
||||
updateHistoryCmd.Transaction = tran;
|
||||
updateHistoryCmd.CommandText = $"UPDATE History SET Languages = ? WHERE MovieId IN ({movieIds})";
|
||||
updateHistoryCmd.AddParameter(languageJson);
|
||||
var param = updateHistoryCmd.CreateParameter();
|
||||
LanguageConverter.SetValue(param, language);
|
||||
|
||||
updateHistoryCmd.ExecuteNonQuery();
|
||||
}
|
||||
@ -103,7 +105,8 @@ private void UpdateLanguage(IDbConnection conn, IDbTransaction tran)
|
||||
{
|
||||
updateBlacklistCmd.Transaction = tran;
|
||||
updateBlacklistCmd.CommandText = $"UPDATE Blacklist SET Languages = ? WHERE MovieId IN ({movieIds})";
|
||||
updateBlacklistCmd.AddParameter(languageJson);
|
||||
var param = updateBlacklistCmd.CreateParameter();
|
||||
LanguageConverter.SetValue(param, language);
|
||||
|
||||
updateBlacklistCmd.ExecuteNonQuery();
|
||||
}
|
||||
|
@ -0,0 +1,20 @@
|
||||
using FluentMigrator;
|
||||
using NzbDrone.Core.Datastore.Migration.Framework;
|
||||
|
||||
namespace NzbDrone.Core.Datastore.Migration
|
||||
{
|
||||
[Migration(162)]
|
||||
public class fix_profile_format_default : NzbDroneMigrationBase
|
||||
{
|
||||
protected override void MainDbUpgrade()
|
||||
{
|
||||
// badValue was set as default in 147 but it's invalid JSON
|
||||
// so System.Text.Json refuses to parse it (even though Newtonsoft allows it)
|
||||
var badValue = "[{format:0, allowed:true}]";
|
||||
var defaultValue = "[{\"format\":0, \"allowed\":true}]";
|
||||
Alter.Column("FormatItems").OnTable("Profiles").AsString().WithDefaultValue(defaultValue);
|
||||
|
||||
Update.Table("Profiles").Set(new { FormatItems = defaultValue }).Where( new { FormatItems = badValue });
|
||||
}
|
||||
}
|
||||
}
|
114
src/NzbDrone.Core/Datastore/TableMapper.cs
Normal file
114
src/NzbDrone.Core/Datastore/TableMapper.cs
Normal file
@ -0,0 +1,114 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
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>(this Expression<Func<T, object>> member)
|
||||
{
|
||||
var memberExpression = (member.Body as MemberExpression);
|
||||
if (memberExpression == null)
|
||||
{
|
||||
memberExpression = (member.Body as UnaryExpression).Operand as MemberExpression;
|
||||
}
|
||||
|
||||
return (PropertyInfo) memberExpression.Member;
|
||||
}
|
||||
}
|
||||
|
||||
public class TableMapper
|
||||
{
|
||||
public TableMapper()
|
||||
{
|
||||
IgnoreList = new Dictionary<Type, List<PropertyInfo>>();
|
||||
TableMap = new Dictionary<Type, string>();
|
||||
}
|
||||
|
||||
public Dictionary<Type, List<PropertyInfo>> IgnoreList { get; set; }
|
||||
public Dictionary<Type, string> TableMap { get; set; }
|
||||
|
||||
public ColumnMapper<TEntity> Entity<TEntity>(string tableName)
|
||||
{
|
||||
TableMap.Add(typeof(TEntity), tableName);
|
||||
|
||||
if (IgnoreList.TryGetValue(typeof(TEntity), out var list))
|
||||
{
|
||||
return new ColumnMapper<TEntity>(list);
|
||||
}
|
||||
|
||||
list = new List<PropertyInfo>();
|
||||
IgnoreList[typeof(TEntity)] = list;
|
||||
return new ColumnMapper<TEntity>(list);
|
||||
}
|
||||
|
||||
public List<PropertyInfo> ExcludeProperties(Type x)
|
||||
{
|
||||
return IgnoreList.ContainsKey(x) ? IgnoreList[x] : new List<PropertyInfo>();
|
||||
}
|
||||
|
||||
public string TableNameMapping(Type x)
|
||||
{
|
||||
return TableMap.ContainsKey(x) ? TableMap[x] : null;
|
||||
}
|
||||
}
|
||||
|
||||
public class ColumnMapper<T>
|
||||
{
|
||||
private readonly List<PropertyInfo> _ignoreList;
|
||||
|
||||
public ColumnMapper(List<PropertyInfo> ignoreList)
|
||||
{
|
||||
_ignoreList = ignoreList;
|
||||
}
|
||||
|
||||
public ColumnMapper<T> AutoMapPropertiesWhere(Func<PropertyInfo, bool> predicate)
|
||||
{
|
||||
Type entityType = typeof(T);
|
||||
var properties = entityType.GetProperties();
|
||||
_ignoreList.AddRange(properties.Where(x => !predicate(x)));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public ColumnMapper<T> RegisterModel()
|
||||
{
|
||||
return AutoMapPropertiesWhere(IsMappableProperty);
|
||||
}
|
||||
|
||||
public ColumnMapper<T> Ignore(Expression<Func<T, object>> property)
|
||||
{
|
||||
_ignoreList.Add(property.GetMemberName());
|
||||
return this;
|
||||
}
|
||||
|
||||
public static bool IsMappableProperty(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,148 +1,138 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Marr.Data;
|
||||
using Marr.Data.Mapping;
|
||||
using Dapper;
|
||||
using NzbDrone.Common.Reflection;
|
||||
using NzbDrone.Core.Authentication;
|
||||
using NzbDrone.Core.Blacklisting;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.Datastore.Converters;
|
||||
using NzbDrone.Core.Datastore.Extensions;
|
||||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.Download.Pending;
|
||||
using NzbDrone.Core.Indexers;
|
||||
using NzbDrone.Core.Instrumentation;
|
||||
using NzbDrone.Core.Jobs;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.Profiles.Delay;
|
||||
using NzbDrone.Core.RemotePathMappings;
|
||||
using NzbDrone.Core.Notifications;
|
||||
using NzbDrone.Core.Organizer;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Profiles;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Restrictions;
|
||||
using NzbDrone.Core.RootFolders;
|
||||
using NzbDrone.Core.Tags;
|
||||
using NzbDrone.Core.ThingiProvider;
|
||||
using NzbDrone.Core.Movies;
|
||||
using NzbDrone.Common.Disk;
|
||||
using NzbDrone.Core.Authentication;
|
||||
using NzbDrone.Core.CustomFilters;
|
||||
using NzbDrone.Core.CustomFormats;
|
||||
using NzbDrone.Core.Datastore.Converters;
|
||||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.Download.Pending;
|
||||
using NzbDrone.Core.Extras.Metadata;
|
||||
using NzbDrone.Core.Extras.Metadata.Files;
|
||||
using NzbDrone.Core.Extras.Others;
|
||||
using NzbDrone.Core.Extras.Subtitles;
|
||||
using NzbDrone.Core.Indexers;
|
||||
using NzbDrone.Core.Instrumentation;
|
||||
using NzbDrone.Core.Jobs;
|
||||
using NzbDrone.Core.Languages;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.Messaging.Commands;
|
||||
using NzbDrone.Core.Movies;
|
||||
using NzbDrone.Core.Movies.AlternativeTitles;
|
||||
using NzbDrone.Core.NetImport;
|
||||
using NzbDrone.Core.NetImport.ImportExclusions;
|
||||
using NzbDrone.Core.Movies.AlternativeTitles;
|
||||
using NzbDrone.Core.Languages;
|
||||
using NzbDrone.Core.Notifications;
|
||||
using NzbDrone.Core.Organizer;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Profiles;
|
||||
using NzbDrone.Core.Profiles.Delay;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.RemotePathMappings;
|
||||
using NzbDrone.Core.Restrictions;
|
||||
using NzbDrone.Core.RootFolders;
|
||||
using NzbDrone.Core.Tags;
|
||||
using NzbDrone.Core.ThingiProvider;
|
||||
using static Dapper.SqlMapper;
|
||||
|
||||
namespace NzbDrone.Core.Datastore
|
||||
{
|
||||
public static class TableMapping
|
||||
{
|
||||
private static readonly FluentMappings Mapper = new FluentMappings(true);
|
||||
static TableMapping()
|
||||
{
|
||||
Mapper = new TableMapper();
|
||||
}
|
||||
|
||||
public static TableMapper Mapper { get; private set; }
|
||||
|
||||
public static void Map()
|
||||
{
|
||||
RegisterMappers();
|
||||
|
||||
Mapper.Entity<Config>().RegisterModel("Config");
|
||||
Mapper.Entity<Config>("Config").RegisterModel();
|
||||
|
||||
Mapper.Entity<RootFolder>().RegisterModel("RootFolders")
|
||||
Mapper.Entity<RootFolder>("RootFolders").RegisterModel()
|
||||
.Ignore(r => r.Accessible)
|
||||
.Ignore(r => r.FreeSpace)
|
||||
.Ignore(r => r.TotalSpace);
|
||||
|
||||
Mapper.Entity<ScheduledTask>().RegisterModel("ScheduledTasks");
|
||||
Mapper.Entity<ScheduledTask>("ScheduledTasks").RegisterModel();
|
||||
|
||||
Mapper.Entity<IndexerDefinition>().RegisterDefinition("Indexers")
|
||||
Mapper.Entity<IndexerDefinition>("Indexers").RegisterModel()
|
||||
.Ignore(x => x.ImplementationName)
|
||||
.Ignore(i => i.Enable)
|
||||
.Ignore(i => i.Protocol)
|
||||
.Ignore(i => i.SupportsRss)
|
||||
.Ignore(i => i.SupportsSearch)
|
||||
.Ignore(d => d.Tags);
|
||||
|
||||
Mapper.Entity<NetImportDefinition>().RegisterDefinition("NetImport")
|
||||
.Ignore(i => i.Enable)
|
||||
.Relationship()
|
||||
.HasOne(n => n.Profile, n => n.ProfileId);
|
||||
Mapper.Entity<NetImportDefinition>("NetImport").RegisterModel()
|
||||
.Ignore(x => x.ImplementationName)
|
||||
.Ignore(i => i.Enable);
|
||||
|
||||
Mapper.Entity<NotificationDefinition>().RegisterDefinition("Notifications")
|
||||
Mapper.Entity<NotificationDefinition>("Notifications").RegisterModel()
|
||||
.Ignore(x => x.ImplementationName)
|
||||
.Ignore(i => i.SupportsOnGrab)
|
||||
.Ignore(i => i.SupportsOnDownload)
|
||||
.Ignore(i => i.SupportsOnUpgrade)
|
||||
.Ignore(i => i.SupportsOnRename)
|
||||
.Ignore(i => i.SupportsOnHealthIssue);
|
||||
|
||||
Mapper.Entity<MetadataDefinition>().RegisterDefinition("Metadata")
|
||||
Mapper.Entity<MetadataDefinition>("Metadata").RegisterModel()
|
||||
.Ignore(x => x.ImplementationName)
|
||||
.Ignore(d => d.Tags);
|
||||
|
||||
Mapper.Entity<DownloadClientDefinition>().RegisterDefinition("DownloadClients")
|
||||
Mapper.Entity<DownloadClientDefinition>("DownloadClients").RegisterModel()
|
||||
.Ignore(x => x.ImplementationName)
|
||||
.Ignore(d => d.Protocol)
|
||||
.Ignore(d => d.Tags);
|
||||
|
||||
Mapper.Entity<History.History>().RegisterModel("History")
|
||||
.AutoMapChildModels();
|
||||
Mapper.Entity<History.History>("History").RegisterModel();
|
||||
|
||||
Mapper.Entity<MovieFile>().RegisterModel("MovieFiles")
|
||||
.Ignore(f => f.Path)
|
||||
.Relationships.AutoMapICollectionOrComplexProperties()
|
||||
.For("Movie")
|
||||
.LazyLoad(condition: parent => parent.Id > 0,
|
||||
query: (db, parent) => db.Query<Movie>().Where(c => c.MovieFileId == parent.Id).ToList())
|
||||
.HasOne(file => file.Movie, file => file.MovieId);
|
||||
Mapper.Entity<MovieFile>("MovieFiles").RegisterModel()
|
||||
.Ignore(f => f.Path);
|
||||
|
||||
Mapper.Entity<Movie>().RegisterModel("Movies")
|
||||
.Ignore(s => s.RootFolderPath)
|
||||
.Ignore(m => m.Actors)
|
||||
.Relationship()
|
||||
.HasOne(s => s.Profile, s => s.ProfileId);
|
||||
//.HasOne(m => m.MovieFile, m => m.MovieFileId);
|
||||
Mapper.Entity<Movie>("Movies").RegisterModel()
|
||||
.Ignore(s => s.RootFolderPath)
|
||||
.Ignore(m => m.Actors);
|
||||
|
||||
Mapper.Entity<AlternativeTitle>().RegisterModel("AlternativeTitles")
|
||||
.For(t => t.Id)
|
||||
.SetAltName("AltTitle_Id")
|
||||
.Relationship()
|
||||
.HasOne(t => t.Movie, t => t.MovieId);
|
||||
Mapper.Entity<AlternativeTitle>("AlternativeTitles").RegisterModel();
|
||||
|
||||
Mapper.Entity<ImportExclusion>("ImportExclusions").RegisterModel();
|
||||
|
||||
Mapper.Entity<ImportExclusion>().RegisterModel("ImportExclusions");
|
||||
Mapper.Entity<QualityDefinition>("QualityDefinitions").RegisterModel()
|
||||
.Ignore(d => d.GroupName)
|
||||
.Ignore(d => d.Weight);
|
||||
|
||||
Mapper.Entity<QualityDefinition>().RegisterModel("QualityDefinitions")
|
||||
.Ignore(d => d.GroupName)
|
||||
.Ignore(d => d.Weight)
|
||||
.Relationship();
|
||||
Mapper.Entity<CustomFormatDefinition>("CustomFormats").RegisterModel();
|
||||
|
||||
Mapper.Entity<CustomFormat>().RegisterModel("CustomFormats")
|
||||
.Relationship();
|
||||
Mapper.Entity<Profile>("Profiles").RegisterModel();
|
||||
Mapper.Entity<Log>("Logs").RegisterModel();
|
||||
Mapper.Entity<NamingConfig>("NamingConfig").RegisterModel();
|
||||
Mapper.Entity<Blacklist>("Blacklist").RegisterModel();
|
||||
Mapper.Entity<MetadataFile>("MetadataFiles").RegisterModel();
|
||||
Mapper.Entity<SubtitleFile>("SubtitleFiles").RegisterModel();
|
||||
Mapper.Entity<OtherExtraFile>("ExtraFiles").RegisterModel();
|
||||
|
||||
Mapper.Entity<Profile>().RegisterModel("Profiles");
|
||||
Mapper.Entity<Log>().RegisterModel("Logs");
|
||||
Mapper.Entity<NamingConfig>().RegisterModel("NamingConfig");
|
||||
Mapper.Entity<Blacklist>().RegisterModel("Blacklist");
|
||||
Mapper.Entity<MetadataFile>().RegisterModel("MetadataFiles");
|
||||
Mapper.Entity<SubtitleFile>().RegisterModel("SubtitleFiles");
|
||||
Mapper.Entity<OtherExtraFile>().RegisterModel("ExtraFiles");
|
||||
|
||||
Mapper.Entity<PendingRelease>().RegisterModel("PendingReleases")
|
||||
Mapper.Entity<PendingRelease>("PendingReleases").RegisterModel()
|
||||
.Ignore(e => e.RemoteMovie);
|
||||
|
||||
Mapper.Entity<RemotePathMapping>().RegisterModel("RemotePathMappings");
|
||||
Mapper.Entity<Tag>().RegisterModel("Tags");
|
||||
Mapper.Entity<Restriction>().RegisterModel("Restrictions");
|
||||
Mapper.Entity<RemotePathMapping>("RemotePathMappings").RegisterModel();
|
||||
Mapper.Entity<Tag>("Tags").RegisterModel();
|
||||
Mapper.Entity<Restriction>("Restrictions").RegisterModel();
|
||||
|
||||
Mapper.Entity<DelayProfile>().RegisterModel("DelayProfiles");
|
||||
Mapper.Entity<User>().RegisterModel("Users");
|
||||
Mapper.Entity<CommandModel>().RegisterModel("Commands")
|
||||
.Ignore(c => c.Message);
|
||||
Mapper.Entity<DelayProfile>("DelayProfiles").RegisterModel();
|
||||
Mapper.Entity<User>("Users").RegisterModel();
|
||||
Mapper.Entity<CommandModel>("Commands").RegisterModel()
|
||||
.Ignore(c => c.Message);
|
||||
|
||||
Mapper.Entity<IndexerStatus>().RegisterModel("IndexerStatus");
|
||||
Mapper.Entity<DownloadClientStatus>().RegisterModel("DownloadClientStatus");
|
||||
Mapper.Entity<IndexerStatus>("IndexerStatus").RegisterModel();
|
||||
Mapper.Entity<DownloadClientStatus>("DownloadClientStatus").RegisterModel();
|
||||
|
||||
Mapper.Entity<CustomFilter>().RegisterModel("CustomFilters");
|
||||
Mapper.Entity<CustomFilter>("CustomFilters").RegisterModel();
|
||||
}
|
||||
|
||||
private static void RegisterMappers()
|
||||
@ -150,32 +140,30 @@ private static void RegisterMappers()
|
||||
RegisterEmbeddedConverter();
|
||||
RegisterProviderSettingConverter();
|
||||
|
||||
MapRepository.Instance.RegisterTypeConverter(typeof(int), new Int32Converter());
|
||||
MapRepository.Instance.RegisterTypeConverter(typeof(double), new DoubleConverter());
|
||||
MapRepository.Instance.RegisterTypeConverter(typeof(DateTime), new UtcConverter());
|
||||
MapRepository.Instance.RegisterTypeConverter(typeof(bool), new BooleanIntConverter());
|
||||
MapRepository.Instance.RegisterTypeConverter(typeof(Enum), new EnumIntConverter());
|
||||
MapRepository.Instance.RegisterTypeConverter(typeof(Quality), new QualityIntConverter());
|
||||
MapRepository.Instance.RegisterTypeConverter(typeof(CustomFormat), new CustomFormatIntConverter());
|
||||
MapRepository.Instance.RegisterTypeConverter(typeof(List<ProfileQualityItem>), new EmbeddedDocumentConverter(new QualityIntConverter()));
|
||||
MapRepository.Instance.RegisterTypeConverter(typeof(List<ProfileFormatItem>), new EmbeddedDocumentConverter(new CustomFormatIntConverter()));
|
||||
MapRepository.Instance.RegisterTypeConverter(typeof(List<FormatTag>), new EmbeddedDocumentConverter(new QualityTagStringConverter()));
|
||||
MapRepository.Instance.RegisterTypeConverter(typeof(QualityModel), new EmbeddedDocumentConverter(new CustomFormatIntConverter(), new QualityIntConverter()));
|
||||
MapRepository.Instance.RegisterTypeConverter(typeof(Dictionary<string, string>), new EmbeddedDocumentConverter());
|
||||
MapRepository.Instance.RegisterTypeConverter(typeof(IDictionary<string, string>), new EmbeddedDocumentConverter());
|
||||
MapRepository.Instance.RegisterTypeConverter(typeof(List<int>), new EmbeddedDocumentConverter());
|
||||
MapRepository.Instance.RegisterTypeConverter(typeof(List<KeyValuePair<string, int>>), new EmbeddedDocumentConverter());
|
||||
MapRepository.Instance.RegisterTypeConverter(typeof(Language), new LanguageIntConverter());
|
||||
MapRepository.Instance.RegisterTypeConverter(typeof(List<Language>), new EmbeddedDocumentConverter(new LanguageIntConverter()));
|
||||
MapRepository.Instance.RegisterTypeConverter(typeof(List<string>), new EmbeddedDocumentConverter());
|
||||
MapRepository.Instance.RegisterTypeConverter(typeof(ParsedMovieInfo), new EmbeddedDocumentConverter());
|
||||
MapRepository.Instance.RegisterTypeConverter(typeof(ReleaseInfo), new EmbeddedDocumentConverter());
|
||||
MapRepository.Instance.RegisterTypeConverter(typeof(HashSet<int>), new EmbeddedDocumentConverter());
|
||||
MapRepository.Instance.RegisterTypeConverter(typeof(OsPath), new OsPathConverter());
|
||||
MapRepository.Instance.RegisterTypeConverter(typeof(Guid), new GuidConverter());
|
||||
MapRepository.Instance.RegisterTypeConverter(typeof(Command), new CommandConverter());
|
||||
MapRepository.Instance.RegisterTypeConverter(typeof(TimeSpan), new TimeSpanConverter());
|
||||
MapRepository.Instance.RegisterTypeConverter(typeof(TimeSpan?), new TimeSpanConverter());
|
||||
SqlMapper.RemoveTypeMap(typeof(DateTime));
|
||||
SqlMapper.AddTypeHandler(new DapperUtcConverter());
|
||||
SqlMapper.AddTypeHandler(new DapperQualityIntConverter());
|
||||
SqlMapper.AddTypeHandler(new DapperCustomFormatIntConverter());
|
||||
SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter<List<ProfileQualityItem>>(new QualityIntConverter()));
|
||||
SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter<List<ProfileFormatItem>>(new CustomFormatIntConverter()));
|
||||
SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter<List<FormatTag>>(new QualityTagStringConverter()));
|
||||
SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter<QualityModel>(new CustomFormatIntConverter(), new QualityIntConverter()));
|
||||
SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter<Dictionary<string, string>>());
|
||||
SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter<IDictionary<string, string>>());
|
||||
SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter<List<int>>());
|
||||
SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter<List<KeyValuePair<string, int>>>());
|
||||
SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter<KeyValuePair<string, int>>());
|
||||
SqlMapper.AddTypeHandler(new DapperLanguageIntConverter());
|
||||
SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter<List<Language>>(new LanguageIntConverter()));
|
||||
SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter<List<string>>());
|
||||
SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter<ParsedMovieInfo>());
|
||||
SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter<ReleaseInfo>());
|
||||
SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter<HashSet<int>>());
|
||||
SqlMapper.AddTypeHandler(new OsPathConverter());
|
||||
SqlMapper.RemoveTypeMap(typeof(Guid));
|
||||
SqlMapper.RemoveTypeMap(typeof(Guid?));
|
||||
SqlMapper.AddTypeHandler(new GuidConverter());
|
||||
SqlMapper.AddTypeHandler(new CommandConverter());
|
||||
}
|
||||
|
||||
private static void RegisterProviderSettingConverter()
|
||||
@ -185,7 +173,7 @@ private static void RegisterProviderSettingConverter()
|
||||
var providerSettingConverter = new ProviderSettingConverter();
|
||||
foreach (var embeddedType in settingTypes)
|
||||
{
|
||||
MapRepository.Instance.RegisterTypeConverter(embeddedType, providerSettingConverter);
|
||||
SqlMapper.AddTypeHandler(embeddedType, providerSettingConverter);
|
||||
}
|
||||
}
|
||||
|
||||
@ -193,16 +181,24 @@ private static void RegisterEmbeddedConverter()
|
||||
{
|
||||
var embeddedTypes = typeof(IEmbeddedDocument).Assembly.ImplementationsOf<IEmbeddedDocument>();
|
||||
|
||||
var embeddedConvertor = new EmbeddedDocumentConverter();
|
||||
var embeddedConverterDefinition = typeof(EmbeddedDocumentConverter<>).GetGenericTypeDefinition();
|
||||
var genericListDefinition = typeof(List<>).GetGenericTypeDefinition();
|
||||
|
||||
foreach (var embeddedType in embeddedTypes)
|
||||
{
|
||||
var embeddedListType = genericListDefinition.MakeGenericType(embeddedType);
|
||||
|
||||
MapRepository.Instance.RegisterTypeConverter(embeddedType, embeddedConvertor);
|
||||
MapRepository.Instance.RegisterTypeConverter(embeddedListType, embeddedConvertor);
|
||||
RegisterEmbeddedConverter(embeddedType, embeddedConverterDefinition);
|
||||
RegisterEmbeddedConverter(embeddedListType, embeddedConverterDefinition);
|
||||
}
|
||||
}
|
||||
|
||||
private static void RegisterEmbeddedConverter(Type embeddedType, Type embeddedConverterDefinition)
|
||||
{
|
||||
var embeddedConverterType = embeddedConverterDefinition.MakeGenericType(embeddedType);
|
||||
var converter = (ITypeHandler) Activator.CreateInstance(embeddedConverterType);
|
||||
|
||||
SqlMapper.AddTypeHandler(embeddedType, converter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
303
src/NzbDrone.Core/Datastore/WhereBuilder.cs
Normal file
303
src/NzbDrone.Core/Datastore/WhereBuilder.cs
Normal file
@ -0,0 +1,303 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using Dapper;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace NzbDrone.Core.Datastore
|
||||
{
|
||||
public class WhereBuilder : ExpressionVisitor
|
||||
{
|
||||
private const DbType EnumerableMultiParameter = (DbType)(-1);
|
||||
|
||||
private readonly string _paramNamePrefix;
|
||||
private int _paramCount = 0;
|
||||
protected StringBuilder _sb;
|
||||
|
||||
public DynamicParameters Parameters { get; private set; }
|
||||
|
||||
public WhereBuilder(Expression filter)
|
||||
{
|
||||
_paramNamePrefix = Guid.NewGuid().ToString().Replace("-", "_");
|
||||
Parameters = new DynamicParameters();
|
||||
_sb = new StringBuilder();
|
||||
|
||||
if (filter != null)
|
||||
{
|
||||
base.Visit(filter);
|
||||
}
|
||||
}
|
||||
|
||||
private string AddParameter(object value, DbType? dbType = null)
|
||||
{
|
||||
_paramCount++;
|
||||
var name = _paramNamePrefix + "_P" + _paramCount;
|
||||
Parameters.Add(name, value, dbType);
|
||||
return '@' + name;
|
||||
}
|
||||
|
||||
protected override Expression VisitBinary(BinaryExpression expression)
|
||||
{
|
||||
_sb.Append("(");
|
||||
|
||||
Visit(expression.Left);
|
||||
|
||||
_sb.AppendFormat(" {0} ", Decode(expression));
|
||||
|
||||
Visit(expression.Right);
|
||||
|
||||
_sb.Append(")");
|
||||
|
||||
return expression;
|
||||
}
|
||||
|
||||
protected override Expression VisitMethodCall(MethodCallExpression expression)
|
||||
{
|
||||
string method = expression.Method.Name;
|
||||
|
||||
switch (expression.Method.Name)
|
||||
{
|
||||
case "Contains":
|
||||
ParseContainsExpression(expression);
|
||||
break;
|
||||
|
||||
case "StartsWith":
|
||||
ParseStartsWith(expression);
|
||||
break;
|
||||
|
||||
case "EndsWith":
|
||||
ParseEndsWith(expression);
|
||||
break;
|
||||
|
||||
default:
|
||||
string msg = string.Format("'{0}' expressions are not yet implemented in the where clause expression tree parser.", method);
|
||||
throw new NotImplementedException(msg);
|
||||
}
|
||||
|
||||
return expression;
|
||||
}
|
||||
|
||||
|
||||
protected override Expression VisitMemberAccess(MemberExpression expression)
|
||||
{
|
||||
string tableName = TableMapping.Mapper.TableNameMapping(expression.Expression.Type);
|
||||
|
||||
if (tableName != null)
|
||||
{
|
||||
_sb.Append($"\"{tableName}\".\"{expression.Member.Name}\"");
|
||||
}
|
||||
else
|
||||
{
|
||||
object value = GetRightValue(expression);
|
||||
|
||||
// string is IEnumerable<Char> but we don't want to pick up that case
|
||||
var type = value.GetType();
|
||||
var typeInfo = type.GetTypeInfo();
|
||||
bool isEnumerable =
|
||||
type != typeof(string) && (
|
||||
typeInfo.ImplementedInterfaces.Any(ti => ti.IsGenericType && ti.GetGenericTypeDefinition() == typeof(IEnumerable<>)) ||
|
||||
(typeInfo.IsGenericType && typeInfo.GetGenericTypeDefinition() == typeof(IEnumerable<>))
|
||||
);
|
||||
|
||||
string paramName;
|
||||
if (isEnumerable)
|
||||
{
|
||||
paramName = AddParameter(value, EnumerableMultiParameter);
|
||||
}
|
||||
else
|
||||
{
|
||||
paramName = AddParameter(value);
|
||||
}
|
||||
|
||||
_sb.Append(paramName);
|
||||
}
|
||||
|
||||
return expression;
|
||||
}
|
||||
|
||||
protected override Expression VisitConstant(ConstantExpression expression)
|
||||
{
|
||||
if (expression.Value != null)
|
||||
{
|
||||
string paramName = AddParameter(expression.Value);
|
||||
_sb.Append(paramName);
|
||||
}
|
||||
else
|
||||
{
|
||||
_sb.Append("NULL");
|
||||
}
|
||||
|
||||
return expression;
|
||||
}
|
||||
|
||||
private object GetRightValue(Expression rightExpression)
|
||||
{
|
||||
object rightValue = null;
|
||||
|
||||
var right = rightExpression as ConstantExpression;
|
||||
if (right == null) // Value is not directly passed in as a constant
|
||||
{
|
||||
var rightMemberExp = (rightExpression as MemberExpression);
|
||||
var parentMemberExpression = rightMemberExp.Expression as MemberExpression;
|
||||
if (parentMemberExpression != null) // Value is passed in as a property on a parent entity
|
||||
{
|
||||
var memberInfo = (rightMemberExp.Expression as MemberExpression).Member;
|
||||
var container = ((rightMemberExp.Expression as MemberExpression).Expression as ConstantExpression).Value;
|
||||
var entity = GetFieldValue(container, memberInfo);
|
||||
rightValue = GetFieldValue(entity, rightMemberExp.Member);
|
||||
}
|
||||
else // Value is passed in as a variable
|
||||
{
|
||||
var parent = (rightMemberExp.Expression as ConstantExpression).Value;
|
||||
rightValue = GetFieldValue(parent, rightMemberExp.Member);
|
||||
}
|
||||
}
|
||||
else // Value is passed in directly as a constant
|
||||
{
|
||||
rightValue = right.Value;
|
||||
}
|
||||
|
||||
return rightValue;
|
||||
}
|
||||
|
||||
private object GetFieldValue(object entity, MemberInfo member)
|
||||
{
|
||||
if (member.MemberType == MemberTypes.Field)
|
||||
{
|
||||
return (member as FieldInfo).GetValue(entity);
|
||||
}
|
||||
if (member.MemberType == MemberTypes.Property)
|
||||
{
|
||||
return (member as PropertyInfo).GetValue(entity);
|
||||
}
|
||||
|
||||
throw new ArgumentException(string.Format("WhereBuilder could not get the value for {0}.{1}.", entity.GetType().Name, member.Name));
|
||||
}
|
||||
|
||||
private string Decode(BinaryExpression expression)
|
||||
{
|
||||
bool isRightSideNullConstant = expression.Right.NodeType ==
|
||||
ExpressionType.Constant &&
|
||||
((ConstantExpression)expression.Right).Value == null;
|
||||
|
||||
if (isRightSideNullConstant)
|
||||
{
|
||||
switch (expression.NodeType)
|
||||
{
|
||||
case ExpressionType.Equal: return "IS";
|
||||
case ExpressionType.NotEqual: return "IS NOT";
|
||||
}
|
||||
}
|
||||
|
||||
switch (expression.NodeType)
|
||||
{
|
||||
case ExpressionType.AndAlso: return "AND";
|
||||
case ExpressionType.And: return "AND";
|
||||
case ExpressionType.Equal: return "=";
|
||||
case ExpressionType.GreaterThan: return ">";
|
||||
case ExpressionType.GreaterThanOrEqual: return ">=";
|
||||
case ExpressionType.LessThan: return "<";
|
||||
case ExpressionType.LessThanOrEqual: return "<=";
|
||||
case ExpressionType.NotEqual: return "<>";
|
||||
case ExpressionType.OrElse: return "OR";
|
||||
case ExpressionType.Or: return "OR";
|
||||
default: throw new NotSupportedException(string.Format("{0} statement is not supported", expression.NodeType.ToString()));
|
||||
}
|
||||
}
|
||||
|
||||
private void ParseContainsExpression(MethodCallExpression expression)
|
||||
{
|
||||
var list = expression.Object;
|
||||
|
||||
if (list != null && list.Type == typeof(string))
|
||||
{
|
||||
ParseStringContains(expression);
|
||||
return;
|
||||
}
|
||||
|
||||
ParseEnumerableContains(expression);
|
||||
}
|
||||
|
||||
private void ParseEnumerableContains(MethodCallExpression body)
|
||||
{
|
||||
// Fish out the list and the item to compare
|
||||
// It's in a different form for arrays and Lists
|
||||
var list = body.Object;
|
||||
Expression item;
|
||||
|
||||
if (list != null)
|
||||
{
|
||||
// Generic collection
|
||||
item = body.Arguments[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Static method
|
||||
// Must be Enumerable.Contains(source, item)
|
||||
if (body.Method.DeclaringType != typeof(Enumerable) || body.Arguments.Count != 2)
|
||||
{
|
||||
throw new NotSupportedException("Unexpected form of Enumerable.Contains");
|
||||
}
|
||||
list = body.Arguments[0];
|
||||
item = body.Arguments[1];
|
||||
}
|
||||
|
||||
_sb.Append("(");
|
||||
|
||||
Visit(item);
|
||||
|
||||
_sb.Append(" IN ");
|
||||
|
||||
Visit(list);
|
||||
|
||||
_sb.Append(")");
|
||||
}
|
||||
|
||||
private void ParseStringContains(MethodCallExpression body)
|
||||
{
|
||||
_sb.Append("(");
|
||||
|
||||
Visit(body.Object);
|
||||
|
||||
_sb.Append(" LIKE '%' || ");
|
||||
|
||||
Visit(body.Arguments[0]);
|
||||
|
||||
_sb.Append(" || '%')");
|
||||
}
|
||||
|
||||
private void ParseStartsWith(MethodCallExpression body)
|
||||
{
|
||||
_sb.Append("(");
|
||||
|
||||
Visit(body.Object);
|
||||
|
||||
_sb.Append(" LIKE ");
|
||||
|
||||
Visit(body.Arguments[0]);
|
||||
|
||||
_sb.Append(" || '%')");
|
||||
}
|
||||
|
||||
private void ParseEndsWith(MethodCallExpression body)
|
||||
{
|
||||
_sb.Append("(");
|
||||
|
||||
Visit(body.Object);
|
||||
|
||||
_sb.Append(" LIKE '%' || ");
|
||||
|
||||
Visit(body.Arguments[0]);
|
||||
|
||||
_sb.Append(")");
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return _sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
@ -62,7 +62,7 @@ private int CompareAll(params int[] comparers)
|
||||
|
||||
private int CompareQuality(DownloadDecision x, DownloadDecision y)
|
||||
{
|
||||
return CompareAll(CompareBy(x.RemoteMovie, y.RemoteMovie, remoteMovie => remoteMovie.Movie.Profile.Value.GetIndex(remoteMovie.ParsedMovieInfo.Quality.Quality)),
|
||||
return CompareAll(CompareBy(x.RemoteMovie, y.RemoteMovie, remoteMovie => remoteMovie.Movie.Profile.GetIndex(remoteMovie.ParsedMovieInfo.Quality.Quality)),
|
||||
CompareCustomFormats(x, y),
|
||||
CompareBy(x.RemoteMovie, y.RemoteMovie, remoteMovie => remoteMovie.ParsedMovieInfo.Quality.Revision.Real),
|
||||
CompareBy(x.RemoteMovie, y.RemoteMovie, remoteMovie => remoteMovie.ParsedMovieInfo.Quality.Revision.Version));
|
||||
@ -73,8 +73,8 @@ private int CompareCustomFormats(DownloadDecision x, DownloadDecision y)
|
||||
var left = x.RemoteMovie.ParsedMovieInfo.Quality.CustomFormats.WithNone();
|
||||
var right = y.RemoteMovie.ParsedMovieInfo.Quality.CustomFormats;
|
||||
|
||||
var leftIndicies = QualityModelComparer.GetIndicies(left, x.RemoteMovie.Movie.Profile.Value);
|
||||
var rightIndicies = QualityModelComparer.GetIndicies(right, y.RemoteMovie.Movie.Profile.Value);
|
||||
var leftIndicies = QualityModelComparer.GetIndicies(left, x.RemoteMovie.Movie.Profile);
|
||||
var rightIndicies = QualityModelComparer.GetIndicies(right, y.RemoteMovie.Movie.Profile);
|
||||
|
||||
var leftTotal = leftIndicies.Sum();
|
||||
var rightTotal = rightIndicies.Sum();
|
||||
@ -87,8 +87,7 @@ private int ComparePreferredWords(DownloadDecision x, DownloadDecision y)
|
||||
return CompareBy(x.RemoteMovie, y.RemoteMovie, remoteMovie =>
|
||||
{
|
||||
var title = remoteMovie.Release.Title;
|
||||
remoteMovie.Movie.Profile.LazyLoad();
|
||||
var preferredWords = remoteMovie.Movie.Profile.Value.PreferredTags;
|
||||
var preferredWords = remoteMovie.Movie.Profile.PreferredTags;
|
||||
|
||||
if (preferredWords == null)
|
||||
{
|
||||
|
@ -22,7 +22,7 @@ public virtual Decision IsSatisfiedBy(RemoteMovie subject, SearchCriteriaBase se
|
||||
{
|
||||
var formats = subject.ParsedMovieInfo.Quality.CustomFormats.WithNone();
|
||||
_logger.Debug("Checking if report meets custom format requirements. {0}", formats.ToExtendedString());
|
||||
var notAllowedFormats = subject.Movie.Profile.Value.FormatItems.Where(v => v.Allowed == false).Select(f => f.Format).ToList();
|
||||
var notAllowedFormats = subject.Movie.Profile.FormatItems.Where(v => v.Allowed == false).Select(f => f.Format).ToList();
|
||||
var notWantedFormats = notAllowedFormats.Intersect(formats);
|
||||
if (notWantedFormats.Any())
|
||||
{
|
||||
|
@ -22,7 +22,7 @@ public CutoffSpecification(UpgradableSpecification qualityUpgradableSpecificatio
|
||||
|
||||
public virtual Decision IsSatisfiedBy(RemoteMovie subject, SearchCriteriaBase searchCriteria)
|
||||
{
|
||||
var profile = subject.Movie.Profile.Value;
|
||||
var profile = subject.Movie.Profile;
|
||||
|
||||
if (subject.Movie.MovieFile != null)
|
||||
{
|
||||
@ -33,7 +33,7 @@ public virtual Decision IsSatisfiedBy(RemoteMovie subject, SearchCriteriaBase se
|
||||
var qualityCutoffIndex = profile.GetIndex(profile.Cutoff);
|
||||
var qualityCutoff = profile.Items[qualityCutoffIndex.Index];
|
||||
|
||||
return Decision.Reject("Existing file meets cutoff: {0} - {1}", qualityCutoff, subject.Movie.Profile.Value.Cutoff);
|
||||
return Decision.Reject("Existing file meets cutoff: {0} - {1}", qualityCutoff, subject.Movie.Profile.Cutoff);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -19,7 +19,7 @@ public LanguageSpecification(Logger logger)
|
||||
|
||||
public virtual Decision IsSatisfiedBy(RemoteMovie subject, SearchCriteriaBase searchCriteria)
|
||||
{
|
||||
var wantedLanguage = subject.Movie.Profile.Value.Language;
|
||||
var wantedLanguage = subject.Movie.Profile.Language;
|
||||
|
||||
if (wantedLanguage == Language.Any)
|
||||
{
|
||||
|
@ -20,7 +20,7 @@ public virtual Decision IsSatisfiedBy(RemoteMovie subject, SearchCriteriaBase se
|
||||
{
|
||||
_logger.Debug("Checking if report meets quality requirements. {0}", subject.ParsedMovieInfo.Quality);
|
||||
|
||||
var profile = subject.Movie.Profile.Value;
|
||||
var profile = subject.Movie.Profile;
|
||||
var qualityIndex = profile.GetIndex(subject.ParsedMovieInfo.Quality.Quality);
|
||||
var qualityOrGroup = profile.Items[qualityIndex.Index];
|
||||
|
||||
|
@ -35,7 +35,7 @@ public Decision IsSatisfiedBy(RemoteMovie subject, SearchCriteriaBase searchCrit
|
||||
foreach (var queueItem in matchingMovies)
|
||||
{
|
||||
var remoteMovie = queueItem.RemoteMovie;
|
||||
var qualityProfile = subject.Movie.Profile.Value;
|
||||
var qualityProfile = subject.Movie.Profile;
|
||||
|
||||
_logger.Debug("Checking if existing release in queue meets cutoff. Queued quality is: {0}", remoteMovie.ParsedMovieInfo.Quality);
|
||||
|
||||
|
@ -37,14 +37,14 @@ public virtual Decision IsSatisfiedBy(RemoteMovie subject, SearchCriteriaBase se
|
||||
return Decision.Accept();
|
||||
}
|
||||
|
||||
var profile = subject.Movie.Profile.Value;
|
||||
var profile = subject.Movie.Profile;
|
||||
var delayProfile = _delayProfileService.BestForTags(subject.Movie.Tags);
|
||||
var delay = delayProfile.GetProtocolDelay(subject.Release.DownloadProtocol);
|
||||
var isPreferredProtocol = subject.Release.DownloadProtocol == delayProfile.PreferredProtocol;
|
||||
|
||||
// Preferred word count
|
||||
var title = subject.Release.Title;
|
||||
var preferredWords = subject.Movie.Profile?.Value?.PreferredTags;
|
||||
var preferredWords = subject.Movie.Profile?.PreferredTags;
|
||||
var preferredCount = 0;
|
||||
|
||||
if (preferredWords == null)
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user