2018-01-05 19:21:19 +08:00
|
|
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
2017-07-26 15:28:32 +08:00
|
|
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
|
|
|
|
|
|
|
using System;
|
2017-10-05 03:52:12 +08:00
|
|
|
using System.Linq;
|
2018-02-09 20:31:33 +08:00
|
|
|
using System.Linq.Expressions;
|
2017-10-05 03:52:12 +08:00
|
|
|
using Microsoft.EntityFrameworkCore;
|
2017-07-27 15:56:41 +08:00
|
|
|
using osu.Game.Database;
|
2017-07-26 15:28:32 +08:00
|
|
|
|
|
|
|
namespace osu.Game.Beatmaps
|
|
|
|
{
|
|
|
|
/// <summary>
|
2017-07-27 15:56:41 +08:00
|
|
|
/// Handles the storage and retrieval of Beatmaps/BeatmapSets to the database backing
|
2017-07-26 15:28:32 +08:00
|
|
|
/// </summary>
|
2018-02-15 11:56:22 +08:00
|
|
|
public class BeatmapStore : MutableDatabaseBackedStore<BeatmapSetInfo>
|
2017-07-26 15:28:32 +08:00
|
|
|
{
|
2017-08-31 14:49:56 +08:00
|
|
|
public event Action<BeatmapInfo> BeatmapHidden;
|
|
|
|
public event Action<BeatmapInfo> BeatmapRestored;
|
|
|
|
|
2018-02-12 22:10:05 +08:00
|
|
|
public BeatmapStore(IDatabaseContextFactory factory)
|
2017-10-17 14:00:27 +08:00
|
|
|
: base(factory)
|
2017-07-26 15:28:32 +08:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
2017-08-31 14:49:56 +08:00
|
|
|
/// Hide a <see cref="BeatmapInfo"/> in the database.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="beatmap">The beatmap to hide.</param>
|
|
|
|
/// <returns>Whether the beatmap's <see cref="BeatmapInfo.Hidden"/> was changed.</returns>
|
|
|
|
public bool Hide(BeatmapInfo beatmap)
|
|
|
|
{
|
2018-02-12 16:55:11 +08:00
|
|
|
using (ContextFactory.GetForWrite())
|
|
|
|
{
|
|
|
|
Refresh(ref beatmap, Beatmaps);
|
2017-10-17 14:50:42 +08:00
|
|
|
|
2018-02-12 16:55:11 +08:00
|
|
|
if (beatmap.Hidden) return false;
|
2018-02-12 18:57:21 +08:00
|
|
|
|
2018-02-12 16:55:11 +08:00
|
|
|
beatmap.Hidden = true;
|
2017-08-31 14:49:56 +08:00
|
|
|
|
2018-02-12 16:55:11 +08:00
|
|
|
BeatmapHidden?.Invoke(beatmap);
|
|
|
|
}
|
2017-08-31 14:49:56 +08:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Restore a previously hidden <see cref="BeatmapInfo"/>.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="beatmap">The beatmap to restore.</param>
|
|
|
|
/// <returns>Whether the beatmap's <see cref="BeatmapInfo.Hidden"/> was changed.</returns>
|
|
|
|
public bool Restore(BeatmapInfo beatmap)
|
|
|
|
{
|
2018-02-12 16:55:11 +08:00
|
|
|
using (ContextFactory.GetForWrite())
|
|
|
|
{
|
|
|
|
Refresh(ref beatmap, Beatmaps);
|
2017-08-31 14:49:56 +08:00
|
|
|
|
2018-02-12 16:55:11 +08:00
|
|
|
if (!beatmap.Hidden) return false;
|
2018-02-12 18:57:21 +08:00
|
|
|
|
2018-02-12 16:55:11 +08:00
|
|
|
beatmap.Hidden = false;
|
|
|
|
}
|
2017-08-31 14:49:56 +08:00
|
|
|
|
|
|
|
BeatmapRestored?.Invoke(beatmap);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-02-09 20:31:33 +08:00
|
|
|
public override void Cleanup() => Cleanup(_ => true);
|
|
|
|
|
|
|
|
public void Cleanup(Expression<Func<BeatmapSetInfo, bool>> query)
|
2017-07-26 15:28:32 +08:00
|
|
|
{
|
2018-02-12 16:55:11 +08:00
|
|
|
using (var usage = ContextFactory.GetForWrite())
|
|
|
|
{
|
|
|
|
var context = usage.Context;
|
2017-10-17 14:50:42 +08:00
|
|
|
|
2018-02-12 16:55:11 +08:00
|
|
|
var purgeable = context.BeatmapSetInfo.Where(s => s.DeletePending && !s.Protected)
|
|
|
|
.Where(query)
|
|
|
|
.Include(s => s.Beatmaps).ThenInclude(b => b.Metadata)
|
|
|
|
.Include(s => s.Beatmaps).ThenInclude(b => b.BaseDifficulty)
|
2018-02-12 18:57:21 +08:00
|
|
|
.Include(s => s.Metadata).ToList();
|
|
|
|
|
|
|
|
if (!purgeable.Any()) return;
|
2017-10-19 16:50:46 +08:00
|
|
|
|
2018-02-12 16:55:11 +08:00
|
|
|
// metadata is M-N so we can't rely on cascades
|
|
|
|
context.BeatmapMetadata.RemoveRange(purgeable.Select(s => s.Metadata));
|
|
|
|
context.BeatmapMetadata.RemoveRange(purgeable.SelectMany(s => s.Beatmaps.Select(b => b.Metadata).Where(m => m != null)));
|
2017-10-19 16:50:46 +08:00
|
|
|
|
2018-02-12 16:55:11 +08:00
|
|
|
// todo: we can probably make cascades work here with a FK in BeatmapDifficulty. just make to make it work correctly.
|
|
|
|
context.BeatmapDifficulty.RemoveRange(purgeable.SelectMany(s => s.Beatmaps.Select(b => b.BaseDifficulty)));
|
2017-10-19 16:50:46 +08:00
|
|
|
|
2018-02-12 16:55:11 +08:00
|
|
|
// cascades down to beatmaps.
|
|
|
|
context.BeatmapSetInfo.RemoveRange(purgeable);
|
|
|
|
}
|
2017-10-05 03:52:12 +08:00
|
|
|
}
|
2017-10-16 11:56:58 +08:00
|
|
|
|
2018-02-12 16:55:11 +08:00
|
|
|
public IQueryable<BeatmapSetInfo> BeatmapSets => ContextFactory.Get().BeatmapSetInfo
|
2018-02-15 11:21:11 +08:00
|
|
|
.Include(s => s.Metadata)
|
|
|
|
.Include(s => s.Beatmaps).ThenInclude(s => s.Ruleset)
|
|
|
|
.Include(s => s.Beatmaps).ThenInclude(b => b.BaseDifficulty)
|
|
|
|
.Include(s => s.Beatmaps).ThenInclude(b => b.Metadata)
|
|
|
|
.Include(s => s.Files).ThenInclude(f => f.FileInfo);
|
2017-10-17 14:50:42 +08:00
|
|
|
|
2018-02-12 16:55:11 +08:00
|
|
|
public IQueryable<BeatmapInfo> Beatmaps => ContextFactory.Get().BeatmapInfo
|
2018-02-15 11:21:11 +08:00
|
|
|
.Include(b => b.BeatmapSet).ThenInclude(s => s.Metadata)
|
|
|
|
.Include(b => b.BeatmapSet).ThenInclude(s => s.Files).ThenInclude(f => f.FileInfo)
|
|
|
|
.Include(b => b.Metadata)
|
|
|
|
.Include(b => b.Ruleset)
|
|
|
|
.Include(b => b.BaseDifficulty);
|
2017-07-26 15:28:32 +08:00
|
|
|
}
|
|
|
|
}
|