func RegisterModel(model Model) {
	modelList = append(modelList, model)
	modelTypeName := model.GetTypeName(model)
	modelFieldList := model.GetStructFields(model)
	typeNameJSONKeyStructFieldMap := map[string]reflect.StructField{}
	typeNameStructFieldList := []reflect.StructField{}
	for _, field := range modelFieldList {
		jsonKey := field.Name
		jsonTag, ok := field.Tag.Lookup("json")
		if ok {
			tagStatementList := strings.Split(jsonTag, ",")
			for _, tagStatement := range tagStatementList {
				switch tagStatement {
				case "omitempty", "-":
					continue
				default:
					jsonKey = tagStatement
					break
				}
			}
		}
		typeNameJSONKeyStructFieldMap[jsonKey] = field
		typeNameStructFieldList = append(typeNameStructFieldList, field)
		tag, ok := field.Tag.Lookup("gorm")
		if ok {
			tagStatementList := strings.Split(tag, ";")
			for _, tagStatement := range tagStatementList {
				switch tagStatement {
				case "primary_key":
					typeNameDefaultModelKeyMap[modelTypeName] = ModelKey{
						KeyParameter: jsonKey,
						KeyField:     field.Name,
					}
					break
				}
			}
		}
	}
	if _, exists := typeNameDefaultModelKeyMap[modelTypeName]; !exists {
		typeNameDefaultModelKeyMap[modelTypeName] = ModelKey{
			KeyParameter: "id",
			KeyField:     "ID",
		}
	}
	typeNameStructFieldListMap[modelTypeName] = typeNameStructFieldList
	typeNameJSONKeyStructFieldMapMap[modelTypeName] = typeNameJSONKeyStructFieldMap
}
RegisterModel registers a model to migrate automatically, and to generate new instances in processing requests
package extension
import (
	"errors"
	"fmt"
	"net/url"
	"reflect"
	"strings"
	"github.com/gin-gonic/gin"
	"github.com/jinzhu/gorm"
	"github.com/qb0C80aE/clay/logging"
	"github.com/serenize/snaker"
)
const (
	TagJSON string = "json"
	TagGORM string = "gorm"
	TagYAML string = "yaml"
	TagForm string = "form"
)
var modelList = []Model{}
var typeNameModelMap = map[string]Model{}
var resourceNameModelMap = map[string]Model{}
var typeNameResourceNameMap = map[string]string{}
var resourceNameTypeNameMap = map[string]string{}
var typeNameDefaultModelKeyMap = map[string]ModelKey{}
var typeNameStructFieldListMap = map[string][]reflect.StructField{}
var typeNameJSONKeyStructFieldMapMap = map[string]map[string]reflect.StructField{}
type structTree map[string]structTree
var structFieldTypeProxyType = reflect.TypeOf(&StructFieldTypeProxy{})
type StructFieldTypeProxy struct {
	reflect.Type
	name string
	kind reflect.Kind
}
func (receiver *StructFieldTypeProxy) Name() string {
	return receiver.name
}
func (receiver *StructFieldTypeProxy) Kind() reflect.Kind {
	return receiver.kind
}
func NewStructFieldTypeProxy(name string, kind reflect.Kind) *StructFieldTypeProxy {
	structFieldTypePlaceHolder := &StructFieldTypeProxy{
		Type: structFieldTypeProxyType,
		name: name,
		kind: kind,
	}
	return structFieldTypePlaceHolder
}
type Model interface {
	GetTypeName(model Model) string
	GetResourceName(model Model) (string, error)
	GenerateTableName(model Model, db *gorm.DB) string
	GetStructFields(model Model) []reflect.StructField
	GetModelKey(model Model, keyParameterSpecifier string) (ModelKey, error)
	GetContainerForMigration() (interface{}, error)
	GetSingle(model Model, db *gorm.DB, parameters gin.Params, urlValues url.Values, queryString string) (interface{}, error)
	GetMulti(model Model, db *gorm.DB, parameters gin.Params, urlValues url.Values, queryString string) (interface{}, error)
	Create(model Model, db *gorm.DB, parameters gin.Params, urlValues url.Values, inputContainer interface{}) (interface{}, error)
	Update(model Model, db *gorm.DB, parameters gin.Params, urlValues url.Values, inputContainer interface{}) (interface{}, error)
	Delete(model Model, db *gorm.DB, parameters gin.Params, urlValues url.Values) error
	Patch(model Model, db *gorm.DB, parameters gin.Params, urlValues url.Values, inputContainer interface{}) (interface{}, error)
	GetOptions(model Model, db *gorm.DB, parameters gin.Params, urlValues url.Values) error
	GetCount(model Model, db *gorm.DB) (int, error)
}
type ModelKey struct {
	KeyParameter string
	KeyField     string
}
func InspectActualElementType(object interface{}) reflect.Type {
	objectType := reflect.TypeOf(object)
	for (objectType.Kind() == reflect.Ptr) || (objectType.Kind() == reflect.Interface) {
		objectType = objectType.Elem()
	}
	switch objectType.Kind() {
	case reflect.Array, reflect.Slice:
		objectType = objectType.Elem()
		for objectType.Kind() == reflect.Ptr {
			objectType = objectType.Elem()
		}
	}
	return objectType
}
func GetActualType(object interface{}) reflect.Type {
	objectType := reflect.TypeOf(object)
	for (objectType.Kind() == reflect.Ptr) || (objectType.Kind() == reflect.Interface) {
		objectType = objectType.Elem()
	}
	return objectType
}
func GetActualValue(object interface{}) reflect.Value {
	objectValue := reflect.ValueOf(object)
	for (objectValue.Kind() == reflect.Ptr) || (objectValue.Kind() == reflect.Interface) {
		objectValue = objectValue.Elem()
	}
	return objectValue
}
func GetModelKey(model Model, keyParameterSpecifier string) (ModelKey, error) {
	modelKey, err := GetRegisteredDefaultModelKey(model)
	if err != nil {
		return ModelKey{}, err
	}
	if len(keyParameterSpecifier) > 0 {
		container, err := CreateContainerByTypeName(model.GetTypeName(model))
		if err != nil {
			return ModelKey{}, err
		}
		containerType := GetActualType(container)
		jsonKey := ""
		fieldName := ""
		for i := 0; i < containerType.NumField(); i++ {
			field := containerType.Field(i)
			jsonTag, ok := field.Tag.Lookup("json")
			if ok {
				tagStatementList := strings.Split(jsonTag, ",")
				for _, tagStatement := range tagStatementList {
					switch tagStatement {
					case "omitempty", "-":
						continue
					default:
						if keyParameterSpecifier == tagStatement {
							jsonKey = tagStatement
							fieldName = field.Name
							break
						}
					}
				}
			}
		}
		if len(fieldName) == 0 {
			return ModelKey{}, fmt.Errorf("key_parameter %s does not exist in %s", keyParameterSpecifier, containerType.String())
		}
		modelKey = ModelKey{
			KeyParameter: jsonKey,
			KeyField:     fieldName,
		}
	}
	return modelKey, nil
}