Skip to content

Commit 8ff2044

Browse files
author
Declan Taylor
committed
Changed logic for filtering PathInformation for cached data - now matches based on FullName.
Cached data is returned in descending order of search time. Divided classes into separate files.
1 parent 38fe617 commit 8ff2044

File tree

8 files changed

+170
-99
lines changed

8 files changed

+170
-99
lines changed

source/Demos/CachedPathSuggestBoxDemo/CachedPathSuggestBoxDemo.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,8 @@
1414
<ProjectReference Include="..\..\SuggestBoxLib\SuggestBoxLib.csproj" />
1515
</ItemGroup>
1616

17+
<ItemGroup>
18+
<Folder Include="Data\" />
19+
</ItemGroup>
20+
1721
</Project>
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
#nullable enable
2+
using System;
3+
using System.Collections.Generic;
4+
using System.IO;
5+
using System.Linq;
6+
using System.Threading.Tasks;
7+
8+
namespace CachedPathSuggestBoxDemo.Infrastructure
9+
{
10+
11+
12+
public class CachedPathInformationSuggest :ISuggest
13+
{
14+
public void Insert(string path)
15+
{
16+
var fileInfo =new FileInfo(path);
17+
if (fileInfo.Exists)
18+
{
19+
LiteRepository.Instance.Insert(fileInfo.FullName);
20+
}
21+
22+
var directoryInfo = new DirectoryInfo(path);
23+
if (!directoryInfo.Exists) return;
24+
LiteRepository.Instance.Insert(directoryInfo.FullName);
25+
}
26+
27+
/// <summary>
28+
/// Makes suggestions of paths based on match between query and the name of the path.
29+
/// Only returns latest 3 results. Newest first.
30+
/// </summary>
31+
/// <inheritdoc cref="MakeSuggestions"/>
32+
/// <example>
33+
/// <see cref="queryThis"/> : doc
34+
/// will match with
35+
/// c:\\Documents
36+
/// t:\\files\store\doC.xaml
37+
/// but not
38+
/// f:\\do_letters
39+
/// g:\\document\lists.ico
40+
/// </example>
41+
public async Task<IEnumerable<object>?> MakeSuggestions(string queryThis)
42+
{
43+
return await Task.Run(() => MakeSuggestionsPrivate(queryThis).ToArray());
44+
45+
IEnumerable<object> MakeSuggestionsPrivate(string queryThis) => from item in GetPathInformations(queryThis)
46+
where item.Name.Contains(queryThis, StringComparison.CurrentCultureIgnoreCase)
47+
select new { Header = item.FullName, Value = item.FullName };
48+
49+
static PathInformation[] GetPathInformations(string key)
50+
{
51+
return LiteRepository.Instance.Filter(key).OrderByDescending(a => a.Value).Take(5).Select(a => new PathInformation(a.Key)).ToArray();
52+
}
53+
}
54+
}
55+
}

