Browse Source

move name case-insensitivity down to schema level

pull/2749/head
Jason Dove 7 months ago
parent
commit
45e62af5e3
No known key found for this signature in database
  1. 96
      ErsatzTV.Application/Filler/Commands/CreateFillerPresetHandler.cs
  2. 48
      ErsatzTV.Application/Filler/Commands/UpdateFillerPresetHandler.cs
  3. 12
      ErsatzTV.Application/Filler/Queries/GetPagedFillerPresetsHandler.cs
  4. 13
      ErsatzTV.Application/MediaCollections/Commands/CreateCollectionHandler.cs
  5. 13
      ErsatzTV.Application/MediaCollections/Commands/CreateMultiCollectionHandler.cs
  6. 7
      ErsatzTV.Application/MediaCollections/Commands/CreatePlaylistHandler.cs
  7. 13
      ErsatzTV.Application/MediaCollections/Commands/CreateRerunCollectionHandler.cs
  8. 13
      ErsatzTV.Application/MediaCollections/Commands/CreateSmartCollectionHandler.cs
  9. 21
      ErsatzTV.Application/MediaCollections/Commands/UpdateCollectionHandler.cs
  10. 14
      ErsatzTV.Application/MediaCollections/Commands/UpdateMultiCollectionHandler.cs
  11. 23
      ErsatzTV.Application/MediaCollections/Commands/UpdateRerunCollectionHandler.cs
  12. 14
      ErsatzTV.Application/MediaCollections/Commands/UpdateSmartCollectionHandler.cs
  13. 6
      ErsatzTV.Application/MediaCollections/Queries/GetPagedCollectionsHandler.cs
  14. 6
      ErsatzTV.Application/MediaCollections/Queries/GetPagedMultiCollectionsHandler.cs
  15. 6
      ErsatzTV.Application/MediaCollections/Queries/GetPagedRerunCollectionsHandler.cs
  16. 6
      ErsatzTV.Application/MediaCollections/Queries/GetPagedSmartCollectionsHandler.cs
  17. 12
      ErsatzTV.Application/MediaCollections/Queries/GetPagedTraktListsHandler.cs
  18. 4
      ErsatzTV.Application/Playouts/Queries/GetPagedPlayoutsHandler.cs
  19. 10
      ErsatzTV.Application/ProgramSchedules/Commands/CreateProgramScheduleHandler.cs
  20. 44
      ErsatzTV.Application/ProgramSchedules/Commands/UpdateProgramScheduleHandler.cs
  21. 6
      ErsatzTV.Application/ProgramSchedules/Queries/GetPagedProgramSchedulesHandler.cs
  22. 14
      ErsatzTV.Application/Scheduling/Commands/CopyBlockHandler.cs
  23. 10
      ErsatzTV.Application/Scheduling/Commands/CreateBlockGroupHandler.cs
  24. 7
      ErsatzTV.Application/Scheduling/Commands/CreateBlockHandler.cs
  25. 10
      ErsatzTV.Application/Scheduling/Commands/CreateDecoGroupHandler.cs
  26. 7
      ErsatzTV.Application/Scheduling/Commands/CreateDecoHandler.cs
  27. 10
      ErsatzTV.Application/Scheduling/Commands/CreateDecoTemplateGroupHandler.cs
  28. 7
      ErsatzTV.Application/Scheduling/Commands/CreateDecoTemplateHandler.cs
  29. 10
      ErsatzTV.Application/Scheduling/Commands/CreateTemplateGroupHandler.cs
  30. 7
      ErsatzTV.Application/Scheduling/Commands/CreateTemplateHandler.cs
  31. 9
      ErsatzTV.Application/Scheduling/Commands/UpdateDecoHandler.cs
  32. 6
      ErsatzTV.Application/Search/Queries/SearchArtistsHandler.cs
  33. 6
      ErsatzTV.Application/Search/Queries/SearchCollectionsHandler.cs
  34. 8
      ErsatzTV.Application/Search/Queries/SearchMoviesHandler.cs
  35. 6
      ErsatzTV.Application/Search/Queries/SearchMultiCollectionsHandler.cs
  36. 6
      ErsatzTV.Application/Search/Queries/SearchRerunCollectionsHandler.cs
  37. 6
      ErsatzTV.Application/Search/Queries/SearchSmartCollectionsHandler.cs
  38. 3
      ErsatzTV.Application/Search/Queries/SearchTelevisionSeasonsHandler.cs
  39. 6
      ErsatzTV.Application/Search/Queries/SearchTelevisionShowsHandler.cs
  40. 19
      ErsatzTV.Application/Watermarks/Commands/CopyWatermarkHandler.cs
  41. 25
      ErsatzTV.Application/Watermarks/Commands/CreateWatermarkHandler.cs
  42. 21
      ErsatzTV.Application/Watermarks/Commands/UpdateWatermarkHandler.cs
  43. 6987
      ErsatzTV.Infrastructure.MySql/Migrations/20260102150305_Update_CaseSensitivity.Designer.cs
  44. 679
      ErsatzTV.Infrastructure.MySql/Migrations/20260102150305_Update_CaseSensitivity.cs
  45. 108
      ErsatzTV.Infrastructure.MySql/Migrations/TvContextModelSnapshot.cs
  46. 6814
      ErsatzTV.Infrastructure.Sqlite/Migrations/20260102150221_Update_CaseSensitivity.Designer.cs
  47. 591
      ErsatzTV.Infrastructure.Sqlite/Migrations/20260102150221_Update_CaseSensitivity.cs
  48. 108
      ErsatzTV.Infrastructure.Sqlite/Migrations/TvContextModelSnapshot.cs
  49. 4
      ErsatzTV.Infrastructure/Data/Configurations/ChannelConfiguration.cs
  50. 12
      ErsatzTV.Infrastructure/Data/Configurations/ChannelWatermarkConfiguration.cs
  51. 7
      ErsatzTV.Infrastructure/Data/Configurations/Collection/CollectionConfiguration.cs
  52. 7
      ErsatzTV.Infrastructure/Data/Configurations/Collection/MultiCollectionConfiguration.cs
  53. 6
      ErsatzTV.Infrastructure/Data/Configurations/Collection/PlaylistConfiguration.cs
  54. 7
      ErsatzTV.Infrastructure/Data/Configurations/Collection/RerunCollectionConfiguration.cs
  55. 4
      ErsatzTV.Infrastructure/Data/Configurations/Collection/SmartCollectionConfiguration.cs
  56. 2
      ErsatzTV.Infrastructure/Data/Configurations/Collection/TraktListConfiguration.cs
  57. 7
      ErsatzTV.Infrastructure/Data/Configurations/Filler/FillerPresetConfiguration.cs
  58. 20
      ErsatzTV.Infrastructure/Data/Configurations/Metadata/ArtistMetadataConfiguration.cs
  59. 11
      ErsatzTV.Infrastructure/Data/Configurations/Metadata/MetadataGuidConfiguration.cs
  60. 12
      ErsatzTV.Infrastructure/Data/Configurations/Metadata/MovieMetadataConfiguration.cs
  61. 2
      ErsatzTV.Infrastructure/Data/Configurations/Metadata/ShowMetadataConfiguration.cs
  62. 4
      ErsatzTV.Infrastructure/Data/Configurations/ProgramScheduleConfiguration.cs
  63. 4
      ErsatzTV.Infrastructure/Data/Configurations/Scheduling/BlockConfiguration.cs
  64. 4
      ErsatzTV.Infrastructure/Data/Configurations/Scheduling/BlockGroupConfiguration.cs
  65. 4
      ErsatzTV.Infrastructure/Data/Configurations/Scheduling/DecoConfiguration.cs
  66. 4
      ErsatzTV.Infrastructure/Data/Configurations/Scheduling/DecoGroupConfiguration.cs
  67. 4
      ErsatzTV.Infrastructure/Data/Configurations/Scheduling/DecoTemplateConfiguration.cs
  68. 4
      ErsatzTV.Infrastructure/Data/Configurations/Scheduling/DecoTemplateGroupConfiguration.cs
  69. 4
      ErsatzTV.Infrastructure/Data/Configurations/Scheduling/TemplateConfiguration.cs
  70. 4
      ErsatzTV.Infrastructure/Data/Configurations/Scheduling/TemplateGroupConfiguration.cs
  71. 4
      ErsatzTV.Infrastructure/Data/Repositories/ChannelRepository.cs
  72. 23
      ErsatzTV.Infrastructure/Data/Repositories/MediaCollectionRepository.cs
  73. 9
      ErsatzTV.Infrastructure/Data/Repositories/TelevisionRepository.cs
  74. 34
      ErsatzTV.Infrastructure/Data/TvContext.cs

96
ErsatzTV.Application/Filler/Commands/CreateFillerPresetHandler.cs

@ -1,57 +1,67 @@ @@ -1,57 +1,67 @@
using Bugsnag;
using ErsatzTV.Core;
using ErsatzTV.Core;
using ErsatzTV.Core.Domain.Filler;
using ErsatzTV.Infrastructure.Data;
using Microsoft.EntityFrameworkCore;
namespace ErsatzTV.Application.Filler;
public class CreateFillerPresetHandler : IRequestHandler<CreateFillerPreset, Either<BaseError, Unit>>
public class CreateFillerPresetHandler(IDbContextFactory<TvContext> dbContextFactory)
: IRequestHandler<CreateFillerPreset, Either<BaseError, Unit>>
{
private readonly IClient _client;
private readonly IDbContextFactory<TvContext> _dbContextFactory;
public CreateFillerPresetHandler(IClient client, IDbContextFactory<TvContext> dbContextFactory)
public async Task<Either<BaseError, Unit>> Handle(CreateFillerPreset request, CancellationToken cancellationToken)
{
_client = client;
_dbContextFactory = dbContextFactory;
await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken);
Validation<BaseError, FillerPreset> validation = await Validate(dbContext, request);
return await validation.Apply(fp => Persist(dbContext, fp, cancellationToken));
}
public async Task<Either<BaseError, Unit>> Handle(CreateFillerPreset request, CancellationToken cancellationToken)
private static async Task<Unit> Persist(
TvContext dbContext,
FillerPreset fillerPreset,
CancellationToken cancellationToken)
{
try
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken);
var fillerPreset = new FillerPreset
{
Name = request.Name,
FillerKind = request.FillerKind,
FillerMode = request.FillerMode,
Duration = request.Duration,
Count = request.Count,
PadToNearestMinute = request.PadToNearestMinute,
AllowWatermarks = request.AllowWatermarks,
CollectionType = request.CollectionType,
CollectionId = request.CollectionId,
MediaItemId = request.MediaItemId,
MultiCollectionId = request.MultiCollectionId,
SmartCollectionId = request.SmartCollectionId,
PlaylistId = request.PlaylistId,
Expression = request.FillerKind is FillerKind.MidRoll ? request.Expression : null,
UseChaptersAsMediaItems =
request.FillerKind is not FillerKind.Fallback && request.UseChaptersAsMediaItems
};
await dbContext.FillerPresets.AddAsync(fillerPreset, cancellationToken);
await dbContext.SaveChangesAsync(cancellationToken);
return Unit.Default;
}
catch (Exception ex)
await dbContext.FillerPresets.AddAsync(fillerPreset, cancellationToken);
await dbContext.SaveChangesAsync(cancellationToken);
return Unit.Default;
}
private static Task<Validation<BaseError, FillerPreset>> Validate(
TvContext dbContext,
CreateFillerPreset request) =>
ValidateName(dbContext, request).MapT(name => new FillerPreset
{
_client.Notify(ex);
return BaseError.New(ex.Message);
}
Name = name,
FillerKind = request.FillerKind,
FillerMode = request.FillerMode,
Duration = request.Duration,
Count = request.Count,
PadToNearestMinute = request.PadToNearestMinute,
AllowWatermarks = request.AllowWatermarks,
CollectionType = request.CollectionType,
CollectionId = request.CollectionId,
MediaItemId = request.MediaItemId,
MultiCollectionId = request.MultiCollectionId,
SmartCollectionId = request.SmartCollectionId,
PlaylistId = request.PlaylistId,
Expression = request.FillerKind is FillerKind.MidRoll ? request.Expression : null,
UseChaptersAsMediaItems =
request.FillerKind is not FillerKind.Fallback && request.UseChaptersAsMediaItems
});
private static async Task<Validation<BaseError, string>> ValidateName(
TvContext dbContext,
CreateFillerPreset request)
{
Validation<BaseError, string> result1 = request.NotEmpty(fp => fp.Name)
.Bind(_ => request.NotLongerThan(50)(fp => fp.Name));
bool duplicateName = await dbContext.FillerPresets
.AnyAsync(fp => fp.Name == request.Name);
Validation<BaseError, Unit> result2 = duplicateName
? Fail<BaseError, Unit>("Filler preset name must be unique")
: Success<BaseError, Unit>(Unit.Default);
return (result1, result2).Apply((_, _) => request.Name);
}
}

48
ErsatzTV.Application/Filler/Commands/UpdateFillerPresetHandler.cs

@ -6,27 +6,21 @@ using Microsoft.EntityFrameworkCore; @@ -6,27 +6,21 @@ using Microsoft.EntityFrameworkCore;
namespace ErsatzTV.Application.Filler;
public class UpdateFillerPresetHandler : IRequestHandler<UpdateFillerPreset, Either<BaseError, Unit>>
public class UpdateFillerPresetHandler(IDbContextFactory<TvContext> dbContextFactory)
: IRequestHandler<UpdateFillerPreset, Either<BaseError, Unit>>
{
private readonly IDbContextFactory<TvContext> _dbContextFactory;
public UpdateFillerPresetHandler(IDbContextFactory<TvContext> dbContextFactory) =>
_dbContextFactory = dbContextFactory;
public async Task<Either<BaseError, Unit>> Handle(UpdateFillerPreset request, CancellationToken cancellationToken)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken);
Validation<BaseError, FillerPreset> validation = await FillerPresetMustExist(
dbContext,
request,
cancellationToken);
return await validation.Apply(ps => ApplyUpdateRequest(dbContext, ps, request));
await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken);
Validation<BaseError, FillerPreset> validation = await Validate(dbContext, request, cancellationToken);
return await validation.Apply(ps => ApplyUpdateRequest(dbContext, ps, request, cancellationToken));
}
private static async Task<Unit> ApplyUpdateRequest(
TvContext dbContext,
FillerPreset existing,
UpdateFillerPreset request)
UpdateFillerPreset request,
CancellationToken cancellationToken)
{
existing.Name = request.Name;
existing.FillerKind = request.FillerKind;
@ -45,16 +39,40 @@ public class UpdateFillerPresetHandler : IRequestHandler<UpdateFillerPreset, Eit @@ -45,16 +39,40 @@ public class UpdateFillerPresetHandler : IRequestHandler<UpdateFillerPreset, Eit
existing.UseChaptersAsMediaItems =
request.FillerKind is not FillerKind.Fallback && request.UseChaptersAsMediaItems;
await dbContext.SaveChangesAsync();
await dbContext.SaveChangesAsync(cancellationToken);
return Unit.Default;
}
private static async Task<Validation<BaseError, FillerPreset>> Validate(
TvContext dbContext,
UpdateFillerPreset request,
CancellationToken cancellationToken) =>
(await FillerPresetMustExist(dbContext, request, cancellationToken), await ValidateName(dbContext, request))
.Apply((collectionToUpdate, _) => collectionToUpdate);
private static Task<Validation<BaseError, FillerPreset>> FillerPresetMustExist(
TvContext dbContext,
UpdateFillerPreset request,
CancellationToken cancellationToken) =>
dbContext.FillerPresets
.SelectOneAsync(ps => ps.Id, ps => ps.Id == request.Id, cancellationToken)
.Map(o => o.ToValidation<BaseError>("FillerPreset does not exist"));
.Map(o => o.ToValidation<BaseError>("Filler preset does not exist"));
private static async Task<Validation<BaseError, string>> ValidateName(
TvContext dbContext,
UpdateFillerPreset request)
{
Validation<BaseError, string> result1 = request.NotEmpty(fp => fp.Name)
.Bind(_ => request.NotLongerThan(50)(fp => fp.Name));
bool duplicateName = await dbContext.FillerPresets
.AnyAsync(c => c.Id != request.Id && c.Name == request.Name);
Validation<BaseError, Unit> result2 = duplicateName
? Fail<BaseError, Unit>("Filler preset name must be unique")
: Success<BaseError, Unit>(Unit.Default);
return (result1, result2).Apply((_, _) => request.Name);
}
}

12
ErsatzTV.Application/Filler/Queries/GetPagedFillerPresetsHandler.cs

@ -4,22 +4,18 @@ using static ErsatzTV.Application.Filler.Mapper; @@ -4,22 +4,18 @@ using static ErsatzTV.Application.Filler.Mapper;
namespace ErsatzTV.Application.Filler;
public class GetPagedFillerPresetsHandler : IRequestHandler<GetPagedFillerPresets, PagedFillerPresetsViewModel>
public class GetPagedFillerPresetsHandler(IDbContextFactory<TvContext> dbContextFactory)
: IRequestHandler<GetPagedFillerPresets, PagedFillerPresetsViewModel>
{
private readonly IDbContextFactory<TvContext> _dbContextFactory;
public GetPagedFillerPresetsHandler(IDbContextFactory<TvContext> dbContextFactory) =>
_dbContextFactory = dbContextFactory;
public async Task<PagedFillerPresetsViewModel> Handle(
GetPagedFillerPresets request,
CancellationToken cancellationToken)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken);
await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken);
int count = await dbContext.FillerPresets.CountAsync(cancellationToken);
List<FillerPresetViewModel> page = await dbContext.FillerPresets
.AsNoTracking()
.OrderBy(f => EF.Functions.Collate(f.Name, TvContext.CaseInsensitiveCollation))
.OrderBy(f => f.Name)
.Skip(request.PageNum * request.PageSize)
.Take(request.PageSize)
.ToListAsync(cancellationToken)

