mirror of
https://github.com/gosom/google-maps-scraper.git
synced 2026-09-19 07:27:12 +08:00
097904f2b9
* feat: implement pagination in Web UI (Fixes #86) - Added Count method to JobRepository and Offset to SelectParams - Updated sqlite implementation to support offset and count calculations - Added ListJobs function to Service, keeping All intact for API backward compatibility - Updated getJobs to parse ?page query param and return JobRowsData - Updated HTML templates to support HTMX outerHTML replacements with out-of-band updates * fix: resolve pagination bugs and add tests for #86 * fix: remove HTMX load loop, stray files, add trigger regression test (#86) - index.html: initial tbody uses hx-trigger='load' only (fires once) - job_rows.html: returned tbody uses hx-trigger='every 10s' only (no load) This eliminates the outerHTML reload loop where the inserted element immediately fires 'load' again before the 10s timer. - Remove pr_body.md and results.csv (local artifacts, not part of #86) - Add TestGetJobsHTMXTriggerIsPollingOnly to assert the fix is permanent - Service.All remains unchanged for existing callers * fix: address pagination review feedback Co-authored-by: Giorgos Komninos <admin@gkomninos.com> --------- Co-authored-by: Giorgos Komninos <admin@gkomninos.com>
95 lines
2.2 KiB
Go
95 lines
2.2 KiB
Go
//nolint:testpackage // tests the private SQLite repository and schema directly
|
|
package sqlite
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/gosom/google-maps-scraper/web"
|
|
)
|
|
|
|
func newTestRepo(t *testing.T) *repo {
|
|
t.Helper()
|
|
|
|
db, err := initDatabase(":memory:")
|
|
if err != nil {
|
|
t.Fatalf("initDatabase: %v", err)
|
|
}
|
|
|
|
t.Cleanup(func() {
|
|
if err := db.Close(); err != nil {
|
|
t.Errorf("close database: %v", err)
|
|
}
|
|
})
|
|
|
|
return &repo{db: db}
|
|
}
|
|
|
|
func createTestJob(t *testing.T, repo *repo, id string, date time.Time) {
|
|
t.Helper()
|
|
|
|
job := web.Job{ID: id, Name: id, Date: date, Status: web.StatusPending}
|
|
if err := repo.Create(context.Background(), &job); err != nil {
|
|
t.Fatalf("Create(%q): %v", id, err)
|
|
}
|
|
}
|
|
|
|
func TestSelectSupportsOffsetWithoutLimit(t *testing.T) {
|
|
repo := newTestRepo(t)
|
|
|
|
createTestJob(t, repo, "a", time.Unix(1, 0))
|
|
createTestJob(t, repo, "b", time.Unix(2, 0))
|
|
createTestJob(t, repo, "c", time.Unix(3, 0))
|
|
|
|
jobs, err := repo.Select(context.Background(), web.SelectParams{Offset: 1})
|
|
if err != nil {
|
|
t.Fatalf("Select: %v", err)
|
|
}
|
|
|
|
if len(jobs) != 2 || jobs[0].ID != "b" || jobs[1].ID != "a" {
|
|
t.Fatalf("unexpected jobs: %+v", jobs)
|
|
}
|
|
}
|
|
|
|
func TestSelectOrdersSameSecondJobsByID(t *testing.T) {
|
|
repo := newTestRepo(t)
|
|
createdAt := time.Unix(1, 0)
|
|
|
|
createTestJob(t, repo, "b", createdAt)
|
|
createTestJob(t, repo, "c", createdAt)
|
|
createTestJob(t, repo, "a", createdAt)
|
|
|
|
jobs, err := repo.Select(context.Background(), web.SelectParams{})
|
|
if err != nil {
|
|
t.Fatalf("Select: %v", err)
|
|
}
|
|
|
|
want := []string{"c", "b", "a"}
|
|
for i := range want {
|
|
if jobs[i].ID != want[i] {
|
|
t.Fatalf("job %d: got %q, want %q", i, jobs[i].ID, want[i])
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestSchemaIndexesJobPaginationOrder(t *testing.T) {
|
|
repo := newTestRepo(t)
|
|
|
|
var statement string
|
|
|
|
err := repo.db.QueryRowContext(
|
|
context.Background(),
|
|
`SELECT sql FROM sqlite_master WHERE type = 'index' AND name = 'idx_jobs_created_at_id'`,
|
|
).Scan(&statement)
|
|
if err != nil {
|
|
t.Fatalf("query pagination index: %v", err)
|
|
}
|
|
|
|
want := strings.Fields("CREATE INDEX idx_jobs_created_at_id ON jobs (created_at DESC, id DESC)")
|
|
if strings.Join(strings.Fields(statement), " ") != strings.Join(want, " ") {
|
|
t.Fatalf("unexpected index: %q", statement)
|
|
}
|
|
}
|