Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/SentenceStudio.Shared/Models/FilterToken.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ public sealed record FilterToken(string Type, string Value)
"status",
"association",
"language",
"encoding"
"encoding",
"type"
};

public bool IsValid =>
Expand Down
4 changes: 2 additions & 2 deletions src/SentenceStudio.Shared/Services/SearchQueryParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public class SearchQueryParser : ISearchQueryParser
// Supports quoted values for multi-word filters: tag:"multi word"
// Also supports unquoted values that end at whitespace
private static readonly Regex FilterPattern = new(
@"(tag|resource|lemma|status|association|language|encoding):(?:""([^""]*)""|(\S+))",
@"(tag|resource|lemma|status|association|language|encoding|type):(?:""([^""]*)""|(\S+))",
RegexOptions.IgnoreCase | RegexOptions.Compiled);

/// <summary>
Expand Down Expand Up @@ -128,7 +128,7 @@ public bool IsValidFilterToken(string filterType, string filterValue)
var textBeforeCursor = text.Substring(0, cursorPosition);

// Match filter prefix at end of text: tag:partial or tag:"partial
var activeFilterPattern = new Regex(@"(tag|resource|lemma|status|association|language|encoding):(?:""([^""]*)|(\S*))$", RegexOptions.IgnoreCase);
var activeFilterPattern = new Regex(@"(tag|resource|lemma|status|association|language|encoding|type):(?:""([^""]*)|(\S*))$", RegexOptions.IgnoreCase);
var match = activeFilterPattern.Match(textBeforeCursor);

if (match.Success)
Expand Down
32 changes: 32 additions & 0 deletions tests/SentenceStudio.UnitTests/Services/SearchQueryParserTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,35 @@ public void Parse_ComplexQuery_HandlesAllFilterTypes()
result.FreeTextTerms.Should().Contain("단풍");
}

[Theory]
[InlineData("type:word", "word")]
[InlineData("type:phrase", "phrase")]
[InlineData("type:sentence", "sentence")]
[InlineData("TYPE:Sentence", "Sentence")]
public void Parse_TypeFilter_ExtractsCorrectly(string query, string expectedValue)
{
// Act
var result = _sut.Parse(query);

// Assert
result.Filters.Should().HaveCount(1);
result.Filters[0].Type.Should().Be("type");
result.Filters[0].Value.Should().Be(expectedValue);
}

[Fact]
public void Parse_TypeFilterWithOtherFilters_ExtractsAll()
{
// Act
var result = _sut.Parse("type:sentence status:learning 단풍");

// Assert
result.Filters.Should().HaveCount(2);
result.Filters.Should().Contain(f => f.Type == "type" && f.Value == "sentence");
result.Filters.Should().Contain(f => f.Type == "status" && f.Value == "learning");
result.FreeTextTerms.Should().Contain("단풍");
}

#endregion

#region IsValidFilterToken Tests
Expand All @@ -238,6 +267,9 @@ public void Parse_ComplexQuery_HandlesAllFilterTypes()
[InlineData("status", "learning", true)]
[InlineData("status", "known", true)]
[InlineData("status", "unknown", true)]
[InlineData("type", "word", true)]
[InlineData("type", "phrase", true)]
[InlineData("type", "sentence", true)]
[InlineData("status", "invalid", false)]
[InlineData("invalid", "value", false)]
[InlineData("tag", "", false)]
Expand Down