model_table_slice.go (2546B)
1 package bun 2 3 import ( 4 "context" 5 "database/sql" 6 "reflect" 7 "time" 8 9 "github.com/uptrace/bun/internal" 10 "github.com/uptrace/bun/schema" 11 ) 12 13 type sliceTableModel struct { 14 structTableModel 15 16 slice reflect.Value 17 sliceLen int 18 sliceOfPtr bool 19 nextElem func() reflect.Value 20 } 21 22 var _ TableModel = (*sliceTableModel)(nil) 23 24 func newSliceTableModel( 25 db *DB, dest interface{}, slice reflect.Value, elemType reflect.Type, 26 ) *sliceTableModel { 27 m := &sliceTableModel{ 28 structTableModel: structTableModel{ 29 db: db, 30 table: db.Table(elemType), 31 dest: dest, 32 root: slice, 33 }, 34 35 slice: slice, 36 sliceLen: slice.Len(), 37 nextElem: internal.MakeSliceNextElemFunc(slice), 38 } 39 m.init(slice.Type()) 40 return m 41 } 42 43 func (m *sliceTableModel) init(sliceType reflect.Type) { 44 switch sliceType.Elem().Kind() { 45 case reflect.Ptr, reflect.Interface: 46 m.sliceOfPtr = true 47 } 48 } 49 50 func (m *sliceTableModel) join(name string) *relationJoin { 51 return m._join(m.slice, name) 52 } 53 54 func (m *sliceTableModel) ScanRows(ctx context.Context, rows *sql.Rows) (int, error) { 55 columns, err := rows.Columns() 56 if err != nil { 57 return 0, err 58 } 59 60 m.columns = columns 61 dest := makeDest(m, len(columns)) 62 63 if m.slice.IsValid() && m.slice.Len() > 0 { 64 m.slice.Set(m.slice.Slice(0, 0)) 65 } 66 67 var n int 68 69 for rows.Next() { 70 m.strct = m.nextElem() 71 if m.sliceOfPtr { 72 m.strct = m.strct.Elem() 73 } 74 m.structInited = false 75 76 if err := m.scanRow(ctx, rows, dest); err != nil { 77 return 0, err 78 } 79 80 n++ 81 } 82 if err := rows.Err(); err != nil { 83 return 0, err 84 } 85 86 return n, nil 87 } 88 89 var _ schema.BeforeAppendModelHook = (*sliceTableModel)(nil) 90 91 func (m *sliceTableModel) BeforeAppendModel(ctx context.Context, query Query) error { 92 if !m.table.HasBeforeAppendModelHook() || !m.slice.IsValid() { 93 return nil 94 } 95 96 sliceLen := m.slice.Len() 97 for i := 0; i < sliceLen; i++ { 98 strct := m.slice.Index(i) 99 if !m.sliceOfPtr { 100 strct = strct.Addr() 101 } 102 err := strct.Interface().(schema.BeforeAppendModelHook).BeforeAppendModel(ctx, query) 103 if err != nil { 104 return err 105 } 106 } 107 return nil 108 } 109 110 // Inherit these hooks from structTableModel. 111 var ( 112 _ schema.BeforeScanRowHook = (*sliceTableModel)(nil) 113 _ schema.AfterScanRowHook = (*sliceTableModel)(nil) 114 ) 115 116 func (m *sliceTableModel) updateSoftDeleteField(tm time.Time) error { 117 sliceLen := m.slice.Len() 118 for i := 0; i < sliceLen; i++ { 119 strct := indirect(m.slice.Index(i)) 120 fv := m.table.SoftDeleteField.Value(strct) 121 if err := m.table.UpdateSoftDeleteField(fv, tm); err != nil { 122 return err 123 } 124 } 125 return nil 126 }