internal/postgres: new way to get latest major version
Add DB.getLatestMajorVersion2, which uses the new series_path and
deprecated columns of latest_module_versions to get latest major
version information.
The function is not hooked up or tested yet, but it demonstrates how
we'll use the new columns.
For golang/go#43265
Change-Id: I015ef312d157585ca00582f7f1addd604a2dca77
Reviewed-on: https://go-review.googlesource.com/c/pkgsite/+/307475
Trust: Jonathan Amsterdam <jba@google.com>
Run-TryBot: Jonathan Amsterdam <jba@google.com>
Reviewed-by: Julie Qiu <julie@golang.org>
diff --git a/internal/postgres/version.go b/internal/postgres/version.go
index 3e987dc..f055dc8 100644
--- a/internal/postgres/version.go
+++ b/internal/postgres/version.go
@@ -255,6 +255,79 @@
}
}
+//lint:ignore U1000 We're going to replace getLatestMajorVersion with this once the new DB columns are populated.
+func (db *DB) getLatestMajorVersion2(ctx context.Context, fullPath, modulePath string) (modPath, pkgPath string, err error) {
+ defer derrors.WrapStack(&err, "DB.getLatestMajorVersion2(%q)", modulePath)
+
+ // Collect all the non-deprecated module paths for the series that have at
+ // least one good version.
+ seriesPath := internal.SeriesPathForModule(modulePath)
+ q, args, err := squirrel.Select("p.path", "l.good_version").
+ From("latest_module_versions l").
+ Join("paths p ON p.id = l.module_path_id").
+ Where(squirrel.Eq{"l.series_path": seriesPath}).
+ Where("NOT l.deprecated").
+ Where(squirrel.NotEq{"l.good_version": ""}).
+ PlaceholderFormat(squirrel.Dollar).
+ ToSql()
+ if err != nil {
+ return "", "", err
+ }
+
+ type pathver struct {
+ path, version string
+ }
+
+ var pathvers []pathver
+ err = db.db.RunQuery(ctx, q, func(rows *sql.Rows) error {
+ var pv pathver
+ if err := rows.Scan(&pv.path, &pv.version); err != nil {
+ return err
+ }
+ pathvers = append(pathvers, pv)
+ return nil
+ }, args...)
+ if err != nil {
+ return "", "", err
+ }
+
+ // Find the highest tagged version.
+ var max pathver
+ for _, pv := range pathvers {
+ if version.IsPseudo(pv.version) {
+ continue
+ }
+ if max.path == "" || version.Later(pv.version, max.version) {
+ max = pv
+ }
+ }
+
+ // No highest tagged version: return empty strings.
+ if max.path == "" {
+ return "", "", nil
+ }
+
+ // Find the unit path at the max-version module path.
+ v1Path := internal.V1Path(fullPath, modulePath)
+ row := db.db.QueryRow(ctx, `
+ SELECT p.path
+ FROM units u
+ INNER JOIN modules m ON m.id = u.module_id
+ INNER JOIN paths p ON p.id = u.path_id
+ INNER JOIN paths p2 ON p2.id = u.v1path_id
+ WHERE p2.path = $1 AND m.module_path = $2 AND m.version = $3`,
+ v1Path, max.path, max.version)
+ var path string
+ switch err := row.Scan(&path); err {
+ case nil:
+ return max.path, path, nil
+ case sql.ErrNoRows:
+ return max.path, max.path, nil
+ default:
+ return "", "", err
+ }
+}
+
// unitExistsAtLatest reports whether unitPath exists at the latest version of modulePath.
func (db *DB) unitExistsAtLatest(ctx context.Context, unitPath, modulePath string) (unitExists bool, err error) {
defer derrors.WrapStack(&err, "DB.unitExistsAtLatest(ctx, %q, %q)", unitPath, modulePath)