13
ErsatzTV.Application/MediaCollections/Commands/CreateCollectionHandler.cs

@ -49,16 +49,15 @@ public class CreateCollectionHandler : @@ -49,16 +49,15 @@ public class CreateCollectionHandler :
TvContext dbContext,
CreateCollection createCollection)
{
List<string> allNames = await dbContext.Collections
.Map(c => c.Name)
.ToListAsync();
Validation<BaseError, string> result1 = createCollection.NotEmpty(c => c.Name)
.Bind(_ => createCollection.NotLongerThan(50)(c => c.Name));
var result2 = Optional(createCollection.Name)
.Where(name => !allNames.Contains(name))
.ToValidation<BaseError>("Collection name must be unique");
bool duplicateName = await dbContext.Collections
.AnyAsync(c => c.Name == createCollection.Name);
Validation<BaseError, Unit> result2 = duplicateName
? Fail<BaseError, Unit>("Collection name must be unique")
: Success<BaseError, Unit>(Unit.Default);
return (result1, result2).Apply((_, _) => createCollection.Name);
}

13
ErsatzTV.Application/MediaCollections/Commands/CreateMultiCollectionHandler.cs

@ -92,16 +92,15 @@ public class CreateMultiCollectionHandler : @@ -92,16 +92,15 @@ public class CreateMultiCollectionHandler :
TvContext dbContext,
CreateMultiCollection createMultiCollection)
{
List<string> allNames = await dbContext.MultiCollections
.Map(c => c.Name)
.ToListAsync();
Validation<BaseError, string> result1 = createMultiCollection.NotEmpty(c => c.Name)
.Bind(_ => createMultiCollection.NotLongerThan(50)(c => c.Name));
var result2 = Optional(createMultiCollection.Name)
.Where(name => !allNames.Contains(name))
.ToValidation<BaseError>("MultiCollection name must be unique");
bool duplicateName = await dbContext.MultiCollections
.AnyAsync(c => c.Name == createMultiCollection.Name);
Validation<BaseError, Unit> result2 = duplicateName
? Fail<BaseError, Unit>("MultiCollection name must be unique")
: Success<BaseError, Unit>(Unit.Default);
return (result1, result2).Apply((_, _) => createMultiCollection.Name);
}

7
ErsatzTV.Application/MediaCollections/Commands/CreatePlaylistHandler.cs

@ -40,11 +40,10 @@ public class CreatePlaylistHandler(IDbContextFactory<TvContext> dbContextFactory @@ -40,11 +40,10 @@ public class CreatePlaylistHandler(IDbContextFactory<TvContext> dbContextFactory
return BaseError.New($"Playlist name \"{request.Name}\" is invalid");
}
Option<Playlist> maybeExisting = await dbContext.Playlists
.FirstOrDefaultAsync(r => r.PlaylistGroupId == request.PlaylistGroupId && r.Name == request.Name)
.Map(Optional);
bool duplicate = await dbContext.Playlists
.AnyAsync(r => r.PlaylistGroupId == request.PlaylistGroupId && r.Name == request.Name);
return maybeExisting.IsSome
return duplicate
? BaseError.New($"A playlist named \"{request.Name}\" already exists in that playlist group")
: Success<BaseError, string>(request.Name);
}

13
ErsatzTV.Application/MediaCollections/Commands/CreateRerunCollectionHandler.cs

@ -46,16 +46,15 @@ public class CreateRerunCollectionHandler(IDbContextFactory<TvContext> dbContext @@ -46,16 +46,15 @@ public class CreateRerunCollectionHandler(IDbContextFactory<TvContext> dbContext
TvContext dbContext,
CreateRerunCollection createCollection)
{
List<string> allNames = await dbContext.RerunCollections
.Map(c => c.Name)
.ToListAsync();
Validation<BaseError, string> result1 = createCollection.NotEmpty(c => c.Name)
.Bind(_ => createCollection.NotLongerThan(50)(c => c.Name));
var result2 = Optional(createCollection.Name)
.Where(name => !allNames.Contains(name))
.ToValidation<BaseError>("Rerun collection name must be unique");
bool duplicateName = await dbContext.RerunCollections
.AnyAsync(c => c.Name == createCollection.Name);
Validation<BaseError, Unit> result2 = duplicateName
? Fail<BaseError, Unit>("Rerun collection name must be unique")
: Success<BaseError, Unit>(Unit.Default);
return (result1, result2).Apply((_, _) => createCollection.Name);
}

13
ErsatzTV.Application/MediaCollections/Commands/CreateSmartCollectionHandler.cs

@ -59,17 +59,16 @@ public class CreateSmartCollectionHandler : @@ -59,17 +59,16 @@ public class CreateSmartCollectionHandler :
TvContext dbContext,
CreateSmartCollection createSmartCollection)
{
List<string> allNames = await dbContext.SmartCollections
.Map(c => c.Name)
.ToListAsync();
bool duplicateName = await dbContext.SmartCollections
.AnyAsync(c => c.Name == createSmartCollection.Name);
Validation<BaseError, Unit> result2 = duplicateName
? Fail<BaseError, Unit>("SmartCollection name must be unique")
: Success<BaseError, Unit>(Unit.Default);
Validation<BaseError, string> result1 = createSmartCollection.NotEmpty(c => c.Name)
.Bind(_ => createSmartCollection.NotLongerThan(50)(c => c.Name));
var result2 = Optional(createSmartCollection.Name)
.Where(name => !allNames.Contains(name, StringComparer.OrdinalIgnoreCase))
.ToValidation<BaseError>("SmartCollection name must be unique");
return (result1, result2).Apply((_, _) => createSmartCollection.Name);
}
}

21
ErsatzTV.Application/MediaCollections/Commands/UpdateCollectionHandler.cs

@ -70,7 +70,7 @@ public class UpdateCollectionHandler : IRequestHandler<UpdateCollection, Either< @@ -70,7 +70,7 @@ public class UpdateCollectionHandler : IRequestHandler<UpdateCollection, Either<
TvContext dbContext,
UpdateCollection request,
CancellationToken cancellationToken) =>
(await CollectionMustExist(dbContext, request, cancellationToken), ValidateName(request))
(await CollectionMustExist(dbContext, request, cancellationToken), await ValidateName(dbContext, request))
.Apply((collectionToUpdate, _) => collectionToUpdate);
private static Task<Validation<BaseError, Collection>> CollectionMustExist(
@ -81,7 +81,20 @@ public class UpdateCollectionHandler : IRequestHandler<UpdateCollection, Either< @@ -81,7 +81,20 @@ public class UpdateCollectionHandler : IRequestHandler<UpdateCollection, Either<
.SelectOneAsync(c => c.Id, c => c.Id == updateCollection.CollectionId, cancellationToken)
.Map(o => o.ToValidation<BaseError>("Collection does not exist."));
private static Validation<BaseError, string> ValidateName(UpdateCollection updateSimpleMediaCollection) =>
updateSimpleMediaCollection.NotEmpty(c => c.Name)
.Bind(_ => updateSimpleMediaCollection.NotLongerThan(50)(c => c.Name));
private static async Task<Validation<BaseError, string>> ValidateName(
TvContext dbContext,
UpdateCollection updateCollection)
{
Validation<BaseError, string> result1 = updateCollection.NotEmpty(c => c.Name)
.Bind(_ => updateCollection.NotLongerThan(50)(c => c.Name));
bool duplicateName = await dbContext.Collections
.AnyAsync(c => c.Id != updateCollection.CollectionId && c.Name == updateCollection.Name);
Validation<BaseError, Unit> result2 = duplicateName
? Fail<BaseError, Unit>("Collection name must be unique")
: Success<BaseError, Unit>(Unit.Default);
return (result1, result2).Apply((_, _) => updateCollection.Name);
}
}

14
ErsatzTV.Application/MediaCollections/Commands/UpdateMultiCollectionHandler.cs

@ -155,17 +155,15 @@ public class UpdateMultiCollectionHandler : IRequestHandler<UpdateMultiCollectio @@ -155,17 +155,15 @@ public class UpdateMultiCollectionHandler : IRequestHandler<UpdateMultiCollectio
TvContext dbContext,
UpdateMultiCollection updateMultiCollection)
{
List<string> allNames = await dbContext.MultiCollections
.Filter(mc => mc.Id != updateMultiCollection.MultiCollectionId)
.Map(c => c.Name)
.ToListAsync();
Validation<BaseError, string> result1 = updateMultiCollection.NotEmpty(c => c.Name)
.Bind(_ => updateMultiCollection.NotLongerThan(50)(c => c.Name));
var result2 = Optional(updateMultiCollection.Name)
.Where(name => !allNames.Contains(name))
.ToValidation<BaseError>("MultiCollection name must be unique");
bool duplicateName = await dbContext.MultiCollections
.AnyAsync(c => c.Id != updateMultiCollection.MultiCollectionId && c.Name == updateMultiCollection.Name);
Validation<BaseError, Unit> result2 = duplicateName
? Fail<BaseError, Unit>("MultiCollection name must be unique")
: Success<BaseError, Unit>(Unit.Default);
return (result1, result2).Apply((_, _) => updateMultiCollection.Name);
}

23
ErsatzTV.Application/MediaCollections/Commands/UpdateRerunCollectionHandler.cs

