package orm

import (
	
	
	
	

	
)

type structTableModel struct {
	table *Table
	rel   *Relation
	joins []join

	root  reflect.Value
	index []int

	strct         reflect.Value
	structInited  bool
	structInitErr error
}

var _ TableModel = (*structTableModel)(nil)

func ( *Table) *structTableModel {
	return &structTableModel{
		table: ,
	}
}

func ( reflect.Value) *structTableModel {
	return &structTableModel{
		table: GetTable(.Type()),
		root:  ,
		strct: ,
	}
}

func (*structTableModel) () bool {
	return true
}

func ( *structTableModel) () string {
	return .table.String()
}

func ( *structTableModel) () bool {
	return !.strct.IsValid()
}

func ( *structTableModel) () *Table {
	return .table
}

func ( *structTableModel) () *Relation {
	return .rel
}

func ( *structTableModel) ( QueryFormatter,  []byte,  string) ([]byte, bool) {
	,  := .table.AppendParam(, .strct, )
	if  {
		return , true
	}

	switch  {
	case "TableName":
		 = .FormatQuery(, string(.table.SQLName))
		return , true
	case "TableAlias":
		 = append(, .table.Alias...)
		return , true
	case "TableColumns":
		 = appendColumns(, .table.Alias, .table.Fields)
		return , true
	case "Columns":
		 = appendColumns(, "", .table.Fields)
		return , true
	case "TablePKs":
		 = appendColumns(, .table.Alias, .table.PKs)
		return , true
	case "PKs":
		 = appendColumns(, "", .table.PKs)
		return , true
	}

	return , false
}

func ( *structTableModel) () reflect.Value {
	return .root
}

func ( *structTableModel) () []int {
	return .index
}

func ( *structTableModel) () []int {
	return .index[:len(.index)-len(.rel.Field.Index)]
}

func ( *structTableModel) () reflect.Kind {
	return reflect.Struct
}

func ( *structTableModel) () reflect.Value {
	return .strct
}

func ( *structTableModel) ( reflect.Value) {
	.strct = .FieldByIndex(.rel.Field.Index)
	.structInited = false
}

func ( *structTableModel) () error {
	if .structInited {
		return .structInitErr
	}
	.structInited = true

	switch .strct.Kind() {
	case reflect.Invalid:
		.structInitErr = errModelNil
		return .structInitErr
	case reflect.Interface:
		.strct = .strct.Elem()
	}

	if .strct.Kind() == reflect.Ptr {
		if .strct.IsNil() {
			.strct.Set(reflect.New(.strct.Type().Elem()))
			.strct = .strct.Elem()
		} else {
			.strct = .strct.Elem()
		}
	}

	.mountJoins()

	return nil
}

func ( *structTableModel) () {
	for  := range .joins {
		 := &.joins[]
		switch .Rel.Type {
		case HasOneRelation, BelongsToRelation:
			.JoinModel.Mount(.strct)
		}
	}
}

func (structTableModel) () error {
	return nil
}

func ( *structTableModel) () ColumnScanner {
	return 
}

func ( *structTableModel) ( ColumnScanner) error {
	return nil
}

var _ BeforeScanHook = (*structTableModel)(nil)

func ( *structTableModel) ( context.Context) error {
	if !.table.hasFlag(beforeScanHookFlag) {
		return nil
	}
	return callBeforeScanHook(, .strct.Addr())
}

var _ AfterScanHook = (*structTableModel)(nil)

func ( *structTableModel) ( context.Context) error {
	if !.table.hasFlag(afterScanHookFlag) || !.structInited {
		return nil
	}

	var  error

	if  := callAfterScanHook(, .strct.Addr());  != nil &&  == nil {
		 = 
	}

	for ,  := range .joins {
		switch .Rel.Type {
		case HasOneRelation, BelongsToRelation:
			if  := .JoinModel.AfterScan();  != nil &&  == nil {
				 = 
			}
		}
	}

	return 
}

func ( *structTableModel) ( context.Context) error {
	if .table.hasFlag(afterSelectHookFlag) {
		return callAfterSelectHook(, .strct.Addr())
	}
	return nil
}

func ( *structTableModel) ( context.Context) (context.Context, error) {
	if .table.hasFlag(beforeInsertHookFlag) {
		return callBeforeInsertHook(, .strct.Addr())
	}
	return , nil
}

