gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

model_table_m2m.go (2693B)


      1 package bun
      2 
      3 import (
      4 	"context"
      5 	"database/sql"
      6 	"fmt"
      7 	"reflect"
      8 
      9 	"github.com/uptrace/bun/internal"
     10 	"github.com/uptrace/bun/schema"
     11 )
     12 
     13 type m2mModel struct {
     14 	*sliceTableModel
     15 	baseTable *schema.Table
     16 	rel       *schema.Relation
     17 
     18 	baseValues map[internal.MapKey][]reflect.Value
     19 	structKey  []interface{}
     20 }
     21 
     22 var _ TableModel = (*m2mModel)(nil)
     23 
     24 func newM2MModel(j *relationJoin) *m2mModel {
     25 	baseTable := j.BaseModel.Table()
     26 	joinModel := j.JoinModel.(*sliceTableModel)
     27 	baseValues := baseValues(joinModel, baseTable.PKs)
     28 	if len(baseValues) == 0 {
     29 		return nil
     30 	}
     31 	m := &m2mModel{
     32 		sliceTableModel: joinModel,
     33 		baseTable:       baseTable,
     34 		rel:             j.Relation,
     35 
     36 		baseValues: baseValues,
     37 	}
     38 	if !m.sliceOfPtr {
     39 		m.strct = reflect.New(m.table.Type).Elem()
     40 	}
     41 	return m
     42 }
     43 
     44 func (m *m2mModel) ScanRows(ctx context.Context, rows *sql.Rows) (int, error) {
     45 	columns, err := rows.Columns()
     46 	if err != nil {
     47 		return 0, err
     48 	}
     49 
     50 	m.columns = columns
     51 	dest := makeDest(m, len(columns))
     52 
     53 	var n int
     54 
     55 	for rows.Next() {
     56 		if m.sliceOfPtr {
     57 			m.strct = reflect.New(m.table.Type).Elem()
     58 		} else {
     59 			m.strct.Set(m.table.ZeroValue)
     60 		}
     61 		m.structInited = false
     62 
     63 		m.scanIndex = 0
     64 		m.structKey = m.structKey[:0]
     65 		if err := rows.Scan(dest...); err != nil {
     66 			return 0, err
     67 		}
     68 
     69 		if err := m.parkStruct(); err != nil {
     70 			return 0, err
     71 		}
     72 
     73 		n++
     74 	}
     75 	if err := rows.Err(); err != nil {
     76 		return 0, err
     77 	}
     78 
     79 	return n, nil
     80 }
     81 
     82 func (m *m2mModel) Scan(src interface{}) error {
     83 	column := m.columns[m.scanIndex]
     84 	m.scanIndex++
     85 
     86 	field, ok := m.table.FieldMap[column]
     87 	if !ok {
     88 		return m.scanM2MColumn(column, src)
     89 	}
     90 
     91 	if err := field.ScanValue(m.strct, src); err != nil {
     92 		return err
     93 	}
     94 
     95 	for _, fk := range m.rel.M2MBaseFields {
     96 		if fk.Name == field.Name {
     97 			m.structKey = append(m.structKey, field.Value(m.strct).Interface())
     98 			break
     99 		}
    100 	}
    101 
    102 	return nil
    103 }
    104 
    105 func (m *m2mModel) scanM2MColumn(column string, src interface{}) error {
    106 	for _, field := range m.rel.M2MBaseFields {
    107 		if field.Name == column {
    108 			dest := reflect.New(field.IndirectType).Elem()
    109 			if err := field.Scan(dest, src); err != nil {
    110 				return err
    111 			}
    112 			m.structKey = append(m.structKey, dest.Interface())
    113 			break
    114 		}
    115 	}
    116 
    117 	_, err := m.scanColumn(column, src)
    118 	return err
    119 }
    120 
    121 func (m *m2mModel) parkStruct() error {
    122 	baseValues, ok := m.baseValues[internal.NewMapKey(m.structKey)]
    123 	if !ok {
    124 		return fmt.Errorf(
    125 			"bun: m2m relation=%s does not have base %s with key=%q (check join conditions)",
    126 			m.rel.Field.GoName, m.baseTable, m.structKey)
    127 	}
    128 
    129 	for _, v := range baseValues {
    130 		if m.sliceOfPtr {
    131 			v.Set(reflect.Append(v, m.strct.Addr()))
    132 		} else {
    133 			v.Set(reflect.Append(v, m.strct))
    134 		}
    135 	}
    136 
    137 	return nil
    138 }