Files
gooseek/backend/internal/db/article_summary_repo.go
home 06fe57c765 feat: Go backend, enhanced search, new widgets, Docker deploy
Major changes:
- Add Go backend (backend/) with microservices architecture
- Enhanced master-agents-svc: reranker, content-classifier, stealth-crawler,
  proxy-manager, media-search, fastClassifier, language detection
- New web-svc widgets: KnowledgeCard, ProductCard, ProfileCard, VideoCard,
  UnifiedCard, CardGallery, InlineImageGallery, SourcesPanel, RelatedQuestions
- Improved discover-svc with discover-db integration
- Docker deployment improvements (Caddyfile, vendor.sh, BUILD.md)
- Library-svc: project_id schema migration
- Remove deprecated finance-svc and travel-svc
- Localization improvements across services

Made-with: Cursor
2026-02-27 04:15:32 +03:00

98 lines
2.5 KiB
Go

package db
import (
"context"
"crypto/sha256"
"database/sql"
"encoding/hex"
"encoding/json"
"strings"
"time"
)
type ArticleSummary struct {
ID int64 `json:"id"`
URLHash string `json:"urlHash"`
URL string `json:"url"`
Events []string `json:"events"`
CreatedAt time.Time `json:"createdAt"`
ExpiresAt time.Time `json:"expiresAt"`
}
type ArticleSummaryRepository struct {
db *PostgresDB
}
func NewArticleSummaryRepository(db *PostgresDB) *ArticleSummaryRepository {
return &ArticleSummaryRepository{db: db}
}
func (r *ArticleSummaryRepository) hashURL(url string) string {
normalized := strings.TrimSpace(url)
normalized = strings.TrimSuffix(normalized, "/")
normalized = strings.TrimPrefix(normalized, "https://")
normalized = strings.TrimPrefix(normalized, "http://")
normalized = strings.TrimPrefix(normalized, "www.")
hash := sha256.Sum256([]byte(normalized))
return hex.EncodeToString(hash[:])
}
func (r *ArticleSummaryRepository) GetByURL(ctx context.Context, url string) (*ArticleSummary, error) {
urlHash := r.hashURL(url)
query := `
SELECT id, url_hash, url, events, created_at, expires_at
FROM article_summaries
WHERE url_hash = $1 AND expires_at > NOW()
`
var a ArticleSummary
var eventsJSON []byte
err := r.db.db.QueryRowContext(ctx, query, urlHash).Scan(
&a.ID, &a.URLHash, &a.URL, &eventsJSON, &a.CreatedAt, &a.ExpiresAt,
)
if err == sql.ErrNoRows {
return nil, nil
}
if err != nil {
return nil, err
}
json.Unmarshal(eventsJSON, &a.Events)
return &a, nil
}
func (r *ArticleSummaryRepository) Save(ctx context.Context, url string, events []string, ttl time.Duration) error {
urlHash := r.hashURL(url)
eventsJSON, _ := json.Marshal(events)
expiresAt := time.Now().Add(ttl)
query := `
INSERT INTO article_summaries (url_hash, url, events, expires_at)
VALUES ($1, $2, $3, $4)
ON CONFLICT (url_hash)
DO UPDATE SET
events = EXCLUDED.events,
expires_at = EXCLUDED.expires_at
`
_, err := r.db.db.ExecContext(ctx, query, urlHash, url, eventsJSON, expiresAt)
return err
}
func (r *ArticleSummaryRepository) Delete(ctx context.Context, url string) error {
urlHash := r.hashURL(url)
_, err := r.db.db.ExecContext(ctx, "DELETE FROM article_summaries WHERE url_hash = $1", urlHash)
return err
}
func (r *ArticleSummaryRepository) CleanupExpired(ctx context.Context) (int64, error) {
result, err := r.db.db.ExecContext(ctx, "DELETE FROM article_summaries WHERE expires_at < NOW()")
if err != nil {
return 0, err
}
return result.RowsAffected()
}