using System; using System.Collections.Generic; using System.Linq; using Dapper; using NzbDrone.Common.Reflection; using NzbDrone.Core.Authentication; using NzbDrone.Core.Blocklisting; using NzbDrone.Core.Configuration; using NzbDrone.Core.CustomFilters; using NzbDrone.Core.Datastore.Converters; using NzbDrone.Core.Download; using NzbDrone.Core.Download.History; using NzbDrone.Core.Download.Pending; using NzbDrone.Core.Extras.Lyrics; using NzbDrone.Core.Extras.Metadata; using NzbDrone.Core.Extras.Metadata.Files; using NzbDrone.Core.Extras.Others; using NzbDrone.Core.History; using NzbDrone.Core.ImportLists; using NzbDrone.Core.ImportLists.Exclusions; using NzbDrone.Core.Indexers; using NzbDrone.Core.Instrumentation; using NzbDrone.Core.Jobs; using NzbDrone.Core.MediaFiles; using NzbDrone.Core.Messaging.Commands; using NzbDrone.Core.Music; using NzbDrone.Core.Notifications; using NzbDrone.Core.Organizer; using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Profiles.Delay; using NzbDrone.Core.Profiles.Metadata; using NzbDrone.Core.Profiles.Qualities; using NzbDrone.Core.Profiles.Releases; using NzbDrone.Core.Qualities; using NzbDrone.Core.RemotePathMappings; using NzbDrone.Core.RootFolders; using NzbDrone.Core.Tags; using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.Update.History; using static Dapper.SqlMapper; namespace NzbDrone.Core.Datastore { public static class TableMapping { static TableMapping() { Mapper = new TableMapper(); } public static TableMapper Mapper { get; private set; } public static void Map() { RegisterMappers(); Mapper.Entity("Config").RegisterModel(); Mapper.Entity("RootFolders").RegisterModel() .Ignore(r => r.Accessible) .Ignore(r => r.FreeSpace) .Ignore(r => r.TotalSpace); Mapper.Entity("ScheduledTasks").RegisterModel(); Mapper.Entity("Indexers").RegisterModel() .Ignore(x => x.ImplementationName) .Ignore(i => i.Enable) .Ignore(i => i.Protocol) .Ignore(i => i.SupportsRss) .Ignore(i => i.SupportsSearch); Mapper.Entity("ImportLists").RegisterModel() .Ignore(x => x.ImplementationName) .Ignore(i => i.Enable) .Ignore(i => i.ListType); Mapper.Entity("Notifications").RegisterModel() .Ignore(x => x.ImplementationName) .Ignore(i => i.SupportsOnGrab) .Ignore(i => i.SupportsOnReleaseImport) .Ignore(i => i.SupportsOnUpgrade) .Ignore(i => i.SupportsOnRename) .Ignore(i => i.SupportsOnHealthIssue) .Ignore(i => i.SupportsOnDownloadFailure) .Ignore(i => i.SupportsOnImportFailure) .Ignore(i => i.SupportsOnTrackRetag) .Ignore(i => i.SupportsOnApplicationUpdate); Mapper.Entity("Metadata").RegisterModel() .Ignore(x => x.ImplementationName) .Ignore(d => d.Tags); Mapper.Entity("DownloadClients").RegisterModel() .Ignore(x => x.ImplementationName) .Ignore(d => d.Protocol) .Ignore(d => d.Tags); Mapper.Entity("History").RegisterModel(); Mapper.Entity("Artists") .Ignore(s => s.RootFolderPath) .Ignore(s => s.Name) .Ignore(s => s.ForeignArtistId) .HasOne(a => a.Metadata, a => a.ArtistMetadataId) .HasOne(a => a.QualityProfile, a => a.QualityProfileId) .HasOne(s => s.MetadataProfile, s => s.MetadataProfileId) .LazyLoad(a => a.Albums, (db, a) => db.Query(new SqlBuilder(db.DatabaseType).Where(rg => rg.ArtistMetadataId == a.Id)).ToList(), a => a.Id > 0); Mapper.Entity("ArtistMetadata").RegisterModel(); Mapper.Entity("Albums").RegisterModel() .Ignore(x => x.ArtistId) .HasOne(r => r.ArtistMetadata, r => r.ArtistMetadataId) .LazyLoad(a => a.AlbumReleases, (db, album) => db.Query(new SqlBuilder(db.DatabaseType).Where(r => r.AlbumId == album.Id)).ToList(), a => a.Id > 0) .LazyLoad(a => a.Artist, (db, album) => ArtistRepository.Query(db, new SqlBuilder(db.DatabaseType) .Join((a, m) => a.ArtistMetadataId == m.Id) .Where(a => a.ArtistMetadataId == album.ArtistMetadataId)).SingleOrDefault(), a => a.ArtistMetadataId > 0); Mapper.Entity("AlbumReleases").RegisterModel() .HasOne(r => r.Album, r => r.AlbumId) .LazyLoad(x => x.Tracks, (db, release) => db.Query(new SqlBuilder(db.DatabaseType).Where(t => t.AlbumReleaseId == release.Id)).ToList(), r => r.Id > 0); Mapper.Entity("Tracks").RegisterModel() .Ignore(t => t.HasFile) .Ignore(t => t.AlbumId) .HasOne(track => track.AlbumRelease, track => track.AlbumReleaseId) .HasOne(track => track.ArtistMetadata, track => track.ArtistMetadataId) .LazyLoad(t => t.TrackFile, (db, track) => MediaFileRepository.Query(db, new SqlBuilder(db.DatabaseType) .Join((l, r) => l.Id == r.TrackFileId) .Join((l, r) => l.AlbumId == r.Id) .Join((l, r) => l.ArtistMetadataId == r.ArtistMetadataId) .Join((l, r) => l.ArtistMetadataId == r.Id) .Where(t => t.Id == track.TrackFileId)).SingleOrDefault(), t => t.TrackFileId > 0) .LazyLoad(x => x.Artist, (db, t) => ArtistRepository.Query(db, new SqlBuilder(db.DatabaseType) .Join((a, m) => a.ArtistMetadataId == m.Id) .Join((l, r) => l.ArtistMetadataId == r.ArtistMetadataId) .Join((l, r) => l.Id == r.AlbumId) .Where(r => r.Id == t.AlbumReleaseId)).SingleOrDefault(), t => t.Id > 0); Mapper.Entity("TrackFiles").RegisterModel() .HasOne(f => f.Album, f => f.AlbumId) .LazyLoad(x => x.Tracks, (db, file) => db.Query(new SqlBuilder(db.DatabaseType).Where(t => t.TrackFileId == file.Id)).ToList(), x => x.Id > 0) .LazyLoad(x => x.Artist, (db, f) => ArtistRepository.Query(db, new SqlBuilder(db.DatabaseType) .Join((a, m) => a.ArtistMetadataId == m.Id) .Join((l, r) => l.ArtistMetadataId == r.ArtistMetadataId) .Where(a => a.Id == f.AlbumId)).SingleOrDefault(), t => t.Id > 0); Mapper.Entity("QualityDefinitions").RegisterModel() .Ignore(d => d.GroupName) .Ignore(d => d.GroupWeight) .Ignore(d => d.Weight); Mapper.Entity("QualityProfiles").RegisterModel(); Mapper.Entity("MetadataProfiles").RegisterModel(); Mapper.Entity("Logs").RegisterModel(); Mapper.Entity("NamingConfig").RegisterModel(); Mapper.Entity("Blocklist").RegisterModel(); Mapper.Entity("MetadataFiles").RegisterModel(); Mapper.Entity("LyricFiles").RegisterModel(); Mapper.Entity("ExtraFiles").RegisterModel(); Mapper.Entity("PendingReleases").RegisterModel() .Ignore(e => e.RemoteAlbum); Mapper.Entity("RemotePathMappings").RegisterModel(); Mapper.Entity("Tags").RegisterModel(); Mapper.Entity("ReleaseProfiles").RegisterModel(); Mapper.Entity("DelayProfiles").RegisterModel(); Mapper.Entity("Users").RegisterModel(); Mapper.Entity("Commands").RegisterModel() .Ignore(c => c.Message); Mapper.Entity("IndexerStatus").RegisterModel(); Mapper.Entity("DownloadClientStatus").RegisterModel(); Mapper.Entity("ImportListStatus").RegisterModel(); Mapper.Entity("CustomFilters").RegisterModel(); Mapper.Entity("ImportListExclusions").RegisterModel(); Mapper.Entity("DownloadHistory").RegisterModel(); Mapper.Entity("UpdateHistory").RegisterModel(); } private static void RegisterMappers() { RegisterEmbeddedConverter(); RegisterProviderSettingConverter(); SqlMapper.RemoveTypeMap(typeof(DateTime)); SqlMapper.AddTypeHandler(new DapperUtcConverter()); SqlMapper.AddTypeHandler(new DapperTimeSpanConverter()); SqlMapper.AddTypeHandler(new DapperQualityIntConverter()); SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter>(new QualityIntConverter())); SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter(new QualityIntConverter())); SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter>()); SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter>()); SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter>()); SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter>>()); SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter>()); SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter>()); SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter>(new PrimaryAlbumTypeIntConverter())); SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter>(new SecondaryAlbumTypeIntConverter())); SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter>(new ReleaseStatusIntConverter())); SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter()); SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter()); SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter()); SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter>()); SqlMapper.AddTypeHandler(new OsPathConverter()); SqlMapper.RemoveTypeMap(typeof(Guid)); SqlMapper.RemoveTypeMap(typeof(Guid?)); SqlMapper.AddTypeHandler(new GuidConverter()); SqlMapper.AddTypeHandler(new CommandConverter()); SqlMapper.AddTypeHandler(new SystemVersionConverter()); } private static void RegisterProviderSettingConverter() { var settingTypes = typeof(IProviderConfig).Assembly.ImplementationsOf() .Where(x => !x.ContainsGenericParameters); var providerSettingConverter = new ProviderSettingConverter(); foreach (var embeddedType in settingTypes) { SqlMapper.AddTypeHandler(embeddedType, providerSettingConverter); } } private static void RegisterEmbeddedConverter() { var embeddedTypes = typeof(IEmbeddedDocument).Assembly.ImplementationsOf(); var embeddedConverterDefinition = typeof(EmbeddedDocumentConverter<>).GetGenericTypeDefinition(); var genericListDefinition = typeof(List<>).GetGenericTypeDefinition(); foreach (var embeddedType in embeddedTypes) { var embeddedListType = genericListDefinition.MakeGenericType(embeddedType); RegisterEmbeddedConverter(embeddedType, embeddedConverterDefinition); RegisterEmbeddedConverter(embeddedListType, embeddedConverterDefinition); } } private static void RegisterEmbeddedConverter(Type embeddedType, Type embeddedConverterDefinition) { var embeddedConverterType = embeddedConverterDefinition.MakeGenericType(embeddedType); var converter = (ITypeHandler)Activator.CreateInstance(embeddedConverterType); SqlMapper.AddTypeHandler(embeddedType, converter); } } }