go-sqlmock icon indicating copy to clipboard operation
go-sqlmock copied to clipboard

Argument matching for queries using unpacked slices

Open gkoscky opened this issue 1 year ago • 0 comments
trafficstars

I have a sqlx.Query being called on a named query with multiple parameters. You can see a working example, but here's the abridged version:

type myStruct struct {
  ColumnA string   `db:"columnA"`
  ColumnB string   `db:"columnB"`
  ColumnC []string `db:"columnC"`
}

func runQuery(db *sqlx.DB, arguments myStruct) ([]myStruct, error) {
  namedQuery := "SELECT * FROM my_table WHERE columnA = :columnA AND columnB = :columnB AND columnC IN (:columnC)"
  
  query, args, _ := sqlx.Named(namedQuery, arguments)
  query, args, _ = sqlx.In(query, args...)
  query = db.Rebind(query)
  
  rows, err := db.Queryx(query, args...)
  if err != nil {
    return nil, fmt.Errorf("error querying: %s", err)
  }
  //…
}

And then a test case like so

  mockDb, mock, err := sqlmock.New()
  sqlxDB := sqlx.NewDb(mockDb, "sqlmock")
  
  toQuery := myStruct{
    ColumnA: "testA",
    ColumnB: "testB",
    ColumnC: []string{"testC", "testD"},
  }
  
  queryArgs := []string{"testA", "testB", "testC", "testD"}
  
  returnRows := mock.NewRows([]string{"columnA", "columnB"}).AddRow("returnA", "returnB")
  mock.ExpectQuery("SELECT \\* FROM my_table ").WithArgs(queryArgs).WillReturnRows(returnRows)
  
  _, err = runQuery(sqlxDB, toQuery)
  if err != nil {
    log.Println(err)
    return
  }

Which results in this error message:

Query 'SELECT * FROM my_table WHERE columnA = ? AND columnB = ? AND columnC IN (?, ?)',
  arguments do not match: expected 1, but got 4 arguments

The error makes sense, because I am passing queryArgs ([]string) to WithArgs, while the actual Queryx(query, args...) method gets an unpacked []interface{} as its arguments. But doing a similar AddRow(queryArgs...) results in:

cannot use queryArgs (variable of type []string) as []driver.Value value in argument to mock.ExpectQuery

Which leads me to my question: How can I pass an array to WithArgs that would match the unpacked arguments passed to Queryx?

I know I could hard code it, but in the non-simplified version of this code, the number of arguments is variable for each test case.

gkoscky avatar Dec 20 '23 20:12 gkoscky