166 lines
4.2 KiB
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
|
|
}
|