select plus - xs-soft/dbr GitHub Wiki

高级查询操作

支持使用map结构取得多行记录 以字段名作为每行map的键

datas:=[]map[string]string{}
dbr.Select("*").From("user").Load(&datas)

来自于dbr的测试用例


直接上原版测试用例代码 Load操作之Map

func TestMaps(t *testing.T) {
	for _, sess := range testSession {
		reset(t, sess)

		_, err := sess.InsertInto("dbr_people").
			Columns("name", "email").
			Values("test1", "[email protected]").
			Values("test2", "[email protected]").
			Values("test2", "[email protected]").
			Exec()
                //如果Load一个MAP的时候,则以第一个字段为键,第二个字段为值
		var m map[string]string
		cnt, err := sess.Select("email, name").From("dbr_people").Load(&m)
		require.NoError(t, err)
		require.Equal(t, 3, cnt)
		require.Len(t, m, 3)
		require.Equal(t, "test1", m["[email protected]"])

                //当最为一个对象map的时候.则以第一个字段为键,并将除了第一个字段之外的值赋予对象
                //即dbrPerson中的id为0
		var m2 map[int64]*dbrPerson
		cnt, err = sess.Select("id, name, email").From("dbr_people").Load(&m2)
		require.NoError(t, err)
		require.Equal(t, 3, cnt)
		require.Len(t, m2, 3)
		require.Equal(t, "[email protected]", m2[1].Email)
		require.Equal(t, "test1", m2[1].Name)
		// the id value is used as the map key, so it is not hydrated in the struct
		require.Equal(t, int64(0), m2[1].Id)

                //当以第一个字段作为KEY,第二个字段作为值,当可能作为KEY的字段有重复的时候,
                //则将值append到其KEY对应MAP下的[]string中
		var m3 map[string][]string
		cnt, err = sess.Select("name, email").From("dbr_people").OrderAsc("id").Load(&m3)
		require.NoError(t, err)
		require.Equal(t, 3, cnt)
		require.Len(t, m3, 2)
		require.Equal(t, []string{"[email protected]"}, m3["test1"])
		require.Equal(t, []string{"[email protected]", "[email protected]"}, m3["test2"])

		var set map[string]struct{}
		cnt, err = sess.Select("name").From("dbr_people").Load(&set)
		require.NoError(t, err)
		require.Equal(t, 3, cnt)
		require.Len(t, set, 2)
		_, ok := set["test1"]
		require.True(t, ok)
	}
}

Load操作之Slice

type stringSliceWithSQLScanner []string

func (ss *stringSliceWithSQLScanner) Scan(src interface{}) error {
	*ss = append(*ss, "called")
	return nil
}
func TestSliceWithSQLScannerSelect(t *testing.T) {
	for _, sess := range testSession {
		reset(t, sess)

		_, err := sess.InsertInto("dbr_people").
			Columns("name", "email").
			Values("test1", "[email protected]").
			Values("test2", "[email protected]").
			Values("test3", "[email protected]").
			Exec()

                //传一个基本对象切片到load,则得到所有记录第一个字段的切片,本案例等同于.ReturnStrings()函数
                //但是这种操作可以是有支持Scan接口的自定义对象比如[]*decimal.Big{}
                //或Return系列函数不支持的类型比如[]Float64{}

		//plain string slice (original behavior)
		var stringSlice []string
		cnt, err := sess.Select("name").From("dbr_people").Load(&stringSlice)

		require.NoError(t, err)
		require.Equal(t, 3, cnt)
		require.Len(t, stringSlice, 3)

                //当对象支持Scanner接口时,则会调用对象的Scan方法,并把第一条记录中的第一个字段.传入做解析.
		//string slice with sql.Scanner implemented, should act as a single record
		var sliceScanner stringSliceWithSQLScanner
		cnt, err = sess.Select("name").From("dbr_people").Load(&sliceScanner)

		require.NoError(t, err)
		require.Equal(t, 1, cnt)
		require.Len(t, sliceScanner, 1)
	}
}

Load操作之InterfaceLoader 我希望把数据载入到一个[]interface 但是数据加载时还要指定interface的实际结构

func TestInterfaceLoader(t *testing.T) {
	for _, sess := range testSession {
		reset(t, sess)

		_, err := sess.InsertInto("dbr_people").
			Columns("name", "email").
			Values("test1", "[email protected]").
			Values("test2", "[email protected]").
			Values("test2", "[email protected]").
			Exec()

		var m []interface{}
                //其中dbrPerson作为解析的结构模板.如果作为结构模板的类型不是一个struct,则会用第一个字段的值去做转换
		cnt, err := sess.Select("*").From("dbr_people").Load(InterfaceLoader(&m, dbrPerson{}))
		require.NoError(t, err)
		require.Equal(t, 3, cnt)
		require.Len(t, m, 3)
		person, ok := m[0].(dbrPerson)
		require.True(t, ok)
		require.Equal(t, "test1", person.Name)
	}
}