stardb/scan_each_orm.go

120 lines
3.8 KiB
Go
Raw Permalink Normal View History

package stardb
import (
"context"
"reflect"
)
// ScanEachORMFunc is called for each mapped struct in streaming ORM mode.
type ScanEachORMFunc func(target interface{}) error
// ScanEachORM streams query rows and maps each row to target before invoking fn.
// target must be a pointer to struct; it is reused for each row.
func (s *StarDB) ScanEachORM(query string, target interface{}, fn ScanEachORMFunc, args ...interface{}) error {
return s.ScanEachORMContext(nil, query, target, fn, args...)
}
// ScanEachORMContext streams query rows with context and maps each row to target before invoking fn.
// target must be a pointer to struct; it is reused for each row.
func (s *StarDB) ScanEachORMContext(ctx context.Context, query string, target interface{}, fn ScanEachORMFunc, args ...interface{}) error {
if fn == nil {
return ErrScanORMFuncNil
}
if err := validateScanORMTarget(target); err != nil {
return err
}
return s.ScanEachContext(ctx, query, func(row *StarResult) error {
if err := mapResultToStructTarget(row, target, s); err != nil {
return err
}
return fn(target)
}, args...)
}
// ScanEachORM streams transaction rows and maps each row to target before invoking fn.
// target must be a pointer to struct; it is reused for each row.
func (t *StarTx) ScanEachORM(query string, target interface{}, fn ScanEachORMFunc, args ...interface{}) error {
return t.ScanEachORMContext(nil, query, target, fn, args...)
}
// ScanEachORMContext streams transaction rows with context and maps each row to target before invoking fn.
// target must be a pointer to struct; it is reused for each row.
func (t *StarTx) ScanEachORMContext(ctx context.Context, query string, target interface{}, fn ScanEachORMFunc, args ...interface{}) error {
if fn == nil {
return ErrScanORMFuncNil
}
if err := validateScanORMTarget(target); err != nil {
return err
}
return t.ScanEachContext(ctx, query, func(row *StarResult) error {
if err := mapResultToStructTarget(row, target, t.db); err != nil {
return err
}
return fn(target)
}, args...)
}
// ScanEachORM streams prepared statement rows and maps each row to target before invoking fn.
// target must be a pointer to struct; it is reused for each row.
func (s *StarStmt) ScanEachORM(target interface{}, fn ScanEachORMFunc, args ...interface{}) error {
return s.ScanEachORMContext(nil, target, fn, args...)
}
// ScanEachORMContext streams prepared statement rows with context and maps each row to target before invoking fn.
// target must be a pointer to struct; it is reused for each row.
func (s *StarStmt) ScanEachORMContext(ctx context.Context, target interface{}, fn ScanEachORMFunc, args ...interface{}) error {
if fn == nil {
return ErrScanORMFuncNil
}
if err := validateScanORMTarget(target); err != nil {
return err
}
return s.ScanEachContext(ctx, func(row *StarResult) error {
if err := mapResultToStructTarget(row, target, s.db); err != nil {
return err
}
return fn(target)
}, args...)
}
func validateScanORMTarget(target interface{}) error {
if target == nil {
return ErrTargetNil
}
targetType := reflect.TypeOf(target)
targetValue := reflect.ValueOf(target)
if targetType.Kind() != reflect.Ptr {
return ErrTargetNotPointer
}
if targetValue.IsNil() {
return ErrTargetPointerNil
}
if targetValue.Elem().Kind() != reflect.Struct {
return ErrTargetNotStruct
}
return nil
}
func mapResultToStructTarget(row *StarResult, target interface{}, db *StarDB) error {
targetValue := reflect.ValueOf(target)
targetValue.Elem().Set(reflect.Zero(targetValue.Elem().Type()))
rowWrapper := &StarRows{
db: db,
length: 1,
columns: row.columns,
columnsType: row.columnsType,
columnIndex: row.columnIndex,
data: [][]interface{}{row.result},
parsed: true,
}
return rowWrapper.setStructFieldsFromRow(target, "db", 0)
}