Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support set custom unmarshal row handle #4312

Open
wants to merge 5 commits into
base: master
Choose a base branch
from

Conversation

changzzhou
Copy link

支持自定义unmarshalRow&unmarshalRows方法

@changzzhou
Copy link
Author

通过自定义unmarshalRow或者unmarshalRows方法,可以比较方便的来解析我们的struct,下面是个简单的例子

package main

import (
	"database/sql"
	"github.com/DATA-DOG/go-sqlmock"
	"github.com/didi/gendry/scanner"
	"github.com/stretchr/testify/assert"
	"github.com/zeromicro/go-zero/core/stores/dbtest"
	"github.com/zeromicro/go-zero/core/stores/sqlx"
	"testing"
)

type User struct {
	ID         int64   `ddb:"id"`
	Name       string  `ddb:"name"`
	Age        int     `ddb:"age"`
	Occupation *string `ddb:"occupation"`
}

func unmarshalRow(v any, rows *sql.Rows, strict bool) (err error) {
	return scanner.Scan(rows, v)
}

func Test_unmarshalRow(t *testing.T) {
	sqlx.SetUnmarshalRowHandler(unmarshalRow)
	sqlx.SetUnmarshalRowsHandler(unmarshalRow)

	dbtest.RunTest(t, func(db *sql.DB, mock sqlmock.Sqlmock) {
		rs := sqlmock.NewRows([]string{"id", "name", "age", "occupation"}).AddRow(1, "Tom", 20, nil)
		rs.AddRow(2, "Jerry", 22, sql.NullString{String: "engineer", Valid: true})
		mock.ExpectQuery("select (.+) from users").WillReturnRows(rs)

		conn := sqlx.NewSqlConnFromDB(db)
		var users []*User
		err := conn.QueryRow(&users, "select * from users")
		assert.Nil(t, err)
		assert.Equal(t, &User{ID: 1, Name: "Tom", Age: 20, Occupation: nil}, users[0])
		occ := "engineer"
		assert.Equal(t, &User{ID: 2, Name: "Jerry", Age: 22, Occupation: &occ}, users[1])
	})
}

@MarkJoyMa
Copy link
Collaborator

Would it be too heavy to modify the global UnmarshalRowHandler of sqlx? And are there scenarios where both are needed? So, you can evaluate whether to follow the model and inject it into the option?

@changzzhou
Copy link
Author

unmarshal row handler with option

update test case

package main

import (
	"database/sql"
	"github.com/DATA-DOG/go-sqlmock"
	"github.com/didi/gendry/scanner"
	"github.com/stretchr/testify/assert"
	"github.com/zeromicro/go-zero/core/stores/dbtest"
	"github.com/zeromicro/go-zero/core/stores/sqlx"
	"testing"
)

type User struct {
	ID         int64   `ddb:"id"`
	Name       string  `ddb:"name"`
	Age        int     `ddb:"age"`
	Occupation *string `ddb:"occupation"`
}

func unmarshalRow(v any, rows sqlx.RowsScanner, strict bool) (err error) {
	return scanner.Scan(rows.(*sql.Rows), v)
}

func Test_unmarshalRow(t *testing.T) {
	dbtest.RunTest(t, func(db *sql.DB, mock sqlmock.Sqlmock) {
		rs := sqlmock.NewRows([]string{"id", "name", "age", "occupation"}).AddRow(1, "Tom", 20, nil)
		rs.AddRow(2, "Jerry", 22, sql.NullString{String: "engineer", Valid: true})
		mock.ExpectQuery("select (.+) from users").WillReturnRows(rs)

		conn := sqlx.NewSqlConnFromDB(db, sqlx.WithMysqlUnmarshalRowHandler(unmarshalRow),
			sqlx.WithMysqlUnmarshalRowsHandler(unmarshalRow),
		)
		var users []*User
		err := conn.QueryRow(&users, "select * from users")
		assert.Nil(t, err)
		assert.Equal(t, &User{ID: 1, Name: "Tom", Age: 20, Occupation: nil}, users[0])
		occ := "engineer"
		assert.Equal(t, &User{ID: 2, Name: "Jerry", Age: 22, Occupation: &occ}, users[1])
	})
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants