Skip to content

Commit d075473

Browse files
committed
Iterate entry WS keys for headwords; add headword to search post-filter
- ComputeHeadwords: iterate CitationForm/LexemeForm keys instead of a passed-in vernacular WS list, so non-current WSs get headwords too - Same change for FwDataMiniLcmApi.ComputeHeadword - Remove GetVernacularWritingSystems() from MiniLcmRepository (no longer needed) - Simplify Finalize overload signature (drop vernacularWritingSystems param) - Add headword match to FilterInternal WHERE clause so entries with morph-token-decorated headwords aren't excluded by the post-filter - Add TODO to Filtering.cs for the same pattern https://claude.ai/code/session_01GFNCNDE5wHE2hGC7pQQp2f
1 parent 75bed9b commit d075473

6 files changed

Lines changed: 32 additions & 27 deletions

File tree

backend/FwLite/FwDataMiniLcmBridge/Api/FwDataMiniLcmApi.cs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -671,15 +671,19 @@ private Entry FromLexEntry(ILexEntry entry)
671671
}
672672
}
673673

674-
private MultiString ComputeHeadword(Entry result, IMoMorphType? lcmMorphType)
674+
private static MultiString ComputeHeadword(Entry result, IMoMorphType? lcmMorphType)
675675
{
676676
var headword = new MultiString();
677677
var leading = lcmMorphType?.Prefix ?? "";
678678
var trailing = lcmMorphType?.Postfix ?? "";
679679

680-
foreach (var wsDef in WritingSystemContainer.CurrentVernacularWritingSystems)
680+
// Iterate all WS keys that have data, not just "current" vernacular WSs,
681+
// so we don't lose headwords for non-current or future writing systems.
682+
var wsIds = result.CitationForm.Values.Keys
683+
.Union(result.LexemeForm.Values.Keys);
684+
685+
foreach (var wsId in wsIds)
681686
{
682-
WritingSystemId wsId = wsDef.Id;
683687
var citation = result.CitationForm[wsId];
684688
if (!string.IsNullOrEmpty(citation))
685689
{

backend/FwLite/LcmCrdt/Data/EntryQueryHelpers.cs

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,31 +38,36 @@ public static string HeadwordWithTokens(this Entry e, WritingSystemId ws, string
3838
: Json.Value(e.CitationForm, ms => ms[ws])!.Trim();
3939

4040
/// <summary>
41-
/// Computes headwords for all vernacular writing systems, applying morph tokens when CitationForm is absent.
41+
/// Computes headwords for all writing systems present in CitationForm or LexemeForm,
42+
/// applying morph tokens when CitationForm is absent.
4243
/// Used for in-memory population of Entry.Headword after loading from DB.
4344
/// </summary>
4445
public static MultiString ComputeHeadwords(Entry entry,
45-
IReadOnlyDictionary<MorphType, MorphTypeData> morphTypeDataLookup,
46-
IEnumerable<WritingSystem> vernacularWritingSystems)
46+
IReadOnlyDictionary<MorphType, MorphTypeData> morphTypeDataLookup)
4747
{
4848
var result = new MultiString();
4949
morphTypeDataLookup.TryGetValue(entry.MorphType, out var morphData);
5050

51-
foreach (var ws in vernacularWritingSystems)
51+
// Iterate all WS keys that have data, not just "current" vernacular WSs,
52+
// so we don't lose headwords for non-current or future writing systems.
53+
var wsIds = entry.CitationForm.Values.Keys
54+
.Union(entry.LexemeForm.Values.Keys);
55+
56+
foreach (var wsId in wsIds)
5257
{
53-
var citation = entry.CitationForm[ws.WsId];
58+
var citation = entry.CitationForm[wsId];
5459
if (!string.IsNullOrEmpty(citation))
5560
{
56-
result[ws.WsId] = citation.Trim();
61+
result[wsId] = citation.Trim();
5762
continue;
5863
}
5964

60-
var lexeme = entry.LexemeForm[ws.WsId];
65+
var lexeme = entry.LexemeForm[wsId];
6166
if (!string.IsNullOrEmpty(lexeme))
6267
{
6368
var leading = morphData?.LeadingToken ?? "";
6469
var trailing = morphData?.TrailingToken ?? "";
65-
result[ws.WsId] = (leading + lexeme + trailing).Trim();
70+
result[wsId] = (leading + lexeme + trailing).Trim();
6671
}
6772
}
6873

backend/FwLite/LcmCrdt/Data/Filtering.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ public static IQueryable<Entry> WhereExemplar(
1515
return query.Where(e => e.Headword(ws).StartsWith(exemplar));
1616
}
1717

18+
// TODO: When morph tokens are added, this should also check headword with tokens.
19+
// See EntrySearchService.FilterInternal for the pattern (needs wsId parameter).
1820
public static Expression<Func<Entry, bool>> SearchFilter(string query)
1921
{
2022
return e => e.LexemeForm.SearchValue(query)

backend/FwLite/LcmCrdt/Data/MiniLcmRepository.cs

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -78,15 +78,6 @@ public void Dispose()
7878
private IReadOnlyDictionary<MorphType, MorphTypeData> _morphTypeDataLookup =
7979
new Dictionary<MorphType, MorphTypeData>();
8080

81-
private WritingSystem[]? _vernacularWritingSystems;
82-
83-
private async ValueTask<WritingSystem[]> GetVernacularWritingSystems()
84-
{
85-
return _vernacularWritingSystems ??= await WritingSystemsOrdered
86-
.Where(ws => ws.Type == WritingSystemType.Vernacular)
87-
.ToArrayAsync();
88-
}
89-
9081
public IQueryable<Publication> Publications => dbContext.Publications;
9182

9283

@@ -159,12 +150,11 @@ public async IAsyncEnumerable<Entry> GetEntries(
159150
queryable = options.ApplyPaging(queryable);
160151
var complexFormComparer = cultureProvider.GetCompareInfo(await GetWritingSystem(default, WritingSystemType.Vernacular))
161152
.AsComplexFormComparer();
162-
var vernacularWss = await GetVernacularWritingSystems();
163153
var entries = AsyncExtensions.AsAsyncEnumerable(queryable);
164154
await EnsureConnectionOpen();//sometimes there can be a race condition where the collations arent setup
165155
await foreach (var entry in EfExtensions.SafeIterate(entries))
166156
{
167-
entry.Finalize(complexFormComparer, _morphTypeDataLookup, vernacularWss);
157+
entry.Finalize(complexFormComparer, _morphTypeDataLookup);
168158
yield return entry;
169159
}
170160
}
@@ -269,7 +259,7 @@ private ValueTask<IQueryable<Entry>> ApplySorting(IQueryable<Entry> queryable, Q
269259
var sortWs = await GetWritingSystem(WritingSystemId.Default, WritingSystemType.Vernacular);
270260
var complexFormComparer = cultureProvider.GetCompareInfo(sortWs)
271261
.AsComplexFormComparer();
272-
entry.Finalize(complexFormComparer, _morphTypeDataLookup, await GetVernacularWritingSystems());
262+
entry.Finalize(complexFormComparer, _morphTypeDataLookup);
273263
}
274264

275265
return entry;

backend/FwLite/LcmCrdt/FullTextSearch/EntrySearchService.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,12 @@ from entry in queryable.InnerJoin(r => r.Id == searchRecord.Id)
7171
where Sql.Ext.SQLite().Match(searchRecord, ftsString) &&
7272
(entry.LexemeForm.SearchValue(query)
7373
|| entry.CitationForm.SearchValue(query)
74-
|| entry.Senses.Any(s => s.Gloss.SearchValue(query)))
74+
|| entry.Senses.Any(s => s.Gloss.SearchValue(query))
75+
// Headword includes morph tokens (e.g. "-" prefix for suffixes) that aren't in
76+
// LexemeForm/CitationForm. Without this, FTS matches on token-decorated headwords
77+
// would be excluded by the post-filter. Currently only checks the active WS;
78+
// when MorphTypeData becomes a CRDT entity, Headword() will include real tokens.
79+
|| SqlHelpers.ContainsIgnoreCaseAccents(entry.Headword(wsId), query))
7580
let headword = entry.Headword(wsId)
7681
let headwordMatches = SqlHelpers.ContainsIgnoreCaseAccents(headword, query)
7782
let headwordPrefixMatches = SqlHelpers.StartsWithIgnoreCaseAccents(headword, query)

backend/FwLite/LcmCrdt/QueryHelpers.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,10 @@ public static class QueryHelpers
77
{
88
public static void Finalize(this Entry entry,
99
IComparer<ComplexFormComponent> complexFormComparer,
10-
IReadOnlyDictionary<MorphType, MorphTypeData> morphTypeDataLookup,
11-
WritingSystem[] vernacularWritingSystems)
10+
IReadOnlyDictionary<MorphType, MorphTypeData> morphTypeDataLookup)
1211
{
1312
entry.Finalize(complexFormComparer);
14-
entry.Headword = EntryQueryHelpers.ComputeHeadwords(entry, morphTypeDataLookup, vernacularWritingSystems);
13+
entry.Headword = EntryQueryHelpers.ComputeHeadwords(entry, morphTypeDataLookup);
1514
}
1615

1716
public static void Finalize(this Entry entry, IComparer<ComplexFormComponent> complexFormComparer)

0 commit comments

Comments
 (0)