@ -54,10 +54,12 @@ public class UpdateRerunCollectionHandler( @@ -54,10 +54,12 @@ public class UpdateRerunCollectionHandler(
return Unit.Default;
}
private static Task<Validation<BaseError, RerunCollection>> Validate(
private static async Task<Validation<BaseError, RerunCollection>> Validate(
TvContext dbContext,
UpdateRerunCollection request,
CancellationToken cancellationToken) => RerunCollectionMustExist(dbContext, request, cancellationToken);
CancellationToken cancellationToken) =>
(await RerunCollectionMustExist(dbContext, request, cancellationToken), await ValidateName(dbContext, request))
.Apply((collectionToUpdate, _) => collectionToUpdate);
private static Task<Validation<BaseError, RerunCollection>> RerunCollectionMustExist(
TvContext dbContext,
@ -66,4 +68,21 @@ public class UpdateRerunCollectionHandler( @@ -66,4 +68,21 @@ public class UpdateRerunCollectionHandler(
dbContext.RerunCollections
.SelectOneAsync(c => c.Id, c => c.Id == updateCollection.RerunCollectionId, cancellationToken)
.Map(o => o.ToValidation<BaseError>("Rerun collection does not exist."));
private static async Task<Validation<BaseError, string>> ValidateName(
TvContext dbContext,
UpdateRerunCollection updateCollection)
{
Validation<BaseError, string> result1 = updateCollection.NotEmpty(c => c.Name)
.Bind(_ => updateCollection.NotLongerThan(50)(c => c.Name));
bool duplicateName = await dbContext.RerunCollections
.AnyAsync(c => c.Id != updateCollection.RerunCollectionId && c.Name == updateCollection.Name);
Validation<BaseError, Unit> result2 = duplicateName
? Fail<BaseError, Unit>("Rerun collection name must be unique")
: Success<BaseError, Unit>(Unit.Default);
return (result1, result2).Apply((_, _) => updateCollection.Name);
}
}

14
ErsatzTV.Application/MediaCollections/Commands/UpdateSmartCollectionHandler.cs

@ -88,17 +88,15 @@ public class @@ -88,17 +88,15 @@ public class
TvContext dbContext,
UpdateSmartCollection updateCollection)
{
List<string> allNames = await dbContext.SmartCollections
.Where(c => c.Id != updateCollection.Id)
.Map(c => c.Name)
.ToListAsync();
Validation<BaseError, string> result1 = updateCollection.NotEmpty(c => c.Name)
.Bind(_ => updateCollection.NotLongerThan(50)(c => c.Name));
var result2 = Optional(updateCollection.Name)
.Where(name => !allNames.Contains(name, StringComparer.OrdinalIgnoreCase))
.ToValidation<BaseError>("SmartCollection name must be unique");
bool duplicateName = await dbContext.SmartCollections
.AnyAsync(c => c.Id != updateCollection.Id && c.Name == updateCollection.Name);
Validation<BaseError, Unit> result2 = duplicateName
? Fail<BaseError, Unit>("SmartCollection name must be unique")
: Success<BaseError, Unit>(Unit.Default);
return (result1, result2).Apply((_, _) => updateCollection.Name);
}

6
ErsatzTV.Application/MediaCollections/Queries/GetPagedCollectionsHandler.cs

@ -19,13 +19,11 @@ public class GetPagedCollectionsHandler(IDbContextFactory<TvContext> dbContextFa @@ -19,13 +19,11 @@ public class GetPagedCollectionsHandler(IDbContextFactory<TvContext> dbContextFa
if (!string.IsNullOrWhiteSpace(request.Query))
{
query = query.Where(s => EF.Functions.Like(
EF.Functions.Collate(s.Name, TvContext.CaseInsensitiveCollation),
$"%{request.Query}%"));
query = query.Where(c => EF.Functions.Like(c.Name, $"%{request.Query}%"));
}
List<MediaCollectionViewModel> page = await query
.OrderBy(c => EF.Functions.Collate(c.Name, TvContext.CaseInsensitiveCollation))
.OrderBy(c => c.Name)
.Skip(request.PageNum * request.PageSize)
.Take(request.PageSize)
.ToListAsync(cancellationToken)

6
ErsatzTV.Application/MediaCollections/Queries/GetPagedMultiCollectionsHandler.cs

@ -19,13 +19,11 @@ public class GetPagedMultiCollectionsHandler(IDbContextFactory<TvContext> dbCont @@ -19,13 +19,11 @@ public class GetPagedMultiCollectionsHandler(IDbContextFactory<TvContext> dbCont
if (!string.IsNullOrWhiteSpace(request.Query))
{
query = query.Where(s => EF.Functions.Like(
EF.Functions.Collate(s.Name, TvContext.CaseInsensitiveCollation),
$"%{request.Query}%"));
query = query.Where(mc => EF.Functions.Like(mc.Name, $"%{request.Query}%"));
}
List<MultiCollectionViewModel> page = await query
.OrderBy(f => EF.Functions.Collate(f.Name, TvContext.CaseInsensitiveCollation))
.OrderBy(mc => mc.Name)
.Skip(request.PageNum * request.PageSize)
.Take(request.PageSize)
.Include(mc => mc.MultiCollectionItems)

6
ErsatzTV.Application/MediaCollections/Queries/GetPagedRerunCollectionsHandler.cs

@ -19,13 +19,11 @@ public class GetPagedRerunCollectionsHandler(IDbContextFactory<TvContext> dbCont @@ -19,13 +19,11 @@ public class GetPagedRerunCollectionsHandler(IDbContextFactory<TvContext> dbCont
if (!string.IsNullOrWhiteSpace(request.Query))
{
query = query.Where(s => EF.Functions.Like(
EF.Functions.Collate(s.Name, TvContext.CaseInsensitiveCollation),
$"%{request.Query}%"));
query = query.Where(rc => EF.Functions.Like(rc.Name, $"%{request.Query}%"));
}
List<RerunCollectionViewModel> page = await query
.OrderBy(f => EF.Functions.Collate(f.Name, TvContext.CaseInsensitiveCollation))
.OrderBy(rc => rc.Name)
.Skip(request.PageNum * request.PageSize)
.Take(request.PageSize)
.ToListAsync(cancellationToken)

6
ErsatzTV.Application/MediaCollections/Queries/GetPagedSmartCollectionsHandler.cs

@ -19,13 +19,11 @@ public class GetPagedSmartCollectionsHandler(IDbContextFactory<TvContext> dbCont @@ -19,13 +19,11 @@ public class GetPagedSmartCollectionsHandler(IDbContextFactory<TvContext> dbCont
if (!string.IsNullOrWhiteSpace(request.Query))
{
query = query.Where(s => EF.Functions.Like(
EF.Functions.Collate(s.Name, TvContext.CaseInsensitiveCollation),
$"%{request.Query}%"));
query = query.Where(sc => EF.Functions.Like(sc.Name, $"%{request.Query}%"));
}
List<SmartCollectionViewModel> page = await query
.OrderBy(s => EF.Functions.Collate(s.Name, TvContext.CaseInsensitiveCollation))
.OrderBy(s => s.Name)
.Skip(request.PageNum * request.PageSize)
.Take(request.PageSize)
.ToListAsync(cancellationToken)

12
ErsatzTV.Application/MediaCollections/Queries/GetPagedTraktListsHandler.cs

@ -4,22 +4,18 @@ using static ErsatzTV.Application.MediaCollections.Mapper; @@ -4,22 +4,18 @@ using static ErsatzTV.Application.MediaCollections.Mapper;
namespace ErsatzTV.Application.MediaCollections;
public class GetPagedTraktListsHandler : IRequestHandler<GetPagedTraktLists, PagedTraktListsViewModel>
public class GetPagedTraktListsHandler(IDbContextFactory<TvContext> dbContextFactory)
: IRequestHandler<GetPagedTraktLists, PagedTraktListsViewModel>
{
private readonly IDbContextFactory<TvContext> _dbContextFactory;
public GetPagedTraktListsHandler(IDbContextFactory<TvContext> dbContextFactory) =>
_dbContextFactory = dbContextFactory;
public async Task<PagedTraktListsViewModel> Handle(
GetPagedTraktLists request,
CancellationToken cancellationToken)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken);
await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken);
int count = await dbContext.TraktLists.CountAsync(cancellationToken);
List<TraktListViewModel> page = await dbContext.TraktLists
.AsNoTracking()
.OrderBy(f => EF.Functions.Collate(f.Name, TvContext.CaseInsensitiveCollation))
.OrderBy(l => l.Name)
.Skip(request.PageNum * request.PageSize)
.Take(request.PageSize)
.Include(l => l.Items)

4
ErsatzTV.Application/Playouts/Queries/GetPagedPlayoutsHandler.cs

@ -24,9 +24,7 @@ public class GetPagedPlayoutsHandler(IDbContextFactory<TvContext> dbContextFacto @@ -24,9 +24,7 @@ public class GetPagedPlayoutsHandler(IDbContextFactory<TvContext> dbContextFacto
if (!string.IsNullOrWhiteSpace(request.Query))
{
query = query.Where(p => EF.Functions.Like(
EF.Functions.Collate(p.Channel.Name, TvContext.CaseInsensitiveCollation),
$"%{request.Query}%"));
query = query.Where(p => EF.Functions.Like(p.Channel.Name, $"%{request.Query}%"));
}
List<PlayoutNameViewModel> page = await query

10
ErsatzTV.Application/ProgramSchedules/Commands/CreateProgramScheduleHandler.cs

@ -51,12 +51,12 @@ public class CreateProgramScheduleHandler(IDbContextFactory<TvContext> dbContext @@ -51,12 +51,12 @@ public class CreateProgramScheduleHandler(IDbContextFactory<TvContext> dbContext
Validation<BaseError, string> result1 = createProgramSchedule.NotEmpty(c => c.Name)
.Bind(_ => createProgramSchedule.NotLongerThan(50)(c => c.Name));
int duplicateNameCount = await dbContext.ProgramSchedules
.CountAsync(ps => ps.Name == createProgramSchedule.Name);
bool duplicateName = await dbContext.ProgramSchedules
.AnyAsync(ps => ps.Name == createProgramSchedule.Name);
var result2 = Optional(duplicateNameCount)
.Where(count => count == 0)
.ToValidation<BaseError>("Schedule name must be unique");
Validation<BaseError, Unit> result2 = duplicateName
? Fail<BaseError, Unit>("Schedule name must be unique")
: Success<BaseError, Unit>(Unit.Default);
return (result1, result2).Apply((_, _) => createProgramSchedule.Name);
}

44
ErsatzTV.Application/ProgramSchedules/Commands/UpdateProgramScheduleHandler.cs

@ -9,25 +9,17 @@ using Microsoft.EntityFrameworkCore; @@ -9,25 +9,17 @@ using Microsoft.EntityFrameworkCore;
namespace ErsatzTV.Application.ProgramSchedules;
public class UpdateProgramScheduleHandler :
IRequestHandler<UpdateProgramSchedule, Either<BaseError, UpdateProgramScheduleResult>>
public class UpdateProgramScheduleHandler(
IDbContextFactory<TvContext> dbContextFactory,
ChannelWriter<IBackgroundServiceRequest> channel)
:
IRequestHandler<UpdateProgramSchedule, Either<BaseError, UpdateProgramScheduleResult>>
{
private readonly ChannelWriter<IBackgroundServiceRequest> _channel;
private readonly IDbContextFactory<TvContext> _dbContextFactory;
public UpdateProgramScheduleHandler(
IDbContextFactory<TvContext> dbContextFactory,
ChannelWriter<IBackgroundServiceRequest> channel)
{
_dbContextFactory = dbContextFactory;
_channel = channel;
}
public async Task<Either<BaseError, UpdateProgramScheduleResult>> Handle(
UpdateProgramSchedule request,
CancellationToken cancellationToken)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken);
await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken);
Validation<BaseError, ProgramSchedule> validation = await Validate(dbContext, request, cancellationToken);
return await validation.Apply(ps => ApplyUpdateRequest(dbContext, ps, request));
}
@ -64,7 +56,7 @@ public class UpdateProgramScheduleHandler : @@ -64,7 +56,7 @@ public class UpdateProgramScheduleHandler :
foreach (int playoutId in playoutIds)
{
await _channel.WriteAsync(new BuildPlayout(playoutId, PlayoutBuildMode.Refresh));
await channel.WriteAsync(new BuildPlayout(playoutId, PlayoutBuildMode.Refresh));
}
}
@ -75,7 +67,7 @@ public class UpdateProgramScheduleHandler : @@ -75,7 +67,7 @@ public class UpdateProgramScheduleHandler :
TvContext dbContext,
UpdateProgramSchedule request,
CancellationToken cancellationToken) =>
(await ProgramScheduleMustExist(dbContext, request, cancellationToken), ValidateName(request))
(await ProgramScheduleMustExist(dbContext, request, cancellationToken), await ValidateName(dbContext, request, cancellationToken))
.Apply((programSchedule, _) => programSchedule);
private static Task<Validation<BaseError, ProgramSchedule>> ProgramScheduleMustExist(
@ -84,9 +76,23 @@ public class UpdateProgramScheduleHandler : @@ -84,9 +76,23 @@ public class UpdateProgramScheduleHandler :
CancellationToken cancellationToken) =>
dbContext.ProgramSchedules
.SelectOneAsync(ps => ps.Id, ps => ps.Id == request.ProgramScheduleId, cancellationToken)
.Map(o => o.ToValidation<BaseError>("ProgramSchedule does not exist"));
.Map(o => o.ToValidation<BaseError>("Schedule does not exist"));
private static Validation<BaseError, string> ValidateName(UpdateProgramSchedule request) =>
request.NotEmpty(c => c.Name)
private static async Task<Validation<BaseError, string>> ValidateName(
TvContext dbContext,
UpdateProgramSchedule request,
CancellationToken cancellationToken)
{
Validation<BaseError, string> result1 = request.NotEmpty(c => c.Name)
.Bind(_ => request.NotLongerThan(50)(c => c.Name));
bool duplicateName = await dbContext.ProgramSchedules
.AnyAsync(c => c.Id != request.ProgramScheduleId && c.Name == request.Name, cancellationToken);
Validation<BaseError, Unit> result2 = duplicateName
? Fail<BaseError, Unit>("Schedule name must be unique")
: Success<BaseError, Unit>(Unit.Default);
return (result1, result2).Apply((_, _) => request.Name);
}
}

6
ErsatzTV.Application/ProgramSchedules/Queries/GetPagedProgramSchedulesHandler.cs

@ -19,13 +19,11 @@ public class GetPagedProgramSchedulesHandler(IDbContextFactory<TvContext> dbCont @@ -19,13 +19,11 @@ public class GetPagedProgramSchedulesHandler(IDbContextFactory<TvContext> dbCont
if (!string.IsNullOrWhiteSpace(request.Query))
{
query = query.Where(s => EF.Functions.Like(
EF.Functions.Collate(s.Name, TvContext.CaseInsensitiveCollation),
$"%{request.Query}%"));
query = query.Where(ps => EF.Functions.Like(ps.Name, $"%{request.Query}%"));
}
List<ProgramScheduleViewModel> page = await query
.OrderBy(s => EF.Functions.Collate(s.Name, TvContext.CaseInsensitiveCollation))
.OrderBy(ps => ps.Name)
.Skip(request.PageNum * request.PageSize)
.Take(request.PageSize)
.ToListAsync(cancellationToken)

14
ErsatzTV.Application/Scheduling/Commands/CopyBlockHandler.cs

@ -92,17 +92,15 @@ public class CopyBlockHandler(IDbContextFactory<TvContext> dbContextFactory) @@ -92,17 +92,15 @@ public class CopyBlockHandler(IDbContextFactory<TvContext> dbContextFactory)
private static async Task<Validation<BaseError, string>> ValidateName(TvContext dbContext, CopyBlock request)
{
List<string> allNames = await dbContext.Blocks
.Where(b => b.BlockGroupId == request.NewBlockGroupId)
.Map(ps => ps.Name)
.ToListAsync();
Validation<BaseError, string> result1 = request.NotEmpty(c => c.NewBlockName)
.Bind(_ => request.NotLongerThan(50)(c => c.NewBlockName));
var result2 = Optional(request.NewBlockName)
.Where(name => !allNames.Contains(name))
.ToValidation<BaseError>("Block name must be unique within the block group.");
bool duplicateName = await dbContext.Blocks
.AnyAsync(b => b.BlockGroupId == request.NewBlockGroupId && b.Name == request.NewBlockName);
Validation<BaseError, Unit> result2 = duplicateName
? Fail<BaseError, Unit>("Block name must be unique within the block group")
: Success<BaseError, Unit>(Unit.Default);
return (result1, result2).Apply((_, _) => request.NewBlockName);
}

10
ErsatzTV.Application/Scheduling/Commands/CreateBlockGroupHandler.cs

@ -34,12 +34,12 @@ public class CreateBlockGroupHandler(IDbContextFactory<TvContext> dbContextFacto @@ -34,12 +34,12 @@ public class CreateBlockGroupHandler(IDbContextFactory<TvContext> dbContextFacto
Validation<BaseError, string> result1 = createBlockGroup.NotEmpty(c => c.Name)
.Bind(_ => createBlockGroup.NotLongerThan(50)(c => c.Name));
int duplicateNameCount = await dbContext.BlockGroups
.CountAsync(ps => ps.Name == createBlockGroup.Name);
bool duplicateName = await dbContext.BlockGroups
.AnyAsync(bg => bg.Name == createBlockGroup.Name);
var result2 = Optional(duplicateNameCount)
.Where(count => count == 0)
.ToValidation<BaseError>("Block group name must be unique");
Validation<BaseError, Unit> result2 = duplicateName
? Fail<BaseError, Unit>("Block group name must be unique")
: Success<BaseError, Unit>(Unit.Default);
return (result1, result2).Apply((_, _) => createBlockGroup.Name);
}

7
ErsatzTV.Application/Scheduling/Commands/CreateBlockHandler.cs

@ -42,11 +42,10 @@ public class CreateBlockHandler(IDbContextFactory<TvContext> dbContextFactory) @@ -42,11 +42,10 @@ public class CreateBlockHandler(IDbContextFactory<TvContext> dbContextFactory)
return BaseError.New($"Block name \"{request.Name}\" is invalid");
}
Option<Block> maybeExisting = await dbContext.Blocks
.FirstOrDefaultAsync(r => r.BlockGroupId == request.BlockGroupId && r.Name == request.Name)
.Map(Optional);
bool duplicate = await dbContext.Blocks
.AnyAsync(r => r.BlockGroupId == request.BlockGroupId && r.Name == request.Name);
return maybeExisting.IsSome
return duplicate
? BaseError.New($"A block named \"{request.Name}\" already exists in that block group")
: Success<BaseError, string>(request.Name);
}

10
ErsatzTV.Application/Scheduling/Commands/CreateDecoGroupHandler.cs

@ -34,12 +34,12 @@ public class CreateDecoGroupHandler(IDbContextFactory<TvContext> dbContextFactor @@ -34,12 +34,12 @@ public class CreateDecoGroupHandler(IDbContextFactory<TvContext> dbContextFactor
Validation<BaseError, string> result1 = createDecoGroup.NotEmpty(c => c.Name)
.Bind(_ => createDecoGroup.NotLongerThan(50)(c => c.Name));
int duplicateNameCount = await dbContext.DecoGroups
.CountAsync(ps => ps.Name == createDecoGroup.Name);
bool duplicateName = await dbContext.DecoGroups
.AnyAsync(ps => ps.Name == createDecoGroup.Name);
var result2 = Optional(duplicateNameCount)
.Where(count => count == 0)
.ToValidation<BaseError>("Deco group name must be unique");
Validation<BaseError, Unit> result2 = duplicateName
? Fail<BaseError, Unit>("Deco group name must be unique")
: Success<BaseError, Unit>(Unit.Default);
return (result1, result2).Apply((_, _) => createDecoGroup.Name);
}

7
ErsatzTV.Application/Scheduling/Commands/CreateDecoHandler.cs

@ -44,11 +44,10 @@ public class CreateDecoHandler(IDbContextFactory<TvContext> dbContextFactory) @@ -44,11 +44,10 @@ public class CreateDecoHandler(IDbContextFactory<TvContext> dbContextFactory)
return BaseError.New($"Deco name \"{request.Name}\" is invalid");
}
Option<Deco> maybeExisting = await dbContext.Decos
.FirstOrDefaultAsync(r => r.DecoGroupId == request.DecoGroupId && r.Name == request.Name)
.Map(Optional);
bool duplicateName = await dbContext.Decos
.AnyAsync(r => r.DecoGroupId == request.DecoGroupId && r.Name == request.Name);
return maybeExisting.IsSome
return duplicateName
? BaseError.New($"A deco named \"{request.Name}\" already exists in that deco group")
: Success<BaseError, string>(request.Name);
}

10
ErsatzTV.Application/Scheduling/Commands/CreateDecoTemplateGroupHandler.cs

@ -38,12 +38,12 @@ public class CreateDecoTemplateGroupHandler(IDbContextFactory<TvContext> dbConte @@ -38,12 +38,12 @@ public class CreateDecoTemplateGroupHandler(IDbContextFactory<TvContext> dbConte
Validation<BaseError, string> result1 = createDecoTemplateGroup.NotEmpty(c => c.Name)
.Bind(_ => createDecoTemplateGroup.NotLongerThan(50)(c => c.Name));
int duplicateNameCount = await dbContext.DecoTemplateGroups
.CountAsync(ps => ps.Name == createDecoTemplateGroup.Name);
bool duplicateName = await dbContext.DecoTemplateGroups
.AnyAsync(ps => ps.Name == createDecoTemplateGroup.Name);
var result2 = Optional(duplicateNameCount)
.Where(count => count == 0)
.ToValidation<BaseError>("Deco template group name must be unique");
Validation<BaseError, Unit> result2 = duplicateName
? Fail<BaseError, Unit>("Deco template group name must be unique")
: Success<BaseError, Unit>(Unit.Default);
return (result1, result2).Apply((_, _) => createDecoTemplateGroup.Name);
}

7
ErsatzTV.Application/Scheduling/Commands/CreateDecoTemplateHandler.cs

@ -43,11 +43,10 @@ public class CreateDecoTemplateHandler(IDbContextFactory<TvContext> dbContextFac @@ -43,11 +43,10 @@ public class CreateDecoTemplateHandler(IDbContextFactory<TvContext> dbContextFac
return BaseError.New($"Deco template name \"{request.Name}\" is invalid");
}
Option<DecoTemplate> maybeExisting = await dbContext.DecoTemplates
.FirstOrDefaultAsync(r => r.DecoTemplateGroupId == request.DecoTemplateGroupId && r.Name == request.Name)
.Map(Optional);
bool duplicateName = await dbContext.DecoTemplates
.AnyAsync(r => r.DecoTemplateGroupId == request.DecoTemplateGroupId && r.Name == request.Name);
return maybeExisting.IsSome
return duplicateName
? BaseError.New($"A deco template named \"{request.Name}\" already exists in that deco template group")
: Success<BaseError, string>(request.Name);
}

10
ErsatzTV.Application/Scheduling/Commands/CreateTemplateGroupHandler.cs

@ -38,12 +38,12 @@ public class CreateTemplateGroupHandler(IDbContextFactory<TvContext> dbContextFa @@ -38,12 +38,12 @@ public class CreateTemplateGroupHandler(IDbContextFactory<TvContext> dbContextFa
Validation<BaseError, string> result1 = createTemplateGroup.NotEmpty(c => c.Name)
.Bind(_ => createTemplateGroup.NotLongerThan(50)(c => c.Name));
int duplicateNameCount = await dbContext.TemplateGroups
.CountAsync(ps => ps.Name == createTemplateGroup.Name);
bool duplicateName = await dbContext.TemplateGroups
.AnyAsync(ps => ps.Name == createTemplateGroup.Name);
var result2 = Optional(duplicateNameCount)
.Where(count => count == 0)
.ToValidation<BaseError>("Template group name must be unique");
Validation<BaseError, Unit> result2 = duplicateName
? Fail<BaseError, Unit>("Template group name must be unique")
: Success<BaseError, Unit>(Unit.Default);
return (result1, result2).Apply((_, _) => createTemplateGroup.Name);
}

7
ErsatzTV.Application/Scheduling/Commands/CreateTemplateHandler.cs

@ -41,11 +41,10 @@ public class CreateTemplateHandler(IDbContextFactory<TvContext> dbContextFactory @@ -41,11 +41,10 @@ public class CreateTemplateHandler(IDbContextFactory<TvContext> dbContextFactory
return BaseError.New($"Template name \"{request.Name}\" is invalid");
}
Option<Template> maybeExisting = await dbContext.Templates
.FirstOrDefaultAsync(r => r.TemplateGroupId == request.TemplateGroupId && r.Name == request.Name)
.Map(Optional);
bool duplicateName = await dbContext.Templates
.AnyAsync(r => r.TemplateGroupId == request.TemplateGroupId && r.Name == request.Name);
return maybeExisting.IsSome
return duplicateName
? BaseError.New($"A template named \"{request.Name}\" already exists in that template group")
: Success<BaseError, string>(request.Name);
}

9
ErsatzTV.Application/Scheduling/Commands/UpdateDecoHandler.cs

@ -206,13 +206,10 @@ public class UpdateDecoHandler(IDbContextFactory<TvContext> dbContextFactory) @@ -206,13 +206,10 @@ public class UpdateDecoHandler(IDbContextFactory<TvContext> dbContextFactory)
return BaseError.New($"Deco name \"{request.Name}\" is invalid");
}
Option<Deco> maybeExisting = await dbContext.Decos
.AsNoTracking()
.FirstOrDefaultAsync(d =>
d.Id != request.DecoId && d.DecoGroupId == request.DecoGroupId && d.Name == request.Name)
.Map(Optional);
bool duplicateName = await dbContext.Decos
.AnyAsync(d => d.Id != request.DecoId && d.DecoGroupId == request.DecoGroupId && d.Name == request.Name);
return maybeExisting.IsSome
return duplicateName
? BaseError.New($"A deco named \"{request.Name}\" already exists in that deco group")
: Success<BaseError, string>(request.Name);
}

6
ErsatzTV.Application/Search/Queries/SearchArtistsHandler.cs

@ -13,10 +13,8 @@ public class SearchArtistsHandler(IDbContextFactory<TvContext> dbContextFactory) @@ -13,10 +13,8 @@ public class SearchArtistsHandler(IDbContextFactory<TvContext> dbContextFactory)
await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken);
return await dbContext.ArtistMetadata
.AsNoTracking()
.Where(a => EF.Functions.Like(
EF.Functions.Collate(a.Title, TvContext.CaseInsensitiveCollation),
$"%{request.Query}%"))
.OrderBy(a => EF.Functions.Collate(a.Title, TvContext.CaseInsensitiveCollation))
.Where(a => EF.Functions.Like(a.Title, $"%{request.Query}%"))
.OrderBy(a => a.Title)
.Take(10)
.ToListAsync(cancellationToken)
.Map(list => list.Bind(a => ToNamedMediaItem(a)).ToList());

6
ErsatzTV.Application/Search/Queries/SearchCollectionsHandler.cs

@ -15,10 +15,8 @@ public class SearchCollectionsHandler(IDbContextFactory<TvContext> dbContextFact @@ -15,10 +15,8 @@ public class SearchCollectionsHandler(IDbContextFactory<TvContext> dbContextFact
await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken);
return await dbContext.Collections
.AsNoTracking()
.Where(c => EF.Functions.Like(
EF.Functions.Collate(c.Name, TvContext.CaseInsensitiveCollation),
$"%{request.Query}%"))
.OrderBy(c => EF.Functions.Collate(c.Name, TvContext.CaseInsensitiveCollation))
.Where(c => EF.Functions.Like(c.Name, $"%{request.Query}%"))
.OrderBy(c => c.Name)
.Take(10)
.ToListAsync(cancellationToken)
.Map(list => list.Map(ProjectToViewModel).ToList());

8
ErsatzTV.Application/Search/Queries/SearchMoviesHandler.cs

@ -14,11 +14,9 @@ public class SearchMoviesHandler(IDbContextFactory<TvContext> dbContextFactory) @@ -14,11 +14,9 @@ public class SearchMoviesHandler(IDbContextFactory<TvContext> dbContextFactory)
await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken);
return await dbContext.MovieMetadata
.AsNoTracking()
.Where(s => EF.Functions.Like(
EF.Functions.Collate(s.Title + " " + s.Year, TvContext.CaseInsensitiveCollation),
$"%{request.Query}%"))
.OrderBy(a => EF.Functions.Collate(a.Title, TvContext.CaseInsensitiveCollation))
.ThenBy(s => s.Year)
.Where(m => EF.Functions.Like(m.Title + " " + m.Year, $"%{request.Query}%"))
.OrderBy(m => m.Title)
.ThenBy(m => m.Year)
.Take(10)
.ToListAsync(cancellationToken)
.Map(list => list.Map(ToNamedMediaItem).ToList());

6
ErsatzTV.Application/Search/Queries/SearchMultiCollectionsHandler.cs

@ -15,10 +15,8 @@ public class SearchMultiCollectionsHandler(IDbContextFactory<TvContext> dbContex @@ -15,10 +15,8 @@ public class SearchMultiCollectionsHandler(IDbContextFactory<TvContext> dbContex
await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken);
return await dbContext.MultiCollections
.AsNoTracking()
.Where(c => EF.Functions.Like(
EF.Functions.Collate(c.Name, TvContext.CaseInsensitiveCollation),
$"%{request.Query}%"))
.OrderBy(c => EF.Functions.Collate(c.Name, TvContext.CaseInsensitiveCollation))
.Where(mc => EF.Functions.Like(mc.Name, $"%{request.Query}%"))
.OrderBy(mc => mc.Name)
.Take(10)
.ToListAsync(cancellationToken)
.Map(list => list.Map(ProjectToViewModel).ToList());

6
ErsatzTV.Application/Search/Queries/SearchRerunCollectionsHandler.cs

@ -15,10 +15,8 @@ public class SearchRerunCollectionsHandler(IDbContextFactory<TvContext> dbContex @@ -15,10 +15,8 @@ public class SearchRerunCollectionsHandler(IDbContextFactory<TvContext> dbContex
await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken);
return await dbContext.RerunCollections
.AsNoTracking()
.Where(c => EF.Functions.Like(
EF.Functions.Collate(c.Name, TvContext.CaseInsensitiveCollation),
$"%{request.Query}%"))
.OrderBy(c => EF.Functions.Collate(c.Name, TvContext.CaseInsensitiveCollation))
.Where(rc => EF.Functions.Like(rc.Name, $"%{request.Query}%"))
.OrderBy(rc => rc.Name)
.Take(10)
.ToListAsync(cancellationToken)
.Map(list => list.Map(ProjectToViewModel).ToList());

6
ErsatzTV.Application/Search/Queries/SearchSmartCollectionsHandler.cs

@ -15,10 +15,8 @@ public class SearchSmartCollectionsHandler(IDbContextFactory<TvContext> dbContex @@ -15,10 +15,8 @@ public class SearchSmartCollectionsHandler(IDbContextFactory<TvContext> dbContex
await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken);
return await dbContext.SmartCollections
.AsNoTracking()
.Where(c => EF.Functions.Like(
EF.Functions.Collate(c.Name, TvContext.CaseInsensitiveCollation),
$"%{request.Query}%"))
.OrderBy(c => EF.Functions.Collate(c.Name, TvContext.CaseInsensitiveCollation))
.Where(sc => EF.Functions.Like(sc.Name, $"%{request.Query}%"))
.OrderBy(sc => sc.Name)
.Take(10)
.ToListAsync(cancellationToken)
.Map(list => list.Map(ProjectToViewModel).ToList());

3
ErsatzTV.Application/Search/Queries/SearchTelevisionSeasonsHandler.cs

@ -20,8 +20,7 @@ public class SearchTelevisionSeasonsHandler(IDbContextFactory<TvContext> dbConte @@ -20,8 +20,7 @@ public class SearchTelevisionSeasonsHandler(IDbContextFactory<TvContext> dbConte
join showMetadata in dbContext.Set<ShowMetadata>()
on season.ShowId equals showMetadata.ShowId
where EF.Functions.Like(showMetadata.Title + " " + seasonMetadata.Title, $"%{request.Query}%")
orderby EF.Functions.Collate(showMetadata.Title, TvContext.CaseInsensitiveCollation), season
.SeasonNumber
orderby showMetadata.Title, season.SeasonNumber
select new TelevisionSeason(season.Id, showMetadata.Title, showMetadata.Year, season.SeasonNumber))
.Take(20)
.ToListAsync(cancellationToken)

6
ErsatzTV.Application/Search/Queries/SearchTelevisionShowsHandler.cs

@ -16,10 +16,8 @@ public class SearchTelevisionShowsHandler(IDbContextFactory<TvContext> dbContext @@ -16,10 +16,8 @@ public class SearchTelevisionShowsHandler(IDbContextFactory<TvContext> dbContext
await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken);
return await dbContext.ShowMetadata
.AsNoTracking()
.Where(s => EF.Functions.Like(
EF.Functions.Collate(s.Title + " " + s.Year, TvContext.CaseInsensitiveCollation),
$"%{request.Query}%"))
.OrderBy(s => EF.Functions.Collate(s.Title, TvContext.CaseInsensitiveCollation))
.Where(s => EF.Functions.Like(s.Title + " " + s.Year, $"%{request.Query}%"))
.OrderBy(s => s.Title)
.ThenBy(s => s.Year)
.Take(10)
.ToListAsync(cancellationToken)

19
ErsatzTV.Application/Watermarks/Commands/CopyWatermarkHandler.cs

@ -45,12 +45,23 @@ public class CopyWatermarkHandler(IDbContextFactory<TvContext> dbContextFactory, @@ -45,12 +45,23 @@ public class CopyWatermarkHandler(IDbContextFactory<TvContext> dbContextFactory,
TvContext dbContext,
CopyWatermark request,
CancellationToken cancellationToken) =>
(ValidateName(request), await WatermarkMustExist(dbContext, request, cancellationToken))
(await ValidateName(dbContext, request), await WatermarkMustExist(dbContext, request, cancellationToken))
.Apply((name, watermark) => new CopyWatermarkParameters(name, watermark));
private static Validation<BaseError, string> ValidateName(CopyWatermark request) =>
request.NotEmpty(x => x.Name)
.Bind(_ => request.NotLongerThan(50)(x => x.Name));
private static async Task<Validation<BaseError, string>> ValidateName(TvContext dbContext, CopyWatermark request)
{
Validation<BaseError, string> result1 = request.NotEmpty(c => c.Name)
.Bind(_ => request.NotLongerThan(50)(c => c.Name));
bool duplicateName = await dbContext.ChannelWatermarks
.AnyAsync(wm => wm.Name == request.Name);
Validation<BaseError, Unit> result2 = duplicateName
? Fail<BaseError, Unit>("ChannelWatermark name must be unique")
: Success<BaseError, Unit>(Unit.Default);
return (result1, result2).Apply((_, _) => request.Name);
}
private static Task<Validation<BaseError, ChannelWatermark>> WatermarkMustExist(
TvContext dbContext,

25
ErsatzTV.Application/Watermarks/Commands/CreateWatermarkHandler.cs

@ -22,7 +22,7 @@ public class CreateWatermarkHandler : IRequestHandler<CreateWatermark, Either<Ba @@ -22,7 +22,7 @@ public class CreateWatermarkHandler : IRequestHandler<CreateWatermark, Either<Ba
CancellationToken cancellationToken)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken);
Validation<BaseError, ChannelWatermark> validation = Validate(request);
Validation<BaseError, ChannelWatermark> validation = await Validate(dbContext, request);
return await validation.Apply(profile => PersistChannelWatermark(dbContext, profile));
}
@ -36,8 +36,10 @@ public class CreateWatermarkHandler : IRequestHandler<CreateWatermark, Either<Ba @@ -36,8 +36,10 @@ public class CreateWatermarkHandler : IRequestHandler<CreateWatermark, Either<Ba
return new CreateWatermarkResult(watermark.Id);
}
private static Validation<BaseError, ChannelWatermark> Validate(CreateWatermark request) =>
ValidateName(request)
private static async Task<Validation<BaseError, ChannelWatermark>> Validate(
TvContext dbContext,
CreateWatermark request) =>
await ValidateName(dbContext, request)
.Map(_ =>
{
var watermark = new ChannelWatermark
@ -69,7 +71,18 @@ public class CreateWatermarkHandler : IRequestHandler<CreateWatermark, Either<Ba @@ -69,7 +71,18 @@ public class CreateWatermarkHandler : IRequestHandler<CreateWatermark, Either<Ba
return watermark;
});
private static Validation<BaseError, string> ValidateName(CreateWatermark request) =>
request.NotEmpty(x => x.Name)
.Bind(_ => request.NotLongerThan(50)(x => x.Name));
private static async Task<Validation<BaseError, string>> ValidateName(TvContext dbContext, CreateWatermark request)
{
Validation<BaseError, string> result1 = request.NotEmpty(c => c.Name)
.Bind(_ => request.NotLongerThan(50)(c => c.Name));
bool duplicateName = await dbContext.ChannelWatermarks
.AnyAsync(wm => wm.Name == request.Name);
Validation<BaseError, Unit> result2 = duplicateName
? Fail<BaseError, Unit>("ChannelWatermark name must be unique")
: Success<BaseError, Unit>(Unit.Default);
return (result1, result2).Apply((_, _) => request.Name);
}
}

21
ErsatzTV.Application/Watermarks/Commands/UpdateWatermarkHandler.cs

@ -65,7 +65,7 @@ public class UpdateWatermarkHandler : IRequestHandler<UpdateWatermark, Either<Ba @@ -65,7 +65,7 @@ public class UpdateWatermarkHandler : IRequestHandler<UpdateWatermark, Either<Ba
TvContext dbContext,
UpdateWatermark request,
CancellationToken cancellationToken) =>
(await WatermarkMustExist(dbContext, request, cancellationToken), ValidateName(request))
(await WatermarkMustExist(dbContext, request, cancellationToken), await ValidateName(dbContext, request))
.Apply((watermark, _) => watermark);
private static Task<Validation<BaseError, ChannelWatermark>> WatermarkMustExist(
@ -76,7 +76,20 @@ public class UpdateWatermarkHandler : IRequestHandler<UpdateWatermark, Either<Ba @@ -76,7 +76,20 @@ public class UpdateWatermarkHandler : IRequestHandler<UpdateWatermark, Either<Ba
.SelectOneAsync(p => p.Id, p => p.Id == updateWatermark.Id, cancellationToken)
.Map(o => o.ToValidation<BaseError>("Watermark does not exist."));
private static Validation<BaseError, string> ValidateName(UpdateWatermark updateWatermark) =>
updateWatermark.NotEmpty(x => x.Name)
.Bind(_ => updateWatermark.NotLongerThan(50)(x => x.Name));
private static async Task<Validation<BaseError, string>> ValidateName(
TvContext dbContext,
UpdateWatermark updateWatermark)
{
bool duplicateName = await dbContext.ChannelWatermarks
.AnyAsync(wm => wm.Id != updateWatermark.Id && wm.Name == updateWatermark.Name);
Validation<BaseError, Unit> result2 = duplicateName
? Fail<BaseError, Unit>("ChannelWatermark name must be unique")
: Success<BaseError, Unit>(Unit.Default);
Validation<BaseError, string> result1 = updateWatermark.NotEmpty(c => c.Name)
.Bind(_ => updateWatermark.NotLongerThan(50)(c => c.Name));
return (result1, result2).Apply((_, _) => updateWatermark.Name);
}
}

6987
ErsatzTV.Infrastructure.MySql/Migrations/20260102150305_Update_CaseSensitivity.Designer.cs generated

File diff suppressed because it is too large Load Diff

679
ErsatzTV.Infrastructure.MySql/Migrations/20260102150305_Update_CaseSensitivity.cs

@ -0,0 +1,679 @@ @@ -0,0 +1,679 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace ErsatzTV.Infrastructure.MySql.Migrations
{
/// <inheritdoc />
public partial class Update_CaseSensitivity : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "TraktList",
type: "varchar(255)",
nullable: true,
collation: "utf8mb4_general_ci",
oldClrType: typeof(string),
oldType: "longtext",
oldNullable: true)
.Annotation("MySql:CharSet", "utf8mb4")
.OldAnnotation("MySql:CharSet", "utf8mb4");
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "TemplateGroup",
type: "varchar(50)",
maxLength: 50,
nullable: true,
collation: "utf8mb4_general_ci",
oldClrType: typeof(string),
oldType: "varchar(255)",
oldNullable: true)
.Annotation("MySql:CharSet", "utf8mb4")
.OldAnnotation("MySql:CharSet", "utf8mb4");
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "Template",
type: "varchar(50)",
maxLength: 50,
nullable: true,
collation: "utf8mb4_general_ci",
oldClrType: typeof(string),
oldType: "varchar(255)",
oldNullable: true)
.Annotation("MySql:CharSet", "utf8mb4")
.OldAnnotation("MySql:CharSet", "utf8mb4");
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "SmartCollection",
type: "varchar(50)",
maxLength: 50,
nullable: true,
collation: "utf8mb4_general_ci",
oldClrType: typeof(string),
oldType: "varchar(255)",
oldNullable: true,
oldCollation: "utf8mb4_general_ci")
.Annotation("MySql:CharSet", "utf8mb4")
.OldAnnotation("MySql:CharSet", "utf8mb4");
migrationBuilder.AlterColumn<string>(
name: "Title",
table: "ShowMetadata",
type: "varchar(255)",
nullable: true,
collation: "utf8mb4_general_ci",
oldClrType: typeof(string),
oldType: "longtext",
oldNullable: true)
.Annotation("MySql:CharSet", "utf8mb4")
.OldAnnotation("MySql:CharSet", "utf8mb4");
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "RerunCollection",
type: "varchar(50)",
maxLength: 50,
nullable: true,
collation: "utf8mb4_general_ci",
oldClrType: typeof(string),
oldType: "longtext",
oldNullable: true)
.Annotation("MySql:CharSet", "utf8mb4")
.OldAnnotation("MySql:CharSet", "utf8mb4");
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "ProgramSchedule",
type: "varchar(50)",
maxLength: 50,
nullable: true,
collation: "utf8mb4_general_ci",
oldClrType: typeof(string),
oldType: "varchar(255)",
oldNullable: true)
.Annotation("MySql:CharSet", "utf8mb4")
.OldAnnotation("MySql:CharSet", "utf8mb4");
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "Playlist",
type: "varchar(50)",
maxLength: 50,
nullable: true,
collation: "utf8mb4_general_ci",
oldClrType: typeof(string),
oldType: "varchar(255)",
oldNullable: true)
.Annotation("MySql:CharSet", "utf8mb4")
.OldAnnotation("MySql:CharSet", "utf8mb4");
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "MultiCollection",
type: "varchar(50)",
maxLength: 50,
nullable: true,
collation: "utf8mb4_general_ci",
oldClrType: typeof(string),
oldType: "longtext",
oldNullable: true)
.Annotation("MySql:CharSet", "utf8mb4")
.OldAnnotation("MySql:CharSet", "utf8mb4");
migrationBuilder.AlterColumn<string>(
name: "Title",
table: "MovieMetadata",
type: "varchar(255)",
nullable: true,
collation: "utf8mb4_general_ci",
oldClrType: typeof(string),
oldType: "longtext",
oldNullable: true)
.Annotation("MySql:CharSet", "utf8mb4")
.OldAnnotation("MySql:CharSet", "utf8mb4");
migrationBuilder.AlterColumn<string>(
name: "Guid",
table: "MetadataGuid",
type: "varchar(128)",
maxLength: 128,
nullable: true,
collation: "utf8mb4_general_ci",
oldClrType: typeof(string),
oldType: "longtext",
oldNullable: true)
.Annotation("MySql:CharSet", "utf8mb4")
.OldAnnotation("MySql:CharSet", "utf8mb4");
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "FillerPreset",
type: "varchar(50)",
maxLength: 50,
nullable: true,
collation: "utf8mb4_general_ci",
oldClrType: typeof(string),
oldType: "longtext",
oldNullable: true)
.Annotation("MySql:CharSet", "utf8mb4")
.OldAnnotation("MySql:CharSet", "utf8mb4");
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "DecoTemplateGroup",
type: "varchar(50)",
maxLength: 50,
nullable: true,
collation: "utf8mb4_general_ci",
oldClrType: typeof(string),
oldType: "varchar(255)",
oldNullable: true)
.Annotation("MySql:CharSet", "utf8mb4")
.OldAnnotation("MySql:CharSet", "utf8mb4");
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "DecoTemplate",
type: "varchar(50)",
maxLength: 50,
nullable: true,
collation: "utf8mb4_general_ci",
oldClrType: typeof(string),
oldType: "varchar(255)",
oldNullable: true)
.Annotation("MySql:CharSet", "utf8mb4")
.OldAnnotation("MySql:CharSet", "utf8mb4");
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "DecoGroup",
type: "varchar(50)",
maxLength: 50,
nullable: true,
collation: "utf8mb4_general_ci",
oldClrType: typeof(string),
oldType: "varchar(255)",
oldNullable: true)
.Annotation("MySql:CharSet", "utf8mb4")
.OldAnnotation("MySql:CharSet", "utf8mb4");
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "Deco",
type: "varchar(50)",
maxLength: 50,
nullable: true,
collation: "utf8mb4_general_ci",
oldClrType: typeof(string),
oldType: "varchar(255)",
oldNullable: true)
.Annotation("MySql:CharSet", "utf8mb4")
.OldAnnotation("MySql:CharSet", "utf8mb4");
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "Collection",
type: "varchar(50)",
maxLength: 50,
nullable: true,
collation: "utf8mb4_general_ci",
oldClrType: typeof(string),
oldType: "longtext",
oldNullable: true)
.Annotation("MySql:CharSet", "utf8mb4")
.OldAnnotation("MySql:CharSet", "utf8mb4");
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "ChannelWatermark",
type: "varchar(50)",
maxLength: 50,
nullable: true,
collation: "utf8mb4_general_ci",
oldClrType: typeof(string),
oldType: "longtext",
oldNullable: true)
.Annotation("MySql:CharSet", "utf8mb4")
.OldAnnotation("MySql:CharSet", "utf8mb4");
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "Channel",
type: "varchar(50)",
maxLength: 50,
nullable: true,
collation: "utf8mb4_general_ci",
oldClrType: typeof(string),
oldType: "longtext",
oldNullable: true)
.Annotation("MySql:CharSet", "utf8mb4")
.OldAnnotation("MySql:CharSet", "utf8mb4");
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "BlockGroup",
type: "varchar(50)",
maxLength: 50,
nullable: true,
collation: "utf8mb4_general_ci",
oldClrType: typeof(string),
oldType: "varchar(255)",
oldNullable: true)
.Annotation("MySql:CharSet", "utf8mb4")
.OldAnnotation("MySql:CharSet", "utf8mb4");
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "Block",
type: "varchar(50)",
maxLength: 50,
nullable: true,
collation: "utf8mb4_general_ci",
oldClrType: typeof(string),
oldType: "varchar(255)",
oldNullable: true)
.Annotation("MySql:CharSet", "utf8mb4")
.OldAnnotation("MySql:CharSet", "utf8mb4");
migrationBuilder.AlterColumn<string>(
name: "Title",
table: "ArtistMetadata",
type: "varchar(255)",
nullable: true,
collation: "utf8mb4_general_ci",
oldClrType: typeof(string),
oldType: "longtext",
oldNullable: true)
.Annotation("MySql:CharSet", "utf8mb4")
.OldAnnotation("MySql:CharSet", "utf8mb4");
migrationBuilder.CreateIndex(
name: "IX_TraktList_Name",
table: "TraktList",
column: "Name");
migrationBuilder.CreateIndex(
name: "IX_ShowMetadata_Title",
table: "ShowMetadata",
column: "Title");
migrationBuilder.CreateIndex(
name: "IX_RerunCollection_Name",
table: "RerunCollection",
column: "Name",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_MultiCollection_Name",
table: "MultiCollection",
column: "Name",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_MovieMetadata_Title",
table: "MovieMetadata",
column: "Title");
migrationBuilder.CreateIndex(
name: "IX_MetadataGuid_Guid",
table: "MetadataGuid",
column: "Guid");
migrationBuilder.CreateIndex(
name: "IX_FillerPreset_Name",
table: "FillerPreset",
column: "Name",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_Collection_Name",
table: "Collection",
column: "Name",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_ChannelWatermark_Name",
table: "ChannelWatermark",
column: "Name",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_ArtistMetadata_Title",
table: "ArtistMetadata",
column: "Title");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropIndex(
name: "IX_TraktList_Name",
table: "TraktList");
migrationBuilder.DropIndex(
name: "IX_ShowMetadata_Title",
table: "ShowMetadata");
migrationBuilder.DropIndex(
name: "IX_RerunCollection_Name",
table: "RerunCollection");
migrationBuilder.DropIndex(
name: "IX_MultiCollection_Name",
table: "MultiCollection");
migrationBuilder.DropIndex(
name: "IX_MovieMetadata_Title",
table: "MovieMetadata");
migrationBuilder.DropIndex(
name: "IX_MetadataGuid_Guid",
table: "MetadataGuid");
migrationBuilder.DropIndex(
name: "IX_FillerPreset_Name",
table: "FillerPreset");
migrationBuilder.DropIndex(
name: "IX_Collection_Name",
table: "Collection");
migrationBuilder.DropIndex(
name: "IX_ChannelWatermark_Name",
table: "ChannelWatermark");
migrationBuilder.DropIndex(
name: "IX_ArtistMetadata_Title",
table: "ArtistMetadata");
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "TraktList",
type: "longtext",
nullable: true,
oldClrType: typeof(string),
oldType: "varchar(255)",
oldNullable: true,
oldCollation: "utf8mb4_general_ci")
.Annotation("MySql:CharSet", "utf8mb4")
.OldAnnotation("MySql:CharSet", "utf8mb4");
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "TemplateGroup",
type: "varchar(255)",
nullable: true,
oldClrType: typeof(string),
oldType: "varchar(50)",
oldMaxLength: 50,
oldNullable: true,
oldCollation: "utf8mb4_general_ci")
.Annotation("MySql:CharSet", "utf8mb4")
.OldAnnotation("MySql:CharSet", "utf8mb4");
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "Template",
type: "varchar(255)",
nullable: true,
oldClrType: typeof(string),
oldType: "varchar(50)",
oldMaxLength: 50,
oldNullable: true,
oldCollation: "utf8mb4_general_ci")
.Annotation("MySql:CharSet", "utf8mb4")
.OldAnnotation("MySql:CharSet", "utf8mb4");
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "SmartCollection",
type: "varchar(255)",
nullable: true,
collation: "utf8mb4_general_ci",
oldClrType: typeof(string),
oldType: "varchar(50)",
oldMaxLength: 50,
oldNullable: true,
oldCollation: "utf8mb4_general_ci")
.Annotation("MySql:CharSet", "utf8mb4")
.OldAnnotation("MySql:CharSet", "utf8mb4");
migrationBuilder.AlterColumn<string>(
name: "Title",
table: "ShowMetadata",
type: "longtext",
nullable: true,
oldClrType: typeof(string),
oldType: "varchar(255)",
oldNullable: true,
oldCollation: "utf8mb4_general_ci")
.Annotation("MySql:CharSet", "utf8mb4")
.OldAnnotation("MySql:CharSet", "utf8mb4");
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "RerunCollection",
type: "longtext",
nullable: true,
oldClrType: typeof(string),
oldType: "varchar(50)",
oldMaxLength: 50,
oldNullable: true,
oldCollation: "utf8mb4_general_ci")
.Annotation("MySql:CharSet", "utf8mb4")
.OldAnnotation("MySql:CharSet", "utf8mb4");
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "ProgramSchedule",
type: "varchar(255)",
nullable: true,
oldClrType: typeof(string),
oldType: "varchar(50)",
oldMaxLength: 50,
oldNullable: true,
oldCollation: "utf8mb4_general_ci")
.Annotation("MySql:CharSet", "utf8mb4")
.OldAnnotation("MySql:CharSet", "utf8mb4");
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "Playlist",
type: "varchar(255)",
nullable: true,
oldClrType: typeof(string),
oldType: "varchar(50)",
oldMaxLength: 50,
oldNullable: true,
oldCollation: "utf8mb4_general_ci")
.Annotation("MySql:CharSet", "utf8mb4")
.OldAnnotation("MySql:CharSet", "utf8mb4");
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "MultiCollection",
type: "longtext",
nullable: true,
oldClrType: typeof(string),
oldType: "varchar(50)",
oldMaxLength: 50,
oldNullable: true,
oldCollation: "utf8mb4_general_ci")
.Annotation("MySql:CharSet", "utf8mb4")
.OldAnnotation("MySql:CharSet", "utf8mb4");
migrationBuilder.AlterColumn<string>(
name: "Title",
table: "MovieMetadata",
type: "longtext",
nullable: true,
oldClrType: typeof(string),
oldType: "varchar(255)",
oldNullable: true,
oldCollation: "utf8mb4_general_ci")
.Annotation("MySql:CharSet", "utf8mb4")
.OldAnnotation("MySql:CharSet", "utf8mb4");
migrationBuilder.AlterColumn<string>(
name: "Guid",
table: "MetadataGuid",
type: "longtext",
nullable: true,
oldClrType: typeof(string),
oldType: "varchar(128)",
oldMaxLength: 128,
oldNullable: true,
oldCollation: "utf8mb4_general_ci")
.Annotation("MySql:CharSet", "utf8mb4")
.OldAnnotation("MySql:CharSet", "utf8mb4");
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "FillerPreset",
type: "longtext",
nullable: true,
oldClrType: typeof(string),
oldType: "varchar(50)",
oldMaxLength: 50,
oldNullable: true,
oldCollation: "utf8mb4_general_ci")
.Annotation("MySql:CharSet", "utf8mb4")
.OldAnnotation("MySql:CharSet", "utf8mb4");
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "DecoTemplateGroup",
type: "varchar(255)",
nullable: true,
oldClrType: typeof(string),
oldType: "varchar(50)",
oldMaxLength: 50,
oldNullable: true,
oldCollation: "utf8mb4_general_ci")
.Annotation("MySql:CharSet", "utf8mb4")
.OldAnnotation("MySql:CharSet", "utf8mb4");
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "DecoTemplate",
type: "varchar(255)",
nullable: true,
oldClrType: typeof(string),
oldType: "varchar(50)",
oldMaxLength: 50,
oldNullable: true,
oldCollation: "utf8mb4_general_ci")
.Annotation("MySql:CharSet", "utf8mb4")
.OldAnnotation("MySql:CharSet", "utf8mb4");
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "DecoGroup",
type: "varchar(255)",
nullable: true,
oldClrType: typeof(string),
oldType: "varchar(50)",
oldMaxLength: 50,
oldNullable: true,
oldCollation: "utf8mb4_general_ci")
.Annotation("MySql:CharSet", "utf8mb4")
.OldAnnotation("MySql:CharSet", "utf8mb4");
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "Deco",
type: "varchar(255)",
nullable: true,
oldClrType: typeof(string),
oldType: "varchar(50)",
oldMaxLength: 50,
oldNullable: true,
oldCollation: "utf8mb4_general_ci")
.Annotation("MySql:CharSet", "utf8mb4")
.OldAnnotation("MySql:CharSet", "utf8mb4");
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "Collection",
type: "longtext",
nullable: true,
oldClrType: typeof(string),
oldType: "varchar(50)",
oldMaxLength: 50,
oldNullable: true,
oldCollation: "utf8mb4_general_ci")
.Annotation("MySql:CharSet", "utf8mb4")
.OldAnnotation("MySql:CharSet", "utf8mb4");
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "ChannelWatermark",
type: "longtext",
nullable: true,
oldClrType: typeof(string),
oldType: "varchar(50)",
oldMaxLength: 50,
oldNullable: true,
oldCollation: "utf8mb4_general_ci")
.Annotation("MySql:CharSet", "utf8mb4")
.OldAnnotation("MySql:CharSet", "utf8mb4");
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "Channel",
type: "longtext",
nullable: true,
oldClrType: typeof(string),
oldType: "varchar(50)",
oldMaxLength: 50,
oldNullable: true,
oldCollation: "utf8mb4_general_ci")
.Annotation("MySql:CharSet", "utf8mb4")
.OldAnnotation("MySql:CharSet", "utf8mb4");
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "BlockGroup",
type: "varchar(255)",
nullable: true,
oldClrType: typeof(string),
oldType: "varchar(50)",
oldMaxLength: 50,
oldNullable: true,
oldCollation: "utf8mb4_general_ci")
.Annotation("MySql:CharSet", "utf8mb4")
.OldAnnotation("MySql:CharSet", "utf8mb4");
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "Block",
type: "varchar(255)",
nullable: true,
oldClrType: typeof(string),
oldType: "varchar(50)",
oldMaxLength: 50,
oldNullable: true,
oldCollation: "utf8mb4_general_ci")
.Annotation("MySql:CharSet", "utf8mb4")
.OldAnnotation("MySql:CharSet", "utf8mb4");
migrationBuilder.AlterColumn<string>(
name: "Title",
table: "ArtistMetadata",
type: "longtext",
nullable: true,
oldClrType: typeof(string),
oldType: "varchar(255)",
oldNullable: true,
oldCollation: "utf8mb4_general_ci")
.Annotation("MySql:CharSet", "utf8mb4")
.OldAnnotation("MySql:CharSet", "utf8mb4");
}
}
}

