Added nested structure scan.
This commit is contained in:
parent
7d7dda3b7a
commit
3f4b5c69d3
5 changed files with 124 additions and 21 deletions
|
|
@ -28,7 +28,7 @@ func (c ColumnInfo) ToGoVarName() string {
|
||||||
|
|
||||||
func (c ColumnInfo) ToGoType() string {
|
func (c ColumnInfo) ToGoType() string {
|
||||||
typeStr := c.GoBaseType()
|
typeStr := c.GoBaseType()
|
||||||
if c.IsNullable {
|
if c.IsNullable || c.TableInfo.IsForeignKey(c.Name) {
|
||||||
return "*" + typeStr
|
return "*" + typeStr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -54,6 +54,8 @@ func (c ColumnInfo) GoBaseType() string {
|
||||||
return "[]byte"
|
return "[]byte"
|
||||||
case "text":
|
case "text":
|
||||||
return "string"
|
return "string"
|
||||||
|
case "numeric", "real":
|
||||||
|
return "float64"
|
||||||
default:
|
default:
|
||||||
return "string"
|
return "string"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -74,16 +74,24 @@ func (c *baseColumn) setTableName(table string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *baseColumn) SerializeSqlForColumnList(out *bytes.Buffer) error {
|
func (c *baseColumn) SerializeSqlForColumnList(out *bytes.Buffer) error {
|
||||||
|
|
||||||
|
c.SerializeSql(out)
|
||||||
|
|
||||||
|
if c.table != "" {
|
||||||
|
_, _ = out.WriteString(" AS \"" + c.table + "." + c.name + "\"")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *baseColumn) SerializeSql(out *bytes.Buffer) error {
|
||||||
if c.table != "" {
|
if c.table != "" {
|
||||||
_, _ = out.WriteString(c.table)
|
_, _ = out.WriteString(c.table)
|
||||||
_, _ = out.WriteString(".")
|
_, _ = out.WriteString(".")
|
||||||
}
|
}
|
||||||
_, _ = out.WriteString(c.name)
|
_, _ = out.WriteString(c.name)
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *baseColumn) SerializeSql(out *bytes.Buffer) error {
|
return nil
|
||||||
return c.SerializeSqlForColumnList(out)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type bytesColumn struct {
|
type bytesColumn struct {
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"github.com/serenize/snaker"
|
"github.com/serenize/snaker"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Execute(db *sql.DB, query string, destinationPtr interface{}) error {
|
func Execute(db *sql.DB, query string, destinationPtr interface{}) error {
|
||||||
|
|
@ -26,10 +27,14 @@ func Execute(db *sql.DB, query string, destinationPtr interface{}) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
columnNames, _ := rows.Columns()
|
columnNames, _ := rows.Columns()
|
||||||
columnTypes, _ := rows.ColumnTypes()
|
columnTypes, _ := rows.ColumnTypes()
|
||||||
values := createScanValue(columnTypes)
|
values := createScanValue(columnTypes)
|
||||||
|
//
|
||||||
|
//spew.Dump(columnTypes)
|
||||||
|
//spew.Dump(values)
|
||||||
|
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
err := rows.Scan(values...)
|
err := rows.Scan(values...)
|
||||||
|
|
@ -79,30 +84,79 @@ func newElemForSlice(destinationSlicePtr interface{}) interface{} {
|
||||||
func mapValuesToStruct(columnNames []string, row []interface{}, destination interface{}) error {
|
func mapValuesToStruct(columnNames []string, row []interface{}, destination interface{}) error {
|
||||||
structType := reflect.TypeOf(destination).Elem()
|
structType := reflect.TypeOf(destination).Elem()
|
||||||
structValue := reflect.ValueOf(destination).Elem()
|
structValue := reflect.ValueOf(destination).Elem()
|
||||||
|
structName := structType.Name()
|
||||||
|
|
||||||
for i := 0; i < structType.NumField(); i++ {
|
for i := 0; i < structType.NumField(); i++ {
|
||||||
fieldType := structType.Field(i)
|
fieldType := structType.Field(i)
|
||||||
|
//fieldTypeName := fieldType.Name
|
||||||
fieldValue := structValue.Field(i)
|
fieldValue := structValue.Field(i)
|
||||||
|
//fmt.Println("---------------", fieldTypeName)
|
||||||
|
//spew.Dump(fieldType.Type)
|
||||||
|
|
||||||
fieldName := fieldType.Name
|
if !isDbBaseType(fieldType.Type) {
|
||||||
|
if fieldType.Type.Kind() == reflect.Struct {
|
||||||
|
err := mapValuesToStruct(columnNames, row, fieldValue.Addr().Interface())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else if fieldType.Type.Kind() == reflect.Ptr {
|
||||||
|
newStructValue := reflect.New(fieldType.Type.Elem())
|
||||||
|
err := mapValuesToStruct(columnNames, row, newStructValue.Interface())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
//columnName := structName + "." + fieldName
|
if newStructValue.Elem().Interface() != reflect.New(fieldType.Type.Elem()).Elem().Interface() {
|
||||||
columnName := snaker.CamelToSnake(fieldName)
|
fieldValue.Set(newStructValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fieldName := fieldType.Name
|
||||||
|
|
||||||
rowIndex := getIndex(columnNames, columnName)
|
columnName := snaker.CamelToSnake(structName) + "." + snaker.CamelToSnake(fieldName)
|
||||||
|
//columnName := snaker.CamelToSnake(fieldName)
|
||||||
|
|
||||||
if rowIndex < 0 {
|
//fmt.Println(columnName)
|
||||||
continue
|
rowIndex := getIndex(columnNames, columnName)
|
||||||
|
|
||||||
|
if rowIndex < 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
//spew.Dump(row[rowIndex])
|
||||||
|
|
||||||
|
rowColumnValue := reflect.ValueOf(row[rowIndex])
|
||||||
|
|
||||||
|
//spew.Dump(rowColumnValue, fieldValue)
|
||||||
|
setReflectValue(rowColumnValue, fieldValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
rowColumnValue := reflect.ValueOf(row[rowIndex])
|
|
||||||
|
|
||||||
setReflectValue(rowColumnValue, fieldValue)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var timeType = reflect.TypeOf(time.Now())
|
||||||
|
var floatType = reflect.TypeOf(1.0)
|
||||||
|
var stringType = reflect.TypeOf("str")
|
||||||
|
var intType = reflect.TypeOf(1)
|
||||||
|
|
||||||
|
func isDbBaseType(objType reflect.Type) bool {
|
||||||
|
//isBaseType := objType == timeType || floatType == objType || stringType == objType || intType == objType
|
||||||
|
//isPtrToBaseType := objType.Kind() == reflect.Ptr && (objType.Elem() == timeType || floatType == objType.Elem() ||
|
||||||
|
// stringType == objType.Elem() || intType == objType.Elem())
|
||||||
|
typeStr := objType.String()
|
||||||
|
|
||||||
|
switch typeStr {
|
||||||
|
case "string", "int32", "int16", "float64", "time.Time":
|
||||||
|
return true
|
||||||
|
case "*string", "*int32", "*int16", "*float64", "*time.Time":
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
//return isBaseType || isPtrToBaseType
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func setReflectValue(source, destination reflect.Value) {
|
func setReflectValue(source, destination reflect.Value) {
|
||||||
if destination.Kind() == reflect.Ptr {
|
if destination.Kind() == reflect.Ptr {
|
||||||
if source.Kind() == reflect.Ptr {
|
if source.Kind() == reflect.Ptr {
|
||||||
|
|
@ -133,7 +187,7 @@ func createScanValue(columnTypes []*sql.ColumnType) []interface{} {
|
||||||
values := make([]interface{}, len(columnTypes))
|
values := make([]interface{}, len(columnTypes))
|
||||||
|
|
||||||
for i, sqlColumnType := range columnTypes {
|
for i, sqlColumnType := range columnTypes {
|
||||||
columnType := sqlColumnType.ScanType()
|
columnType := getScanType(sqlColumnType)
|
||||||
|
|
||||||
columnValue := reflect.New(columnType)
|
columnValue := reflect.New(columnType)
|
||||||
|
|
||||||
|
|
@ -142,3 +196,18 @@ func createScanValue(columnTypes []*sql.ColumnType) []interface{} {
|
||||||
|
|
||||||
return values
|
return values
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getScanType(columnType *sql.ColumnType) reflect.Type {
|
||||||
|
scanType := columnType.ScanType()
|
||||||
|
//fmt.Println(scanType.String())
|
||||||
|
if scanType.String() != "interface {}" {
|
||||||
|
return scanType
|
||||||
|
}
|
||||||
|
|
||||||
|
switch columnType.DatabaseTypeName() {
|
||||||
|
case "FLOAT4":
|
||||||
|
return floatType
|
||||||
|
default:
|
||||||
|
return stringType
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -443,7 +443,7 @@ func Eq(lhs, rhs Expression) BoolExpression {
|
||||||
if ok && sqltypes.Value(lit.value).IsNull() {
|
if ok && sqltypes.Value(lit.value).IsNull() {
|
||||||
return newBoolExpression(lhs, rhs, []byte(" IS "))
|
return newBoolExpression(lhs, rhs, []byte(" IS "))
|
||||||
}
|
}
|
||||||
return newBoolExpression(lhs, rhs, []byte("="))
|
return newBoolExpression(lhs, rhs, []byte(" = "))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns a representation of "a=b", where b is a literal
|
// Returns a representation of "a=b", where b is a literal
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,8 @@ package tests
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/davecgh/go-spew/spew"
|
|
||||||
"github.com/sub0Zero/go-sqlbuilder/generator"
|
"github.com/sub0Zero/go-sqlbuilder/generator"
|
||||||
|
"github.com/sub0Zero/go-sqlbuilder/sqlbuilder"
|
||||||
"github.com/sub0Zero/go-sqlbuilder/tests/.test_files/dvd_rental/dvds/model"
|
"github.com/sub0Zero/go-sqlbuilder/tests/.test_files/dvd_rental/dvds/model"
|
||||||
. "github.com/sub0Zero/go-sqlbuilder/tests/.test_files/dvd_rental/dvds/table"
|
. "github.com/sub0Zero/go-sqlbuilder/tests/.test_files/dvd_rental/dvds/table"
|
||||||
"gotest.tools/assert"
|
"gotest.tools/assert"
|
||||||
|
|
@ -74,8 +74,7 @@ func TestSelectQuery(t *testing.T) {
|
||||||
queryStr, err := query.String()
|
queryStr, err := query.String()
|
||||||
|
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
assert.Equal(t, queryStr, "SELECT customer.customer_id,customer.store_id,customer.first_name,customer.last_name,customer.email,customer.address_id,customer.activebool,customer.create_date,customer.last_update,customer.active FROM dvds.customer")
|
assert.Equal(t, queryStr, `SELECT customer.customer_id AS "customer.customer_id",customer.store_id AS "customer.store_id",customer.first_name AS "customer.first_name",customer.last_name AS "customer.last_name",customer.email AS "customer.email",customer.address_id AS "customer.address_id",customer.activebool AS "customer.activebool",customer.create_date AS "customer.create_date",customer.last_update AS "customer.last_update",customer.active AS "customer.active" FROM dvds.customer`)
|
||||||
|
|
||||||
//fmt.Println(queryStr)
|
//fmt.Println(queryStr)
|
||||||
|
|
||||||
err = query.Execute(db, &customers)
|
err = query.Execute(db, &customers)
|
||||||
|
|
@ -93,9 +92,34 @@ func TestSelectQuery(t *testing.T) {
|
||||||
|
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
||||||
spew.Dump(actor)
|
//spew.Dump(actor)
|
||||||
//time, _ := time.Parse("2006-01-02 15:04:05.00MST", "2013-05-26 14:47:57.62MST")
|
//time, _ := time.Parse("2006-01-02 15:04:05.00MST", "2013-05-26 14:47:57.62MST")
|
||||||
assert.Equal(t, actor.ActorID, int32(1))
|
assert.Equal(t, actor.ActorID, int32(1))
|
||||||
assert.Equal(t, actor.FirstName, "Penelope")
|
assert.Equal(t, actor.FirstName, "Penelope")
|
||||||
assert.Equal(t, actor.LastName, "Guiness")
|
assert.Equal(t, actor.LastName, "Guiness")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestJoinQuery(t *testing.T) {
|
||||||
|
|
||||||
|
//filmActor := model.FilmActor{}
|
||||||
|
allFilmActorColumns := append(append(Actor.All, Film.All...), Language.All...)
|
||||||
|
query := FilmActor.
|
||||||
|
InnerJoinOn(Actor, sqlbuilder.Eq(FilmActor.ActorID, Actor.ActorID)).
|
||||||
|
InnerJoinOn(Film, sqlbuilder.Eq(FilmActor.FilmID, Film.FilmID)).
|
||||||
|
InnerJoinOn(Language, sqlbuilder.Eq(Film.LanguageID, Language.LanguageID)).
|
||||||
|
Select(allFilmActorColumns...).
|
||||||
|
Where(sqlbuilder.Eq(FilmActor.ActorID, sqlbuilder.Literal(1)))
|
||||||
|
|
||||||
|
queryStr, err := query.String()
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
fmt.Println(queryStr)
|
||||||
|
|
||||||
|
filmActor := model.FilmActor{}
|
||||||
|
|
||||||
|
err = query.Execute(db, &filmActor)
|
||||||
|
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
//spew.Dump(filmActor)
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue