From 96b08b8777308d59a76a149d644cca18708e25c5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 27 Jul 2017 15:06:10 +0900 Subject: [PATCH] Simplify and document DatabaseStore API --- .../Beatmaps/IO/ImportBeatmapTest.cs | 19 +++++---- osu.Game/Beatmaps/BeatmapDatabase.cs | 2 +- osu.Game/Beatmaps/BeatmapStore.cs | 8 ++-- osu.Game/Database/DatabaseStore.cs | 41 +++++++++++++++---- osu.Game/IO/FileDatabase.cs | 2 +- osu.Game/Overlays/Music/PlaylistOverlay.cs | 2 +- osu.Game/Screens/Menu/Intro.cs | 5 ++- osu.Game/Screens/Select/SongSelect.cs | 2 +- 8 files changed, 54 insertions(+), 27 deletions(-) diff --git a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs index 5c1fd381e2..a9bf7f3dad 100644 --- a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs +++ b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs @@ -115,9 +115,11 @@ namespace osu.Game.Tests.Beatmaps.IO { IEnumerable resultSets = null; + var store = osu.Dependencies.Get(); + Action waitAction = () => { - while (!(resultSets = osu.Dependencies.Get().Database. + while (!(resultSets = store.Database. Query().Where(s => s.OnlineBeatmapSetID == 241526)).Any()) Thread.Sleep(50); }; @@ -134,15 +136,16 @@ namespace osu.Game.Tests.Beatmaps.IO //if we don't re-check here, the set will be inserted but the beatmaps won't be present yet. waitAction = () => { - while ((resultBeatmaps = osu.Dependencies.Get().Database. - GetAllWithChildren(s => s.OnlineBeatmapSetID == 241526 && s.BaseDifficultyID > 0)).Count() != 12) + while ((resultBeatmaps = store.Database. + QueryAndPopulate(s => s.OnlineBeatmapSetID == 241526 && s.BaseDifficultyID > 0)).Count() != 12) Thread.Sleep(50); }; Assert.IsTrue(waitAction.BeginInvoke(null, null).AsyncWaitHandle.WaitOne(timeout), @"Beatmaps did not import to the database in allocated time"); - var set = osu.Dependencies.Get().Database.GetChildren(resultSets.First()); + var set = resultSets.First(); + store.Database.Populate(set); Assert.IsTrue(set.Beatmaps.Count == resultBeatmaps.Count(), $@"Incorrect database beatmap count post-import ({resultBeatmaps.Count()} but should be {set.Beatmaps.Count})."); @@ -152,16 +155,16 @@ namespace osu.Game.Tests.Beatmaps.IO Assert.IsTrue(set.Beatmaps.Count > 0); - var beatmap = osu.Dependencies.Get().GetWorkingBeatmap(set.Beatmaps.First(b => b.RulesetID == 0))?.Beatmap; + var beatmap = store.GetWorkingBeatmap(set.Beatmaps.First(b => b.RulesetID == 0))?.Beatmap; Assert.IsTrue(beatmap?.HitObjects.Count > 0); - beatmap = osu.Dependencies.Get().GetWorkingBeatmap(set.Beatmaps.First(b => b.RulesetID == 1))?.Beatmap; + beatmap = store.GetWorkingBeatmap(set.Beatmaps.First(b => b.RulesetID == 1))?.Beatmap; Assert.IsTrue(beatmap?.HitObjects.Count > 0); - beatmap = osu.Dependencies.Get().GetWorkingBeatmap(set.Beatmaps.First(b => b.RulesetID == 2))?.Beatmap; + beatmap = store.GetWorkingBeatmap(set.Beatmaps.First(b => b.RulesetID == 2))?.Beatmap; Assert.IsTrue(beatmap?.HitObjects.Count > 0); - beatmap = osu.Dependencies.Get().GetWorkingBeatmap(set.Beatmaps.First(b => b.RulesetID == 3))?.Beatmap; + beatmap = store.GetWorkingBeatmap(set.Beatmaps.First(b => b.RulesetID == 3))?.Beatmap; Assert.IsTrue(beatmap?.HitObjects.Count > 0); } } diff --git a/osu.Game/Beatmaps/BeatmapDatabase.cs b/osu.Game/Beatmaps/BeatmapDatabase.cs index d32bf2dd5d..5906e72f50 100644 --- a/osu.Game/Beatmaps/BeatmapDatabase.cs +++ b/osu.Game/Beatmaps/BeatmapDatabase.cs @@ -94,7 +94,7 @@ namespace osu.Game.Beatmaps private void cleanupPendingDeletions() { - foreach (var b in GetAllWithChildren(b => b.DeletePending && !b.Protected)) + foreach (var b in QueryAndPopulate(b => b.DeletePending && !b.Protected)) { try { diff --git a/osu.Game/Beatmaps/BeatmapStore.cs b/osu.Game/Beatmaps/BeatmapStore.cs index b1c15e87be..a5f74aad1a 100644 --- a/osu.Game/Beatmaps/BeatmapStore.cs +++ b/osu.Game/Beatmaps/BeatmapStore.cs @@ -150,9 +150,7 @@ namespace osu.Game.Beatmaps if (beatmapInfo == null || beatmapInfo == DefaultBeatmap?.BeatmapInfo) return DefaultBeatmap; - beatmapInfo = Database.GetChildren(beatmapInfo, true); - - Database.GetChildren(beatmapInfo.BeatmapSet, true); + Database.Populate(beatmapInfo); if (beatmapInfo.BeatmapSet == null) throw new InvalidOperationException($@"Beatmap set {beatmapInfo.BeatmapSetInfoID} is not in the local database."); @@ -185,7 +183,7 @@ namespace osu.Game.Beatmaps BeatmapSetInfo set = Database.Query().FirstOrDefault(query); if (set != null) - Database.GetChildren(set, true); + Database.Populate(set); return set; } @@ -235,7 +233,7 @@ namespace osu.Game.Beatmaps if (existing != null) { - Database.GetChildren(existing); + Database.Populate(existing); Undelete(existing); return existing; } diff --git a/osu.Game/Database/DatabaseStore.cs b/osu.Game/Database/DatabaseStore.cs index 5187769bb2..8e884f062a 100644 --- a/osu.Game/Database/DatabaseStore.cs +++ b/osu.Game/Database/DatabaseStore.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Linq.Expressions; using osu.Framework.Logging; using osu.Framework.Platform; @@ -42,28 +43,50 @@ namespace osu.Game.Database /// public void Reset() => Prepare(true); - public TableQuery Query() where T : class + + public TableQuery Query(Expression> filter = null) where T : class { - return Connection.Table(); + checkType(typeof(T)); + + var query = Connection.Table(); + + if (filter != null) + query = query.Where(filter); + + return query; } /// - /// This is expensive. Use with caution. + /// Query and populate results. /// - public List GetAllWithChildren(Expression> filter = null, bool recursive = true) + /// An optional filter to refine results. + /// + public List QueryAndPopulate(Expression> filter = null) where T : class { - return Connection.GetAllWithChildren(filter, recursive); + checkType(typeof(T)); + + return Connection.GetAllWithChildren(filter, true); } - public T GetChildren(T item, bool recursive = false) + /// + /// Populate a database-backed item. + /// + /// + /// Whether population should recurse beyond a single level. + public void Populate(T item, bool recursive = true) { - if (item == null) return default(T); + checkType(item.GetType()); Connection.GetChildren(item, recursive); - return item; + } + + private void checkType(Type type) + { + if (!ValidTypes.Contains(type)) + throw new InvalidOperationException($"The requested operation specified a type of {type}, which is invalid for this {nameof(DatabaseStore)}."); } protected abstract Type[] ValidTypes { get; } } -} \ No newline at end of file +} diff --git a/osu.Game/IO/FileDatabase.cs b/osu.Game/IO/FileDatabase.cs index b61fbdb0e1..2fb43f9a57 100644 --- a/osu.Game/IO/FileDatabase.cs +++ b/osu.Game/IO/FileDatabase.cs @@ -97,7 +97,7 @@ namespace osu.Game.IO private void deletePending() { - foreach (var f in GetAllWithChildren(f => f.ReferenceCount < 1)) + foreach (var f in QueryAndPopulate(f => f.ReferenceCount < 1)) { try { diff --git a/osu.Game/Overlays/Music/PlaylistOverlay.cs b/osu.Game/Overlays/Music/PlaylistOverlay.cs index 37ec90ad32..780e713a3f 100644 --- a/osu.Game/Overlays/Music/PlaylistOverlay.cs +++ b/osu.Game/Overlays/Music/PlaylistOverlay.cs @@ -77,7 +77,7 @@ namespace osu.Game.Overlays.Music }, }; - list.BeatmapSets = BeatmapSets = beatmaps.Database.GetAllWithChildren(b => !b.DeletePending).ToList(); + list.BeatmapSets = BeatmapSets = beatmaps.Database.QueryAndPopulate(b => !b.DeletePending).ToList(); beatmaps.BeatmapSetAdded += s => list.AddBeatmapSet(s); beatmaps.BeatmapSetRemoved += s => list.RemoveBeatmapSet(s); diff --git a/osu.Game/Screens/Menu/Intro.cs b/osu.Game/Screens/Menu/Intro.cs index 55eedaba9a..b0f067d6ee 100644 --- a/osu.Game/Screens/Menu/Intro.cs +++ b/osu.Game/Screens/Menu/Intro.cs @@ -76,10 +76,13 @@ namespace osu.Game.Screens.Menu if (!menuMusic) { - var query = beatmaps.Database.Query().Where(b => !b.DeletePending); + var query = beatmaps.Database.Query(b => !b.DeletePending); int count = query.Count(); if (count > 0) + { setInfo = query.ElementAt(RNG.Next(0, count - 1)); + beatmaps.Database.Populate(setInfo); + } } if (setInfo == null) diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index ef1a65d914..1d87080958 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -180,7 +180,7 @@ namespace osu.Game.Screens.Select initialAddSetsTask = new CancellationTokenSource(); - carousel.Beatmaps = store.Database.GetAllWithChildren(b => !b.DeletePending); + carousel.Beatmaps = store.Database.QueryAndPopulate(b => !b.DeletePending); Beatmap.ValueChanged += beatmap_ValueChanged;