108
ErsatzTV.Infrastructure.MySql/Migrations/TvContextModelSnapshot.cs

@ -139,7 +139,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations @@ -139,7 +139,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations
.HasColumnType("longtext");
b.Property<string>("Title")
.HasColumnType("longtext");
.HasColumnType("varchar(255)")
.UseCollation("utf8mb4_general_ci");
b.Property<int?>("Year")
.HasColumnType("int");
@ -148,6 +149,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations @@ -148,6 +149,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations
b.HasIndex("ArtistId");
b.HasIndex("Title");
b.ToTable("ArtistMetadata", (string)null);
});
@ -317,7 +320,9 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations @@ -317,7 +320,9 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations
.HasColumnType("longtext");
b.Property<string>("Name")
.HasColumnType("longtext");
.HasMaxLength(50)
.HasColumnType("varchar(50)")
.UseCollation("utf8mb4_general_ci");
b.Property<string>("Number")
.HasColumnType("varchar(255)");
@ -418,7 +423,9 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations @@ -418,7 +423,9 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations
.HasColumnType("int");
b.Property<string>("Name")
.HasColumnType("longtext");
.HasMaxLength(50)
.HasColumnType("varchar(50)")
.UseCollation("utf8mb4_general_ci");
b.Property<int>("Opacity")
.HasColumnType("int");
@ -446,6 +453,9 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations @@ -446,6 +453,9 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations
b.HasKey("Id");
b.HasIndex("Name")
.IsUnique();
b.ToTable("ChannelWatermark", (string)null);
});
@ -458,13 +468,18 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations @@ -458,13 +468,18 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
b.Property<string>("Name")
.HasColumnType("longtext");
.HasMaxLength(50)
.HasColumnType("varchar(50)")
.UseCollation("utf8mb4_general_ci");
b.Property<bool>("UseCustomPlaybackOrder")
.HasColumnType("tinyint(1)");
b.HasKey("Id");
b.HasIndex("Name")
.IsUnique();
b.ToTable("Collection", (string)null);
});
@ -831,7 +846,9 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations @@ -831,7 +846,9 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations
.HasColumnType("int");
b.Property<string>("Name")
.HasColumnType("longtext");
.HasMaxLength(50)
.HasColumnType("varchar(50)")
.UseCollation("utf8mb4_general_ci");
b.Property<int?>("PadToNearestMinute")
.HasColumnType("int");
@ -853,6 +870,9 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations @@ -853,6 +870,9 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations
b.HasIndex("MultiCollectionId");
b.HasIndex("Name")
.IsUnique();
b.HasIndex("PlaylistId");
b.HasIndex("SmartCollectionId");
@ -1469,7 +1489,9 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations @@ -1469,7 +1489,9 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations
.HasColumnType("int");
b.Property<string>("Guid")
.HasColumnType("longtext");
.HasMaxLength(128)
.HasColumnType("varchar(128)")
.UseCollation("utf8mb4_general_ci");
b.Property<int?>("ImageMetadataId")
.HasColumnType("int");
@ -1501,6 +1523,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations @@ -1501,6 +1523,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations
b.HasIndex("EpisodeMetadataId");
b.HasIndex("Guid");
b.HasIndex("ImageMetadataId");
b.HasIndex("MovieMetadataId");
@ -1583,7 +1607,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations @@ -1583,7 +1607,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations
.HasColumnType("longtext");
b.Property<string>("Title")
.HasColumnType("longtext");
.HasColumnType("varchar(255)")
.UseCollation("utf8mb4_general_ci");
b.Property<int?>("Year")
.HasColumnType("int");
@ -1592,6 +1617,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations @@ -1592,6 +1617,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations
b.HasIndex("MovieId");
b.HasIndex("Title");
b.ToTable("MovieMetadata", (string)null);
});
@ -1604,10 +1631,15 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations @@ -1604,10 +1631,15 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
b.Property<string>("Name")
.HasColumnType("longtext");
.HasMaxLength(50)
.HasColumnType("varchar(50)")
.UseCollation("utf8mb4_general_ci");
b.HasKey("Id");
b.HasIndex("Name")
.IsUnique();
b.ToTable("MultiCollection", (string)null);
});
@ -1791,7 +1823,9 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations @@ -1791,7 +1823,9 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations
.HasColumnType("tinyint(1)");
b.Property<string>("Name")
.HasColumnType("varchar(255)");
.HasMaxLength(50)
.HasColumnType("varchar(50)")
.UseCollation("utf8mb4_general_ci");
b.Property<int>("PlaylistGroupId")
.HasColumnType("int");
@ -2252,7 +2286,9 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations @@ -2252,7 +2286,9 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations
.HasColumnType("tinyint(1)");
b.Property<string>("Name")
.HasColumnType("varchar(255)");
.HasMaxLength(50)
.HasColumnType("varchar(50)")
.UseCollation("utf8mb4_general_ci");
b.Property<bool>("RandomStartPoint")
.HasColumnType("tinyint(1)");
@ -2540,7 +2576,9 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations @@ -2540,7 +2576,9 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations
.HasColumnType("int");
b.Property<string>("Name")
.HasColumnType("longtext");
.HasMaxLength(50)
.HasColumnType("varchar(50)")
.UseCollation("utf8mb4_general_ci");
b.Property<int>("RerunPlaybackOrder")
.HasColumnType("int");
@ -2556,6 +2594,9 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations @@ -2556,6 +2594,9 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations
b.HasIndex("MultiCollectionId");
b.HasIndex("Name")
.IsUnique();
b.HasIndex("SmartCollectionId");
b.ToTable("RerunCollection", (string)null);
@ -2606,7 +2647,9 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations @@ -2606,7 +2647,9 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations
.HasColumnType("int");
b.Property<string>("Name")
.HasColumnType("varchar(255)");
.HasMaxLength(50)
.HasColumnType("varchar(50)")
.UseCollation("utf8mb4_general_ci");
b.Property<int>("StopScheduling")
.HasColumnType("int");
@ -2628,7 +2671,9 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations @@ -2628,7 +2671,9 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
b.Property<string>("Name")
.HasColumnType("varchar(255)");
.HasMaxLength(50)
.HasColumnType("varchar(50)")
.UseCollation("utf8mb4_general_ci");
b.HasKey("Id");
@ -2754,7 +2799,9 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations @@ -2754,7 +2799,9 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations
.HasColumnType("int");
b.Property<string>("Name")
.HasColumnType("varchar(255)");
.HasMaxLength(50)
.HasColumnType("varchar(50)")
.UseCollation("utf8mb4_general_ci");
b.Property<bool>("UseGraphicsElementsDuringFiller")
.HasColumnType("tinyint(1)");
@ -2847,7 +2894,9 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations @@ -2847,7 +2894,9 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
b.Property<string>("Name")
.HasColumnType("varchar(255)");
.HasMaxLength(50)
.HasColumnType("varchar(50)")
.UseCollation("utf8mb4_general_ci");
b.HasKey("Id");
@ -2872,7 +2921,9 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations @@ -2872,7 +2921,9 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations
.HasColumnType("int");
b.Property<string>("Name")
.HasColumnType("varchar(255)");
.HasMaxLength(50)
.HasColumnType("varchar(50)")
.UseCollation("utf8mb4_general_ci");
b.HasKey("Id");
@ -2891,7 +2942,9 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations @@ -2891,7 +2942,9 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
b.Property<string>("Name")
.HasColumnType("varchar(255)");
.HasMaxLength(50)
.HasColumnType("varchar(50)")
.UseCollation("utf8mb4_general_ci");
b.HasKey("Id");
@ -3078,7 +3131,9 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations @@ -3078,7 +3131,9 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations
.HasColumnType("datetime(6)");
b.Property<string>("Name")
.HasColumnType("varchar(255)");
.HasMaxLength(50)
.HasColumnType("varchar(50)")
.UseCollation("utf8mb4_general_ci");
b.Property<int>("TemplateGroupId")
.HasColumnType("int");
@ -3100,7 +3155,9 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations @@ -3100,7 +3155,9 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
b.Property<string>("Name")
.HasColumnType("varchar(255)");
.HasMaxLength(50)
.HasColumnType("varchar(50)")
.UseCollation("utf8mb4_general_ci");
b.HasKey("Id");
@ -3223,7 +3280,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations @@ -3223,7 +3280,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations
.HasColumnType("longtext");
b.Property<string>("Title")
.HasColumnType("longtext");
.HasColumnType("varchar(255)")
.UseCollation("utf8mb4_general_ci");
b.Property<int?>("Year")
.HasColumnType("int");
@ -3232,6 +3290,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations @@ -3232,6 +3290,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations
b.HasIndex("ShowId");
b.HasIndex("Title");
b.ToTable("ShowMetadata", (string)null);
});
@ -3244,7 +3304,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations @@ -3244,7 +3304,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
b.Property<string>("Name")
.HasColumnType("varchar(255)")
.HasMaxLength(50)
.HasColumnType("varchar(50)")
.UseCollation("utf8mb4_general_ci");
b.Property<string>("Query")
@ -3607,7 +3668,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations @@ -3607,7 +3668,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations
.HasColumnType("longtext");
b.Property<string>("Name")
.HasColumnType("longtext");
.HasColumnType("varchar(255)")
.UseCollation("utf8mb4_general_ci");
b.Property<int?>("PlaylistId")
.HasColumnType("int");
@ -3620,6 +3682,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations @@ -3620,6 +3682,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations
b.HasKey("Id");
b.HasIndex("Name");
b.HasIndex("PlaylistId");
b.ToTable("TraktList", (string)null);

