148 lines
4.1 KiB
Go
148 lines
4.1 KiB
Go
package dbmeta
|
|
|
|
import (
|
|
"reflect"
|
|
|
|
"git.bit5.ru/backend/db"
|
|
"git.bit5.ru/backend/errors"
|
|
"git.bit5.ru/backend/meta"
|
|
)
|
|
|
|
func DeleteMetaStruct(db *db.DBC, metaStruct interface{}, ownerId uint32) error {
|
|
metaStructValue, metaStructType, err := getValueAndType(metaStruct)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
fieldsProps, err := getMetastructFieldProps(metaStructValue)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Iterate through struct fields to find field type struct or slice
|
|
for i := 0; i < metaStructType.NumField(); i++ {
|
|
field := metaStructType.Field(i)
|
|
|
|
if fieldsProps != nil {
|
|
if props, ok := fieldsProps[field.Name]; ok {
|
|
if _, ok := props["db_skip_save"]; ok {
|
|
continue
|
|
}
|
|
}
|
|
}
|
|
|
|
fieldType := field.Type
|
|
fieldValue := metaStructValue.Field(i)
|
|
|
|
// skip unexported fields
|
|
if len(field.PkgPath) > 0 {
|
|
continue
|
|
}
|
|
|
|
switch fieldType.Kind() {
|
|
case reflect.Slice:
|
|
// Try to get reflect.Value of slice underlying element
|
|
sliceElement := getSliceElementValue(fieldValue)
|
|
if err := DeleteMetaStruct(db, sliceElement.Addr().Interface(), ownerId); err != nil {
|
|
return err
|
|
}
|
|
|
|
case reflect.Struct:
|
|
if err := DeleteMetaStruct(db, fieldValue.Addr().Interface(), ownerId); err != nil {
|
|
return err
|
|
}
|
|
break
|
|
case reflect.UnsafePointer:
|
|
// Now we don't use these types in meta. If we will - fix it.
|
|
return errors.Errorf("I don't know what I should do with it: %s", fieldType.Kind())
|
|
case reflect.Map, reflect.Ptr, reflect.Array:
|
|
default:
|
|
break
|
|
}
|
|
}
|
|
|
|
if !isMetaDataItem(metaStructValue) {
|
|
return nil
|
|
}
|
|
|
|
table, ownerColumn, err := getTableAndOwnerColumn(metaStructValue)
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = deleteFromTable(db, table, ownerColumn, ownerId)
|
|
|
|
return err
|
|
}
|
|
|
|
func isMetaDataItem(metaStructValue reflect.Value) bool {
|
|
if !metaStructValue.CanInterface() {
|
|
return false
|
|
}
|
|
_, ok := metaStructValue.Addr().Interface().(meta.IMetaDataItem)
|
|
return ok
|
|
}
|
|
|
|
// Get value and type of MetaStruct. Only pointer is allowed.
|
|
func getValueAndType(metaStruct interface{}) (reflect.Value, reflect.Type, error) {
|
|
metaStructValue := reflect.ValueOf(metaStruct)
|
|
metaStructType := metaStructValue.Type()
|
|
|
|
if metaStructType.Kind() != reflect.Ptr {
|
|
return metaStructValue, metaStructType, errors.New("Value must be a pointer to a struct")
|
|
}
|
|
metaStructValue = metaStructValue.Elem()
|
|
metaStructType = metaStructType.Elem()
|
|
|
|
return metaStructValue, metaStructType, nil
|
|
}
|
|
|
|
// Get fieldsProps from metastruct
|
|
func getMetastructFieldProps(metaStructValue reflect.Value) (map[string]map[string]string, error) {
|
|
fieldsProps := make(map[string]map[string]string)
|
|
|
|
// Check if value is addressable, because meta.IClassProps' method CLASS_FIELDS_PROPS() has a pointer reciever
|
|
if !metaStructValue.CanAddr() {
|
|
return fieldsProps, errors.New("value is not addressable!")
|
|
}
|
|
|
|
if !metaStructValue.CanInterface() {
|
|
return fieldsProps, errors.New("Interface cannot used!")
|
|
}
|
|
|
|
iMetaClassFieldProps, ok := metaStructValue.Addr().Interface().(meta.IClassProps)
|
|
if !ok {
|
|
return fieldsProps, errors.New("value is not meta.IClassProps interface!")
|
|
}
|
|
fieldsProps = *iMetaClassFieldProps.CLASS_FIELDS_PROPS()
|
|
|
|
return fieldsProps, nil
|
|
}
|
|
|
|
// Returns slice element value to get table data
|
|
func getSliceElementValue(slice reflect.Value) reflect.Value {
|
|
// Slice Kind here is a pointer.
|
|
// First call of Elem() returns type from pointer(?).
|
|
// Second returns type of slice element
|
|
sliceElementType := slice.Type().Elem().Elem()
|
|
// Call Elem() on new value, because type of element type is pointer(?)
|
|
sliceElementValue := reflect.New(sliceElementType).Elem()
|
|
|
|
return sliceElementValue
|
|
}
|
|
|
|
func getTableAndOwnerColumn(metaStructValue reflect.Value) (string, string, error) {
|
|
|
|
iDataItem, ok := metaStructValue.Addr().Interface().(meta.IMetaDataItem)
|
|
if !ok {
|
|
return "", "", errors.New("Can't convert to interface meta.IMetaDataItem!")
|
|
}
|
|
|
|
return iDataItem.GetDbTableName(), iDataItem.GetOwnerFieldName(), nil
|
|
}
|
|
|
|
func deleteFromTable(db *db.DBC, table string, ownerColumnName string, ownerId uint32) error {
|
|
_, err := db.DeleteFrom(table).Where(ownerColumnName+" = ?", ownerId).Exec()
|
|
return err
|
|
}
|