internal/postgres: get and update raw_latest_versions

Add functions to get a row from the raw_latest_versions table,
and to update a row if the new version is later.

For golang/go#44437

Change-Id: I9f44b815b4eb42c6cd286f10f2e946e753c38989
Reviewed-on: https://go-review.googlesource.com/c/pkgsite/+/295450
Trust: Jonathan Amsterdam <jba@google.com>
Run-TryBot: Jonathan Amsterdam <jba@google.com>
TryBot-Result: kokoro <noreply+kokoro@google.com>
Reviewed-by: Julie Qiu <julie@golang.org>
diff --git a/internal/postgres/version_test.go b/internal/postgres/version_test.go
index 1d37063..09b8611 100644
--- a/internal/postgres/version_test.go
+++ b/internal/postgres/version_test.go
@@ -10,6 +10,7 @@
 	"testing"
 
 	"github.com/google/go-cmp/cmp"
+	"golang.org/x/mod/modfile"
 	"golang.org/x/pkgsite/internal"
 	"golang.org/x/pkgsite/internal/source"
 	"golang.org/x/pkgsite/internal/stdlib"
@@ -347,3 +348,58 @@
 		})
 	}
 }
+
+func TestRawLatestInfo(t *testing.T) {
+	t.Parallel()
+	testDB, release := acquire(t)
+	defer release()
+	ctx := context.Background()
+
+	goMod, err := modfile.ParseLax("m from DB", []byte(`module m`), nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	info := &internal.RawLatestInfo{ModulePath: "m", Version: "v1.0.0", GoModFile: goMod}
+	if err := testDB.UpdateRawLatestInfo(ctx, info); err != nil {
+		t.Fatal(err)
+	}
+	got, err := testDB.GetRawLatestInfo(ctx, "m")
+	if err != nil {
+		t.Fatal(err)
+	}
+	if diff := cmp.Diff(info, got); diff != "" {
+		t.Fatalf("mismatch (-want, +got): %s", diff)
+	}
+
+	info.Version = "v1.2.3"
+	if err := testDB.UpdateRawLatestInfo(ctx, info); err != nil {
+		t.Fatal(err)
+	}
+	got, err = testDB.GetRawLatestInfo(ctx, "m")
+	if err != nil {
+		t.Fatal(err)
+	}
+	if diff := cmp.Diff(info, got); diff != "" {
+		t.Fatalf("mismatch (-want, +got): %s", diff)
+	}
+
+}
+
+func TestShouldUpdateRawLatest(t *testing.T) {
+	for _, test := range []struct {
+		new, cur string
+		want     bool
+	}{
+		{"v1.2.0", "v1.0.0", true},
+		{"v1.2.0", "v1.2.0", false},
+		{"v1.2.0", "v1.3.0", false},
+		{"v1.0.0", "v1.9.9-pre", true},          // release beats prerelease
+		{"v1.0.0", "v2.3.4+incompatible", true}, // compatible beats incompatible
+	} {
+		got := shouldUpdateRawLatest(test.new, test.cur)
+		if got != test.want {
+			t.Errorf("shouldUpdateRawLatest(%q, %q) = %t, want %t", test.new, test.cur, got, test.want)
+		}
+	}
+}