6814
ErsatzTV.Infrastructure.Sqlite/Migrations/20260102150221_Update_CaseSensitivity.Designer.cs generated

File diff suppressed because it is too large Load Diff

591
ErsatzTV.Infrastructure.Sqlite/Migrations/20260102150221_Update_CaseSensitivity.cs

@ -0,0 +1,591 @@ @@ -0,0 +1,591 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace ErsatzTV.Infrastructure.Sqlite.Migrations
{
/// <inheritdoc />
public partial class Update_CaseSensitivity : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "TraktList",
type: "TEXT",
nullable: true,
collation: "NOCASE",
oldClrType: typeof(string),
oldType: "TEXT",
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "TemplateGroup",
type: "varchar(50)",
maxLength: 50,
nullable: true,
collation: "NOCASE",
oldClrType: typeof(string),
oldType: "TEXT",
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "Template",
type: "varchar(50)",
maxLength: 50,
nullable: true,
collation: "NOCASE",
oldClrType: typeof(string),
oldType: "TEXT",
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "SmartCollection",
type: "varchar(50)",
maxLength: 50,
nullable: true,
collation: "NOCASE",
oldClrType: typeof(string),
oldType: "TEXT",
oldNullable: true,
oldCollation: "NOCASE");
migrationBuilder.AlterColumn<string>(
name: "Title",
table: "ShowMetadata",
type: "TEXT",
nullable: true,
collation: "NOCASE",
oldClrType: typeof(string),
oldType: "TEXT",
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "RerunCollection",
type: "varchar(50)",
maxLength: 50,
nullable: true,
collation: "NOCASE",
oldClrType: typeof(string),
oldType: "TEXT",
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "ProgramSchedule",
type: "varchar(50)",
maxLength: 50,
nullable: true,
collation: "NOCASE",
oldClrType: typeof(string),
oldType: "TEXT",
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "Playlist",
type: "varchar(50)",
maxLength: 50,
nullable: true,
collation: "NOCASE",
oldClrType: typeof(string),
oldType: "TEXT",
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "MultiCollection",
type: "varchar(50)",
maxLength: 50,
nullable: true,
collation: "NOCASE",
oldClrType: typeof(string),
oldType: "TEXT",
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "Title",
table: "MovieMetadata",
type: "TEXT",
nullable: true,
collation: "NOCASE",
oldClrType: typeof(string),
oldType: "TEXT",
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "Guid",
table: "MetadataGuid",
type: "varchar(128)",
maxLength: 128,
nullable: true,
collation: "NOCASE",
oldClrType: typeof(string),
oldType: "TEXT",
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "FillerPreset",
type: "varchar(50)",
maxLength: 50,
nullable: true,
collation: "NOCASE",
oldClrType: typeof(string),
oldType: "TEXT",
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "DecoTemplateGroup",
type: "varchar(50)",
maxLength: 50,
nullable: true,
collation: "NOCASE",
oldClrType: typeof(string),
oldType: "TEXT",
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "DecoTemplate",
type: "varchar(50)",
maxLength: 50,
nullable: true,
collation: "NOCASE",
oldClrType: typeof(string),
oldType: "TEXT",
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "DecoGroup",
type: "varchar(50)",
maxLength: 50,
nullable: true,
collation: "NOCASE",
oldClrType: typeof(string),
oldType: "TEXT",
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "Deco",
type: "varchar(50)",
maxLength: 50,
nullable: true,
collation: "NOCASE",
oldClrType: typeof(string),
oldType: "TEXT",
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "Collection",
type: "varchar(50)",
maxLength: 50,
nullable: true,
collation: "NOCASE",
oldClrType: typeof(string),
oldType: "TEXT",
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "ChannelWatermark",
type: "varchar(50)",
maxLength: 50,
nullable: true,
collation: "NOCASE",
oldClrType: typeof(string),
oldType: "TEXT",
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "Channel",
type: "varchar(50)",
maxLength: 50,
nullable: true,
collation: "NOCASE",
oldClrType: typeof(string),
oldType: "TEXT",
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "BlockGroup",
type: "varchar(50)",
maxLength: 50,
nullable: true,
collation: "NOCASE",
oldClrType: typeof(string),
oldType: "TEXT",
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "Block",
type: "varchar(50)",
maxLength: 50,
nullable: true,
collation: "NOCASE",
oldClrType: typeof(string),
oldType: "TEXT",
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "Title",
table: "ArtistMetadata",
type: "TEXT",
nullable: true,
collation: "NOCASE",
oldClrType: typeof(string),
oldType: "TEXT",
oldNullable: true);
migrationBuilder.CreateIndex(
name: "IX_TraktList_Name",
table: "TraktList",
column: "Name");
migrationBuilder.CreateIndex(
name: "IX_ShowMetadata_Title",
table: "ShowMetadata",
column: "Title");
migrationBuilder.CreateIndex(
name: "IX_RerunCollection_Name",
table: "RerunCollection",
column: "Name",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_MultiCollection_Name",
table: "MultiCollection",
column: "Name",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_MovieMetadata_Title",
table: "MovieMetadata",
column: "Title");
migrationBuilder.CreateIndex(
name: "IX_MetadataGuid_Guid",
table: "MetadataGuid",
column: "Guid");
migrationBuilder.CreateIndex(
name: "IX_FillerPreset_Name",
table: "FillerPreset",
column: "Name",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_Collection_Name",
table: "Collection",
column: "Name",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_ChannelWatermark_Name",
table: "ChannelWatermark",
column: "Name",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_ArtistMetadata_Title",
table: "ArtistMetadata",
column: "Title");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropIndex(
name: "IX_TraktList_Name",
table: "TraktList");
migrationBuilder.DropIndex(
name: "IX_ShowMetadata_Title",
table: "ShowMetadata");
migrationBuilder.DropIndex(
name: "IX_RerunCollection_Name",
table: "RerunCollection");
migrationBuilder.DropIndex(
name: "IX_MultiCollection_Name",
table: "MultiCollection");
migrationBuilder.DropIndex(
name: "IX_MovieMetadata_Title",
table: "MovieMetadata");
migrationBuilder.DropIndex(
name: "IX_MetadataGuid_Guid",
table: "MetadataGuid");
migrationBuilder.DropIndex(
name: "IX_FillerPreset_Name",
table: "FillerPreset");
migrationBuilder.DropIndex(
name: "IX_Collection_Name",
table: "Collection");
migrationBuilder.DropIndex(
name: "IX_ChannelWatermark_Name",
table: "ChannelWatermark");
migrationBuilder.DropIndex(
name: "IX_ArtistMetadata_Title",
table: "ArtistMetadata");
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "TraktList",
type: "TEXT",
nullable: true,
oldClrType: typeof(string),
oldType: "TEXT",
oldNullable: true,
oldCollation: "NOCASE");
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "TemplateGroup",
type: "TEXT",
nullable: true,
oldClrType: typeof(string),
oldType: "varchar(50)",
oldMaxLength: 50,
oldNullable: true,
oldCollation: "NOCASE");
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "Template",
type: "TEXT",
nullable: true,
oldClrType: typeof(string),
oldType: "varchar(50)",
oldMaxLength: 50,
oldNullable: true,
oldCollation: "NOCASE");
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "SmartCollection",
type: "TEXT",
nullable: true,
collation: "NOCASE",
oldClrType: typeof(string),
oldType: "varchar(50)",
oldMaxLength: 50,
oldNullable: true,
oldCollation: "NOCASE");
migrationBuilder.AlterColumn<string>(
name: "Title",
table: "ShowMetadata",
type: "TEXT",
nullable: true,
oldClrType: typeof(string),
oldType: "TEXT",
oldNullable: true,
oldCollation: "NOCASE");
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "RerunCollection",
type: "TEXT",
nullable: true,
oldClrType: typeof(string),
oldType: "varchar(50)",
oldMaxLength: 50,
oldNullable: true,
oldCollation: "NOCASE");
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "ProgramSchedule",
type: "TEXT",
nullable: true,
oldClrType: typeof(string),
oldType: "varchar(50)",
oldMaxLength: 50,
oldNullable: true,
oldCollation: "NOCASE");
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "Playlist",
type: "TEXT",
nullable: true,
oldClrType: typeof(string),
oldType: "varchar(50)",
oldMaxLength: 50,
oldNullable: true,
oldCollation: "NOCASE");
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "MultiCollection",
type: "TEXT",
nullable: true,
oldClrType: typeof(string),
oldType: "varchar(50)",
oldMaxLength: 50,
oldNullable: true,
oldCollation: "NOCASE");
migrationBuilder.AlterColumn<string>(
name: "Title",
table: "MovieMetadata",
type: "TEXT",
nullable: true,
oldClrType: typeof(string),
oldType: "TEXT",
oldNullable: true,
oldCollation: "NOCASE");
migrationBuilder.AlterColumn<string>(
name: "Guid",
table: "MetadataGuid",
type: "TEXT",
nullable: true,
oldClrType: typeof(string),
oldType: "varchar(128)",
oldMaxLength: 128,
oldNullable: true,
oldCollation: "NOCASE");
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "FillerPreset",
type: "TEXT",
nullable: true,
oldClrType: typeof(string),
oldType: "varchar(50)",
oldMaxLength: 50,
oldNullable: true,
oldCollation: "NOCASE");
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "DecoTemplateGroup",
type: "TEXT",
nullable: true,
oldClrType: typeof(string),
oldType: "varchar(50)",
oldMaxLength: 50,
oldNullable: true,
oldCollation: "NOCASE");
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "DecoTemplate",
type: "TEXT",
nullable: true,
oldClrType: typeof(string),
oldType: "varchar(50)",
oldMaxLength: 50,
oldNullable: true,
oldCollation: "NOCASE");
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "DecoGroup",
type: "TEXT",
nullable: true,
oldClrType: typeof(string),
oldType: "varchar(50)",
oldMaxLength: 50,
oldNullable: true,
oldCollation: "NOCASE");
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "Deco",
type: "TEXT",
nullable: true,
oldClrType: typeof(string),
oldType: "varchar(50)",
oldMaxLength: 50,
oldNullable: true,
oldCollation: "NOCASE");
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "Collection",
type: "TEXT",
nullable: true,
oldClrType: typeof(string),
oldType: "varchar(50)",
oldMaxLength: 50,
oldNullable: true,
oldCollation: "NOCASE");
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "ChannelWatermark",
type: "TEXT",
nullable: true,
oldClrType: typeof(string),
oldType: "varchar(50)",
oldMaxLength: 50,
oldNullable: true,
oldCollation: "NOCASE");
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "Channel",
type: "TEXT",
nullable: true,
oldClrType: typeof(string),
oldType: "varchar(50)",
oldMaxLength: 50,
oldNullable: true,
oldCollation: "NOCASE");
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "BlockGroup",
type: "TEXT",
nullable: true,
oldClrType: typeof(string),
oldType: "varchar(50)",
oldMaxLength: 50,
oldNullable: true,
oldCollation: "NOCASE");
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "Block",
type: "TEXT",
nullable: true,
oldClrType: typeof(string),
oldType: "varchar(50)",
oldMaxLength: 50,
oldNullable: true,
oldCollation: "NOCASE");
migrationBuilder.AlterColumn<string>(
name: "Title",
table: "ArtistMetadata",
type: "TEXT",
nullable: true,
oldClrType: typeof(string),
oldType: "TEXT",
oldNullable: true,
oldCollation: "NOCASE");
}
}
}

