dbmeta/load.go

166 lines
4.2 KiB
Go

package dbmeta
import (
"fmt"
"reflect"
"strings"
"git.bit5.ru/backend/db"
"git.bit5.ru/backend/errors"
"git.bit5.ru/backend/meta"
)
func LoadMetaStruct(db *db.DBC, data meta.IMetaStruct, ownerId uint32) error {
return loadStruct(db, data, ownerId)
}
func loadStruct(db *db.DBC, itemInter interface{}, ownerId uint32) error {
refItem := reflect.ValueOf(itemInter)
mType := refItem.Type()
var fprops map[string]map[string]string
if refItem.CanInterface() {
imeta, _ := refItem.Interface().(meta.IClassProps)
if imeta != nil {
fprops = *imeta.CLASS_FIELDS_PROPS()
}
}
if mType.Kind() == reflect.Ptr {
refItem = refItem.Elem()
mType = mType.Elem()
}
for i := 0; i < mType.NumField(); i++ {
field := mType.Field(i)
tfield := field.Type
if fprops != nil {
if props, ok := fprops[field.Name]; ok {
if _, ok := props["db_skip_load"]; ok {
continue
}
}
}
// skip unexported fields
if len(field.PkgPath) > 0 {
continue
}
switch tfield.Kind() {
case reflect.Slice:
if err := loadMetaCollection(db, refItem.Field(i).Addr().Interface(), ownerId); err != nil {
return err
}
break
case reflect.Struct:
if err := loadStruct(db, refItem.Field(i).Addr().Interface(), ownerId); err != nil {
return err
}
break
case reflect.Map:
case reflect.Ptr:
case reflect.Array:
case reflect.UnsafePointer:
// Now we don't use these types in meta. If we will - fix it.
return errors.Errorf("I don't now what I should do with it: %s", tfield.Kind())
default:
break
}
}
var row meta.IMetaStruct
if refItem.CanInterface() {
row = refItem.Addr().Interface().(meta.IMetaStruct)
}
if row == nil {
return errors.Errorf("Couldn't convert to IdataRow: %s", mType.Name())
}
props := *row.CLASS_PROPS()
if _, ok := props["POD"]; !ok {
// skip struct
return nil
}
if ownerField, ok := props["owner"]; ok {
field := refItem.FieldByName(strings.Title(ownerField))
if !field.IsValid() {
return errors.Errorf("Owner field \"%s\" is not found in struct \"%s\"", ownerField, mType.Name())
}
field.Set(reflect.ValueOf(ownerId))
}
if pkeyField, ok := props["pkey"]; ok {
field := refItem.FieldByName(strings.Title(pkeyField))
if !field.IsValid() {
return errors.Errorf("Pkey field \"%s\" is not found in struct \"%s\"", pkeyField, mType.Name())
}
err := FindOne(db, row, fmt.Sprintf("WHERE `%s`=?", pkeyField), []interface{}{field.Interface()})
if err != nil {
return err
}
refItem.Set(reflect.ValueOf(row).Elem())
} else {
return errors.Errorf("Struct \"%s\" doesn't have pkey field", mType.Name())
}
return nil
}
func LoadMetaMStruct(db *db.DBC, data interface{}, ownerId uint32) error {
return loadMetaCollection(db, data, ownerId)
}
func loadMetaCollection(db *db.DBC, dataItem interface{}, ownerId uint32) error {
var err error
refSlice := reflect.ValueOf(dataItem)
if refSlice.Kind() == reflect.Ptr {
refSlice = refSlice.Elem()
}
if refSlice.Kind() != reflect.Slice {
return errors.Errorf("It isn't slice: %s", refSlice.Kind())
}
sliceItem := reflect.New(refSlice.Type().Elem().Elem())
item := sliceItem.Interface().(meta.IMetaDataItem)
if item == nil {
return errors.Errorf("Couldn't convert to IMetaDataItem: %s", refSlice.Type().Elem())
}
ownerFieldIndex := -1
ownerField := item.GetOwnerFieldName()
for index, field := range item.GetDbFields() {
if field == ownerField {
ownerFieldIndex = index
break
}
}
if ownerFieldIndex == -1 {
return errors.New("Owner field not found in fields list")
}
sql := "SELECT `" + strings.Join(item.GetDbFields(), "`, `") + "` FROM " + "`" + item.GetDbTableName() + "`" +
" WHERE `" + ownerField + "`=" + fmt.Sprintf("%d", ownerId)
_, err = db.SelectBySQL(sql).LoadStructs(refSlice.Addr().Interface())
if err != nil {
return err
}
return nil
}
func FindOne(dbc *db.DBC, dataItem meta.IMetaStruct, appendSQL string, params []interface{}) error {
info, err := makeDataRowInfo(dataItem)
if err != nil {
return err
}
sql := "SELECT `" + strings.Join(info.fields, "`, `") + "` FROM `" + info.tableName + "` " + appendSQL
err = dbc.SelectBySQL(sql, params...).LoadStruct(dataItem)
if db.IsNotFoundError(err) {
return nil
}
return err
}