Skip to content

Commit 3dc299e

Browse files
committed
refactor: search member presenters by name
1 parent 7370f5a commit 3dc299e

2 files changed

Lines changed: 50 additions & 78 deletions

File tree

SgfDevs.Tests/PresenterMemberMatcherTests.cs

Lines changed: 10 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -8,43 +8,28 @@ namespace SgfDevs.Tests;
88
public class PresenterMemberMatcherTests
99
{
1010
[Fact]
11-
public void MatchPresenter_MatchesUniqueNormalizedFullName()
11+
public void BuildSearchTerms_IncludesNormalizedNameOnce()
1212
{
13-
var memberKey = Guid.NewGuid();
14-
var presenter = new ImportedPresenterPlan("speaker-1", "Bertram Gilfoyle", null);
15-
var lookup = PresenterMemberMatcher.BuildMemberNameLookup(
16-
[
17-
(memberKey, "Bertram Gilfoyle", "Bertram", "Gilfoyle")
18-
]);
13+
var result = PresenterMemberMatcher.BuildSearchTerms("Bertram Gilfoyle");
1914

20-
var result = PresenterMemberMatcher.MatchPresenter(presenter, lookup);
21-
22-
Assert.Equal(memberKey, result.MatchedMemberKey);
15+
Assert.Equal(["bertram gilfoyle", "Bertram Gilfoyle"], result);
2316
}
2417

2518
[Fact]
26-
public void MatchPresenter_DoesNotMatchWhenMultipleMembersShareTheSameName()
19+
public void GetMatchedMemberKey_ReturnsSingleKeyWhenExactlyOneMatchExists()
2720
{
28-
var presenter = new ImportedPresenterPlan("speaker-1", "Dinesh Chugtai", null);
29-
var lookup = PresenterMemberMatcher.BuildMemberNameLookup(
30-
[
31-
(Guid.NewGuid(), "Dinesh Chugtai", "Dinesh", "Chugtai"),
32-
(Guid.NewGuid(), "Dinesh Chugtai", "Dinesh", "Chugtai")
33-
]);
21+
var key = Guid.NewGuid();
3422

35-
var result = PresenterMemberMatcher.MatchPresenter(presenter, lookup);
23+
var result = PresenterMemberMatcher.GetMatchedMemberKey([key]);
3624

37-
Assert.Null(result.MatchedMemberKey);
25+
Assert.Equal(key, result);
3826
}
3927

4028
[Fact]
41-
public void MatchPresenter_DoesNotMatchWhenNoMemberExists()
29+
public void GetMatchedMemberKey_ReturnsNullWhenMultipleMatchesExist()
4230
{
43-
var presenter = new ImportedPresenterPlan("speaker-1", "Jared Dunn", null);
44-
var lookup = PresenterMemberMatcher.BuildMemberNameLookup(Array.Empty<(Guid Key, string? Name, string? FirstName, string? LastName)>());
45-
46-
var result = PresenterMemberMatcher.MatchPresenter(presenter, lookup);
31+
var result = PresenterMemberMatcher.GetMatchedMemberKey([Guid.NewGuid(), Guid.NewGuid()]);
4732

48-
Assert.Null(result.MatchedMemberKey);
33+
Assert.Null(result);
4934
}
5035
}

SgfDevs/Dev/EventSync/PresenterMemberMatcher.cs

Lines changed: 40 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.Collections.Generic;
44
using System.Linq;
55
using SgfDevs.Dev.EventSync.Sessionize;
6+
using Umbraco.Cms.Core.Persistence.Querying;
67
using Umbraco.Cms.Core.Services;
78

89
namespace SgfDevs.Dev.EventSync;
@@ -18,41 +19,53 @@ public PresenterMemberMatcher(IMemberService memberService)
1819

1920
public IReadOnlyList<ImportedPresenterPlan> MatchPresenters(IReadOnlyList<ImportedPresenterPlan> presenters)
2021
{
21-
var memberNameLookup = BuildMemberNameLookup(GetAllMemberNames());
22-
2322
return presenters
24-
.Select(presenter => MatchPresenter(presenter, memberNameLookup))
23+
.Select(MatchPresenter)
2524
.ToList();
2625
}
2726

