func()

in internal/postgres/unit.go [425:547]


func (db *DB) getUnitWithAllFields(ctx context.Context, um *internal.UnitMeta, bc internal.BuildContext) (_ *internal.Unit, err error) {
	defer derrors.WrapStack(&err, "getUnitWithAllFields(ctx, %q, %q, %q)", um.Path, um.ModulePath, um.Version)
	defer middleware.ElapsedStat(ctx, "getUnitWithAllFields")()

	// Get build contexts and unit ID.
	var pathID, unitID, moduleID int
	var bcs []internal.BuildContext
	err = db.db.RunQuery(ctx, `
		SELECT d.goos, d.goarch, u.id, p.id, u.module_id
		FROM units u
		INNER JOIN paths p ON p.id = u.path_id
		INNER JOIN modules m ON m.id = u.module_id
		LEFT JOIN documentation d ON d.unit_id = u.id
		WHERE
			p.path = $1
			AND m.module_path = $2
			AND m.version = $3
	`, func(rows *sql.Rows) error {
		var bc internal.BuildContext
		// GOOS and GOARCH will be NULL if there are no documentation rows for
		// the unit, but we still want the unit ID.

		if err := rows.Scan(database.NullIsEmpty(&bc.GOOS), database.NullIsEmpty(&bc.GOARCH), &unitID, &pathID, &moduleID); err != nil {
			return err
		}
		if bc.GOOS != "" && bc.GOARCH != "" {
			bcs = append(bcs, bc)
		}
		return nil
	}, um.Path, um.ModulePath, um.Version)
	if err != nil {
		return nil, err
	}
	sort.Slice(bcs, func(i, j int) bool { return internal.CompareBuildContexts(bcs[i], bcs[j]) < 0 })
	var bcMatched internal.BuildContext
	for _, c := range bcs {
		if bc.Match(c) {
			bcMatched = c
			break
		}
	}
	// Get README, documentation and import counts.
	query := `
        SELECT
			r.file_path,
			r.contents,
			d.synopsis,
			d.source,
			COALESCE((
				SELECT COUNT(unit_id)
				FROM imports
				WHERE unit_id = u.id
				GROUP BY unit_id
				), 0) AS num_imports,
			COALESCE((
				SELECT imported_by_count
				FROM search_documents
				-- Only package_path_id is needed b/c it is the PK for
				-- search_documents.
				WHERE package_path_id = $1
				), 0) AS num_imported_by
		FROM units u
		LEFT JOIN readmes r
		ON r.unit_id = u.id

		LEFT JOIN (
			SELECT synopsis, source, goos, goarch, unit_id
			FROM documentation d
			WHERE d.GOOS = $3 AND d.GOARCH = $4
        ) d
		ON d.unit_id = u.id
		WHERE u.id = $2
	`
	var (
		r internal.Readme
		u internal.Unit
	)
	u.BuildContexts = bcs
	var goos, goarch interface{}
	if bcMatched.GOOS != "" {
		goos = bcMatched.GOOS
		goarch = bcMatched.GOARCH
	}
	doc := &internal.Documentation{GOOS: bcMatched.GOOS, GOARCH: bcMatched.GOARCH}
	end := middleware.ElapsedStat(ctx, "getUnitWithAllFields-readme-and-imports")
	err = db.db.QueryRow(ctx, query, pathID, unitID, goos, goarch).Scan(
		database.NullIsEmpty(&r.Filepath),
		database.NullIsEmpty(&r.Contents),
		database.NullIsEmpty(&doc.Synopsis),
		&doc.Source,
		&u.NumImports,
		&u.NumImportedBy,
	)
	switch err {
	case sql.ErrNoRows:
		// Neither a README nor documentation; that's OK, continue.
	case nil:
		if r.Filepath != "" && um.ModulePath != stdlib.ModulePath {
			u.Readme = &r
		}
		if doc.GOOS != "" {
			u.Documentation = []*internal.Documentation{doc}
		}
	default:
		return nil, err
	}
	end()
	// Get other info.
	pkgs, err := db.getPackagesInUnit(ctx, um.Path, moduleID)
	if err != nil {
		return nil, err
	}
	u.Subdirectories = pkgs
	u.UnitMeta = *um

	if um.IsPackage() && !um.IsCommand() && doc.Source != nil {
		u.SymbolHistory, err = GetSymbolHistoryForBuildContext(ctx, db.db, pathID, um.ModulePath, bcMatched)
		if err != nil {
			return nil, err
		}
	}
	return &u, nil
}