internal/postgres: update definition of latest

The definition of latest is updated to prefer incompatible
release/prerelease versions over pseudoversion. This matches the
definition by cmd/go.

Change-Id: Ic3c79c32e14dc4df3cf11d52df6548f0fd781a6b
Reviewed-on: https://go-review.googlesource.com/c/pkgsite/+/259997
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/internal/postgres/insert_module_test.go b/internal/postgres/insert_module_test.go
index 6a1dd4a..e1652f7 100644
--- a/internal/postgres/insert_module_test.go
+++ b/internal/postgres/insert_module_test.go
@@ -394,6 +394,51 @@
 	}
 }
 
+func TestLatestVersion_PreferIncompatibleOverPrerelease(t *testing.T) {
+	defer ResetTestDB(testDB, t)
+	ctx := context.Background()
+
+	for _, mod := range []struct {
+		version    string
+		modulePath string
+	}{
+		{
+			version:    "v0.0.0-20201007032633-0806396f153e",
+			modulePath: sample.ModulePath,
+		},
+		{
+			version:    "v2.0.0+incompatible",
+			modulePath: sample.ModulePath,
+		},
+	} {
+		m := sample.LegacyDefaultModule()
+		m.Version = mod.version
+		m.ModulePath = mod.modulePath
+
+		if err := testDB.InsertModule(ctx, m); err != nil {
+			t.Fatal(err)
+		}
+	}
+
+	for _, tc := range []struct {
+		modulePath string
+		want       string
+	}{
+		{
+			modulePath: sample.ModulePath,
+			want:       "v2.0.0+incompatible",
+		},
+	} {
+		isLatest, err := isLatestVersion(ctx, testDB.db, tc.modulePath, tc.want)
+		if err != nil {
+			t.Fatal(err)
+		}
+		if !isLatest {
+			t.Errorf("%s is not the latest version", tc.want)
+		}
+	}
+}
+
 func TestDeleteModule(t *testing.T) {
 	ctx, cancel := context.WithTimeout(context.Background(), testTimeout)
 	defer cancel()
diff --git a/internal/postgres/path.go b/internal/postgres/path.go
index 924c647..a7d892a 100644
--- a/internal/postgres/path.go
+++ b/internal/postgres/path.go
@@ -16,14 +16,23 @@
 	"golang.org/x/pkgsite/internal/stdlib"
 )
 
+// orderByLatest orders paths according to the go command.
+// Versions are ordered by:
+// (1) release (non-incompatible)
+// (2) prerelease (non-incompatible)
+// (3) release, incompatible
+// (4) prerelease, incompatible
+// (5) pseudo
+// They are then sorted based on semver, then decreasing module path length (so
+// that nested modules are prefered).
 const orderByLatest = `
 			ORDER BY
-				m.incompatible,
 				CASE
-				    -- Order the versions by release then prerelease then pseudo.
-				    WHEN m.version_type = 'release' THEN 1
-				    WHEN m.version_type = 'prerelease' THEN 2
-				    ELSE 3
+					WHEN m.version_type = 'release' AND NOT m.incompatible THEN 1
+					WHEN m.version_type = 'prerelease' AND NOT m.incompatible THEN 2
+					WHEN m.version_type = 'release' THEN 3
+					WHEN m.version_type = 'prerelease' THEN 4
+					ELSE 5
 				END,
 				m.sort_version DESC,
 				m.module_path DESC`
@@ -66,14 +75,14 @@
 	)
 	query := fmt.Sprintf(`
 		SELECT
-		    m.module_path,
-		    m.version,
-		    m.commit_time,
-		    m.source_info,
-		    p.name,
-		    p.redistributable,
-		    p.license_types,
-		    p.license_paths
+			m.module_path,
+			m.version,
+			m.commit_time,
+			m.source_info,
+			p.name,
+			p.redistributable,
+			p.license_types,
+			p.license_paths
 		FROM paths p
 		INNER JOIN modules m ON (p.module_id = m.id)
 		%s