func ( *structTableModel) ( context.Context) error {
	if .table.hasFlag(afterInsertHookFlag) {
		return callAfterInsertHook(, .strct.Addr())
	}
	return nil
}

func ( *structTableModel) ( context.Context) (context.Context, error) {
	if .table.hasFlag(beforeUpdateHookFlag) && !.IsNil() {
		return callBeforeUpdateHook(, .strct.Addr())
	}
	return , nil
}

func ( *structTableModel) ( context.Context) error {
	if .table.hasFlag(afterUpdateHookFlag) && !.IsNil() {
		return callAfterUpdateHook(, .strct.Addr())
	}
	return nil
}

func ( *structTableModel) ( context.Context) (context.Context, error) {
	if .table.hasFlag(beforeDeleteHookFlag) && !.IsNil() {
		return callBeforeDeleteHook(, .strct.Addr())
	}
	return , nil
}

func ( *structTableModel) ( context.Context) error {
	if .table.hasFlag(afterDeleteHookFlag) && !.IsNil() {
		return callAfterDeleteHook(, .strct.Addr())
	}
	return nil
}

func ( *structTableModel) (
	 types.ColumnInfo,  types.Reader,  int,
) error {
	,  := .scanColumn(, , )
	if  {
		return 
	}
	if .table.hasFlag(discardUnknownColumnsFlag) || .Name[0] == '_' {
		return nil
	}
	return fmt.Errorf(
		"pg: can't find column=%s in %s "+
			"(prefix the column with underscore or use discard_unknown_columns)",
		.Name, .table,
	)
}

func ( *structTableModel) ( types.ColumnInfo,  types.Reader,  int) (bool, error) {
	// Don't init nil struct if value is NULL.
	if  == -1 &&
		!.structInited &&
		.strct.Kind() == reflect.Ptr &&
		.strct.IsNil() {
		return true, nil
	}

	if  := .initStruct();  != nil {
		return true, 
	}

	,  := splitColumn(.Name)
	if  != "" {
		if  := .GetJoin();  != nil {
			 := 
			.Name = 
			return .JoinModel.scanColumn(, , )
		}
		if .table.ModelName ==  {
			 := 
			.Name = 
			return .(, , )
		}
	}

	,  := .table.FieldsMap[.Name]
	if ! {
		return false, nil
	}

	return true, .ScanValue(.strct, , )
}

func ( *structTableModel) ( string) *join {
	for  := range .joins {
		 := &.joins[]
		if .Rel.Field.GoName ==  || .Rel.Field.SQLName ==  {
			return 
		}
	}
	return nil
}

func ( *structTableModel) () []join {
	return .joins
}

func ( *structTableModel) ( join) *join {
	.joins = append(.joins, )
	return &.joins[len(.joins)-1]
}

func ( *structTableModel) ( string,  func(*Query) (*Query, error)) *join {
	return .join(.Value(), , )
}

func ( *structTableModel) (
	 reflect.Value,  string,  func(*Query) (*Query, error),
) *join {
	 := strings.Split(, ".")
	 := make([]int, 0, len())

	 := join{
		BaseModel: ,
		JoinModel: ,
	}
	var  *join
	var  bool

	for ,  := range  {
		,  := .JoinModel.Table().Relations[]
		if ! {
			 = true
			break
		}

		.Rel = 
		 = append(, .Field.Index...)

		if  := .JoinModel.GetJoin();  != nil {
			.BaseModel = .BaseModel
			.JoinModel = .JoinModel

			 = 
		} else {
			,  := newTableModelIndex(.table.Type, , , )
			if  != nil {
				return nil
			}

			.Parent = 
			.BaseModel = .JoinModel
			.JoinModel = 

			 = .BaseModel.AddJoin()
		}
	}

	// No joins with such name.
	if  == nil {
		return nil
	}
	if  != nil {
		.ApplyQuery = 
	}

	if  {
		 := [len()-1]
		if  == "_" {
			if .Columns == nil {
				.Columns = make([]string, 0)
			}
		} else {
			.Columns = append(.Columns, )
		}
	}

	return 
}

func ( *structTableModel) () error {
	 := .table.SoftDeleteField.Value(.strct)
	return .table.SetSoftDeleteField()
}

func ( string) (string, string) {
	 := strings.Index(, "__")
	if  == -1 {
		return "", 
	}
	return [:], [+2:]
}