scylladb/gocqlx

expected 1 column in result while scanning scannable type ptr but got 9 when using GetRelease with BindMap

Closed this issue · 3 comments

I am passing in a map of type params map[string]interface{} to lookup a value in the table.

My table

type User struct {
	ID         gocql.UUID `cql:"id"`
	FirstName  string     `validate:"required"`
	LastName   string     `validate:"required"`
	Email      string     `validate:"email,required,db_unique"`
	Password   string     `copier:"-"`
	IsVerified bool
	IsActive   bool
	CreatedAt  time.Time
	UpdatedAt  time.Time
}

var columns = []string{
	"id",
	"first_name",
        "last_name",
	"email",
	"password",
	"is_active",
	"is_verified",
	"created_at",
	"updated_at",
}

var userMeta = table.Metadata{
	Name:    "users",
	Columns: columns,
}

var userTable = table.New(userMeta)

func (u *User) Get(params map[string]interface{}) error {
	common.Logger.Info("Get", zap.Any("params", params))
	query := db.DB.Session.Query(userTable.Get()).BindMap(params)

	if err := query.GetRelease(&u); err != nil {
		common.Logger.Error(err.Error())
		return err
	}

	return nil
}

The value of params is {"Email":"anc@yahoo.com"}. The error I am getting is

expected 1 column in result while scanning scannable type ptr but got 9

The statement being built is

"SELECT * FROM users " values=[] consistency=QUORUM"

Please note that the above query works with BindStruct but I need to pass in map instead of struct.

Where am I going wrong?

// ysf

Adding more context. I am using the validation package from go-playground and trying to build custom validation for uniqueness on a field db_unique.

Here is my code for that.

type Model interface {
	Get(map[string]interface{}) error
	// Get(interface{}) error
}

func Unique(fl validator.FieldLevel) bool {
	common.Logger.Info("Unique validation")
	model := fl.Parent().Addr().Interface().(Model)
	if err := model.Get(map[string]interface{}{fl.FieldName(): fl.Param()}); err != nil {
		return true
	}
	return true
}

looking at the code ... I am getting the error at

if scannable && len(iter.Columns()) > 1 {

I think the error breaks down to

// If the destination is some other type, then the row must only have one column
// which can scan into that type.

and my code

model := fl.Parent().Addr().Interface().(Model)

because the destination is an interface?

I changed my approach a little bit to use reflect.Call ... I know this is not the forum to ask this .. but can you please guide me as to where I am going wrong.

func Unique(fl validator.FieldLevel) bool {
	common.Logger.Info("Unique validation")
	params := map[string]interface{}{fl.FieldName(): fl.Field().Interface()}
	if err := fl.Parent().MethodByName("Get").Call([]reflect.Value{reflect.ValueOf(params)}); err != nil {
		return true
	}
	return true
}

The error I am getting is ..

  panic: reflect: call of reflect.Value.Call on zero Value

  -> reflect.flag.mustBe
  ->   /usr/local/go/src/reflect/value.go:223

Found the error.

func (u *User) Get(params map[string]interface{}) error {
	common.Logger.Info("Get", zap.Any("params", params))
	query := db.DB.Session.Query(userTable.Get()).BindMap(params)

	if err := query.GetRelease(u); err != nil { // This was &u.
		common.Logger.Error(err.Error())
		return err
	}

	return nil
}