content,internal/frontend: update count on importedby page
When loading the imported by page, fetch the imported by count from
search_documents.num_imported_by, instead of limiting at 20,000.
This will use the same logic for the imported by count with the
main page and search page.
For golang/go#39138
Change-Id: Iae188d01129b6e35cfd82b79e51a0ef12938c459
Reviewed-on: https://go-review.googlesource.com/c/pkgsite/+/288849
Trust: Julie Qiu <julie@golang.org>
Run-TryBot: Julie Qiu <julie@golang.org>
TryBot-Result: kokoro <noreply+kokoro@google.com>
Reviewed-by: Jonathan Amsterdam <jba@google.com>
diff --git a/content/static/html/helpers/_importedby.tmpl b/content/static/html/helpers/_importedby.tmpl
index 8cff4f2..80022cb 100644
--- a/content/static/html/helpers/_importedby.tmpl
+++ b/content/static/html/helpers/_importedby.tmpl
@@ -7,9 +7,7 @@
{{define "importedby"}}
<div class="ImportedBy">
{{if .ImportedBy}}
- <p>
- <b>Known {{pluralize .Total "importer"}}:</b> {{.Total}}{{if not .TotalIsExact}}+{{end}}
- </p>
+ <b>Known {{pluralize .Total "importer"}}:</b> {{.NumImportedByDisplay}}
{{template "sections" .ImportedBy}}
{{else}}
{{template "empty_content" "No known importers for this package!"}}
diff --git a/internal/frontend/imports.go b/internal/frontend/imports.go
index eef9709..286c0eb 100644
--- a/internal/frontend/imports.go
+++ b/internal/frontend/imports.go
@@ -6,6 +6,7 @@
import (
"context"
+ "fmt"
"strings"
"golang.org/x/pkgsite/internal"
@@ -64,6 +65,7 @@
// ImportedByDetails contains information for the collection of packages that
// import a given package.
type ImportedByDetails struct {
+ // ModulePath is the module path for the package referenced on this page.
ModulePath string
// ImportedBy is the collection of packages that import the
@@ -71,8 +73,12 @@
// They are organized into a tree of sections by prefix.
ImportedBy []*Section
- Total int // number of packages in ImportedBy
- TotalIsExact bool // if false, then there may be more than Total
+ // NumImportedByDisplay is the display text at the top of the imported by
+ // tab section, which shows the imported by count and package limit.
+ NumImportedByDisplay string
+
+ // Total is the total number of importers.
+ Total int
}
var (
@@ -97,22 +103,20 @@
if err != nil {
return nil, err
}
- importedByCount := len(importedBy)
-
- // If we reached the query limit, then we don't know the total.
- // Say so, and show one less than the limit.
- // For example, if the limit is 101 and we get 101 results, then we'll
- // say there are more than 100, and show the first 100.
- totalIsExact := true
- if importedByCount == tabImportedByLimit {
- importedBy = importedBy[:len(importedBy)-1]
- totalIsExact = false
+ numImportedBy, err := db.GetImportedByCount(ctx, pkgPath, modulePath)
+ if err != nil {
+ return nil, err
}
sections := Sections(importedBy, nextPrefixAccount)
+
+ display := formatImportedByCount(numImportedBy)
+ if numImportedBy >= tabImportedByLimit {
+ display += fmt.Sprintf(" (displaying %d packages)", tabImportedByLimit-1)
+ }
return &ImportedByDetails{
- ModulePath: modulePath,
- ImportedBy: sections,
- Total: importedByCount,
- TotalIsExact: totalIsExact,
+ ModulePath: modulePath,
+ ImportedBy: sections,
+ NumImportedByDisplay: display,
+ Total: numImportedBy,
}, nil
}
diff --git a/internal/frontend/imports_test.go b/internal/frontend/imports_test.go
index e93cc6d..dccf731 100644
--- a/internal/frontend/imports_test.go
+++ b/internal/frontend/imports_test.go
@@ -6,7 +6,9 @@
import (
"context"
+ "fmt"
"path"
+ "strconv"
"testing"
"github.com/google/go-cmp/cmp"
@@ -110,15 +112,16 @@
wantDetails *ImportedByDetails
}{
{
- pkg: pkg3,
- wantDetails: &ImportedByDetails{TotalIsExact: true},
+ pkg: pkg3,
+ wantDetails: &ImportedByDetails{
+ NumImportedByDisplay: "0",
+ },
},
{
pkg: pkg2,
wantDetails: &ImportedByDetails{
- ImportedBy: []*Section{{Prefix: pkg3.Path, NumLines: 0}},
- Total: 1,
- TotalIsExact: true,
+ ImportedBy: []*Section{{Prefix: pkg3.Path, NumLines: 0}},
+ NumImportedByDisplay: "0",
},
},
{
@@ -128,29 +131,58 @@
{Prefix: pkg2.Path, NumLines: 0},
{Prefix: pkg3.Path, NumLines: 0},
},
- Total: 2,
- TotalIsExact: true,
+ NumImportedByDisplay: "0",
},
},
}
- checkFetchImportedByDetails := func(ctx context.Context, pkg *internal.Unit, wantDetails *ImportedByDetails) {
- got, err := fetchImportedByDetails(ctx, testDB, pkg.Path, pkg.ModulePath)
- if err != nil {
- t.Fatalf("fetchImportedByDetails(ctx, db, %q) = %v err = %v, want %v",
- pkg.Path, got, err, wantDetails)
- }
- wantDetails.ModulePath = pkg.ModulePath
- if diff := cmp.Diff(wantDetails, got); diff != "" {
- t.Errorf("fetchImportedByDetails(ctx, db, %q) mismatch (-want +got):\n%s", pkg.Path, diff)
- }
- }
for _, test := range tests {
t.Run(test.pkg.Path, func(t *testing.T) {
otherVersion := newModule(path.Dir(test.pkg.Path), test.pkg)
otherVersion.Version = "v1.0.5"
pkg := otherVersion.Units[1]
- checkFetchImportedByDetails(ctx, pkg, test.wantDetails)
+ checkFetchImportedByDetails(ctx, t, pkg, test.wantDetails)
})
}
}
+
+func TestFetchImportedByDetails_ExceedsTabLimit(t *testing.T) {
+ defer postgres.ResetTestDB(testDB, t)
+ ctx, cancel := context.WithTimeout(context.Background(), testTimeout)
+ defer cancel()
+
+ for _, count := range []int{tabImportedByLimit, 30000} {
+ t.Run(strconv.Itoa(count), func(t *testing.T) {
+ args := postgres.UpsertSearchDocumentArgs{
+ PackagePath: sample.PackagePath,
+ ModulePath: sample.ModulePath,
+ }
+ if err := testDB.InsertModule(ctx, sample.Module(sample.ModulePath, sample.VersionString, sample.PackageName)); err != nil {
+ t.Fatal(err)
+ }
+ if err := testDB.UpsertSearchDocumentWithImportedByCount(ctx, args, count); err != nil {
+ t.Fatal(err)
+ }
+
+ pkg := sample.UnitForPackage(sample.PackagePath, sample.ModulePath, sample.VersionString, sample.PackageName, true)
+ wantDetails := &ImportedByDetails{
+ ModulePath: sample.ModulePath,
+ NumImportedByDisplay: fmt.Sprintf("%s (displaying 20000 packages)", formatImportedByCount(count)),
+ Total: count,
+ }
+ checkFetchImportedByDetails(ctx, t, pkg, wantDetails)
+ })
+ }
+}
+
+func checkFetchImportedByDetails(ctx context.Context, t *testing.T, pkg *internal.Unit, wantDetails *ImportedByDetails) {
+ got, err := fetchImportedByDetails(ctx, testDB, pkg.Path, pkg.ModulePath)
+ if err != nil {
+ t.Fatalf("fetchImportedByDetails(ctx, db, %q) = %v err = %v, want %v",
+ pkg.Path, got, err, wantDetails)
+ }
+ wantDetails.ModulePath = pkg.ModulePath
+ if diff := cmp.Diff(wantDetails, got); diff != "" {
+ t.Errorf("fetchImportedByDetails(ctx, db, %q) mismatch (-want +got):\n%s", pkg.Path, diff)
+ }
+}
diff --git a/internal/postgres/insert_module.go b/internal/postgres/insert_module.go
index a241fc1..fad2ae4 100644
--- a/internal/postgres/insert_module.go
+++ b/internal/postgres/insert_module.go
@@ -148,7 +148,7 @@
return err
}
// Insert the module's packages into search_documents.
- return db.upsertSearchDocuments(ctx, tx, m)
+ return upsertSearchDocuments(ctx, tx, m)
})
}
diff --git a/internal/postgres/search.go b/internal/postgres/search.go
index decba91..bfd2b76 100644
--- a/internal/postgres/search.go
+++ b/internal/postgres/search.go
@@ -452,7 +452,7 @@
// upsertSearchDocuments adds search information for mod ot the search_documents table.
// It assumes that all non-redistributable data has been removed from mod.
-func (db *DB) upsertSearchDocuments(ctx context.Context, ddb *database.DB, mod *internal.Module) (err error) {
+func upsertSearchDocuments(ctx context.Context, ddb *database.DB, mod *internal.Module) (err error) {
defer derrors.Wrap(&err, "upsertSearchDocuments(ctx, %q)", mod.ModulePath)
ctx, span := trace.StartSpan(ctx, "UpsertSearchDocuments")
defer span.End()
@@ -460,7 +460,7 @@
if isInternalPackage(pkg.Path) {
continue
}
- args := upsertSearchDocumentArgs{
+ args := UpsertSearchDocumentArgs{
PackagePath: pkg.Path,
ModulePath: mod.ModulePath,
}
@@ -472,14 +472,14 @@
args.ReadmeFilePath = pkg.Readme.Filepath
args.ReadmeContents = pkg.Readme.Contents
}
- if err := db.UpsertSearchDocument(ctx, ddb, args); err != nil {
+ if err := UpsertSearchDocument(ctx, ddb, args); err != nil {
return err
}
}
return nil
}
-type upsertSearchDocumentArgs struct {
+type UpsertSearchDocumentArgs struct {
PackagePath string
ModulePath string
Synopsis string
@@ -492,7 +492,7 @@
//
// The given module should have already been validated via a call to
// validateModule.
-func (db *DB) UpsertSearchDocument(ctx context.Context, ddb *database.DB, args upsertSearchDocumentArgs) (err error) {
+func UpsertSearchDocument(ctx context.Context, ddb *database.DB, args UpsertSearchDocumentArgs) (err error) {
defer derrors.Wrap(&err, "DB.UpsertSearchDocument(ctx, ddb, %q, %q)", args.PackagePath, args.ModulePath)
// Only summarize the README if the package and module have the same path.
@@ -508,7 +508,7 @@
// GetPackagesForSearchDocumentUpsert fetches search information for packages in search_documents
// whose update time is before the given time.
-func (db *DB) GetPackagesForSearchDocumentUpsert(ctx context.Context, before time.Time, limit int) (argsList []upsertSearchDocumentArgs, err error) {
+func (db *DB) GetPackagesForSearchDocumentUpsert(ctx context.Context, before time.Time, limit int) (argsList []UpsertSearchDocumentArgs, err error) {
defer derrors.Wrap(&err, "GetPackagesForSearchDocumentUpsert(ctx, %s, %d)", before, limit)
query := `
@@ -535,7 +535,7 @@
collect := func(rows *sql.Rows) error {
var (
- a upsertSearchDocumentArgs
+ a UpsertSearchDocumentArgs
redist bool
)
if err := rows.Scan(&a.PackagePath, &a.ModulePath, &a.Synopsis, &redist,
@@ -875,3 +875,17 @@
return nil
})
}
+
+// UpsertSearchDocumentWithImportedByCount is the same as UpsertSearchDocument,
+// except it also updates the imported by count. This is only used for testing.
+func (db *DB) UpsertSearchDocumentWithImportedByCount(ctx context.Context, args UpsertSearchDocumentArgs, importedByCount int) (err error) {
+ defer derrors.Wrap(&err, "DB.UpsertSearchDocumentWithImportedByCount(ctx, ddb, %q, %q)", args.PackagePath, args.ModulePath)
+
+ if err := UpsertSearchDocument(ctx, db.db, args); err != nil {
+ return err
+ }
+ _, err = db.db.Exec(ctx,
+ `UPDATE search_documents SET imported_by_count=$1 WHERE package_path=$2;`,
+ importedByCount, args.PackagePath)
+ return err
+}
diff --git a/internal/postgres/search_test.go b/internal/postgres/search_test.go
index db41c98..2ba034b 100644
--- a/internal/postgres/search_test.go
+++ b/internal/postgres/search_test.go
@@ -989,7 +989,7 @@
t.Fatal(err)
}
sort.Slice(got, func(i, j int) bool { return got[i].PackagePath < got[j].PackagePath })
- want := []upsertSearchDocumentArgs{
+ want := []UpsertSearchDocumentArgs{
{
PackagePath: moduleN.ModulePath,
ModulePath: moduleN.ModulePath,
diff --git a/internal/worker/server.go b/internal/worker/server.go
index 229591d..dfe0847 100644
--- a/internal/worker/server.go
+++ b/internal/worker/server.go
@@ -244,7 +244,7 @@
}
for _, args := range sdargs {
- if err := s.db.UpsertSearchDocument(ctx, s.db.Underlying(), args); err != nil {
+ if err := postgres.UpsertSearchDocument(ctx, s.db.Underlying(), args); err != nil {
return err
}
}