Add ability to test collection rules before saving:
- New API endpoint: POST /api/collections/test-rules
- Evaluates rules against all media items
- Returns matching books with reasons
- Supports all operators: equals, contains, greater_than, etc.
- Works with all fields: genre, author, series, etc.
Backend Implementation:
- TestRules() handler in collections.go
- evaluateRule() matches book properties against rule criteria
- compareValues() handles string/numeric comparisons
- Case-insensitive matching for contains operator
Frontend Integration:
- Updated testRule() function in collection_rules.templ
- Displays matching books with covers and authors
- Shows match reason (which rule criteria matched)
- Limits preview to 20 results with count indicator
Tests Added:
- TestCompareValues_Equals: Exact match validation
- TestCompareValues_Contains: Substring matching
- TestCompareValues_GreaterThan: Numeric comparison
- TestCompareValues_NotEquals: Negation
- TestEvaluateRule_Genre: Genre field matching
- TestEvaluateRule_Author: Author field matching
- TestEvaluateRule_CopyrightYear: Year field matching
API Request Format:
{
"rules": [{
"field": "genre",
"operator": "equals",
"value": "Science Fiction"
}]
}
API Response Format:
{
"matches": [{
"media_item_id": "uuid",
"title": "Book Title",
"author": "Author Name",
"cover_image_path": "/path/to/cover.jpg",
"match_reason": "Matched rule: genre equals Science Fiction"
}],
"total": 42
}
Resolves Limitation #1: Rule Testing Preview
93 lines
2.4 KiB
Go
93 lines
2.4 KiB
Go
package handlers
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"bookmann/internal/database"
|
|
|
|
"github.com/jackc/pgx/v5/pgtype"
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
func TestCompareValues_Equals(t *testing.T) {
|
|
handler := &CollectionHandler{}
|
|
|
|
result := handler.compareValues("Science Fiction", "equals", "Science Fiction")
|
|
assert.True(t, result)
|
|
|
|
result = handler.compareValues("Science Fiction", "equals", "Fantasy")
|
|
assert.False(t, result)
|
|
}
|
|
|
|
func TestCompareValues_Contains(t *testing.T) {
|
|
handler := &CollectionHandler{}
|
|
|
|
result := handler.compareValues("Isaac Asimov", "contains", "asimov")
|
|
assert.True(t, result)
|
|
|
|
result = handler.compareValues("Isaac Asimov", "contains", "clarke")
|
|
assert.False(t, result)
|
|
}
|
|
|
|
func TestCompareValues_GreaterThan(t *testing.T) {
|
|
handler := &CollectionHandler{}
|
|
|
|
result := handler.compareValues("2021", "greater_than", "2000")
|
|
assert.True(t, result)
|
|
|
|
result = handler.compareValues("1999", "greater_than", "2000")
|
|
assert.False(t, result)
|
|
}
|
|
|
|
func TestCompareValues_NotEquals(t *testing.T) {
|
|
handler := &CollectionHandler{}
|
|
|
|
result := handler.compareValues("Science Fiction", "not_equals", "Fantasy")
|
|
assert.True(t, result)
|
|
|
|
result = handler.compareValues("Science Fiction", "not_equals", "Science Fiction")
|
|
assert.False(t, result)
|
|
}
|
|
|
|
func TestEvaluateRule_Genre(t *testing.T) {
|
|
item := database.ListMediaItemsRow{
|
|
Genre: pgtype.Text{String: "Science Fiction", Valid: true},
|
|
}
|
|
|
|
handler := &CollectionHandler{}
|
|
|
|
result := handler.evaluateRule(item, "genre", "equals", "Science Fiction")
|
|
assert.True(t, result)
|
|
|
|
result = handler.evaluateRule(item, "genre", "equals", "Fantasy")
|
|
assert.False(t, result)
|
|
}
|
|
|
|
func TestEvaluateRule_Author(t *testing.T) {
|
|
item := database.ListMediaItemsRow{
|
|
Author: pgtype.Text{String: "Isaac Asimov", Valid: true},
|
|
}
|
|
|
|
handler := &CollectionHandler{}
|
|
|
|
result := handler.evaluateRule(item, "author", "contains", "asimov")
|
|
assert.True(t, result)
|
|
|
|
result = handler.evaluateRule(item, "author", "contains", "clarke")
|
|
assert.False(t, result)
|
|
}
|
|
|
|
func TestEvaluateRule_CopyrightYear(t *testing.T) {
|
|
item := database.ListMediaItemsRow{
|
|
CopyrightYear: pgtype.Int4{Int32: 2021, Valid: true},
|
|
}
|
|
|
|
handler := &CollectionHandler{}
|
|
|
|
result := handler.evaluateRule(item, "copyright_year", "greater_than", "2000")
|
|
assert.True(t, result)
|
|
|
|
result = handler.evaluateRule(item, "copyright_year", "less_than", "2000")
|
|
assert.False(t, result)
|
|
}
|