internal/postgres: add GetLatestPackageForPaths

This change adds GetLatestPackageForPaths which returns the latest
package associated with each path in a list of strings. This method
will eventually be used to get the packages queried by search results.

Updates b/124308701
Fixes b/126714352

Change-Id: I2b6e86aec7b5ba82ed0e45db52784d3cde1b8074
Reviewed-on: https://team-review.git.corp.google.com/c/golang/discovery/+/439699
Reviewed-by: Julie Qiu <julieqiu@google.com>
This commit is contained in:
Channing Kimble-Brown 2019-03-21 16:25:14 -04:00 коммит произвёл Julie Qiu
Родитель af51706d15
Коммит c2e51712c3
2 изменённых файлов: 207 добавлений и 0 удалений

Просмотреть файл

@ -393,3 +393,80 @@ func (db *DB) InsertVersion(version *internal.Version) error {
return nil
})
}
// GetLatestPackageForPaths returns a list of packages that have the latest version that
// corresponds to each path specified in the list of paths. The resulting list is
// sorted by package path lexicographically. So if multiple packages have the same
// path then the package whose module path comes first lexicographically will be
// returned.
func (db *DB) GetLatestPackageForPaths(paths []string) ([]*internal.Package, error) {
var (
packages []*internal.Package
commitTime, createdAt, updatedAt time.Time
path, modulePath, name, synopsis, license, version string
)
query := `
SELECT DISTINCT ON (p.path)
v.created_at,
v.updated_at,
p.path,
p.module_path,
v.version,
v.commit_time,
v.license,
p.name,
p.synopsis
FROM
packages p
INNER JOIN
versions v
ON
v.module_path = p.module_path
AND v.version = p.version
WHERE
p.path = $1
ORDER BY
p.path,
p.module_path,
v.major DESC,
v.minor DESC,
v.patch DESC,
v.prerelease DESC;`
anyPaths := fmt.Sprintf("ANY('%s'::text[])", strings.Join(paths, ", "))
rows, err := db.Query(query, anyPaths)
if err != nil {
return nil, fmt.Errorf("db.Query(%q, %q) returned error: %v", query, anyPaths, err)
}
defer rows.Close()
for rows.Next() {
if err := rows.Scan(&createdAt, &updatedAt, &path, &modulePath, &version, &commitTime, &license, &name, &synopsis); err != nil {
return nil, fmt.Errorf("row.Scan(%q, %q, %q, %q, %q, %q, %q, %q, %q): %v",
createdAt, updatedAt, path, modulePath, version, commitTime, license, name, synopsis, err)
}
packages = append(packages, &internal.Package{
Name: name,
Path: path,
Synopsis: synopsis,
Version: &internal.Version{
CreatedAt: createdAt,
UpdatedAt: updatedAt,
Module: &internal.Module{
Path: modulePath,
},
Version: version,
CommitTime: commitTime,
License: license,
},
})
}
if err := rows.Err(); err != nil {
return nil, fmt.Errorf("rows.Err() returned error %v", err)
}
return packages, nil
}

Просмотреть файл

@ -322,6 +322,136 @@ func TestPostgres_GetLatestPackage(t *testing.T) {
}
}
func TestPostgres_GetLatestPackageForPaths(t *testing.T) {
teardownTestCase, db := SetupCleanDB(t)
defer teardownTestCase(t)
var (
now = time.Now()
pkg1 = &internal.Package{
Path: "path/to/foo/bar",
Name: "bar",
Synopsis: "This is a package synopsis",
}
pkg2 = &internal.Package{
Path: "path2/to/foo/bar2",
Name: "bar2",
Synopsis: "This is another package synopsis",
}
series = &internal.Series{
Path: "myseries",
}
module1 = &internal.Module{
Path: "path2/to/foo",
Series: series,
}
module2 = &internal.Module{
Path: "path2/to/foo",
Series: series,
}
testVersions = []*internal.Version{
&internal.Version{
Module: module1,
Version: "v1.0.0-alpha.1",
License: "licensename",
ReadMe: []byte("readme"),
CommitTime: now,
Packages: []*internal.Package{pkg1},
VersionType: internal.VersionTypePrerelease,
},
&internal.Version{
Module: module1,
Version: "v1.0.0",
License: "licensename",
ReadMe: []byte("readme"),
CommitTime: now,
Packages: []*internal.Package{pkg1},
VersionType: internal.VersionTypeRelease,
},
&internal.Version{
Module: module2,
Version: "v1.0.0-20190311183353-d8887717615a",
License: "licensename",
ReadMe: []byte("readme"),
CommitTime: now,
Packages: []*internal.Package{pkg2},
VersionType: internal.VersionTypePseudo,
},
&internal.Version{
Module: module2,
Version: "v1.0.1-beta",
License: "licensename",
ReadMe: []byte("readme"),
CommitTime: now,
Packages: []*internal.Package{pkg2},
VersionType: internal.VersionTypePseudo,
},
}
)
tc := struct {
paths []string
versions []*internal.Version
wantPkgs []*internal.Package
wantReadErr bool
}{
paths: []string{pkg1.Path, pkg2.Path},
versions: testVersions,
wantPkgs: []*internal.Package{
&internal.Package{
Name: pkg1.Name,
Path: pkg1.Path,
Synopsis: pkg1.Synopsis,
Version: &internal.Version{
CreatedAt: testVersions[1].CreatedAt,
UpdatedAt: testVersions[1].UpdatedAt,
Module: &internal.Module{
Path: module1.Path,
},
Version: testVersions[1].Version,
Synopsis: testVersions[1].Synopsis,
CommitTime: testVersions[1].CommitTime,
License: testVersions[1].License,
},
},
&internal.Package{
Name: pkg2.Name,
Path: pkg2.Path,
Synopsis: pkg2.Synopsis,
Version: &internal.Version{
CreatedAt: testVersions[3].CreatedAt,
UpdatedAt: testVersions[3].UpdatedAt,
Module: &internal.Module{
Path: module1.Path,
},
Version: testVersions[3].Version,
Synopsis: testVersions[3].Synopsis,
CommitTime: testVersions[3].CommitTime,
License: testVersions[3].License,
},
},
},
}
for _, v := range tc.versions {
if err := db.InsertVersion(v); err != nil {
t.Errorf("db.InsertVersion(%v): %v", v, err)
}
}
gotPkgs, err := db.GetLatestPackageForPaths(tc.paths)
if (err != nil) != tc.wantReadErr {
t.Errorf("db.GetLatestPackageForPaths(%q): %v", tc.paths, err)
}
for i, gotPkg := range gotPkgs {
if diff := packagesDiff(gotPkg, tc.wantPkgs[i]); diff != "" {
t.Errorf("got %v at index %v, want %v, diff is %v",
gotPkg, i, tc.wantPkgs[i], diff)
}
}
}
func TestPostgress_InsertVersionLogs(t *testing.T) {
teardownTestCase, db := SetupCleanDB(t)
defer teardownTestCase(t)