package bun

import (
	
	
	
	
	
	

	
)

type structTableModel struct {
	db    *DB
	table *schema.Table

	rel   *schema.Relation
	joins []relationJoin

	dest  interface{}
	root  reflect.Value
	index []int

	strct         reflect.Value
	structInited  bool
	structInitErr error

	columns   []string
	scanIndex int
}

var _ tableModel = (*structTableModel)(nil)

func ( *DB,  interface{},  *schema.Table) *structTableModel {
	return &structTableModel{
		db:    ,
		table: ,
		dest:  ,
	}
}

func ( *DB,  interface{},  reflect.Value) *structTableModel {
	return &structTableModel{
		db:    ,
		table: .Table(.Type()),
		dest:  ,
		root:  ,
		strct: ,
	}
}

func ( *structTableModel) () interface{} {
	return .dest
}

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

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

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.Value) {
	.strct = .FieldByIndex(.rel.Field.Index)
	.structInited = false
}

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

	switch .strct.Kind() {
	case reflect.Invalid:
		.structInitErr = errNilModel
		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 .Relation.Type {
		case schema.HasOneRelation, schema.BelongsToRelation:
			.JoinModel.Mount(.strct)
		}
	}
}

var _ schema.BeforeScanHook = (*structTableModel)(nil)

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

var _ schema.AfterScanHook = (*structTableModel)(nil)

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

	var  error

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

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

	return 
}

func ( *structTableModel) ( string) *relationJoin {
	for  := range .joins {
		 := &.joins[]
		if .Relation.Field.Name ==  || .Relation.Field.GoName ==  {
			return 
		}
	}
	return nil
}

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

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

func ( *structTableModel) ( string) *relationJoin {
	return .join(.strct, )
}

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

	 := relationJoin{
		BaseModel: ,
		JoinModel: ,
	}
	var  *relationJoin

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

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

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

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

			.Parent = 
			.BaseModel = .JoinModel
			.JoinModel = 

			 = .BaseModel.AddJoin()
		}
	}

	return 
}

func ( *structTableModel) ( time.Time) error {
	if !.strct.IsValid() {
		return nil
	}
	 := .table.SoftDeleteField.Value(.strct)
	return .table.UpdateSoftDeleteField(, )
}

func ( *structTableModel) ( context.Context,  *sql.Rows) (int, error) {
	if !.Next() {
		return 0, .Err()
	}

	var  int

	if  := .ScanRow(, );  != nil {
		return 0, 
	}
	++

	// And discard the rest. This is especially important for SQLite3, which can return
	// a row like it was inserted sucessfully and then return an actual error for the next row.
	// See issues/100.
	for .Next() {
		++
	}
	if  := .Err();  != nil {
		return 0, 
	}

	return , nil
}

func ( *structTableModel) ( context.Context,  *sql.Rows) error {
	,  := .Columns()
	if  != nil {
		return 
	}

	.columns = 
	 := makeDest(, len())

	return .scanRow(, , )
}

func ( *structTableModel) ( context.Context,  *sql.Rows,  []interface{}) error {
	if  := .BeforeScan();  != nil {
		return 
	}

	.scanIndex = 0
	if  := .Scan(...);  != nil {
		return 
	}

	if  := .AfterScan();  != nil {
		return 
	}

	return nil
}

func ( *structTableModel) ( interface{}) error {
	 := .columns[.scanIndex]
	.scanIndex++

	return .ScanColumn(unquote(), )
}

func ( *structTableModel) ( string,  interface{}) error {
	if ,  := .scanColumn(, );  {
		return 
	}
	if  == "" || [0] == '_' || .db.flags.Has(discardUnknownColumns) {
		return nil
	}
	return fmt.Errorf("bun: %s does not have column %q", .table.TypeName, )
}

func ( *structTableModel) ( string,  interface{}) (bool, error) {
	if  != nil {
		if  := .initStruct();  != nil {
			return true, 
		}
	}

	if ,  := .table.FieldMap[];  {
		if  == nil && .isNil() {
			return true, nil
		}
		return true, .ScanValue(.strct, )
	}

	if ,  := splitColumn();  != "" {
		if  := .GetJoin();  != nil {
			return true, .JoinModel.ScanColumn(, )
		}

		if .table.ModelName ==  {
			return true, .ScanColumn(, )
		}
	}

	return false, nil
}

func ( *structTableModel) () bool {
	return .strct.Kind() == reflect.Ptr && .strct.IsNil()
}

func ( *structTableModel) (
	 schema.Formatter,  []byte,  string,
) ([]byte, bool) {
	return .table.AppendNamedArg(, , , .strct)
}

// sqlite3 sometimes does not unquote columns.
func ( string) string {
	if  == "" {
		return 
	}
	if [0] == '"' && [len()-1] == '"' {
		return [1 : len()-1]
	}
	return 
}

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