28-
internal static ImportedPresenterPlan MatchPresenter(
29-
ImportedPresenterPlan presenter,
30-
IReadOnlyDictionary<string, IReadOnlyList<Guid>> memberNameLookup)
27+
private ImportedPresenterPlan MatchPresenter(ImportedPresenterPlan presenter)
28+
{
29+
var matchedMemberKey = FindUniqueMemberKey(presenter.Name);
30+
return matchedMemberKey.HasValue
31+
? presenter with { MatchedMemberKey = matchedMemberKey.Value }
32+
: presenter;
33+
}
34+
35+
internal static Guid? GetMatchedMemberKey(IReadOnlyList<Guid> memberKeys)
3136
{
32-
var normalizedName = NormalizeName(presenter.Name);
37+
return memberKeys.Count == 1 ? memberKeys[0] : null;
38+
}
39+
40+
internal static IReadOnlyList<string> BuildSearchTerms(string? name)
41+
{
42+
var normalizedName = NormalizeName(name);
3343
if (string.IsNullOrWhiteSpace(normalizedName))
3444
{
35-
return presenter;
45+
return [];
3646
}
3747

38-
if (memberNameLookup.TryGetValue(normalizedName, out var memberKeys) == false || memberKeys.Count != 1)
48+
var searchTerms = new List<string> { normalizedName };
49+
var trimmedName = name?.Trim();
50+
51+
if (string.IsNullOrWhiteSpace(trimmedName) == false && string.Equals(normalizedName, trimmedName, StringComparison.OrdinalIgnoreCase) == false)
3952
{
40-
return presenter;
53+
searchTerms.Add(trimmedName);
4154
}
4255

43-
return presenter with { MatchedMemberKey = memberKeys[0] };
56+
return searchTerms
57+
.Distinct(StringComparer.OrdinalIgnoreCase)
58+
.ToList();
4459
}
4560

46-
internal static IReadOnlyDictionary<string, IReadOnlyList<Guid>> BuildMemberNameLookup(IEnumerable<(Guid Key, string? Name, string? FirstName, string? LastName)> members)
61+
private Guid? FindUniqueMemberKey(string? presenterName)
4762
{
48-
return members
49-
.SelectMany(member => GetCandidateNames(member)
50-
.Select(name => new { Name = name, member.Key }))
51-
.GroupBy(item => item.Name, StringComparer.Ordinal)
52-
.ToDictionary(
53-
group => group.Key,
54-
group => (IReadOnlyList<Guid>)group.Select(item => item.Key).Distinct().ToList(),
55-
StringComparer.Ordinal);
63+
var memberKeys = BuildSearchTerms(presenterName)
64+
.SelectMany(FindMembersByDisplayName)
65+
.Distinct()
66+
.ToList();
67+
68+
return GetMatchedMemberKey(memberKeys);
5669
}
5770

5871
internal static string NormalizeName(string? name)
@@ -68,41 +81,15 @@ internal static string NormalizeName(string? name)
6881
.ToLowerInvariant();
6982
}
7083

71-
private IEnumerable<(Guid Key, string? Name, string? FirstName, string? LastName)> GetAllMemberNames()
84+
private IReadOnlyList<Guid> FindMembersByDisplayName(string searchTerm)
7285
{
73-
long pageIndex = 0;
74-
const int pageSize = 500;
86+
const int pageIndex = 0;
87+
const int pageSize = 10;
7588
long totalRecords;
7689

77-
do
78-
{
79-
var members = _memberService.GetAll(pageIndex, pageSize, out totalRecords).ToList();
80-
81-
foreach (var member in members)
82-
{
83-
yield return (
84-
member.Key,
85-
member.Name,
86-
member.GetValue<string>("firstName"),
87-
member.GetValue<string>("lastName"));
88-
}
89-
90-
pageIndex++;
91-
}
92-
while (pageIndex * pageSize < totalRecords);
93-
}
94-
95-
private static IEnumerable<string> GetCandidateNames((Guid Key, string? Name, string? FirstName, string? LastName) member)
96-
{
97-
if (string.IsNullOrWhiteSpace(member.Name) == false)
98-
{
99-
yield return NormalizeName(member.Name);
100-
}
101-
102-
var fullName = string.Join(' ', new[] { member.FirstName, member.LastName }.Where(value => string.IsNullOrWhiteSpace(value) == false));
103-
if (string.IsNullOrWhiteSpace(fullName) == false)
104-
{
105-
yield return NormalizeName(fullName);
106-
}
90+
return _memberService
91+
.FindMembersByDisplayName(searchTerm, pageIndex, pageSize, out totalRecords, StringPropertyMatchType.Exact)
92+
.Select(member => member.Key)
93+
.ToList();
10794
}
10895
}

0 commit comments

Comments
 (0)