Design Prot Merge #1
@@ -8,7 +8,7 @@ using Musify.Domain.ValueObjects;
|
|||||||
|
|
||||||
namespace Musify.Application.Services;
|
namespace Musify.Application.Services;
|
||||||
|
|
||||||
public sealed record YouTubeTrackProvision(Track Track, bool Created, YouTubeSongResult? Song);
|
public sealed record YouTubeTrackProvision(Track Track, YouTubeSongResult? Song);
|
||||||
|
|
||||||
public sealed class YouTubeTrackProvisioner(
|
public sealed class YouTubeTrackProvisioner(
|
||||||
IDatabase database,
|
IDatabase database,
|
||||||
@@ -26,7 +26,7 @@ public sealed class YouTubeTrackProvisioner(
|
|||||||
{
|
{
|
||||||
var existing = await FindAsync(videoId, cancellationToken);
|
var existing = await FindAsync(videoId, cancellationToken);
|
||||||
if (existing is not null)
|
if (existing is not null)
|
||||||
return new YouTubeTrackProvision(existing, Created: false, Song: null);
|
return new YouTubeTrackProvision(existing, Song: null);
|
||||||
|
|
||||||
var songResult = await youTubeMusicService.GetSongAsync(videoId, cancellationToken);
|
var songResult = await youTubeMusicService.GetSongAsync(videoId, cancellationToken);
|
||||||
if (songResult.IsError)
|
if (songResult.IsError)
|
||||||
@@ -81,7 +81,7 @@ public sealed class YouTubeTrackProvisioner(
|
|||||||
{
|
{
|
||||||
await database.SaveChangesAsync(cancellationToken);
|
await database.SaveChangesAsync(cancellationToken);
|
||||||
logger.LogInformation("Created YouTube track {VideoId} ({TrackId})", videoId, track.Id);
|
logger.LogInformation("Created YouTube track {VideoId} ({TrackId})", videoId, track.Id);
|
||||||
return new YouTubeTrackProvision(track, Created: true, Song: song);
|
return new YouTubeTrackProvision(track, Song: song);
|
||||||
}
|
}
|
||||||
catch (DbUpdateException)
|
catch (DbUpdateException)
|
||||||
{
|
{
|
||||||
@@ -92,7 +92,7 @@ public sealed class YouTubeTrackProvisioner(
|
|||||||
logger.LogWarning("YouTube track {VideoId} creation raced but could not be refetched", videoId);
|
logger.LogWarning("YouTube track {VideoId} creation raced but could not be refetched", videoId);
|
||||||
return Error.Conflict(description: "The track was just created by another request. Retry the operation.");
|
return Error.Conflict(description: "The track was just created by another request. Retry the operation.");
|
||||||
}
|
}
|
||||||
return new YouTubeTrackProvision(refetched, Created: false, Song: null);
|
return new YouTubeTrackProvision(refetched, Song: null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,6 +108,30 @@ public sealed class YouTubeTrackProvisioner(
|
|||||||
if (existing is not null)
|
if (existing is not null)
|
||||||
return existing;
|
return existing;
|
||||||
|
|
||||||
|
if (byExternalId)
|
||||||
|
{
|
||||||
|
var adoptable = await database.Artists
|
||||||
|
.SingleOrDefaultAsync(a => a.ExternalId == null && a.UserId == null && a.NormalizedName == normalized, cancellationToken);
|
||||||
|
if (adoptable is not null)
|
||||||
|
{
|
||||||
|
var previousName = adoptable.Name;
|
||||||
|
adoptable.ExternalId = reference.Id;
|
||||||
|
adoptable.Name = name;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await database.SaveChangesAsync(cancellationToken);
|
||||||
|
return adoptable;
|
||||||
|
}
|
||||||
|
catch (DbUpdateException)
|
||||||
|
{
|
||||||
|
adoptable.ExternalId = null;
|
||||||
|
adoptable.Name = previousName;
|
||||||
|
return await database.Artists.SingleAsync(a => a.ExternalId == reference.Id, cancellationToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var artist = new Artist
|
var artist = new Artist
|
||||||
{
|
{
|
||||||
Name = name,
|
Name = name,
|
||||||
|
|||||||
@@ -47,6 +47,14 @@ namespace Musify.Application.Users
|
|||||||
user.SecondName = request.SecondName;
|
user.SecondName = request.SecondName;
|
||||||
user.ProfilePictureUrl = request.ProfilePictureUrl;
|
user.ProfilePictureUrl = request.ProfilePictureUrl;
|
||||||
|
|
||||||
|
var artist = await database.Artists
|
||||||
|
.SingleOrDefaultAsync(a => a.UserId == request.Id, cancellationToken);
|
||||||
|
if (artist is not null)
|
||||||
|
{
|
||||||
|
artist.Name = request.Name;
|
||||||
|
artist.NormalizedName = request.Name.ToUpperInvariant();
|
||||||
|
}
|
||||||
|
|
||||||
var written = await database.SaveChangesAsync(cancellationToken);
|
var written = await database.SaveChangesAsync(cancellationToken);
|
||||||
if (written > 0)
|
if (written > 0)
|
||||||
logger.LogInformation("Synced profile for user {UserId}", request.Id);
|
logger.LogInformation("Synced profile for user {UserId}", request.Id);
|
||||||
|
|||||||
+12
-2
@@ -108,6 +108,11 @@ namespace Musify.Infrastructure.Persistence.Migrations
|
|||||||
WHERE t."Source" = 0 AND ut."TrackId" = t."Id";
|
WHERE t."Source" = 0 AND ut."TrackId" = t."Id";
|
||||||
""");
|
""");
|
||||||
|
|
||||||
|
migrationBuilder.Sql(
|
||||||
|
"""
|
||||||
|
DELETE FROM "Tracks" WHERE "Source" = 0 AND "OwnerUserId" IS NULL;
|
||||||
|
""");
|
||||||
|
|
||||||
migrationBuilder.Sql(
|
migrationBuilder.Sql(
|
||||||
"""
|
"""
|
||||||
INSERT INTO "Artists" ("Id", "Name", "NormalizedName", "UserId", "ExternalId", "CreatedAt", "UpdatedAt")
|
INSERT INTO "Artists" ("Id", "Name", "NormalizedName", "UserId", "ExternalId", "CreatedAt", "UpdatedAt")
|
||||||
@@ -120,7 +125,12 @@ namespace Musify.Infrastructure.Persistence.Migrations
|
|||||||
"""
|
"""
|
||||||
INSERT INTO "Artists" ("Id", "Name", "NormalizedName", "UserId", "ExternalId", "CreatedAt", "UpdatedAt")
|
INSERT INTO "Artists" ("Id", "Name", "NormalizedName", "UserId", "ExternalId", "CreatedAt", "UpdatedAt")
|
||||||
SELECT gen_random_uuid(), s."Artist", upper(s."Artist"), NULL, NULL, now(), now()
|
SELECT gen_random_uuid(), s."Artist", upper(s."Artist"), NULL, NULL, now(), now()
|
||||||
FROM (SELECT DISTINCT "Artist" FROM "Tracks" WHERE "Source" = 1 AND "Artist" IS NOT NULL) s;
|
FROM (
|
||||||
|
SELECT DISTINCT ON (upper("Artist")) "Artist"
|
||||||
|
FROM "Tracks"
|
||||||
|
WHERE "Source" = 1 AND "Artist" IS NOT NULL
|
||||||
|
ORDER BY upper("Artist"), "Artist"
|
||||||
|
) s;
|
||||||
""");
|
""");
|
||||||
|
|
||||||
migrationBuilder.Sql(
|
migrationBuilder.Sql(
|
||||||
@@ -135,7 +145,7 @@ namespace Musify.Infrastructure.Persistence.Migrations
|
|||||||
"""
|
"""
|
||||||
INSERT INTO "TrackArtist" ("TrackId", "ArtistId", "Position")
|
INSERT INTO "TrackArtist" ("TrackId", "ArtistId", "Position")
|
||||||
SELECT t."Id", a."Id", 0 FROM "Tracks" t
|
SELECT t."Id", a."Id", 0 FROM "Tracks" t
|
||||||
JOIN "Artists" a ON a."UserId" IS NULL AND a."ExternalId" IS NULL AND a."Name" = t."Artist"
|
JOIN "Artists" a ON a."UserId" IS NULL AND a."ExternalId" IS NULL AND a."NormalizedName" = upper(t."Artist")
|
||||||
WHERE t."Source" = 1 AND t."Artist" IS NOT NULL;
|
WHERE t."Source" = 1 AND t."Artist" IS NOT NULL;
|
||||||
""");
|
""");
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user