108
ErsatzTV.Infrastructure.Sqlite/Migrations/TvContextModelSnapshot.cs

@ -130,7 +130,8 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations @@ -130,7 +130,8 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations
.HasColumnType("TEXT");
b.Property<string>("Title")
.HasColumnType("TEXT");
.HasColumnType("TEXT")
.UseCollation("NOCASE");
b.Property<int?>("Year")
.HasColumnType("INTEGER");
@ -139,6 +140,8 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations @@ -139,6 +140,8 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations
b.HasIndex("ArtistId");
b.HasIndex("Title");
b.ToTable("ArtistMetadata", (string)null);
});
@ -304,7 +307,9 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations @@ -304,7 +307,9 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations
.HasColumnType("TEXT");
b.Property<string>("Name")
.HasColumnType("TEXT");
.HasMaxLength(50)
.HasColumnType("varchar(50)")
.UseCollation("NOCASE");
b.Property<string>("Number")
.HasColumnType("TEXT");
@ -403,7 +408,9 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations @@ -403,7 +408,9 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations
.HasColumnType("INTEGER");
b.Property<string>("Name")
.HasColumnType("TEXT");
.HasMaxLength(50)
.HasColumnType("varchar(50)")
.UseCollation("NOCASE");
b.Property<int>("Opacity")
.HasColumnType("INTEGER");
@ -431,6 +438,9 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations @@ -431,6 +438,9 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations
b.HasKey("Id");
b.HasIndex("Name")
.IsUnique();
b.ToTable("ChannelWatermark", (string)null);
});
@ -441,13 +451,18 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations @@ -441,13 +451,18 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations
.HasColumnType("INTEGER");
b.Property<string>("Name")
.HasColumnType("TEXT");
.HasMaxLength(50)
.HasColumnType("varchar(50)")
.UseCollation("NOCASE");
b.Property<bool>("UseCustomPlaybackOrder")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.HasIndex("Name")
.IsUnique();
b.ToTable("Collection", (string)null);
});
@ -798,7 +813,9 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations @@ -798,7 +813,9 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations
.HasColumnType("INTEGER");
b.Property<string>("Name")
.HasColumnType("TEXT");
.HasMaxLength(50)
.HasColumnType("varchar(50)")
.UseCollation("NOCASE");
b.Property<int?>("PadToNearestMinute")
.HasColumnType("INTEGER");
@ -820,6 +837,9 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations @@ -820,6 +837,9 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations
b.HasIndex("MultiCollectionId");
b.HasIndex("Name")
.IsUnique();
b.HasIndex("PlaylistId");
b.HasIndex("SmartCollectionId");
@ -1400,7 +1420,9 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations @@ -1400,7 +1420,9 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations
.HasColumnType("INTEGER");
b.Property<string>("Guid")
.HasColumnType("TEXT");
.HasMaxLength(128)
.HasColumnType("varchar(128)")
.UseCollation("NOCASE");
b.Property<int?>("ImageMetadataId")
.HasColumnType("INTEGER");
@ -1432,6 +1454,8 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations @@ -1432,6 +1454,8 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations
b.HasIndex("EpisodeMetadataId");
b.HasIndex("Guid");
b.HasIndex("ImageMetadataId");
b.HasIndex("MovieMetadataId");
@ -1510,7 +1534,8 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations @@ -1510,7 +1534,8 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations
.HasColumnType("TEXT");
b.Property<string>("Title")
.HasColumnType("TEXT");
.HasColumnType("TEXT")
.UseCollation("NOCASE");
b.Property<int?>("Year")
.HasColumnType("INTEGER");
@ -1519,6 +1544,8 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations @@ -1519,6 +1544,8 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations
b.HasIndex("MovieId");
b.HasIndex("Title");
b.ToTable("MovieMetadata", (string)null);
});
@ -1529,10 +1556,15 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations @@ -1529,10 +1556,15 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations
.HasColumnType("INTEGER");
b.Property<string>("Name")
.HasColumnType("TEXT");
.HasMaxLength(50)
.HasColumnType("varchar(50)")
.UseCollation("NOCASE");
b.HasKey("Id");
b.HasIndex("Name")
.IsUnique();
b.ToTable("MultiCollection", (string)null);
});
@ -1708,7 +1740,9 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations @@ -1708,7 +1740,9 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations
.HasColumnType("INTEGER");
b.Property<string>("Name")
.HasColumnType("TEXT");
.HasMaxLength(50)
.HasColumnType("varchar(50)")
.UseCollation("NOCASE");
b.Property<int>("PlaylistGroupId")
.HasColumnType("INTEGER");
@ -2147,7 +2181,9 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations @@ -2147,7 +2181,9 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations
.HasColumnType("INTEGER");
b.Property<string>("Name")
.HasColumnType("TEXT");
.HasMaxLength(50)
.HasColumnType("varchar(50)")
.UseCollation("NOCASE");
b.Property<bool>("RandomStartPoint")
.HasColumnType("INTEGER");
@ -2427,7 +2463,9 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations @@ -2427,7 +2463,9 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations
.HasColumnType("INTEGER");
b.Property<string>("Name")
.HasColumnType("TEXT");
.HasMaxLength(50)
.HasColumnType("varchar(50)")
.UseCollation("NOCASE");
b.Property<int>("RerunPlaybackOrder")
.HasColumnType("INTEGER");
@ -2443,6 +2481,9 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations @@ -2443,6 +2481,9 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations
b.HasIndex("MultiCollectionId");
b.HasIndex("Name")
.IsUnique();
b.HasIndex("SmartCollectionId");
b.ToTable("RerunCollection", (string)null);
@ -2489,7 +2530,9 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations @@ -2489,7 +2530,9 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations
.HasColumnType("INTEGER");
b.Property<string>("Name")
.HasColumnType("TEXT");
.HasMaxLength(50)
.HasColumnType("varchar(50)")
.UseCollation("NOCASE");
b.Property<int>("StopScheduling")
.HasColumnType("INTEGER");
@ -2509,7 +2552,9 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations @@ -2509,7 +2552,9 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations
.HasColumnType("INTEGER");
b.Property<string>("Name")
.HasColumnType("TEXT");
.HasMaxLength(50)
.HasColumnType("varchar(50)")
.UseCollation("NOCASE");
b.HasKey("Id");
@ -2631,7 +2676,9 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations @@ -2631,7 +2676,9 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations
.HasColumnType("INTEGER");
b.Property<string>("Name")
.HasColumnType("TEXT");
.HasMaxLength(50)
.HasColumnType("varchar(50)")
.UseCollation("NOCASE");
b.Property<bool>("UseGraphicsElementsDuringFiller")
.HasColumnType("INTEGER");
@ -2720,7 +2767,9 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations @@ -2720,7 +2767,9 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations
.HasColumnType("INTEGER");
b.Property<string>("Name")
.HasColumnType("TEXT");
.HasMaxLength(50)
.HasColumnType("varchar(50)")
.UseCollation("NOCASE");
b.HasKey("Id");
@ -2743,7 +2792,9 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations @@ -2743,7 +2792,9 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations
.HasColumnType("INTEGER");
b.Property<string>("Name")
.HasColumnType("TEXT");
.HasMaxLength(50)
.HasColumnType("varchar(50)")
.UseCollation("NOCASE");
b.HasKey("Id");
@ -2760,7 +2811,9 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations @@ -2760,7 +2811,9 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations
.HasColumnType("INTEGER");
b.Property<string>("Name")
.HasColumnType("TEXT");
.HasMaxLength(50)
.HasColumnType("varchar(50)")
.UseCollation("NOCASE");
b.HasKey("Id");
@ -2937,7 +2990,9 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations @@ -2937,7 +2990,9 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations
.HasColumnType("TEXT");
b.Property<string>("Name")
.HasColumnType("TEXT");
.HasMaxLength(50)
.HasColumnType("varchar(50)")
.UseCollation("NOCASE");
b.Property<int>("TemplateGroupId")
.HasColumnType("INTEGER");
@ -2957,7 +3012,9 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations @@ -2957,7 +3012,9 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations
.HasColumnType("INTEGER");
b.Property<string>("Name")
.HasColumnType("TEXT");
.HasMaxLength(50)
.HasColumnType("varchar(50)")
.UseCollation("NOCASE");
b.HasKey("Id");
@ -3074,7 +3131,8 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations @@ -3074,7 +3131,8 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations
.HasColumnType("TEXT");
b.Property<string>("Title")
.HasColumnType("TEXT");
.HasColumnType("TEXT")
.UseCollation("NOCASE");
b.Property<int?>("Year")
.HasColumnType("INTEGER");
@ -3083,6 +3141,8 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations @@ -3083,6 +3141,8 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations
b.HasIndex("ShowId");
b.HasIndex("Title");
b.ToTable("ShowMetadata", (string)null);
});
@ -3093,7 +3153,8 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations @@ -3093,7 +3153,8 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations
.HasColumnType("INTEGER");
b.Property<string>("Name")
.HasColumnType("TEXT")
.HasMaxLength(50)
.HasColumnType("varchar(50)")
.UseCollation("NOCASE");
b.Property<string>("Query")
@ -3444,7 +3505,8 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations @@ -3444,7 +3505,8 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations
.HasColumnType("TEXT");
b.Property<string>("Name")
.HasColumnType("TEXT");
.HasColumnType("TEXT")
.UseCollation("NOCASE");
b.Property<int?>("PlaylistId")
.HasColumnType("INTEGER");
@ -3457,6 +3519,8 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations @@ -3457,6 +3519,8 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations
b.HasKey("Id");
b.HasIndex("Name");
b.HasIndex("PlaylistId");
b.ToTable("TraktList", (string)null);

