Ruleguard by example: External types

package gorules

import "github.com/quasilyte/go-ruleguard/dsl"

// Imagine that you're using the sqlx package.
// You have runQuery() and runQueryContext() wrappers to exec SQL queries.
//
// What you would like to do is to suggest runQueryContext() whether it's possible.
//
// Now we need to check if the runQuery() argument is capable of ExecContext() and
// if it is, propose the runQueryContext() as an alternative.

func execContext(m dsl.Matcher) {
	// First, we need to tell ruleguard what do we mean when we say "sqlx" inside
	// the type filters. Import() works for the current group scope.
	m.Import("github.com/jmoiron/sqlx")

	// Now it's as simple as it was before: check whether $e implements the
	// interface from the imported package.
	m.Match(`runQuery($e, $*_)`).
		Where(m["e"].Type.Implements(`sqlx.ExecerContext`)).
		Report(`prefer runQueryContext`)
}
package main

import (
	"context"

	"github.com/jmoiron/sqlx"
)

func main() {
	var db sqlx.DB
	var execer sqlx.Execer // Doesn't implement sqlx.ExecerContext

	runQuery(&db, "SELECT 9000")
	runQuery(execer, "SELECT 9000")
}

func runQuery(e sqlx.Execer, rest ...interface{}) {}

func runQueryContext(ctx context.Context, e sqlx.ExecerContext, rest ...interface{}) {}

Notes: