diff options
Diffstat (limited to 'internal/postgres/package_symbol.go')
| -rw-r--r-- | internal/postgres/package_symbol.go | 94 |
1 files changed, 91 insertions, 3 deletions
diff --git a/internal/postgres/package_symbol.go b/internal/postgres/package_symbol.go index aaa28267..4d99b07c 100644 --- a/internal/postgres/package_symbol.go +++ b/internal/postgres/package_symbol.go @@ -8,6 +8,7 @@ import ( "context" "database/sql" "fmt" + "sort" "github.com/Masterminds/squirrel" "golang.org/x/pkgsite/internal" @@ -16,6 +17,93 @@ import ( "golang.org/x/pkgsite/internal/middleware/stats" ) +// GetSymbols returns all of the symbols for a given package path and module path. +func (db *DB) GetSymbols(ctx context.Context, pkgPath, modulePath, version string, bc internal.BuildContext) (_ []*internal.Symbol, err error) { + defer derrors.Wrap(&err, "DB.GetSymbols(ctx, %q, %q, %q, %v)", pkgPath, modulePath, version, bc) + defer stats.Elapsed(ctx, "DB.GetSymbols")() + + query := packageSymbolQueryJoin( + squirrel.Select( + "s1.name AS symbol_name", + "s2.name AS parent_symbol_name", + "ps.section", + "ps.type", + "ps.synopsis", + "d.goos", + "d.goarch"), pkgPath, modulePath). + Where(squirrel.Eq{"m.version": version}). + OrderBy("CASE WHEN ps.type='Type' THEN 0 ELSE 1 END"). + OrderBy("s1.name") + + q, args, err := query.PlaceholderFormat(squirrel.Dollar).ToSql() + if err != nil { + return nil, err + } + + resultsByBC := make(map[internal.BuildContext][]internal.SymbolMeta) + collect := func(rows *sql.Rows) error { + var ( + name, parentName, synopsis, goos, goarch string + section internal.SymbolSection + kind internal.SymbolKind + ) + if err := rows.Scan(&name, &parentName, §ion, &kind, &synopsis, &goos, &goarch); err != nil { + return fmt.Errorf("row.Scan(): %v", err) + } + rowBC := internal.BuildContext{GOOS: goos, GOARCH: goarch} + if bc.Match(rowBC) { + resultsByBC[rowBC] = append(resultsByBC[rowBC], internal.SymbolMeta{ + Name: name, + ParentName: parentName, + Section: section, + Kind: kind, + Synopsis: synopsis, + }) + } + return nil + } + + if err := db.db.RunQuery(ctx, q, collect, args...); err != nil { + return nil, err + } + + if len(resultsByBC) == 0 { + return nil, derrors.NotFound + } + + // Find the best build context among those that matched. + var matchedBCs []internal.BuildContext + for b := range resultsByBC { + matchedBCs = append(matchedBCs, b) + } + sort.Slice(matchedBCs, func(i, j int) bool { + return internal.CompareBuildContexts(matchedBCs[i], matchedBCs[j]) < 0 + }) + bestBC := matchedBCs[0] + + var symbols []*internal.Symbol + symbolMap := make(map[string]*internal.Symbol) + rows := resultsByBC[bestBC] + for i := range rows { + sm := rows[i] + if sm.ParentName != "" && sm.ParentName != sm.Name { + if parent, ok := symbolMap[sm.ParentName]; ok { + parent.Children = append(parent.Children, &rows[i]) + continue + } + } + // Treat as top-level if no parent or parent not found in this build context. + s := &internal.Symbol{ + SymbolMeta: sm, + GOOS: bestBC.GOOS, + GOARCH: bestBC.GOARCH, + } + symbols = append(symbols, s) + symbolMap[sm.Name] = s + } + return symbols, nil +} + // getPackageSymbols returns all of the symbols for a given package path and module path. func getPackageSymbols(ctx context.Context, ddb *database.DB, packagePath, modulePath string, ) (_ *internal.SymbolHistory, err error) { @@ -32,6 +120,8 @@ func getPackageSymbols(ctx context.Context, ddb *database.DB, packagePath, modul "m.version", "d.goos", "d.goarch"), packagePath, modulePath). + Where("NOT m.incompatible"). + Where(squirrel.Eq{"m.version_type": "release"}). OrderBy("CASE WHEN ps.type='Type' THEN 0 ELSE 1 END"). OrderBy("s1.name") q, args, err := query.PlaceholderFormat(squirrel.Dollar).ToSql() @@ -64,9 +154,7 @@ func packageSymbolQueryJoin(query squirrel.SelectBuilder, pkgPath, modulePath st Join("symbol_names s1 ON ps.symbol_name_id = s1.id"). Join("symbol_names s2 ON ps.parent_symbol_name_id = s2.id"). Where(squirrel.Eq{"p1.path": pkgPath}). - Where(squirrel.Eq{"m.module_path": modulePath}). - Where("NOT m.incompatible"). - Where(squirrel.Eq{"m.version_type": "release"}) + Where(squirrel.Eq{"m.module_path": modulePath}) } func collectSymbolHistory(check func(sh *internal.SymbolHistory, sm internal.SymbolMeta, v string, build internal.BuildContext) error) (*internal.SymbolHistory, func(rows *sql.Rows) error) { |
