From a13011aa490ff8a6df52676de9fdc3bd7c15176e Mon Sep 17 00:00:00 2001 From: Robin Dadswell <19610103+RobinDadswell@users.noreply.github.com> Date: Wed, 26 Jan 2022 00:08:27 +0000 Subject: [PATCH] New: Postgres Database Support Co-Authored-By: Qstick <376117+Qstick@users.noreply.github.com> --- frontend/src/System/Status/About/About.js | 9 + src/NuGet.Config | 1 + .../AutomationTest.cs | 2 +- .../CleanseLogMessageFixture.cs | 18 + .../ServiceFactoryFixture.cs | 5 +- .../Instrumentation/CleanseLogMessage.cs | 1 + .../Datastore/DatabaseFixture.cs | 16 +- .../Datastore/DatabaseRelationshipFixture.cs | 12 + .../Migration/070_delay_profileFixture.cs | 20 +- .../071_unknown_quality_in_profileFixture.cs | 13 +- .../072_history_downloadIdFixture.cs | 8 +- .../Migration/075_force_lib_updateFixture.cs | 38 +- .../Migration/079_dedupe_tagsFixture.cs | 62 +-- ..._prefix_to_transmission_categoryFixture.cs | 14 +- .../084_update_quality_minmax_sizeFixture.cs | 10 +- .../085_expand_transmission_urlbaseFixture.cs | 14 +- .../086_pushbullet_device_idsFixture.cs | 8 +- ...pushbullet_devices_channels_listFixture.cs | 4 +- .../090_update_kickass_urlFixture.cs | 6 +- .../099_extra_and_subtitle_filesFixture.cs | 4 +- ..._add_ultrahd_quality_in_profilesFixture.cs | 2 +- ...103_fix_metadata_file_extensionsFixture.cs | 4 +- .../Migration/106_update_btn_urlFixture.cs | 6 +- ...108_fix_metadata_file_extensionsFixture.cs | 6 +- .../109_import_extra_files_configFixture.cs | 6 +- .../110_fix_extra_files_configFixture.cs | 20 +- ...7_add_webrip_qualites_in_profileFixture.cs | 8 +- .../121_update_animetosho_urlFixture.cs | 2 +- ...2_add_remux_qualities_in_profileFixture.cs | 4 +- ...ity_profiles_add_upgrade_allowedFixture.cs | 4 +- ...132_add_download_client_priorityFixture.cs | 20 +- ...148_mediainfo_channel_propertiesFixture.cs | 2 +- .../157_email_multiple_addressesFixture.cs | 2 +- .../158_cdh_per_downloadclientFixture.cs | 12 +- .../161_fix_pending_releasesFixture.cs | 6 +- .../171_add_custom_formatsFixture.cs | 30 +- ..._invalid_roksbox_metadata_imagesFixture.cs | 2 +- .../192_import_exclusion_typeFixture.cs | 4 +- ...ture.cs => WhereBuilderPostgresFixture.cs} | 30 +- .../Datastore/WhereBuilderSqliteFixture.cs | 198 +++++++++ src/NzbDrone.Core.Test/Framework/DbTest.cs | 56 ++- .../Framework/DbTestCleanup.cs | 6 +- .../Framework/TestDatabase.cs | 3 + .../SeriesStatisticsFixture.cs | 6 +- src/NzbDrone.Core/Backup/BackupService.cs | 7 +- .../Blocklisting/BlocklistRepository.cs | 2 +- .../Configuration/ConfigFileProvider.cs | 21 +- .../Datastore/BasicRepository.cs | 21 +- .../Datastore/ConnectionStringFactory.cs | 61 ++- src/NzbDrone.Core/Datastore/Database.cs | 34 +- .../Datastore/DatabaseConnectionInfo.cs | 14 + src/NzbDrone.Core/Datastore/DbFactory.cs | 62 ++- .../Datastore/Extensions/BuilderExtensions.cs | 46 ++- src/NzbDrone.Core/Datastore/LogDatabase.cs | 4 + src/NzbDrone.Core/Datastore/MainDatabase.cs | 4 + .../007_add_renameEpisodes_to_naming.cs | 4 +- .../Migration/009_fix_renameEpisodes.cs | 6 +- .../Datastore/Migration/010_add_monitored.cs | 10 +- .../Migration/013_add_air_date_utc.cs | 4 +- .../016_updated_imported_history_item.cs | 4 +- .../Migration/017_reset_scene_names.cs | 4 +- .../Migration/018_remove_duplicates.cs | 18 +- .../020_add_year_and_seasons_to_series.cs | 6 +- .../029_add_formats_to_naming_config.cs | 8 +- ...d_season_folder_format_to_naming_config.cs | 10 +- .../032_set_default_release_group.cs | 5 +- .../Migration/033_add_api_key_to_pushover.cs | 8 +- ...d_series_folder_format_to_naming_config.cs | 4 +- .../036_update_with_quality_converters.cs | 8 +- .../037_add_configurable_qualities.cs | 4 +- .../038_add_on_upgrade_to_notifications.cs | 4 +- .../041_fix_xbmc_season_images_metadata.cs | 4 +- .../043_convert_config_to_download_clients.cs | 6 +- .../044_fix_xbmc_episode_metadata.cs | 24 +- .../Datastore/Migration/046_fix_nzb_su_url.cs | 8 +- .../Datastore/Migration/049_fix_dognzb_url.cs | 8 +- .../Migration/051_download_client_import.cs | 18 +- .../Migration/052_add_columns_for_anime.cs | 6 +- .../Migration/053_add_series_sorttitle.cs | 4 +- .../Migration/054_rename_profiles.cs | 6 +- ...7_convert_episode_file_path_to_relative.cs | 4 +- .../059_add_enable_options_to_indexers.cs | 6 +- .../Migration/061_clear_bad_scene_names.cs | 18 +- .../Migration/062_convert_quality_models.cs | 4 +- .../065_make_scene_numbering_nullable.cs | 9 +- .../Datastore/Migration/066_add_tags.cs | 6 +- .../Migration/068_add_release_restrictions.cs | 6 +- .../Datastore/Migration/069_quality_proper.cs | 4 +- .../Datastore/Migration/070_delay_profile.cs | 61 +-- .../071_unknown_quality_in_profile.cs | 25 +- .../Datastore/Migration/072_history_grabid.cs | 38 +- .../Datastore/Migration/074_disable_eztv.cs | 4 +- .../Datastore/Migration/079_dedupe_tags.cs | 32 +- ...ove_dot_prefix_to_transmission_category.cs | 22 +- .../Migration/082_add_fanzub_settings.cs | 4 +- .../084_update_quality_minmax_size.cs | 4 +- .../085_expand_transmission_urlbase.cs | 22 +- .../Migration/086_pushbullet_device_ids.cs | 20 +- .../Datastore/Migration/087_remove_eztv.cs | 4 +- .../088_pushbullet_devices_channels_list.cs | 22 +- .../089_add_on_rename_to_notifcations.cs | 8 +- .../Migration/090_update_kickass_url.cs | 8 +- .../Migration/096_disable_kickass.cs | 4 +- .../Migration/099_extra_and_subtitle_files.cs | 25 +- ...e_to_episodeFiles_history_and_blacklist.cs | 36 +- .../103_fix_metadata_file_extensions.cs | 23 +- .../Datastore/Migration/104_remove_kickass.cs | 4 +- .../105_rename_torrent_downloadstation.cs | 4 +- .../Datastore/Migration/106_update_btn_url.cs | 2 +- .../Datastore/Migration/107_remove_wombles.cs | 4 +- .../Migration/108_fix_extra_file_extension.cs | 25 +- .../Migration/109_import_extra_files.cs | 28 +- .../Migration/110_fix_extra_files_config.cs | 10 +- .../Migration/111_create_language_profiles.cs | 6 +- .../113_consolidate_indexer_baseurl.cs | 4 +- .../Datastore/Migration/116_disable_nyaa.cs | 4 +- ...dd_webrip_and_br480_qualites_in_profile.cs | 24 +- ...rate_automatic_and_interactive_searches.cs | 2 +- .../Migration/121_update_animetosho_url.cs | 2 +- .../122_add_remux_qualities_in_profile.cs | 23 +- ...me_quality_profiles_add_upgrade_allowed.cs | 4 +- .../Migration/131_download_propers_config.cs | 6 +- .../132_add_download_client_priority.cs | 53 ++- .../134_add_specials_folder_format.cs | 15 +- .../135_health_issue_notification.cs | 6 +- .../Datastore/Migration/138_remove_bitmetv.cs | 6 +- .../Migration/139_add_download_history.cs | 2 +- ...140_remove_chown_and_folderchmod_config.cs | 2 +- .../146_cleanup_duplicates_updatehistory.cs | 6 +- .../147_swap_filechmod_for_folderchmod.cs | 8 +- .../Migration/148_mediainfo_channels.cs | 4 +- .../149_add_on_delete_to_notifications.cs | 6 +- .../Migration/152_update_btn_url_to_https.cs | 2 +- ...53_add_on_episodefiledelete_for_upgrade.cs | 4 +- .../155_add_arabic_and_hindi_languages.cs | 4 +- .../156_add_bypass_to_delay_profile.cs | 2 +- .../Migration/157_email_multiple_addresses.cs | 20 +- .../Migration/158_cdh_per_downloadclient.cs | 19 +- .../Migration/161_remove_plex_hometheater.cs | 4 +- .../Migration/162_release_profile_to_array.cs | 4 +- .../Migration/163_mediainfo_to_ffmpeg.cs | 4 +- .../165_add_on_update_to_notifications.cs | 2 +- .../Migration/166_update_series_sort_title.cs | 4 +- ..._add_malayalam _and_ukrainian_languages.cs | 4 +- .../Migration/171_add_custom_formats.cs | 41 +- .../Datastore/Migration/173_remove_omg.cs | 2 +- ...175_language_profiles_to_custom_formats.cs | 6 +- .../181_quality_definition_preferred_size.cs | 2 +- .../Migration/183_update_images_remote_url.cs | 4 +- ..._remove_invalid_roksbox_metadata_images.cs | 3 +- .../187_add_on_series_add_to_notifications.cs | 2 +- ...date_timestamp_columns_to_with_timezone.cs | 55 +++ .../190_health_restored_notification.cs | 2 +- .../Migration/192_import_exclusion_type.cs | 5 +- .../Framework/MigrationController.cs | 16 +- .../Datastore/PostgresOptions.cs | 26 ++ src/NzbDrone.Core/Datastore/SqlBuilder.cs | 8 + src/NzbDrone.Core/Datastore/TableMapper.cs | 37 +- src/NzbDrone.Core/Datastore/TableMapping.cs | 2 +- src/NzbDrone.Core/Datastore/WhereBuilder.cs | 384 +---------------- .../Datastore/WhereBuilderPostgres.cs | 389 ++++++++++++++++++ .../Datastore/WhereBuilderSqlite.cs | 389 ++++++++++++++++++ .../History/HistoryRepository.cs | 2 +- .../CleanupAbsolutePathMetadataFiles.cs | 38 +- .../CleanupAdditionalNamingSpecs.cs | 10 +- .../Housekeepers/CleanupAdditionalUsers.cs | 10 +- ...ownloadClientUnavailablePendingReleases.cs | 35 +- .../CleanupDuplicateMetadataFiles.cs | 42 +- .../Housekeepers/CleanupOrphanedBlocklist.cs | 14 +- .../CleanupOrphanedDownloadClientStatus.cs | 15 +- .../CleanupOrphanedEpisodeFiles.cs | 12 +- .../Housekeepers/CleanupOrphanedEpisodes.cs | 12 +- .../CleanupOrphanedHistoryItems.cs | 24 +- .../CleanupOrphanedImportListStatus.cs | 12 +- .../CleanupOrphanedIndexerStatus.cs | 14 +- .../CleanupOrphanedMetadataFiles.cs | 36 +- .../CleanupOrphanedPendingReleases.cs | 12 +- .../Housekeepers/CleanupUnusedTags.cs | 11 +- .../FixFutureRunScheduledTasks.cs | 10 +- .../Instrumentation/DatabaseTarget.cs | 70 +++- .../Messaging/Commands/CommandRepository.cs | 2 +- .../SeriesStats/SeriesStatisticsRepository.cs | 44 +- src/NzbDrone.Core/Sonarr.Core.csproj | 6 +- src/NzbDrone.Core/Tv/EpisodeRepository.cs | 17 +- src/NzbDrone.Core/Tv/SeriesRepository.cs | 11 +- .../Update/UpdatePackageProvider.cs | 6 +- src/NzbDrone.Host.Test/ContainerFixture.cs | 3 + src/NzbDrone.Host/Bootstrap.cs | 8 + .../IntegrationTest.cs | 30 +- .../Datastore/PostgresDatabase.cs | 69 ++++ .../Datastore/SqliteDatabase.cs | 14 + src/NzbDrone.Test.Common/NzbDroneRunner.cs | 23 +- src/Sonarr.Api.V3/System/SystemController.cs | 3 +- src/Sonarr.Api.V3/System/SystemResource.cs | 3 + src/postgres.runsettings | 11 + 195 files changed, 2600 insertions(+), 1325 deletions(-) rename src/NzbDrone.Core.Test/Datastore/{WhereBuilderFixture.cs => WhereBuilderPostgresFixture.cs} (88%) create mode 100644 src/NzbDrone.Core.Test/Datastore/WhereBuilderSqliteFixture.cs create mode 100644 src/NzbDrone.Core/Datastore/DatabaseConnectionInfo.cs create mode 100644 src/NzbDrone.Core/Datastore/Migration/188_postgres_update_timestamp_columns_to_with_timezone.cs create mode 100644 src/NzbDrone.Core/Datastore/PostgresOptions.cs create mode 100644 src/NzbDrone.Core/Datastore/WhereBuilderPostgres.cs create mode 100644 src/NzbDrone.Core/Datastore/WhereBuilderSqlite.cs create mode 100644 src/NzbDrone.Test.Common/Datastore/PostgresDatabase.cs create mode 100644 src/NzbDrone.Test.Common/Datastore/SqliteDatabase.cs create mode 100644 src/postgres.runsettings diff --git a/frontend/src/System/Status/About/About.js b/frontend/src/System/Status/About/About.js index b0b289135..7cd66edf2 100644 --- a/frontend/src/System/Status/About/About.js +++ b/frontend/src/System/Status/About/About.js @@ -22,6 +22,8 @@ class About extends Component { isNetCore, isDocker, runtimeVersion, + databaseVersion, + databaseType, appData, startupPath, mode, @@ -69,6 +71,11 @@ class About extends Component { /> } + + + \ No newline at end of file diff --git a/src/NzbDrone.Automation.Test/AutomationTest.cs b/src/NzbDrone.Automation.Test/AutomationTest.cs index 37996477f..799670e31 100644 --- a/src/NzbDrone.Automation.Test/AutomationTest.cs +++ b/src/NzbDrone.Automation.Test/AutomationTest.cs @@ -43,7 +43,7 @@ namespace NzbDrone.Automation.Test driver.Manage().Window.Size = new System.Drawing.Size(1920, 1080); - _runner = new NzbDroneRunner(LogManager.GetCurrentClassLogger()); + _runner = new NzbDroneRunner(LogManager.GetCurrentClassLogger(), null); _runner.KillAll(); _runner.Start(true); diff --git a/src/NzbDrone.Common.Test/InstrumentationTests/CleanseLogMessageFixture.cs b/src/NzbDrone.Common.Test/InstrumentationTests/CleanseLogMessageFixture.cs index 59407f4dd..388a96635 100644 --- a/src/NzbDrone.Common.Test/InstrumentationTests/CleanseLogMessageFixture.cs +++ b/src/NzbDrone.Common.Test/InstrumentationTests/CleanseLogMessageFixture.cs @@ -66,6 +66,9 @@ namespace NzbDrone.Common.Test.InstrumentationTests [TestCase("Hardlinking episode file: /Users/mySecret/Downloads to /media/abc.mkv")] [TestCase("Hardlink '/home/mySecret/Downloads/abs.mkv' to '/media/abc.mkv' failed.")] [TestCase("Hardlink '/Users/mySecret/Downloads/abs.mkv' to '/media/abc.mkv' failed.")] + [TestCase("/sonarr/signalr/messages/negotiate?access_token=1234530f422f4aacb6b301233210aaaa&negotiateVersion=1")] + [TestCase(@"[Info] MigrationController: *** Migrating Database=sonarr-main;Host=postgres14;Username=mySecret;Password=mySecret;Port=5432;Enlist=False ***")] + [TestCase(@"[Info] MigrationController: *** Migrating Database=sonarr-main;Host=postgres14;Username=mySecret;Password=mySecret;Port=5432;token=mySecret;Enlist=False&username=mySecret;mypassword=mySecret;mypass=shouldkeep1;test_token=mySecret;password=123%@%_@!#^#@;use_password=mySecret;get_token=shouldkeep2;usetoken=shouldkeep3;passwrd=mySecret;")] // Announce URLs (passkeys) Magnet & Tracker [TestCase(@"magnet_uri"":""magnet:?xt=urn:btih:9pr04sgkillroyimaveql2tyu8xyui&dn=&tr=https%3a%2f%2fxxx.yyy%2f9pr04sg601233210imaveql2tyu8xyui%2fannounce""}")] @@ -90,9 +93,24 @@ namespace NzbDrone.Common.Test.InstrumentationTests var cleansedMessage = CleanseLogMessage.Cleanse(message); cleansedMessage.Should().NotContain("mySecret"); + cleansedMessage.Should().NotContain("123%@%_@!#^#@"); cleansedMessage.Should().NotContain("01233210"); } + [TestCase(@"[Info] MigrationController: *** Migrating Database=sonarr-main;Host=postgres14;Username=mySecret;Password=mySecret;Port=5432;token=mySecret;Enlist=False&username=mySecret;mypassword=mySecret;mypass=shouldkeep1;test_token=mySecret;password=123%@%_@!#^#@;use_password=mySecret;get_token=shouldkeep2;usetoken=shouldkeep3;passwrd=mySecret;")] + public void should_keep_message(string message) + { + var cleansedMessage = CleanseLogMessage.Cleanse(message); + + cleansedMessage.Should().NotContain("mySecret"); + cleansedMessage.Should().NotContain("123%@%_@!#^#@"); + cleansedMessage.Should().NotContain("01233210"); + + cleansedMessage.Should().Contain("shouldkeep1"); + cleansedMessage.Should().Contain("shouldkeep2"); + cleansedMessage.Should().Contain("shouldkeep3"); + } + [TestCase(@"Some message (from 32.2.3.5 user agent)")] [TestCase(@"Auth-Invalidated ip 32.2.3.5")] [TestCase(@"Auth-Success ip 32.2.3.5")] diff --git a/src/NzbDrone.Common.Test/ServiceFactoryFixture.cs b/src/NzbDrone.Common.Test/ServiceFactoryFixture.cs index f543af256..58642f2e4 100644 --- a/src/NzbDrone.Common.Test/ServiceFactoryFixture.cs +++ b/src/NzbDrone.Common.Test/ServiceFactoryFixture.cs @@ -4,11 +4,13 @@ using DryIoc.Microsoft.DependencyInjection; using FluentAssertions; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Options; using Moq; using NUnit.Framework; using NzbDrone.Common.Composition.Extensions; using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.Instrumentation.Extensions; +using NzbDrone.Core.Datastore; using NzbDrone.Core.Datastore.Extensions; using NzbDrone.Core.Lifecycle; using NzbDrone.Core.Messaging.Events; @@ -29,7 +31,8 @@ namespace NzbDrone.Common.Test .AddDummyDatabase() .AddStartupContext(new StartupContext("first", "second")); - container.RegisterInstance(new Mock().Object); + container.RegisterInstance(new Mock().Object); + container.RegisterInstance(new Mock>().Object); var serviceProvider = container.GetServiceProvider(); diff --git a/src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs b/src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs index defe1bde0..d0150a7bc 100644 --- a/src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs +++ b/src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs @@ -17,6 +17,7 @@ namespace NzbDrone.Common.Instrumentation new (@"iptorrents\.com/[/a-z0-9?&;]*?(?:[?&;](u|tp)=(?[^&=;]+?))+(?= |;|&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase), new (@"/fetch/[a-z0-9]{32}/(?[a-z0-9]{32})", RegexOptions.Compiled), new (@"getnzb.*?(?<=\?|&)(r)=(?[^&=]+?)(?= |&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase), + new (@"\b(\w*)?(_?(?[^&=]+?)(?= |&|$|;)", RegexOptions.Compiled | RegexOptions.IgnoreCase), // Trackers Announce Keys; Designed for Qbit Json; should work for all in theory new (@"announce(\.php)?(/|%2f|%3fpasskey%3d)(?[a-z0-9]{16,})|(?[a-z0-9]{16,})(/|%2f)announce"), diff --git a/src/NzbDrone.Core.Test/Datastore/DatabaseFixture.cs b/src/NzbDrone.Core.Test/Datastore/DatabaseFixture.cs index 19631c00c..b24765caf 100644 --- a/src/NzbDrone.Core.Test/Datastore/DatabaseFixture.cs +++ b/src/NzbDrone.Core.Test/Datastore/DatabaseFixture.cs @@ -15,7 +15,7 @@ namespace NzbDrone.Core.Test.Datastore public void SingleOrDefault_should_return_null_on_empty_db() { Mocker.Resolve() - .OpenConnection().Query("SELECT * FROM Series") + .OpenConnection().Query("SELECT * FROM \"Series\"") .SingleOrDefault() .Should() .BeNull(); @@ -27,6 +27,20 @@ namespace NzbDrone.Core.Test.Datastore Mocker.Resolve().Vacuum(); } + [Test] + public void postgres_should_not_contain_timestamp_without_timezone_columns() + { + if (Db.DatabaseType != DatabaseType.PostgreSQL) + { + return; + } + + Mocker.Resolve() + .OpenConnection().Query("SELECT table_name, column_name, data_type FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = 'public' AND data_type = 'timestamp without time zone'") + .Should() + .BeNullOrEmpty(); + } + [Test] public void get_version() { diff --git a/src/NzbDrone.Core.Test/Datastore/DatabaseRelationshipFixture.cs b/src/NzbDrone.Core.Test/Datastore/DatabaseRelationshipFixture.cs index 4a1226e1d..e40f9a0fa 100644 --- a/src/NzbDrone.Core.Test/Datastore/DatabaseRelationshipFixture.cs +++ b/src/NzbDrone.Core.Test/Datastore/DatabaseRelationshipFixture.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Linq; using FizzWare.NBuilder; @@ -15,6 +16,17 @@ namespace NzbDrone.Core.Test.Datastore [TestFixture] public class DatabaseRelationshipFixture : DbTest { + [SetUp] + public void Setup() + { + AssertionOptions.AssertEquivalencyUsing(options => + { + options.Using(ctx => ctx.Subject.Should().BeCloseTo(ctx.Expectation.ToUniversalTime(), TimeSpan.FromMilliseconds(20))).WhenTypeIs(); + options.Using(ctx => ctx.Subject.Should().BeCloseTo(ctx.Expectation.Value.ToUniversalTime(), TimeSpan.FromMilliseconds(20))).WhenTypeIs(); + return options; + }); + } + [Test] public void one_to_one() { diff --git a/src/NzbDrone.Core.Test/Datastore/Migration/070_delay_profileFixture.cs b/src/NzbDrone.Core.Test/Datastore/Migration/070_delay_profileFixture.cs index bdc199f1f..90304067f 100644 --- a/src/NzbDrone.Core.Test/Datastore/Migration/070_delay_profileFixture.cs +++ b/src/NzbDrone.Core.Test/Datastore/Migration/070_delay_profileFixture.cs @@ -1,4 +1,4 @@ -using System.Linq; +using System.Linq; using FluentAssertions; using NUnit.Framework; using NzbDrone.Core.Datastore.Migration; @@ -26,12 +26,12 @@ namespace NzbDrone.Core.Test.Datastore.Migration { GrabDelay = 2, Name = "TwoHours", - Cutoff = "{}", + Cutoff = 0, Items = "[]" }); }); - var allProfiles = db.Query("SELECT * FROM DelayProfiles"); + var allProfiles = db.Query("SELECT * FROM \"DelayProfiles\""); allProfiles.Should().HaveCount(3); allProfiles.Should().OnlyContain(c => c.PreferredProtocol == 1); @@ -54,7 +54,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration }); }); - var tags = db.Query("SELECT * FROM Tags"); + var tags = db.Query("SELECT * FROM \"Tags\""); tags.Should().HaveCount(1); tags.First().Label.Should().Be("delay-60"); @@ -83,17 +83,17 @@ namespace NzbDrone.Core.Test.Datastore.Migration Status = 0, Images = "[]", Path = @"C:\Test\Series", - Monitored = 1, - SeasonFolder = 1, - RunTime = 0, + Monitored = true, + SeasonFolder = true, + Runtime = 0, SeriesType = 0, - UseSceneNumbering = 0, + UseSceneNumbering = false, Tags = "[1]" }); }); - var tag = db.Query("SELECT Id, Label FROM Tags").Single(); - var series = db.Query("SELECT Tags FROM Series"); + var tag = db.Query("SELECT \"Id\", \"Label\" FROM \"Tags\"").Single(); + var series = db.Query("SELECT \"Tags\" FROM \"Series\""); series.Should().HaveCount(1); diff --git a/src/NzbDrone.Core.Test/Datastore/Migration/071_unknown_quality_in_profileFixture.cs b/src/NzbDrone.Core.Test/Datastore/Migration/071_unknown_quality_in_profileFixture.cs index 4aa14402f..5f5d8b1c6 100644 --- a/src/NzbDrone.Core.Test/Datastore/Migration/071_unknown_quality_in_profileFixture.cs +++ b/src/NzbDrone.Core.Test/Datastore/Migration/071_unknown_quality_in_profileFixture.cs @@ -1,6 +1,8 @@ +using System.Collections.Generic; using System.Linq; using FluentAssertions; using NUnit.Framework; +using NzbDrone.Common.Serializer; using NzbDrone.Core.Datastore.Migration; using NzbDrone.Core.Test.Framework; @@ -19,12 +21,19 @@ namespace NzbDrone.Core.Test.Datastore.Migration Id = 0, Name = "SDTV", Cutoff = 1, - Items = "[ { \"quality\": 1, \"allowed\": true } ]", + Items = new List + { + new + { + Quality = 1, + Allowed = true + } + }.ToJson(), Language = 1 }); }); - var profiles = db.Query("SELECT Items FROM Profiles LIMIT 1"); + var profiles = db.Query("SELECT \"Items\" FROM \"Profiles\" LIMIT 1"); var items = profiles.First().Items; items.Should().HaveCount(2); diff --git a/src/NzbDrone.Core.Test/Datastore/Migration/072_history_downloadIdFixture.cs b/src/NzbDrone.Core.Test/Datastore/Migration/072_history_downloadIdFixture.cs index 363a6a180..072d46888 100644 --- a/src/NzbDrone.Core.Test/Datastore/Migration/072_history_downloadIdFixture.cs +++ b/src/NzbDrone.Core.Test/Datastore/Migration/072_history_downloadIdFixture.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using FluentAssertions; @@ -31,7 +31,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration }); }); - var history = db.Query("SELECT DownloadId, Data FROM History"); + var history = db.Query("SELECT \"DownloadId\", \"Data\" FROM \"History\""); history.Should().HaveCount(2); history.Should().NotContain(c => c.Data.ContainsKey("downloadClientId")); @@ -56,7 +56,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration }); }); - var history = db.Query("SELECT DownloadId, Data FROM History"); + var history = db.Query("SELECT \"DownloadId\", \"Data\" FROM \"History\""); history.Should().HaveCount(2); history.Should().NotContain(c => c.Data.ContainsKey("downloadClientId")); @@ -77,7 +77,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration }); }); - var history = db.Query("SELECT DownloadId, Data FROM History").Single(); + var history = db.Query("SELECT \"DownloadId\", \"Data\" FROM \"History\"").Single(); history.Data.Should().NotContainKey("downloadClientId"); history.Data.Should().Contain(new KeyValuePair("indexer", "test")); diff --git a/src/NzbDrone.Core.Test/Datastore/Migration/075_force_lib_updateFixture.cs b/src/NzbDrone.Core.Test/Datastore/Migration/075_force_lib_updateFixture.cs index a7ce2fe45..b8d47f6db 100644 --- a/src/NzbDrone.Core.Test/Datastore/Migration/075_force_lib_updateFixture.cs +++ b/src/NzbDrone.Core.Test/Datastore/Migration/075_force_lib_updateFixture.cs @@ -1,4 +1,4 @@ -using System.Linq; +using System.Linq; using FluentAssertions; using NUnit.Framework; using NzbDrone.Core.Datastore.Migration; @@ -14,8 +14,8 @@ namespace NzbDrone.Core.Test.Datastore.Migration { var db = WithMigrationTestDb(); - db.Query("SELECT * FROM ScheduledTasks").Should().BeEmpty(); - db.Query("SELECT * FROM Series").Should().BeEmpty(); + db.Query("SELECT * FROM \"ScheduledTasks\"").Should().BeEmpty(); + db.Query("SELECT * FROM \"Series\"").Should().BeEmpty(); } [Test] @@ -38,7 +38,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration }); }); - var jobs = db.Query("SELECT TypeName, LastExecution FROM ScheduledTasks"); + var jobs = db.Query("SELECT \"TypeName\", \"LastExecution\" FROM \"ScheduledTasks\""); jobs.Single(c => c.TypeName == "NzbDrone.Core.Tv.Commands.RefreshSeriesCommand") .LastExecution.Year.Should() @@ -57,49 +57,49 @@ namespace NzbDrone.Core.Test.Datastore.Migration c.Insert.IntoTable("Profiles").Row(new { Name = "Profile1", - CutOff = 0, + Cutoff = 0, Items = "[]", Language = 1 }); c.Insert.IntoTable("Series").Row(new { - Tvdbid = 1, + TvdbId = 1, TvRageId =1, Title ="Title1", CleanTitle ="CleanTitle1", - Status =1, - Images ="", - Path ="c:\\test", - Monitored =1, - SeasonFolder =1, - Runtime= 0, - SeriesType=0, - UseSceneNumbering =0, + Status = 1, + Images = "", + Path = "c:\\test", + Monitored = true, + SeasonFolder = true, + Runtime = 0, + SeriesType = 0, + UseSceneNumbering = false, LastInfoSync = "2000-01-01 00:00:00", ProfileId = 1 }); c.Insert.IntoTable("Series").Row(new { - Tvdbid = 2, + TvdbId = 2, TvRageId = 2, Title = "Title2", CleanTitle = "CleanTitle2", Status = 1, Images = "", Path = "c:\\test2", - Monitored = 1, - SeasonFolder = 1, + Monitored = true, + SeasonFolder = true, Runtime = 0, SeriesType = 0, - UseSceneNumbering = 0, + UseSceneNumbering = false, LastInfoSync = "2000-01-01 00:00:00", ProfileId = 1 }); }); - var series = db.Query("SELECT LastInfoSync FROM Series"); + var series = db.Query("SELECT \"LastInfoSync\" FROM \"Series\""); series.Should().OnlyContain(c => c.LastInfoSync.Value.Year == 2014); } diff --git a/src/NzbDrone.Core.Test/Datastore/Migration/079_dedupe_tagsFixture.cs b/src/NzbDrone.Core.Test/Datastore/Migration/079_dedupe_tagsFixture.cs index 1c24643aa..def163cef 100644 --- a/src/NzbDrone.Core.Test/Datastore/Migration/079_dedupe_tagsFixture.cs +++ b/src/NzbDrone.Core.Test/Datastore/Migration/079_dedupe_tagsFixture.cs @@ -1,4 +1,4 @@ -using System.Linq; +using System.Linq; using FluentAssertions; using NUnit.Framework; using NzbDrone.Core.Datastore.Migration; @@ -17,25 +17,25 @@ namespace NzbDrone.Core.Test.Datastore.Migration c.Insert.IntoTable("Profiles").Row(new { Name = "Profile1", - CutOff = 0, + Cutoff = 0, Items = "[]", Language = 1 }); c.Insert.IntoTable("Series").Row(new { - Tvdbid = 1, + TvdbId = 1, TvRageId = 1, Title = "Title1", CleanTitle = "CleanTitle1", Status = 1, Images = "", Path = "c:\\test", - Monitored = 1, - SeasonFolder = 1, + Monitored = true, + SeasonFolder = true, Runtime = 0, SeriesType = 0, - UseSceneNumbering = 0, + UseSceneNumbering = false, LastInfoSync = "2000-01-01 00:00:00", ProfileId = 1 }); @@ -46,7 +46,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration }); }); - var tags = db.Query("SELECT * FROM Tags"); + var tags = db.Query("SELECT * FROM \"Tags\""); tags.Should().HaveCount(1); } @@ -58,25 +58,25 @@ namespace NzbDrone.Core.Test.Datastore.Migration c.Insert.IntoTable("Profiles").Row(new { Name = "Profile1", - CutOff = 0, + Cutoff = 0, Items = "[]", Language = 1 }); c.Insert.IntoTable("Series").Row(new { - Tvdbid = 1, + TvdbId = 1, TvRageId = 1, Title = "Title1", CleanTitle = "CleanTitle1", Status = 1, Images = "", Path = "c:\\test", - Monitored = 1, - SeasonFolder = 1, + Monitored = true, + SeasonFolder = true, Runtime = 0, SeriesType = 0, - UseSceneNumbering = 0, + UseSceneNumbering = false, LastInfoSync = "2000-01-01 00:00:00", Tags = "[]", ProfileId = 1 @@ -88,7 +88,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration }); }); - var tags = db.Query("SELECT * FROM Tags"); + var tags = db.Query("SELECT * FROM \"Tags\""); tags.Should().HaveCount(1); } @@ -108,7 +108,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration }); }); - var tags = db.Query("SELECT * FROM Tags"); + var tags = db.Query("SELECT * FROM \"Tags\""); tags.Should().HaveCount(1); } @@ -123,7 +123,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration }); }); - Assert.That(() => db.Query("INSERT INTO Tags (Label) VALUES ('test')"), Throws.Exception); + Assert.That(() => db.Query("INSERT INTO \"Tags\" (\"Label\") VALUES ('test')"), Throws.Exception); } [Test] @@ -134,25 +134,25 @@ namespace NzbDrone.Core.Test.Datastore.Migration c.Insert.IntoTable("Profiles").Row(new { Name = "Profile1", - CutOff = 0, + Cutoff = 0, Items = "[]", Language = 1 }); c.Insert.IntoTable("Series").Row(new { - Tvdbid = 1, + TvdbId = 1, TvRageId = 1, Title = "Title1", CleanTitle = "CleanTitle1", Status = 1, Images = "", Path = "c:\\test", - Monitored = 1, - SeasonFolder = 1, + Monitored = true, + SeasonFolder = true, Runtime = 0, SeriesType = 0, - UseSceneNumbering = 0, + UseSceneNumbering = false, LastInfoSync = "2000-01-01 00:00:00", Tags = "[2]", ProfileId = 1 @@ -169,7 +169,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration }); }); - var series = db.Query("SELECT Tags FROM Series WHERE Id = 1").Single(); + var series = db.Query("SELECT \"Tags\" FROM \"Series\" WHERE \"Id\" = 1").Single(); series.Tags.First().Should().Be(1); } @@ -181,25 +181,25 @@ namespace NzbDrone.Core.Test.Datastore.Migration c.Insert.IntoTable("Profiles").Row(new { Name = "Profile1", - CutOff = 0, + Cutoff = 0, Items = "[]", Language = 1 }); c.Insert.IntoTable("Series").Row(new { - Tvdbid = 1, + TvdbId = 1, TvRageId = 1, Title = "Title1", CleanTitle = "CleanTitle1", Status = 1, Images = "", Path = "c:\\test", - Monitored = 1, - SeasonFolder = 1, + Monitored = true, + SeasonFolder = true, Runtime = 0, SeriesType = 0, - UseSceneNumbering = 0, + UseSceneNumbering = false, LastInfoSync = "2000-01-01 00:00:00", Tags = "[2]", ProfileId = 1 @@ -207,18 +207,18 @@ namespace NzbDrone.Core.Test.Datastore.Migration c.Insert.IntoTable("Series").Row(new { - Tvdbid = 2, + TvdbId = 2, TvRageId = 2, Title = "Title2", CleanTitle = "CleanTitle2", Status = 1, Images = "", Path = "c:\\test", - Monitored = 1, - SeasonFolder = 1, + Monitored = true, + SeasonFolder = true, Runtime = 0, SeriesType = 0, - UseSceneNumbering = 0, + UseSceneNumbering = false, LastInfoSync = "2000-01-01 00:00:00", Tags = "[]", ProfileId = 1 @@ -235,7 +235,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration }); }); - var series = db.Query("SELECT Tags FROM Series WHERE Id = 2").Single(); + var series = db.Query("SELECT \"Tags\" FROM \"Series\" WHERE \"Id\" = 2").Single(); series.Tags.Should().BeEmpty(); } } diff --git a/src/NzbDrone.Core.Test/Datastore/Migration/081_move_dot_prefix_to_transmission_categoryFixture.cs b/src/NzbDrone.Core.Test/Datastore/Migration/081_move_dot_prefix_to_transmission_categoryFixture.cs index afd2aab45..680f62ed9 100644 --- a/src/NzbDrone.Core.Test/Datastore/Migration/081_move_dot_prefix_to_transmission_categoryFixture.cs +++ b/src/NzbDrone.Core.Test/Datastore/Migration/081_move_dot_prefix_to_transmission_categoryFixture.cs @@ -1,4 +1,4 @@ -using System.Linq; +using System.Linq; using FluentAssertions; using NUnit.Framework; using NzbDrone.Common.Serializer; @@ -17,7 +17,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration { c.Insert.IntoTable("DownloadClients").Row(new { - Enable = 1, + Enable = true, Name = "Sab", Implementation = "Sabnzbd", Settings = new @@ -29,7 +29,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration }); }); - var downloadClients = db.Query("SELECT Settings FROM DownloadClients"); + var downloadClients = db.Query("SELECT \"Settings\" FROM \"DownloadClients\""); downloadClients.Should().HaveCount(1); downloadClients.First().Settings.ToObject().TvCategory.Should().Be("abc"); @@ -42,7 +42,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration { c.Insert.IntoTable("DownloadClients").Row(new { - Enable = 1, + Enable = true, Name = "Trans", Implementation = "Transmission", Settings = new @@ -54,7 +54,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration }); }); - var downloadClients = db.Query("SELECT Settings FROM DownloadClients"); + var downloadClients = db.Query("SELECT \"Settings\" FROM \"DownloadClients\""); downloadClients.Should().HaveCount(1); downloadClients.First().Settings.ToObject().TvCategory.Should().Be(".abc"); @@ -67,7 +67,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration { c.Insert.IntoTable("DownloadClients").Row(new { - Enable = 1, + Enable = true, Name = "Trans", Implementation = "Transmission", Settings = new @@ -79,7 +79,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration }); }); - var downloadClients = db.Query("SELECT Settings FROM DownloadClients"); + var downloadClients = db.Query("SELECT \"Settings\" FROM \"DownloadClients\""); downloadClients.Should().HaveCount(1); downloadClients.First().Settings.ToObject().TvCategory.Should().Be(""); diff --git a/src/NzbDrone.Core.Test/Datastore/Migration/084_update_quality_minmax_sizeFixture.cs b/src/NzbDrone.Core.Test/Datastore/Migration/084_update_quality_minmax_sizeFixture.cs index 8b4b237e6..6f1a275c1 100644 --- a/src/NzbDrone.Core.Test/Datastore/Migration/084_update_quality_minmax_sizeFixture.cs +++ b/src/NzbDrone.Core.Test/Datastore/Migration/084_update_quality_minmax_sizeFixture.cs @@ -1,4 +1,4 @@ -using System.Linq; +using System.Linq; using FluentAssertions; using NUnit.Framework; using NzbDrone.Core.Datastore.Migration; @@ -14,7 +14,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration { var db = WithMigrationTestDb(); - var qualityDefinitions = db.Query("SELECT * FROM QualityDefinitions"); + var qualityDefinitions = db.Query("SELECT * FROM \"QualityDefinitions\""); qualityDefinitions.Should().BeEmpty(); } @@ -40,7 +40,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration }); }); - var qualityDefinitions = db.Query("SELECT * FROM QualityDefinitions"); + var qualityDefinitions = db.Query("SELECT * FROM \"QualityDefinitions\""); qualityDefinitions.Should().HaveCount(2); qualityDefinitions.First(v => v.Quality == 10).MaxSize.Should().NotHaveValue(); @@ -60,7 +60,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration }); }); - var qualityDefinitions = db.Query("SELECT * FROM QualityDefinitions"); + var qualityDefinitions = db.Query("SELECT * FROM \"QualityDefinitions\""); qualityDefinitions.Should().HaveCount(1); qualityDefinitions.First(v => v.Quality == 1).MaxSize.Should().NotHaveValue(); @@ -87,7 +87,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration }); }); - var qualityDefinitions = db.Query("SELECT * FROM QualityDefinitions"); + var qualityDefinitions = db.Query("SELECT * FROM \"QualityDefinitions\""); qualityDefinitions.Should().HaveCount(2); qualityDefinitions.First(v => v.Quality == 1).MaxSize.Should().Be(100); diff --git a/src/NzbDrone.Core.Test/Datastore/Migration/085_expand_transmission_urlbaseFixture.cs b/src/NzbDrone.Core.Test/Datastore/Migration/085_expand_transmission_urlbaseFixture.cs index 655b717ee..10babdb33 100644 --- a/src/NzbDrone.Core.Test/Datastore/Migration/085_expand_transmission_urlbaseFixture.cs +++ b/src/NzbDrone.Core.Test/Datastore/Migration/085_expand_transmission_urlbaseFixture.cs @@ -1,4 +1,4 @@ -using System.Linq; +using System.Linq; using FluentAssertions; using NUnit.Framework; using NzbDrone.Common.Serializer; @@ -17,7 +17,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration { c.Insert.IntoTable("DownloadClients").Row(new { - Enable = 1, + Enable = true, Name = "Deluge", Implementation = "Deluge", Settings = new DelugeSettings85 @@ -30,7 +30,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration }); }); - var items = db.Query("SELECT * FROM DownloadClients"); + var items = db.Query("SELECT * FROM \"DownloadClients\""); items.Should().HaveCount(1); items.First().Settings.ToObject().UrlBase.Should().Be("/my/"); @@ -43,7 +43,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration { c.Insert.IntoTable("DownloadClients").Row(new { - Enable = 1, + Enable = true, Name = "Trans", Implementation = "Transmission", Settings = new TransmissionSettings81 @@ -55,7 +55,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration }); }); - var items = db.Query("SELECT * FROM DownloadClients"); + var items = db.Query("SELECT * FROM \"DownloadClients\""); items.Should().HaveCount(1); items.First().Settings.ToObject().UrlBase.Should().Be("/transmission/"); @@ -68,7 +68,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration { c.Insert.IntoTable("DownloadClients").Row(new { - Enable = 1, + Enable = true, Name = "Trans", Implementation = "Transmission", Settings = new TransmissionSettings81 @@ -81,7 +81,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration }); }); - var items = db.Query("SELECT * FROM DownloadClients"); + var items = db.Query("SELECT * FROM \"DownloadClients\""); items.Should().HaveCount(1); items.First().Settings.ToObject().UrlBase.Should().Be("/my/url/transmission/"); diff --git a/src/NzbDrone.Core.Test/Datastore/Migration/086_pushbullet_device_idsFixture.cs b/src/NzbDrone.Core.Test/Datastore/Migration/086_pushbullet_device_idsFixture.cs index a478ef5d4..6e07f19ef 100644 --- a/src/NzbDrone.Core.Test/Datastore/Migration/086_pushbullet_device_idsFixture.cs +++ b/src/NzbDrone.Core.Test/Datastore/Migration/086_pushbullet_device_idsFixture.cs @@ -1,4 +1,4 @@ -using System.Linq; +using System.Linq; using FluentAssertions; using NUnit.Framework; using NzbDrone.Common.Serializer; @@ -27,7 +27,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration }); }); - var items = db.Query("SELECT * FROM Notifications"); + var items = db.Query("SELECT * FROM \"Notifications\""); items.Should().HaveCount(1); } @@ -52,7 +52,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration }); }); - var items = db.Query("SELECT * FROM Notifications"); + var items = db.Query("SELECT * FROM \"Notifications\""); items.Should().HaveCount(1); } @@ -80,7 +80,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration }); }); - var items = db.Query("SELECT * FROM Notifications"); + var items = db.Query("SELECT * FROM \"Notifications\""); items.Should().HaveCount(1); items.First().Settings.ToObject().DeviceIds.First().Should().Be(deviceId); diff --git a/src/NzbDrone.Core.Test/Datastore/Migration/088_pushbullet_devices_channels_listFixture.cs b/src/NzbDrone.Core.Test/Datastore/Migration/088_pushbullet_devices_channels_listFixture.cs index 37679998c..4913b1662 100644 --- a/src/NzbDrone.Core.Test/Datastore/Migration/088_pushbullet_devices_channels_listFixture.cs +++ b/src/NzbDrone.Core.Test/Datastore/Migration/088_pushbullet_devices_channels_listFixture.cs @@ -1,4 +1,4 @@ -using System.Linq; +using System.Linq; using FluentAssertions; using NUnit.Framework; using NzbDrone.Common.Serializer; @@ -31,7 +31,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration }); }); - var items = db.Query("SELECT * FROM Notifications"); + var items = db.Query("SELECT * FROM \"Notifications\""); items.Should().HaveCount(1); items.First().Settings.ToObject().ChannelTags.Should().HaveCount(2); diff --git a/src/NzbDrone.Core.Test/Datastore/Migration/090_update_kickass_urlFixture.cs b/src/NzbDrone.Core.Test/Datastore/Migration/090_update_kickass_urlFixture.cs index 9a73fb50c..38ae24ca4 100644 --- a/src/NzbDrone.Core.Test/Datastore/Migration/090_update_kickass_urlFixture.cs +++ b/src/NzbDrone.Core.Test/Datastore/Migration/090_update_kickass_urlFixture.cs @@ -1,4 +1,4 @@ -using System.Linq; +using System.Linq; using FluentAssertions; using NUnit.Framework; using NzbDrone.Common.Serializer; @@ -33,7 +33,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration }); }); - var items = db.Query("SELECT * FROM Indexers"); + var items = db.Query("SELECT * FROM \"Indexers\""); items.Should().HaveCount(1); items.First().Settings.ToObject().BaseUrl.Should().Be("https://kat.cr"); @@ -56,7 +56,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration }); }); - var items = db.Query("SELECT * FROM Indexers"); + var items = db.Query("SELECT * FROM \"Indexers\""); items.Should().HaveCount(1); items.First().Settings.ToObject().BaseUrl.Should().Be("kickass.so"); diff --git a/src/NzbDrone.Core.Test/Datastore/Migration/099_extra_and_subtitle_filesFixture.cs b/src/NzbDrone.Core.Test/Datastore/Migration/099_extra_and_subtitle_filesFixture.cs index f72d950f0..c048d6af0 100644 --- a/src/NzbDrone.Core.Test/Datastore/Migration/099_extra_and_subtitle_filesFixture.cs +++ b/src/NzbDrone.Core.Test/Datastore/Migration/099_extra_and_subtitle_filesFixture.cs @@ -1,4 +1,4 @@ -using System.Linq; +using System.Linq; using FluentAssertions; using NUnit.Framework; using NzbDrone.Core.Datastore.Migration; @@ -44,7 +44,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration }); }); - var items = db.Query("SELECT * FROM MetadataFiles"); + var items = db.Query("SELECT * FROM \"MetadataFiles\""); items.Should().HaveCount(2); items.First().Extension.Should().Be(".jpg"); diff --git a/src/NzbDrone.Core.Test/Datastore/Migration/101_add_ultrahd_quality_in_profilesFixture.cs b/src/NzbDrone.Core.Test/Datastore/Migration/101_add_ultrahd_quality_in_profilesFixture.cs index d4c97f327..210b330ce 100644 --- a/src/NzbDrone.Core.Test/Datastore/Migration/101_add_ultrahd_quality_in_profilesFixture.cs +++ b/src/NzbDrone.Core.Test/Datastore/Migration/101_add_ultrahd_quality_in_profilesFixture.cs @@ -24,7 +24,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration }); }); - var profiles = db.Query("SELECT Items FROM Profiles LIMIT 1"); + var profiles = db.Query("SELECT \"Items\" FROM \"Profiles\" LIMIT 1"); var items = profiles.First().Items; items.Should().HaveCount(4); diff --git a/src/NzbDrone.Core.Test/Datastore/Migration/103_fix_metadata_file_extensionsFixture.cs b/src/NzbDrone.Core.Test/Datastore/Migration/103_fix_metadata_file_extensionsFixture.cs index 86905df18..ed4a255f9 100644 --- a/src/NzbDrone.Core.Test/Datastore/Migration/103_fix_metadata_file_extensionsFixture.cs +++ b/src/NzbDrone.Core.Test/Datastore/Migration/103_fix_metadata_file_extensionsFixture.cs @@ -1,4 +1,4 @@ -using System.Linq; +using System.Linq; using FluentAssertions; using NUnit.Framework; using NzbDrone.Core.Datastore.Migration; @@ -27,7 +27,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration }); }); - var items = db.Query("SELECT * FROM MetadataFiles"); + var items = db.Query("SELECT * FROM \"MetadataFiles\""); items.Should().HaveCount(1); items.First().Extension.Should().Be(".jpg"); diff --git a/src/NzbDrone.Core.Test/Datastore/Migration/106_update_btn_urlFixture.cs b/src/NzbDrone.Core.Test/Datastore/Migration/106_update_btn_urlFixture.cs index 3b719d42e..057ba1d55 100644 --- a/src/NzbDrone.Core.Test/Datastore/Migration/106_update_btn_urlFixture.cs +++ b/src/NzbDrone.Core.Test/Datastore/Migration/106_update_btn_urlFixture.cs @@ -1,4 +1,4 @@ -using System.Linq; +using System.Linq; using FluentAssertions; using NUnit.Framework; using NzbDrone.Common.Serializer; @@ -30,7 +30,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration }); }); - var items = db.Query("SELECT * FROM Indexers"); + var items = db.Query("SELECT * FROM \"Indexers\""); items.Should().HaveCount(1); items.First().Settings.ToObject().BaseUrl.Should().Contain("api.broadcasthe.net"); @@ -53,7 +53,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration }); }); - var items = db.Query("SELECT * FROM Indexers"); + var items = db.Query("SELECT * FROM \"Indexers\""); items.Should().HaveCount(1); items.First().Settings.ToObject().BaseUrl.Should().Be("http://api.btnapps.net"); diff --git a/src/NzbDrone.Core.Test/Datastore/Migration/108_fix_metadata_file_extensionsFixture.cs b/src/NzbDrone.Core.Test/Datastore/Migration/108_fix_metadata_file_extensionsFixture.cs index ba12a2a4e..ed79fb91c 100644 --- a/src/NzbDrone.Core.Test/Datastore/Migration/108_fix_metadata_file_extensionsFixture.cs +++ b/src/NzbDrone.Core.Test/Datastore/Migration/108_fix_metadata_file_extensionsFixture.cs @@ -27,7 +27,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration }); }); - var items = db.Query("Select * from ExtraFiles"); + var items = db.Query("Select * from \"ExtraFiles\""); items.Should().BeEmpty(); } @@ -50,7 +50,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration }); }); - var items = db.Query("Select * from SubtitleFiles"); + var items = db.Query("Select * from \"SubtitleFiles\""); items.Should().HaveCount(1); items.First()["Extension"].Should().Be(".srt"); @@ -73,7 +73,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration }); }); - var items = db.Query("Select * from ExtraFiles"); + var items = db.Query("Select * from \"ExtraFiles\""); items.Should().HaveCount(1); items.First()["Extension"].Should().Be(".nfo-orig"); diff --git a/src/NzbDrone.Core.Test/Datastore/Migration/109_import_extra_files_configFixture.cs b/src/NzbDrone.Core.Test/Datastore/Migration/109_import_extra_files_configFixture.cs index e32aade5b..ad4affc98 100644 --- a/src/NzbDrone.Core.Test/Datastore/Migration/109_import_extra_files_configFixture.cs +++ b/src/NzbDrone.Core.Test/Datastore/Migration/109_import_extra_files_configFixture.cs @@ -13,7 +13,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration { var db = WithMigrationTestDb(); - var items = db.QueryScalar("SELECT Value FROM Config WHERE Key = 'importextrafiles'"); + var items = db.QueryScalar("SELECT \"Value\" FROM \"Config\" WHERE \"Key\" = 'importextrafiles'"); items.Should().BeNull(); } @@ -29,7 +29,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration }); }); - var items = db.QueryScalar("SELECT Value FROM Config WHERE Key = 'importextrafiles'"); + var items = db.QueryScalar("SELECT \"Value\" FROM \"Config\" WHERE \"Key\" = 'importextrafiles'"); items.Should().BeNull(); } @@ -45,7 +45,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration }); }); - var items = db.QueryScalar("SELECT Value FROM Config WHERE Key = 'importextrafiles'"); + var items = db.QueryScalar("SELECT \"Value\" FROM \"Config\" WHERE \"Key\" = 'importextrafiles'"); items.Should().Be("True"); } } diff --git a/src/NzbDrone.Core.Test/Datastore/Migration/110_fix_extra_files_configFixture.cs b/src/NzbDrone.Core.Test/Datastore/Migration/110_fix_extra_files_configFixture.cs index b7c02f8d6..3fc62b809 100644 --- a/src/NzbDrone.Core.Test/Datastore/Migration/110_fix_extra_files_configFixture.cs +++ b/src/NzbDrone.Core.Test/Datastore/Migration/110_fix_extra_files_configFixture.cs @@ -13,7 +13,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration { var db = WithMigrationTestDb(); - var itemEnabled = db.QueryScalar("SELECT Value FROM Config WHERE Key = 'importextrafiles'"); + var itemEnabled = db.QueryScalar("SELECT \"Value\" FROM \"Config\" WHERE \"Key\" = 'importextrafiles'"); itemEnabled.Should().BeNull(); } @@ -29,7 +29,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration }); }); - var itemEnabled = db.QueryScalar("SELECT Value FROM Config WHERE Key = 'importextrafiles'"); + var itemEnabled = db.QueryScalar("SELECT \"Value\" FROM \"Config\" WHERE \"Key\" = 'importextrafiles'"); itemEnabled.Should().Be("True"); } @@ -51,10 +51,10 @@ namespace NzbDrone.Core.Test.Datastore.Migration }); }); - var itemEnabled = db.QueryScalar("SELECT Value FROM Config WHERE Key = 'importextrafiles'"); + var itemEnabled = db.QueryScalar("SELECT \"Value\" FROM \"Config\" WHERE \"Key\" = 'importextrafiles'"); itemEnabled.Should().Be("False"); - var itemExtensions = db.QueryScalar("SELECT Value FROM Config WHERE Key = 'extrafileextensions'"); + var itemExtensions = db.QueryScalar("SELECT \"Value\" FROM \"Config\" WHERE \"Key\" = 'extrafileextensions'"); itemExtensions.Should().Be("srt"); } @@ -76,10 +76,10 @@ namespace NzbDrone.Core.Test.Datastore.Migration }); }); - var itemEnabled = db.QueryScalar("SELECT Value FROM Config WHERE Key = 'importextrafiles'"); + var itemEnabled = db.QueryScalar("SELECT \"Value\" FROM \"Config\" WHERE \"Key\" = 'importextrafiles'"); itemEnabled.Should().Be("True"); - var itemExtensions = db.QueryScalar("SELECT Value FROM Config WHERE Key = 'extrafileextensions'"); + var itemExtensions = db.QueryScalar("SELECT \"Value\" FROM \"Config\" WHERE \"Key\" = 'extrafileextensions'"); itemExtensions.Should().Be(""); } @@ -95,10 +95,10 @@ namespace NzbDrone.Core.Test.Datastore.Migration }); }); - var itemEnabled = db.QueryScalar("SELECT Value FROM Config WHERE Key = 'importextrafiles'"); + var itemEnabled = db.QueryScalar("SELECT \"Value\" FROM \"Config\" WHERE \"Key\" = 'importextrafiles'"); itemEnabled.Should().Be("False"); - var itemExtensions = db.QueryScalar("SELECT Value FROM Config WHERE Key = 'extrafileextensions'"); + var itemExtensions = db.QueryScalar("SELECT \"Value\" FROM \"Config\" WHERE \"Key\" = 'extrafileextensions'"); itemExtensions.Should().BeNull(); } @@ -120,10 +120,10 @@ namespace NzbDrone.Core.Test.Datastore.Migration }); }); - var itemEnabled = db.QueryScalar("SELECT Value FROM Config WHERE Key = 'importextrafiles'"); + var itemEnabled = db.QueryScalar("SELECT \"Value\" FROM \"Config\" WHERE \"Key\" = 'importextrafiles'"); itemEnabled.Should().Be("False"); - var itemExtensions = db.QueryScalar("SELECT Value FROM Config WHERE Key = 'extrafileextensions'"); + var itemExtensions = db.QueryScalar("SELECT \"Value\" FROM \"Config\" WHERE \"Key\" = 'extrafileextensions'"); itemExtensions.Should().Be("sub"); } } diff --git a/src/NzbDrone.Core.Test/Datastore/Migration/117_add_webrip_qualites_in_profileFixture.cs b/src/NzbDrone.Core.Test/Datastore/Migration/117_add_webrip_qualites_in_profileFixture.cs index 78c976e1a..9c6774b03 100644 --- a/src/NzbDrone.Core.Test/Datastore/Migration/117_add_webrip_qualites_in_profileFixture.cs +++ b/src/NzbDrone.Core.Test/Datastore/Migration/117_add_webrip_qualites_in_profileFixture.cs @@ -29,7 +29,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration }); }); - var profiles = db.Query("SELECT Items FROM Profiles LIMIT 1"); + var profiles = db.Query("SELECT \"Items\" FROM \"Profiles\" LIMIT 1"); var items = profiles.First().Items; items.Should().HaveCount(6); @@ -52,7 +52,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration }); }); - var profiles = db.Query("SELECT Items FROM Profiles LIMIT 1"); + var profiles = db.Query("SELECT \"Items\" FROM \"Profiles\" LIMIT 1"); var items = profiles.First().Items; items.Should().HaveCount(6); @@ -75,7 +75,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration }); }); - var profiles = db.Query("SELECT Items FROM Profiles LIMIT 1"); + var profiles = db.Query("SELECT \"Items\" FROM \"Profiles\" LIMIT 1"); var items = profiles.First().Items; items.Should().HaveCount(6); @@ -98,7 +98,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration }); }); - var profiles = db.Query("SELECT Items FROM Profiles LIMIT 1"); + var profiles = db.Query("SELECT \"Items\" FROM \"Profiles\" LIMIT 1"); var items = profiles.First().Items; items[1].Items.First().Quality.Should().Be((int)Quality.WEBRip480p); diff --git a/src/NzbDrone.Core.Test/Datastore/Migration/121_update_animetosho_urlFixture.cs b/src/NzbDrone.Core.Test/Datastore/Migration/121_update_animetosho_urlFixture.cs index 35418167a..ad3c3e0c6 100644 --- a/src/NzbDrone.Core.Test/Datastore/Migration/121_update_animetosho_urlFixture.cs +++ b/src/NzbDrone.Core.Test/Datastore/Migration/121_update_animetosho_urlFixture.cs @@ -32,7 +32,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration }); }); - var items = db.Query("SELECT * FROM Indexers"); + var items = db.Query("SELECT * FROM \"Indexers\""); items.Should().HaveCount(1); items.First().Settings.ToObject().BaseUrl.Should().Be(baseUrl.Replace("animetosho", "feed.animetosho")); diff --git a/src/NzbDrone.Core.Test/Datastore/Migration/122_add_remux_qualities_in_profileFixture.cs b/src/NzbDrone.Core.Test/Datastore/Migration/122_add_remux_qualities_in_profileFixture.cs index 74ca3960e..2b1613a7f 100644 --- a/src/NzbDrone.Core.Test/Datastore/Migration/122_add_remux_qualities_in_profileFixture.cs +++ b/src/NzbDrone.Core.Test/Datastore/Migration/122_add_remux_qualities_in_profileFixture.cs @@ -23,7 +23,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration }); }); - var profiles = db.Query("SELECT Items FROM Profiles LIMIT 1"); + var profiles = db.Query("SELECT \"Items\" FROM \"Profiles\" LIMIT 1"); var items = profiles.First().Items; items.Should().HaveCount(4); @@ -46,7 +46,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration }); }); - var profiles = db.Query("SELECT Items FROM Profiles LIMIT 1"); + var profiles = db.Query("SELECT \"Items\" FROM \"Profiles\" LIMIT 1"); var items = profiles.First().Items; items.Should().HaveCount(4); diff --git a/src/NzbDrone.Core.Test/Datastore/Migration/128_rename_quality_profiles_add_upgrade_allowedFixture.cs b/src/NzbDrone.Core.Test/Datastore/Migration/128_rename_quality_profiles_add_upgrade_allowedFixture.cs index 97f45a5cf..11e9bd55a 100644 --- a/src/NzbDrone.Core.Test/Datastore/Migration/128_rename_quality_profiles_add_upgrade_allowedFixture.cs +++ b/src/NzbDrone.Core.Test/Datastore/Migration/128_rename_quality_profiles_add_upgrade_allowedFixture.cs @@ -16,11 +16,11 @@ namespace NzbDrone.Core.Test.Datastore.Migration var dbBefore = WithTestDb(new MigrationContext(MigrationType, 110)); // Ensure 111 isn't applied - dbBefore.GetDirectDataMapper().Query("INSERT INTO VersionInfo (Version, AppliedOn, Description) VALUES (111, '2018-12-24T18:21:07', 'remove_bitmetv')"); + dbBefore.GetDirectDataMapper().Query("INSERT INTO \"VersionInfo\" (\"Version\", \"AppliedOn\", \"Description\") VALUES (111, '2018-12-24T18:21:07', 'remove_bitmetv')"); var dbAfter = WithMigrationTestDb(); - var result = dbAfter.QueryScalar("SELECT COUNT(*) FROM VersionInfo WHERE Description = 'remove_bitmetv'"); + var result = dbAfter.QueryScalar("SELECT COUNT(*) FROM \"VersionInfo\" WHERE \"Description\" = 'remove_bitmetv'"); result.Should().Be(0); } diff --git a/src/NzbDrone.Core.Test/Datastore/Migration/132_add_download_client_priorityFixture.cs b/src/NzbDrone.Core.Test/Datastore/Migration/132_add_download_client_priorityFixture.cs index 373377d91..832c6e954 100644 --- a/src/NzbDrone.Core.Test/Datastore/Migration/132_add_download_client_priorityFixture.cs +++ b/src/NzbDrone.Core.Test/Datastore/Migration/132_add_download_client_priorityFixture.cs @@ -18,7 +18,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration { c.Insert.IntoTable("DownloadClients").Row(new { - Enable = 1, + Enable = true, Name = "Deluge", Implementation = "Deluge", Settings = new DelugeSettings85 @@ -31,7 +31,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration }); }); - var items = db.Query("SELECT * FROM DownloadClients"); + var items = db.Query("SELECT * FROM \"DownloadClients\""); items.Should().HaveCount(1); items.First().Priority.Should().Be(1); @@ -44,7 +44,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration { c.Insert.IntoTable("DownloadClients").Row(new { - Enable = 1, + Enable = true, Name = "Deluge", Implementation = "Deluge", Settings = new DelugeSettings85 @@ -56,7 +56,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration ConfigContract = "DelugeSettings" }).Row(new { - Enable = 1, + Enable = true, Name = "Deluge2", Implementation = "Deluge", Settings = new DelugeSettings85 @@ -68,7 +68,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration ConfigContract = "DelugeSettings" }).Row(new { - Enable = 1, + Enable = true, Name = "sab", Implementation = "Sabnzbd", Settings = new SabnzbdSettings81 @@ -80,7 +80,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration }); }); - var items = db.Query("SELECT * FROM DownloadClients"); + var items = db.Query("SELECT * FROM \"DownloadClients\""); items.Should().HaveCount(3); items[0].Priority.Should().Be(1); @@ -95,7 +95,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration { c.Insert.IntoTable("DownloadClients").Row(new { - Enable = 0, + Enable = false, Name = "Deluge", Implementation = "Deluge", Settings = new DelugeSettings85 @@ -107,7 +107,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration ConfigContract = "DelugeSettings" }).Row(new { - Enable = 0, + Enable = false, Name = "Deluge2", Implementation = "Deluge", Settings = new DelugeSettings85 @@ -119,7 +119,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration ConfigContract = "DelugeSettings" }).Row(new { - Enable = 0, + Enable = false, Name = "sab", Implementation = "Sabnzbd", Settings = new SabnzbdSettings81 @@ -131,7 +131,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration }); }); - var items = db.Query("SELECT * FROM DownloadClients"); + var items = db.Query("SELECT * FROM \"DownloadClients\""); items.Should().HaveCount(3); items[0].Priority.Should().Be(1); diff --git a/src/NzbDrone.Core.Test/Datastore/Migration/148_mediainfo_channel_propertiesFixture.cs b/src/NzbDrone.Core.Test/Datastore/Migration/148_mediainfo_channel_propertiesFixture.cs index c73328db2..3a5b005e7 100644 --- a/src/NzbDrone.Core.Test/Datastore/Migration/148_mediainfo_channel_propertiesFixture.cs +++ b/src/NzbDrone.Core.Test/Datastore/Migration/148_mediainfo_channel_propertiesFixture.cs @@ -67,7 +67,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration AddEpisodeFile(c, 1); }); - var items = db.Query("SELECT MediaInfo FROM EpisodeFiles"); + var items = db.Query("SELECT \"MediaInfo\" FROM \"EpisodeFiles\""); items.Should().HaveCount(1); diff --git a/src/NzbDrone.Core.Test/Datastore/Migration/157_email_multiple_addressesFixture.cs b/src/NzbDrone.Core.Test/Datastore/Migration/157_email_multiple_addressesFixture.cs index 19e937aaf..e38f647c4 100644 --- a/src/NzbDrone.Core.Test/Datastore/Migration/157_email_multiple_addressesFixture.cs +++ b/src/NzbDrone.Core.Test/Datastore/Migration/157_email_multiple_addressesFixture.cs @@ -37,7 +37,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration }); }); - var items = db.Query("SELECT * FROM Notifications"); + var items = db.Query("SELECT * FROM \"Notifications\""); items.Should().HaveCount(1); items.First().Implementation.Should().Be("Email"); diff --git a/src/NzbDrone.Core.Test/Datastore/Migration/158_cdh_per_downloadclientFixture.cs b/src/NzbDrone.Core.Test/Datastore/Migration/158_cdh_per_downloadclientFixture.cs index e2a05c84a..4ca329932 100644 --- a/src/NzbDrone.Core.Test/Datastore/Migration/158_cdh_per_downloadclientFixture.cs +++ b/src/NzbDrone.Core.Test/Datastore/Migration/158_cdh_per_downloadclientFixture.cs @@ -19,7 +19,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration { c.Insert.IntoTable("DownloadClients").Row(new { - Enable = 1, + Enable = true, Name = "Deluge", Implementation = "Deluge", Priority = 1, @@ -33,7 +33,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration }); }); - var items = db.Query("SELECT * FROM DownloadClients"); + var items = db.Query("SELECT * FROM \"DownloadClients\""); items.Should().HaveCount(1); items.First().RemoveCompletedDownloads.Should().BeFalse(); @@ -53,7 +53,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration c.Insert.IntoTable("DownloadClients").Row(new { - Enable = 1, + Enable = true, Name = "Deluge", Implementation = "Deluge", Priority = 1, @@ -67,7 +67,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration }); }); - var items = db.Query("SELECT * FROM DownloadClients"); + var items = db.Query("SELECT * FROM \"DownloadClients\""); items.Should().HaveCount(1); items.First().RemoveCompletedDownloads.Should().BeTrue(); @@ -81,7 +81,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration { c.Insert.IntoTable("DownloadClients").Row(new { - Enable = 1, + Enable = true, Name = "RTorrent", Implementation = "RTorrent", Priority = 1, @@ -95,7 +95,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration }); }); - var items = db.Query("SELECT * FROM DownloadClients"); + var items = db.Query("SELECT * FROM \"DownloadClients\""); items.Should().HaveCount(1); items.First().RemoveCompletedDownloads.Should().BeFalse(); diff --git a/src/NzbDrone.Core.Test/Datastore/Migration/161_fix_pending_releasesFixture.cs b/src/NzbDrone.Core.Test/Datastore/Migration/161_fix_pending_releasesFixture.cs index ba6067432..1aaf4afeb 100644 --- a/src/NzbDrone.Core.Test/Datastore/Migration/161_fix_pending_releasesFixture.cs +++ b/src/NzbDrone.Core.Test/Datastore/Migration/161_fix_pending_releasesFixture.cs @@ -74,13 +74,13 @@ namespace NzbDrone.Core.Test.Datastore.Migration ""isPossibleSceneSeasonSpecial"": false }", Release = "{}", - Reason = PendingReleaseReason.Delay + Reason = (int)PendingReleaseReason.Delay }); }); - var json = db.Query("SELECT ParsedEpisodeInfo FROM PendingReleases").First(); + var json = db.Query("SELECT \"ParsedEpisodeInfo\" FROM \"PendingReleases\"").First(); - var pending = db.Query("SELECT ParsedEpisodeInfo FROM PendingReleases").First(); + var pending = db.Query("SELECT \"ParsedEpisodeInfo\" FROM \"PendingReleases\"").First(); pending.Quality.Quality.Should().Be(Quality.HDTV720p.Id); pending.Language.Should().Be(Language.English.Id); } diff --git a/src/NzbDrone.Core.Test/Datastore/Migration/171_add_custom_formatsFixture.cs b/src/NzbDrone.Core.Test/Datastore/Migration/171_add_custom_formatsFixture.cs index af3b8171e..7846398c4 100644 --- a/src/NzbDrone.Core.Test/Datastore/Migration/171_add_custom_formatsFixture.cs +++ b/src/NzbDrone.Core.Test/Datastore/Migration/171_add_custom_formatsFixture.cs @@ -36,7 +36,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration }); }); - var customFormats = db.Query("SELECT Id, Name, IncludeCustomFormatWhenRenaming, Specifications FROM CustomFormats"); + var customFormats = db.Query("SELECT \"Id\", \"Name\", \"IncludeCustomFormatWhenRenaming\", \"Specifications\" FROM \"CustomFormats\""); customFormats.Should().HaveCount(1); customFormats.First().Name.Should().Be("Profile_1"); @@ -69,7 +69,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration }); }); - var customFormats = db.Query("SELECT Id, Name, IncludeCustomFormatWhenRenaming, Specifications FROM CustomFormats"); + var customFormats = db.Query("SELECT \"Id\", \"Name\", \"IncludeCustomFormatWhenRenaming\", \"Specifications\" FROM \"CustomFormats\""); customFormats.Should().HaveCount(0); } @@ -99,7 +99,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration }); }); - var customFormats = db.Query("SELECT Id, Name, IncludeCustomFormatWhenRenaming, Specifications FROM CustomFormats"); + var customFormats = db.Query("SELECT \"Id\", \"Name\", \"IncludeCustomFormatWhenRenaming\", \"Specifications\" FROM \"CustomFormats\""); customFormats.Should().HaveCount(1); customFormats.First().Name.Should().Be("Profile_1"); @@ -136,7 +136,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration }); }); - var releaseProfiles = db.Query("SELECT Id, Name FROM ReleaseProfiles"); + var releaseProfiles = db.Query("SELECT \"Id\", \"Name\" FROM \"ReleaseProfiles\""); releaseProfiles.Should().HaveCount(1); releaseProfiles.First().Name.Should().Be("Profile"); @@ -167,7 +167,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration }); }); - var releaseProfiles = db.Query("SELECT Id, Name FROM ReleaseProfiles"); + var releaseProfiles = db.Query("SELECT \"Id\", \"Name\" FROM \"ReleaseProfiles\""); releaseProfiles.Should().HaveCount(0); } @@ -196,7 +196,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration }); }); - var customFormats = db.Query("SELECT Id, Name, IncludeCustomFormatWhenRenaming, Specifications FROM CustomFormats"); + var customFormats = db.Query("SELECT \"Id\", \"Name\", \"IncludeCustomFormatWhenRenaming\", \"Specifications\" FROM \"CustomFormats\""); customFormats.Should().HaveCount(1); customFormats.First().Name.Should().Be("Unnamed_1"); @@ -246,7 +246,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration }); }); - var customFormats = db.Query("SELECT Id, Name, IncludeCustomFormatWhenRenaming, Specifications FROM CustomFormats"); + var customFormats = db.Query("SELECT \"Id\", \"Name\", \"IncludeCustomFormatWhenRenaming\", \"Specifications\" FROM \"CustomFormats\""); customFormats.Should().HaveCount(2); customFormats.First().Name.Should().Be("Unnamed_1"); @@ -333,7 +333,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration }); }); - var customFormats = db.Query("SELECT Id, Name, IncludeCustomFormatWhenRenaming, Specifications FROM CustomFormats"); + var customFormats = db.Query("SELECT \"Id\", \"Name\", \"IncludeCustomFormatWhenRenaming\", \"Specifications\" FROM \"CustomFormats\""); customFormats.Should().HaveCount(6); customFormats.First().Name.Should().Be("Some - Profile_1_0"); @@ -372,7 +372,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration }); }); - var customFormats = db.Query("SELECT Id, Name, IncludeCustomFormatWhenRenaming, Specifications FROM CustomFormats"); + var customFormats = db.Query("SELECT \"Id\", \"Name\", \"IncludeCustomFormatWhenRenaming\", \"Specifications\" FROM \"CustomFormats\""); customFormats.Should().HaveCount(2); customFormats.First().Name.Should().Be("Profile_1_0"); @@ -413,7 +413,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration }); }); - var customFormats = db.Query("SELECT Id, Name, FormatItems FROM QualityProfiles"); + var customFormats = db.Query("SELECT \"Id\", \"Name\", \"FormatItems\" FROM \"QualityProfiles\""); customFormats.Should().HaveCount(1); customFormats.First().FormatItems.Should().HaveCount(1); @@ -452,7 +452,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration }); }); - var customFormats = db.Query("SELECT Id, Name, FormatItems FROM QualityProfiles"); + var customFormats = db.Query("SELECT \"Id\", \"Name\", \"FormatItems\" FROM \"QualityProfiles\""); customFormats.Should().HaveCount(1); customFormats.First().FormatItems.Should().HaveCount(1); @@ -466,14 +466,14 @@ namespace NzbDrone.Core.Test.Datastore.Migration { c.Insert.IntoTable("NamingConfig").Row(new { - MultiEpisodeStyle = false, + MultiEpisodeStyle = 0, StandardEpisodeFormat = "{Series Title} - S{season:00}E{episode:00} - {Episode Title} {Preferred Words } {Quality Full}", DailyEpisodeFormat = "{Series Title} - {Air-Date} - {Episode Title} {Preferred.Words } {Quality Full}", AnimeEpisodeFormat = "{Series Title} - S{season:00}E{episode:00} - {Preferred_Words} {Quality Full}", }); }); - var customFormats = db.Query("SELECT StandardEpisodeFormat, DailyEpisodeFormat, AnimeEpisodeFormat FROM NamingConfig"); + var customFormats = db.Query("SELECT \"StandardEpisodeFormat\", \"DailyEpisodeFormat\", \"AnimeEpisodeFormat\" FROM \"NamingConfig\""); customFormats.Should().HaveCount(1); customFormats.First().StandardEpisodeFormat.Should().Be("{Series Title} - S{season:00}E{episode:00} - {Episode Title} {Custom Formats } {Quality Full}"); @@ -506,7 +506,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration }); }); - var customFormats = db.Query("SELECT Id, Name, IncludeCustomFormatWhenRenaming, Specifications FROM CustomFormats"); + var customFormats = db.Query("SELECT \"Id\", \"Name\", \"IncludeCustomFormatWhenRenaming\", \"Specifications\" FROM \"CustomFormats\""); customFormats.Should().HaveCount(1); customFormats.First().Specifications.Should().HaveCount(1); @@ -538,7 +538,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration }); }); - var customFormats = db.Query("SELECT Id, Name, IncludeCustomFormatWhenRenaming, Specifications FROM CustomFormats"); + var customFormats = db.Query("SELECT \"Id\", \"Name\", \"IncludeCustomFormatWhenRenaming\", \"Specifications\" FROM \"CustomFormats\""); customFormats.Should().HaveCount(1); customFormats.First().Specifications.Should().HaveCount(1); diff --git a/src/NzbDrone.Core.Test/Datastore/Migration/184_remove_invalid_roksbox_metadata_imagesFixture.cs b/src/NzbDrone.Core.Test/Datastore/Migration/184_remove_invalid_roksbox_metadata_imagesFixture.cs index a67e6786b..3a413fc76 100644 --- a/src/NzbDrone.Core.Test/Datastore/Migration/184_remove_invalid_roksbox_metadata_imagesFixture.cs +++ b/src/NzbDrone.Core.Test/Datastore/Migration/184_remove_invalid_roksbox_metadata_imagesFixture.cs @@ -43,7 +43,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration }); }); - var metadataFiles = db.Query("SELECT * FROM MetadataFiles"); + var metadataFiles = db.Query("SELECT * FROM \"MetadataFiles\""); metadataFiles.Should().HaveCount(1); metadataFiles.First().RelativePath.Should().NotContain("metadata"); diff --git a/src/NzbDrone.Core.Test/Datastore/Migration/192_import_exclusion_typeFixture.cs b/src/NzbDrone.Core.Test/Datastore/Migration/192_import_exclusion_typeFixture.cs index 19729798b..35a5e5d88 100644 --- a/src/NzbDrone.Core.Test/Datastore/Migration/192_import_exclusion_typeFixture.cs +++ b/src/NzbDrone.Core.Test/Datastore/Migration/192_import_exclusion_typeFixture.cs @@ -23,9 +23,9 @@ namespace NzbDrone.Core.Test.Datastore.Migration }); // Should be able to insert as int after migration - db.Execute("INSERT INTO ImportListExclusions (TvdbId, Title) VALUES (2, 'Some Other Series')"); + db.Execute("INSERT INTO \"ImportListExclusions\" (\"TvdbId\", \"Title\") VALUES (2, 'Some Other Series')"); - var exclusions = db.Query("SELECT * FROM ImportListExclusions"); + var exclusions = db.Query("SELECT * FROM \"ImportListExclusions\""); exclusions.Should().HaveCount(2); exclusions.First().TvdbId.Should().Be(1); diff --git a/src/NzbDrone.Core.Test/Datastore/WhereBuilderFixture.cs b/src/NzbDrone.Core.Test/Datastore/WhereBuilderPostgresFixture.cs similarity index 88% rename from src/NzbDrone.Core.Test/Datastore/WhereBuilderFixture.cs rename to src/NzbDrone.Core.Test/Datastore/WhereBuilderPostgresFixture.cs index e478c2baa..ab8d1860e 100644 --- a/src/NzbDrone.Core.Test/Datastore/WhereBuilderFixture.cs +++ b/src/NzbDrone.Core.Test/Datastore/WhereBuilderPostgresFixture.cs @@ -11,9 +11,9 @@ using NzbDrone.Core.Tv; namespace NzbDrone.Core.Test.Datastore { [TestFixture] - public class WhereBuilderFixture : CoreTest + public class WhereBuilderPostgresFixture : CoreTest { - private WhereBuilder _subject; + private WhereBuilderPostgres _subject; [OneTimeSetUp] public void MapTables() @@ -22,9 +22,9 @@ namespace NzbDrone.Core.Test.Datastore Mocker.Resolve(); } - private WhereBuilder Where(Expression> filter) + private WhereBuilderPostgres Where(Expression> filter) { - return new WhereBuilder(filter, true, 0); + return new WhereBuilderPostgres(filter, true, 0); } [Test] @@ -71,7 +71,7 @@ namespace NzbDrone.Core.Test.Datastore public void where_throws_without_concrete_condition_if_requiresConcreteCondition() { Expression> filter = (x, y) => x.Id == y.Id; - _subject = new WhereBuilder(filter, true, 0); + _subject = new WhereBuilderPostgres(filter, true, 0); Assert.Throws(() => _subject.ToString()); } @@ -79,7 +79,7 @@ namespace NzbDrone.Core.Test.Datastore public void where_allows_abstract_condition_if_not_requiresConcreteCondition() { Expression> filter = (x, y) => x.Id == y.Id; - _subject = new WhereBuilder(filter, false, 0); + _subject = new WhereBuilderPostgres(filter, false, 0); _subject.ToString().Should().Be($"(\"Series\".\"Id\" = \"Series\".\"Id\")"); } @@ -115,7 +115,7 @@ namespace NzbDrone.Core.Test.Datastore var test = "small"; _subject = Where(x => x.CleanTitle.Contains(test)); - _subject.ToString().Should().Be($"(\"Series\".\"CleanTitle\" LIKE '%' || @Clause1_P1 || '%')"); + _subject.ToString().Should().Be($"(\"Series\".\"CleanTitle\" ILIKE '%' || @Clause1_P1 || '%')"); _subject.Parameters.Get("Clause1_P1").Should().Be(test); } @@ -125,7 +125,7 @@ namespace NzbDrone.Core.Test.Datastore var test = "small"; _subject = Where(x => test.Contains(x.CleanTitle)); - _subject.ToString().Should().Be($"(@Clause1_P1 LIKE '%' || \"Series\".\"CleanTitle\" || '%')"); + _subject.ToString().Should().Be($"(@Clause1_P1 ILIKE '%' || \"Series\".\"CleanTitle\" || '%')"); _subject.Parameters.Get("Clause1_P1").Should().Be(test); } @@ -135,7 +135,7 @@ namespace NzbDrone.Core.Test.Datastore var test = "small"; _subject = Where(x => x.CleanTitle.StartsWith(test)); - _subject.ToString().Should().Be($"(\"Series\".\"CleanTitle\" LIKE @Clause1_P1 || '%')"); + _subject.ToString().Should().Be($"(\"Series\".\"CleanTitle\" ILIKE @Clause1_P1 || '%')"); _subject.Parameters.Get("Clause1_P1").Should().Be(test); } @@ -145,7 +145,7 @@ namespace NzbDrone.Core.Test.Datastore var test = "small"; _subject = Where(x => x.CleanTitle.EndsWith(test)); - _subject.ToString().Should().Be($"(\"Series\".\"CleanTitle\" LIKE '%' || @Clause1_P1)"); + _subject.ToString().Should().Be($"(\"Series\".\"CleanTitle\" ILIKE '%' || @Clause1_P1)"); _subject.Parameters.Get("Clause1_P1").Should().Be(test); } @@ -155,7 +155,7 @@ namespace NzbDrone.Core.Test.Datastore var list = new List { 1, 2, 3 }; _subject = Where(x => list.Contains(x.Id)); - _subject.ToString().Should().Be($"(\"Series\".\"Id\" IN (1, 2, 3))"); + _subject.ToString().Should().Be($"(\"Series\".\"Id\" = ANY (('{{1, 2, 3}}')))"); _subject.Parameters.ParameterNames.Should().BeEmpty(); } @@ -166,7 +166,7 @@ namespace NzbDrone.Core.Test.Datastore var list = new List { 1, 2, 3 }; _subject = Where(x => x.CleanTitle == "test" && list.Contains(x.Id)); - _subject.ToString().Should().Be($"((\"Series\".\"CleanTitle\" = @Clause1_P1) AND (\"Series\".\"Id\" IN (1, 2, 3)))"); + _subject.ToString().Should().Be($"((\"Series\".\"CleanTitle\" = @Clause1_P1) AND (\"Series\".\"Id\" = ANY (('{{1, 2, 3}}'))))"); } [Test] @@ -176,7 +176,7 @@ namespace NzbDrone.Core.Test.Datastore _subject = Where(x => list.Contains(x.CleanTitle)); - _subject.ToString().Should().Be($"(\"Series\".\"CleanTitle\" IN @Clause1_P1)"); + _subject.ToString().Should().Be($"(\"Series\".\"CleanTitle\" = ANY (@Clause1_P1))"); } [Test] @@ -193,7 +193,7 @@ namespace NzbDrone.Core.Test.Datastore var allowed = new List { SeriesStatusType.Upcoming, SeriesStatusType.Continuing }; _subject = Where(x => allowed.Contains(x.Status)); - _subject.ToString().Should().Be($"(\"Series\".\"Status\" IN @Clause1_P1)"); + _subject.ToString().Should().Be($"(\"Series\".\"Status\" = ANY (@Clause1_P1))"); } [Test] @@ -202,7 +202,7 @@ namespace NzbDrone.Core.Test.Datastore var allowed = new SeriesStatusType[] { SeriesStatusType.Upcoming, SeriesStatusType.Continuing }; _subject = Where(x => allowed.Contains(x.Status)); - _subject.ToString().Should().Be($"(\"Series\".\"Status\" IN @Clause1_P1)"); + _subject.ToString().Should().Be($"(\"Series\".\"Status\" = ANY (@Clause1_P1))"); } } } diff --git a/src/NzbDrone.Core.Test/Datastore/WhereBuilderSqliteFixture.cs b/src/NzbDrone.Core.Test/Datastore/WhereBuilderSqliteFixture.cs new file mode 100644 index 000000000..71a37c094 --- /dev/null +++ b/src/NzbDrone.Core.Test/Datastore/WhereBuilderSqliteFixture.cs @@ -0,0 +1,198 @@ +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.Test.Framework; +using NzbDrone.Core.Tv; + +namespace NzbDrone.Core.Test.Datastore +{ + [TestFixture] + public class WhereBuilderSqliteFixture : CoreTest + { + private WhereBuilderSqlite _subject; + + [OneTimeSetUp] + public void MapTables() + { + // Generate table mapping + Mocker.Resolve(); + } + + private WhereBuilderSqlite Where(Expression> filter) + { + return new WhereBuilderSqlite(filter, true, 0); + } + + [Test] + public void where_equal_const() + { + _subject = Where(x => x.Id == 10); + + _subject.ToString().Should().Be($"(\"Series\".\"Id\" = @Clause1_P1)"); + _subject.Parameters.Get("Clause1_P1").Should().Be(10); + } + + [Test] + public void where_equal_variable() + { + var id = 10; + _subject = Where(x => x.Id == id); + + _subject.ToString().Should().Be($"(\"Series\".\"Id\" = @Clause1_P1)"); + _subject.Parameters.Get("Clause1_P1").Should().Be(id); + } + + [Test] + public void where_equal_property() + { + var author = new Series { Id = 10 }; + _subject = Where(x => x.Id == author.Id); + + _subject.Parameters.ParameterNames.Should().HaveCount(1); + _subject.ToString().Should().Be($"(\"Series\".\"Id\" = @Clause1_P1)"); + _subject.Parameters.Get("Clause1_P1").Should().Be(author.Id); + } + + [Test] + public void where_equal_lazy_property() + { + _subject = Where(x => x.QualityProfile.Value.Id == 1); + + _subject.Parameters.ParameterNames.Should().HaveCount(1); + _subject.ToString().Should().Be($"(\"QualityProfiles\".\"Id\" = @Clause1_P1)"); + _subject.Parameters.Get("Clause1_P1").Should().Be(1); + } + + [Test] + public void where_throws_without_concrete_condition_if_requiresConcreteCondition() + { + Expression> filter = (x, y) => x.Id == y.Id; + _subject = new WhereBuilderSqlite(filter, true, 0); + Assert.Throws(() => _subject.ToString()); + } + + [Test] + public void where_allows_abstract_condition_if_not_requiresConcreteCondition() + { + Expression> filter = (x, y) => x.Id == y.Id; + _subject = new WhereBuilderSqlite(filter, false, 0); + _subject.ToString().Should().Be($"(\"Series\".\"Id\" = \"Series\".\"Id\")"); + } + + [Test] + public void where_string_is_null() + { + _subject = Where(x => x.CleanTitle == null); + + _subject.ToString().Should().Be($"(\"Series\".\"CleanTitle\" IS NULL)"); + } + + [Test] + public void where_string_is_null_value() + { + string imdb = null; + _subject = Where(x => x.CleanTitle == imdb); + + _subject.ToString().Should().Be($"(\"Series\".\"CleanTitle\" IS NULL)"); + } + + [Test] + public void where_equal_null_property() + { + var author = new Series { CleanTitle = null }; + _subject = Where(x => x.CleanTitle == author.CleanTitle); + + _subject.ToString().Should().Be($"(\"Series\".\"CleanTitle\" IS NULL)"); + } + + [Test] + public void where_column_contains_string() + { + var test = "small"; + _subject = Where(x => x.CleanTitle.Contains(test)); + + _subject.ToString().Should().Be($"(\"Series\".\"CleanTitle\" LIKE '%' || @Clause1_P1 || '%')"); + _subject.Parameters.Get("Clause1_P1").Should().Be(test); + } + + [Test] + public void where_string_contains_column() + { + var test = "small"; + _subject = Where(x => test.Contains(x.CleanTitle)); + + _subject.ToString().Should().Be($"(@Clause1_P1 LIKE '%' || \"Series\".\"CleanTitle\" || '%')"); + _subject.Parameters.Get("Clause1_P1").Should().Be(test); + } + + [Test] + public void where_column_starts_with_string() + { + var test = "small"; + _subject = Where(x => x.CleanTitle.StartsWith(test)); + + _subject.ToString().Should().Be($"(\"Series\".\"CleanTitle\" LIKE @Clause1_P1 || '%')"); + _subject.Parameters.Get("Clause1_P1").Should().Be(test); + } + + [Test] + public void where_column_ends_with_string() + { + var test = "small"; + _subject = Where(x => x.CleanTitle.EndsWith(test)); + + _subject.ToString().Should().Be($"(\"Series\".\"CleanTitle\" LIKE '%' || @Clause1_P1)"); + _subject.Parameters.Get("Clause1_P1").Should().Be(test); + } + + [Test] + public void where_in_list() + { + var list = new List { 1, 2, 3 }; + _subject = Where(x => list.Contains(x.Id)); + + _subject.ToString().Should().Be($"(\"Series\".\"Id\" IN (1, 2, 3))"); + + _subject.Parameters.ParameterNames.Should().BeEmpty(); + } + + [Test] + public void where_in_list_2() + { + var list = new List { 1, 2, 3 }; + _subject = Where(x => x.CleanTitle == "test" && list.Contains(x.Id)); + + _subject.ToString().Should().Be($"((\"Series\".\"CleanTitle\" = @Clause1_P1) AND (\"Series\".\"Id\" IN (1, 2, 3)))"); + } + + [Test] + public void enum_as_int() + { + _subject = Where(x => x.Status == SeriesStatusType.Continuing); + + _subject.ToString().Should().Be($"(\"Series\".\"Status\" = @Clause1_P1)"); + } + + [Test] + public void enum_in_list() + { + var allowed = new List { SeriesStatusType.Continuing, SeriesStatusType.Ended }; + _subject = Where(x => allowed.Contains(x.Status)); + + _subject.ToString().Should().Be($"(\"Series\".\"Status\" IN @Clause1_P1)"); + } + + [Test] + public void enum_in_array() + { + var allowed = new SeriesStatusType[] { SeriesStatusType.Continuing, SeriesStatusType.Ended }; + _subject = Where(x => allowed.Contains(x.Status)); + + _subject.ToString().Should().Be($"(\"Series\".\"Status\" IN @Clause1_P1)"); + } + } +} diff --git a/src/NzbDrone.Core.Test/Framework/DbTest.cs b/src/NzbDrone.Core.Test/Framework/DbTest.cs index e38336375..fba791b15 100644 --- a/src/NzbDrone.Core.Test/Framework/DbTest.cs +++ b/src/NzbDrone.Core.Test/Framework/DbTest.cs @@ -1,14 +1,18 @@ -using System; +using System; using System.Collections.Generic; using System.Data.SQLite; using System.IO; using System.Linq; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; +using Microsoft.Extensions.Options; +using Npgsql; using NUnit.Framework; using NzbDrone.Common.Extensions; +using NzbDrone.Core.Configuration; using NzbDrone.Core.Datastore; using NzbDrone.Core.Datastore.Migration.Framework; +using NzbDrone.Test.Common.Datastore; namespace NzbDrone.Core.Test.Framework { @@ -49,6 +53,7 @@ namespace NzbDrone.Core.Test.Framework public abstract class DbTest : CoreTest { private ITestDatabase _db; + private DatabaseType _databaseType; protected virtual MigrationType MigrationType => MigrationType.Main; @@ -101,17 +106,39 @@ namespace NzbDrone.Core.Test.Framework private IDatabase CreateDatabase(MigrationContext migrationContext) { + if (_databaseType == DatabaseType.PostgreSQL) + { + CreatePostgresDb(); + } + var factory = Mocker.Resolve(); // If a special migration test or log migration then create new - if (migrationContext.BeforeMigration != null) + if (migrationContext.BeforeMigration != null || _databaseType == DatabaseType.PostgreSQL) { return factory.Create(migrationContext); } + return CreateSqliteDatabase(factory, migrationContext); + } + + private void CreatePostgresDb() + { + var options = Mocker.Resolve>().Value; + PostgresDatabase.Create(options, MigrationType); + } + + private void DropPostgresDb() + { + var options = Mocker.Resolve>().Value; + PostgresDatabase.Drop(options, MigrationType); + } + + private IDatabase CreateSqliteDatabase(IDbFactory factory, MigrationContext migrationContext) + { // Otherwise try to use a cached migrated db - var cachedDb = GetCachedDatabase(migrationContext.MigrationType); - var testDb = GetTestDb(migrationContext.MigrationType); + var cachedDb = SqliteDatabase.GetCachedDb(migrationContext.MigrationType); + var testDb = GetTestSqliteDb(migrationContext.MigrationType); if (File.Exists(cachedDb)) { TestLogger.Info($"Using cached initial database {cachedDb}"); @@ -131,12 +158,7 @@ namespace NzbDrone.Core.Test.Framework } } - private string GetCachedDatabase(MigrationType type) - { - return Path.Combine(TestContext.CurrentContext.TestDirectory, $"cached_{type}.db"); - } - - private string GetTestDb(MigrationType type) + private string GetTestSqliteDb(MigrationType type) { return type == MigrationType.Main ? TestFolderInfo.GetDatabase() : TestFolderInfo.GetLogDatabase(); } @@ -151,6 +173,13 @@ namespace NzbDrone.Core.Test.Framework WithTempAsAppPath(); SetupLogging(); + // populate the possible postgres options + var postgresOptions = PostgresDatabase.GetTestOptions(); + _databaseType = postgresOptions.Host.IsNotNullOrWhiteSpace() ? DatabaseType.PostgreSQL : DatabaseType.SQLite; + + // Set up remaining container services + Mocker.SetConstant(Options.Create(postgresOptions)); + Mocker.SetConstant(Mocker.Resolve()); Mocker.SetConstant(Mocker.Resolve()); Mocker.SetConstant(Mocker.Resolve()); @@ -170,12 +199,19 @@ namespace NzbDrone.Core.Test.Framework // Make sure there are no lingering connections. (When this happens it means we haven't disposed something properly) GC.Collect(); GC.WaitForPendingFinalizers(); + SQLiteConnection.ClearAllPools(); + NpgsqlConnection.ClearAllPools(); if (TestFolderInfo != null) { DeleteTempFolder(TestFolderInfo.AppDataFolder); } + + if (_databaseType == DatabaseType.PostgreSQL) + { + DropPostgresDb(); + } } } } diff --git a/src/NzbDrone.Core.Test/Framework/DbTestCleanup.cs b/src/NzbDrone.Core.Test/Framework/DbTestCleanup.cs index 587043e95..ae6b102a7 100644 --- a/src/NzbDrone.Core.Test/Framework/DbTestCleanup.cs +++ b/src/NzbDrone.Core.Test/Framework/DbTestCleanup.cs @@ -1,5 +1,7 @@ using System.IO; using NUnit.Framework; +using NzbDrone.Core.Datastore.Migration.Framework; +using NzbDrone.Test.Common.Datastore; namespace NzbDrone.Core.Test { @@ -10,13 +12,13 @@ namespace NzbDrone.Core.Test [OneTimeTearDown] public void ClearCachedDatabase() { - var mainCache = Path.Combine(TestContext.CurrentContext.TestDirectory, $"cached_Main.db"); + var mainCache = SqliteDatabase.GetCachedDb(MigrationType.Main); if (File.Exists(mainCache)) { File.Delete(mainCache); } - var logCache = Path.Combine(TestContext.CurrentContext.TestDirectory, $"cached_Log.db"); + var logCache = SqliteDatabase.GetCachedDb(MigrationType.Log); if (File.Exists(logCache)) { File.Delete(logCache); diff --git a/src/NzbDrone.Core.Test/Framework/TestDatabase.cs b/src/NzbDrone.Core.Test/Framework/TestDatabase.cs index 3fbfdf028..5391cfb1f 100644 --- a/src/NzbDrone.Core.Test/Framework/TestDatabase.cs +++ b/src/NzbDrone.Core.Test/Framework/TestDatabase.cs @@ -23,6 +23,7 @@ namespace NzbDrone.Core.Test.Framework where T : ModelBase, new(); IDirectDataMapper GetDirectDataMapper(); IDbConnection OpenConnection(); + DatabaseType DatabaseType { get; } } public class TestDatabase : ITestDatabase @@ -30,6 +31,8 @@ namespace NzbDrone.Core.Test.Framework private readonly IDatabase _dbConnection; private readonly IEventAggregator _eventAggregator; + public DatabaseType DatabaseType => _dbConnection.DatabaseType; + public TestDatabase(IDatabase dbConnection) { _eventAggregator = new Mock().Object; diff --git a/src/NzbDrone.Core.Test/SeriesStatsTests/SeriesStatisticsFixture.cs b/src/NzbDrone.Core.Test/SeriesStatsTests/SeriesStatisticsFixture.cs index 254b4e987..772b084ae 100644 --- a/src/NzbDrone.Core.Test/SeriesStatsTests/SeriesStatisticsFixture.cs +++ b/src/NzbDrone.Core.Test/SeriesStatsTests/SeriesStatisticsFixture.cs @@ -78,7 +78,7 @@ namespace NzbDrone.Core.Test.SeriesStatsTests var stats = Subject.SeriesStatistics(); stats.Should().HaveCount(1); - stats.First().NextAiring.Should().Be(_episode.AirDateUtc); + stats.First().NextAiring.Should().BeCloseTo(_episode.AirDateUtc.Value, TimeSpan.FromMilliseconds(1000)); stats.First().PreviousAiring.Should().NotHaveValue(); } @@ -105,7 +105,7 @@ namespace NzbDrone.Core.Test.SeriesStatsTests stats.Should().HaveCount(1); stats.First().NextAiring.Should().NotHaveValue(); - stats.First().PreviousAiring.Should().Be(_episode.AirDateUtc); + stats.First().PreviousAiring.Should().BeCloseTo(_episode.AirDateUtc.Value, TimeSpan.FromMilliseconds(1000)); } [Test] @@ -119,7 +119,7 @@ namespace NzbDrone.Core.Test.SeriesStatsTests stats.Should().HaveCount(1); stats.First().NextAiring.Should().NotHaveValue(); - stats.First().PreviousAiring.Should().Be(_episode.AirDateUtc); + stats.First().PreviousAiring.Should().BeCloseTo(_episode.AirDateUtc.Value, TimeSpan.FromMilliseconds(1000)); } [Test] diff --git a/src/NzbDrone.Core/Backup/BackupService.cs b/src/NzbDrone.Core/Backup/BackupService.cs index 56f1fe23c..e45370214 100644 --- a/src/NzbDrone.Core/Backup/BackupService.cs +++ b/src/NzbDrone.Core/Backup/BackupService.cs @@ -189,9 +189,12 @@ namespace NzbDrone.Core.Backup private void BackupDatabase() { - _logger.ProgressDebug("Backing up database"); + if (_maindDb.DatabaseType == DatabaseType.SQLite) + { + _logger.ProgressDebug("Backing up database"); - _makeDatabaseBackup.BackupDatabase(_maindDb, _backupTempFolder); + _makeDatabaseBackup.BackupDatabase(_maindDb, _backupTempFolder); + } } private void BackupConfigFile() diff --git a/src/NzbDrone.Core/Blocklisting/BlocklistRepository.cs b/src/NzbDrone.Core/Blocklisting/BlocklistRepository.cs index e52edea18..43348430b 100644 --- a/src/NzbDrone.Core/Blocklisting/BlocklistRepository.cs +++ b/src/NzbDrone.Core/Blocklisting/BlocklistRepository.cs @@ -40,7 +40,7 @@ namespace NzbDrone.Core.Blocklisting Delete(x => seriesIds.Contains(x.SeriesId)); } - protected override SqlBuilder PagedBuilder() => new SqlBuilder().Join((b, m) => b.SeriesId == m.Id); + protected override SqlBuilder PagedBuilder() => new SqlBuilder(_database.DatabaseType).Join((b, m) => b.SeriesId == m.Id); protected override IEnumerable PagedQuery(SqlBuilder sql) => _database.QueryJoined(sql, (bl, movie) => { bl.Series = movie; diff --git a/src/NzbDrone.Core/Configuration/ConfigFileProvider.cs b/src/NzbDrone.Core/Configuration/ConfigFileProvider.cs index 766147a2a..e48f9c245 100644 --- a/src/NzbDrone.Core/Configuration/ConfigFileProvider.cs +++ b/src/NzbDrone.Core/Configuration/ConfigFileProvider.cs @@ -5,12 +5,14 @@ using System.Linq; using System.Text.RegularExpressions; using System.Xml; using System.Xml.Linq; +using Microsoft.Extensions.Options; using NzbDrone.Common.Cache; using NzbDrone.Common.Disk; using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.Extensions; using NzbDrone.Core.Authentication; using NzbDrone.Core.Configuration.Events; +using NzbDrone.Core.Datastore; using NzbDrone.Core.Lifecycle; using NzbDrone.Core.Messaging.Commands; using NzbDrone.Core.Messaging.Events; @@ -52,6 +54,12 @@ namespace NzbDrone.Core.Configuration int SyslogPort { get; } string SyslogLevel { get; } string Theme { get; } + string PostgresHost { get; } + int PostgresPort { get; } + string PostgresUser { get; } + string PostgresPassword { get; } + string PostgresMainDb { get; } + string PostgresLogDb { get; } } public class ConfigFileProvider : IConfigFileProvider @@ -61,6 +69,7 @@ namespace NzbDrone.Core.Configuration private readonly IEventAggregator _eventAggregator; private readonly IDiskProvider _diskProvider; private readonly ICached _cache; + private readonly PostgresOptions _postgresOptions; private readonly string _configFile; private static readonly Regex HiddenCharacterRegex = new Regex("[^a-z0-9]", RegexOptions.Compiled | RegexOptions.IgnoreCase); @@ -70,12 +79,14 @@ namespace NzbDrone.Core.Configuration public ConfigFileProvider(IAppFolderInfo appFolderInfo, ICacheManager cacheManager, IEventAggregator eventAggregator, - IDiskProvider diskProvider) + IDiskProvider diskProvider, + IOptions postgresOptions) { _cache = cacheManager.GetCache(GetType()); _eventAggregator = eventAggregator; _diskProvider = diskProvider; _configFile = appFolderInfo.GetConfigPath(); + _postgresOptions = postgresOptions.Value; } public Dictionary GetConfigDictionary() @@ -191,6 +202,14 @@ namespace NzbDrone.Core.Configuration public string ConsoleLogLevel => GetValue("ConsoleLogLevel", string.Empty, persist: false); public string Theme => GetValue("Theme", "auto", persist: false); + + public string PostgresHost => _postgresOptions?.Host ?? GetValue("PostgresHost", string.Empty, persist: false); + public string PostgresUser => _postgresOptions?.User ?? GetValue("PostgresUser", string.Empty, persist: false); + public string PostgresPassword => _postgresOptions?.Password ?? GetValue("PostgresPassword", string.Empty, persist: false); + public string PostgresMainDb => _postgresOptions?.MainDb ?? GetValue("PostgresMainDb", "sonarr-main", persist: false); + public string PostgresLogDb => _postgresOptions?.LogDb ?? GetValue("PostgresLogDb", "sonarr-log", persist: false); + public int PostgresPort => (_postgresOptions?.Port ?? 0) != 0 ? _postgresOptions.Port : GetValueInt("PostgresPort", 5432, persist: false); + public bool LogSql => GetValueBoolean("LogSql", false, persist: false); public int LogRotate => GetValueInt("LogRotate", 50, persist: false); public bool FilterSentryEvents => GetValueBoolean("FilterSentryEvents", true, persist: false); diff --git a/src/NzbDrone.Core/Datastore/BasicRepository.cs b/src/NzbDrone.Core/Datastore/BasicRepository.cs index e0fab1b1c..86e1240e4 100644 --- a/src/NzbDrone.Core/Datastore/BasicRepository.cs +++ b/src/NzbDrone.Core/Datastore/BasicRepository.cs @@ -67,7 +67,7 @@ namespace NzbDrone.Core.Datastore _updateSql = GetUpdateSql(_properties); } - protected virtual SqlBuilder Builder() => new SqlBuilder(); + protected virtual SqlBuilder Builder() => new SqlBuilder(_database.DatabaseType); protected virtual List Query(SqlBuilder builder) => _database.Query(builder).ToList(); @@ -79,7 +79,7 @@ namespace NzbDrone.Core.Datastore { using (var conn = _database.OpenConnection()) { - return conn.ExecuteScalar($"SELECT COUNT(*) FROM {_table}"); + return conn.ExecuteScalar($"SELECT COUNT(*) FROM \"{_table}\""); } } @@ -175,6 +175,11 @@ namespace NzbDrone.Core.Datastore } } + if (_database.DatabaseType == DatabaseType.PostgreSQL) + { + return $"INSERT INTO \"{_table}\" ({sbColumnList.ToString()}) VALUES ({sbParameterList.ToString()}) RETURNING \"Id\""; + } + return $"INSERT INTO {_table} ({sbColumnList.ToString()}) VALUES ({sbParameterList.ToString()}); SELECT last_insert_rowid() id"; } @@ -182,7 +187,8 @@ namespace NzbDrone.Core.Datastore { SqlBuilderExtensions.LogQuery(_insertSql, model); var multi = connection.QueryMultiple(_insertSql, model, transaction); - var id = (int)multi.Read().First().id; + var multiRead = multi.Read(); + var id = (int)(multiRead.First().id ?? multiRead.First().Id); _keyProperty.SetValue(model, id); return model; @@ -293,7 +299,7 @@ namespace NzbDrone.Core.Datastore { using (var conn = _database.OpenConnection()) { - conn.Execute($"DELETE FROM [{_table}]"); + conn.Execute($"DELETE FROM \"{_table}\""); } if (vacuum) @@ -352,7 +358,7 @@ namespace NzbDrone.Core.Datastore private string GetUpdateSql(List propertiesToUpdate) { var sb = new StringBuilder(); - sb.AppendFormat("UPDATE {0} SET ", _table); + sb.AppendFormat("UPDATE \"{0}\" SET ", _table); for (var i = 0; i < propertiesToUpdate.Count; i++) { @@ -420,9 +426,10 @@ namespace NzbDrone.Core.Datastore pagingSpec.SortKey = $"{_table}.{_keyProperty.Name}"; } + var sortKey = TableMapping.Mapper.GetSortKey(pagingSpec.SortKey); 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 pagingOffset = Math.Max(pagingSpec.Page - 1, 0) * pagingSpec.PageSize; + builder.OrderBy($"\"{sortKey}\" {sortDirection} LIMIT {pagingSpec.PageSize} OFFSET {pagingOffset}"); return queryFunc(builder).ToList(); } diff --git a/src/NzbDrone.Core/Datastore/ConnectionStringFactory.cs b/src/NzbDrone.Core/Datastore/ConnectionStringFactory.cs index 8db300f6e..069b944fb 100644 --- a/src/NzbDrone.Core/Datastore/ConnectionStringFactory.cs +++ b/src/NzbDrone.Core/Datastore/ConnectionStringFactory.cs @@ -1,27 +1,36 @@ -using System; +using System; using System.Data.SQLite; +using Npgsql; using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.Extensions; +using NzbDrone.Core.Configuration; namespace NzbDrone.Core.Datastore { public interface IConnectionStringFactory { - string MainDbConnectionString { get; } - string LogDbConnectionString { get; } + DatabaseConnectionInfo MainDbConnection { get; } + DatabaseConnectionInfo LogDbConnection { get; } string GetDatabasePath(string connectionString); } public class ConnectionStringFactory : IConnectionStringFactory { - public ConnectionStringFactory(IAppFolderInfo appFolderInfo) + private readonly IConfigFileProvider _configFileProvider; + + public ConnectionStringFactory(IAppFolderInfo appFolderInfo, IConfigFileProvider configFileProvider) { - MainDbConnectionString = GetConnectionString(appFolderInfo.GetDatabase()); - LogDbConnectionString = GetConnectionString(appFolderInfo.GetLogDatabase()); + _configFileProvider = configFileProvider; + + MainDbConnection = _configFileProvider.PostgresHost.IsNotNullOrWhiteSpace() ? GetPostgresConnectionString(_configFileProvider.PostgresMainDb) : + GetConnectionString(appFolderInfo.GetDatabase()); + + LogDbConnection = _configFileProvider.PostgresHost.IsNotNullOrWhiteSpace() ? GetPostgresConnectionString(_configFileProvider.PostgresLogDb) : + GetConnectionString(appFolderInfo.GetLogDatabase()); } - public string MainDbConnectionString { get; private set; } - public string LogDbConnectionString { get; private set; } + public DatabaseConnectionInfo MainDbConnection { get; private set; } + public DatabaseConnectionInfo LogDbConnection { get; private set; } public string GetDatabasePath(string connectionString) { @@ -30,23 +39,39 @@ namespace NzbDrone.Core.Datastore return connectionBuilder.DataSource; } - private static string GetConnectionString(string dbPath) + private static DatabaseConnectionInfo GetConnectionString(string dbPath) { - var connectionBuilder = new SQLiteConnectionStringBuilder(); - - connectionBuilder.DataSource = dbPath; - connectionBuilder.CacheSize = (int)-10000; - connectionBuilder.DateTimeKind = DateTimeKind.Utc; - connectionBuilder.JournalMode = OsInfo.IsOsx ? SQLiteJournalModeEnum.Truncate : SQLiteJournalModeEnum.Wal; - connectionBuilder.Pooling = true; - connectionBuilder.Version = 3; + var connectionBuilder = new SQLiteConnectionStringBuilder + { + DataSource = dbPath, + CacheSize = (int)-10000, + DateTimeKind = DateTimeKind.Utc, + JournalMode = OsInfo.IsOsx ? SQLiteJournalModeEnum.Truncate : SQLiteJournalModeEnum.Wal, + Pooling = true, + Version = 3 + }; if (OsInfo.IsOsx) { connectionBuilder.Add("Full FSync", true); } - return connectionBuilder.ConnectionString; + return new DatabaseConnectionInfo(DatabaseType.SQLite, connectionBuilder.ConnectionString); + } + + private DatabaseConnectionInfo GetPostgresConnectionString(string dbName) + { + var connectionBuilder = new NpgsqlConnectionStringBuilder + { + Database = dbName, + Host = _configFileProvider.PostgresHost, + Username = _configFileProvider.PostgresUser, + Password = _configFileProvider.PostgresPassword, + Port = _configFileProvider.PostgresPort, + Enlist = false + }; + + return new DatabaseConnectionInfo(DatabaseType.PostgreSQL, connectionBuilder.ConnectionString); } } } diff --git a/src/NzbDrone.Core/Datastore/Database.cs b/src/NzbDrone.Core/Datastore/Database.cs index a9b6e807f..887039bcb 100644 --- a/src/NzbDrone.Core/Datastore/Database.cs +++ b/src/NzbDrone.Core/Datastore/Database.cs @@ -1,5 +1,8 @@ -using System; +using System; using System.Data; +using System.Data.Common; +using System.Data.SQLite; +using System.Text.RegularExpressions; using Dapper; using NLog; using NzbDrone.Common.Instrumentation; @@ -11,6 +14,7 @@ namespace NzbDrone.Core.Datastore IDbConnection OpenConnection(); Version Version { get; } int Migration { get; } + DatabaseType DatabaseType { get; } void Vacuum(); } @@ -32,15 +36,25 @@ namespace NzbDrone.Core.Datastore return _datamapperFactory(); } + public DatabaseType DatabaseType + { + get + { + using var db = _datamapperFactory(); + + return db is SQLiteConnection ? DatabaseType.SQLite : DatabaseType.PostgreSQL; + } + } + public Version Version { get { - using (var db = _datamapperFactory()) - { - var version = db.QueryFirstOrDefault("SELECT sqlite_version()"); - return new Version(version); - } + using var db = _datamapperFactory(); + var dbConnection = db as DbConnection; + var version = Regex.Replace(dbConnection.ServerVersion, @"\(.*?\)", ""); + + return new Version(version); } } @@ -50,7 +64,7 @@ namespace NzbDrone.Core.Datastore { using (var db = _datamapperFactory()) { - return db.QueryFirstOrDefault("SELECT version from VersionInfo ORDER BY version DESC LIMIT 1"); + return db.QueryFirstOrDefault("SELECT \"Version\" from \"VersionInfo\" ORDER BY \"Version\" DESC LIMIT 1"); } } } @@ -73,4 +87,10 @@ namespace NzbDrone.Core.Datastore } } } + + public enum DatabaseType + { + SQLite, + PostgreSQL + } } diff --git a/src/NzbDrone.Core/Datastore/DatabaseConnectionInfo.cs b/src/NzbDrone.Core/Datastore/DatabaseConnectionInfo.cs new file mode 100644 index 000000000..5b53f086f --- /dev/null +++ b/src/NzbDrone.Core/Datastore/DatabaseConnectionInfo.cs @@ -0,0 +1,14 @@ +namespace NzbDrone.Core.Datastore +{ + public class DatabaseConnectionInfo + { + public DatabaseConnectionInfo(DatabaseType databaseType, string connectionString) + { + DatabaseType = databaseType; + ConnectionString = connectionString; + } + + public DatabaseType DatabaseType { get; internal set; } + public string ConnectionString { get; internal set; } + } +} diff --git a/src/NzbDrone.Core/Datastore/DbFactory.cs b/src/NzbDrone.Core/Datastore/DbFactory.cs index b24fbae85..7c3543638 100644 --- a/src/NzbDrone.Core/Datastore/DbFactory.cs +++ b/src/NzbDrone.Core/Datastore/DbFactory.cs @@ -1,6 +1,10 @@ using System; +using System.Data.Common; using System.Data.SQLite; +using System.Net.Sockets; +using System.Threading; using NLog; +using Npgsql; using NzbDrone.Common.Disk; using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.Exceptions; @@ -57,22 +61,22 @@ namespace NzbDrone.Core.Datastore public IDatabase Create(MigrationContext migrationContext) { - string connectionString; + DatabaseConnectionInfo connectionInfo; switch (migrationContext.MigrationType) { case MigrationType.Main: { - connectionString = _connectionStringFactory.MainDbConnectionString; - CreateMain(connectionString, migrationContext); + connectionInfo = _connectionStringFactory.MainDbConnection; + CreateMain(connectionInfo.ConnectionString, migrationContext); break; } case MigrationType.Log: { - connectionString = _connectionStringFactory.LogDbConnectionString; - CreateLog(connectionString, migrationContext); + connectionInfo = _connectionStringFactory.LogDbConnection; + CreateLog(connectionInfo.ConnectionString, migrationContext); break; } @@ -85,10 +89,19 @@ namespace NzbDrone.Core.Datastore var db = new Database(migrationContext.MigrationType.ToString(), () => { - var conn = SQLiteFactory.Instance.CreateConnection(); - conn.ConnectionString = connectionString; - conn.Open(); + DbConnection conn; + if (connectionInfo.DatabaseType == DatabaseType.SQLite) + { + conn = SQLiteFactory.Instance.CreateConnection(); + conn.ConnectionString = connectionInfo.ConnectionString; + } + else + { + conn = new NpgsqlConnection(connectionInfo.ConnectionString); + } + + conn.Open(); return conn; }); @@ -113,6 +126,39 @@ namespace NzbDrone.Core.Datastore throw new CorruptDatabaseException("Database file: {0} is corrupt, restore from backup if available. See: https://wiki.servarr.com/sonarr/faq#i-am-getting-an-error-database-disk-image-is-malformed", e, fileName); } + catch (NpgsqlException e) + { + if (e.InnerException is SocketException) + { + var retryCount = 3; + + while (true) + { + Logger.Error(e, "Failure to connect to Postgres DB, {0} retries remaining", retryCount); + + Thread.Sleep(5000); + + try + { + _migrationController.Migrate(connectionString, migrationContext); + return; + } + catch (Exception ex) + { + if (--retryCount > 0) + { + continue; + } + + throw new SonarrStartupException(ex, "Error creating main database"); + } + } + } + else + { + throw new SonarrStartupException(e, "Error creating main database"); + } + } catch (Exception e) { throw new SonarrStartupException(e, "Error creating main database"); diff --git a/src/NzbDrone.Core/Datastore/Extensions/BuilderExtensions.cs b/src/NzbDrone.Core/Datastore/Extensions/BuilderExtensions.cs index 97ce5d731..3bff36b7a 100644 --- a/src/NzbDrone.Core/Datastore/Extensions/BuilderExtensions.cs +++ b/src/NzbDrone.Core/Datastore/Extensions/BuilderExtensions.cs @@ -20,12 +20,12 @@ namespace NzbDrone.Core.Datastore public static SqlBuilder Select(this SqlBuilder builder, params Type[] types) { - return builder.Select(types.Select(x => TableMapping.Mapper.TableNameMapping(x) + ".*").Join(", ")); + return builder.Select(types.Select(x => $"\"{TableMapping.Mapper.TableNameMapping(x)}\".*").Join(", ")); } public static SqlBuilder SelectDistinct(this SqlBuilder builder, params Type[] types) { - return builder.Select("DISTINCT " + types.Select(x => TableMapping.Mapper.TableNameMapping(x) + ".*").Join(", ")); + return builder.Select("DISTINCT " + types.Select(x => $"\"{TableMapping.Mapper.TableNameMapping(x)}\".*").Join(", ")); } public static SqlBuilder SelectCount(this SqlBuilder builder) @@ -42,41 +42,48 @@ namespace NzbDrone.Core.Datastore public static SqlBuilder Where(this SqlBuilder builder, Expression> filter) { - var wb = new WhereBuilder(filter, true, builder.Sequence); + var wb = GetWhereBuilder(builder.DatabaseType, filter, true, builder.Sequence); + + return builder.Where(wb.ToString(), wb.Parameters); + } + + public static SqlBuilder WherePostgres(this SqlBuilder builder, Expression> filter) + { + var wb = new WhereBuilderPostgres(filter, true, builder.Sequence); return builder.Where(wb.ToString(), wb.Parameters); } public static SqlBuilder OrWhere(this SqlBuilder builder, Expression> filter) { - var wb = new WhereBuilder(filter, true, builder.Sequence); + var wb = GetWhereBuilder(builder.DatabaseType, filter, true, builder.Sequence); return builder.OrWhere(wb.ToString(), wb.Parameters); } public static SqlBuilder Join(this SqlBuilder builder, Expression> filter) { - var wb = new WhereBuilder(filter, false, builder.Sequence); + var wb = GetWhereBuilder(builder.DatabaseType, filter, false, builder.Sequence); var rightTable = TableMapping.Mapper.TableNameMapping(typeof(TRight)); - return builder.Join($"{rightTable} ON {wb.ToString()}"); + return builder.Join($"\"{rightTable}\" ON {wb.ToString()}"); } public static SqlBuilder LeftJoin(this SqlBuilder builder, Expression> filter) { - var wb = new WhereBuilder(filter, false, builder.Sequence); + var wb = GetWhereBuilder(builder.DatabaseType, filter, false, builder.Sequence); var rightTable = TableMapping.Mapper.TableNameMapping(typeof(TRight)); - return builder.LeftJoin($"{rightTable} ON {wb.ToString()}"); + return builder.LeftJoin($"\"{rightTable}\" ON {wb.ToString()}"); } public static SqlBuilder GroupBy(this SqlBuilder builder, Expression> property) { var table = TableMapping.Mapper.TableNameMapping(typeof(TModel)); var propName = property.GetMemberName().Name; - return builder.GroupBy($"{table}.{propName}"); + return builder.GroupBy($"\"{table}\".\"{propName}\""); } public static SqlBuilder.Template AddSelectTemplate(this SqlBuilder builder, Type type) @@ -138,6 +145,18 @@ namespace NzbDrone.Core.Datastore return sb.ToString(); } + private static WhereBuilder GetWhereBuilder(DatabaseType databaseType, Expression filter, bool requireConcrete, int seq) + { + if (databaseType == DatabaseType.PostgreSQL) + { + return new WhereBuilderPostgres(filter, requireConcrete, seq); + } + else + { + return new WhereBuilderSqlite(filter, requireConcrete, seq); + } + } + private static Dictionary ToDictionary(this DynamicParameters dynamicParams) { var argsDictionary = new Dictionary(); @@ -150,11 +169,14 @@ namespace NzbDrone.Core.Datastore } var templates = dynamicParams.GetType().GetField("templates", BindingFlags.NonPublic | BindingFlags.Instance); - if (templates != null && templates.GetValue(dynamicParams) is List list) + if (templates != null) { - foreach (var objProps in list.Select(obj => obj.GetPropertyValuePairs().ToList())) + if (templates.GetValue(dynamicParams) is List list) { - objProps.ForEach(p => argsDictionary.Add(p.Key, p.Value)); + foreach (var objProps in list.Select(obj => obj.GetPropertyValuePairs().ToList())) + { + objProps.ForEach(p => argsDictionary.Add(p.Key, p.Value)); + } } } diff --git a/src/NzbDrone.Core/Datastore/LogDatabase.cs b/src/NzbDrone.Core/Datastore/LogDatabase.cs index f992c8bbe..a770c2661 100644 --- a/src/NzbDrone.Core/Datastore/LogDatabase.cs +++ b/src/NzbDrone.Core/Datastore/LogDatabase.cs @@ -10,10 +10,12 @@ namespace NzbDrone.Core.Datastore public class LogDatabase : ILogDatabase { private readonly IDatabase _database; + private readonly DatabaseType _databaseType; public LogDatabase(IDatabase database) { _database = database; + _databaseType = _database == null ? DatabaseType.SQLite : _database.DatabaseType; } public IDbConnection OpenConnection() @@ -25,6 +27,8 @@ namespace NzbDrone.Core.Datastore public int Migration => _database.Migration; + public DatabaseType DatabaseType => _databaseType; + public void Vacuum() { _database.Vacuum(); diff --git a/src/NzbDrone.Core/Datastore/MainDatabase.cs b/src/NzbDrone.Core/Datastore/MainDatabase.cs index 4a9d3298c..521293299 100644 --- a/src/NzbDrone.Core/Datastore/MainDatabase.cs +++ b/src/NzbDrone.Core/Datastore/MainDatabase.cs @@ -10,10 +10,12 @@ namespace NzbDrone.Core.Datastore public class MainDatabase : IMainDatabase { private readonly IDatabase _database; + private readonly DatabaseType _databaseType; public MainDatabase(IDatabase database) { _database = database; + _databaseType = _database == null ? DatabaseType.SQLite : _database.DatabaseType; } public IDbConnection OpenConnection() @@ -25,6 +27,8 @@ namespace NzbDrone.Core.Datastore public int Migration => _database.Migration; + public DatabaseType DatabaseType => _databaseType; + public void Vacuum() { _database.Vacuum(); diff --git a/src/NzbDrone.Core/Datastore/Migration/007_add_renameEpisodes_to_naming.cs b/src/NzbDrone.Core/Datastore/Migration/007_add_renameEpisodes_to_naming.cs index 3fc4abef9..92ab47692 100644 --- a/src/NzbDrone.Core/Datastore/Migration/007_add_renameEpisodes_to_naming.cs +++ b/src/NzbDrone.Core/Datastore/Migration/007_add_renameEpisodes_to_naming.cs @@ -1,4 +1,4 @@ -using FluentMigrator; +using FluentMigrator; using NzbDrone.Core.Datastore.Migration.Framework; namespace NzbDrone.Core.Datastore.Migration @@ -13,7 +13,7 @@ namespace NzbDrone.Core.Datastore.Migration .AsBoolean() .Nullable(); - Execute.Sql("UPDATE NamingConfig SET RenameEpisodes =~ UseSceneName"); + Execute.Sql("UPDATE \"NamingConfig\" SET \"RenameEpisodes\" = NOT \"UseSceneName\""); } } } diff --git a/src/NzbDrone.Core/Datastore/Migration/009_fix_renameEpisodes.cs b/src/NzbDrone.Core/Datastore/Migration/009_fix_renameEpisodes.cs index bdc0c54e5..bcd4ffe42 100644 --- a/src/NzbDrone.Core/Datastore/Migration/009_fix_renameEpisodes.cs +++ b/src/NzbDrone.Core/Datastore/Migration/009_fix_renameEpisodes.cs @@ -1,4 +1,4 @@ -using FluentMigrator; +using FluentMigrator; using NzbDrone.Core.Datastore.Migration.Framework; namespace NzbDrone.Core.Datastore.Migration @@ -10,8 +10,8 @@ namespace NzbDrone.Core.Datastore.Migration { Delete.Column("SeasonFolderFormat").FromTable("NamingConfig"); - Execute.Sql("UPDATE NamingConfig SET RenameEpisodes = 1 WHERE RenameEpisodes = -1"); - Execute.Sql("UPDATE NamingConfig SET RenameEpisodes = 0 WHERE RenameEpisodes = -2"); + IfDatabase("sqlite").Update.Table("NamingConfig").Set(new { RenameEpisodes = 1 }).Where(new { RenameEpisodes = -1 }); + IfDatabase("sqlite").Update.Table("NamingConfig").Set(new { RenameEpisodes = 0 }).Where(new { RenameEpisodes = -2 }); } } } diff --git a/src/NzbDrone.Core/Datastore/Migration/010_add_monitored.cs b/src/NzbDrone.Core/Datastore/Migration/010_add_monitored.cs index a64f44877..6147f5b07 100644 --- a/src/NzbDrone.Core/Datastore/Migration/010_add_monitored.cs +++ b/src/NzbDrone.Core/Datastore/Migration/010_add_monitored.cs @@ -1,4 +1,4 @@ -using FluentMigrator; +using FluentMigrator; using NzbDrone.Core.Datastore.Migration.Framework; namespace NzbDrone.Core.Datastore.Migration @@ -11,11 +11,11 @@ namespace NzbDrone.Core.Datastore.Migration Alter.Table("Episodes").AddColumn("Monitored").AsBoolean().Nullable(); Alter.Table("Seasons").AddColumn("Monitored").AsBoolean().Nullable(); - Execute.Sql("UPDATE Episodes SET Monitored = 1 WHERE Ignored = 0"); - Execute.Sql("UPDATE Episodes SET Monitored = 0 WHERE Ignored = 1"); + Update.Table("Episodes").Set(new { Monitored = true }).Where(new { Ignored = false }); + Update.Table("Episodes").Set(new { Monitored = false }).Where(new { Ignored = true }); - Execute.Sql("UPDATE Seasons SET Monitored = 1 WHERE Ignored = 0"); - Execute.Sql("UPDATE Seasons SET Monitored = 0 WHERE Ignored = 1"); + Update.Table("Seasons").Set(new { Monitored = true }).Where(new { Ignored = false }); + Update.Table("Seasons").Set(new { Monitored = false }).Where(new { Ignored = true }); } } } diff --git a/src/NzbDrone.Core/Datastore/Migration/013_add_air_date_utc.cs b/src/NzbDrone.Core/Datastore/Migration/013_add_air_date_utc.cs index ece91b397..bcebcf997 100644 --- a/src/NzbDrone.Core/Datastore/Migration/013_add_air_date_utc.cs +++ b/src/NzbDrone.Core/Datastore/Migration/013_add_air_date_utc.cs @@ -1,4 +1,4 @@ -using FluentMigrator; +using FluentMigrator; using NzbDrone.Core.Datastore.Migration.Framework; namespace NzbDrone.Core.Datastore.Migration @@ -10,7 +10,7 @@ namespace NzbDrone.Core.Datastore.Migration { Alter.Table("Episodes").AddColumn("AirDateUtc").AsDateTime().Nullable(); - Execute.Sql("UPDATE Episodes SET AirDateUtc = AirDate"); + Execute.Sql("UPDATE \"Episodes\" SET \"AirDateUtc\" = \"AirDate\""); } } } diff --git a/src/NzbDrone.Core/Datastore/Migration/016_updated_imported_history_item.cs b/src/NzbDrone.Core/Datastore/Migration/016_updated_imported_history_item.cs index 7a2c50e71..1649cf300 100644 --- a/src/NzbDrone.Core/Datastore/Migration/016_updated_imported_history_item.cs +++ b/src/NzbDrone.Core/Datastore/Migration/016_updated_imported_history_item.cs @@ -1,4 +1,4 @@ -using FluentMigrator; +using FluentMigrator; using NzbDrone.Core.Datastore.Migration.Framework; namespace NzbDrone.Core.Datastore.Migration @@ -8,7 +8,7 @@ namespace NzbDrone.Core.Datastore.Migration { protected override void MainDbUpgrade() { - Execute.Sql(@"UPDATE HISTORY SET Data = replace( Data, '""Path""', '""ImportedPath""' ) WHERE EventType=3"); + Execute.Sql("UPDATE \"History\" SET \"Data\" = replace( \"Data\", '\"Path\"', '\"ImportedPath\"' ) WHERE \"EventType\" = 3"); } } } diff --git a/src/NzbDrone.Core/Datastore/Migration/017_reset_scene_names.cs b/src/NzbDrone.Core/Datastore/Migration/017_reset_scene_names.cs index 0893137b4..ecdace0b6 100644 --- a/src/NzbDrone.Core/Datastore/Migration/017_reset_scene_names.cs +++ b/src/NzbDrone.Core/Datastore/Migration/017_reset_scene_names.cs @@ -1,4 +1,4 @@ -using FluentMigrator; +using FluentMigrator; using NzbDrone.Core.Datastore.Migration.Framework; namespace NzbDrone.Core.Datastore.Migration @@ -9,7 +9,7 @@ namespace NzbDrone.Core.Datastore.Migration protected override void MainDbUpgrade() { // we were storing new file name as scene name. - Execute.Sql(@"UPDATE EpisodeFiles SET SceneName = NULL where SceneName != NULL"); + Execute.Sql("UPDATE \"EpisodeFiles\" SET \"SceneName\" = NULL where \"SceneName\" != NULL"); } } } diff --git a/src/NzbDrone.Core/Datastore/Migration/018_remove_duplicates.cs b/src/NzbDrone.Core/Datastore/Migration/018_remove_duplicates.cs index dbe11a6a9..d35e0d988 100644 --- a/src/NzbDrone.Core/Datastore/Migration/018_remove_duplicates.cs +++ b/src/NzbDrone.Core/Datastore/Migration/018_remove_duplicates.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Data; using System.Linq; @@ -35,7 +35,7 @@ namespace NzbDrone.Core.Datastore.Migration { var getDuplicates = conn.CreateCommand(); getDuplicates.Transaction = tran; - getDuplicates.CommandText = string.Format("select id, {0} from {1}", columnName, tableName); + getDuplicates.CommandText = string.Format("SELECT \"Id\", \"{0}\" from \"{1}\"", columnName, tableName); var result = new List>(); @@ -68,19 +68,19 @@ namespace NzbDrone.Core.Datastore.Migration var deleteCmd = conn.CreateCommand(); deleteCmd.Transaction = tran; - deleteCmd.CommandText = string.Format("DELETE FROM Series WHERE Id = {0}", seriesId.ToString()); + deleteCmd.CommandText = string.Format("DELETE FROM \"Series\" WHERE \"Id\" = {0}", seriesId.ToString()); deleteCmd.ExecuteNonQuery(); - deleteCmd.CommandText = string.Format("DELETE FROM Episodes WHERE SeriesId = {0}", seriesId.ToString()); + deleteCmd.CommandText = string.Format("DELETE FROM \"Episodes\" WHERE \"SeriesId\" = {0}", seriesId.ToString()); deleteCmd.ExecuteNonQuery(); - deleteCmd.CommandText = string.Format("DELETE FROM Seasons WHERE SeriesId = {0}", seriesId.ToString()); + deleteCmd.CommandText = string.Format("DELETE FROM \"Seasons\" WHERE \"SeriesId\" = {0}", seriesId.ToString()); deleteCmd.ExecuteNonQuery(); - deleteCmd.CommandText = string.Format("DELETE FROM History WHERE SeriesId = {0}", seriesId.ToString()); + deleteCmd.CommandText = string.Format("DELETE FROM \"History\" WHERE \"SeriesId\" = {0}", seriesId.ToString()); deleteCmd.ExecuteNonQuery(); - deleteCmd.CommandText = string.Format("DELETE FROM EpisodeFiles WHERE SeriesId = {0}", seriesId.ToString()); + deleteCmd.CommandText = string.Format("DELETE FROM \"EpisodeFiles\" WHERE \"SeriesId\" = {0}", seriesId.ToString()); deleteCmd.ExecuteNonQuery(); } @@ -89,10 +89,10 @@ namespace NzbDrone.Core.Datastore.Migration var deleteCmd = conn.CreateCommand(); deleteCmd.Transaction = tran; - deleteCmd.CommandText = string.Format("DELETE FROM Episodes WHERE Id = {0}", episodeId.ToString()); + deleteCmd.CommandText = string.Format("DELETE FROM \"Episodes\" WHERE \"Id\" = {0}", episodeId.ToString()); deleteCmd.ExecuteNonQuery(); - deleteCmd.CommandText = string.Format("DELETE FROM History WHERE EpisodeId = {0}", episodeId.ToString()); + deleteCmd.CommandText = string.Format("DELETE FROM \"History\" WHERE \"EpisodeId\" = {0}", episodeId.ToString()); deleteCmd.ExecuteNonQuery(); } } diff --git a/src/NzbDrone.Core/Datastore/Migration/020_add_year_and_seasons_to_series.cs b/src/NzbDrone.Core/Datastore/Migration/020_add_year_and_seasons_to_series.cs index d08d32e0e..f19e1045a 100644 --- a/src/NzbDrone.Core/Datastore/Migration/020_add_year_and_seasons_to_series.cs +++ b/src/NzbDrone.Core/Datastore/Migration/020_add_year_and_seasons_to_series.cs @@ -22,7 +22,7 @@ namespace NzbDrone.Core.Datastore.Migration using (var allSeriesCmd = conn.CreateCommand()) { allSeriesCmd.Transaction = tran; - allSeriesCmd.CommandText = @"SELECT Id FROM Series"; + allSeriesCmd.CommandText = "SELECT \"Id\" FROM \"Series\""; using (var allSeriesReader = allSeriesCmd.ExecuteReader()) { while (allSeriesReader.Read()) @@ -33,7 +33,7 @@ namespace NzbDrone.Core.Datastore.Migration using (var seasonsCmd = conn.CreateCommand()) { seasonsCmd.Transaction = tran; - seasonsCmd.CommandText = string.Format(@"SELECT SeasonNumber, Monitored FROM Seasons WHERE SeriesId = {0}", seriesId); + seasonsCmd.CommandText = $"SELECT \"SeasonNumber\", \"Monitored\" FROM \"Seasons\" WHERE \"SeriesId\" = {seriesId}"; using (var seasonReader = seasonsCmd.ExecuteReader()) { @@ -54,7 +54,7 @@ namespace NzbDrone.Core.Datastore.Migration using (var updateCmd = conn.CreateCommand()) { - var text = string.Format("UPDATE Series SET Seasons = '{0}' WHERE Id = {1}", seasons.ToJson(), seriesId); + var text = $"UPDATE \"Series\" SET \"Seasons\" = '{seasons.ToJson()}' WHERE \"Id\" = {seriesId}"; updateCmd.Transaction = tran; updateCmd.CommandText = text; diff --git a/src/NzbDrone.Core/Datastore/Migration/029_add_formats_to_naming_config.cs b/src/NzbDrone.Core/Datastore/Migration/029_add_formats_to_naming_config.cs index 6297bc38b..c0bdbba8d 100644 --- a/src/NzbDrone.Core/Datastore/Migration/029_add_formats_to_naming_config.cs +++ b/src/NzbDrone.Core/Datastore/Migration/029_add_formats_to_naming_config.cs @@ -22,7 +22,7 @@ namespace NzbDrone.Core.Datastore.Migration using (var namingConfigCmd = conn.CreateCommand()) { namingConfigCmd.Transaction = tran; - namingConfigCmd.CommandText = @"SELECT * FROM NamingConfig LIMIT 1"; + namingConfigCmd.CommandText = "SELECT * FROM \"NamingConfig\" LIMIT 1"; using (var namingConfigReader = namingConfigCmd.ExecuteReader()) { var separatorIndex = namingConfigReader.GetOrdinal("Separator"); @@ -98,9 +98,9 @@ namespace NzbDrone.Core.Datastore.Migration using (var updateCmd = conn.CreateCommand()) { - var text = string.Format("UPDATE NamingConfig " + - "SET StandardEpisodeFormat = '{0}', " + - "DailyEpisodeFormat = '{1}'", + var text = string.Format("UPDATE \"NamingConfig\" " + + "SET \"StandardEpisodeFormat\" = '{0}', " + + "\"DailyEpisodeFormat\" = '{1}'", standardEpisodeFormat, dailyEpisodeFormat); diff --git a/src/NzbDrone.Core/Datastore/Migration/030_add_season_folder_format_to_naming_config.cs b/src/NzbDrone.Core/Datastore/Migration/030_add_season_folder_format_to_naming_config.cs index d7e7c8873..43f8c6163 100644 --- a/src/NzbDrone.Core/Datastore/Migration/030_add_season_folder_format_to_naming_config.cs +++ b/src/NzbDrone.Core/Datastore/Migration/030_add_season_folder_format_to_naming_config.cs @@ -11,8 +11,8 @@ namespace NzbDrone.Core.Datastore.Migration { Alter.Table("NamingConfig").AddColumn("SeasonFolderFormat").AsString().Nullable(); Execute.WithConnection(ConvertConfig); - Execute.Sql("DELETE FROM Config WHERE [Key] = 'seasonfolderformat'"); - Execute.Sql("DELETE FROM Config WHERE [Key] = 'useseasonfolder'"); + Execute.Sql("DELETE FROM \"Config\" WHERE \"Key\" = 'seasonfolderformat'"); + Execute.Sql("DELETE FROM \"Config\" WHERE \"Key\" = 'useseasonfolder'"); } private void ConvertConfig(IDbConnection conn, IDbTransaction tran) @@ -20,7 +20,7 @@ namespace NzbDrone.Core.Datastore.Migration using (var namingConfigCmd = conn.CreateCommand()) { namingConfigCmd.Transaction = tran; - namingConfigCmd.CommandText = @"SELECT [Value] FROM Config WHERE [Key] = 'seasonfolderformat'"; + namingConfigCmd.CommandText = "SELECT \"Value\" FROM \"Config\" WHERE \"Key\" = 'seasonfolderformat'"; var seasonFormat = "Season {season}"; using (var namingConfigReader = namingConfigCmd.ExecuteReader()) @@ -41,8 +41,8 @@ namespace NzbDrone.Core.Datastore.Migration using (var updateCmd = conn.CreateCommand()) { - var text = string.Format("UPDATE NamingConfig " + - "SET SeasonFolderFormat = '{0}'", + var text = string.Format("UPDATE \"NamingConfig\" " + + "SET \"SeasonFolderFormat\" = '{0}'", seasonFormat); updateCmd.Transaction = tran; diff --git a/src/NzbDrone.Core/Datastore/Migration/032_set_default_release_group.cs b/src/NzbDrone.Core/Datastore/Migration/032_set_default_release_group.cs index 5ecc4e2c0..b61b6669f 100644 --- a/src/NzbDrone.Core/Datastore/Migration/032_set_default_release_group.cs +++ b/src/NzbDrone.Core/Datastore/Migration/032_set_default_release_group.cs @@ -1,4 +1,5 @@ -using FluentMigrator; +using System; +using FluentMigrator; using NzbDrone.Core.Datastore.Migration.Framework; namespace NzbDrone.Core.Datastore.Migration @@ -8,7 +9,7 @@ namespace NzbDrone.Core.Datastore.Migration { protected override void MainDbUpgrade() { - Execute.Sql("UPDATE EpisodeFiles SET ReleaseGroup = 'DRONE' WHERE ReleaseGroup IS NULL"); + Update.Table("EpisodeFiles").Set(new { ReleaseGroup = "DRONE" }).Where(new { ReleaseGroup = DBNull.Value }); } } } diff --git a/src/NzbDrone.Core/Datastore/Migration/033_add_api_key_to_pushover.cs b/src/NzbDrone.Core/Datastore/Migration/033_add_api_key_to_pushover.cs index 9fde88cbe..8ecb508cc 100644 --- a/src/NzbDrone.Core/Datastore/Migration/033_add_api_key_to_pushover.cs +++ b/src/NzbDrone.Core/Datastore/Migration/033_add_api_key_to_pushover.cs @@ -20,7 +20,7 @@ namespace NzbDrone.Core.Datastore.Migration using (var selectCommand = conn.CreateCommand()) { selectCommand.Transaction = tran; - selectCommand.CommandText = @"SELECT * FROM Notifications WHERE ConfigContract = 'PushoverSettings'"; + selectCommand.CommandText = "SELECT * FROM \"Notifications\" WHERE \"ConfigContract\" = 'PushoverSettings'"; using (var reader = selectCommand.ExecuteReader()) { @@ -41,9 +41,9 @@ namespace NzbDrone.Core.Datastore.Migration using (var updateCmd = conn.CreateCommand()) { - var text = string.Format("UPDATE Notifications " + - "SET Settings = '{0}'" + - "WHERE Id = {1}", + var text = string.Format("UPDATE \"Notifications\" " + + "SET \"Settings\" = '{0}'" + + "WHERE \"Id\" = {1}", settings.ToJson(), id); diff --git a/src/NzbDrone.Core/Datastore/Migration/035_add_series_folder_format_to_naming_config.cs b/src/NzbDrone.Core/Datastore/Migration/035_add_series_folder_format_to_naming_config.cs index 9423a54f0..92fe1aed6 100644 --- a/src/NzbDrone.Core/Datastore/Migration/035_add_series_folder_format_to_naming_config.cs +++ b/src/NzbDrone.Core/Datastore/Migration/035_add_series_folder_format_to_naming_config.cs @@ -1,4 +1,4 @@ -using FluentMigrator; +using FluentMigrator; using NzbDrone.Core.Datastore.Migration.Framework; namespace NzbDrone.Core.Datastore.Migration @@ -10,7 +10,7 @@ namespace NzbDrone.Core.Datastore.Migration { Alter.Table("NamingConfig").AddColumn("SeriesFolderFormat").AsString().Nullable(); - Execute.Sql("UPDATE NamingConfig SET SeriesFolderFormat = '{Series Title}'"); + Update.Table("NamingConfig").Set(new { SeriesFolderFormat = "{Series Title}" }).AllRows(); } } } diff --git a/src/NzbDrone.Core/Datastore/Migration/036_update_with_quality_converters.cs b/src/NzbDrone.Core/Datastore/Migration/036_update_with_quality_converters.cs index 7aefd52bc..96fffde59 100644 --- a/src/NzbDrone.Core/Datastore/Migration/036_update_with_quality_converters.cs +++ b/src/NzbDrone.Core/Datastore/Migration/036_update_with_quality_converters.cs @@ -32,7 +32,7 @@ namespace NzbDrone.Core.Datastore.Migration using (var qualityProfileCmd = conn.CreateCommand()) { qualityProfileCmd.Transaction = tran; - qualityProfileCmd.CommandText = @"SELECT Id, Allowed FROM QualityProfiles"; + qualityProfileCmd.CommandText = "SELECT \"Id\", \"Allowed\" FROM \"QualityProfiles\""; using (var qualityProfileReader = qualityProfileCmd.ExecuteReader()) { while (qualityProfileReader.Read()) @@ -47,7 +47,7 @@ namespace NzbDrone.Core.Datastore.Migration using (var updateCmd = conn.CreateCommand()) { updateCmd.Transaction = tran; - updateCmd.CommandText = "UPDATE QualityProfiles SET Items = ? WHERE Id = ?"; + updateCmd.CommandText = "UPDATE \"QualityProfiles\" SET \"Items\" = ? WHERE \"Id\" = ?"; var param = updateCmd.CreateParameter(); qualityProfileItemConverter.SetValue(param, items); updateCmd.Parameters.Add(param); @@ -75,7 +75,7 @@ namespace NzbDrone.Core.Datastore.Migration using (var qualityModelCmd = conn.CreateCommand()) { qualityModelCmd.Transaction = tran; - qualityModelCmd.CommandText = @"SELECT Distinct Quality FROM " + tableName; + qualityModelCmd.CommandText = $"SELECT Distinct \"Quality\" FROM \"{tableName}\""; using (var qualityModelReader = qualityModelCmd.ExecuteReader()) { while (qualityModelReader.Read()) @@ -96,7 +96,7 @@ namespace NzbDrone.Core.Datastore.Migration using (var updateCmd = conn.CreateCommand()) { updateCmd.Transaction = tran; - updateCmd.CommandText = "UPDATE " + tableName + " SET Quality = ? WHERE Quality = ?"; + updateCmd.CommandText = "UPDATE \"" + tableName + "\" SET \"Quality\" = ? WHERE \"Quality\" = ?"; var param = updateCmd.CreateParameter(); qualityModelConverter.SetValue(param, qualityNew); updateCmd.Parameters.Add(param); diff --git a/src/NzbDrone.Core/Datastore/Migration/037_add_configurable_qualities.cs b/src/NzbDrone.Core/Datastore/Migration/037_add_configurable_qualities.cs index d7e95ed68..dbd4e1232 100644 --- a/src/NzbDrone.Core/Datastore/Migration/037_add_configurable_qualities.cs +++ b/src/NzbDrone.Core/Datastore/Migration/037_add_configurable_qualities.cs @@ -33,7 +33,7 @@ namespace NzbDrone.Core.Datastore.Migration using (var qualitySizeCmd = conn.CreateCommand()) { qualitySizeCmd.Transaction = tran; - qualitySizeCmd.CommandText = @"SELECT QualityId, MinSize, MaxSize FROM QualitySizes"; + qualitySizeCmd.CommandText = "SELECT \"QualityId\", \"MinSize\", \"MaxSize\" FROM \"QualitySizes\""; using (var qualitySizeReader = qualitySizeCmd.ExecuteReader()) { while (qualitySizeReader.Read()) @@ -47,7 +47,7 @@ namespace NzbDrone.Core.Datastore.Migration using (var updateCmd = conn.CreateCommand()) { updateCmd.Transaction = tran; - updateCmd.CommandText = "INSERT INTO QualityDefinitions (Quality, Title, Weight, MinSize, MaxSize) VALUES (?, ?, ?, ?, ?)"; + updateCmd.CommandText = "INSERT INTO \"QualityDefinitions\" (\"Quality\", \"Title\", \"Weight\", \"MinSize\", \"MaxSize\") VALUES (?, ?, ?, ?, ?)"; updateCmd.AddParameter(qualityId); updateCmd.AddParameter(defaultConfig.Title); updateCmd.AddParameter(defaultConfig.Weight); diff --git a/src/NzbDrone.Core/Datastore/Migration/038_add_on_upgrade_to_notifications.cs b/src/NzbDrone.Core/Datastore/Migration/038_add_on_upgrade_to_notifications.cs index f5cae2ba0..70cd54a99 100644 --- a/src/NzbDrone.Core/Datastore/Migration/038_add_on_upgrade_to_notifications.cs +++ b/src/NzbDrone.Core/Datastore/Migration/038_add_on_upgrade_to_notifications.cs @@ -1,4 +1,4 @@ -using FluentMigrator; +using FluentMigrator; using NzbDrone.Core.Datastore.Migration.Framework; namespace NzbDrone.Core.Datastore.Migration @@ -10,7 +10,7 @@ namespace NzbDrone.Core.Datastore.Migration { Alter.Table("Notifications").AddColumn("OnUpgrade").AsBoolean().Nullable(); - Execute.Sql("UPDATE Notifications SET OnUpgrade = OnDownload"); + Execute.Sql("UPDATE \"Notifications\" SET \"OnUpgrade\" = \"OnDownload\""); } } } diff --git a/src/NzbDrone.Core/Datastore/Migration/041_fix_xbmc_season_images_metadata.cs b/src/NzbDrone.Core/Datastore/Migration/041_fix_xbmc_season_images_metadata.cs index 25cbc8ed4..69931b901 100644 --- a/src/NzbDrone.Core/Datastore/Migration/041_fix_xbmc_season_images_metadata.cs +++ b/src/NzbDrone.Core/Datastore/Migration/041_fix_xbmc_season_images_metadata.cs @@ -1,4 +1,4 @@ -using FluentMigrator; +using FluentMigrator; using NzbDrone.Core.Datastore.Migration.Framework; namespace NzbDrone.Core.Datastore.Migration @@ -8,7 +8,7 @@ namespace NzbDrone.Core.Datastore.Migration { protected override void MainDbUpgrade() { - Execute.Sql("UPDATE MetadataFiles SET Type = 4 WHERE Consumer = 'XbmcMetadata' AND SeasonNumber IS NOT NULL"); + Execute.Sql("UPDATE \"MetadataFiles\" SET \"Type\" = 4 WHERE \"Consumer\" = 'XbmcMetadata' AND \"SeasonNumber\" IS NOT NULL"); } } } diff --git a/src/NzbDrone.Core/Datastore/Migration/043_convert_config_to_download_clients.cs b/src/NzbDrone.Core/Datastore/Migration/043_convert_config_to_download_clients.cs index d871e40ea..a481281a7 100644 --- a/src/NzbDrone.Core/Datastore/Migration/043_convert_config_to_download_clients.cs +++ b/src/NzbDrone.Core/Datastore/Migration/043_convert_config_to_download_clients.cs @@ -22,7 +22,7 @@ namespace NzbDrone.Core.Datastore.Migration using (var configCmd = conn.CreateCommand()) { configCmd.Transaction = tran; - configCmd.CommandText = @"SELECT * FROM Config"; + configCmd.CommandText = "SELECT * FROM \"Config\""; using (var configReader = configCmd.ExecuteReader()) { var keyIndex = configReader.GetOrdinal("Key"); @@ -121,7 +121,7 @@ namespace NzbDrone.Core.Datastore.Migration { using (var updateCmd = conn.CreateCommand()) { - var text = string.Format("INSERT INTO DownloadClients (Enable, Name, Implementation, Settings, ConfigContract, Protocol) VALUES (1, ?, ?, ?, ?, ?)"); + var text = string.Format("INSERT INTO \"DownloadClients\" (\"Enable\", \"Name\", \"Implementation\", \"Settings\", \"ConfigContract\", \"Protocol\") VALUES (1, ?, ?, ?, ?, ?)"); updateCmd.AddParameter(name); updateCmd.AddParameter(implementation); updateCmd.AddParameter(settings); @@ -138,7 +138,7 @@ namespace NzbDrone.Core.Datastore.Migration { using (var updateCmd = conn.CreateCommand()) { - var text = "DELETE FROM Config WHERE [KEY] IN ('nzbgetusername', 'nzbgetpassword', 'nzbgethost', 'nzbgetport', " + + var text = "DELETE FROM \"Config\" WHERE [KEY] IN ('nzbgetusername', 'nzbgetpassword', 'nzbgethost', 'nzbgetport', " + "'nzbgettvcategory', 'nzbgetrecenttvpriority', 'nzbgetoldertvpriority', 'sabhost', 'sabport', " + "'sabapikey', 'sabusername', 'sabpassword', 'sabtvcategory', 'sabrecenttvpriority', " + "'saboldertvpriority', 'sabusessl', 'downloadclient', 'blackholefolder', 'pneumaticfolder')"; diff --git a/src/NzbDrone.Core/Datastore/Migration/044_fix_xbmc_episode_metadata.cs b/src/NzbDrone.Core/Datastore/Migration/044_fix_xbmc_episode_metadata.cs index 5d6ff5ba8..0ac13f116 100644 --- a/src/NzbDrone.Core/Datastore/Migration/044_fix_xbmc_episode_metadata.cs +++ b/src/NzbDrone.Core/Datastore/Migration/044_fix_xbmc_episode_metadata.cs @@ -1,4 +1,4 @@ -using FluentMigrator; +using FluentMigrator; using NzbDrone.Core.Datastore.Migration.Framework; namespace NzbDrone.Core.Datastore.Migration @@ -9,19 +9,19 @@ namespace NzbDrone.Core.Datastore.Migration protected override void MainDbUpgrade() { // Convert Episode Metadata to proper type - Execute.Sql("UPDATE MetadataFiles " + - "SET Type = 2 " + - "WHERE Consumer = 'XbmcMetadata' " + - "AND EpisodeFileId IS NOT NULL " + - "AND Type = 4 " + - "AND RelativePath LIKE '%.nfo'"); + Execute.Sql("UPDATE \"MetadataFiles\" " + + "SET \"Type\" = 2 " + + "WHERE \"Consumer\" = 'XbmcMetadata' " + + "AND \"EpisodeFileId\" IS NOT NULL " + + "AND \"Type\" = 4 " + + "AND \"RelativePath\" LIKE '%.nfo'"); // Convert Episode Images to proper type - Execute.Sql("UPDATE MetadataFiles " + - "SET Type = 5 " + - "WHERE Consumer = 'XbmcMetadata' " + - "AND EpisodeFileId IS NOT NULL " + - "AND Type = 4"); + Execute.Sql("UPDATE \"MetadataFiles\" " + + "SET \"Type\" = 5 " + + "WHERE \"Consumer\" = 'XbmcMetadata' " + + "AND \"EpisodeFileId\" IS NOT NULL " + + "AND \"Type\" = 4"); } } } diff --git a/src/NzbDrone.Core/Datastore/Migration/046_fix_nzb_su_url.cs b/src/NzbDrone.Core/Datastore/Migration/046_fix_nzb_su_url.cs index 6d5496c0a..7de093e8c 100644 --- a/src/NzbDrone.Core/Datastore/Migration/046_fix_nzb_su_url.cs +++ b/src/NzbDrone.Core/Datastore/Migration/046_fix_nzb_su_url.cs @@ -1,4 +1,4 @@ -using FluentMigrator; +using FluentMigrator; using NzbDrone.Core.Datastore.Migration.Framework; namespace NzbDrone.Core.Datastore.Migration @@ -8,9 +8,9 @@ namespace NzbDrone.Core.Datastore.Migration { protected override void MainDbUpgrade() { - Execute.Sql("UPDATE Indexers SET Settings = replace(Settings, '//nzb.su', '//api.nzb.su')" + - "WHERE Implementation = 'Newznab'" + - "AND Settings LIKE '%//nzb.su%'"); + Execute.Sql("UPDATE \"Indexers\" SET \"Settings\" = replace(\"Settings\", '//nzb.su', '//api.nzb.su')" + + "WHERE \"Implementation\" = 'Newznab'" + + "AND \"Settings\" LIKE '%//nzb.su%'"); } } } diff --git a/src/NzbDrone.Core/Datastore/Migration/049_fix_dognzb_url.cs b/src/NzbDrone.Core/Datastore/Migration/049_fix_dognzb_url.cs index ebbe8d8c0..60108c393 100644 --- a/src/NzbDrone.Core/Datastore/Migration/049_fix_dognzb_url.cs +++ b/src/NzbDrone.Core/Datastore/Migration/049_fix_dognzb_url.cs @@ -1,4 +1,4 @@ -using FluentMigrator; +using FluentMigrator; using NzbDrone.Core.Datastore.Migration.Framework; namespace NzbDrone.Core.Datastore.Migration @@ -8,9 +8,9 @@ namespace NzbDrone.Core.Datastore.Migration { protected override void MainDbUpgrade() { - Execute.Sql("UPDATE Indexers SET Settings = replace(Settings, '//dognzb.cr', '//api.dognzb.cr')" + - "WHERE Implementation = 'Newznab'" + - "AND Settings LIKE '%//dognzb.cr%'"); + Execute.Sql("UPDATE \"Indexers\" SET \"Settings\" = replace(\"Settings\", '//dognzb.cr', '//api.dognzb.cr')" + + "WHERE \"Implementation\" = 'Newznab'" + + "AND \"Settings\" LIKE '%//dognzb.cr%'"); } } } diff --git a/src/NzbDrone.Core/Datastore/Migration/051_download_client_import.cs b/src/NzbDrone.Core/Datastore/Migration/051_download_client_import.cs index ef875b0d1..a9de5795a 100644 --- a/src/NzbDrone.Core/Datastore/Migration/051_download_client_import.cs +++ b/src/NzbDrone.Core/Datastore/Migration/051_download_client_import.cs @@ -27,13 +27,13 @@ namespace NzbDrone.Core.Datastore.Migration using (var cmd = conn.CreateCommand()) { cmd.Transaction = tran; - cmd.CommandText = @"SELECT Value FROM Config WHERE Key = 'downloadedepisodesfolder'"; + cmd.CommandText = "SELECT \"Value\" FROM \"Config\" WHERE \"Key\" = 'downloadedepisodesfolder'"; var result = cmd.ExecuteScalar(); if (result == null) { - cmd.CommandText = @"INSERT INTO Config (Key, Value) VALUES ('enablecompleteddownloadhandling', 'True')"; + cmd.CommandText = "INSERT INTO \"Config\" (\"Key\", \"Value\") VALUES ('enablecompleteddownloadhandling', 'True')"; cmd.ExecuteNonQuery(); } } @@ -44,11 +44,11 @@ namespace NzbDrone.Core.Datastore.Migration using (var downloadClientsCmd = conn.CreateCommand()) { downloadClientsCmd.Transaction = tran; - downloadClientsCmd.CommandText = @"SELECT Value FROM Config WHERE Key = 'downloadedepisodesfolder'"; + downloadClientsCmd.CommandText = "SELECT \"Value\" FROM \"Config\" WHERE \"Key\" = 'downloadedepisodesfolder'"; var downloadedEpisodesFolder = downloadClientsCmd.ExecuteScalar() as string; downloadClientsCmd.Transaction = tran; - downloadClientsCmd.CommandText = @"SELECT Id, Implementation, Settings, ConfigContract FROM DownloadClients WHERE ConfigContract = 'FolderSettings'"; + downloadClientsCmd.CommandText = "SELECT \"Id\", \"Implementation\", \"Settings\", \"ConfigContract\" FROM \"DownloadClients\" WHERE \"ConfigContract\" = 'FolderSettings'"; using (var downloadClientReader = downloadClientsCmd.ExecuteReader()) { while (downloadClientReader.Read()) @@ -71,7 +71,7 @@ namespace NzbDrone.Core.Datastore.Migration using (var updateCmd = conn.CreateCommand()) { updateCmd.Transaction = tran; - updateCmd.CommandText = "UPDATE DownloadClients SET Implementation = ?, Settings = ?, ConfigContract = ? WHERE Id = ?"; + updateCmd.CommandText = "UPDATE \"DownloadClients\" SET \"Implementation\" = ?, \"Settings\" = ?, \"ConfigContract\" = ? WHERE \"Id\" = ?"; updateCmd.AddParameter("UsenetBlackhole"); updateCmd.AddParameter(newSettings); updateCmd.AddParameter("UsenetBlackholeSettings"); @@ -90,7 +90,7 @@ namespace NzbDrone.Core.Datastore.Migration using (var updateCmd = conn.CreateCommand()) { updateCmd.Transaction = tran; - updateCmd.CommandText = "UPDATE DownloadClients SET Settings = ?, ConfigContract = ? WHERE Id = ?"; + updateCmd.CommandText = "UPDATE \"DownloadClients\" SET \"Settings\" = ?, \"ConfigContract\" = ? WHERE \"Id\" = ?"; updateCmd.AddParameter(newSettings); updateCmd.AddParameter("PneumaticSettings"); updateCmd.AddParameter(id); @@ -103,7 +103,7 @@ namespace NzbDrone.Core.Datastore.Migration using (var updateCmd = conn.CreateCommand()) { updateCmd.Transaction = tran; - updateCmd.CommandText = "DELETE FROM DownloadClients WHERE Id = ?"; + updateCmd.CommandText = "DELETE FROM \"DownloadClients\" WHERE \"Id\" = ?"; updateCmd.AddParameter(id); updateCmd.ExecuteNonQuery(); @@ -141,7 +141,7 @@ namespace NzbDrone.Core.Datastore.Migration using (var historyCmd = conn.CreateCommand()) { historyCmd.Transaction = tran; - historyCmd.CommandText = @"SELECT Id, EpisodeId, SeriesId, SourceTitle, Date, Data, EventType FROM History WHERE EventType NOT NULL"; + historyCmd.CommandText = "SELECT \"Id\", \"EpisodeId\", \"SeriesId\", \"SourceTitle\", \"Date\", \"Data\", \"EventType\" FROM \"History\" WHERE \"EventType\" IS NOT NULL"; using (var historyRead = historyCmd.ExecuteReader()) { while (historyRead.Read()) @@ -238,7 +238,7 @@ namespace NzbDrone.Core.Datastore.Migration pair.Key.Data["downloadClientId"] = pair.Value.Data["downloadClientId"]; updateHistoryCmd.Transaction = tran; - updateHistoryCmd.CommandText = "UPDATE History SET Data = ? WHERE Id = ?"; + updateHistoryCmd.CommandText = "UPDATE \"History\" SET \"Data\" = ? WHERE \"Id\" = ?"; updateHistoryCmd.AddParameter(pair.Key.Data.ToJson()); updateHistoryCmd.AddParameter(pair.Key.Id); diff --git a/src/NzbDrone.Core/Datastore/Migration/052_add_columns_for_anime.cs b/src/NzbDrone.Core/Datastore/Migration/052_add_columns_for_anime.cs index 027caba39..de6ae33e3 100644 --- a/src/NzbDrone.Core/Datastore/Migration/052_add_columns_for_anime.cs +++ b/src/NzbDrone.Core/Datastore/Migration/052_add_columns_for_anime.cs @@ -1,4 +1,4 @@ -using FluentMigrator; +using FluentMigrator; using NzbDrone.Core.Datastore.Migration.Framework; namespace NzbDrone.Core.Datastore.Migration @@ -10,11 +10,11 @@ namespace NzbDrone.Core.Datastore.Migration { // Support XEM names Alter.Table("SceneMappings").AddColumn("Type").AsString().Nullable(); - Execute.Sql("DELETE FROM SceneMappings"); + Execute.Sql("DELETE FROM \"SceneMappings\""); // Add AnimeEpisodeFormat (set to Standard Episode format for now) Alter.Table("NamingConfig").AddColumn("AnimeEpisodeFormat").AsString().Nullable(); - Execute.Sql("UPDATE NamingConfig SET AnimeEpisodeFormat = StandardEpisodeFormat"); + Execute.Sql("UPDATE \"NamingConfig\" SET \"AnimeEpisodeFormat\" = \"StandardEpisodeFormat\""); } } } diff --git a/src/NzbDrone.Core/Datastore/Migration/053_add_series_sorttitle.cs b/src/NzbDrone.Core/Datastore/Migration/053_add_series_sorttitle.cs index 9d4168b94..02bf64232 100644 --- a/src/NzbDrone.Core/Datastore/Migration/053_add_series_sorttitle.cs +++ b/src/NzbDrone.Core/Datastore/Migration/053_add_series_sorttitle.cs @@ -19,7 +19,7 @@ namespace NzbDrone.Core.Datastore.Migration using (var getSeriesCmd = conn.CreateCommand()) { getSeriesCmd.Transaction = tran; - getSeriesCmd.CommandText = @"SELECT Id, Title FROM Series"; + getSeriesCmd.CommandText = "SELECT \"Id\", \"Title\" FROM \"Series\""; using (var seriesReader = getSeriesCmd.ExecuteReader()) { while (seriesReader.Read()) @@ -32,7 +32,7 @@ namespace NzbDrone.Core.Datastore.Migration using (var updateCmd = conn.CreateCommand()) { updateCmd.Transaction = tran; - updateCmd.CommandText = "UPDATE Series SET SortTitle = ? WHERE Id = ?"; + updateCmd.CommandText = "UPDATE \"Series\" SET \"SortTitle\" = ? WHERE \"Id\" = ?"; updateCmd.AddParameter(sortTitle); updateCmd.AddParameter(id); diff --git a/src/NzbDrone.Core/Datastore/Migration/054_rename_profiles.cs b/src/NzbDrone.Core/Datastore/Migration/054_rename_profiles.cs index d0b67d7e9..eb34886d6 100644 --- a/src/NzbDrone.Core/Datastore/Migration/054_rename_profiles.cs +++ b/src/NzbDrone.Core/Datastore/Migration/054_rename_profiles.cs @@ -1,4 +1,4 @@ -using FluentMigrator; +using FluentMigrator; using NzbDrone.Core.Datastore.Migration.Framework; namespace NzbDrone.Core.Datastore.Migration @@ -13,11 +13,11 @@ namespace NzbDrone.Core.Datastore.Migration Alter.Table("Profiles").AddColumn("Language").AsInt32().Nullable(); Alter.Table("Profiles").AddColumn("GrabDelay").AsInt32().Nullable(); Alter.Table("Profiles").AddColumn("GrabDelayMode").AsInt32().Nullable(); - Execute.Sql("UPDATE Profiles SET Language = 1, GrabDelay = 0, GrabDelayMode = 0"); + Update.Table("Profiles").Set(new { Language = 1, GrabDelay = 0, GrabDelayMode = 0 }).AllRows(); // Rename QualityProfileId in Series Alter.Table("Series").AddColumn("ProfileId").AsInt32().Nullable(); - Execute.Sql("UPDATE Series SET ProfileId = QualityProfileId"); + Execute.Sql("UPDATE \"Series\" SET \"ProfileId\" = \"QualityProfileId\""); // Add HeldReleases Create.TableForModel("PendingReleases") diff --git a/src/NzbDrone.Core/Datastore/Migration/057_convert_episode_file_path_to_relative.cs b/src/NzbDrone.Core/Datastore/Migration/057_convert_episode_file_path_to_relative.cs index 37893357d..e13596fe8 100644 --- a/src/NzbDrone.Core/Datastore/Migration/057_convert_episode_file_path_to_relative.cs +++ b/src/NzbDrone.Core/Datastore/Migration/057_convert_episode_file_path_to_relative.cs @@ -23,7 +23,7 @@ namespace NzbDrone.Core.Datastore.Migration using (var getSeriesCmd = conn.CreateCommand()) { getSeriesCmd.Transaction = tran; - getSeriesCmd.CommandText = @"SELECT Id, Path FROM Series"; + getSeriesCmd.CommandText = "SELECT \"Id\", \"Path\" FROM \"Series\""; using (var seriesReader = getSeriesCmd.ExecuteReader()) { while (seriesReader.Read()) @@ -34,7 +34,7 @@ namespace NzbDrone.Core.Datastore.Migration using (var updateCmd = conn.CreateCommand()) { updateCmd.Transaction = tran; - updateCmd.CommandText = "UPDATE EpisodeFiles SET RelativePath = REPLACE(Path, ?, '') WHERE SeriesId = ?"; + updateCmd.CommandText = "UPDATE \"EpisodeFiles\" SET \"RelativePath\" = REPLACE(\"Path\", ?, '') WHERE \"SeriesId\" = ?"; updateCmd.AddParameter(seriesPath); updateCmd.AddParameter(seriesId); diff --git a/src/NzbDrone.Core/Datastore/Migration/059_add_enable_options_to_indexers.cs b/src/NzbDrone.Core/Datastore/Migration/059_add_enable_options_to_indexers.cs index 0905578c5..9eff8fa08 100644 --- a/src/NzbDrone.Core/Datastore/Migration/059_add_enable_options_to_indexers.cs +++ b/src/NzbDrone.Core/Datastore/Migration/059_add_enable_options_to_indexers.cs @@ -1,4 +1,4 @@ -using FluentMigrator; +using FluentMigrator; using NzbDrone.Core.Datastore.Migration.Framework; namespace NzbDrone.Core.Datastore.Migration @@ -12,8 +12,8 @@ namespace NzbDrone.Core.Datastore.Migration .AddColumn("EnableRss").AsBoolean().Nullable() .AddColumn("EnableSearch").AsBoolean().Nullable(); - Execute.Sql("UPDATE Indexers SET EnableRss = Enable, EnableSearch = Enable"); - Execute.Sql("UPDATE Indexers SET EnableSearch = 0 WHERE Implementation = 'Wombles'"); + Execute.Sql("UPDATE \"Indexers\" SET \"EnableRss\" = \"Enable\", \"EnableSearch\" = \"Enable\""); + Update.Table("Indexers").Set(new { EnableSearch = false }).Where(new { Implementation = "Wombles" }); } } } diff --git a/src/NzbDrone.Core/Datastore/Migration/061_clear_bad_scene_names.cs b/src/NzbDrone.Core/Datastore/Migration/061_clear_bad_scene_names.cs index 4bc2275dc..87da567bb 100644 --- a/src/NzbDrone.Core/Datastore/Migration/061_clear_bad_scene_names.cs +++ b/src/NzbDrone.Core/Datastore/Migration/061_clear_bad_scene_names.cs @@ -1,4 +1,4 @@ -using FluentMigrator; +using FluentMigrator; using NzbDrone.Core.Datastore.Migration.Framework; namespace NzbDrone.Core.Datastore.Migration @@ -8,15 +8,15 @@ namespace NzbDrone.Core.Datastore.Migration { protected override void MainDbUpgrade() { - Execute.Sql("UPDATE [EpisodeFiles] " + - "SET ReleaseGroup = NULL , SceneName = NULL " + + Execute.Sql("UPDATE \"EpisodeFiles\" " + + "SET \"ReleaseGroup\" = NULL , \"SceneName\" = NULL " + "WHERE " + - " ReleaseGroup IS NULL " + - " OR SceneName IS NULL " + - " OR ReleaseGroup =='DRONE' " + - " OR LENGTH(SceneName) <10 " + - " OR LENGTH(ReleaseGroup) > 20 " + - " OR SceneName NOT LIKE '%.%'"); + " \"ReleaseGroup\" IS NULL " + + " OR \"SceneName\" IS NULL " + + " OR \"ReleaseGroup\" = 'DRONE' " + + " OR LENGTH(\"SceneName\") <10 " + + " OR LENGTH(\"ReleaseGroup\") > 20 " + + " OR \"SceneName\" NOT LIKE '%.%'"); } } } diff --git a/src/NzbDrone.Core/Datastore/Migration/062_convert_quality_models.cs b/src/NzbDrone.Core/Datastore/Migration/062_convert_quality_models.cs index 10ec980d5..bb24d8b02 100644 --- a/src/NzbDrone.Core/Datastore/Migration/062_convert_quality_models.cs +++ b/src/NzbDrone.Core/Datastore/Migration/062_convert_quality_models.cs @@ -29,7 +29,7 @@ namespace NzbDrone.Core.Datastore.Migration using (var qualityModelCmd = conn.CreateCommand()) { qualityModelCmd.Transaction = tran; - qualityModelCmd.CommandText = @"SELECT Distinct Quality FROM " + tableName; + qualityModelCmd.CommandText = $"SELECT Distinct \"Quality\" FROM \"{tableName}\""; using (var qualityModelReader = qualityModelCmd.ExecuteReader()) { @@ -60,7 +60,7 @@ namespace NzbDrone.Core.Datastore.Migration using (var updateCmd = conn.CreateCommand()) { updateCmd.Transaction = tran; - updateCmd.CommandText = "UPDATE " + tableName + " SET Quality = ? WHERE Quality = ?"; + updateCmd.CommandText = "UPDATE \"" + tableName + "\" SET \"Quality\" = ? WHERE \"Quality\" = ?"; updateCmd.AddParameter(quality.Value); updateCmd.AddParameter(quality.Key); diff --git a/src/NzbDrone.Core/Datastore/Migration/065_make_scene_numbering_nullable.cs b/src/NzbDrone.Core/Datastore/Migration/065_make_scene_numbering_nullable.cs index 7936f04dd..ac72e3ae7 100644 --- a/src/NzbDrone.Core/Datastore/Migration/065_make_scene_numbering_nullable.cs +++ b/src/NzbDrone.Core/Datastore/Migration/065_make_scene_numbering_nullable.cs @@ -1,4 +1,5 @@ -using FluentMigrator; +using System; +using FluentMigrator; using NzbDrone.Core.Datastore.Migration.Framework; namespace NzbDrone.Core.Datastore.Migration @@ -8,9 +9,9 @@ namespace NzbDrone.Core.Datastore.Migration { protected override void MainDbUpgrade() { - Execute.Sql("UPDATE Episodes SET AbsoluteEpisodeNumber = NULL WHERE AbsoluteEpisodeNumber = 0"); - Execute.Sql("UPDATE Episodes SET SceneAbsoluteEpisodeNumber = NULL WHERE SceneAbsoluteEpisodeNumber = 0"); - Execute.Sql("UPDATE Episodes SET SceneSeasonNumber = NULL, SceneEpisodeNumber = NULL WHERE SceneSeasonNumber = 0 AND SceneEpisodeNumber = 0"); + Update.Table("Episodes").Set(new { AbsoluteEpisodeNumber = DBNull.Value }).Where(new { AbsoluteEpisodeNumber = 0 }); + Update.Table("Episodes").Set(new { SceneAbsoluteEpisodeNumber = DBNull.Value }).Where(new { SceneAbsoluteEpisodeNumber = 0 }); + Update.Table("Episodes").Set(new { SceneSeasonNumber = DBNull.Value, SceneEpisodeNumber = DBNull.Value }).Where(new { SceneSeasonNumber = 0, SceneEpisodeNumber = 0 }); } } } diff --git a/src/NzbDrone.Core/Datastore/Migration/066_add_tags.cs b/src/NzbDrone.Core/Datastore/Migration/066_add_tags.cs index 7a0c09838..3e91da6f1 100644 --- a/src/NzbDrone.Core/Datastore/Migration/066_add_tags.cs +++ b/src/NzbDrone.Core/Datastore/Migration/066_add_tags.cs @@ -1,4 +1,4 @@ -using FluentMigrator; +using FluentMigrator; using NzbDrone.Core.Datastore.Migration.Framework; namespace NzbDrone.Core.Datastore.Migration @@ -17,8 +17,8 @@ namespace NzbDrone.Core.Datastore.Migration Alter.Table("Notifications") .AddColumn("Tags").AsString().Nullable(); - Execute.Sql("UPDATE Series SET Tags = '[]'"); - Execute.Sql("UPDATE Notifications SET Tags = '[]'"); + Update.Table("Series").Set(new { Tags = "[]" }).AllRows(); + Update.Table("Notifications").Set(new { Tags = "[]" }).AllRows(); } } } diff --git a/src/NzbDrone.Core/Datastore/Migration/068_add_release_restrictions.cs b/src/NzbDrone.Core/Datastore/Migration/068_add_release_restrictions.cs index 43937e6b2..089496974 100644 --- a/src/NzbDrone.Core/Datastore/Migration/068_add_release_restrictions.cs +++ b/src/NzbDrone.Core/Datastore/Migration/068_add_release_restrictions.cs @@ -16,7 +16,7 @@ namespace NzbDrone.Core.Datastore.Migration .WithColumn("Tags").AsString().NotNullable(); Execute.WithConnection(ConvertRestrictions); - Execute.Sql("DELETE FROM Config WHERE [Key] = 'releaserestrictions'"); + Delete.FromTable("Config").Row(new { Key = "releaserestrictions" }); } private void ConvertRestrictions(IDbConnection conn, IDbTransaction tran) @@ -24,7 +24,7 @@ namespace NzbDrone.Core.Datastore.Migration using (var getRestictionsCmd = conn.CreateCommand()) { getRestictionsCmd.Transaction = tran; - getRestictionsCmd.CommandText = @"SELECT [Value] FROM Config WHERE [Key] = 'releaserestrictions'"; + getRestictionsCmd.CommandText = "SELECT \"Value\" FROM \"Config\" WHERE \"Key\" = 'releaserestrictions'"; using (var configReader = getRestictionsCmd.ExecuteReader()) { @@ -36,7 +36,7 @@ namespace NzbDrone.Core.Datastore.Migration using (var insertCmd = conn.CreateCommand()) { insertCmd.Transaction = tran; - insertCmd.CommandText = "INSERT INTO Restrictions (Ignored, Tags) VALUES (?, '[]')"; + insertCmd.CommandText = "INSERT INTO \"Restrictions\" (\"Ignored\", \"Tags\") VALUES (?, '[]')"; insertCmd.AddParameter(restrictions); insertCmd.ExecuteNonQuery(); diff --git a/src/NzbDrone.Core/Datastore/Migration/069_quality_proper.cs b/src/NzbDrone.Core/Datastore/Migration/069_quality_proper.cs index 36c183fae..2648a71e1 100644 --- a/src/NzbDrone.Core/Datastore/Migration/069_quality_proper.cs +++ b/src/NzbDrone.Core/Datastore/Migration/069_quality_proper.cs @@ -22,7 +22,7 @@ namespace NzbDrone.Core.Datastore.Migration using (var namingConfigCmd = conn.CreateCommand()) { namingConfigCmd.Transaction = tran; - namingConfigCmd.CommandText = @"SELECT StandardEpisodeFormat, DailyEpisodeFormat, AnimeEpisodeFormat FROM NamingConfig LIMIT 1"; + namingConfigCmd.CommandText = "SELECT \"StandardEpisodeFormat\", \"DailyEpisodeFormat\", \"AnimeEpisodeFormat\" FROM \"NamingConfig\" LIMIT 1"; using (var configReader = namingConfigCmd.ExecuteReader()) { @@ -40,7 +40,7 @@ namespace NzbDrone.Core.Datastore.Migration { updateCmd.Transaction = tran; - updateCmd.CommandText = "UPDATE NamingConfig SET StandardEpisodeFormat = ?, DailyEpisodeFormat = ?, AnimeEpisodeFormat = ?"; + updateCmd.CommandText = "UPDATE \"NamingConfig\" SET \"StandardEpisodeFormat\" = ?, \"DailyEpisodeFormat\" = ?, \"AnimeEpisodeFormat\" = ?"; updateCmd.AddParameter(newStandard); updateCmd.AddParameter(newDaily); updateCmd.AddParameter(newAnime); diff --git a/src/NzbDrone.Core/Datastore/Migration/070_delay_profile.cs b/src/NzbDrone.Core/Datastore/Migration/070_delay_profile.cs index b2cd28121..03716e3a6 100644 --- a/src/NzbDrone.Core/Datastore/Migration/070_delay_profile.cs +++ b/src/NzbDrone.Core/Datastore/Migration/070_delay_profile.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Data; using System.Linq; +using Dapper; using FluentMigrator; using NzbDrone.Common.Serializer; using NzbDrone.Core.Datastore.Migration.Framework; @@ -24,8 +25,8 @@ namespace NzbDrone.Core.Datastore.Migration Insert.IntoTable("DelayProfiles").Row(new { - EnableUsenet = 1, - EnableTorrent = 1, + EnableUsenet = true, + EnableTorrent = true, PreferredProtocol = 1, UsenetDelay = 0, TorrentDelay = 0, @@ -43,6 +44,7 @@ namespace NzbDrone.Core.Datastore.Migration { var profiles = GetProfiles(conn, tran); var order = 1; + var updateProfiles = new List(); foreach (var profileClosure in profiles.DistinctBy(p => p.GrabDelay)) { @@ -56,16 +58,12 @@ namespace NzbDrone.Core.Datastore.Migration var tagId = InsertTag(conn, tran, tag); var tags = string.Format("[{0}]", tagId); - using (var insertDelayProfileCmd = conn.CreateCommand()) + updateProfiles.Add(new { - insertDelayProfileCmd.Transaction = tran; - insertDelayProfileCmd.CommandText = "INSERT INTO DelayProfiles (EnableUsenet, EnableTorrent, PreferredProtocol, TorrentDelay, UsenetDelay, [Order], Tags) VALUES (1, 1, 1, 0, ?, ?, ?)"; - insertDelayProfileCmd.AddParameter(profile.GrabDelay); - insertDelayProfileCmd.AddParameter(order); - insertDelayProfileCmd.AddParameter(tags); - - insertDelayProfileCmd.ExecuteNonQuery(); - } + UsenetDelay = profile.GrabDelay, + Order = order, + Tags = tags + }); var matchingProfileIds = profiles.Where(p => p.GrabDelay == profile.GrabDelay) .Select(p => p.Id); @@ -74,6 +72,9 @@ namespace NzbDrone.Core.Datastore.Migration order++; } + + var insertDelayProfilesSql = $"INSERT INTO \"DelayProfiles\" (\"EnableUsenet\", \"EnableTorrent\", \"PreferredProtocol\", \"TorrentDelay\", \"UsenetDelay\", \"Order\", \"Tags\") VALUES (true, true, 1, 0, @UsenetDelay, @Order, @Tags)"; + conn.Execute(insertDelayProfilesSql, updateProfiles, transaction: tran); } private List GetProfiles(IDbConnection conn, IDbTransaction tran) @@ -83,7 +84,7 @@ namespace NzbDrone.Core.Datastore.Migration using (var getProfilesCmd = conn.CreateCommand()) { getProfilesCmd.Transaction = tran; - getProfilesCmd.CommandText = @"SELECT Id, GrabDelay FROM Profiles"; + getProfilesCmd.CommandText = "SELECT \"Id\", \"GrabDelay\" FROM \"Profiles\""; using (var profileReader = getProfilesCmd.ExecuteReader()) { @@ -106,25 +107,28 @@ namespace NzbDrone.Core.Datastore.Migration private int InsertTag(IDbConnection conn, IDbTransaction tran, string tagLabel) { - using (var insertCmd = conn.CreateCommand()) + var parameters = new { - insertCmd.Transaction = tran; - insertCmd.CommandText = @"INSERT INTO Tags (Label) VALUES (?); SELECT last_insert_rowid()"; - insertCmd.AddParameter(tagLabel); + TagLabel = tagLabel + }; - var id = insertCmd.ExecuteScalar(); + var insertTagSql = "INSERT INTO \"Tags\" (\"Label\") VALUES (@TagLabel)"; + conn.Execute(insertTagSql, parameters, transaction: tran); - return Convert.ToInt32(id); - } + var selectTagSql = "SELECT \"Id\" FROM \"Tags\" WHERE \"Label\" = @TagLabel"; + var id = conn.ExecuteScalar(selectTagSql, parameters, transaction: tran); + + return Convert.ToInt32(id); } private void UpdateSeries(IDbConnection conn, IDbTransaction tran, IEnumerable profileIds, int tagId) { + var updatedSeries = new List(); + using (var getSeriesCmd = conn.CreateCommand()) { getSeriesCmd.Transaction = tran; - getSeriesCmd.CommandText = "SELECT Id, Tags FROM Series WHERE ProfileId IN (?)"; - getSeriesCmd.AddParameter(string.Join(",", profileIds)); + getSeriesCmd.CommandText = $"SELECT \"Id\", \"Tags\" FROM \"Series\" WHERE \"ProfileId\" IN ({string.Join(",", profileIds)})"; using (var seriesReader = getSeriesCmd.ExecuteReader()) { @@ -136,18 +140,17 @@ namespace NzbDrone.Core.Datastore.Migration var tags = Json.Deserialize>(tagString); tags.Add(tagId); - using (var updateSeriesCmd = conn.CreateCommand()) + updatedSeries.Add(new { - updateSeriesCmd.Transaction = tran; - updateSeriesCmd.CommandText = "UPDATE Series SET Tags = ? WHERE Id = ?"; - updateSeriesCmd.AddParameter(tags.ToJson()); - updateSeriesCmd.AddParameter(id); - - updateSeriesCmd.ExecuteNonQuery(); - } + Tags = tags.ToJson(), + Id = id + }); } } } + + var updateSeriesSql = "UPDATE \"Series\" SET \"Tags\" = @Tags WHERE \"Id\" = @Id"; + conn.Execute(updateSeriesSql, updatedSeries, transaction: tran); } } diff --git a/src/NzbDrone.Core/Datastore/Migration/071_unknown_quality_in_profile.cs b/src/NzbDrone.Core/Datastore/Migration/071_unknown_quality_in_profile.cs index f75bd01e6..ca57b145f 100644 --- a/src/NzbDrone.Core/Datastore/Migration/071_unknown_quality_in_profile.cs +++ b/src/NzbDrone.Core/Datastore/Migration/071_unknown_quality_in_profile.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Data; using System.Linq; +using Dapper; using FluentMigrator; using NzbDrone.Common.Serializer; using NzbDrone.Core.Datastore.Migration.Framework; @@ -58,21 +59,17 @@ namespace NzbDrone.Core.Datastore.Migration public void Commit() { - foreach (var profile in _changedProfiles) + var profilesToUpdate = _changedProfiles.Select(p => new { - using (var updateProfileCmd = _connection.CreateCommand()) - { - updateProfileCmd.Transaction = _transaction; - updateProfileCmd.CommandText = "UPDATE Profiles SET Name = ?, Cutoff = ?, Items = ?, Language = ? WHERE Id = ?"; - updateProfileCmd.AddParameter(profile.Name); - updateProfileCmd.AddParameter(profile.Cutoff); - updateProfileCmd.AddParameter(profile.Items.ToJson()); - updateProfileCmd.AddParameter(profile.Language); - updateProfileCmd.AddParameter(profile.Id); + Id = p.Id, + Name = p.Name, + Cutoff = p.Cutoff, + Language = p.Language, + Items = p.Items.ToJson() + }); - updateProfileCmd.ExecuteNonQuery(); - } - } + var updateSql = $"UPDATE \"Profiles\" SET \"Name\" = @Name, \"Cutoff\" = @Cutoff, \"Language\" = @Language, \"Items\" = @Items WHERE \"Id\" = @Id"; + _connection.Execute(updateSql, profilesToUpdate, transaction: _transaction); _changedProfiles.Clear(); } @@ -169,7 +166,7 @@ namespace NzbDrone.Core.Datastore.Migration using (var getProfilesCmd = _connection.CreateCommand()) { getProfilesCmd.Transaction = _transaction; - getProfilesCmd.CommandText = @"SELECT Id, Name, Cutoff, Items, Language FROM Profiles"; + getProfilesCmd.CommandText = "SELECT \"Id\", \"Name\", \"Cutoff\", \"Items\", \"Language\" FROM \"Profiles\""; using (var profileReader = getProfilesCmd.ExecuteReader()) { diff --git a/src/NzbDrone.Core/Datastore/Migration/072_history_grabid.cs b/src/NzbDrone.Core/Datastore/Migration/072_history_grabid.cs index 9e51224fb..b10e94b40 100644 --- a/src/NzbDrone.Core/Datastore/Migration/072_history_grabid.cs +++ b/src/NzbDrone.Core/Datastore/Migration/072_history_grabid.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Data; +using Dapper; using FluentMigrator; using NzbDrone.Common.Serializer; using NzbDrone.Core.Datastore.Migration.Framework; @@ -22,10 +23,12 @@ namespace NzbDrone.Core.Datastore.Migration private void MoveToColumn(IDbConnection conn, IDbTransaction tran) { + var updatedHistory = new List(); + using (var getHistory = conn.CreateCommand()) { getHistory.Transaction = tran; - getHistory.CommandText = @"SELECT Id, Data FROM History WHERE Data LIKE '%downloadClientId%'"; + getHistory.CommandText = "SELECT \"Id\", \"Data\" FROM \"History\" WHERE \"Data\" LIKE '%downloadClientId%'"; using (var historyReader = getHistory.ExecuteReader()) { @@ -34,30 +37,23 @@ namespace NzbDrone.Core.Datastore.Migration var id = historyReader.GetInt32(0); var data = historyReader.GetString(1); - UpdateHistory(tran, conn, id, data); + var dic = Json.Deserialize>(data); + + var downloadId = dic["downloadClientId"]; + dic.Remove("downloadClientId"); + + updatedHistory.Add(new + { + Id = id, + Data = dic.ToJson(), + DownloadId = downloadId + }); } } } - } - private void UpdateHistory(IDbTransaction tran, IDbConnection conn, int id, string data) - { - var dic = Json.Deserialize>(data); - - var downloadId = dic["downloadClientId"]; - dic.Remove("downloadClientId"); - - using (var updateHistoryCmd = conn.CreateCommand()) - { - updateHistoryCmd.Transaction = tran; - updateHistoryCmd.CommandText = @"UPDATE History SET DownloadId = ?, Data = ? WHERE Id = ?"; - - updateHistoryCmd.AddParameter(downloadId); - updateHistoryCmd.AddParameter(dic.ToJson()); - updateHistoryCmd.AddParameter(id); - - updateHistoryCmd.ExecuteNonQuery(); - } + var updateSql = $"UPDATE \"History\" SET \"DownloadId\" = @DownloadId, \"Data\" = @Data WHERE \"Id\" = @Id"; + conn.Execute(updateSql, updatedHistory, transaction: tran); } } diff --git a/src/NzbDrone.Core/Datastore/Migration/074_disable_eztv.cs b/src/NzbDrone.Core/Datastore/Migration/074_disable_eztv.cs index c090df19b..072fe6b5b 100644 --- a/src/NzbDrone.Core/Datastore/Migration/074_disable_eztv.cs +++ b/src/NzbDrone.Core/Datastore/Migration/074_disable_eztv.cs @@ -1,4 +1,4 @@ -using FluentMigrator; +using FluentMigrator; using NzbDrone.Core.Datastore.Migration.Framework; namespace NzbDrone.Core.Datastore.Migration @@ -8,7 +8,7 @@ namespace NzbDrone.Core.Datastore.Migration { protected override void MainDbUpgrade() { - Execute.Sql("UPDATE Indexers SET EnableRss = 0, EnableSearch = 0 WHERE Implementation = 'Eztv' AND Settings LIKE '%ezrss.it%'"); + Execute.Sql("UPDATE \"Indexers\" SET \"EnableRss\" = false, \"EnableSearch\" = false WHERE \"Implementation\" = 'Eztv' AND \"Settings\" LIKE '%ezrss.it%'"); } } } diff --git a/src/NzbDrone.Core/Datastore/Migration/079_dedupe_tags.cs b/src/NzbDrone.Core/Datastore/Migration/079_dedupe_tags.cs index 1f140c937..8a6972f20 100644 --- a/src/NzbDrone.Core/Datastore/Migration/079_dedupe_tags.cs +++ b/src/NzbDrone.Core/Datastore/Migration/079_dedupe_tags.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Data; using System.Linq; +using Dapper; using FluentMigrator; using NzbDrone.Common.Serializer; using NzbDrone.Core.Datastore.Migration.Framework; @@ -48,7 +49,7 @@ namespace NzbDrone.Core.Datastore.Migration using (var tagCmd = conn.CreateCommand()) { tagCmd.Transaction = tran; - tagCmd.CommandText = @"SELECT Id, Label FROM Tags"; + tagCmd.CommandText = "SELECT \"Id\", \"Label\" FROM \"Tags\""; using (var tagReader = tagCmd.ExecuteReader()) { @@ -72,7 +73,7 @@ namespace NzbDrone.Core.Datastore.Migration using (var tagCmd = conn.CreateCommand()) { tagCmd.Transaction = tran; - tagCmd.CommandText = string.Format("SELECT Id, Tags FROM {0}", table); + tagCmd.CommandText = string.Format("SELECT \"Id\", \"Tags\" FROM \"{0}\"", table); using (var tagReader = tagCmd.ExecuteReader()) { @@ -109,29 +110,28 @@ namespace NzbDrone.Core.Datastore.Migration } } - foreach (var model in toUpdate.DistinctBy(m => m.Id)) + var updatedTags = toUpdate.DistinctBy(m => m.Id).Select(t => new { - using (var updateCmd = conn.CreateCommand()) - { - updateCmd.Transaction = tran; - updateCmd.CommandText = string.Format(@"UPDATE {0} SET Tags = ? WHERE Id = ?", table); - updateCmd.AddParameter(model.Tags.ToJson()); - updateCmd.AddParameter(model.Id); + Tags = t.Tags.ToJson(), + Id = t.Id + }); - updateCmd.ExecuteNonQuery(); - } - } + var updateTagsSql = $"UPDATE \"{table}\" SET \"Tags\" = @Tags WHERE \"Id\" = @Id"; + conn.Execute(updateTagsSql, updatedTags, transaction: tran); } private void DeleteTags(IDbConnection conn, IDbTransaction tran, List replacements) { var idsToRemove = replacements.Select(r => r.OldId).Distinct(); - using (var removeCmd = conn.CreateCommand()) + if (idsToRemove.Any()) { - removeCmd.Transaction = tran; - removeCmd.CommandText = string.Format("DELETE FROM Tags WHERE Id IN ({0})", string.Join(",", idsToRemove)); - removeCmd.ExecuteNonQuery(); + using (var removeCmd = conn.CreateCommand()) + { + removeCmd.Transaction = tran; + removeCmd.CommandText = $"DELETE FROM \"Tags\" WHERE \"Id\" IN ({string.Join(", ", idsToRemove)})"; + removeCmd.ExecuteNonQuery(); + } } } diff --git a/src/NzbDrone.Core/Datastore/Migration/081_move_dot_prefix_to_transmission_category.cs b/src/NzbDrone.Core/Datastore/Migration/081_move_dot_prefix_to_transmission_category.cs index c48fd75a8..f77f92e26 100644 --- a/src/NzbDrone.Core/Datastore/Migration/081_move_dot_prefix_to_transmission_category.cs +++ b/src/NzbDrone.Core/Datastore/Migration/081_move_dot_prefix_to_transmission_category.cs @@ -1,5 +1,6 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Data; +using Dapper; using FluentMigrator; using Newtonsoft.Json.Linq; using NzbDrone.Common.Extensions; @@ -18,10 +19,12 @@ namespace NzbDrone.Core.Datastore.Migration private void UpdateTransmissionSettings(IDbConnection conn, IDbTransaction tran) { + var updatedClients = new List(); + using (var cmd = conn.CreateCommand()) { cmd.Transaction = tran; - cmd.CommandText = "SELECT Id, Settings FROM DownloadClients WHERE Implementation = 'Transmission'"; + cmd.CommandText = "SELECT \"Id\", \"Settings\" FROM \"DownloadClients\" WHERE \"Implementation\" = 'Transmission'"; using (var reader = cmd.ExecuteReader()) { @@ -37,19 +40,18 @@ namespace NzbDrone.Core.Datastore.Migration { settings["tvCategory"] = "." + tvCategory; - using (var updateCmd = conn.CreateCommand()) + updatedClients.Add(new { - updateCmd.Transaction = tran; - updateCmd.CommandText = "UPDATE DownloadClients SET Settings = ? WHERE Id = ?"; - updateCmd.AddParameter(settings.ToJson()); - updateCmd.AddParameter(id); - - updateCmd.ExecuteNonQuery(); - } + Settings = settings.ToJson(), + Id = id + }); } } } } + + var updateClientsSql = "UPDATE \"DownloadClients\" SET \"Settings\" = @Settings WHERE \"Id\" = @Id"; + conn.Execute(updateClientsSql, updatedClients, transaction: tran); } } diff --git a/src/NzbDrone.Core/Datastore/Migration/082_add_fanzub_settings.cs b/src/NzbDrone.Core/Datastore/Migration/082_add_fanzub_settings.cs index 43d332224..0ef429df4 100644 --- a/src/NzbDrone.Core/Datastore/Migration/082_add_fanzub_settings.cs +++ b/src/NzbDrone.Core/Datastore/Migration/082_add_fanzub_settings.cs @@ -1,4 +1,4 @@ -using FluentMigrator; +using FluentMigrator; using NzbDrone.Core.Datastore.Migration.Framework; namespace NzbDrone.Core.Datastore.Migration @@ -8,7 +8,7 @@ namespace NzbDrone.Core.Datastore.Migration { protected override void MainDbUpgrade() { - Execute.Sql("UPDATE Indexers SET ConfigContract = 'FanzubSettings' WHERE Implementation = 'Fanzub' AND ConfigContract = 'NullConfig'"); + Update.Table("Indexers").Set(new { ConfigContract = "FanzubSettings" }).Where(new { Implementation = "Fanzub", ConfigContract = "NullConfig" }); } } } diff --git a/src/NzbDrone.Core/Datastore/Migration/084_update_quality_minmax_size.cs b/src/NzbDrone.Core/Datastore/Migration/084_update_quality_minmax_size.cs index 03a0a8ea3..6faf47ffd 100644 --- a/src/NzbDrone.Core/Datastore/Migration/084_update_quality_minmax_size.cs +++ b/src/NzbDrone.Core/Datastore/Migration/084_update_quality_minmax_size.cs @@ -1,4 +1,4 @@ -using FluentMigrator; +using FluentMigrator; using NzbDrone.Core.Datastore.Migration.Framework; namespace NzbDrone.Core.Datastore.Migration @@ -11,7 +11,7 @@ namespace NzbDrone.Core.Datastore.Migration Alter.Table("QualityDefinitions").AlterColumn("MinSize").AsDouble().Nullable(); Alter.Table("QualityDefinitions").AlterColumn("MaxSize").AsDouble().Nullable(); - Execute.Sql("UPDATE QualityDefinitions SET MaxSize = NULL WHERE Quality = 10 OR MaxSize = 0"); + Execute.Sql("UPDATE \"QualityDefinitions\" SET \"MaxSize\" = NULL WHERE \"Quality\" = 10 OR \"MaxSize\" = 0"); } } diff --git a/src/NzbDrone.Core/Datastore/Migration/085_expand_transmission_urlbase.cs b/src/NzbDrone.Core/Datastore/Migration/085_expand_transmission_urlbase.cs index 981e90799..d243847f0 100644 --- a/src/NzbDrone.Core/Datastore/Migration/085_expand_transmission_urlbase.cs +++ b/src/NzbDrone.Core/Datastore/Migration/085_expand_transmission_urlbase.cs @@ -1,5 +1,6 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Data; +using Dapper; using FluentMigrator; using NzbDrone.Common.Extensions; using NzbDrone.Common.Serializer; @@ -17,10 +18,12 @@ namespace NzbDrone.Core.Datastore.Migration private void UpdateTransmissionSettings(IDbConnection conn, IDbTransaction tran) { + var updatedClients = new List(); + using (var cmd = conn.CreateCommand()) { cmd.Transaction = tran; - cmd.CommandText = "SELECT Id, Settings FROM DownloadClients WHERE Implementation = 'Transmission'"; + cmd.CommandText = "SELECT \"Id\", \"Settings\" FROM \"DownloadClients\" WHERE \"Implementation\" = 'Transmission'"; using (var reader = cmd.ExecuteReader()) { @@ -42,18 +45,17 @@ namespace NzbDrone.Core.Datastore.Migration settings["urlBase"] = string.Format("/{0}/transmission/", urlBase.Trim('/')); } - using (var updateCmd = conn.CreateCommand()) + updatedClients.Add(new { - updateCmd.Transaction = tran; - updateCmd.CommandText = "UPDATE DownloadClients SET Settings = ? WHERE Id = ?"; - updateCmd.AddParameter(settings.ToJson()); - updateCmd.AddParameter(id); - - updateCmd.ExecuteNonQuery(); - } + Settings = settings.ToJson(), + Id = id + }); } } } + + var updateClientsSql = "UPDATE \"DownloadClients\" SET \"Settings\" = @Settings WHERE \"Id\" = @Id"; + conn.Execute(updateClientsSql, updatedClients, transaction: tran); } } diff --git a/src/NzbDrone.Core/Datastore/Migration/086_pushbullet_device_ids.cs b/src/NzbDrone.Core/Datastore/Migration/086_pushbullet_device_ids.cs index e73e89eaa..d63105b02 100644 --- a/src/NzbDrone.Core/Datastore/Migration/086_pushbullet_device_ids.cs +++ b/src/NzbDrone.Core/Datastore/Migration/086_pushbullet_device_ids.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Data; +using Dapper; using FluentMigrator; using Newtonsoft.Json.Linq; using NzbDrone.Common.Serializer; @@ -17,10 +18,12 @@ namespace NzbDrone.Core.Datastore.Migration private void UpdateTransmissionSettings(IDbConnection conn, IDbTransaction tran) { + var updatedClients = new List(); + using (var cmd = conn.CreateCommand()) { cmd.Transaction = tran; - cmd.CommandText = "SELECT Id, Settings FROM Notifications WHERE Implementation = 'PushBullet'"; + cmd.CommandText = "SELECT \"Id\", \"Settings\" FROM \"Notifications\" WHERE \"Implementation\" = 'PushBullet'"; using (var reader = cmd.ExecuteReader()) { @@ -37,19 +40,18 @@ namespace NzbDrone.Core.Datastore.Migration settings.Add("deviceIds", new[] { deviceId }); settings.Remove("deviceId"); - using (var updateCmd = conn.CreateCommand()) + updatedClients.Add(new { - updateCmd.Transaction = tran; - updateCmd.CommandText = "UPDATE Notifications SET Settings = ? WHERE Id = ?"; - updateCmd.AddParameter(settings.ToJson()); - updateCmd.AddParameter(id); - - updateCmd.ExecuteNonQuery(); - } + Settings = settings.ToJson(), + Id = id + }); } } } } + + var updateClientsSql = "UPDATE \"Notifications\" SET \"Settings\" = @Settings WHERE \"Id\" = @Id"; + conn.Execute(updateClientsSql, updatedClients, transaction: tran); } } diff --git a/src/NzbDrone.Core/Datastore/Migration/087_remove_eztv.cs b/src/NzbDrone.Core/Datastore/Migration/087_remove_eztv.cs index d6990053a..19e54d3f8 100644 --- a/src/NzbDrone.Core/Datastore/Migration/087_remove_eztv.cs +++ b/src/NzbDrone.Core/Datastore/Migration/087_remove_eztv.cs @@ -1,4 +1,4 @@ -using FluentMigrator; +using FluentMigrator; using NzbDrone.Core.Datastore.Migration.Framework; namespace NzbDrone.Core.Datastore.Migration @@ -8,7 +8,7 @@ namespace NzbDrone.Core.Datastore.Migration { protected override void MainDbUpgrade() { - Execute.Sql("DELETE FROM Indexers WHERE Implementation = 'Eztv'"); + Delete.FromTable("Indexers").Row(new { Implementation = "Eztv" }); } } } diff --git a/src/NzbDrone.Core/Datastore/Migration/088_pushbullet_devices_channels_list.cs b/src/NzbDrone.Core/Datastore/Migration/088_pushbullet_devices_channels_list.cs index 9991b42e0..121b0e9af 100644 --- a/src/NzbDrone.Core/Datastore/Migration/088_pushbullet_devices_channels_list.cs +++ b/src/NzbDrone.Core/Datastore/Migration/088_pushbullet_devices_channels_list.cs @@ -1,6 +1,7 @@ -using System; +using System; using System.Collections.Generic; using System.Data; +using Dapper; using FluentMigrator; using NzbDrone.Common.Extensions; using NzbDrone.Common.Serializer; @@ -18,10 +19,12 @@ namespace NzbDrone.Core.Datastore.Migration private void UpdateTransmissionSettings(IDbConnection conn, IDbTransaction tran) { + var updatedClients = new List(); + using (var cmd = conn.CreateCommand()) { cmd.Transaction = tran; - cmd.CommandText = "SELECT Id, Settings FROM Notifications WHERE Implementation = 'PushBullet'"; + cmd.CommandText = "SELECT \"Id\", \"Settings\" FROM \"Notifications\" WHERE \"Implementation\" = 'PushBullet'"; using (var reader = cmd.ExecuteReader()) { @@ -55,18 +58,17 @@ namespace NzbDrone.Core.Datastore.Migration } } - using (var updateCmd = conn.CreateCommand()) + updatedClients.Add(new { - updateCmd.Transaction = tran; - updateCmd.CommandText = "UPDATE Notifications SET Settings = ? WHERE Id = ?"; - updateCmd.AddParameter(settings.ToJson()); - updateCmd.AddParameter(id); - - updateCmd.ExecuteNonQuery(); - } + Settings = settings.ToJson(), + Id = id + }); } } } + + var updateClientsSql = "UPDATE \"Notifications\" SET \"Settings\" = @Settings WHERE \"Id\" = @Id"; + conn.Execute(updateClientsSql, updatedClients, transaction: tran); } } diff --git a/src/NzbDrone.Core/Datastore/Migration/089_add_on_rename_to_notifcations.cs b/src/NzbDrone.Core/Datastore/Migration/089_add_on_rename_to_notifcations.cs index e06db676b..88c6af275 100644 --- a/src/NzbDrone.Core/Datastore/Migration/089_add_on_rename_to_notifcations.cs +++ b/src/NzbDrone.Core/Datastore/Migration/089_add_on_rename_to_notifcations.cs @@ -1,4 +1,4 @@ -using FluentMigrator; +using FluentMigrator; using NzbDrone.Core.Datastore.Migration.Framework; namespace NzbDrone.Core.Datastore.Migration @@ -10,12 +10,12 @@ namespace NzbDrone.Core.Datastore.Migration { Alter.Table("Notifications").AddColumn("OnRename").AsBoolean().Nullable(); - Execute.Sql("UPDATE Notifications SET OnRename = OnDownload WHERE Implementation IN ('PlexServer', 'Xbmc', 'MediaBrowser')"); - Execute.Sql("UPDATE Notifications SET OnRename = 0 WHERE Implementation NOT IN ('PlexServer', 'Xbmc', 'MediaBrowser')"); + Execute.Sql("UPDATE \"Notifications\" SET \"OnRename\" = \"OnDownload\" WHERE \"Implementation\" IN ('PlexServer', 'Xbmc', 'MediaBrowser')"); + Execute.Sql("UPDATE \"Notifications\" SET \"OnRename\" = false WHERE \"Implementation\" NOT IN ('PlexServer', 'Xbmc', 'MediaBrowser')"); Alter.Table("Notifications").AlterColumn("OnRename").AsBoolean().NotNullable(); - Execute.Sql("UPDATE Notifications SET OnGrab = 0 WHERE Implementation = 'PlexServer'"); + Update.Table("Notifications").Set(new { OnGrab = false }).Where(new { Implementation = "PlexServer" }); } } } diff --git a/src/NzbDrone.Core/Datastore/Migration/090_update_kickass_url.cs b/src/NzbDrone.Core/Datastore/Migration/090_update_kickass_url.cs index bc22b3258..7342d0969 100644 --- a/src/NzbDrone.Core/Datastore/Migration/090_update_kickass_url.cs +++ b/src/NzbDrone.Core/Datastore/Migration/090_update_kickass_url.cs @@ -1,4 +1,4 @@ -using FluentMigrator; +using FluentMigrator; using Newtonsoft.Json.Linq; using NzbDrone.Core.Datastore.Migration.Framework; @@ -10,9 +10,9 @@ namespace NzbDrone.Core.Datastore.Migration protected override void MainDbUpgrade() { Execute.Sql( - "UPDATE Indexers SET Settings = Replace(Settings, 'kickass.so', 'kat.cr') WHERE Implementation = 'KickassTorrents';" + - "UPDATE Indexers SET Settings = Replace(Settings, 'kickass.to', 'kat.cr') WHERE Implementation = 'KickassTorrents';" + - "UPDATE Indexers SET Settings = Replace(Settings, 'http://', 'https://') WHERE Implementation = 'KickassTorrents';"); + "UPDATE \"Indexers\" SET \"Settings\" = Replace(\"Settings\", 'kickass.so', 'kat.cr') WHERE \"Implementation\" = 'KickassTorrents';" + + "UPDATE \"Indexers\" SET \"Settings\" = Replace(\"Settings\", 'kickass.to', 'kat.cr') WHERE \"Implementation\" = 'KickassTorrents';" + + "UPDATE \"Indexers\" SET \"Settings\" = Replace(\"Settings\", 'http://', 'https://') WHERE \"Implementation\" = 'KickassTorrents';"); } } diff --git a/src/NzbDrone.Core/Datastore/Migration/096_disable_kickass.cs b/src/NzbDrone.Core/Datastore/Migration/096_disable_kickass.cs index 69894cbce..ec65d8cd5 100644 --- a/src/NzbDrone.Core/Datastore/Migration/096_disable_kickass.cs +++ b/src/NzbDrone.Core/Datastore/Migration/096_disable_kickass.cs @@ -1,4 +1,4 @@ -using FluentMigrator; +using FluentMigrator; using NzbDrone.Core.Datastore.Migration.Framework; namespace NzbDrone.Core.Datastore.Migration @@ -8,7 +8,7 @@ namespace NzbDrone.Core.Datastore.Migration { protected override void MainDbUpgrade() { - Execute.Sql("UPDATE Indexers SET EnableRss = 0, EnableSearch = 0, Settings = Replace(Settings, 'https://kat.cr', '') WHERE Implementation = 'KickassTorrents' AND Settings LIKE '%kat.cr%';"); + Execute.Sql("UPDATE \"Indexers\" SET \"EnableRss\" = false, \"EnableSearch\" = false, \"Settings\" = Replace(\"Settings\", 'https://kat.cr', '') WHERE \"Implementation\" = 'KickassTorrents' AND \"Settings\" LIKE '%kat.cr%';"); } } } diff --git a/src/NzbDrone.Core/Datastore/Migration/099_extra_and_subtitle_files.cs b/src/NzbDrone.Core/Datastore/Migration/099_extra_and_subtitle_files.cs index f7a173157..1fda381a6 100644 --- a/src/NzbDrone.Core/Datastore/Migration/099_extra_and_subtitle_files.cs +++ b/src/NzbDrone.Core/Datastore/Migration/099_extra_and_subtitle_files.cs @@ -1,5 +1,7 @@ -using System; +using System; +using System.Collections.Generic; using System.Data; +using Dapper; using FluentMigrator; using NzbDrone.Core.Datastore.Migration.Framework; @@ -34,7 +36,7 @@ namespace NzbDrone.Core.Datastore.Migration .AddColumn("Extension").AsString().Nullable(); // Remove Metadata files that don't have an extension - Execute.Sql("DELETE FROM MetadataFiles WHERE RelativePath NOT LIKE '%.%'"); + Execute.Sql("DELETE FROM \"MetadataFiles\" WHERE \"RelativePath\" NOT LIKE '%.%'"); // Set Extension using the extension from RelativePath Execute.WithConnection(SetMetadataFileExtension); @@ -44,10 +46,12 @@ namespace NzbDrone.Core.Datastore.Migration private void SetMetadataFileExtension(IDbConnection conn, IDbTransaction tran) { + var updatedMetadataFiles = new List(); + using (var cmd = conn.CreateCommand()) { cmd.Transaction = tran; - cmd.CommandText = "SELECT Id, RelativePath FROM MetadataFiles"; + cmd.CommandText = "SELECT \"Id\", \"RelativePath\" FROM \"MetadataFiles\""; using (var reader = cmd.ExecuteReader()) { @@ -57,18 +61,17 @@ namespace NzbDrone.Core.Datastore.Migration var relativePath = reader.GetString(1); var extension = relativePath.Substring(relativePath.LastIndexOf(".", StringComparison.InvariantCultureIgnoreCase)); - using (var updateCmd = conn.CreateCommand()) + updatedMetadataFiles.Add(new { - updateCmd.Transaction = tran; - updateCmd.CommandText = "UPDATE MetadataFiles SET Extension = ? WHERE Id = ?"; - updateCmd.AddParameter(extension); - updateCmd.AddParameter(id); - - updateCmd.ExecuteNonQuery(); - } + Id = id, + Extension = extension + }); } } } + + var updateSql = $"UPDATE \"MetadataFiles\" SET \"Extension\" = @Extension WHERE \"Id\" = @Id"; + conn.Execute(updateSql, updatedMetadataFiles, transaction: tran); } } diff --git a/src/NzbDrone.Core/Datastore/Migration/102_add_language_to_episodeFiles_history_and_blacklist.cs b/src/NzbDrone.Core/Datastore/Migration/102_add_language_to_episodeFiles_history_and_blacklist.cs index fd9cff0e2..52cc063e1 100644 --- a/src/NzbDrone.Core/Datastore/Migration/102_add_language_to_episodeFiles_history_and_blacklist.cs +++ b/src/NzbDrone.Core/Datastore/Migration/102_add_language_to_episodeFiles_history_and_blacklist.cs @@ -35,23 +35,25 @@ namespace NzbDrone.Core.Datastore.Migration using (var getProfileCmd = conn.CreateCommand()) { getProfileCmd.Transaction = tran; - getProfileCmd.CommandText = "SELECT Id, Language FROM Profiles"; + getProfileCmd.CommandText = "SELECT \"Id\", \"Language\" FROM \"Profiles\""; - var profilesReader = getProfileCmd.ExecuteReader(); - while (profilesReader.Read()) + using (var profilesReader = getProfileCmd.ExecuteReader()) { - var profileId = profilesReader.GetInt32(0); - var episodeLanguage = Language.English.Id; - try + while (profilesReader.Read()) { - episodeLanguage = profilesReader.GetInt32(1); - } - catch (InvalidCastException e) - { - _logger.Debug("Language field not found in Profiles, using English as default." + e.Message); - } + var profileId = profilesReader.GetInt32(0); + var episodeLanguage = Language.English.Id; + try + { + episodeLanguage = profilesReader.GetInt32(1); + } + catch (InvalidCastException e) + { + _logger.Debug("Language field not found in Profiles, using English as default." + e.Message); + } - profileLanguages[profileId] = episodeLanguage; + profileLanguages[profileId] = episodeLanguage; + } } } @@ -59,7 +61,7 @@ namespace NzbDrone.Core.Datastore.Migration using (var getSeriesCmd = conn.CreateCommand()) { getSeriesCmd.Transaction = tran; - getSeriesCmd.CommandText = @"SELECT Id, ProfileId FROM Series"; + getSeriesCmd.CommandText = "SELECT \"Id\", \"ProfileId\" FROM \"Series\""; using (var seriesReader = getSeriesCmd.ExecuteReader()) { while (seriesReader.Read()) @@ -81,7 +83,7 @@ namespace NzbDrone.Core.Datastore.Migration using (var updateEpisodeFilesCmd = conn.CreateCommand()) { updateEpisodeFilesCmd.Transaction = tran; - updateEpisodeFilesCmd.CommandText = $"UPDATE EpisodeFiles SET Language = ? WHERE SeriesId IN ({seriesIds})"; + updateEpisodeFilesCmd.CommandText = $"UPDATE \"EpisodeFiles\" SET \"Language\" = ? WHERE \"SeriesId\" IN ({seriesIds})"; var param = updateEpisodeFilesCmd.CreateParameter(); languageConverter.SetValue(param, language); updateEpisodeFilesCmd.Parameters.Add(param); @@ -92,7 +94,7 @@ namespace NzbDrone.Core.Datastore.Migration using (var updateHistoryCmd = conn.CreateCommand()) { updateHistoryCmd.Transaction = tran; - updateHistoryCmd.CommandText = $"UPDATE History SET Language = ? WHERE SeriesId IN ({seriesIds})"; + updateHistoryCmd.CommandText = $"UPDATE \"History\" SET \"Language\" = ? WHERE \"SeriesId\" IN ({seriesIds})"; var param = updateHistoryCmd.CreateParameter(); languageConverter.SetValue(param, language); updateHistoryCmd.Parameters.Add(param); @@ -103,7 +105,7 @@ namespace NzbDrone.Core.Datastore.Migration using (var updateBlacklistCmd = conn.CreateCommand()) { updateBlacklistCmd.Transaction = tran; - updateBlacklistCmd.CommandText = $"UPDATE Blacklist SET Language = ? WHERE SeriesId IN ({seriesIds})"; + updateBlacklistCmd.CommandText = $"UPDATE \"Blacklist\" SET \"Language\" = ? WHERE \"SeriesId\" IN ({seriesIds})"; var param = updateBlacklistCmd.CreateParameter(); languageConverter.SetValue(param, language); updateBlacklistCmd.Parameters.Add(param); diff --git a/src/NzbDrone.Core/Datastore/Migration/103_fix_metadata_file_extensions.cs b/src/NzbDrone.Core/Datastore/Migration/103_fix_metadata_file_extensions.cs index d4ed853a3..e7ab9adba 100644 --- a/src/NzbDrone.Core/Datastore/Migration/103_fix_metadata_file_extensions.cs +++ b/src/NzbDrone.Core/Datastore/Migration/103_fix_metadata_file_extensions.cs @@ -1,5 +1,7 @@ -using System; +using System; +using System.Collections.Generic; using System.Data; +using Dapper; using FluentMigrator; using NzbDrone.Core.Datastore.Migration.Framework; @@ -15,10 +17,12 @@ namespace NzbDrone.Core.Datastore.Migration private void SetMetadataFileExtension(IDbConnection conn, IDbTransaction tran) { + var updatedMetadataFiles = new List(); + using (var cmd = conn.CreateCommand()) { cmd.Transaction = tran; - cmd.CommandText = "SELECT Id, Extension FROM MetadataFiles"; + cmd.CommandText = "SELECT \"Id\", \"Extension\" FROM \"MetadataFiles\""; using (var reader = cmd.ExecuteReader()) { @@ -28,18 +32,17 @@ namespace NzbDrone.Core.Datastore.Migration var extension = reader.GetString(1); extension = extension.Substring(extension.LastIndexOf(".", StringComparison.InvariantCultureIgnoreCase)); - using (var updateCmd = conn.CreateCommand()) + updatedMetadataFiles.Add(new { - updateCmd.Transaction = tran; - updateCmd.CommandText = "UPDATE MetadataFiles SET Extension = ? WHERE Id = ?"; - updateCmd.AddParameter(extension); - updateCmd.AddParameter(id); - - updateCmd.ExecuteNonQuery(); - } + Id = id, + Extension = extension + }); } } } + + var updateSql = $"UPDATE \"MetadataFiles\" SET \"Extension\" = @Extension WHERE \"Id\" = @Id"; + conn.Execute(updateSql, updatedMetadataFiles, transaction: tran); } } } diff --git a/src/NzbDrone.Core/Datastore/Migration/104_remove_kickass.cs b/src/NzbDrone.Core/Datastore/Migration/104_remove_kickass.cs index c7f21fe38..62838c5dc 100644 --- a/src/NzbDrone.Core/Datastore/Migration/104_remove_kickass.cs +++ b/src/NzbDrone.Core/Datastore/Migration/104_remove_kickass.cs @@ -1,4 +1,4 @@ -using FluentMigrator; +using FluentMigrator; using NzbDrone.Core.Datastore.Migration.Framework; namespace NzbDrone.Core.Datastore.Migration @@ -8,7 +8,7 @@ namespace NzbDrone.Core.Datastore.Migration { protected override void MainDbUpgrade() { - Execute.Sql("DELETE FROM Indexers WHERE Implementation = 'KickassTorrents';"); + Delete.FromTable("Indexers").Row(new { Implementation = "KickassTorrents" }); } } } diff --git a/src/NzbDrone.Core/Datastore/Migration/105_rename_torrent_downloadstation.cs b/src/NzbDrone.Core/Datastore/Migration/105_rename_torrent_downloadstation.cs index c5a71c885..bfb2e2a42 100644 --- a/src/NzbDrone.Core/Datastore/Migration/105_rename_torrent_downloadstation.cs +++ b/src/NzbDrone.Core/Datastore/Migration/105_rename_torrent_downloadstation.cs @@ -1,4 +1,4 @@ -using FluentMigrator; +using FluentMigrator; using NzbDrone.Core.Datastore.Migration.Framework; namespace NzbDrone.Core.Datastore.Migration @@ -8,7 +8,7 @@ namespace NzbDrone.Core.Datastore.Migration { protected override void MainDbUpgrade() { - Execute.Sql("UPDATE DownloadClients SET Implementation = 'TorrentDownloadStation' WHERE Implementation = 'DownloadStation';"); + Update.Table("DownloadClients").Set(new { Implementation = "TorrentDownloadStation" }).Where(new { Implementation = "DownloadStation" }); } } } diff --git a/src/NzbDrone.Core/Datastore/Migration/106_update_btn_url.cs b/src/NzbDrone.Core/Datastore/Migration/106_update_btn_url.cs index 2057e7ec6..4ca8f693c 100644 --- a/src/NzbDrone.Core/Datastore/Migration/106_update_btn_url.cs +++ b/src/NzbDrone.Core/Datastore/Migration/106_update_btn_url.cs @@ -8,7 +8,7 @@ namespace NzbDrone.Core.Datastore.Migration { protected override void MainDbUpgrade() { - Execute.Sql("UPDATE Indexers SET Settings = Replace(Settings, 'api.btnapps.net', 'api.broadcasthe.net') WHERE Implementation = 'BroadcastheNet';"); + Execute.Sql("UPDATE \"Indexers\" SET \"Settings\" = Replace(\"Settings\", 'api.btnapps.net', 'api.broadcasthe.net') WHERE \"Implementation\" = 'BroadcastheNet';"); } } diff --git a/src/NzbDrone.Core/Datastore/Migration/107_remove_wombles.cs b/src/NzbDrone.Core/Datastore/Migration/107_remove_wombles.cs index 7bbb5ceb7..8baceacc4 100644 --- a/src/NzbDrone.Core/Datastore/Migration/107_remove_wombles.cs +++ b/src/NzbDrone.Core/Datastore/Migration/107_remove_wombles.cs @@ -1,4 +1,4 @@ -using FluentMigrator; +using FluentMigrator; using NzbDrone.Core.Datastore.Migration.Framework; namespace NzbDrone.Core.Datastore.Migration @@ -8,7 +8,7 @@ namespace NzbDrone.Core.Datastore.Migration { protected override void MainDbUpgrade() { - Execute.Sql("DELETE FROM Indexers WHERE Implementation = 'Wombles';"); + Delete.FromTable("Indexers").Row(new { Implementation = "Wombles" }); } } } diff --git a/src/NzbDrone.Core/Datastore/Migration/108_fix_extra_file_extension.cs b/src/NzbDrone.Core/Datastore/Migration/108_fix_extra_file_extension.cs index 6d5225349..1b00559ed 100644 --- a/src/NzbDrone.Core/Datastore/Migration/108_fix_extra_file_extension.cs +++ b/src/NzbDrone.Core/Datastore/Migration/108_fix_extra_file_extension.cs @@ -1,5 +1,7 @@ -using System; +using System; +using System.Collections.Generic; using System.Data; +using Dapper; using FluentMigrator; using NzbDrone.Core.Datastore.Migration.Framework; @@ -12,7 +14,7 @@ namespace NzbDrone.Core.Datastore.Migration { // Delete extraneous files without extensions that Sonarr found previously, // these will be blocked from importing as well. - Execute.Sql("DELETE FROM ExtraFiles WHERE TRIM(Extension) = ''"); + Execute.Sql("DELETE FROM \"ExtraFiles\" WHERE TRIM(\"Extension\") = ''"); Execute.WithConnection(FixExtraFileExtension); } @@ -25,10 +27,12 @@ namespace NzbDrone.Core.Datastore.Migration private void FixExtraFileExtensionForTable(IDbConnection conn, IDbTransaction tran, string table) { + var updatedFiles = new List(); + using (var cmd = conn.CreateCommand()) { cmd.Transaction = tran; - cmd.CommandText = $"SELECT Id, RelativePath FROM {table}"; + cmd.CommandText = $"SELECT \"Id\", \"RelativePath\" FROM \"{table}\""; using (var reader = cmd.ExecuteReader()) { @@ -38,18 +42,17 @@ namespace NzbDrone.Core.Datastore.Migration var relativePath = reader.GetString(1); var extension = relativePath.Substring(relativePath.LastIndexOf(".", StringComparison.InvariantCultureIgnoreCase)); - using (var updateCmd = conn.CreateCommand()) + updatedFiles.Add(new { - updateCmd.Transaction = tran; - updateCmd.CommandText = $"UPDATE {table} SET Extension = ? WHERE Id = ?"; - updateCmd.AddParameter(extension); - updateCmd.AddParameter(id); - - updateCmd.ExecuteNonQuery(); - } + Extension = extension, + Id = id + }); } } } + + var updateSql = $"UPDATE \"{table}\" SET \"Extension\" = @Extension WHERE \"Id\" = @Id"; + conn.Execute(updateSql, updatedFiles, transaction: tran); } } } diff --git a/src/NzbDrone.Core/Datastore/Migration/109_import_extra_files.cs b/src/NzbDrone.Core/Datastore/Migration/109_import_extra_files.cs index e78e2c6a3..9499c42e2 100644 --- a/src/NzbDrone.Core/Datastore/Migration/109_import_extra_files.cs +++ b/src/NzbDrone.Core/Datastore/Migration/109_import_extra_files.cs @@ -1,4 +1,4 @@ -using System.Data; +using System.Data; using FluentMigrator; using NzbDrone.Common.Extensions; using NzbDrone.Core.Datastore.Migration.Framework; @@ -15,29 +15,31 @@ namespace NzbDrone.Core.Datastore.Migration private void ImportExtraFiles(IDbConnection conn, IDbTransaction tran) { + var extraFileExtensions = string.Empty; + using (var cmd = conn.CreateCommand()) { cmd.Transaction = tran; - cmd.CommandText = "SELECT Value from Config WHERE Key = 'extrafileextensions'"; + cmd.CommandText = "SELECT \"Value\" from \"Config\" WHERE \"Key\" = 'extrafileextensions'"; using (var reader = cmd.ExecuteReader()) { while (reader.Read()) { - var value = reader.GetString(0); - - if (value.IsNotNullOrWhiteSpace()) - { - using (var insertCmd = conn.CreateCommand()) - { - insertCmd.Transaction = tran; - insertCmd.CommandText = "INSERT INTO Config (Key, Value) VALUES('importextrafiles', 'True')"; - insertCmd.ExecuteNonQuery(); - } - } + extraFileExtensions = reader.GetString(0); } } } + + if (extraFileExtensions.IsNotNullOrWhiteSpace()) + { + using (var insertCmd = conn.CreateCommand()) + { + insertCmd.Transaction = tran; + insertCmd.CommandText = "INSERT INTO \"Config\" (\"Key\", \"Value\") VALUES('importextrafiles', 'True')"; + insertCmd.ExecuteNonQuery(); + } + } } } } diff --git a/src/NzbDrone.Core/Datastore/Migration/110_fix_extra_files_config.cs b/src/NzbDrone.Core/Datastore/Migration/110_fix_extra_files_config.cs index 5f136deb1..2f964ce51 100644 --- a/src/NzbDrone.Core/Datastore/Migration/110_fix_extra_files_config.cs +++ b/src/NzbDrone.Core/Datastore/Migration/110_fix_extra_files_config.cs @@ -1,4 +1,4 @@ -using System.Data; +using System.Data; using FluentMigrator; using NzbDrone.Common.Extensions; using NzbDrone.Core.Datastore.Migration.Framework; @@ -21,7 +21,7 @@ namespace NzbDrone.Core.Datastore.Migration using (var cmd = conn.CreateCommand()) { cmd.Transaction = tran; - cmd.CommandText = "SELECT Value FROM Config WHERE Key = 'extrafileextensions'"; + cmd.CommandText = "SELECT \"Value\" FROM \"Config\" WHERE \"Key\" = 'extrafileextensions'"; extraFileExtensions = (string)cmd.ExecuteScalar(); } @@ -29,7 +29,7 @@ namespace NzbDrone.Core.Datastore.Migration using (var cmd = conn.CreateCommand()) { cmd.Transaction = tran; - cmd.CommandText = "SELECT Value FROM Config WHERE Key = 'importextrafiles'"; + cmd.CommandText = "SELECT \"Value\" FROM \"Config\" WHERE \"Key\" = 'importextrafiles'"; importExtraFiles = (string)cmd.ExecuteScalar(); } @@ -39,7 +39,7 @@ namespace NzbDrone.Core.Datastore.Migration using (var insertCmd = conn.CreateCommand()) { insertCmd.Transaction = tran; - insertCmd.CommandText = "UPDATE Config SET Value = 'True' WHERE Key = 'importextrafiles'"; + insertCmd.CommandText = "UPDATE \"Config\" SET \"Value\" = 'True' WHERE \"Key\" = 'importextrafiles'"; insertCmd.ExecuteNonQuery(); } } @@ -48,7 +48,7 @@ namespace NzbDrone.Core.Datastore.Migration using (var insertCmd = conn.CreateCommand()) { insertCmd.Transaction = tran; - insertCmd.CommandText = "UPDATE Config SET Value = 'srt' WHERE Key = 'extrafileextensions'"; + insertCmd.CommandText = "UPDATE \"Config\" SET \"Value\" = 'srt' WHERE \"Key\" = 'extrafileextensions'"; insertCmd.ExecuteNonQuery(); } } diff --git a/src/NzbDrone.Core/Datastore/Migration/111_create_language_profiles.cs b/src/NzbDrone.Core/Datastore/Migration/111_create_language_profiles.cs index 0405a339a..1ef95814e 100644 --- a/src/NzbDrone.Core/Datastore/Migration/111_create_language_profiles.cs +++ b/src/NzbDrone.Core/Datastore/Migration/111_create_language_profiles.cs @@ -36,7 +36,7 @@ namespace NzbDrone.Core.Datastore.Migration using (var insertNewLanguageProfileCmd = conn.CreateCommand()) { insertNewLanguageProfileCmd.Transaction = tran; - insertNewLanguageProfileCmd.CommandText = "INSERT INTO LanguageProfiles (Id, Name, Cutoff, Languages) VALUES (?, ?, ?, ?)"; + insertNewLanguageProfileCmd.CommandText = "INSERT INTO \"LanguageProfiles\" (\"Id\", \"Name\", \"Cutoff\", \"Languages\") VALUES (?, ?, ?, ?)"; insertNewLanguageProfileCmd.AddParameter(profile.Id); insertNewLanguageProfileCmd.AddParameter(profile.Name); insertNewLanguageProfileCmd.AddParameter(profile.Cutoff.Id); @@ -52,7 +52,7 @@ namespace NzbDrone.Core.Datastore.Migration foreach (var profileId in profile.ProfileIds) { updateSeriesCmd.Transaction = tran; - updateSeriesCmd.CommandText = "UPDATE Series SET LanguageProfileId = ? WHERE ProfileId = ?"; + updateSeriesCmd.CommandText = "UPDATE \"Series\" SET \"LanguageProfileId\" = ? WHERE \"ProfileId\" = ?"; updateSeriesCmd.AddParameter(profile.Id); updateSeriesCmd.AddParameter(profileId); updateSeriesCmd.ExecuteNonQuery(); @@ -87,7 +87,7 @@ namespace NzbDrone.Core.Datastore.Migration using (var getProfilesCmd = conn.CreateCommand()) { getProfilesCmd.Transaction = tran; - getProfilesCmd.CommandText = @"SELECT Id, Language FROM Profiles"; + getProfilesCmd.CommandText = "SELECT \"Id\", \"Language\" FROM \"Profiles\""; using (var profileReader = getProfilesCmd.ExecuteReader()) { diff --git a/src/NzbDrone.Core/Datastore/Migration/113_consolidate_indexer_baseurl.cs b/src/NzbDrone.Core/Datastore/Migration/113_consolidate_indexer_baseurl.cs index ca063f160..dadda6f27 100644 --- a/src/NzbDrone.Core/Datastore/Migration/113_consolidate_indexer_baseurl.cs +++ b/src/NzbDrone.Core/Datastore/Migration/113_consolidate_indexer_baseurl.cs @@ -20,7 +20,7 @@ namespace NzbDrone.Core.Datastore.Migration using (var cmd = conn.CreateCommand()) { cmd.Transaction = tran; - cmd.CommandText = "SELECT Id, Settings FROM Indexers WHERE ConfigContract IN ('NewznabSettings', 'TorznabSettings', 'IPTorrentsSettings', 'OmgwtfnzbsSettings')"; + cmd.CommandText = "SELECT \"Id\", \"Settings\" FROM \"Indexers\" WHERE \"ConfigContract\" IN ('NewznabSettings', 'TorznabSettings', 'IPTorrentsSettings', 'OmgwtfnzbsSettings')"; using (var reader = cmd.ExecuteReader()) { @@ -42,7 +42,7 @@ namespace NzbDrone.Core.Datastore.Migration using (var updateCmd = conn.CreateCommand()) { updateCmd.Transaction = tran; - updateCmd.CommandText = "UPDATE Indexers SET Settings = ? WHERE Id = ?"; + updateCmd.CommandText = "UPDATE \"Indexers\" SET \"Settings\" = ? WHERE \"Id\" = ?"; updateCmd.AddParameter(settings); updateCmd.AddParameter(id); updateCmd.ExecuteNonQuery(); diff --git a/src/NzbDrone.Core/Datastore/Migration/116_disable_nyaa.cs b/src/NzbDrone.Core/Datastore/Migration/116_disable_nyaa.cs index 9dcbe0cb0..84cd7d7bb 100644 --- a/src/NzbDrone.Core/Datastore/Migration/116_disable_nyaa.cs +++ b/src/NzbDrone.Core/Datastore/Migration/116_disable_nyaa.cs @@ -1,4 +1,4 @@ -using FluentMigrator; +using FluentMigrator; using NzbDrone.Core.Datastore.Migration.Framework; namespace NzbDrone.Core.Datastore.Migration @@ -8,7 +8,7 @@ namespace NzbDrone.Core.Datastore.Migration { protected override void MainDbUpgrade() { - Execute.Sql("UPDATE Indexers SET EnableRss = 0, EnableSearch = 0, Settings = Replace(Settings, 'https://nyaa.se', '') WHERE Implementation = 'Nyaa' AND Settings LIKE '%nyaa.se%';"); + Execute.Sql("UPDATE \"Indexers\" SET \"EnableRss\" = false, \"EnableSearch\" = false, \"Settings\" = Replace(\"Settings\", 'https://nyaa.se', '') WHERE \"Implementation\" = 'Nyaa' AND \"Settings\" LIKE '%nyaa.se%';"); } } } diff --git a/src/NzbDrone.Core/Datastore/Migration/117_add_webrip_and_br480_qualites_in_profile.cs b/src/NzbDrone.Core/Datastore/Migration/117_add_webrip_and_br480_qualites_in_profile.cs index b4391928d..edc34c25f 100644 --- a/src/NzbDrone.Core/Datastore/Migration/117_add_webrip_and_br480_qualites_in_profile.cs +++ b/src/NzbDrone.Core/Datastore/Migration/117_add_webrip_and_br480_qualites_in_profile.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Data; using System.Linq; +using Dapper; using FluentMigrator; using Newtonsoft.Json; using NzbDrone.Common.Serializer; @@ -72,21 +73,16 @@ namespace NzbDrone.Core.Datastore.Migration public void Commit() { - foreach (var profile in _changedProfiles) + var profilesToUpdate = _changedProfiles.Select(p => new { - using (var updateProfileCmd = _connection.CreateCommand()) - { - updateProfileCmd.Transaction = _transaction; - updateProfileCmd.CommandText = - "UPDATE Profiles SET Name = ?, Cutoff = ?, Items = ? WHERE Id = ?"; - updateProfileCmd.AddParameter(profile.Name); - updateProfileCmd.AddParameter(profile.Cutoff); - updateProfileCmd.AddParameter(profile.Items.ToJson()); - updateProfileCmd.AddParameter(profile.Id); + Id = p.Id, + Name = p.Name, + Cutoff = p.Cutoff, + Items = p.Items.ToJson() + }); - updateProfileCmd.ExecuteNonQuery(); - } - } + var updateSql = $"UPDATE \"Profiles\" SET \"Name\" = @Name, \"Cutoff\" = @Cutoff, \"Items\" = @Items WHERE \"Id\" = @Id"; + _connection.Execute(updateSql, profilesToUpdate, transaction: _transaction); _changedProfiles.Clear(); } @@ -158,7 +154,7 @@ namespace NzbDrone.Core.Datastore.Migration using (var getProfilesCmd = _connection.CreateCommand()) { getProfilesCmd.Transaction = _transaction; - getProfilesCmd.CommandText = @"SELECT Id, Name, Cutoff, Items FROM Profiles"; + getProfilesCmd.CommandText = "SELECT \"Id\", \"Name\", \"Cutoff\", \"Items\" FROM \"Profiles\""; using (var profileReader = getProfilesCmd.ExecuteReader()) { diff --git a/src/NzbDrone.Core/Datastore/Migration/119_separate_automatic_and_interactive_searches.cs b/src/NzbDrone.Core/Datastore/Migration/119_separate_automatic_and_interactive_searches.cs index eb22cde57..0655d2224 100644 --- a/src/NzbDrone.Core/Datastore/Migration/119_separate_automatic_and_interactive_searches.cs +++ b/src/NzbDrone.Core/Datastore/Migration/119_separate_automatic_and_interactive_searches.cs @@ -11,7 +11,7 @@ namespace NzbDrone.Core.Datastore.Migration Rename.Column("EnableSearch").OnTable("Indexers").To("EnableAutomaticSearch"); Alter.Table("Indexers").AddColumn("EnableInteractiveSearch").AsBoolean().Nullable(); - Execute.Sql("UPDATE Indexers SET EnableInteractiveSearch = EnableAutomaticSearch"); + Execute.Sql("UPDATE \"Indexers\" SET \"EnableInteractiveSearch\" = \"EnableAutomaticSearch\""); Alter.Table("Indexers").AlterColumn("EnableInteractiveSearch").AsBoolean().NotNullable(); } diff --git a/src/NzbDrone.Core/Datastore/Migration/121_update_animetosho_url.cs b/src/NzbDrone.Core/Datastore/Migration/121_update_animetosho_url.cs index da74b46ab..d08d8187c 100644 --- a/src/NzbDrone.Core/Datastore/Migration/121_update_animetosho_url.cs +++ b/src/NzbDrone.Core/Datastore/Migration/121_update_animetosho_url.cs @@ -9,7 +9,7 @@ namespace NzbDrone.Core.Datastore.Migration { protected override void MainDbUpgrade() { - Execute.Sql("UPDATE Indexers SET Settings = Replace(Replace(Settings, '//animetosho.org', '//feed.animetosho.org'), '/feed/nabapi', '/nabapi') WHERE (Implementation = 'Newznab' OR Implementation = 'Torznab') AND Settings LIKE '%animetosho%';"); + Execute.Sql("UPDATE \"Indexers\" SET \"Settings\" = Replace(Replace(\"Settings\", '//animetosho.org', '//feed.animetosho.org'), '/feed/nabapi', '/nabapi') WHERE (\"Implementation\" = 'Newznab' OR \"Implementation\" = 'Torznab') AND \"Settings\" LIKE '%animetosho%';"); } } diff --git a/src/NzbDrone.Core/Datastore/Migration/122_add_remux_qualities_in_profile.cs b/src/NzbDrone.Core/Datastore/Migration/122_add_remux_qualities_in_profile.cs index db8bf89bd..29d6ae019 100644 --- a/src/NzbDrone.Core/Datastore/Migration/122_add_remux_qualities_in_profile.cs +++ b/src/NzbDrone.Core/Datastore/Migration/122_add_remux_qualities_in_profile.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Data; using System.Linq; +using Dapper; using FluentMigrator; using Newtonsoft.Json; using NzbDrone.Common.Serializer; @@ -68,20 +69,16 @@ namespace NzbDrone.Core.Datastore.Migration public void Commit() { - foreach (var profile in _changedProfiles) + var profilesToUpdate = _changedProfiles.Select(p => new { - using (var updateProfileCmd = _connection.CreateCommand()) - { - updateProfileCmd.Transaction = _transaction; - updateProfileCmd.CommandText = "UPDATE Profiles SET Name = ?, Cutoff = ?, Items = ? WHERE Id = ?"; - updateProfileCmd.AddParameter(profile.Name); - updateProfileCmd.AddParameter(profile.Cutoff); - updateProfileCmd.AddParameter(profile.Items.ToJson()); - updateProfileCmd.AddParameter(profile.Id); + Id = p.Id, + Name = p.Name, + Cutoff = p.Cutoff, + Items = p.Items.ToJson() + }); - updateProfileCmd.ExecuteNonQuery(); - } - } + var updateSql = $"UPDATE \"Profiles\" SET \"Name\" = @Name, \"Cutoff\" = @Cutoff, \"Items\" = @Items WHERE \"Id\" = @Id"; + _connection.Execute(updateSql, profilesToUpdate, transaction: _transaction); _changedProfiles.Clear(); } @@ -117,7 +114,7 @@ namespace NzbDrone.Core.Datastore.Migration using (var getProfilesCmd = _connection.CreateCommand()) { getProfilesCmd.Transaction = _transaction; - getProfilesCmd.CommandText = @"SELECT Id, Name, Cutoff, Items FROM Profiles"; + getProfilesCmd.CommandText = "SELECT \"Id\", \"Name\", \"Cutoff\", \"Items\" FROM \"Profiles\""; using (var profileReader = getProfilesCmd.ExecuteReader()) { diff --git a/src/NzbDrone.Core/Datastore/Migration/128_rename_quality_profiles_add_upgrade_allowed.cs b/src/NzbDrone.Core/Datastore/Migration/128_rename_quality_profiles_add_upgrade_allowed.cs index 91739863b..8fef1944a 100644 --- a/src/NzbDrone.Core/Datastore/Migration/128_rename_quality_profiles_add_upgrade_allowed.cs +++ b/src/NzbDrone.Core/Datastore/Migration/128_rename_quality_profiles_add_upgrade_allowed.cs @@ -10,8 +10,8 @@ namespace NzbDrone.Core.Datastore.Migration { Rename.Table("Profiles").To("QualityProfiles"); - Alter.Table("QualityProfiles").AddColumn("UpgradeAllowed").AsInt32().Nullable(); - Alter.Table("LanguageProfiles").AddColumn("UpgradeAllowed").AsInt32().Nullable(); + Alter.Table("QualityProfiles").AddColumn("UpgradeAllowed").AsBoolean().Nullable(); + Alter.Table("LanguageProfiles").AddColumn("UpgradeAllowed").AsBoolean().Nullable(); // Set upgrade allowed for existing profiles (default will be false for new profiles) Update.Table("QualityProfiles").Set(new { UpgradeAllowed = true }).AllRows(); diff --git a/src/NzbDrone.Core/Datastore/Migration/131_download_propers_config.cs b/src/NzbDrone.Core/Datastore/Migration/131_download_propers_config.cs index bda215ac6..5db3adb7e 100644 --- a/src/NzbDrone.Core/Datastore/Migration/131_download_propers_config.cs +++ b/src/NzbDrone.Core/Datastore/Migration/131_download_propers_config.cs @@ -10,7 +10,7 @@ namespace NzbDrone.Core.Datastore.Migration protected override void MainDbUpgrade() { Execute.WithConnection(SetConfigValue); - Execute.Sql("DELETE FROM Config WHERE Key = 'autodownloadpropers'"); + Execute.Sql("DELETE FROM \"Config\" WHERE \"Key\" = 'autodownloadpropers'"); } private void SetConfigValue(IDbConnection conn, IDbTransaction tran) @@ -18,7 +18,7 @@ namespace NzbDrone.Core.Datastore.Migration using (var cmd = conn.CreateCommand()) { cmd.Transaction = tran; - cmd.CommandText = "SELECT Value FROM Config WHERE Key = 'autodownloadpropers'"; + cmd.CommandText = "SELECT \"Value\" FROM \"Config\" WHERE \"Key\" = 'autodownloadpropers'"; using (var reader = cmd.ExecuteReader()) { @@ -30,7 +30,7 @@ namespace NzbDrone.Core.Datastore.Migration using (var updateCmd = conn.CreateCommand()) { updateCmd.Transaction = tran; - updateCmd.CommandText = "INSERT INTO Config (key, value) VALUES ('downloadpropersandrepacks', ?)"; + updateCmd.CommandText = "INSERT INTO \"Config\" (\"key\", \"value\") VALUES ('downloadpropersandrepacks', ?)"; updateCmd.AddParameter(newValue); updateCmd.ExecuteNonQuery(); diff --git a/src/NzbDrone.Core/Datastore/Migration/132_add_download_client_priority.cs b/src/NzbDrone.Core/Datastore/Migration/132_add_download_client_priority.cs index f70cbc89d..470bb8834 100644 --- a/src/NzbDrone.Core/Datastore/Migration/132_add_download_client_priority.cs +++ b/src/NzbDrone.Core/Datastore/Migration/132_add_download_client_priority.cs @@ -1,5 +1,7 @@ using System.Collections.Generic; using System.Data; +using System.Linq; +using Dapper; using FluentMigrator; using NzbDrone.Core.Datastore.Migration.Framework; @@ -22,34 +24,43 @@ namespace NzbDrone.Core.Datastore.Migration private void InitPriorityForBackwardCompatibility(IDbConnection conn, IDbTransaction tran) { - using (var cmd = conn.CreateCommand()) + var downloadClients = conn.Query($"SELECT \"Id\", \"Implementation\" FROM \"DownloadClients\" WHERE \"Enable\""); + + if (!downloadClients.Any()) { - cmd.Transaction = tran; - cmd.CommandText = "SELECT Id, Implementation FROM DownloadClients WHERE Enable = 1"; + return; + } - using (var reader = cmd.ExecuteReader()) + var nextUsenet = 1; + var nextTorrent = 1; + + foreach (var downloadClient in downloadClients) + { + var isUsenet = _usenetImplementations.Contains(downloadClient.Implementation); + using (var updateCmd = conn.CreateCommand()) { - var nextUsenet = 1; - var nextTorrent = 1; - while (reader.Read()) + updateCmd.Transaction = tran; + if (conn.GetType().FullName == "Npgsql.NpgsqlConnection") { - var id = reader.GetInt32(0); - var implName = reader.GetString(1); - - var isUsenet = _usenetImplementations.Contains(implName); - - using (var updateCmd = conn.CreateCommand()) - { - updateCmd.Transaction = tran; - updateCmd.CommandText = "UPDATE DownloadClients SET Priority = ? WHERE Id = ?"; - updateCmd.AddParameter(isUsenet ? nextUsenet++ : nextTorrent++); - updateCmd.AddParameter(id); - - updateCmd.ExecuteNonQuery(); - } + updateCmd.CommandText = "UPDATE \"DownloadClients\" SET \"Priority\" = $1 WHERE \"Id\" = $2"; } + else + { + updateCmd.CommandText = "UPDATE \"DownloadClients\" SET \"Priority\" = ? WHERE \"Id\" = ?"; + } + + updateCmd.AddParameter(isUsenet ? nextUsenet++ : nextTorrent++); + updateCmd.AddParameter(downloadClient.Id); + + updateCmd.ExecuteNonQuery(); } } } } + + public class DownloadClients036 + { + public int Id { get; set; } + public string Implementation { get; set; } + } } diff --git a/src/NzbDrone.Core/Datastore/Migration/134_add_specials_folder_format.cs b/src/NzbDrone.Core/Datastore/Migration/134_add_specials_folder_format.cs index c0ecab3fc..36d105344 100644 --- a/src/NzbDrone.Core/Datastore/Migration/134_add_specials_folder_format.cs +++ b/src/NzbDrone.Core/Datastore/Migration/134_add_specials_folder_format.cs @@ -1,4 +1,3 @@ -using System.Data; using FluentMigrator; using NzbDrone.Core.Datastore.Migration.Framework; @@ -10,20 +9,8 @@ namespace NzbDrone.Core.Datastore.Migration protected override void MainDbUpgrade() { Alter.Table("NamingConfig").AddColumn("SpecialsFolderFormat").AsString().Nullable(); - Execute.WithConnection(ConvertConfig); - } - private void ConvertConfig(IDbConnection conn, IDbTransaction tran) - { - var defaultFormat = "Specials"; - - using (var updateCmd = conn.CreateCommand()) - { - updateCmd.Transaction = tran; - updateCmd.CommandText = "UPDATE NamingConfig SET SpecialsFolderFormat = ?"; - updateCmd.AddParameter(defaultFormat); - updateCmd.ExecuteNonQuery(); - } + Update.Table("NamingConfig").Set(new { SpecialsFolderFormat = "Specials" }).AllRows(); } } } diff --git a/src/NzbDrone.Core/Datastore/Migration/135_health_issue_notification.cs b/src/NzbDrone.Core/Datastore/Migration/135_health_issue_notification.cs index 2bd945dd7..c59112038 100644 --- a/src/NzbDrone.Core/Datastore/Migration/135_health_issue_notification.cs +++ b/src/NzbDrone.Core/Datastore/Migration/135_health_issue_notification.cs @@ -1,4 +1,4 @@ -using FluentMigrator; +using FluentMigrator; using NzbDrone.Core.Datastore.Migration.Framework; namespace NzbDrone.Core.Datastore.Migration @@ -8,8 +8,8 @@ namespace NzbDrone.Core.Datastore.Migration { protected override void MainDbUpgrade() { - Alter.Table("Notifications").AddColumn("OnHealthIssue").AsBoolean().WithDefaultValue(0); - Alter.Table("Notifications").AddColumn("IncludeHealthWarnings").AsBoolean().WithDefaultValue(0); + Alter.Table("Notifications").AddColumn("OnHealthIssue").AsBoolean().WithDefaultValue(false); + Alter.Table("Notifications").AddColumn("IncludeHealthWarnings").AsBoolean().WithDefaultValue(false); } } } diff --git a/src/NzbDrone.Core/Datastore/Migration/138_remove_bitmetv.cs b/src/NzbDrone.Core/Datastore/Migration/138_remove_bitmetv.cs index 455084c8b..1feeca5a5 100644 --- a/src/NzbDrone.Core/Datastore/Migration/138_remove_bitmetv.cs +++ b/src/NzbDrone.Core/Datastore/Migration/138_remove_bitmetv.cs @@ -1,4 +1,4 @@ -using FluentMigrator; +using FluentMigrator; using NzbDrone.Core.Datastore.Migration.Framework; namespace NzbDrone.Core.Datastore.Migration @@ -8,10 +8,10 @@ namespace NzbDrone.Core.Datastore.Migration { protected override void MainDbUpgrade() { - Execute.Sql("DELETE FROM Indexers WHERE Implementation = 'BitMeTv'"); + Delete.FromTable("Indexers").Row(new { Implementation = "BitMeTv" }); // Also disable usenet-crawler for the poor guys that still have it enabled - Execute.Sql("UPDATE Indexers SET EnableRss = 0, EnableAutomaticSearch = 0, EnableInteractiveSearch = 0 WHERE Implementation = 'Newznab' AND Settings LIKE '%usenet-crawler.com%'"); + Execute.Sql("UPDATE \"Indexers\" SET \"EnableRss\" = false, \"EnableAutomaticSearch\" = false, \"EnableInteractiveSearch\" = false WHERE \"Implementation\" = 'Newznab' AND \"Settings\" LIKE '%usenet-crawler.com%'"); } } } diff --git a/src/NzbDrone.Core/Datastore/Migration/139_add_download_history.cs b/src/NzbDrone.Core/Datastore/Migration/139_add_download_history.cs index b1e039153..d4e5954b6 100644 --- a/src/NzbDrone.Core/Datastore/Migration/139_add_download_history.cs +++ b/src/NzbDrone.Core/Datastore/Migration/139_add_download_history.cs @@ -28,7 +28,7 @@ namespace NzbDrone.Core.Datastore.Migration Create.Index().OnTable("DownloadHistory").OnColumn("SeriesId"); Create.Index().OnTable("DownloadHistory").OnColumn("DownloadId"); - Execute.WithConnection(InitialImportedDownloadHistory); + IfDatabase("sqlite").Execute.WithConnection(InitialImportedDownloadHistory); } private static readonly Dictionary EventTypeMap = new Dictionary() diff --git a/src/NzbDrone.Core/Datastore/Migration/140_remove_chown_and_folderchmod_config.cs b/src/NzbDrone.Core/Datastore/Migration/140_remove_chown_and_folderchmod_config.cs index 25719286d..e1175bb4d 100644 --- a/src/NzbDrone.Core/Datastore/Migration/140_remove_chown_and_folderchmod_config.cs +++ b/src/NzbDrone.Core/Datastore/Migration/140_remove_chown_and_folderchmod_config.cs @@ -8,7 +8,7 @@ namespace NzbDrone.Core.Datastore.Migration { protected override void MainDbUpgrade() { - Execute.Sql("DELETE FROM config WHERE Key IN ('folderchmod', 'chownuser')"); + Execute.Sql("DELETE FROM \"Config\" WHERE \"Key\" IN ('folderchmod', 'chownuser')"); // Note: v1 version of migration removed 'chowngroup' } diff --git a/src/NzbDrone.Core/Datastore/Migration/146_cleanup_duplicates_updatehistory.cs b/src/NzbDrone.Core/Datastore/Migration/146_cleanup_duplicates_updatehistory.cs index 7a7d8feb4..8ee414a8d 100644 --- a/src/NzbDrone.Core/Datastore/Migration/146_cleanup_duplicates_updatehistory.cs +++ b/src/NzbDrone.Core/Datastore/Migration/146_cleanup_duplicates_updatehistory.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Data; using System.Linq; using FluentMigrator; @@ -22,7 +22,7 @@ namespace NzbDrone.Core.Datastore.Migration using (var cmdQuery = conn.CreateCommand()) { cmdQuery.Transaction = tran; - cmdQuery.CommandText = "SELECT Id, Version FROM UpdateHistory WHERE EventType = 2 ORDER BY Date"; + cmdQuery.CommandText = "SELECT \"Id\", \"Version\" FROM \"UpdateHistory\" WHERE \"EventType\" = 2 ORDER BY \"Date\""; var lastVersion = string.Empty; using (var reader = cmdQuery.ExecuteReader()) @@ -49,7 +49,7 @@ namespace NzbDrone.Core.Datastore.Migration var ids = toDelete.Select(v => v.ToString()).Join(", "); cmdDelete.Transaction = tran; - cmdDelete.CommandText = $"DELETE FROM UpdateHistory WHERE Id IN ({ids})"; + cmdDelete.CommandText = $"DELETE FROM \"UpdateHistory\" WHERE \"Id\" IN ({ids})"; cmdDelete.ExecuteNonQuery(); } diff --git a/src/NzbDrone.Core/Datastore/Migration/147_swap_filechmod_for_folderchmod.cs b/src/NzbDrone.Core/Datastore/Migration/147_swap_filechmod_for_folderchmod.cs index ab5f0e9d3..589b9edbb 100644 --- a/src/NzbDrone.Core/Datastore/Migration/147_swap_filechmod_for_folderchmod.cs +++ b/src/NzbDrone.Core/Datastore/Migration/147_swap_filechmod_for_folderchmod.cs @@ -12,7 +12,7 @@ namespace NzbDrone.Core.Datastore.Migration protected override void MainDbUpgrade() { // Reverts part of migration 140, note that the v1 of migration140 also removed chowngroup - Execute.WithConnection(ConvertFileChmodToFolderChmod); + IfDatabase("sqlite").Execute.WithConnection(ConvertFileChmodToFolderChmod); } private void ConvertFileChmodToFolderChmod(IDbConnection conn, IDbTransaction tran) @@ -20,7 +20,7 @@ namespace NzbDrone.Core.Datastore.Migration using (var getFileChmodCmd = conn.CreateCommand()) { getFileChmodCmd.Transaction = tran; - getFileChmodCmd.CommandText = @"SELECT Value FROM Config WHERE Key = 'filechmod'"; + getFileChmodCmd.CommandText = "SELECT \"Value\" FROM \"Config\" WHERE \"Key\" = 'filechmod'"; if (getFileChmodCmd.ExecuteScalar() is string fileChmod) { @@ -34,7 +34,7 @@ namespace NzbDrone.Core.Datastore.Migration using (var insertCmd = conn.CreateCommand()) { insertCmd.Transaction = tran; - insertCmd.CommandText = "INSERT INTO Config (Key, Value) VALUES ('chmodfolder', ?)"; + insertCmd.CommandText = "INSERT INTO \"Config\" (\"Key\", \"Value\") VALUES ('chmodfolder', ?)"; insertCmd.AddParameter(folderChmod); insertCmd.ExecuteNonQuery(); @@ -44,7 +44,7 @@ namespace NzbDrone.Core.Datastore.Migration using (var deleteCmd = conn.CreateCommand()) { deleteCmd.Transaction = tran; - deleteCmd.CommandText = "DELETE FROM Config WHERE Key = 'filechmod'"; + deleteCmd.CommandText = "DELETE FROM \"Config\" WHERE \"Key\" = 'filechmod'"; deleteCmd.ExecuteNonQuery(); } diff --git a/src/NzbDrone.Core/Datastore/Migration/148_mediainfo_channels.cs b/src/NzbDrone.Core/Datastore/Migration/148_mediainfo_channels.cs index 4a34f5c18..6ff98f263 100644 --- a/src/NzbDrone.Core/Datastore/Migration/148_mediainfo_channels.cs +++ b/src/NzbDrone.Core/Datastore/Migration/148_mediainfo_channels.cs @@ -8,8 +8,8 @@ namespace NzbDrone.Core.Datastore.Migration { protected override void MainDbUpgrade() { - Execute.Sql("UPDATE EpisodeFiles SET MediaInfo = Replace(MediaInfo, '\"audioChannels\"', '\"audioChannelsContainer\"');"); - Execute.Sql("UPDATE EpisodeFiles SET MediaInfo = Replace(MediaInfo, '\"audioChannelPositionsText\"', '\"audioChannelPositionsTextContainer\"');"); + Execute.Sql("UPDATE \"EpisodeFiles\" SET \"MediaInfo\" = Replace(\"MediaInfo\", '\"audioChannels\"', '\"audioChannelsContainer\"');"); + Execute.Sql("UPDATE \"EpisodeFiles\" SET \"MediaInfo\" = Replace(\"MediaInfo\", '\"audioChannelPositionsText\"', '\"audioChannelPositionsTextContainer\"');"); } } } diff --git a/src/NzbDrone.Core/Datastore/Migration/149_add_on_delete_to_notifications.cs b/src/NzbDrone.Core/Datastore/Migration/149_add_on_delete_to_notifications.cs index 70906256f..66386ab6b 100644 --- a/src/NzbDrone.Core/Datastore/Migration/149_add_on_delete_to_notifications.cs +++ b/src/NzbDrone.Core/Datastore/Migration/149_add_on_delete_to_notifications.cs @@ -1,4 +1,4 @@ -using FluentMigrator; +using FluentMigrator; using NzbDrone.Core.Datastore.Migration.Framework; namespace NzbDrone.Core.Datastore.Migration @@ -8,8 +8,8 @@ namespace NzbDrone.Core.Datastore.Migration { protected override void MainDbUpgrade() { - Alter.Table("Notifications").AddColumn("OnSeriesDelete").AsBoolean().WithDefaultValue(0); - Alter.Table("Notifications").AddColumn("OnEpisodeFileDelete").AsBoolean().WithDefaultValue(0); + Alter.Table("Notifications").AddColumn("OnSeriesDelete").AsBoolean().WithDefaultValue(false); + Alter.Table("Notifications").AddColumn("OnEpisodeFileDelete").AsBoolean().WithDefaultValue(false); } } } diff --git a/src/NzbDrone.Core/Datastore/Migration/152_update_btn_url_to_https.cs b/src/NzbDrone.Core/Datastore/Migration/152_update_btn_url_to_https.cs index 9aba312fc..3997fc5b3 100644 --- a/src/NzbDrone.Core/Datastore/Migration/152_update_btn_url_to_https.cs +++ b/src/NzbDrone.Core/Datastore/Migration/152_update_btn_url_to_https.cs @@ -8,7 +8,7 @@ namespace NzbDrone.Core.Datastore.Migration { protected override void MainDbUpgrade() { - Execute.Sql("UPDATE Indexers SET Settings = Replace(Settings, 'http://api.broadcasthe.net', 'https://api.broadcasthe.net') WHERE Implementation = 'BroadcastheNet';"); + Execute.Sql("UPDATE \"Indexers\" SET \"Settings\" = Replace(\"Settings\", 'http://api.broadcasthe.net', 'https://api.broadcasthe.net') WHERE \"Implementation\" = 'BroadcastheNet';"); } } } diff --git a/src/NzbDrone.Core/Datastore/Migration/153_add_on_episodefiledelete_for_upgrade.cs b/src/NzbDrone.Core/Datastore/Migration/153_add_on_episodefiledelete_for_upgrade.cs index e7463e5e2..08d833072 100644 --- a/src/NzbDrone.Core/Datastore/Migration/153_add_on_episodefiledelete_for_upgrade.cs +++ b/src/NzbDrone.Core/Datastore/Migration/153_add_on_episodefiledelete_for_upgrade.cs @@ -1,4 +1,4 @@ -using FluentMigrator; +using FluentMigrator; using NzbDrone.Core.Datastore.Migration.Framework; namespace NzbDrone.Core.Datastore.Migration @@ -8,7 +8,7 @@ namespace NzbDrone.Core.Datastore.Migration { protected override void MainDbUpgrade() { - Alter.Table("Notifications").AddColumn("OnEpisodeFileDeleteForUpgrade").AsBoolean().WithDefaultValue(1); + Alter.Table("Notifications").AddColumn("OnEpisodeFileDeleteForUpgrade").AsBoolean().WithDefaultValue(true); } } } diff --git a/src/NzbDrone.Core/Datastore/Migration/155_add_arabic_and_hindi_languages.cs b/src/NzbDrone.Core/Datastore/Migration/155_add_arabic_and_hindi_languages.cs index 581c01eeb..45c274451 100644 --- a/src/NzbDrone.Core/Datastore/Migration/155_add_arabic_and_hindi_languages.cs +++ b/src/NzbDrone.Core/Datastore/Migration/155_add_arabic_and_hindi_languages.cs @@ -63,7 +63,7 @@ namespace NzbDrone.Core.Datastore.Migration using (var updateProfileCmd = _connection.CreateCommand()) { updateProfileCmd.Transaction = _transaction; - updateProfileCmd.CommandText = "UPDATE LanguageProfiles SET Languages = ? WHERE Id = ?"; + updateProfileCmd.CommandText = "UPDATE \"LanguageProfiles\" SET \"Languages\" = ? WHERE \"Id\" = ?"; updateProfileCmd.AddParameter(profile.Languages.ToJson()); updateProfileCmd.AddParameter(profile.Id); @@ -100,7 +100,7 @@ namespace NzbDrone.Core.Datastore.Migration using (var getProfilesCmd = _connection.CreateCommand()) { getProfilesCmd.Transaction = _transaction; - getProfilesCmd.CommandText = @"SELECT Id, Name, Languages, UpgradeAllowed, Cutoff FROM LanguageProfiles"; + getProfilesCmd.CommandText = "SELECT \"Id\", \"Name\", \"Languages\", \"UpgradeAllowed\", \"Cutoff\" FROM \"LanguageProfiles\""; using (var profileReader = getProfilesCmd.ExecuteReader()) { diff --git a/src/NzbDrone.Core/Datastore/Migration/156_add_bypass_to_delay_profile.cs b/src/NzbDrone.Core/Datastore/Migration/156_add_bypass_to_delay_profile.cs index 4004f3b9c..6b32b2c03 100644 --- a/src/NzbDrone.Core/Datastore/Migration/156_add_bypass_to_delay_profile.cs +++ b/src/NzbDrone.Core/Datastore/Migration/156_add_bypass_to_delay_profile.cs @@ -11,7 +11,7 @@ namespace NzbDrone.Core.Datastore.Migration Alter.Table("DelayProfiles").AddColumn("BypassIfHighestQuality").AsBoolean().WithDefaultValue(false); // Set to true for existing Delay Profiles to keep behavior the same. - Execute.Sql("UPDATE DelayProfiles SET BypassIfHighestQuality = 1;"); + Update.Table("DelayProfiles").Set(new { BypassIfHighestQuality = true }).AllRows(); } } } diff --git a/src/NzbDrone.Core/Datastore/Migration/157_email_multiple_addresses.cs b/src/NzbDrone.Core/Datastore/Migration/157_email_multiple_addresses.cs index 1001ccbd3..1a127f269 100644 --- a/src/NzbDrone.Core/Datastore/Migration/157_email_multiple_addresses.cs +++ b/src/NzbDrone.Core/Datastore/Migration/157_email_multiple_addresses.cs @@ -1,5 +1,7 @@ +using System.Collections.Generic; using System.Data; using System.Linq; +using Dapper; using FluentMigrator; using Newtonsoft.Json.Linq; using NzbDrone.Common.Serializer; @@ -17,10 +19,11 @@ namespace NzbDrone.Core.Datastore.Migration private void ChangeEmailAddressType(IDbConnection conn, IDbTransaction tran) { + var updatedEmails = new List(); using (var getEmailCmd = conn.CreateCommand()) { getEmailCmd.Transaction = tran; - getEmailCmd.CommandText = "SELECT Id, Settings FROM Notifications WHERE Implementation = 'Email'"; + getEmailCmd.CommandText = "SELECT \"Id\", \"Settings\" FROM \"Notifications\" WHERE \"Implementation\" = 'Email'"; using (var reader = getEmailCmd.ExecuteReader()) { @@ -32,18 +35,17 @@ namespace NzbDrone.Core.Datastore.Migration // "To" was changed from string to array settings["to"] = new JArray(settings["to"].ToObject().Split(',').Select(v => v.Trim()).ToArray()); - using (var updateCmd = conn.CreateCommand()) + updatedEmails.Add(new { - updateCmd.Transaction = tran; - updateCmd.CommandText = "UPDATE Notifications SET Settings = ? WHERE Id = ?"; - updateCmd.AddParameter(settings.ToJson()); - updateCmd.AddParameter(id); - - updateCmd.ExecuteNonQuery(); - } + Settings = settings.ToJson(), + Id = id + }); } } } + + var updateSql = $"UPDATE \"Notifications\" SET \"Settings\" = @Settings WHERE \"Id\" = @Id"; + conn.Execute(updateSql, updatedEmails, transaction: tran); } } } diff --git a/src/NzbDrone.Core/Datastore/Migration/158_cdh_per_downloadclient.cs b/src/NzbDrone.Core/Datastore/Migration/158_cdh_per_downloadclient.cs index bb1209bfa..b88345e36 100644 --- a/src/NzbDrone.Core/Datastore/Migration/158_cdh_per_downloadclient.cs +++ b/src/NzbDrone.Core/Datastore/Migration/158_cdh_per_downloadclient.cs @@ -1,4 +1,5 @@ using System.Data; +using Dapper; using FluentMigrator; using NzbDrone.Core.Datastore.Migration.Framework; @@ -21,7 +22,7 @@ namespace NzbDrone.Core.Datastore.Migration var removeCompletedDownloads = false; var removeFailedDownloads = true; - using (var removeCompletedDownloadsCmd = conn.CreateCommand(tran, "SELECT Value FROM Config WHERE Key = 'removecompleteddownloads'")) + using (var removeCompletedDownloadsCmd = conn.CreateCommand(tran, "SELECT \"Value\" FROM \"Config\" WHERE \"Key\" = 'removecompleteddownloads'")) { if ((removeCompletedDownloadsCmd.ExecuteScalar() as string)?.ToLower() == "true") { @@ -29,7 +30,7 @@ namespace NzbDrone.Core.Datastore.Migration } } - using (var removeFailedDownloadsCmd = conn.CreateCommand(tran, "SELECT Value FROM Config WHERE Key = 'removefaileddownloads'")) + using (var removeFailedDownloadsCmd = conn.CreateCommand(tran, "SELECT \"Value\" FROM \"Config\" WHERE \"Key\" = 'removefaileddownloads'")) { if ((removeFailedDownloadsCmd.ExecuteScalar() as string)?.ToLower() == "false") { @@ -37,17 +38,11 @@ namespace NzbDrone.Core.Datastore.Migration } } - using (var updateClientCmd = conn.CreateCommand(tran, $"UPDATE DownloadClients SET RemoveCompletedDownloads = (CASE WHEN Implementation IN (\"RTorrent\", \"Flood\") THEN 0 ELSE ? END), RemoveFailedDownloads = ?")) - { - updateClientCmd.AddParameter(removeCompletedDownloads ? 1 : 0); - updateClientCmd.AddParameter(removeFailedDownloads ? 1 : 0); - updateClientCmd.ExecuteNonQuery(); - } + var parameters = new { RemoveFailedDownloads = removeFailedDownloads, RemoveCompletedDownloads = removeCompletedDownloads }; + var updateSql = $"UPDATE \"DownloadClients\" SET \"RemoveCompletedDownloads\" = (CASE WHEN \"Implementation\" IN ('RTorrent', 'Flood') THEN 'false' ELSE @RemoveCompletedDownloads END), \"RemoveFailedDownloads\" = @RemoveFailedDownloads"; + conn.Execute(updateSql, parameters, transaction: tran); - using (var removeConfigCmd = conn.CreateCommand(tran, $"DELETE FROM Config WHERE Key IN ('removecompleteddownloads', 'removefaileddownloads')")) - { - removeConfigCmd.ExecuteNonQuery(); - } + conn.Execute("DELETE FROM \"Config\" WHERE \"Key\" IN ('removecompleteddownloads', 'removefaileddownloads')"); } } } diff --git a/src/NzbDrone.Core/Datastore/Migration/161_remove_plex_hometheater.cs b/src/NzbDrone.Core/Datastore/Migration/161_remove_plex_hometheater.cs index 49161c511..afd9b8472 100644 --- a/src/NzbDrone.Core/Datastore/Migration/161_remove_plex_hometheater.cs +++ b/src/NzbDrone.Core/Datastore/Migration/161_remove_plex_hometheater.cs @@ -23,7 +23,7 @@ namespace NzbDrone.Core.Datastore.Migration { SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter()); SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter()); - var rows = conn.Query("SELECT Id, ParsedEpisodeInfo from PendingReleases"); + var rows = conn.Query("SELECT \"Id\", \"ParsedEpisodeInfo\" from \"PendingReleases\""); var newRows = new List(); @@ -69,7 +69,7 @@ namespace NzbDrone.Core.Datastore.Migration }); } - var sql = $"UPDATE PendingReleases SET ParsedEpisodeInfo = @ParsedEpisodeInfo WHERE Id = @Id"; + var sql = $"UPDATE \"PendingReleases\" SET \"ParsedEpisodeInfo\" = @ParsedEpisodeInfo WHERE \"Id\" = @Id"; conn.Execute(sql, newRows, transaction: tran); } diff --git a/src/NzbDrone.Core/Datastore/Migration/162_release_profile_to_array.cs b/src/NzbDrone.Core/Datastore/Migration/162_release_profile_to_array.cs index e88c4c44f..0ef9b5640 100644 --- a/src/NzbDrone.Core/Datastore/Migration/162_release_profile_to_array.cs +++ b/src/NzbDrone.Core/Datastore/Migration/162_release_profile_to_array.cs @@ -20,7 +20,7 @@ namespace NzbDrone.Core.Datastore.Migration using (var getEmailCmd = conn.CreateCommand()) { getEmailCmd.Transaction = tran; - getEmailCmd.CommandText = "SELECT Id, Required, Ignored FROM ReleaseProfiles"; + getEmailCmd.CommandText = "SELECT \"Id\", \"Required\", \"Ignored\" FROM \"ReleaseProfiles\""; using (var reader = getEmailCmd.ExecuteReader()) { @@ -41,7 +41,7 @@ namespace NzbDrone.Core.Datastore.Migration using (var updateCmd = conn.CreateCommand()) { updateCmd.Transaction = tran; - updateCmd.CommandText = "UPDATE ReleaseProfiles SET Required = ?, Ignored = ? WHERE Id = ?"; + updateCmd.CommandText = "UPDATE \"ReleaseProfiles\" SET \"Required\" = ?, \"Ignored\" = ? WHERE \"Id\" = ?"; updateCmd.AddParameter(required.ToJson()); updateCmd.AddParameter(ignored.ToJson()); updateCmd.AddParameter(id); diff --git a/src/NzbDrone.Core/Datastore/Migration/163_mediainfo_to_ffmpeg.cs b/src/NzbDrone.Core/Datastore/Migration/163_mediainfo_to_ffmpeg.cs index c285fe15a..7d3610b54 100644 --- a/src/NzbDrone.Core/Datastore/Migration/163_mediainfo_to_ffmpeg.cs +++ b/src/NzbDrone.Core/Datastore/Migration/163_mediainfo_to_ffmpeg.cs @@ -47,7 +47,7 @@ namespace NzbDrone.Core.Datastore.Migration private void MigrateToFfprobe(IDbConnection conn, IDbTransaction tran) { - var existing = conn.Query("SELECT Id, MediaInfo, SceneName FROM EpisodeFiles"); + var existing = conn.Query("SELECT \"Id\", \"MediaInfo\", \"SceneName\" FROM \"EpisodeFiles\""); var updated = new List(); @@ -78,7 +78,7 @@ namespace NzbDrone.Core.Datastore.Migration }); } - var updateSql = "UPDATE EpisodeFiles SET MediaInfo = @MediaInfo WHERE Id = @Id"; + var updateSql = "UPDATE \"EpisodeFiles\" SET \"MediaInfo\" = @MediaInfo WHERE \"Id\" = @Id"; conn.Execute(updateSql, updated, transaction: tran); } diff --git a/src/NzbDrone.Core/Datastore/Migration/165_add_on_update_to_notifications.cs b/src/NzbDrone.Core/Datastore/Migration/165_add_on_update_to_notifications.cs index 338e4efc1..789de6673 100644 --- a/src/NzbDrone.Core/Datastore/Migration/165_add_on_update_to_notifications.cs +++ b/src/NzbDrone.Core/Datastore/Migration/165_add_on_update_to_notifications.cs @@ -8,7 +8,7 @@ namespace NzbDrone.Core.Datastore.Migration { protected override void MainDbUpgrade() { - Alter.Table("Notifications").AddColumn("OnApplicationUpdate").AsBoolean().WithDefaultValue(0); + Alter.Table("Notifications").AddColumn("OnApplicationUpdate").AsBoolean().WithDefaultValue(false); } } } diff --git a/src/NzbDrone.Core/Datastore/Migration/166_update_series_sort_title.cs b/src/NzbDrone.Core/Datastore/Migration/166_update_series_sort_title.cs index c455b7c2f..281db2792 100644 --- a/src/NzbDrone.Core/Datastore/Migration/166_update_series_sort_title.cs +++ b/src/NzbDrone.Core/Datastore/Migration/166_update_series_sort_title.cs @@ -18,7 +18,7 @@ namespace NzbDrone.Core.Datastore.Migration using (var getSeriesCmd = conn.CreateCommand()) { getSeriesCmd.Transaction = tran; - getSeriesCmd.CommandText = @"SELECT Id, TvdbId, Title FROM Series"; + getSeriesCmd.CommandText = "SELECT \"Id\", \"TvdbId\", \"Title\" FROM \"Series\""; using (var seriesReader = getSeriesCmd.ExecuteReader()) { while (seriesReader.Read()) @@ -32,7 +32,7 @@ namespace NzbDrone.Core.Datastore.Migration using (var updateCmd = conn.CreateCommand()) { updateCmd.Transaction = tran; - updateCmd.CommandText = "UPDATE Series SET SortTitle = ? WHERE Id = ?"; + updateCmd.CommandText = "UPDATE \"Series\" SET \"SortTitle\" = ? WHERE \"Id\" = ?"; updateCmd.AddParameter(sortTitle); updateCmd.AddParameter(id); diff --git a/src/NzbDrone.Core/Datastore/Migration/169_add_malayalam _and_ukrainian_languages.cs b/src/NzbDrone.Core/Datastore/Migration/169_add_malayalam _and_ukrainian_languages.cs index a578ad743..5ef76b7ef 100644 --- a/src/NzbDrone.Core/Datastore/Migration/169_add_malayalam _and_ukrainian_languages.cs +++ b/src/NzbDrone.Core/Datastore/Migration/169_add_malayalam _and_ukrainian_languages.cs @@ -63,7 +63,7 @@ namespace NzbDrone.Core.Datastore.Migration using (var updateProfileCmd = _connection.CreateCommand()) { updateProfileCmd.Transaction = _transaction; - updateProfileCmd.CommandText = "UPDATE LanguageProfiles SET Languages = ? WHERE Id = ?"; + updateProfileCmd.CommandText = "UPDATE \"LanguageProfiles\" SET \"Languages\" = ? WHERE \"Id\" = ?"; updateProfileCmd.AddParameter(profile.Languages.ToJson()); updateProfileCmd.AddParameter(profile.Id); @@ -100,7 +100,7 @@ namespace NzbDrone.Core.Datastore.Migration using (var getProfilesCmd = _connection.CreateCommand()) { getProfilesCmd.Transaction = _transaction; - getProfilesCmd.CommandText = @"SELECT Id, Name, Languages, UpgradeAllowed, Cutoff FROM LanguageProfiles"; + getProfilesCmd.CommandText = "SELECT \"Id\", \"Name\", \"Languages\", \"UpgradeAllowed\", \"Cutoff\" FROM \"LanguageProfiles\""; using (var profileReader = getProfilesCmd.ExecuteReader()) { diff --git a/src/NzbDrone.Core/Datastore/Migration/171_add_custom_formats.cs b/src/NzbDrone.Core/Datastore/Migration/171_add_custom_formats.cs index 1fe016229..869abbdcf 100644 --- a/src/NzbDrone.Core/Datastore/Migration/171_add_custom_formats.cs +++ b/src/NzbDrone.Core/Datastore/Migration/171_add_custom_formats.cs @@ -36,7 +36,7 @@ namespace NzbDrone.Core.Datastore.Migration Delete.Column("IncludePreferredWhenRenaming").FromTable("ReleaseProfiles"); // Remove Profiles that will no longer validate - Execute.Sql("DELETE FROM ReleaseProfiles WHERE Required == '[]' AND Ignored == '[]'"); + Delete.FromTable("ReleaseProfiles").Row(new { Required = "[]", Ignored = "[]" }); // TODO: Kill any references to Preferred in History and Files // Data.PreferredWordScore @@ -51,7 +51,7 @@ namespace NzbDrone.Core.Datastore.Migration using (var getProfiles = conn.CreateCommand()) { getProfiles.Transaction = tran; - getProfiles.CommandText = @"SELECT Id FROM QualityProfiles"; + getProfiles.CommandText = "SELECT \"Id\" FROM \"QualityProfiles\""; using (var definitionsReader = getProfiles.ExecuteReader()) { @@ -70,7 +70,7 @@ namespace NzbDrone.Core.Datastore.Migration using (var cmd = conn.CreateCommand()) { cmd.Transaction = tran; - cmd.CommandText = "SELECT Preferred, Name, IncludePreferredWhenRenaming, Enabled, Id FROM ReleaseProfiles WHERE Preferred IS NOT NULL"; + cmd.CommandText = "SELECT \"Preferred\", \"Name\", \"IncludePreferredWhenRenaming\", \"Enabled\", \"Id\" FROM \"ReleaseProfiles\" WHERE \"Preferred\" IS NOT NULL"; using (var reader = cmd.ExecuteReader()) { @@ -144,7 +144,7 @@ namespace NzbDrone.Core.Datastore.Migration } // Insert Custom Formats - var updateSql = "INSERT INTO CustomFormats (Name, IncludeCustomFormatWhenRenaming, Specifications) VALUES (@Name, @IncludeCustomFormatWhenRenaming, @Specifications)"; + var updateSql = "INSERT INTO \"CustomFormats\" (\"Name\", \"IncludeCustomFormatWhenRenaming\", \"Specifications\") VALUES (@Name, @IncludeCustomFormatWhenRenaming, @Specifications)"; conn.Execute(updateSql, updatedCollections, transaction: tran); // Pull List of Custom Formats with new Ids @@ -152,7 +152,7 @@ namespace NzbDrone.Core.Datastore.Migration using (var getProfiles = conn.CreateCommand()) { getProfiles.Transaction = tran; - getProfiles.CommandText = @"SELECT Id, Name FROM CustomFormats"; + getProfiles.CommandText = "SELECT \"Id\", \"Name\" FROM \"CustomFormats\""; using (var definitionsReader = getProfiles.ExecuteReader()) { @@ -176,16 +176,19 @@ namespace NzbDrone.Core.Datastore.Migration } // Push profile updates to DB - var updateProfilesSql = "UPDATE QualityProfiles SET FormatItems = @FormatItems WHERE Id = @Id"; + var updateProfilesSql = "UPDATE \"QualityProfiles\" SET \"FormatItems\" = @FormatItems WHERE \"Id\" = @Id"; conn.Execute(updateProfilesSql, qualityProfiles, transaction: tran); } private void MigrateNamingConfigs(IDbConnection conn, IDbTransaction tran) { + var updatedNamingConfigs = new List(); + using (var namingConfigCmd = conn.CreateCommand()) { namingConfigCmd.Transaction = tran; - namingConfigCmd.CommandText = @"SELECT * FROM NamingConfig LIMIT 1"; + namingConfigCmd.CommandText = "SELECT * FROM \"NamingConfig\" LIMIT 1"; + using (var namingConfigReader = namingConfigCmd.ExecuteReader()) { var standardEpisodeFormatIndex = namingConfigReader.GetOrdinal("StandardEpisodeFormat"); @@ -198,23 +201,21 @@ namespace NzbDrone.Core.Datastore.Migration var dailyEpisodeFormat = NameReplace(namingConfigReader.GetString(dailyEpisodeFormatIndex)); var animeEpisodeFormat = NameReplace(namingConfigReader.GetString(animeEpisodeFormatIndex)); - using (var updateCmd = conn.CreateCommand()) + updatedNamingConfigs.Add(new { - var text = string.Format("UPDATE NamingConfig " + - "SET StandardEpisodeFormat = '{0}', " + - "DailyEpisodeFormat = '{1}', " + - "AnimeEpisodeFormat = '{2}'", - standardEpisodeFormat, - dailyEpisodeFormat, - animeEpisodeFormat); - - updateCmd.Transaction = tran; - updateCmd.CommandText = text; - updateCmd.ExecuteNonQuery(); - } + StandardEpisodeFormat = standardEpisodeFormat, + DailyEpisodeFormat = dailyEpisodeFormat, + AnimeEpisodeFormat = animeEpisodeFormat + }); } } } + + var updateNamingSql = "UPDATE \"NamingConfig\" " + + "SET \"StandardEpisodeFormat\" = @StandardEpisodeFormat, " + + "\"DailyEpisodeFormat\" = @DailyEpisodeFormat, " + + "\"AnimeEpisodeFormat\" = @AnimeEpisodeFormat"; + conn.Execute(updateNamingSql, updatedNamingConfigs, transaction: tran); } private string NameReplace(string oldTokenString) diff --git a/src/NzbDrone.Core/Datastore/Migration/173_remove_omg.cs b/src/NzbDrone.Core/Datastore/Migration/173_remove_omg.cs index 89c5747ad..012e480d2 100644 --- a/src/NzbDrone.Core/Datastore/Migration/173_remove_omg.cs +++ b/src/NzbDrone.Core/Datastore/Migration/173_remove_omg.cs @@ -8,7 +8,7 @@ namespace NzbDrone.Core.Datastore.Migration { protected override void MainDbUpgrade() { - Execute.Sql("DELETE FROM Indexers WHERE Implementation = 'Omgwtfnzbs'"); + Execute.Sql("DELETE FROM \"Indexers\" WHERE \"Implementation\" = 'Omgwtfnzbs'"); } } } diff --git a/src/NzbDrone.Core/Datastore/Migration/175_language_profiles_to_custom_formats.cs b/src/NzbDrone.Core/Datastore/Migration/175_language_profiles_to_custom_formats.cs index ccfeff408..94e24a264 100644 --- a/src/NzbDrone.Core/Datastore/Migration/175_language_profiles_to_custom_formats.cs +++ b/src/NzbDrone.Core/Datastore/Migration/175_language_profiles_to_custom_formats.cs @@ -18,9 +18,9 @@ namespace NzbDrone.Core.Datastore.Migration .AddColumn("Languages").AsString().NotNullable().WithDefaultValue("[]"); // Migrate Language to Languages in all tables - Execute.Sql("UPDATE EpisodeFiles SET Languages = '[' || Language || ']'"); - Execute.Sql("UPDATE History SET Languages = '[' || Language || ']'"); - Execute.Sql("UPDATE Blocklist SET Languages = '[' || Language || ']'"); + Execute.Sql("UPDATE \"EpisodeFiles\" SET \"Languages\" = '[' || \"Language\" || ']'"); + Execute.Sql("UPDATE \"History\" SET \"Languages\" = '[' || \"Language\" || ']'"); + Execute.Sql("UPDATE \"Blocklist\" SET \"Languages\" = '[' || \"Language\" || ']'"); // Migrate Language Profiles to CFs diff --git a/src/NzbDrone.Core/Datastore/Migration/181_quality_definition_preferred_size.cs b/src/NzbDrone.Core/Datastore/Migration/181_quality_definition_preferred_size.cs index 4f15d3b5c..006719e5b 100644 --- a/src/NzbDrone.Core/Datastore/Migration/181_quality_definition_preferred_size.cs +++ b/src/NzbDrone.Core/Datastore/Migration/181_quality_definition_preferred_size.cs @@ -10,7 +10,7 @@ namespace NzbDrone.Core.Datastore.Migration { Alter.Table("QualityDefinitions").AddColumn("PreferredSize").AsDouble().Nullable(); - Execute.Sql("UPDATE QualityDefinitions SET PreferredSize = MaxSize - 5 WHERE MaxSize > 5"); + Execute.Sql("UPDATE \"QualityDefinitions\" SET \"PreferredSize\" = \"MaxSize\" - 5 WHERE \"MaxSize\" > 5"); } } } diff --git a/src/NzbDrone.Core/Datastore/Migration/183_update_images_remote_url.cs b/src/NzbDrone.Core/Datastore/Migration/183_update_images_remote_url.cs index e100657e0..6a6a2192c 100644 --- a/src/NzbDrone.Core/Datastore/Migration/183_update_images_remote_url.cs +++ b/src/NzbDrone.Core/Datastore/Migration/183_update_images_remote_url.cs @@ -8,8 +8,8 @@ namespace NzbDrone.Core.Datastore.Migration { protected override void MainDbUpgrade() { - Execute.Sql("UPDATE Episodes SET Images = REPLACE(Images, '\"url\"', '\"remoteUrl\"')"); - Execute.Sql("UPDATE Series SET Images = REPLACE(Images, '\"url\"', '\"remoteUrl\"'), Actors = REPLACE(Actors, '\"url\"', '\"remoteUrl\"'), Seasons = REPLACE(Seasons, '\"url\"', '\"remoteUrl\"')"); + Execute.Sql("UPDATE \"Episodes\" SET \"Images\" = REPLACE(\"Images\", '\"url\"', '\"remoteUrl\"')"); + Execute.Sql("UPDATE \"Series\" SET \"Images\" = REPLACE(\"Images\", '\"url\"', '\"remoteUrl\"'), \"Actors\" = REPLACE(\"Actors\", '\"url\"', '\"remoteUrl\"'), \"Seasons\" = REPLACE(\"Seasons\", '\"url\"', '\"remoteUrl\"')"); } } } diff --git a/src/NzbDrone.Core/Datastore/Migration/184_remove_invalid_roksbox_metadata_images.cs b/src/NzbDrone.Core/Datastore/Migration/184_remove_invalid_roksbox_metadata_images.cs index ccb6d1d9e..41bf34a92 100644 --- a/src/NzbDrone.Core/Datastore/Migration/184_remove_invalid_roksbox_metadata_images.cs +++ b/src/NzbDrone.Core/Datastore/Migration/184_remove_invalid_roksbox_metadata_images.cs @@ -8,7 +8,8 @@ namespace NzbDrone.Core.Datastore.Migration { protected override void MainDbUpgrade() { - Execute.Sql(@"DELETE FROM MetadataFiles WHERE Consumer = 'RoksboxMetadata' AND Type = 5 AND (RelativePath LIKE '%/metadata/%' OR RelativePath LIKE '%\metadata\%')"); + IfDatabase("sqlite").Execute.Sql("DELETE FROM \"MetadataFiles\" WHERE \"Consumer\" = 'RoksboxMetadata' AND \"Type\" = 5 AND (\"RelativePath\" LIKE '%/metadata/%' OR \"RelativePath\" LIKE '%\\metadata\\%')"); + IfDatabase("postgresql").Execute.Sql("DELETE FROM \"MetadataFiles\" WHERE \"Consumer\" = 'RoksboxMetadata' AND \"Type\" = 5 AND (\"RelativePath\" LIKE '%/metadata/%' OR \"RelativePath\" LIKE '%\\\\metadata\\\\%')"); } } } diff --git a/src/NzbDrone.Core/Datastore/Migration/187_add_on_series_add_to_notifications.cs b/src/NzbDrone.Core/Datastore/Migration/187_add_on_series_add_to_notifications.cs index 2cda61506..546ae3886 100644 --- a/src/NzbDrone.Core/Datastore/Migration/187_add_on_series_add_to_notifications.cs +++ b/src/NzbDrone.Core/Datastore/Migration/187_add_on_series_add_to_notifications.cs @@ -8,7 +8,7 @@ namespace NzbDrone.Core.Datastore.Migration { protected override void MainDbUpgrade() { - Alter.Table("Notifications").AddColumn("OnSeriesAdd").AsBoolean().WithDefaultValue(0); + Alter.Table("Notifications").AddColumn("OnSeriesAdd").AsBoolean().WithDefaultValue(false); } } } diff --git a/src/NzbDrone.Core/Datastore/Migration/188_postgres_update_timestamp_columns_to_with_timezone.cs b/src/NzbDrone.Core/Datastore/Migration/188_postgres_update_timestamp_columns_to_with_timezone.cs new file mode 100644 index 000000000..f8a865c4a --- /dev/null +++ b/src/NzbDrone.Core/Datastore/Migration/188_postgres_update_timestamp_columns_to_with_timezone.cs @@ -0,0 +1,55 @@ +using FluentMigrator; +using NzbDrone.Core.Datastore.Migration.Framework; + +namespace NzbDrone.Core.Datastore.Migration +{ + [Migration(188)] + public class postgres_update_timestamp_columns_to_with_timezone : NzbDroneMigrationBase + { + protected override void MainDbUpgrade() + { + Alter.Table("Blocklist").AlterColumn("Date").AsDateTimeOffset().NotNullable(); + Alter.Table("Blocklist").AlterColumn("PublishedDate").AsDateTimeOffset().Nullable(); + Alter.Table("Commands").AlterColumn("QueuedAt").AsDateTimeOffset().NotNullable(); + Alter.Table("Commands").AlterColumn("StartedAt").AsDateTimeOffset().Nullable(); + Alter.Table("Commands").AlterColumn("EndedAt").AsDateTimeOffset().Nullable(); + Alter.Table("DownloadClientStatus").AlterColumn("InitialFailure").AsDateTimeOffset().Nullable(); + Alter.Table("DownloadClientStatus").AlterColumn("MostRecentFailure").AsDateTimeOffset().Nullable(); + Alter.Table("DownloadClientStatus").AlterColumn("DisabledTill").AsDateTimeOffset().Nullable(); + Alter.Table("DownloadHistory").AlterColumn("Date").AsDateTimeOffset().NotNullable(); + Alter.Table("EpisodeFiles").AlterColumn("DateAdded").AsDateTimeOffset().NotNullable(); + Alter.Table("Episodes").AlterColumn("AirDateUtc").AsDateTimeOffset().Nullable(); + Alter.Table("Episodes").AlterColumn("LastSearchTime").AsDateTimeOffset().Nullable(); + Alter.Table("ExtraFiles").AlterColumn("Added").AsDateTimeOffset().NotNullable(); + Alter.Table("ExtraFiles").AlterColumn("LastUpdated").AsDateTimeOffset().NotNullable(); + Alter.Table("History").AlterColumn("Date").AsDateTimeOffset().NotNullable(); + Alter.Table("ImportListStatus").AlterColumn("InitialFailure").AsDateTimeOffset().Nullable(); + Alter.Table("ImportListStatus").AlterColumn("MostRecentFailure").AsDateTimeOffset().Nullable(); + Alter.Table("ImportListStatus").AlterColumn("DisabledTill").AsDateTimeOffset().Nullable(); + Alter.Table("ImportListStatus").AlterColumn("LastInfoSync").AsDateTimeOffset().Nullable(); + Alter.Table("IndexerStatus").AlterColumn("InitialFailure").AsDateTimeOffset().Nullable(); + Alter.Table("IndexerStatus").AlterColumn("MostRecentFailure").AsDateTimeOffset().Nullable(); + Alter.Table("IndexerStatus").AlterColumn("DisabledTill").AsDateTimeOffset().Nullable(); + Alter.Table("MetadataFiles").AlterColumn("LastUpdated").AsDateTimeOffset().NotNullable(); + Alter.Table("MetadataFiles").AlterColumn("Added").AsDateTimeOffset().Nullable(); + Alter.Table("PendingReleases").AlterColumn("Added").AsDateTimeOffset().NotNullable(); + Alter.Table("ScheduledTasks").AlterColumn("LastExecution").AsDateTimeOffset().NotNullable(); + Alter.Table("ScheduledTasks").AlterColumn("LastStartTime").AsDateTimeOffset().Nullable(); + Alter.Table("Series").AlterColumn("LastInfoSync").AsDateTimeOffset().Nullable(); + Alter.Table("Series").AlterColumn("LastDiskSync").AsDateTimeOffset().Nullable(); + Alter.Table("Series").AlterColumn("FirstAired").AsDateTimeOffset().Nullable(); + Alter.Table("Series").AlterColumn("NextAiring").AsDateTimeOffset().Nullable(); + Alter.Table("Series").AlterColumn("Added").AsDateTimeOffset().Nullable(); + Alter.Table("SubtitleFiles").AlterColumn("LastUpdated").AsDateTimeOffset().NotNullable(); + Alter.Table("SubtitleFiles").AlterColumn("Added").AsDateTimeOffset().Nullable(); + Alter.Table("VersionInfo").AlterColumn("AppliedOn").AsDateTimeOffset().Nullable(); + } + + protected override void LogDbUpgrade() + { + Alter.Table("Logs").AlterColumn("Time").AsDateTimeOffset().NotNullable(); + Alter.Table("UpdateHistory").AlterColumn("Date").AsDateTimeOffset().NotNullable(); + Alter.Table("VersionInfo").AlterColumn("AppliedOn").AsDateTimeOffset().Nullable(); + } + } +} diff --git a/src/NzbDrone.Core/Datastore/Migration/190_health_restored_notification.cs b/src/NzbDrone.Core/Datastore/Migration/190_health_restored_notification.cs index 0319f3471..09057850c 100644 --- a/src/NzbDrone.Core/Datastore/Migration/190_health_restored_notification.cs +++ b/src/NzbDrone.Core/Datastore/Migration/190_health_restored_notification.cs @@ -8,7 +8,7 @@ namespace NzbDrone.Core.Datastore.Migration { protected override void MainDbUpgrade() { - Alter.Table("Notifications").AddColumn("OnHealthRestored").AsBoolean().WithDefaultValue(0); + Alter.Table("Notifications").AddColumn("OnHealthRestored").AsBoolean().WithDefaultValue(false); } } } diff --git a/src/NzbDrone.Core/Datastore/Migration/192_import_exclusion_type.cs b/src/NzbDrone.Core/Datastore/Migration/192_import_exclusion_type.cs index 8b59ec4dc..06d0d21e4 100644 --- a/src/NzbDrone.Core/Datastore/Migration/192_import_exclusion_type.cs +++ b/src/NzbDrone.Core/Datastore/Migration/192_import_exclusion_type.cs @@ -8,7 +8,10 @@ namespace NzbDrone.Core.Datastore.Migration { protected override void MainDbUpgrade() { - Alter.Table("ImportListExclusions").AlterColumn("TvdbId").AsInt32(); + IfDatabase("sqlite").Alter.Table("ImportListExclusions").AlterColumn("TvdbId").AsInt32(); + + // PG cannot autocast varchar to integer + IfDatabase("postgresql").Execute.Sql("ALTER TABLE \"ImportListExclusions\" ALTER COLUMN \"TvdbId\" TYPE INTEGER USING \"TvdbId\"::integer"); } } } diff --git a/src/NzbDrone.Core/Datastore/Migration/Framework/MigrationController.cs b/src/NzbDrone.Core/Datastore/Migration/Framework/MigrationController.cs index 2a788e380..eca2cc7bc 100644 --- a/src/NzbDrone.Core/Datastore/Migration/Framework/MigrationController.cs +++ b/src/NzbDrone.Core/Datastore/Migration/Framework/MigrationController.cs @@ -2,6 +2,7 @@ using System.Diagnostics; using System.Reflection; using FluentMigrator.Runner; +using FluentMigrator.Runner.Generators; using FluentMigrator.Runner.Initialization; using FluentMigrator.Runner.Processors; using Microsoft.Extensions.DependencyInjection; @@ -34,11 +35,16 @@ namespace NzbDrone.Core.Datastore.Migration.Framework _logger.Info("*** Migrating {0} ***", connectionString); - var serviceProvider = new ServiceCollection() + ServiceProvider serviceProvider; + + var db = connectionString.Contains(".db") ? "sqlite" : "postgres"; + + serviceProvider = new ServiceCollection() .AddLogging(b => b.AddNLog()) .AddFluentMigratorCore() .ConfigureRunner( builder => builder + .AddPostgres() .AddNzbDroneSQLite() .WithGlobalConnectionString(connectionString) .WithMigrationsIn(Assembly.GetExecutingAssembly())) @@ -48,6 +54,14 @@ namespace NzbDrone.Core.Datastore.Migration.Framework opt.PreviewOnly = false; opt.Timeout = TimeSpan.FromSeconds(60); }) + .Configure(cfg => + { + cfg.ProcessorId = db; + }) + .Configure(cfg => + { + cfg.GeneratorId = db; + }) .BuildServiceProvider(); using (var scope = serviceProvider.CreateScope()) diff --git a/src/NzbDrone.Core/Datastore/PostgresOptions.cs b/src/NzbDrone.Core/Datastore/PostgresOptions.cs new file mode 100644 index 000000000..e478bdb0e --- /dev/null +++ b/src/NzbDrone.Core/Datastore/PostgresOptions.cs @@ -0,0 +1,26 @@ +using Microsoft.Extensions.Configuration; + +namespace NzbDrone.Core.Datastore +{ + public class PostgresOptions + { + public string Host { get; set; } + public int Port { get; set; } + public string User { get; set; } + public string Password { get; set; } + public string MainDb { get; set; } + public string LogDb { get; set; } + + public static PostgresOptions GetOptions() + { + var config = new ConfigurationBuilder() + .AddEnvironmentVariables() + .Build(); + + var postgresOptions = new PostgresOptions(); + config.GetSection("Sonarr:Postgres").Bind(postgresOptions); + + return postgresOptions; + } + } +} diff --git a/src/NzbDrone.Core/Datastore/SqlBuilder.cs b/src/NzbDrone.Core/Datastore/SqlBuilder.cs index e686d4852..8febd5b6a 100644 --- a/src/NzbDrone.Core/Datastore/SqlBuilder.cs +++ b/src/NzbDrone.Core/Datastore/SqlBuilder.cs @@ -8,9 +8,17 @@ namespace NzbDrone.Core.Datastore public class SqlBuilder { private readonly Dictionary _data = new Dictionary(); + private readonly DatabaseType _databaseType; + + public SqlBuilder(DatabaseType databaseType) + { + _databaseType = databaseType; + } public int Sequence { get; private set; } + public DatabaseType DatabaseType => _databaseType; + public Template AddTemplate(string sql, dynamic parameters = null) => new Template(this, sql, parameters); diff --git a/src/NzbDrone.Core/Datastore/TableMapper.cs b/src/NzbDrone.Core/Datastore/TableMapper.cs index f1c3ef7e1..24ab5869e 100644 --- a/src/NzbDrone.Core/Datastore/TableMapper.cs +++ b/src/NzbDrone.Core/Datastore/TableMapper.cs @@ -49,17 +49,17 @@ namespace NzbDrone.Core.Datastore public string SelectTemplate(Type x) { - return $"SELECT /**select**/ FROM {TableMap[x]} /**join**/ /**innerjoin**/ /**leftjoin**/ /**where**/ /**groupby**/ /**having**/ /**orderby**/"; + return $"SELECT /**select**/ FROM \"{TableMap[x]}\" /**join**/ /**innerjoin**/ /**leftjoin**/ /**where**/ /**groupby**/ /**having**/ /**orderby**/"; } public string DeleteTemplate(Type x) { - return $"DELETE FROM {TableMap[x]} /**where**/"; + return $"DELETE FROM \"{TableMap[x]}\" /**where**/"; } public string PageCountTemplate(Type x) { - return $"SELECT /**select**/ FROM {TableMap[x]} /**join**/ /**innerjoin**/ /**leftjoin**/ /**where**/"; + return $"SELECT /**select**/ FROM \"{TableMap[x]}\" /**join**/ /**innerjoin**/ /**leftjoin**/ /**where**/"; } public bool IsValidSortKey(string sortKey) @@ -90,6 +90,35 @@ namespace NzbDrone.Core.Datastore return true; } + + public string GetSortKey(string sortKey) + { + string table = null; + + if (sortKey.Contains('.')) + { + var split = sortKey.Split('.'); + if (split.Length != 2) + { + return sortKey; + } + + table = split[0]; + sortKey = split[1]; + } + + if (table != null && !TableMap.Values.Contains(table, StringComparer.OrdinalIgnoreCase)) + { + return sortKey; + } + + if (!_allowedOrderBy.Contains(sortKey)) + { + return sortKey; + } + + return _allowedOrderBy.First(x => x.Equals(sortKey, StringComparison.OrdinalIgnoreCase)); + } } public class LazyLoadedProperty @@ -154,7 +183,7 @@ namespace NzbDrone.Core.Datastore (db, parent) => { var id = childIdSelector(parent); - return db.Query(new SqlBuilder().Where(x => x.Id == id)).SingleOrDefault(); + return db.Query(new SqlBuilder(db.DatabaseType).Where(x => x.Id == id)).SingleOrDefault(); }, parent => childIdSelector(parent) > 0); } diff --git a/src/NzbDrone.Core/Datastore/TableMapping.cs b/src/NzbDrone.Core/Datastore/TableMapping.cs index c2aa5230b..be3761ae2 100644 --- a/src/NzbDrone.Core/Datastore/TableMapping.cs +++ b/src/NzbDrone.Core/Datastore/TableMapping.cs @@ -115,7 +115,7 @@ namespace NzbDrone.Core.Datastore Mapper.Entity("EpisodeFiles").RegisterModel() .HasOne(f => f.Series, f => f.SeriesId) .LazyLoad(x => x.Episodes, - (db, parent) => db.Query(new SqlBuilder().Where(c => c.EpisodeFileId == parent.Id)).ToList(), + (db, parent) => db.Query(new SqlBuilder(db.DatabaseType).Where(c => c.EpisodeFileId == parent.Id)).ToList(), t => t.Id > 0) .Ignore(f => f.Path); diff --git a/src/NzbDrone.Core/Datastore/WhereBuilder.cs b/src/NzbDrone.Core/Datastore/WhereBuilder.cs index eeac16727..969364e4f 100644 --- a/src/NzbDrone.Core/Datastore/WhereBuilder.cs +++ b/src/NzbDrone.Core/Datastore/WhereBuilder.cs @@ -1,389 +1,9 @@ -using System; -using System.Collections.Generic; -using System.Data; -using System.Linq; -using System.Linq.Expressions; -using System.Reflection; -using System.Text; using Dapper; namespace NzbDrone.Core.Datastore { - public class WhereBuilder : ExpressionVisitor + public abstract class WhereBuilder : ExpressionVisitor { - protected StringBuilder _sb; - - private const DbType EnumerableMultiParameter = (DbType)(-1); - private readonly string _paramNamePrefix; - private readonly bool _requireConcreteValue; - private int _paramCount; - private bool _gotConcreteValue; - - public WhereBuilder(Expression filter, bool requireConcreteValue, int seq) - { - _paramNamePrefix = string.Format("Clause{0}", seq + 1); - _requireConcreteValue = requireConcreteValue; - _sb = new StringBuilder(); - - Parameters = new DynamicParameters(); - - if (filter != null) - { - Visit(filter); - } - } - - public DynamicParameters Parameters { get; private set; } - - private string AddParameter(object value, DbType? dbType = null) - { - _gotConcreteValue = true; - _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) - { - var method = expression.Method.Name; - - switch (expression.Method.Name) - { - case "Contains": - ParseContainsExpression(expression); - break; - - case "StartsWith": - ParseStartsWith(expression); - break; - - case "EndsWith": - ParseEndsWith(expression); - break; - - default: - var 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) - { - var tableName = expression?.Expression?.Type != null ? TableMapping.Mapper.TableNameMapping(expression.Expression.Type) : null; - var gotValue = TryGetRightValue(expression, out var value); - - // Only use the SQL condition if the expression didn't resolve to an actual value - if (tableName != null && !gotValue) - { - _sb.Append($"\"{tableName}\".\"{expression.Member.Name}\""); - } - else - { - if (value != null) - { - // string is IEnumerable but we don't want to pick up that case - var type = value.GetType(); - var typeInfo = type.GetTypeInfo(); - var isEnumerable = - type != typeof(string) && ( - typeInfo.ImplementedInterfaces.Any(ti => ti.IsGenericType && ti.GetGenericTypeDefinition() == typeof(IEnumerable<>)) || - (typeInfo.IsGenericType && typeInfo.GetGenericTypeDefinition() == typeof(IEnumerable<>))); - - var paramName = isEnumerable ? AddParameter(value, EnumerableMultiParameter) : AddParameter(value); - _sb.Append(paramName); - } - else - { - _gotConcreteValue = true; - _sb.Append("NULL"); - } - } - - return expression; - } - - protected override Expression VisitConstant(ConstantExpression expression) - { - if (expression.Value != null) - { - var paramName = AddParameter(expression.Value); - _sb.Append(paramName); - } - else - { - _gotConcreteValue = true; - _sb.Append("NULL"); - } - - return expression; - } - - private bool TryGetConstantValue(Expression expression, out object result) - { - result = null; - - if (expression is ConstantExpression constExp) - { - result = constExp.Value; - return true; - } - - return false; - } - - private bool TryGetPropertyValue(MemberExpression expression, out object result) - { - result = null; - - if (expression.Expression is MemberExpression nested) - { - // Value is passed in as a property on a parent entity - var container = (nested.Expression as ConstantExpression)?.Value; - - if (container == null) - { - return false; - } - - var entity = GetFieldValue(container, nested.Member); - result = GetFieldValue(entity, expression.Member); - return true; - } - - return false; - } - - private bool TryGetVariableValue(MemberExpression expression, out object result) - { - result = null; - - // Value is passed in as a variable - if (expression.Expression is ConstantExpression nested) - { - result = GetFieldValue(nested.Value, expression.Member); - return true; - } - - return false; - } - - private bool TryGetRightValue(Expression expression, out object value) - { - value = null; - - if (TryGetConstantValue(expression, out value)) - { - return true; - } - - var memberExp = expression as MemberExpression; - - if (TryGetPropertyValue(memberExp, out value)) - { - return true; - } - - if (TryGetVariableValue(memberExp, out value)) - { - return true; - } - - return false; - } - - 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 bool IsNullVariable(Expression expression) - { - if (expression.NodeType == ExpressionType.Constant && - TryGetConstantValue(expression, out var constResult) && - constResult == null) - { - return true; - } - - if (expression.NodeType == ExpressionType.MemberAccess && - expression is MemberExpression member && - ((TryGetPropertyValue(member, out var result) && result == null) || - (TryGetVariableValue(member, out result) && result == null))) - { - return true; - } - - return false; - } - - private string Decode(BinaryExpression expression) - { - if (IsNullVariable(expression.Right)) - { - 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 "); - - // hardcode the integer list if it exists to bypass parameter limit - if (item.Type == typeof(int) && TryGetRightValue(list, out var value)) - { - var items = (IEnumerable)value; - _sb.Append('('); - _sb.Append(string.Join(", ", items)); - _sb.Append(')'); - - _gotConcreteValue = true; - } - else - { - 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() - { - var sql = _sb.ToString(); - - if (_requireConcreteValue && !_gotConcreteValue) - { - var e = new InvalidOperationException("WhereBuilder requires a concrete condition"); - e.Data.Add("sql", sql); - throw e; - } - - return sql; - } + public DynamicParameters Parameters { get; protected set; } } } diff --git a/src/NzbDrone.Core/Datastore/WhereBuilderPostgres.cs b/src/NzbDrone.Core/Datastore/WhereBuilderPostgres.cs new file mode 100644 index 000000000..fe951228b --- /dev/null +++ b/src/NzbDrone.Core/Datastore/WhereBuilderPostgres.cs @@ -0,0 +1,389 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; +using System.Text; +using Dapper; + +namespace NzbDrone.Core.Datastore +{ + public class WhereBuilderPostgres : WhereBuilder + { + protected StringBuilder _sb; + + private const DbType EnumerableMultiParameter = (DbType)(-1); + private readonly string _paramNamePrefix; + private readonly bool _requireConcreteValue; + private int _paramCount; + private bool _gotConcreteValue; + + public WhereBuilderPostgres(Expression filter, bool requireConcreteValue, int seq) + { + _paramNamePrefix = string.Format("Clause{0}", seq + 1); + _requireConcreteValue = requireConcreteValue; + _sb = new StringBuilder(); + + Parameters = new DynamicParameters(); + + if (filter != null) + { + Visit(filter); + } + } + + private string AddParameter(object value, DbType? dbType = null) + { + _gotConcreteValue = true; + _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) + { + var method = expression.Method.Name; + + switch (expression.Method.Name) + { + case "Contains": + ParseContainsExpression(expression); + break; + + case "StartsWith": + ParseStartsWith(expression); + break; + + case "EndsWith": + ParseEndsWith(expression); + break; + + default: + var 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) + { + var tableName = expression?.Expression?.Type != null ? TableMapping.Mapper.TableNameMapping(expression.Expression.Type) : null; + var gotValue = TryGetRightValue(expression, out var value); + + // Only use the SQL condition if the expression didn't resolve to an actual value + if (tableName != null && !gotValue) + { + _sb.Append($"\"{tableName}\".\"{expression.Member.Name}\""); + } + else + { + if (value != null) + { + // string is IEnumerable but we don't want to pick up that case + var type = value.GetType(); + var typeInfo = type.GetTypeInfo(); + var isEnumerable = + type != typeof(string) && ( + typeInfo.ImplementedInterfaces.Any(ti => ti.IsGenericType && ti.GetGenericTypeDefinition() == typeof(IEnumerable<>)) || + (typeInfo.IsGenericType && typeInfo.GetGenericTypeDefinition() == typeof(IEnumerable<>))); + + var paramName = isEnumerable ? AddParameter(value, EnumerableMultiParameter) : AddParameter(value); + _sb.Append(paramName); + } + else + { + _gotConcreteValue = true; + _sb.Append("NULL"); + } + } + + return expression; + } + + protected override Expression VisitConstant(ConstantExpression expression) + { + if (expression.Value != null) + { + var paramName = AddParameter(expression.Value); + _sb.Append(paramName); + } + else + { + _gotConcreteValue = true; + _sb.Append("NULL"); + } + + return expression; + } + + private bool TryGetConstantValue(Expression expression, out object result) + { + result = null; + + if (expression is ConstantExpression constExp) + { + result = constExp.Value; + return true; + } + + return false; + } + + private bool TryGetPropertyValue(MemberExpression expression, out object result) + { + result = null; + + if (expression.Expression is MemberExpression nested) + { + // Value is passed in as a property on a parent entity + var container = (nested.Expression as ConstantExpression)?.Value; + + if (container == null) + { + return false; + } + + var entity = GetFieldValue(container, nested.Member); + result = GetFieldValue(entity, expression.Member); + return true; + } + + return false; + } + + private bool TryGetVariableValue(MemberExpression expression, out object result) + { + result = null; + + // Value is passed in as a variable + if (expression.Expression is ConstantExpression nested) + { + result = GetFieldValue(nested.Value, expression.Member); + return true; + } + + return false; + } + + private bool TryGetRightValue(Expression expression, out object value) + { + value = null; + + if (TryGetConstantValue(expression, out value)) + { + return true; + } + + var memberExp = expression as MemberExpression; + + if (TryGetPropertyValue(memberExp, out value)) + { + return true; + } + + if (TryGetVariableValue(memberExp, out value)) + { + return true; + } + + return false; + } + + 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 bool IsNullVariable(Expression expression) + { + if (expression.NodeType == ExpressionType.Constant && + TryGetConstantValue(expression, out var constResult) && + constResult == null) + { + return true; + } + + if (expression.NodeType == ExpressionType.MemberAccess && + expression is MemberExpression member && + ((TryGetPropertyValue(member, out var result) && result == null) || + (TryGetVariableValue(member, out result) && result == null))) + { + return true; + } + + return false; + } + + private string Decode(BinaryExpression expression) + { + if (IsNullVariable(expression.Right)) + { + 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) || + (list.Type == typeof(List) && !TryGetRightValue(list, out var _)))) + { + 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(" = ANY ("); + + // hardcode the integer list if it exists to bypass parameter limit + if (item.Type == typeof(int) && TryGetRightValue(list, out var value)) + { + var items = (IEnumerable)value; + _sb.Append("('{"); + _sb.Append(string.Join(", ", items)); + _sb.Append("}')"); + + _gotConcreteValue = true; + } + else + { + Visit(list); + } + + _sb.Append("))"); + } + + private void ParseStringContains(MethodCallExpression body) + { + _sb.Append('('); + + Visit(body.Object); + + _sb.Append(" ILIKE '%' || "); + + Visit(body.Arguments[0]); + + _sb.Append(" || '%')"); + } + + private void ParseStartsWith(MethodCallExpression body) + { + _sb.Append('('); + + Visit(body.Object); + + _sb.Append(" ILIKE "); + + Visit(body.Arguments[0]); + + _sb.Append(" || '%')"); + } + + private void ParseEndsWith(MethodCallExpression body) + { + _sb.Append('('); + + Visit(body.Object); + + _sb.Append(" ILIKE '%' || "); + + Visit(body.Arguments[0]); + + _sb.Append(')'); + } + + public override string ToString() + { + var sql = _sb.ToString(); + + if (_requireConcreteValue && !_gotConcreteValue) + { + var e = new InvalidOperationException("WhereBuilder requires a concrete condition"); + e.Data.Add("sql", sql); + throw e; + } + + return sql; + } + } +} diff --git a/src/NzbDrone.Core/Datastore/WhereBuilderSqlite.cs b/src/NzbDrone.Core/Datastore/WhereBuilderSqlite.cs new file mode 100644 index 000000000..b91c9e61e --- /dev/null +++ b/src/NzbDrone.Core/Datastore/WhereBuilderSqlite.cs @@ -0,0 +1,389 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; +using System.Text; +using Dapper; + +namespace NzbDrone.Core.Datastore +{ + public class WhereBuilderSqlite : WhereBuilder + { + protected StringBuilder _sb; + + private const DbType EnumerableMultiParameter = (DbType)(-1); + private readonly string _paramNamePrefix; + private readonly bool _requireConcreteValue; + private int _paramCount; + private bool _gotConcreteValue; + + public WhereBuilderSqlite(Expression filter, bool requireConcreteValue, int seq) + { + _paramNamePrefix = string.Format("Clause{0}", seq + 1); + _requireConcreteValue = requireConcreteValue; + _sb = new StringBuilder(); + + Parameters = new DynamicParameters(); + + if (filter != null) + { + Visit(filter); + } + } + + private string AddParameter(object value, DbType? dbType = null) + { + _gotConcreteValue = true; + _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) + { + var method = expression.Method.Name; + + switch (expression.Method.Name) + { + case "Contains": + ParseContainsExpression(expression); + break; + + case "StartsWith": + ParseStartsWith(expression); + break; + + case "EndsWith": + ParseEndsWith(expression); + break; + + default: + var 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) + { + var tableName = expression?.Expression?.Type != null ? TableMapping.Mapper.TableNameMapping(expression.Expression.Type) : null; + var gotValue = TryGetRightValue(expression, out var value); + + // Only use the SQL condition if the expression didn't resolve to an actual value + if (tableName != null && !gotValue) + { + _sb.Append($"\"{tableName}\".\"{expression.Member.Name}\""); + } + else + { + if (value != null) + { + // string is IEnumerable but we don't want to pick up that case + var type = value.GetType(); + var typeInfo = type.GetTypeInfo(); + var isEnumerable = + type != typeof(string) && ( + typeInfo.ImplementedInterfaces.Any(ti => ti.IsGenericType && ti.GetGenericTypeDefinition() == typeof(IEnumerable<>)) || + (typeInfo.IsGenericType && typeInfo.GetGenericTypeDefinition() == typeof(IEnumerable<>))); + + var paramName = isEnumerable ? AddParameter(value, EnumerableMultiParameter) : AddParameter(value); + _sb.Append(paramName); + } + else + { + _gotConcreteValue = true; + _sb.Append("NULL"); + } + } + + return expression; + } + + protected override Expression VisitConstant(ConstantExpression expression) + { + if (expression.Value != null) + { + var paramName = AddParameter(expression.Value); + _sb.Append(paramName); + } + else + { + _gotConcreteValue = true; + _sb.Append("NULL"); + } + + return expression; + } + + private bool TryGetConstantValue(Expression expression, out object result) + { + result = null; + + if (expression is ConstantExpression constExp) + { + result = constExp.Value; + return true; + } + + return false; + } + + private bool TryGetPropertyValue(MemberExpression expression, out object result) + { + result = null; + + if (expression.Expression is MemberExpression nested) + { + // Value is passed in as a property on a parent entity + var container = (nested.Expression as ConstantExpression)?.Value; + + if (container == null) + { + return false; + } + + var entity = GetFieldValue(container, nested.Member); + result = GetFieldValue(entity, expression.Member); + return true; + } + + return false; + } + + private bool TryGetVariableValue(MemberExpression expression, out object result) + { + result = null; + + // Value is passed in as a variable + if (expression.Expression is ConstantExpression nested) + { + result = GetFieldValue(nested.Value, expression.Member); + return true; + } + + return false; + } + + private bool TryGetRightValue(Expression expression, out object value) + { + value = null; + + if (TryGetConstantValue(expression, out value)) + { + return true; + } + + var memberExp = expression as MemberExpression; + + if (TryGetPropertyValue(memberExp, out value)) + { + return true; + } + + if (TryGetVariableValue(memberExp, out value)) + { + return true; + } + + return false; + } + + 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 bool IsNullVariable(Expression expression) + { + if (expression.NodeType == ExpressionType.Constant && + TryGetConstantValue(expression, out var constResult) && + constResult == null) + { + return true; + } + + if (expression.NodeType == ExpressionType.MemberAccess && + expression is MemberExpression member && + ((TryGetPropertyValue(member, out var result) && result == null) || + (TryGetVariableValue(member, out result) && result == null))) + { + return true; + } + + return false; + } + + private string Decode(BinaryExpression expression) + { + if (IsNullVariable(expression.Right)) + { + 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) || + (list.Type == typeof(List) && !TryGetRightValue(list, out var _)))) + { + 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 "); + + // hardcode the integer list if it exists to bypass parameter limit + if (item.Type == typeof(int) && TryGetRightValue(list, out var value)) + { + var items = (IEnumerable)value; + _sb.Append('('); + _sb.Append(string.Join(", ", items)); + _sb.Append(')'); + + _gotConcreteValue = true; + } + else + { + 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() + { + var sql = _sb.ToString(); + + if (_requireConcreteValue && !_gotConcreteValue) + { + var e = new InvalidOperationException("WhereBuilder requires a concrete condition"); + e.Data.Add("sql", sql); + throw e; + } + + return sql; + } + } +} diff --git a/src/NzbDrone.Core/History/HistoryRepository.cs b/src/NzbDrone.Core/History/HistoryRepository.cs index 28774e865..c5546147a 100644 --- a/src/NzbDrone.Core/History/HistoryRepository.cs +++ b/src/NzbDrone.Core/History/HistoryRepository.cs @@ -101,7 +101,7 @@ namespace NzbDrone.Core.History Delete(c => seriesIds.Contains(c.SeriesId)); } - protected override SqlBuilder PagedBuilder() => new SqlBuilder() + protected override SqlBuilder PagedBuilder() => new SqlBuilder(_database.DatabaseType) .Join((h, a) => h.SeriesId == a.Id) .Join((h, a) => h.EpisodeId == a.Id); diff --git a/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupAbsolutePathMetadataFiles.cs b/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupAbsolutePathMetadataFiles.cs index 8acce195f..b5c0726d7 100644 --- a/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupAbsolutePathMetadataFiles.cs +++ b/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupAbsolutePathMetadataFiles.cs @@ -1,4 +1,4 @@ -using Dapper; +using Dapper; using NzbDrone.Core.Datastore; namespace NzbDrone.Core.Housekeeping.Housekeepers @@ -15,16 +15,32 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers public void Clean() { using var mapper = _database.OpenConnection(); - mapper.Execute(@"DELETE FROM MetadataFiles - WHERE Id IN ( - SELECT Id FROM MetadataFiles - WHERE RelativePath - LIKE '_:\%' - OR RelativePath - LIKE '\%' - OR RelativePath - LIKE '/%' - )"); + if (_database.DatabaseType == DatabaseType.PostgreSQL) + { + mapper.Execute(@"DELETE FROM ""MetadataFiles"" + WHERE ""Id"" = ANY ( + SELECT ""Id"" FROM ""MetadataFiles"" + WHERE ""RelativePath"" + LIKE '_:\\%' + OR ""RelativePath"" + LIKE '\\%' + OR ""RelativePath"" + LIKE '/%' + )"); + } + else + { + mapper.Execute(@"DELETE FROM ""MetadataFiles"" + WHERE ""Id"" IN ( + SELECT ""Id"" FROM ""MetadataFiles"" + WHERE ""RelativePath"" + LIKE '_:\%' + OR ""RelativePath"" + LIKE '\%' + OR ""RelativePath"" + LIKE '/%' + )"); + } } } } diff --git a/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupAdditionalNamingSpecs.cs b/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupAdditionalNamingSpecs.cs index d0803292a..45d0734d5 100644 --- a/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupAdditionalNamingSpecs.cs +++ b/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupAdditionalNamingSpecs.cs @@ -1,4 +1,4 @@ -using Dapper; +using Dapper; using NzbDrone.Core.Datastore; namespace NzbDrone.Core.Housekeeping.Housekeepers @@ -15,10 +15,10 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers public void Clean() { using var mapper = _database.OpenConnection(); - mapper.Execute(@"DELETE FROM NamingConfig - WHERE ID NOT IN ( - SELECT ID FROM NamingConfig - LIMIT 1)"); + mapper.Execute(@"DELETE FROM ""NamingConfig"" + WHERE ""Id"" NOT IN ( + SELECT ""Id"" FROM ""NamingConfig"" + LIMIT 1)"); } } } diff --git a/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupAdditionalUsers.cs b/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupAdditionalUsers.cs index 356105d01..5df9dfea5 100644 --- a/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupAdditionalUsers.cs +++ b/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupAdditionalUsers.cs @@ -1,4 +1,4 @@ -using Dapper; +using Dapper; using NzbDrone.Core.Datastore; namespace NzbDrone.Core.Housekeeping.Housekeepers @@ -15,10 +15,10 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers public void Clean() { using var mapper = _database.OpenConnection(); - mapper.Execute(@"DELETE FROM Users - WHERE ID NOT IN ( - SELECT ID FROM Users - LIMIT 1)"); + mapper.Execute(@"DELETE FROM ""Users"" + WHERE ""Id"" NOT IN ( + SELECT ""Id"" FROM ""Users"" + LIMIT 1)"); } } } diff --git a/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupDownloadClientUnavailablePendingReleases.cs b/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupDownloadClientUnavailablePendingReleases.cs index bdd5014d2..7e3cb6d81 100644 --- a/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupDownloadClientUnavailablePendingReleases.cs +++ b/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupDownloadClientUnavailablePendingReleases.cs @@ -1,4 +1,4 @@ -using System; +using System; using Dapper; using NzbDrone.Core.Datastore; using NzbDrone.Core.Download.Pending; @@ -16,15 +16,30 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers public void Clean() { - using var mapper = _database.OpenConnection(); - mapper.Execute(@"DELETE FROM PendingReleases - WHERE Added < @TwoWeeksAgo - AND REASON IN @Reasons", - new - { - TwoWeeksAgo = DateTime.UtcNow.AddDays(-14), - Reasons = new[] { (int)PendingReleaseReason.DownloadClientUnavailable, (int)PendingReleaseReason.Fallback } - }); + var mapper = _database.OpenConnection(); + + if (_database.DatabaseType == DatabaseType.PostgreSQL) + { + mapper.Execute(@"DELETE FROM ""PendingReleases"" + WHERE ""Added"" < @TwoWeeksAgo + AND ""Reason"" = ANY (@Reasons)", + new + { + TwoWeeksAgo = DateTime.UtcNow.AddDays(-14), + Reasons = new[] { (int)PendingReleaseReason.DownloadClientUnavailable, (int)PendingReleaseReason.Fallback } + }); + } + else + { + mapper.Execute(@"DELETE FROM ""PendingReleases"" + WHERE ""Added"" < @TwoWeeksAgo + AND ""REASON"" IN @Reasons", + new + { + TwoWeeksAgo = DateTime.UtcNow.AddDays(-14), + Reasons = new[] { (int)PendingReleaseReason.DownloadClientUnavailable, (int)PendingReleaseReason.Fallback } + }); + } } } } diff --git a/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupDuplicateMetadataFiles.cs b/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupDuplicateMetadataFiles.cs index 1ac1504b0..e5e414b3d 100644 --- a/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupDuplicateMetadataFiles.cs +++ b/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupDuplicateMetadataFiles.cs @@ -22,37 +22,37 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers private void DeleteDuplicateSeriesMetadata() { using var mapper = _database.OpenConnection(); - mapper.Execute(@"DELETE FROM MetadataFiles - WHERE Id IN ( - SELECT Id FROM MetadataFiles - WHERE Type = 1 - GROUP BY SeriesId, Consumer - HAVING COUNT(SeriesId) > 1 - )"); + mapper.Execute(@"DELETE FROM ""MetadataFiles"" + WHERE ""Id"" IN ( + SELECT MIN(""Id"") FROM ""MetadataFiles"" + WHERE ""Type"" = 1 + GROUP BY ""SeriesId"", ""Consumer"" + HAVING COUNT(""SeriesId"") > 1 + )"); } private void DeleteDuplicateEpisodeMetadata() { using var mapper = _database.OpenConnection(); - mapper.Execute(@"DELETE FROM MetadataFiles - WHERE Id IN ( - SELECT Id FROM MetadataFiles - WHERE Type = 2 - GROUP BY EpisodeFileId, Consumer - HAVING COUNT(EpisodeFileId) > 1 - )"); + mapper.Execute(@"DELETE FROM ""MetadataFiles"" + WHERE ""Id"" IN ( + SELECT MIN(""Id"") FROM ""MetadataFiles"" + WHERE ""Type"" = 2 + GROUP BY ""EpisodeFileId"", ""Consumer"" + HAVING COUNT(""EpisodeFileId"") > 1 + )"); } private void DeleteDuplicateEpisodeImages() { using var mapper = _database.OpenConnection(); - mapper.Execute(@"DELETE FROM MetadataFiles - WHERE Id IN ( - SELECT Id FROM MetadataFiles - WHERE Type = 5 - GROUP BY EpisodeFileId, Consumer - HAVING COUNT(EpisodeFileId) > 1 - )"); + mapper.Execute(@"DELETE FROM ""MetadataFiles"" + WHERE ""Id"" IN ( + SELECT MIN(""Id"") FROM ""MetadataFiles"" + WHERE ""Type"" = 5 + GROUP BY ""EpisodeFileId"", ""Consumer"" + HAVING COUNT(""EpisodeFileId"") > 1 + )"); } } } diff --git a/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupOrphanedBlocklist.cs b/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupOrphanedBlocklist.cs index fa9b9767d..bc3677e5d 100644 --- a/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupOrphanedBlocklist.cs +++ b/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupOrphanedBlocklist.cs @@ -1,4 +1,4 @@ -using Dapper; +using Dapper; using NzbDrone.Core.Datastore; namespace NzbDrone.Core.Housekeeping.Housekeepers @@ -15,12 +15,12 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers public void Clean() { using var mapper = _database.OpenConnection(); - mapper.Execute(@"DELETE FROM Blocklist - WHERE Id IN ( - SELECT Blocklist.Id FROM Blocklist - LEFT OUTER JOIN Series - ON Blocklist.SeriesId = Series.Id - WHERE Series.Id IS NULL)"); + mapper.Execute(@"DELETE FROM ""Blocklist"" + WHERE ""Id"" IN ( + SELECT ""Blocklist"".""Id"" FROM ""Blocklist"" + LEFT OUTER JOIN ""Series"" + ON ""Blocklist"".""SeriesId"" = ""Series"".""Id"" + WHERE ""Series"".""Id"" IS NULL)"); } } } diff --git a/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupOrphanedDownloadClientStatus.cs b/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupOrphanedDownloadClientStatus.cs index 5268f800e..846ddae2f 100644 --- a/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupOrphanedDownloadClientStatus.cs +++ b/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupOrphanedDownloadClientStatus.cs @@ -14,13 +14,14 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers public void Clean() { - using var mapper = _database.OpenConnection(); - mapper.Execute(@"DELETE FROM DownloadClientStatus - WHERE Id IN ( - SELECT DownloadClientStatus.Id FROM DownloadClientStatus - LEFT OUTER JOIN DownloadClients - ON DownloadClientStatus.ProviderId = DownloadClients.Id - WHERE DownloadClients.Id IS NULL)"); + var mapper = _database.OpenConnection(); + + mapper.Execute(@"DELETE FROM ""DownloadClientStatus"" + WHERE ""Id"" IN ( + SELECT ""DownloadClientStatus"".""Id"" FROM ""DownloadClientStatus"" + LEFT OUTER JOIN ""DownloadClients"" + ON ""DownloadClientStatus"".""ProviderId"" = ""DownloadClients"".""Id"" + WHERE ""DownloadClients"".""Id"" IS NULL)"); } } } diff --git a/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupOrphanedEpisodeFiles.cs b/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupOrphanedEpisodeFiles.cs index d90d3e491..51ea92e2d 100644 --- a/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupOrphanedEpisodeFiles.cs +++ b/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupOrphanedEpisodeFiles.cs @@ -15,12 +15,12 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers public void Clean() { using var mapper = _database.OpenConnection(); - mapper.Execute(@"DELETE FROM EpisodeFiles - WHERE Id IN ( - SELECT EpisodeFiles.Id FROM EpisodeFiles - LEFT OUTER JOIN Episodes - ON EpisodeFiles.Id = Episodes.EpisodeFileId - WHERE Episodes.Id IS NULL)"); + mapper.Execute(@"DELETE FROM ""EpisodeFiles"" + WHERE ""Id"" IN ( + SELECT ""EpisodeFiles"".""Id"" FROM ""EpisodeFiles"" + LEFT OUTER JOIN ""Episodes"" + ON ""EpisodeFiles"".""Id"" = ""Episodes"".""EpisodeFileId"" + WHERE ""Episodes"".""Id"" IS NULL)"); } } } diff --git a/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupOrphanedEpisodes.cs b/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupOrphanedEpisodes.cs index 4cf39c4ab..b349d2b6e 100644 --- a/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupOrphanedEpisodes.cs +++ b/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupOrphanedEpisodes.cs @@ -15,12 +15,12 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers public void Clean() { using var mapper = _database.OpenConnection(); - mapper.Execute(@"DELETE FROM Episodes - WHERE Id IN ( - SELECT Episodes.Id FROM Episodes - LEFT OUTER JOIN Series - ON Episodes.SeriesId = Series.Id - WHERE Series.Id IS NULL)"); + mapper.Execute(@"DELETE FROM ""Episodes"" + WHERE ""Id"" IN ( + SELECT ""Episodes"".""Id"" FROM ""Episodes"" + LEFT OUTER JOIN ""Series"" + ON ""Episodes"".""SeriesId"" = ""Series"".""Id"" + WHERE ""Series"".""Id"" IS NULL)"); } } } diff --git a/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupOrphanedHistoryItems.cs b/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupOrphanedHistoryItems.cs index c4b4dd786..6fb2b15c5 100644 --- a/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupOrphanedHistoryItems.cs +++ b/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupOrphanedHistoryItems.cs @@ -21,23 +21,23 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers private void CleanupOrphanedBySeries() { using var mapper = _database.OpenConnection(); - mapper.Execute(@"DELETE FROM History - WHERE Id IN ( - SELECT History.Id FROM History - LEFT OUTER JOIN Series - ON History.SeriesId = Series.Id - WHERE Series.Id IS NULL)"); + mapper.Execute(@"DELETE FROM ""History"" + WHERE ""Id"" IN ( + SELECT ""History"".""Id"" FROM ""History"" + LEFT OUTER JOIN ""Series"" + ON ""History"".""SeriesId"" = ""Series"".""Id"" + WHERE ""Series"".""Id"" IS NULL)"); } private void CleanupOrphanedByEpisode() { using var mapper = _database.OpenConnection(); - mapper.Execute(@"DELETE FROM History - WHERE Id IN ( - SELECT History.Id FROM History - LEFT OUTER JOIN Episodes - ON History.EpisodeId = Episodes.Id - WHERE Episodes.Id IS NULL)"); + mapper.Execute(@"DELETE FROM ""History"" + WHERE ""Id"" IN ( + SELECT ""History"".""Id"" FROM ""History"" + LEFT OUTER JOIN ""Episodes"" + ON ""History"".""EpisodeId"" = ""Episodes"".""Id"" + WHERE ""Episodes"".""Id"" IS NULL)"); } } } diff --git a/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupOrphanedImportListStatus.cs b/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupOrphanedImportListStatus.cs index 606e87390..af23ef77e 100644 --- a/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupOrphanedImportListStatus.cs +++ b/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupOrphanedImportListStatus.cs @@ -15,12 +15,12 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers public void Clean() { using var mapper = _database.OpenConnection(); - mapper.Execute(@"DELETE FROM ImportListStatus - WHERE Id IN ( - SELECT ImportListStatus.Id FROM ImportListStatus - LEFT OUTER JOIN ImportLists - ON ImportListStatus.ProviderId = ImportLists.Id - WHERE ImportLists.Id IS NULL)"); + mapper.Execute(@"DELETE FROM ""ImportListStatus"" + WHERE ""Id"" IN ( + SELECT ""ImportListStatus"".""Id"" FROM ""ImportListStatus"" + LEFT OUTER JOIN ""ImportLists"" + ON ""ImportListStatus"".""ProviderId"" = ""ImportLists"".""Id"" + WHERE ""ImportLists"".""Id"" IS NULL)"); } } } diff --git a/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupOrphanedIndexerStatus.cs b/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupOrphanedIndexerStatus.cs index d70fcd360..b9d36583d 100644 --- a/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupOrphanedIndexerStatus.cs +++ b/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupOrphanedIndexerStatus.cs @@ -1,4 +1,4 @@ -using Dapper; +using Dapper; using NzbDrone.Core.Datastore; namespace NzbDrone.Core.Housekeeping.Housekeepers @@ -15,12 +15,12 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers public void Clean() { using var mapper = _database.OpenConnection(); - mapper.Execute(@"DELETE FROM IndexerStatus - WHERE Id IN ( - SELECT IndexerStatus.Id FROM IndexerStatus - LEFT OUTER JOIN Indexers - ON IndexerStatus.ProviderId = Indexers.Id - WHERE Indexers.Id IS NULL)"); + mapper.Execute(@"DELETE FROM ""IndexerStatus"" + WHERE ""Id"" IN ( + SELECT ""IndexerStatus"".""Id"" FROM ""IndexerStatus"" + LEFT OUTER JOIN ""Indexers"" + ON ""IndexerStatus"".""ProviderId"" = ""Indexers"".""Id"" + WHERE ""Indexers"".""Id"" IS NULL)"); } } } diff --git a/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupOrphanedMetadataFiles.cs b/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupOrphanedMetadataFiles.cs index d1db9bbac..a8750c650 100644 --- a/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupOrphanedMetadataFiles.cs +++ b/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupOrphanedMetadataFiles.cs @@ -22,34 +22,34 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers private void DeleteOrphanedBySeries() { using var mapper = _database.OpenConnection(); - mapper.Execute(@"DELETE FROM MetadataFiles - WHERE Id IN ( - SELECT MetadataFiles.Id FROM MetadataFiles - LEFT OUTER JOIN Series - ON MetadataFiles.SeriesId = Series.Id - WHERE Series.Id IS NULL)"); + mapper.Execute(@"DELETE FROM ""MetadataFiles"" + WHERE ""Id"" IN ( + SELECT ""MetadataFiles"".""Id"" FROM ""MetadataFiles"" + LEFT OUTER JOIN ""Series"" + ON ""MetadataFiles"".""SeriesId"" = ""Series"".""Id"" + WHERE ""Series"".""Id"" IS NULL)"); } private void DeleteOrphanedByEpisodeFile() { using var mapper = _database.OpenConnection(); - mapper.Execute(@"DELETE FROM MetadataFiles - WHERE Id IN ( - SELECT MetadataFiles.Id FROM MetadataFiles - LEFT OUTER JOIN EpisodeFiles - ON MetadataFiles.EpisodeFileId = EpisodeFiles.Id - WHERE MetadataFiles.EpisodeFileId > 0 - AND EpisodeFiles.Id IS NULL)"); + mapper.Execute(@"DELETE FROM ""MetadataFiles"" + WHERE ""Id"" IN ( + SELECT ""MetadataFiles"".""Id"" FROM ""MetadataFiles"" + LEFT OUTER JOIN ""EpisodeFiles"" + ON ""MetadataFiles"".""EpisodeFileId"" = ""EpisodeFiles"".""Id"" + WHERE ""MetadataFiles"".""EpisodeFileId"" > 0 + AND ""EpisodeFiles"".""Id"" IS NULL)"); } private void DeleteWhereEpisodeFileIsZero() { using var mapper = _database.OpenConnection(); - mapper.Execute(@"DELETE FROM MetadataFiles - WHERE Id IN ( - SELECT Id FROM MetadataFiles - WHERE Type IN (2, 5) - AND EpisodeFileId = 0)"); + mapper.Execute(@"DELETE FROM ""MetadataFiles"" + WHERE ""Id"" IN ( + SELECT ""Id"" FROM ""MetadataFiles"" + WHERE ""Type"" IN (2, 5) + AND ""EpisodeFileId"" = 0)"); } } } diff --git a/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupOrphanedPendingReleases.cs b/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupOrphanedPendingReleases.cs index de1c171da..78ec177c1 100644 --- a/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupOrphanedPendingReleases.cs +++ b/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupOrphanedPendingReleases.cs @@ -15,12 +15,12 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers public void Clean() { using var mapper = _database.OpenConnection(); - mapper.Execute(@"DELETE FROM PendingReleases - WHERE Id IN ( - SELECT PendingReleases.Id FROM PendingReleases - LEFT OUTER JOIN Series - ON PendingReleases.SeriesId = Series.Id - WHERE Series.Id IS NULL)"); + mapper.Execute(@"DELETE FROM ""PendingReleases"" + WHERE ""Id"" IN ( + SELECT ""PendingReleases"".""Id"" FROM ""PendingReleases"" + LEFT OUTER JOIN ""Series"" + ON ""PendingReleases"".""SeriesId"" = ""Series"".""Id"" + WHERE ""Series"".""Id"" IS NULL)"); } } } diff --git a/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupUnusedTags.cs b/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupUnusedTags.cs index 27e5eccef..9bd726ba3 100644 --- a/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupUnusedTags.cs +++ b/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupUnusedTags.cs @@ -25,12 +25,19 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers var usedTagsList = string.Join(",", usedTags.Select(d => d.ToString()).ToArray()); - mapper.Execute($"DELETE FROM Tags WHERE NOT Id IN ({usedTagsList})"); + if (_database.DatabaseType == DatabaseType.PostgreSQL) + { + mapper.Execute($"DELETE FROM \"Tags\" WHERE NOT \"Id\" = ANY (\'{{{usedTagsList}}}\'::int[])"); + } + else + { + mapper.Execute($"DELETE FROM \"Tags\" WHERE NOT \"Id\" IN ({usedTagsList})"); + } } private int[] GetUsedTags(string table, IDbConnection mapper) { - return mapper.Query>($"SELECT DISTINCT Tags FROM {table} WHERE NOT Tags = '[]' AND NOT Tags IS NULL") + return mapper.Query>($"SELECT DISTINCT \"Tags\" FROM \"{table}\" WHERE NOT \"Tags\" = '[]' AND NOT \"Tags\" IS NULL") .SelectMany(x => x) .Distinct() .ToArray(); diff --git a/src/NzbDrone.Core/Housekeeping/Housekeepers/FixFutureRunScheduledTasks.cs b/src/NzbDrone.Core/Housekeeping/Housekeepers/FixFutureRunScheduledTasks.cs index d4047cfc3..2918ee2be 100644 --- a/src/NzbDrone.Core/Housekeeping/Housekeepers/FixFutureRunScheduledTasks.cs +++ b/src/NzbDrone.Core/Housekeeping/Housekeepers/FixFutureRunScheduledTasks.cs @@ -1,4 +1,4 @@ -using System; +using System; using Dapper; using NLog; using NzbDrone.Common.EnvironmentInfo; @@ -25,10 +25,10 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers } using var mapper = _database.OpenConnection(); - mapper.Execute(@"UPDATE ScheduledTasks - SET LastExecution = @time - WHERE LastExecution > @time", - new { time = DateTime.UtcNow }); + mapper.Execute(@"UPDATE ""ScheduledTasks"" + SET ""LastExecution"" = @time + WHERE ""LastExecution"" > @time", + new { time = DateTime.UtcNow }); } } } diff --git a/src/NzbDrone.Core/Instrumentation/DatabaseTarget.cs b/src/NzbDrone.Core/Instrumentation/DatabaseTarget.cs index 9567c9f9e..64a23782e 100644 --- a/src/NzbDrone.Core/Instrumentation/DatabaseTarget.cs +++ b/src/NzbDrone.Core/Instrumentation/DatabaseTarget.cs @@ -1,9 +1,11 @@ +using System; using System.Data; using System.Data.SQLite; using NLog; using NLog.Common; using NLog.Config; using NLog.Targets; +using Npgsql; using NzbDrone.Common.Instrumentation; using NzbDrone.Core.Datastore; using NzbDrone.Core.Lifecycle; @@ -13,7 +15,7 @@ namespace NzbDrone.Core.Instrumentation { public class DatabaseTarget : TargetWithLayout, IHandle { - private const string INSERT_COMMAND = "INSERT INTO [Logs]([Message],[Time],[Logger],[Exception],[ExceptionType],[Level]) " + + private const string INSERT_COMMAND = "INSERT INTO \"Logs\" (\"Message\",\"Time\",\"Logger\",\"Exception\",\"ExceptionType\",\"Level\") " + "VALUES(@Message,@Time,@Logger,@Exception,@ExceptionType,@Level)"; private readonly IConnectionStringFactory _connectionStringFactory; @@ -83,23 +85,15 @@ namespace NzbDrone.Core.Instrumentation log.Level = logEvent.Level.Name; - using (var connection = - SQLiteFactory.Instance.CreateConnection()) - { - connection.ConnectionString = _connectionStringFactory.LogDbConnectionString; - connection.Open(); - using (var sqlCommand = connection.CreateCommand()) - { - sqlCommand.CommandText = INSERT_COMMAND; - sqlCommand.Parameters.Add(new SQLiteParameter("Message", DbType.String) { Value = log.Message }); - sqlCommand.Parameters.Add(new SQLiteParameter("Time", DbType.DateTime) { Value = log.Time.ToUniversalTime() }); - sqlCommand.Parameters.Add(new SQLiteParameter("Logger", DbType.String) { Value = log.Logger }); - sqlCommand.Parameters.Add(new SQLiteParameter("Exception", DbType.String) { Value = log.Exception }); - sqlCommand.Parameters.Add(new SQLiteParameter("ExceptionType", DbType.String) { Value = log.ExceptionType }); - sqlCommand.Parameters.Add(new SQLiteParameter("Level", DbType.String) { Value = log.Level }); + var connectionInfo = _connectionStringFactory.LogDbConnection; - sqlCommand.ExecuteNonQuery(); - } + if (connectionInfo.DatabaseType == DatabaseType.SQLite) + { + WriteSqliteLog(log, connectionInfo.ConnectionString); + } + else + { + WritePostgresLog(log, connectionInfo.ConnectionString); } } catch (SQLiteException ex) @@ -109,6 +103,48 @@ namespace NzbDrone.Core.Instrumentation } } + private void WritePostgresLog(Log log, string connectionString) + { + using (var connection = + new NpgsqlConnection(connectionString)) + { + connection.Open(); + using (var sqlCommand = connection.CreateCommand()) + { + sqlCommand.CommandText = INSERT_COMMAND; + sqlCommand.Parameters.Add(new NpgsqlParameter("Message", DbType.String) { Value = log.Message }); + sqlCommand.Parameters.Add(new NpgsqlParameter("Time", DbType.DateTime) { Value = log.Time.ToUniversalTime() }); + sqlCommand.Parameters.Add(new NpgsqlParameter("Logger", DbType.String) { Value = log.Logger }); + sqlCommand.Parameters.Add(new NpgsqlParameter("Exception", DbType.String) { Value = log.Exception == null ? DBNull.Value : log.Exception }); + sqlCommand.Parameters.Add(new NpgsqlParameter("ExceptionType", DbType.String) { Value = log.ExceptionType == null ? DBNull.Value : log.ExceptionType }); + sqlCommand.Parameters.Add(new NpgsqlParameter("Level", DbType.String) { Value = log.Level }); + + sqlCommand.ExecuteNonQuery(); + } + } + } + + private void WriteSqliteLog(Log log, string connectionString) + { + using (var connection = + SQLiteFactory.Instance.CreateConnection()) + { + connection.ConnectionString = connectionString; + connection.Open(); + using (var sqlCommand = connection.CreateCommand()) + { + sqlCommand.CommandText = INSERT_COMMAND; + sqlCommand.Parameters.Add(new SQLiteParameter("Message", DbType.String) { Value = log.Message }); + sqlCommand.Parameters.Add(new SQLiteParameter("Time", DbType.DateTime) { Value = log.Time.ToUniversalTime() }); + sqlCommand.Parameters.Add(new SQLiteParameter("Logger", DbType.String) { Value = log.Logger }); + sqlCommand.Parameters.Add(new SQLiteParameter("Exception", DbType.String) { Value = log.Exception }); + sqlCommand.Parameters.Add(new SQLiteParameter("ExceptionType", DbType.String) { Value = log.ExceptionType }); + sqlCommand.Parameters.Add(new SQLiteParameter("Level", DbType.String) { Value = log.Level }); + sqlCommand.ExecuteNonQuery(); + } + } + } + public void Handle(ApplicationShutdownRequested message) { if (LogManager.Configuration?.LoggingRules?.Contains(Rule) == true) diff --git a/src/NzbDrone.Core/Messaging/Commands/CommandRepository.cs b/src/NzbDrone.Core/Messaging/Commands/CommandRepository.cs index 1bf894ecc..d41f2fbba 100644 --- a/src/NzbDrone.Core/Messaging/Commands/CommandRepository.cs +++ b/src/NzbDrone.Core/Messaging/Commands/CommandRepository.cs @@ -31,7 +31,7 @@ namespace NzbDrone.Core.Messaging.Commands public void OrphanStarted() { - var sql = @"UPDATE Commands SET Status = @Orphaned, EndedAt = @Ended WHERE Status = @Started"; + var sql = @"UPDATE ""Commands"" SET ""Status"" = @Orphaned, ""EndedAt"" = @Ended WHERE ""Status"" = @Started"; var args = new { Orphaned = (int)CommandStatus.Orphaned, diff --git a/src/NzbDrone.Core/SeriesStats/SeriesStatisticsRepository.cs b/src/NzbDrone.Core/SeriesStats/SeriesStatisticsRepository.cs index fd854d75a..d95828776 100644 --- a/src/NzbDrone.Core/SeriesStats/SeriesStatisticsRepository.cs +++ b/src/NzbDrone.Core/SeriesStats/SeriesStatisticsRepository.cs @@ -16,8 +16,8 @@ namespace NzbDrone.Core.SeriesStats public class SeriesStatisticsRepository : ISeriesStatisticsRepository { - private const string _selectEpisodesTemplate = "SELECT /**select**/ FROM Episodes /**join**/ /**innerjoin**/ /**leftjoin**/ /**where**/ /**groupby**/ /**having**/ /**orderby**/"; - private const string _selectEpisodeFilesTemplate = "SELECT /**select**/ FROM EpisodeFiles /**join**/ /**innerjoin**/ /**leftjoin**/ /**where**/ /**groupby**/ /**having**/ /**orderby**/"; + private const string _selectEpisodesTemplate = "SELECT /**select**/ FROM \"Episodes\" /**join**/ /**innerjoin**/ /**leftjoin**/ /**where**/ /**groupby**/ /**having**/ /**orderby**/"; + private const string _selectEpisodeFilesTemplate = "SELECT /**select**/ FROM \"EpisodeFiles\" /**join**/ /**innerjoin**/ /**leftjoin**/ /**where**/ /**groupby**/ /**having**/ /**orderby**/"; private readonly IMainDatabase _database; @@ -69,26 +69,40 @@ namespace NzbDrone.Core.SeriesStats var parameters = new DynamicParameters(); parameters.Add("currentDate", currentDate, null); - return new SqlBuilder() - .Select(@"Episodes.SeriesId AS SeriesId, - Episodes.SeasonNumber, + var trueIndicator = _database.DatabaseType == DatabaseType.PostgreSQL ? "true" : "1"; + var falseIndicator = _database.DatabaseType == DatabaseType.PostgreSQL ? "false" : "0"; + + return new SqlBuilder(_database.DatabaseType) + .Select($@"""Episodes"".""SeriesId"" AS SeriesId, + ""Episodes"".""SeasonNumber"", COUNT(*) AS TotalEpisodeCount, - SUM(CASE WHEN AirdateUtc <= @currentDate OR EpisodeFileId > 0 THEN 1 ELSE 0 END) AS AvailableEpisodeCount, - SUM(CASE WHEN (Monitored = 1 AND AirdateUtc <= @currentDate) OR EpisodeFileId > 0 THEN 1 ELSE 0 END) AS EpisodeCount, - SUM(CASE WHEN EpisodeFileId > 0 THEN 1 ELSE 0 END) AS EpisodeFileCount, - MIN(CASE WHEN AirDateUtc < @currentDate OR EpisodeFileId > 0 OR Monitored = 0 THEN NULL ELSE AirDateUtc END) AS NextAiringString, - MAX(CASE WHEN AirDateUtc >= @currentDate OR EpisodeFileId = 0 AND Monitored = 0 THEN NULL ELSE AirDateUtc END) AS PreviousAiringString", parameters) + SUM(CASE WHEN ""AirDateUtc"" <= @currentDate OR ""EpisodeFileId"" > 0 THEN 1 ELSE 0 END) AS AvailableEpisodeCount, + SUM(CASE WHEN (""Monitored"" = {trueIndicator} AND ""AirDateUtc"" <= @currentDate) OR ""EpisodeFileId"" > 0 THEN 1 ELSE 0 END) AS EpisodeCount, + SUM(CASE WHEN ""EpisodeFileId"" > 0 THEN 1 ELSE 0 END) AS EpisodeFileCount, + MIN(CASE WHEN ""AirDateUtc"" < @currentDate OR ""EpisodeFileId"" > 0 OR ""Monitored"" = {falseIndicator} THEN NULL ELSE ""AirDateUtc"" END) AS NextAiringString, + MAX(CASE WHEN ""AirDateUtc"" >= @currentDate OR ""EpisodeFileId"" = 0 AND ""Monitored"" = {falseIndicator} THEN NULL ELSE ""AirDateUtc"" END) AS PreviousAiringString", parameters) .GroupBy(x => x.SeriesId) .GroupBy(x => x.SeasonNumber); } private SqlBuilder EpisodeFilesBuilder() { - return new SqlBuilder() - .Select(@"SeriesId, - SeasonNumber, - SUM(COALESCE(Size, 0)) AS SizeOnDisk, - GROUP_CONCAT(ReleaseGroup, '|') AS ReleaseGroupsString") + if (_database.DatabaseType == DatabaseType.SQLite) + { + return new SqlBuilder(_database.DatabaseType) + .Select(@"""SeriesId"", + ""SeasonNumber"", + SUM(COALESCE(""Size"", 0)) AS SizeOnDisk, + GROUP_CONCAT(""ReleaseGroup"", '|') AS ReleaseGroupsString") + .GroupBy(x => x.SeriesId) + .GroupBy(x => x.SeasonNumber); + } + + return new SqlBuilder(_database.DatabaseType) + .Select(@"""SeriesId"", + ""SeasonNumber"", + SUM(COALESCE(""Size"", 0)) AS SizeOnDisk, + string_agg(""ReleaseGroup"", '|') AS ReleaseGroupsString") .GroupBy(x => x.SeriesId) .GroupBy(x => x.SeasonNumber); } diff --git a/src/NzbDrone.Core/Sonarr.Core.csproj b/src/NzbDrone.Core/Sonarr.Core.csproj index 68b3ddb17..c18e1b25e 100644 --- a/src/NzbDrone.Core/Sonarr.Core.csproj +++ b/src/NzbDrone.Core/Sonarr.Core.csproj @@ -12,8 +12,9 @@ - - + + + @@ -21,6 +22,7 @@ + diff --git a/src/NzbDrone.Core/Tv/EpisodeRepository.cs b/src/NzbDrone.Core/Tv/EpisodeRepository.cs index b8d06cdcf..13755d1ca 100644 --- a/src/NzbDrone.Core/Tv/EpisodeRepository.cs +++ b/src/NzbDrone.Core/Tv/EpisodeRepository.cs @@ -135,7 +135,7 @@ namespace NzbDrone.Core.Tv pagingSpec.Records = GetPagedRecords(EpisodesWhereCutoffUnmetBuilder(qualitiesBelowCutoff, languagesBelowCutoff, startingSeasonNumber), pagingSpec, PagedQuery); - var countTemplate = $"SELECT COUNT(*) FROM (SELECT /**select**/ FROM {TableMapping.Mapper.TableNameMapping(typeof(Episode))} /**join**/ /**innerjoin**/ /**leftjoin**/ /**where**/ /**groupby**/ /**having**/)"; + var countTemplate = $"SELECT COUNT(*) FROM (SELECT /**select**/ FROM \"{TableMapping.Mapper.TableNameMapping(typeof(Episode))}\" /**join**/ /**innerjoin**/ /**leftjoin**/ /**where**/ /**groupby**/ /**having**/) AS \"Inner\""; pagingSpec.TotalRecords = GetPagedRecordCount(EpisodesWhereCutoffUnmetBuilder(qualitiesBelowCutoff, languagesBelowCutoff, startingSeasonNumber).Select(typeof(Episode)), pagingSpec, countTemplate); return pagingSpec; @@ -177,7 +177,7 @@ namespace NzbDrone.Core.Tv { using (var conn = _database.OpenConnection()) { - conn.Execute("UPDATE Episodes SET Monitored = @monitored WHERE SeriesId = @seriesId AND SeasonNumber = @seasonNumber AND Monitored != @monitored", + conn.Execute("UPDATE \"Episodes\" SET \"Monitored\" = @monitored WHERE \"SeriesId\" = @seriesId AND \"SeasonNumber\" = @seasonNumber AND \"Monitored\" != @monitored", new { seriesId = seriesId, seasonNumber = seasonNumber, monitored = monitored }); } } @@ -215,7 +215,13 @@ namespace NzbDrone.Core.Tv private string BuildAirDateUtcCutoffWhereClause(DateTime currentTime) { - return string.Format("datetime(strftime('%s', \"Episodes\".\"AirDateUtc\") + \"Series\".\"RunTime\" * 60, 'unixepoch') <= '{0}'", + if (_database.DatabaseType == DatabaseType.PostgreSQL) + { + return string.Format("\"Episodes\".\"AirDateUtc\" + make_interval(mins => \"Series\".\"Runtime\") <= '{0}'", + currentTime.ToString("yyyy-MM-dd HH:mm:ss")); + } + + return string.Format("datetime(strftime('%s', \"Episodes\".\"AirDateUtc\") + \"Series\".\"Runtime\" * 60, 'unixepoch') <= '{0}'", currentTime.ToString("yyyy-MM-dd HH:mm:ss")); } @@ -227,7 +233,8 @@ namespace NzbDrone.Core.Tv .Where( string.Format("({0})", BuildQualityCutoffWhereClause(qualitiesBelowCutoff))) - .GroupBy(e => e.Id); + .GroupBy(e => e.Id) + .GroupBy(s => s.Id); private string BuildQualityCutoffWhereClause(List qualitiesBelowCutoff) { @@ -237,7 +244,7 @@ namespace NzbDrone.Core.Tv { foreach (var belowCutoff in profile.QualityIds) { - clauses.Add(string.Format("(Series.[QualityProfileId] = {0} AND EpisodeFiles.Quality LIKE '%_quality_: {1},%')", profile.ProfileId, belowCutoff)); + clauses.Add(string.Format("(\"Series\".\"QualityProfileId\" = {0} AND \"EpisodeFiles\".\"Quality\" LIKE '%_quality_: {1},%')", profile.ProfileId, belowCutoff)); } } diff --git a/src/NzbDrone.Core/Tv/SeriesRepository.cs b/src/NzbDrone.Core/Tv/SeriesRepository.cs index 9613395f5..9a9b9bda6 100644 --- a/src/NzbDrone.Core/Tv/SeriesRepository.cs +++ b/src/NzbDrone.Core/Tv/SeriesRepository.cs @@ -53,7 +53,12 @@ namespace NzbDrone.Core.Tv public List FindByTitleInexact(string cleanTitle) { - var builder = Builder().Where($"instr(@cleanTitle, Series.[CleanTitle])", new { cleanTitle = cleanTitle }); + var builder = Builder().Where($"instr(@cleanTitle, \"Series\".\"CleanTitle\")", new { cleanTitle = cleanTitle }); + + if (_database.DatabaseType == DatabaseType.PostgreSQL) + { + builder = Builder().Where($"(strpos(@cleanTitle, \"Series\".\"CleanTitle\") > 0)", new { cleanTitle = cleanTitle }); + } return Query(builder).ToList(); } @@ -78,7 +83,7 @@ namespace NzbDrone.Core.Tv { using (var conn = _database.OpenConnection()) { - return conn.Query("SELECT TvdbId FROM Series").ToList(); + return conn.Query("SELECT \"TvdbId\" FROM \"Series\"").ToList(); } } @@ -86,7 +91,7 @@ namespace NzbDrone.Core.Tv { using (var conn = _database.OpenConnection()) { - var strSql = "SELECT Id AS [Key], Path AS [Value] FROM Series"; + var strSql = "SELECT \"Id\" AS Key, \"Path\" AS Value FROM \"Series\""; return conn.Query>(strSql).ToDictionary(x => x.Key, x => x.Value); } } diff --git a/src/NzbDrone.Core/Update/UpdatePackageProvider.cs b/src/NzbDrone.Core/Update/UpdatePackageProvider.cs index e75f2d8e5..b0015d48d 100644 --- a/src/NzbDrone.Core/Update/UpdatePackageProvider.cs +++ b/src/NzbDrone.Core/Update/UpdatePackageProvider.cs @@ -5,6 +5,7 @@ using NzbDrone.Common.Cloud; using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.Http; using NzbDrone.Core.Analytics; +using NzbDrone.Core.Datastore; namespace NzbDrone.Core.Update { @@ -20,13 +21,15 @@ namespace NzbDrone.Core.Update private readonly IHttpRequestBuilderFactory _requestBuilder; private readonly IPlatformInfo _platformInfo; private readonly IAnalyticsService _analyticsService; + private readonly IMainDatabase _mainDatabase; - public UpdatePackageProvider(IHttpClient httpClient, ISonarrCloudRequestBuilder requestBuilder, IAnalyticsService analyticsService, IPlatformInfo platformInfo) + public UpdatePackageProvider(IHttpClient httpClient, ISonarrCloudRequestBuilder requestBuilder, IAnalyticsService analyticsService, IPlatformInfo platformInfo, IMainDatabase mainDatabase) { _platformInfo = platformInfo; _analyticsService = analyticsService; _requestBuilder = requestBuilder.Services; _httpClient = httpClient; + _mainDatabase = mainDatabase; } public UpdatePackage GetLatestUpdate(string branch, Version currentVersion) @@ -38,6 +41,7 @@ namespace NzbDrone.Core.Update .AddQueryParam("arch", RuntimeInformation.OSArchitecture) .AddQueryParam("runtime", "netcore") .AddQueryParam("runtimeVer", _platformInfo.Version) + .AddQueryParam("dbType", _mainDatabase.DatabaseType) .SetSegment("branch", branch); if (_analyticsService.IsEnabled) diff --git a/src/NzbDrone.Host.Test/ContainerFixture.cs b/src/NzbDrone.Host.Test/ContainerFixture.cs index 3da68e3b4..6a43eaff9 100644 --- a/src/NzbDrone.Host.Test/ContainerFixture.cs +++ b/src/NzbDrone.Host.Test/ContainerFixture.cs @@ -5,12 +5,14 @@ using DryIoc.Microsoft.DependencyInjection; using FluentAssertions; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Options; using Moq; using NUnit.Framework; using NzbDrone.Common; using NzbDrone.Common.Composition.Extensions; using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.Instrumentation.Extensions; +using NzbDrone.Core.Datastore; using NzbDrone.Core.Datastore.Extensions; using NzbDrone.Core.Download; using NzbDrone.Core.Download.TrackedDownloads; @@ -43,6 +45,7 @@ namespace NzbDrone.App.Test // dummy lifetime and broadcaster so tests resolve container.RegisterInstance(new Mock().Object); container.RegisterInstance(new Mock().Object); + container.RegisterInstance>(new Mock>().Object); _container = container.GetServiceProvider(); } diff --git a/src/NzbDrone.Host/Bootstrap.cs b/src/NzbDrone.Host/Bootstrap.cs index 110052cf7..1a07ae1f2 100644 --- a/src/NzbDrone.Host/Bootstrap.cs +++ b/src/NzbDrone.Host/Bootstrap.cs @@ -9,6 +9,7 @@ using DryIoc; using DryIoc.Microsoft.DependencyInjection; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting.WindowsServices; using Microsoft.Extensions.Logging; @@ -23,6 +24,8 @@ using NzbDrone.Core.Configuration; using NzbDrone.Core.Datastore.Extensions; using LogLevel = Microsoft.Extensions.Logging.LogLevel; +using PostgresOptions = NzbDrone.Core.Datastore.PostgresOptions; + namespace NzbDrone.Host { public static class Bootstrap @@ -132,6 +135,10 @@ namespace NzbDrone.Host .AddDatabase() .AddStartupContext(context); }) + .ConfigureServices(services => + { + services.Configure(config.GetSection("Sonarr:Postgres")); + }) .ConfigureWebHost(builder => { builder.UseConfiguration(config); @@ -206,6 +213,7 @@ namespace NzbDrone.Host return new ConfigurationBuilder() .AddXmlFile(configPath, optional: true, reloadOnChange: false) .AddInMemoryCollection(new List> { new ("dataProtectionFolder", appFolder.GetDataProtectionPath()) }) + .AddEnvironmentVariables() .Build(); } catch (InvalidDataException ex) diff --git a/src/NzbDrone.Integration.Test/IntegrationTest.cs b/src/NzbDrone.Integration.Test/IntegrationTest.cs index 869f17d4e..a6721fdcb 100644 --- a/src/NzbDrone.Integration.Test/IntegrationTest.cs +++ b/src/NzbDrone.Integration.Test/IntegrationTest.cs @@ -2,8 +2,11 @@ using System.Threading; using NLog; using NUnit.Framework; using NzbDrone.Common.Extensions; +using NzbDrone.Core.Datastore; +using NzbDrone.Core.Datastore.Migration.Framework; using NzbDrone.Core.Indexers.Newznab; using NzbDrone.Test.Common; +using NzbDrone.Test.Common.Datastore; using Sonarr.Http.ClientSchema; namespace NzbDrone.Integration.Test @@ -19,6 +22,8 @@ namespace NzbDrone.Integration.Test protected int Port { get; private set; } + protected PostgresOptions PostgresOptions { get; set; } = new (); + protected override string RootUrl => $"http://localhost:{Port}/"; protected override string ApiKey => _runner.ApiKey; @@ -27,7 +32,14 @@ namespace NzbDrone.Integration.Test { Port = Interlocked.Increment(ref StaticPort); - _runner = new NzbDroneRunner(LogManager.GetCurrentClassLogger(), Port); + PostgresOptions = PostgresDatabase.GetTestOptions(); + + if (PostgresOptions?.Host != null) + { + CreatePostgresDb(PostgresOptions); + } + + _runner = new NzbDroneRunner(LogManager.GetCurrentClassLogger(), PostgresOptions, Port); _runner.Kill(); _runner.Start(); @@ -59,6 +71,22 @@ namespace NzbDrone.Integration.Test protected override void StopTestTarget() { _runner.Kill(); + if (PostgresOptions?.Host != null) + { + DropPostgresDb(PostgresOptions); + } + } + + private static void CreatePostgresDb(PostgresOptions options) + { + PostgresDatabase.Create(options, MigrationType.Main); + PostgresDatabase.Create(options, MigrationType.Log); + } + + private static void DropPostgresDb(PostgresOptions options) + { + PostgresDatabase.Drop(options, MigrationType.Main); + PostgresDatabase.Drop(options, MigrationType.Log); } } } diff --git a/src/NzbDrone.Test.Common/Datastore/PostgresDatabase.cs b/src/NzbDrone.Test.Common/Datastore/PostgresDatabase.cs new file mode 100644 index 000000000..940334ca2 --- /dev/null +++ b/src/NzbDrone.Test.Common/Datastore/PostgresDatabase.cs @@ -0,0 +1,69 @@ +using System; +using Npgsql; +using NzbDrone.Core.Datastore; +using NzbDrone.Core.Datastore.Migration.Framework; + +namespace NzbDrone.Test.Common.Datastore +{ + public static class PostgresDatabase + { + public static PostgresOptions GetTestOptions() + { + var options = PostgresOptions.GetOptions(); + + var uid = TestBase.GetUID(); + options.MainDb = uid + "_main"; + options.LogDb = uid + "_log"; + + return options; + } + + public static void Create(PostgresOptions options, MigrationType migrationType) + { + var db = GetDatabaseName(options, migrationType); + var connectionString = GetConnectionString(options); + using var conn = new NpgsqlConnection(connectionString); + conn.Open(); + + using var cmd = conn.CreateCommand(); + cmd.CommandText = $"CREATE DATABASE \"{db}\" WITH OWNER = {options.User} ENCODING = 'UTF8' CONNECTION LIMIT = -1;"; + cmd.ExecuteNonQuery(); + } + + public static void Drop(PostgresOptions options, MigrationType migrationType) + { + var db = GetDatabaseName(options, migrationType); + var connectionString = GetConnectionString(options); + using var conn = new NpgsqlConnection(connectionString); + conn.Open(); + + using var cmd = conn.CreateCommand(); + cmd.CommandText = $"DROP DATABASE \"{db}\" WITH (FORCE);"; + cmd.ExecuteNonQuery(); + } + + private static string GetConnectionString(PostgresOptions options) + { + var builder = new NpgsqlConnectionStringBuilder() + { + Host = options.Host, + Port = options.Port, + Username = options.User, + Password = options.Password, + Enlist = false + }; + + return builder.ConnectionString; + } + + private static string GetDatabaseName(PostgresOptions options, MigrationType migrationType) + { + return migrationType switch + { + MigrationType.Main => options.MainDb, + MigrationType.Log => options.LogDb, + _ => throw new NotImplementedException("Unknown migration type") + }; + } + } +} diff --git a/src/NzbDrone.Test.Common/Datastore/SqliteDatabase.cs b/src/NzbDrone.Test.Common/Datastore/SqliteDatabase.cs new file mode 100644 index 000000000..151e245fc --- /dev/null +++ b/src/NzbDrone.Test.Common/Datastore/SqliteDatabase.cs @@ -0,0 +1,14 @@ +using System.IO; +using NUnit.Framework; +using NzbDrone.Core.Datastore.Migration.Framework; + +namespace NzbDrone.Test.Common.Datastore +{ + public static class SqliteDatabase + { + public static string GetCachedDb(MigrationType type) + { + return Path.Combine(TestContext.CurrentContext.TestDirectory, $"cached_{type}.db"); + } + } +} diff --git a/src/NzbDrone.Test.Common/NzbDroneRunner.cs b/src/NzbDrone.Test.Common/NzbDroneRunner.cs index 41b8dae49..25f977fce 100644 --- a/src/NzbDrone.Test.Common/NzbDroneRunner.cs +++ b/src/NzbDrone.Test.Common/NzbDroneRunner.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Specialized; using System.Diagnostics; using System.IO; using System.Threading; @@ -8,7 +9,9 @@ using NUnit.Framework; using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.Extensions; using NzbDrone.Common.Processes; +using NzbDrone.Common.Serializer; using NzbDrone.Core.Configuration; +using NzbDrone.Core.Datastore; using RestSharp; namespace NzbDrone.Test.Common @@ -21,13 +24,15 @@ namespace NzbDrone.Test.Common public string AppData { get; private set; } public string ApiKey { get; private set; } + public PostgresOptions PostgresOptions { get; private set; } public int Port { get; private set; } - public NzbDroneRunner(Logger logger, int port = 8989) + public NzbDroneRunner(Logger logger, PostgresOptions postgresOptions, int port = 8989) { _processProvider = new ProcessProvider(logger); _restClient = new RestClient($"http://localhost:{port}/api/v3"); + PostgresOptions = postgresOptions; Port = port; } @@ -131,9 +136,23 @@ namespace NzbDrone.Test.Common private void Start(string outputSonarrConsoleExe) { + StringDictionary envVars = new (); + if (PostgresOptions?.Host != null) + { + envVars.Add("Sonarr__Postgres__Host", PostgresOptions.Host); + envVars.Add("Sonarr__Postgres__Port", PostgresOptions.Port.ToString()); + envVars.Add("Sonarr__Postgres__User", PostgresOptions.User); + envVars.Add("Sonarr__Postgres__Password", PostgresOptions.Password); + envVars.Add("Sonarr__Postgres__MainDb", PostgresOptions.MainDb); + envVars.Add("Sonarr__Postgres__LogDb", PostgresOptions.LogDb); + + TestContext.Progress.WriteLine("Using env vars:\n{0}", envVars.ToJson()); + } + TestContext.Progress.WriteLine("Starting instance from {0} on port {1}", outputSonarrConsoleExe, Port); + var args = "-nobrowser -nosingleinstancecheck -data=\"" + AppData + "\""; - _nzbDroneProcess = _processProvider.Start(outputSonarrConsoleExe, args, null, OnOutputDataReceived, OnOutputDataReceived); + _nzbDroneProcess = _processProvider.Start(outputSonarrConsoleExe, args, envVars, OnOutputDataReceived, OnOutputDataReceived); } private void OnOutputDataReceived(string data) diff --git a/src/Sonarr.Api.V3/System/SystemController.cs b/src/Sonarr.Api.V3/System/SystemController.cs index 549d7d9bf..80d177cfb 100644 --- a/src/Sonarr.Api.V3/System/SystemController.cs +++ b/src/Sonarr.Api.V3/System/SystemController.cs @@ -79,7 +79,8 @@ namespace Sonarr.Api.V3.System Mode = _runtimeInfo.Mode, Branch = _configFileProvider.Branch, Authentication = _configFileProvider.AuthenticationMethod, - SqliteVersion = _database.Version, + DatabaseType = _database.DatabaseType, + DatabaseVersion = _database.Version, MigrationVersion = _database.Migration, UrlBase = _configFileProvider.UrlBase, RuntimeVersion = _platformInfo.Version, diff --git a/src/Sonarr.Api.V3/System/SystemResource.cs b/src/Sonarr.Api.V3/System/SystemResource.cs index d12a7865f..53f35921e 100644 --- a/src/Sonarr.Api.V3/System/SystemResource.cs +++ b/src/Sonarr.Api.V3/System/SystemResource.cs @@ -1,6 +1,7 @@ using System; using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Core.Authentication; +using NzbDrone.Core.Datastore; using NzbDrone.Core.Update; namespace Sonarr.Api.V3.System @@ -37,5 +38,7 @@ namespace Sonarr.Api.V3.System public string PackageAuthor { get; set; } public UpdateMechanism PackageUpdateMechanism { get; set; } public string PackageUpdateMechanismMessage { get; set; } + public Version DatabaseVersion { get; set; } + public DatabaseType DatabaseType { get; set; } } } diff --git a/src/postgres.runsettings b/src/postgres.runsettings new file mode 100644 index 000000000..e4ad60eb9 --- /dev/null +++ b/src/postgres.runsettings @@ -0,0 +1,11 @@ + + + + + 192.168.100.5 + 5432 + abc + abc + + +