mirror of
https://github.com/edufeed-org/eventstore.git
synced 2025-12-10 00:34:32 +00:00
add some filter function
This commit is contained in:
parent
956860676a
commit
5e16129e4c
4 changed files with 212 additions and 30 deletions
|
|
@ -17,15 +17,22 @@ func (ts *TSBackend) QueryEvents(ctx context.Context, filter nostr.Filter) (chan
|
|||
ch := make(chan *nostr.Event)
|
||||
|
||||
log.Printf("Processing query with search: %s", filter.Search)
|
||||
|
||||
// If we have no search parameter, return an empty channel
|
||||
if filter.Search == "" {
|
||||
log.Printf("No search parameter provided, returning empty result")
|
||||
close(ch)
|
||||
return ch, nil
|
||||
|
||||
// Determine the limit for results (default to 100 if not specified)
|
||||
limit := 100
|
||||
if filter.Limit > 0 {
|
||||
limit = filter.Limit
|
||||
}
|
||||
|
||||
nostrsearch, err := ts.SearchResources(filter.Search)
|
||||
// Use empty search string or the provided search string
|
||||
searchStr := filter.Search
|
||||
if searchStr == "" {
|
||||
log.Printf("No search parameter provided, querying all documents with limit %d", limit)
|
||||
} else {
|
||||
log.Printf("Processing query with search: %s and limit %d", searchStr, limit)
|
||||
}
|
||||
|
||||
nostrsearch, err := ts.SearchResourcesWithLimit(searchStr, limit)
|
||||
if err != nil {
|
||||
log.Printf("Search failed: %v", err)
|
||||
// Return the channel anyway, but close it immediately
|
||||
|
|
@ -57,7 +64,7 @@ func (ts *TSBackend) QueryEvents(ctx context.Context, filter nostr.Filter) (chan
|
|||
close(ch)
|
||||
}
|
||||
}()
|
||||
|
||||
|
||||
return ch, nil
|
||||
}
|
||||
|
||||
|
|
@ -126,6 +133,76 @@ func (ts *TSBackend) SearchResources(searchStr string) ([]nostr.Event, error) {
|
|||
return parseSearchResponse(body)
|
||||
}
|
||||
|
||||
// searches for resources with limit support and returns both the AMB metadata and converted Nostr events
|
||||
func (ts *TSBackend) SearchResourcesWithLimit(searchStr string, limit int) ([]nostr.Event, error) {
|
||||
parsedQuery := ParseSearchQuery(searchStr)
|
||||
|
||||
mainQuery, params, err := BuildTypesenseQuery(parsedQuery)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error building Typesense query: %v", err)
|
||||
}
|
||||
|
||||
// If no search terms provided, use wildcard to match all documents
|
||||
if mainQuery == "" {
|
||||
mainQuery = "*"
|
||||
}
|
||||
|
||||
// URL encode the main query
|
||||
encodedQuery := url.QueryEscape(mainQuery)
|
||||
|
||||
// Default fields to search in
|
||||
queryBy := "name,description,about,learningResourceType,keywords,creator,publisher"
|
||||
|
||||
// Start building the search URL with limit
|
||||
searchURL := fmt.Sprintf("%s/collections/%s/documents/search?validate_field_names=false&q=%s&query_by=%s&per_page=%d",
|
||||
ts.Host, ts.CollectionName, encodedQuery, queryBy, limit)
|
||||
|
||||
// Add additional parameters
|
||||
for key, value := range params {
|
||||
searchURL += fmt.Sprintf("&%s=%s", key, url.QueryEscape(value))
|
||||
}
|
||||
|
||||
// Debug information
|
||||
fmt.Printf("Search URL: %s\n", searchURL)
|
||||
|
||||
resp, body, err := ts.makehttpRequest(searchURL, http.MethodGet, nil)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error reading response body: %v", err)
|
||||
}
|
||||
|
||||
// Check for errors
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("search failed with status code %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
|
||||
// Try to parse the raw JSON to understand its structure
|
||||
var rawResponse interface{}
|
||||
if err := json.Unmarshal(body, &rawResponse); err != nil {
|
||||
fmt.Printf("Warning: Could not parse raw response as JSON: %v\n", err)
|
||||
} else {
|
||||
// Check if we got a hits array
|
||||
responseMap, ok := rawResponse.(map[string]interface{})
|
||||
if ok {
|
||||
if hits, exists := responseMap["hits"]; exists {
|
||||
hitsArray, ok := hits.([]interface{})
|
||||
if ok {
|
||||
fmt.Printf("Response contains %d hits\n", len(hitsArray))
|
||||
if len(hitsArray) > 0 {
|
||||
// Look at the structure of the first hit
|
||||
firstHit, ok := hitsArray[0].(map[string]interface{})
|
||||
if ok {
|
||||
fmt.Printf("First hit keys: %v\n", getMapKeys(firstHit))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return parseSearchResponse(body)
|
||||
}
|
||||
|
||||
// SearchQuery represents a parsed search query with raw terms and field filters
|
||||
type SearchQuery struct {
|
||||
RawTerms []string
|
||||
|
|
@ -154,7 +231,7 @@ func ParseSearchQuery(searchStr string) SearchQuery {
|
|||
// This is a field:value pair with dot notation
|
||||
fieldName := match[2]
|
||||
fieldValue := match[3]
|
||||
|
||||
|
||||
// Add to the array of values for this field
|
||||
query.FieldFilters[fieldName] = append(query.FieldFilters[fieldName], fieldValue)
|
||||
} else if match[4] != "" {
|
||||
|
|
@ -164,7 +241,7 @@ func ParseSearchQuery(searchStr string) SearchQuery {
|
|||
// Simple field:value without dot notation
|
||||
fieldName := parts[0]
|
||||
fieldValue := parts[1]
|
||||
|
||||
|
||||
// Add to the array of values for this field
|
||||
query.FieldFilters[fieldName] = append(query.FieldFilters[fieldName], fieldValue)
|
||||
} else {
|
||||
|
|
@ -198,7 +275,7 @@ func BuildTypesenseQuery(query SearchQuery) (string, map[string]string, error) {
|
|||
for _, value := range values {
|
||||
// Create the filter expression
|
||||
filterExpr := fmt.Sprintf("%s:%s", field, value)
|
||||
|
||||
|
||||
// Add to the corresponding field group
|
||||
fieldGroups[baseName] = append(fieldGroups[baseName], filterExpr)
|
||||
}
|
||||
|
|
@ -234,44 +311,44 @@ func parseSearchResponse(responseBody []byte) ([]nostr.Event, error) {
|
|||
|
||||
// Debug: Print the raw response structure
|
||||
fmt.Printf("Search response found %d hits\n", searchResponse.Found)
|
||||
|
||||
|
||||
nostrResults := make([]nostr.Event, 0, len(searchResponse.Hits))
|
||||
|
||||
for i, hit := range searchResponse.Hits {
|
||||
// Debug: Print hit structure information
|
||||
fmt.Printf("Processing hit %d, keys: %v\n", i, getMapKeys(hit))
|
||||
|
||||
|
||||
// Check if document exists in the hit
|
||||
docRaw, exists := hit["document"]
|
||||
if !exists {
|
||||
fmt.Printf("Warning: hit %d has no 'document' field\n", i)
|
||||
continue // Skip this hit
|
||||
}
|
||||
|
||||
|
||||
// Extract document directly as a map[string]interface{}
|
||||
docMap, ok := docRaw.(map[string]interface{})
|
||||
if !ok {
|
||||
fmt.Printf("Warning: hit %d document is not a map, type: %T\n", i, docRaw)
|
||||
continue // Skip this hit
|
||||
}
|
||||
|
||||
|
||||
// Debug: Print document keys
|
||||
fmt.Printf("Document keys: %v\n", getMapKeys(docMap))
|
||||
|
||||
|
||||
// Check for EventRaw field directly
|
||||
eventRawVal, hasEventRaw := docMap["eventRaw"]
|
||||
if !hasEventRaw {
|
||||
fmt.Printf("Warning: document has no 'eventRaw' field\n")
|
||||
continue // Skip this document
|
||||
}
|
||||
|
||||
|
||||
// Try to extract EventRaw as string
|
||||
eventRawStr, ok := eventRawVal.(string)
|
||||
if !ok {
|
||||
fmt.Printf("Warning: eventRaw is not a string, type: %T\n", eventRawVal)
|
||||
continue // Skip this document
|
||||
}
|
||||
|
||||
|
||||
// Convert the EventRaw string to a Nostr event
|
||||
nostrEvent, err := StringifiedJSONToNostrEvent(eventRawStr)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -1,2 +1,106 @@
|
|||
package typesense30142
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/nbd-wtf/go-nostr"
|
||||
)
|
||||
|
||||
func TestQueryEventsWithLimit(t *testing.T) {
|
||||
// Test that limit is properly handled
|
||||
tests := []struct {
|
||||
name string
|
||||
filter nostr.Filter
|
||||
expectedLimit int
|
||||
}{
|
||||
{
|
||||
name: "No limit specified - should default to 100",
|
||||
filter: nostr.Filter{
|
||||
Search: "",
|
||||
},
|
||||
expectedLimit: 100,
|
||||
},
|
||||
{
|
||||
name: "Limit of 2 specified",
|
||||
filter: nostr.Filter{
|
||||
Search: "",
|
||||
Limit: 2,
|
||||
},
|
||||
expectedLimit: 2,
|
||||
},
|
||||
{
|
||||
name: "Limit of 50 specified",
|
||||
filter: nostr.Filter{
|
||||
Search: "test",
|
||||
Limit: 50,
|
||||
},
|
||||
expectedLimit: 50,
|
||||
},
|
||||
{
|
||||
name: "Zero limit - should default to 100",
|
||||
filter: nostr.Filter{
|
||||
Search: "test",
|
||||
Limit: 0,
|
||||
},
|
||||
expectedLimit: 100,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// Test the limit logic
|
||||
limit := 100
|
||||
if tt.filter.Limit > 0 {
|
||||
limit = tt.filter.Limit
|
||||
}
|
||||
|
||||
if limit != tt.expectedLimit {
|
||||
t.Errorf("Expected limit %d, got %d", tt.expectedLimit, limit)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildTypesenseQueryWithEmptySearch(t *testing.T) {
|
||||
// Test that empty search strings are handled correctly
|
||||
query := ParseSearchQuery("")
|
||||
mainQuery, params, err := BuildTypesenseQuery(query)
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("BuildTypesenseQuery failed: %v", err)
|
||||
}
|
||||
|
||||
// Empty search should result in empty main query
|
||||
if mainQuery != "" {
|
||||
t.Errorf("Expected empty main query, got: %s", mainQuery)
|
||||
}
|
||||
|
||||
// Should have no filter parameters for empty search
|
||||
if len(params) != 0 {
|
||||
t.Errorf("Expected no filter params for empty search, got: %v", params)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSearchResourcesWithLimitHandlesEmptySearch(t *testing.T) {
|
||||
// Test that SearchResourcesWithLimit properly handles empty search by using wildcard
|
||||
query := ParseSearchQuery("")
|
||||
mainQuery, _, err := BuildTypesenseQuery(query)
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("BuildTypesenseQuery failed: %v", err)
|
||||
}
|
||||
|
||||
// Empty search should result in empty main query initially
|
||||
if mainQuery != "" {
|
||||
t.Errorf("Expected empty main query from ParseSearchQuery, got: %s", mainQuery)
|
||||
}
|
||||
|
||||
// SearchResourcesWithLimit should convert empty query to "*"
|
||||
if mainQuery == "" {
|
||||
mainQuery = "*"
|
||||
}
|
||||
|
||||
if mainQuery != "*" {
|
||||
t.Errorf("Expected wildcard query '*', got: %s", mainQuery)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue