Switch to squirrel
This commit is contained in:
+32
-57
@@ -3,18 +3,14 @@ package sqlite
|
||||
import (
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"iter"
|
||||
"strings"
|
||||
|
||||
"fiatjaf.com/nostr"
|
||||
"github.com/Masterminds/squirrel"
|
||||
)
|
||||
|
||||
func (s *SqliteBackend) QueryEvents(filter nostr.Filter, maxLimit int) iter.Seq[nostr.Event] {
|
||||
return func(yield func(nostr.Event) bool) {
|
||||
s.RLock()
|
||||
defer s.RUnlock()
|
||||
|
||||
if filter.LimitZero {
|
||||
return
|
||||
}
|
||||
@@ -24,9 +20,7 @@ func (s *SqliteBackend) QueryEvents(filter nostr.Filter, maxLimit int) iter.Seq[
|
||||
limit = filter.Limit
|
||||
}
|
||||
|
||||
query, args := s.buildSelectQuery(filter, limit)
|
||||
|
||||
rows, err := s.db.Query(query, args...)
|
||||
rows, err := s.buildSelectQuery(filter, limit).RunWith(s.db).Query()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@@ -80,92 +74,73 @@ func (s *SqliteBackend) QueryEvents(filter nostr.Filter, maxLimit int) iter.Seq[
|
||||
}
|
||||
}
|
||||
|
||||
func (s *SqliteBackend) buildSelectQuery(filter nostr.Filter, limit int) (string, []interface{}) {
|
||||
var conditions []string
|
||||
var args []interface{}
|
||||
var joins []string
|
||||
|
||||
baseQuery := "SELECT id, created_at, kind, pubkey, content, tags, sig FROM events"
|
||||
func (s *SqliteBackend) buildSelectQuery(filter nostr.Filter, limit int) squirrel.SelectBuilder {
|
||||
qb := squirrel.Select("id", "created_at", "kind", "pubkey", "content", "tags", "sig").
|
||||
From("events").
|
||||
OrderBy("created_at DESC")
|
||||
|
||||
// Handle search with FTS (if available)
|
||||
if filter.Search != "" && s.FTSAvailable {
|
||||
joins = append(joins, "JOIN events_fts ON events.rowid = events_fts.rowid")
|
||||
conditions = append(conditions, "events_fts MATCH ?")
|
||||
args = append(args, filter.Search)
|
||||
qb = qb.Join("events_fts ON events.rowid = events_fts.rowid").
|
||||
Where(squirrel.Eq{"events_fts": filter.Search})
|
||||
} else if filter.Search != "" {
|
||||
// Fallback to LIKE search if FTS not available
|
||||
conditions = append(conditions, "content LIKE ?")
|
||||
args = append(args, "%"+filter.Search+"%")
|
||||
qb = qb.Where(squirrel.Like{"content": "%" + filter.Search + "%"})
|
||||
}
|
||||
|
||||
// Add WHERE clause conditions
|
||||
if len(filter.IDs) > 0 {
|
||||
placeholders := make([]string, len(filter.IDs))
|
||||
idStrs := make([]interface{}, len(filter.IDs))
|
||||
for i, id := range filter.IDs {
|
||||
placeholders[i] = "?"
|
||||
args = append(args, id.Hex())
|
||||
idStrs[i] = id.Hex()
|
||||
}
|
||||
conditions = append(conditions, fmt.Sprintf("id IN (%s)", strings.Join(placeholders, ",")))
|
||||
qb = qb.Where(squirrel.Eq{"id": idStrs})
|
||||
}
|
||||
|
||||
if len(filter.Authors) > 0 {
|
||||
placeholders := make([]string, len(filter.Authors))
|
||||
authorStrs := make([]interface{}, len(filter.Authors))
|
||||
for i, author := range filter.Authors {
|
||||
placeholders[i] = "?"
|
||||
args = append(args, author.Hex())
|
||||
authorStrs[i] = author.Hex()
|
||||
}
|
||||
conditions = append(conditions, fmt.Sprintf("pubkey IN (%s)", strings.Join(placeholders, ",")))
|
||||
qb = qb.Where(squirrel.Eq{"pubkey": authorStrs})
|
||||
}
|
||||
|
||||
if len(filter.Kinds) > 0 {
|
||||
placeholders := make([]string, len(filter.Kinds))
|
||||
kindInts := make([]interface{}, len(filter.Kinds))
|
||||
for i, kind := range filter.Kinds {
|
||||
placeholders[i] = "?"
|
||||
args = append(args, int(kind))
|
||||
kindInts[i] = int(kind)
|
||||
}
|
||||
conditions = append(conditions, fmt.Sprintf("kind IN (%s)", strings.Join(placeholders, ",")))
|
||||
qb = qb.Where(squirrel.Eq{"kind": kindInts})
|
||||
}
|
||||
|
||||
if filter.Since != 0 {
|
||||
conditions = append(conditions, "created_at >= ?")
|
||||
args = append(args, filter.Since)
|
||||
qb = qb.Where(squirrel.GtOrEq{"created_at": filter.Since})
|
||||
}
|
||||
|
||||
if filter.Until != 0 {
|
||||
conditions = append(conditions, "created_at <= ?")
|
||||
args = append(args, filter.Until)
|
||||
qb = qb.Where(squirrel.LtOrEq{"created_at": filter.Until})
|
||||
}
|
||||
|
||||
// Handle tags - only filter single-letter tags using event_tags table
|
||||
for tagKey, tagValues := range filter.Tags {
|
||||
if len(tagValues) > 0 && len(tagKey) == 1 {
|
||||
placeholders := make([]string, len(tagValues))
|
||||
tagValueInterfaces := make([]interface{}, len(tagValues))
|
||||
for i, tagValue := range tagValues {
|
||||
placeholders[i] = "?"
|
||||
args = append(args, tagValue)
|
||||
tagValueInterfaces[i] = tagValue
|
||||
}
|
||||
conditions = append(conditions, fmt.Sprintf("id IN (SELECT event_id FROM event_tags WHERE key = ? AND value IN (%s))", strings.Join(placeholders, ",")))
|
||||
args = append(args, tagKey)
|
||||
|
||||
subQuery := squirrel.Select("event_id").
|
||||
From("event_tags").
|
||||
Where(squirrel.Eq{"key": tagKey}).
|
||||
Where(squirrel.Eq{"value": tagValueInterfaces})
|
||||
|
||||
subQuerySql, subQueryArgs, _ := subQuery.ToSql()
|
||||
qb = qb.Where("id IN ("+subQuerySql+")", subQueryArgs...)
|
||||
}
|
||||
}
|
||||
|
||||
// Build the complete query
|
||||
if len(joins) > 0 {
|
||||
baseQuery += " " + strings.Join(joins, " ")
|
||||
}
|
||||
|
||||
if len(conditions) > 0 {
|
||||
baseQuery += " WHERE " + strings.Join(conditions, " AND ")
|
||||
}
|
||||
|
||||
// Order by created_at DESC for most recent first
|
||||
baseQuery += " ORDER BY created_at DESC"
|
||||
|
||||
// Add limit
|
||||
if limit > 0 {
|
||||
baseQuery += " LIMIT ?"
|
||||
args = append(args, limit)
|
||||
qb = qb.Limit(uint64(limit))
|
||||
}
|
||||
|
||||
return baseQuery, args
|
||||
return qb
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user