4
ErsatzTV.Infrastructure/Data/Configurations/ChannelConfiguration.cs

@ -13,6 +13,10 @@ public class ChannelConfiguration : IEntityTypeConfiguration<Channel> @@ -13,6 +13,10 @@ public class ChannelConfiguration : IEntityTypeConfiguration<Channel>
builder.HasIndex(c => c.Number)
.IsUnique();
builder.Property(c => c.Name)
.HasMaxLength(50)
.HasColumnType("varchar(50)");
builder.Property(c => c.IsEnabled)
.HasDefaultValue(true);

12
ErsatzTV.Infrastructure/Data/Configurations/ChannelWatermarkConfiguration.cs

@ -6,5 +6,15 @@ namespace ErsatzTV.Infrastructure.Data.Configurations; @@ -6,5 +6,15 @@ namespace ErsatzTV.Infrastructure.Data.Configurations;
public class ChannelWatermarkConfiguration : IEntityTypeConfiguration<ChannelWatermark>
{
public void Configure(EntityTypeBuilder<ChannelWatermark> builder) => builder.ToTable("ChannelWatermark");
public void Configure(EntityTypeBuilder<ChannelWatermark> builder)
{
builder.ToTable("ChannelWatermark");
builder.Property(wm => wm.Name)
.HasMaxLength(50)
.HasColumnType("varchar(50)");
builder.HasIndex(wm => wm.Name)
.IsUnique();
}
}

7
ErsatzTV.Infrastructure/Data/Configurations/Collection/CollectionConfiguration.cs

@ -10,6 +10,13 @@ public class CollectionConfiguration : IEntityTypeConfiguration<Collection> @@ -10,6 +10,13 @@ public class CollectionConfiguration : IEntityTypeConfiguration<Collection>
{
builder.ToTable("Collection");
builder.Property(c => c.Name)
.HasMaxLength(50)
.HasColumnType("varchar(50)");
builder.HasIndex(c => c.Name)
.IsUnique();
builder.HasMany(c => c.MediaItems)
.WithMany(m => m.Collections)
.UsingEntity<CollectionItem>(

7
ErsatzTV.Infrastructure/Data/Configurations/Collection/MultiCollectionConfiguration.cs

@ -10,6 +10,13 @@ public class MultiCollectionConfiguration : IEntityTypeConfiguration<MultiCollec @@ -10,6 +10,13 @@ public class MultiCollectionConfiguration : IEntityTypeConfiguration<MultiCollec
{
builder.ToTable("MultiCollection");
builder.Property(mc => mc.Name)
.HasMaxLength(50)
.HasColumnType("varchar(50)");
builder.HasIndex(mc => mc.Name)
.IsUnique();
builder.HasMany(m => m.Collections)
.WithMany(m => m.MultiCollections)
.UsingEntity<MultiCollectionItem>(

6
ErsatzTV.Infrastructure/Data/Configurations/Collection/PlaylistConfiguration.cs

@ -10,7 +10,11 @@ public class PlaylistConfiguration : IEntityTypeConfiguration<Playlist> @@ -10,7 +10,11 @@ public class PlaylistConfiguration : IEntityTypeConfiguration<Playlist>
{
builder.ToTable("Playlist");
builder.HasIndex(d => new { d.PlaylistGroupId, d.Name })
builder.Property(p => p.Name)
.HasMaxLength(50)
.HasColumnType("varchar(50)");
builder.HasIndex(p => new { p.PlaylistGroupId, p.Name })
.IsUnique();
builder.HasMany(p => p.Items)

7
ErsatzTV.Infrastructure/Data/Configurations/Collection/RerunCollectionConfiguration.cs

@ -10,6 +10,13 @@ public class RerunCollectionConfiguration : IEntityTypeConfiguration<RerunCollec @@ -10,6 +10,13 @@ public class RerunCollectionConfiguration : IEntityTypeConfiguration<RerunCollec
{
builder.ToTable("RerunCollection");
builder.Property(rc => rc.Name)
.HasMaxLength(50)
.HasColumnType("varchar(50)");
builder.HasIndex(rc => rc.Name)
.IsUnique();
builder.HasOne(i => i.Collection)
.WithMany()
.HasForeignKey(i => i.CollectionId)

4
ErsatzTV.Infrastructure/Data/Configurations/Collection/SmartCollectionConfiguration.cs

@ -10,6 +10,10 @@ public class SmartCollectionConfiguration : IEntityTypeConfiguration<SmartCollec @@ -10,6 +10,10 @@ public class SmartCollectionConfiguration : IEntityTypeConfiguration<SmartCollec
{
builder.ToTable("SmartCollection");
builder.Property(sc => sc.Name)
.HasMaxLength(50)
.HasColumnType("varchar(50)");
builder.HasIndex(sc => sc.Name)
.IsUnique();
}

2
ErsatzTV.Infrastructure/Data/Configurations/Collection/TraktListConfiguration.cs

@ -10,6 +10,8 @@ public class TraktListConfiguration : IEntityTypeConfiguration<TraktList> @@ -10,6 +10,8 @@ public class TraktListConfiguration : IEntityTypeConfiguration<TraktList>
{
builder.ToTable("TraktList");
builder.HasIndex(l => l.Name);
builder.HasMany(l => l.Items)
.WithOne(i => i.TraktList)
.HasForeignKey(i => i.TraktListId)

7
ErsatzTV.Infrastructure/Data/Configurations/Filler/FillerPresetConfiguration.cs

@ -10,6 +10,13 @@ public class FillerPresetConfiguration : IEntityTypeConfiguration<FillerPreset> @@ -10,6 +10,13 @@ public class FillerPresetConfiguration : IEntityTypeConfiguration<FillerPreset>
{
builder.ToTable("FillerPreset");
builder.Property(mc => mc.Name)
.HasMaxLength(50)
.HasColumnType("varchar(50)");
builder.HasIndex(c => c.Name)
.IsUnique();
builder.HasOne(i => i.Collection)
.WithMany()
.HasForeignKey(i => i.CollectionId)

20
ErsatzTV.Infrastructure/Data/Configurations/Metadata/ArtistMetadataConfiguration.cs

@ -10,39 +10,41 @@ public class ArtistMetadataConfiguration : IEntityTypeConfiguration<ArtistMetada @@ -10,39 +10,41 @@ public class ArtistMetadataConfiguration : IEntityTypeConfiguration<ArtistMetada
{
builder.ToTable("ArtistMetadata");
builder.HasMany(sm => sm.Artwork)
builder.HasIndex(am => am.Title);
builder.HasMany(am => am.Artwork)
.WithOne()
.OnDelete(DeleteBehavior.Cascade);
builder.HasMany(sm => sm.Genres)
builder.HasMany(am => am.Genres)
.WithOne()
.OnDelete(DeleteBehavior.Cascade);
builder.HasMany(sm => sm.Tags)
builder.HasMany(am => am.Tags)
.WithOne()
.OnDelete(DeleteBehavior.Cascade);
builder.HasMany(sm => sm.Studios)
builder.HasMany(am => am.Studios)
.WithOne()
.OnDelete(DeleteBehavior.Cascade);
builder.HasMany(sm => sm.Actors)
builder.HasMany(am => am.Actors)
.WithOne()
.OnDelete(DeleteBehavior.Cascade);
builder.HasMany(mm => mm.Guids)
builder.HasMany(am => am.Guids)
.WithOne()
.OnDelete(DeleteBehavior.Cascade);
builder.HasMany(mm => mm.Subtitles)
builder.HasMany(am => am.Subtitles)
.WithOne()
.OnDelete(DeleteBehavior.Cascade);
builder.HasMany(sm => sm.Styles)
builder.HasMany(am => am.Styles)
.WithOne()
.OnDelete(DeleteBehavior.Cascade);
builder.HasMany(sm => sm.Moods)
builder.HasMany(am => am.Moods)
.WithOne()
.OnDelete(DeleteBehavior.Cascade);
}

11
ErsatzTV.Infrastructure/Data/Configurations/Metadata/MetadataGuidConfiguration.cs

@ -6,5 +6,14 @@ namespace ErsatzTV.Infrastructure.Data.Configurations; @@ -6,5 +6,14 @@ namespace ErsatzTV.Infrastructure.Data.Configurations;
public class MetadataGuidConfiguration : IEntityTypeConfiguration<MetadataGuid>
{
public void Configure(EntityTypeBuilder<MetadataGuid> builder) => builder.ToTable("MetadataGuid");
public void Configure(EntityTypeBuilder<MetadataGuid> builder)
{
builder.ToTable("MetadataGuid");
builder.Property(mg => mg.Guid)
.HasMaxLength(128)
.HasColumnType("varchar(128)");
builder.HasIndex(mg => mg.Guid);
}
}

12
ErsatzTV.Infrastructure/Data/Configurations/Metadata/MovieMetadataConfiguration.cs

@ -10,23 +10,25 @@ public class MovieMetadataConfiguration : IEntityTypeConfiguration<MovieMetadata @@ -10,23 +10,25 @@ public class MovieMetadataConfiguration : IEntityTypeConfiguration<MovieMetadata
{
builder.ToTable("MovieMetadata");
builder.HasMany(sm => sm.Artwork)
builder.HasIndex(mm => mm.Title);
builder.HasMany(mm => mm.Artwork)
.WithOne()
.OnDelete(DeleteBehavior.Cascade);
builder.HasMany(sm => sm.Genres)
builder.HasMany(mm => mm.Genres)
.WithOne()
.OnDelete(DeleteBehavior.Cascade);
builder.HasMany(sm => sm.Tags)
builder.HasMany(mm => mm.Tags)
.WithOne()
.OnDelete(DeleteBehavior.Cascade);
builder.HasMany(sm => sm.Studios)
builder.HasMany(mm => mm.Studios)
.WithOne()
.OnDelete(DeleteBehavior.Cascade);
builder.HasMany(sm => sm.Actors)
builder.HasMany(mm => mm.Actors)
.WithOne()
.OnDelete(DeleteBehavior.Cascade);

2
ErsatzTV.Infrastructure/Data/Configurations/Metadata/ShowMetadataConfiguration.cs

@ -10,6 +10,8 @@ public class ShowMetadataConfiguration : IEntityTypeConfiguration<ShowMetadata> @@ -10,6 +10,8 @@ public class ShowMetadataConfiguration : IEntityTypeConfiguration<ShowMetadata>
{
builder.ToTable("ShowMetadata");
builder.HasIndex(sm => sm.Title);
builder.HasMany(sm => sm.Artwork)
.WithOne()
.OnDelete(DeleteBehavior.Cascade);

4
ErsatzTV.Infrastructure/Data/Configurations/ProgramScheduleConfiguration.cs

@ -10,6 +10,10 @@ public class ProgramScheduleConfiguration : IEntityTypeConfiguration<ProgramSche @@ -10,6 +10,10 @@ public class ProgramScheduleConfiguration : IEntityTypeConfiguration<ProgramSche
{
builder.ToTable("ProgramSchedule");
builder.Property(p => p.Name)
.HasMaxLength(50)
.HasColumnType("varchar(50)");
builder.HasIndex(ps => ps.Name)
.IsUnique();

4
ErsatzTV.Infrastructure/Data/Configurations/Scheduling/BlockConfiguration.cs

@ -10,6 +10,10 @@ public class BlockConfiguration : IEntityTypeConfiguration<Block> @@ -10,6 +10,10 @@ public class BlockConfiguration : IEntityTypeConfiguration<Block>
{
builder.ToTable("Block");
builder.Property(b => b.Name)
.HasMaxLength(50)
.HasColumnType("varchar(50)");
builder.HasIndex(b => new { b.BlockGroupId, b.Name })
.IsUnique();

4
ErsatzTV.Infrastructure/Data/Configurations/Scheduling/BlockGroupConfiguration.cs

@ -10,6 +10,10 @@ public class BlockGroupConfiguration : IEntityTypeConfiguration<BlockGroup> @@ -10,6 +10,10 @@ public class BlockGroupConfiguration : IEntityTypeConfiguration<BlockGroup>
{
builder.ToTable("BlockGroup");
builder.Property(b => b.Name)
.HasMaxLength(50)
.HasColumnType("varchar(50)");
builder.HasIndex(b => b.Name)
.IsUnique();

4
ErsatzTV.Infrastructure/Data/Configurations/Scheduling/DecoConfiguration.cs

@ -11,6 +11,10 @@ public class DecoConfiguration : IEntityTypeConfiguration<Deco> @@ -11,6 +11,10 @@ public class DecoConfiguration : IEntityTypeConfiguration<Deco>
{
builder.ToTable("Deco");
builder.Property(d => d.Name)
.HasMaxLength(50)
.HasColumnType("varchar(50)");
builder.HasIndex(d => new { d.DecoGroupId, d.Name })
.IsUnique();

4
ErsatzTV.Infrastructure/Data/Configurations/Scheduling/DecoGroupConfiguration.cs

@ -10,6 +10,10 @@ public class DecoGroupConfiguration : IEntityTypeConfiguration<DecoGroup> @@ -10,6 +10,10 @@ public class DecoGroupConfiguration : IEntityTypeConfiguration<DecoGroup>
{
builder.ToTable("DecoGroup");
builder.Property(dg => dg.Name)
.HasMaxLength(50)
.HasColumnType("varchar(50)");
builder.HasIndex(dg => dg.Name)
.IsUnique();

4
ErsatzTV.Infrastructure/Data/Configurations/Scheduling/DecoTemplateConfiguration.cs

@ -10,6 +10,10 @@ public class DecoTemplateConfiguration : IEntityTypeConfiguration<DecoTemplate> @@ -10,6 +10,10 @@ public class DecoTemplateConfiguration : IEntityTypeConfiguration<DecoTemplate>
{
builder.ToTable("DecoTemplate");
builder.Property(d => d.Name)
.HasMaxLength(50)
.HasColumnType("varchar(50)");
builder.HasIndex(d => new { d.DecoTemplateGroupId, d.Name })
.IsUnique();

4
ErsatzTV.Infrastructure/Data/Configurations/Scheduling/DecoTemplateGroupConfiguration.cs

@ -10,6 +10,10 @@ public class DecoTemplateGroupConfiguration : IEntityTypeConfiguration<DecoTempl @@ -10,6 +10,10 @@ public class DecoTemplateGroupConfiguration : IEntityTypeConfiguration<DecoTempl
{
builder.ToTable("DecoTemplateGroup");
builder.Property(d => d.Name)
.HasMaxLength(50)
.HasColumnType("varchar(50)");
builder.HasIndex(b => b.Name)
.IsUnique();

4
ErsatzTV.Infrastructure/Data/Configurations/Scheduling/TemplateConfiguration.cs

@ -10,6 +10,10 @@ public class TemplateConfiguration : IEntityTypeConfiguration<Template> @@ -10,6 +10,10 @@ public class TemplateConfiguration : IEntityTypeConfiguration<Template>
{
builder.ToTable("Template");
builder.Property(t => t.Name)
.HasMaxLength(50)
.HasColumnType("varchar(50)");
builder.HasIndex(d => new { d.TemplateGroupId, d.Name })
.IsUnique();

4
ErsatzTV.Infrastructure/Data/Configurations/Scheduling/TemplateGroupConfiguration.cs

@ -10,6 +10,10 @@ public class TemplateGroupConfiguration : IEntityTypeConfiguration<TemplateGroup @@ -10,6 +10,10 @@ public class TemplateGroupConfiguration : IEntityTypeConfiguration<TemplateGroup
{
builder.ToTable("TemplateGroup");
builder.Property(t => t.Name)
.HasMaxLength(50)
.HasColumnType("varchar(50)");
builder.HasIndex(b => b.Name)
.IsUnique();

4
ErsatzTV.Infrastructure/Data/Repositories/ChannelRepository.cs

@ -51,9 +51,7 @@ public class ChannelRepository(IDbContextFactory<TvContext> dbContextFactory) : @@ -51,9 +51,7 @@ public class ChannelRepository(IDbContextFactory<TvContext> dbContextFactory) :
List<ChannelWatermark> maybeWatermarks = await dbContext.ChannelWatermarks
.AsNoTracking()
.Where(cw => EF.Functions.Like(
EF.Functions.Collate(cw.Name, TvContext.CaseInsensitiveCollation),
$"%{name}%"))
.Where(cw => EF.Functions.Like(cw.Name, $"%{name}%"))
.ToListAsync();
return maybeWatermarks.HeadOrNone();

23
ErsatzTV.Infrastructure/Data/Repositories/MediaCollectionRepository.cs

@ -176,10 +176,7 @@ public class MediaCollectionRepository : IMediaCollectionRepository @@ -176,10 +176,7 @@ public class MediaCollectionRepository : IMediaCollectionRepository
Option<Playlist> maybePlaylist = await dbContext.Playlists
.AsNoTracking()
.SelectOneAsync(
p => p.Name,
p => EF.Functions.Collate(p.Name, TvContext.CaseInsensitiveCollation) == name,
cancellationToken);
.SingleOrDefaultAsync(p => p.Name == name, cancellationToken);
foreach (Playlist playlist in maybePlaylist)
{
@ -360,10 +357,7 @@ public class MediaCollectionRepository : IMediaCollectionRepository @@ -360,10 +357,7 @@ public class MediaCollectionRepository : IMediaCollectionRepository
Option<Collection> maybeCollection = await dbContext.Collections
.AsNoTracking()
.SelectOneAsync(
c => c.Name,
c => EF.Functions.Collate(c.Name, TvContext.CaseInsensitiveCollation) == name,
cancellationToken);
.SingleOrDefaultAsync(c => c.Name == name, cancellationToken);
foreach (Collection collection in maybeCollection)
{
@ -416,10 +410,7 @@ public class MediaCollectionRepository : IMediaCollectionRepository @@ -416,10 +410,7 @@ public class MediaCollectionRepository : IMediaCollectionRepository
Option<MultiCollection> maybeCollection = await dbContext.MultiCollections
.AsNoTracking()
.SelectOneAsync(
mc => mc.Name,
mc => EF.Functions.Collate(mc.Name, TvContext.CaseInsensitiveCollation) == name,
cancellationToken);
.SingleOrDefaultAsync(mc => mc.Name == name, cancellationToken);
foreach (MultiCollection collection in maybeCollection)
{
@ -451,10 +442,7 @@ public class MediaCollectionRepository : IMediaCollectionRepository @@ -451,10 +442,7 @@ public class MediaCollectionRepository : IMediaCollectionRepository
Option<SmartCollection> maybeCollection = await dbContext.SmartCollections
.AsNoTracking()
.SelectOneAsync(
sc => sc.Name,
sc => EF.Functions.Collate(sc.Name, TvContext.CaseInsensitiveCollation) == name,
cancellationToken);
.SingleOrDefaultAsync(sc => sc.Name == name, cancellationToken);
foreach (SmartCollection collection in maybeCollection)
{
@ -694,8 +682,7 @@ public class MediaCollectionRepository : IMediaCollectionRepository @@ -694,8 +682,7 @@ public class MediaCollectionRepository : IMediaCollectionRepository
List<int> nextIds = await dbContext.ShowMetadata
.AsNoTracking()
.Filter(sm =>
sm.Guids.Any(g => EF.Functions.Collate(g.Guid, TvContext.CaseInsensitiveCollation) == guid))
.Filter(sm => sm.Guids.Any(g => g.Guid == guid))
.Map(sm => sm.ShowId)
.ToListAsync();

9
ErsatzTV.Infrastructure/Data/Repositories/TelevisionRepository.cs

@ -86,9 +86,7 @@ public class TelevisionRepository : ITelevisionRepository @@ -86,9 +86,7 @@ public class TelevisionRepository : ITelevisionRepository
return await dbContext.ShowMetadata
.AsNoTracking()
.Where(sm => sm.Show.LibraryPath.LibraryId == libraryId)
.Where(sm => EF.Functions.Like(
EF.Functions.Collate(sm.Title, TvContext.CaseInsensitiveCollation),
$"%{title}%"))
.Where(sm => EF.Functions.Like(sm.Title, $"%{title}%"))
.Map(sm => sm.ShowId)
.FirstOrDefaultAsync()
.Map(showId => showId > 0 ? Option<int>.Some(showId) : Option<int>.None);
@ -223,9 +221,8 @@ public class TelevisionRepository : ITelevisionRepository @@ -223,9 +221,8 @@ public class TelevisionRepository : ITelevisionRepository
if (maybeId.IsNone)
{
List<int> maybeShowIds = await dbContext.Episodes
.Where(e => e.MediaVersions.Any(mv => mv.MediaFiles.Any(mf => EF.Functions.Like(
EF.Functions.Collate(mf.Path, TvContext.CaseInsensitiveCollation),
$"{showFolder}%"))))
.Where(e => e.MediaVersions.Any(mv =>
mv.MediaFiles.Any(mf => EF.Functions.Like(mf.Path, $"{showFolder}%"))))
.Map(e => e.Season.ShowId)
.Distinct()
.ToListAsync();

34
ErsatzTV.Infrastructure/Data/TvContext.cs

@ -136,18 +136,46 @@ public class TvContext : DbContext @@ -136,18 +136,46 @@ public class TvContext : DbContext
{
base.OnModelCreating(modelBuilder);
string collation = null;
// mysql-specific configuration
if ((Database.ProviderName ?? string.Empty).Contains("MySql", StringComparison.InvariantCultureIgnoreCase))
{
modelBuilder.Entity<MediaFile>().Property(mf => mf.Path).HasColumnType("longtext");
modelBuilder.Entity<SmartCollection>().Property(mc => mc.Name).UseCollation("utf8mb4_general_ci");
collation = "utf8mb4_general_ci";
}
// sqlite-specific configuration
if ((Database.ProviderName ?? string.Empty).Contains("Sqlite", StringComparison.InvariantCultureIgnoreCase))
{
modelBuilder.Entity<SmartCollection>().Property(sc => sc.Name).UseCollation("NOCASE");
collation = "NOCASE";
}
// case-insensitive columns
if (!string.IsNullOrEmpty(collation))
{
modelBuilder.Entity<ArtistMetadata>().Property(b => b.Title).UseCollation(collation);
modelBuilder.Entity<Block>().Property(b => b.Name).UseCollation(collation);
modelBuilder.Entity<BlockGroup>().Property(b => b.Name).UseCollation(collation);
modelBuilder.Entity<Channel>().Property(c => c.Name).UseCollation(collation);
modelBuilder.Entity<ChannelWatermark>().Property(c => c.Name).UseCollation(collation);
modelBuilder.Entity<Collection>().Property(c => c.Name).UseCollation(collation);
modelBuilder.Entity<Deco>().Property(d => d.Name).UseCollation(collation);
modelBuilder.Entity<DecoGroup>().Property(d => d.Name).UseCollation(collation);
modelBuilder.Entity<DecoTemplate>().Property(d => d.Name).UseCollation(collation);
modelBuilder.Entity<DecoTemplateGroup>().Property(d => d.Name).UseCollation(collation);
modelBuilder.Entity<FillerPreset>().Property(fp => fp.Name).UseCollation(collation);
modelBuilder.Entity<MetadataGuid>().Property(mg => mg.Guid).UseCollation(collation);
modelBuilder.Entity<MovieMetadata>().Property(mm => mm.Title).UseCollation(collation);
modelBuilder.Entity<MultiCollection>().Property(mc => mc.Name).UseCollation(collation);
modelBuilder.Entity<Playlist>().Property(p => p.Name).UseCollation(collation);
modelBuilder.Entity<ProgramSchedule>().Property(ps => ps.Name).UseCollation(collation);
modelBuilder.Entity<RerunCollection>().Property(rc => rc.Name).UseCollation(collation);
modelBuilder.Entity<ShowMetadata>().Property(sm => sm.Title).UseCollation(collation);
modelBuilder.Entity<SmartCollection>().Property(sc => sc.Name).UseCollation(collation);
modelBuilder.Entity<Template>().Property(t => t.Name).UseCollation(collation);
modelBuilder.Entity<TemplateGroup>().Property(t => t.Name).UseCollation(collation);
modelBuilder.Entity<TraktList>().Property(t => t.Name).UseCollation(collation);
}
modelBuilder.ApplyConfigurationsFromAssembly(typeof(TvContext).Assembly);

Loading…
Cancel
Save