model_table_slice.go 4.1 KB
package orm

import (
	"context"
	"reflect"
	"time"

	"github.com/go-pg/pg/types"
)

type sliceTableModel struct {
	structTableModel

	slice      reflect.Value
	sliceLen   int
	sliceOfPtr bool
}

var _ TableModel = (*sliceTableModel)(nil)

func newSliceTableModel(slice reflect.Value, elemType reflect.Type) *sliceTableModel {
	m := &sliceTableModel{
		structTableModel: structTableModel{
			table: GetTable(elemType),
			root:  slice,
		},
		slice:    slice,
		sliceLen: slice.Len(),
	}
	m.init(slice.Type())
	return m
}

func (m *sliceTableModel) init(sliceType reflect.Type) {
	switch sliceType.Elem().Kind() {
	case reflect.Ptr, reflect.Interface:
		m.sliceOfPtr = true
	}
}

func (*sliceTableModel) useQueryOne() {}

func (m *sliceTableModel) IsNil() bool {
	return false
}

func (m *sliceTableModel) AppendParam(b []byte, f QueryFormatter, name string) ([]byte, bool) {
	if field, ok := m.table.FieldsMap[name]; ok {
		b = append(b, "_data."...)
		b = append(b, field.Column...)
		return b, true
	}
	return m.structTableModel.AppendParam(b, f, name)
}

func (m *sliceTableModel) Join(name string, apply func(*Query) (*Query, error)) *join {
	return m.join(m.Value(), name, apply)
}

func (m *sliceTableModel) Bind(bind reflect.Value) {
	m.slice = bind.Field(m.index[len(m.index)-1])
}

func (m *sliceTableModel) Kind() reflect.Kind {
	return reflect.Slice
}

func (m *sliceTableModel) Value() reflect.Value {
	return m.slice
}

func (m *sliceTableModel) Init() error {
	if m.slice.IsValid() && m.slice.Len() > 0 {
		m.slice.Set(m.slice.Slice(0, 0))
	}
	return nil
}

func (m *sliceTableModel) NewModel() ColumnScanner {
	m.strct = m.nextElem()
	m.structInited = false
	return m
}

func (m *sliceTableModel) AfterQuery(c context.Context, db DB) error {
	if m.table.HasFlag(AfterQueryHookFlag) {
		return callAfterQueryHookSlice(m.slice, m.sliceOfPtr, c, db)
	}
	return nil
}

func (m *sliceTableModel) AfterSelect(c context.Context, db DB) error {
	if m.table.HasFlag(AfterSelectHookFlag) {
		return callAfterSelectHookSlice(m.slice, m.sliceOfPtr, c, db)
	}
	return nil
}

func (m *sliceTableModel) BeforeInsert(c context.Context, db DB) error {
	if m.table.HasFlag(BeforeInsertHookFlag) {
		return callBeforeInsertHookSlice(m.slice, m.sliceOfPtr, c, db)
	}
	return nil
}

func (m *sliceTableModel) AfterInsert(c context.Context, db DB) error {
	if m.table.HasFlag(AfterInsertHookFlag) {
		return callAfterInsertHookSlice(m.slice, m.sliceOfPtr, c, db)
	}
	return nil
}

func (m *sliceTableModel) BeforeUpdate(c context.Context, db DB) error {
	if m.table.HasFlag(BeforeUpdateHookFlag) {
		return callBeforeUpdateHookSlice(m.slice, m.sliceOfPtr, c, db)
	}
	return nil
}

func (m *sliceTableModel) AfterUpdate(c context.Context, db DB) error {
	if m.table.HasFlag(AfterUpdateHookFlag) {
		return callAfterUpdateHookSlice(m.slice, m.sliceOfPtr, c, db)
	}
	return nil
}

func (m *sliceTableModel) BeforeDelete(c context.Context, db DB) error {
	if m.table.HasFlag(BeforeDeleteHookFlag) {
		return callBeforeDeleteHookSlice(m.slice, m.sliceOfPtr, c, db)
	}
	return nil
}

func (m *sliceTableModel) AfterDelete(c context.Context, db DB) error {
	if m.table.HasFlag(AfterDeleteHookFlag) {
		return callAfterDeleteHookSlice(m.slice, m.sliceOfPtr, c, db)
	}
	return nil
}

func (m *sliceTableModel) nextElem() reflect.Value {
	if m.slice.Len() < m.slice.Cap() {
		m.slice.Set(m.slice.Slice(0, m.slice.Len()+1))
		elem := m.slice.Index(m.slice.Len() - 1)
		if m.sliceOfPtr {
			if elem.IsNil() {
				elem.Set(reflect.New(elem.Type().Elem()))
			}
			return elem.Elem()
		}
		return elem
	}

	if m.sliceOfPtr {
		elem := reflect.New(m.table.Type)
		m.slice.Set(reflect.Append(m.slice, elem))
		return elem.Elem()
	}

	m.slice.Set(reflect.Append(m.slice, m.table.zeroStruct))
	return m.slice.Index(m.slice.Len() - 1)
}

func (m *sliceTableModel) setSoftDeleteField() {
	field := m.table.SoftDeleteField
	now := time.Now()
	var value reflect.Value
	if m.sliceOfPtr {
		value = reflect.ValueOf(&now)
	} else if field.Type == timeType {
		value = reflect.ValueOf(now)
	} else {
		value = reflect.ValueOf(types.NullTime{Time: now})
	}

	for i := 0; i < m.slice.Len(); i++ {
		strct := indirect(m.slice.Index(i))
		field.Value(strct).Set(value)
	}
}