120 lines
3.8 KiB
Go
120 lines
3.8 KiB
Go
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)
|
|
}
|