source/Demos/CachedPathSuggestBoxDemo/Infrastructure/DirectorySuggestSource.cs

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ namespace CachedPathSuggestBoxDemo.Infrastructure
1313
/// Defines a suggestion object to generate suggestions
1414
/// based on sub entries of specified string.
1515
/// </summary>
16-
public class DirectorySuggestSource
16+
public class DirectorySuggest : ISuggest
1717
{
1818
#region fields
1919
private readonly Dictionary<string, CancellationTokenSource> _Queue;
@@ -24,7 +24,7 @@ public class DirectorySuggestSource
2424
/// <summary>
2525
/// Class constructor
2626
/// </summary>
27-
public DirectorySuggestSource()
27+
public DirectorySuggest()
2828
{
2929
_Queue = new Dictionary<string, CancellationTokenSource>();
3030
_SlowStuffSemaphore = new SemaphoreSlim(1, 1);
@@ -69,14 +69,14 @@ public DirectorySuggestSource()
6969

7070

7171

72-
static IEnumerable<object> EnumerateSubDirs(string input)
72+
static IEnumerable<object>? EnumerateSubDirs(string input)
7373
{
7474
if (string.IsNullOrEmpty(input))
7575
return EnumerateLogicalDrives();
7676

7777
var subDirs = EnumerateLogicalDriveOrSubDirs(input, input);
7878

79-
return subDirs ?? Get();
79+
return subDirs!=null? subDirs.Any()? subDirs: Get():null;
8080

8181
// Find last separator and list directories underneath
8282
// with * search-pattern
@@ -90,7 +90,7 @@ IEnumerable<object> Get()
9090
string[]? directories = null;
9191
try
9292
{
93-
directories = System.IO.Directory.GetDirectories(folder, searchPattern);
93+
directories = Directory.GetDirectories(folder, searchPattern);
9494
}
9595
catch
9696
{
@@ -161,21 +161,38 @@ static IEnumerable<object> EnumerateLogicalDrives()
161161

162162
static IEnumerable<object>? EnumerateLogicalDriveOrSubDirs(string testDrive, string input)
163163
{
164-
return System.IO.Directory.Exists(testDrive) != true ?
165-
null :
166-
GetLogicalDriveOrSubDirs2(testDrive, input);
167-
168-
static IEnumerable<object> GetLogicalDriveOrSubDirs2(string testDrive, string input)
164+
return System.IO.Directory.Exists(testDrive) ?
165+
GetDirectories(testDrive) is {} array?
166+
GetLogicalDriveOrSubDirs2(testDrive, input, array):
167+
null:
168+
null;
169+
170+
171+
static IEnumerable<object>? GetLogicalDriveOrSubDirs2(string testDrive, string input, IEnumerable<string> directories)
169172
{
170173
// List the drive itself if there was only 1 or 2 letters
171174
// since this is not a valid drive and we don'nt know if the user
172175
// wants to go to the drive or a folder contained in it
173176
if (input.Length <= 2)
174177
yield return new {Header = testDrive, Value = testDrive};
175178

176-
// and list all sub-directories of that drive
177-
foreach (var item in System.IO.Directory.GetDirectories(testDrive))
178-
yield return new {Header = item, Value = item};
179+
foreach (var item in directories)
180+
yield return new { Header = item, Value = item };
181+
}
182+
183+
static string[]? GetDirectories(string testDrive)
184+
{
185+
string[] directories;
186+
try
187+
{
188+
directories = Directory.GetDirectories(testDrive);
189+
}
190+
catch (UnauthorizedAccessException)
191+
{
192+
return null;
193+
}
194+
195+
return directories;
179196
}
180197
}
181198
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#nullable enable
2+
3+
using System.Collections.Generic;
4+
using System.Threading.Tasks;
5+
6+
namespace CachedPathSuggestBoxDemo.Infrastructure
7+
{
8+
public interface ISuggest
9+
{
10+
/// <summary>
11+
/// Makes suggestions based on <see cref="queryThis"/>
12+
/// </summary>
13+
Task<IEnumerable<object>?> MakeSuggestions(string queryThis);
14+
}
15+
}
Lines changed: 10 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,12 @@
1-
using System;
1+
#nullable enable
2+
using System;
23
using System.Collections.Generic;
34
using System.IO;
45
using System.Linq;
56
using LiteDB;
67

78
namespace CachedPathSuggestBoxDemo.Infrastructure
89
{
9-
10-
public class SuggestionProvider
11-
{
12-
private Lazy<PathInformation[]> filesCache => new Lazy<PathInformation[]>(() =>
13-
{
14-
var folders = LiteRepository.Instance.SelectAll();
15-
return folders.Select(a => new PathInformation(a.Value)).ToArray();
16-
});
17-
18-
public IEnumerable<PathInformation> Collection => filesCache.Value;
19-
20-
public void Insert(string path)
21-
{
22-
var fileInfo =new FileInfo(path);
23-
if(fileInfo.Exists)
24-
LiteRepository.Instance.Insert(fileInfo.Name,fileInfo.FullName);
25-
26-
var directoryInfo = new DirectoryInfo(path);
27-
if (directoryInfo.Exists)
28-
LiteRepository.Instance.Insert(directoryInfo.Name, directoryInfo.FullName);
29-
}
30-
}
31-
32-
3310
public sealed class LiteRepository
3411
{
3512
private const string DbPath = @"..\..\..\Data\KeyValue.litedb";
@@ -43,18 +20,20 @@ static LiteRepository()
4320
{
4421
}
4522

46-
public void Insert(string k, string value, string collectionName = null)
23+
public void Insert(string k, string? collectionName = null)
4724
{
4825
using var db = new LiteDatabase(DbPath);
49-
var col = db.GetCollection<KeyValuePair<string, string>>(collectionName ??= CollectionName);
50-
col.Upsert(new KeyValuePair<string, string>(k, value));
26+
var col = db.GetCollection<KeyValuePair<string, DateTime>>(collectionName ?? CollectionName);
27+
col.Upsert(new KeyValuePair<string, DateTime>(k, DateTime.Now));
5128
}
5229

53-
public IEnumerable<KeyValuePair<string, string>> SelectAll(string collectionName = null)
30+
public IEnumerable<KeyValuePair<string, DateTime>> Filter(string key, string? collectionName = null)
5431
{
5532
using var db = new LiteDatabase(DbPath);
56-
var col = db.GetCollection<KeyValuePair<string, string>>(collectionName ??= CollectionName);
57-
return col.Query().ToArray();
33+
var col = db.GetCollection<KeyValuePair<string, DateTime>>(collectionName ?? CollectionName);
34+
return string.IsNullOrEmpty(key)?
35+
new KeyValuePair<string, DateTime>[]{}:
36+
col.Find(Query.Contains(nameof(KeyValuePair<string, DateTime>.Key), key)).ToArray();
5837
}
5938

6039
private LiteRepository()
@@ -69,45 +48,4 @@ private LiteRepository()
6948

7049
public static LiteRepository Instance { get; } = new LiteRepository();
7150
}
72-
73-
74-
75-
public class PathInformation : IEquatable<PathInformation>
76-
{
77-
public PathInformation(string argValue)
78-
{
79-
if (new DirectoryInfo(argValue).Parent == null)
80-
{
81-
Name = argValue;
82-
}
83-
else
84-
Name = System.IO.Path.GetFileName(argValue);
85-
FullName = argValue;
86-
}
87-
88-
public string Name { get; }
89-
90-
public string FullName { get; }
91-
92-
93-
public bool Equals(PathInformation other)
94-
{
95-
if (ReferenceEquals(null, other)) return false;
96-
if (ReferenceEquals(this, other)) return true;
97-
return Name == other.Name && FullName == other.FullName;
98-
}
99-
100-
public override bool Equals(object obj)
101-
{
102-
if (ReferenceEquals(null, obj)) return false;
103-
if (ReferenceEquals(this, obj)) return true;
104-
if (obj.GetType() != this.GetType()) return false;
105-
return Equals((PathInformation)obj);
106-
}
107-
108-
public override int GetHashCode()
109-
{
110-
return HashCode.Combine(Name, FullName);
111-
}
112-
}
11351
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
using System;
2+
using System.IO;
3+
4+
namespace CachedPathSuggestBoxDemo.Infrastructure
5+
{
6+
public class PathInformation : IEquatable<PathInformation>
7+
{
8+
public PathInformation(string argValue)
9+
{
10+
Name = new DirectoryInfo(argValue).Parent == null ? argValue : Path.GetFileName(argValue);
11+
FullName = argValue;
12+
}
13+
14+
public string Name { get; }
15+
16+
public string FullName { get; }
17+
18+
19+
public bool Equals(PathInformation other)
20+
{
21+
if (ReferenceEquals(null, other)) return false;
22+
if (ReferenceEquals(this, other)) return true;
23+
return Name == other.Name && FullName == other.FullName;
24+
}
25+
26+
public override bool Equals(object obj)
27+
{
28+
if (ReferenceEquals(null, obj)) return false;
29+
if (ReferenceEquals(this, obj)) return true;
30+
if (obj.GetType() != this.GetType()) return false;
31+
return Equals((PathInformation)obj);
32+
}
33+
34+
public override int GetHashCode()
35+
{
36+
return HashCode.Combine(Name, FullName);
37+
}
38+
}
39+
}

source/Demos/CachedPathSuggestBoxDemo/MainWindow.xaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
Width="400"
1616
x:Name="DiskPathSuggestBox"
1717
Hint="Enter a file system path"
18+
FontSize="14"
1819
Text="{Binding Text}"
1920
Margin="5" />
2021
<Button Width="100" Grid.Column="1" Content="Save" FontSize="20" FontWeight="Bold" Margin="5" Click="ButtonBase_OnClick">

source/Demos/CachedPathSuggestBoxDemo/MainWindow.xaml.cs

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,16 @@ namespace CachedPathSuggestBoxDemo
1111
/// </summary>
1212
public partial class MainWindow : Window
1313
{
14-
DirectorySuggestSource source = new DirectorySuggestSource();
15-
FastObservableCollection<object> _ListQueryResult = new FastObservableCollection<object>();
16-
SuggestionProvider folderSuggestionProvider =new SuggestionProvider();
14+
private readonly DirectorySuggest directorySuggest = new DirectorySuggest();
15+
private readonly FastObservableCollection<object> listQueryResult = new FastObservableCollection<object>();
16+
public readonly CachedPathInformationSuggest cachedPathInformationSuggest =new CachedPathInformationSuggest();
1717

1818
public MainWindow()
1919
{
2020
InitializeComponent();
2121

2222
this.DiskPathSuggestBox.TextChangedCommand = new RelayCommand<object>(Execute); ;
23-
this.DiskPathSuggestBox.ItemsSource = _ListQueryResult;
23+
this.DiskPathSuggestBox.ItemsSource = listQueryResult;
2424
this.DiskPathSuggestBox.DataContext = this;
2525

2626
}
@@ -36,26 +36,28 @@ private async void Execute(object p)
3636
if (!(p is string newText))
3737
return;
3838

39-
var suggestions1 = folderSuggestionProvider.Collection.Where(a => a.Name.Contains(newText, StringComparison.CurrentCultureIgnoreCase)).ToArray();
39+
var suggestions2 = await directorySuggest.MakeSuggestions(newText);
4040

41-
var suggestions = await source.MakeSuggestions(newText);
42-
43-
_ListQueryResult.Clear();
44-
if (suggestions == null&& suggestions1.Any()==false)
41+
listQueryResult.Clear();
42+
if (suggestions2 == null)
43+
{
44+
this.DiskPathSuggestBox.ValidText = false;
4545
return;
46+
}
47+
this.DiskPathSuggestBox.ValidText = true;
48+
49+
var suggestions1 = await cachedPathInformationSuggest.MakeSuggestions(newText);
4650

4751
var enumerable = suggestions1
48-
.Select(a => new { Header = a.FullName, Value = a.FullName })
49-
.Concat(suggestions as object[] ?? suggestions?? new List<object>())
52+
.Concat(suggestions2)
5053
.ToArray();
5154

52-
this.DiskPathSuggestBox.ValidText = enumerable.Any();
53-
_ListQueryResult.AddItems(enumerable);
55+
listQueryResult.AddItems(enumerable);
5456
}
5557

5658
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
5759
{
58-
folderSuggestionProvider.Insert(Text);
60+
cachedPathInformationSuggest.Insert(Text);
5961
}
6062
}
6163
}

0 commit comments

Comments
 (0)