MCPcopy Create free account
hub / github.com/chain/Core / ForQueryRows

Function ForQueryRows

database/pg/query.go:50–105  ·  view source on GitHub ↗

ForQueryRows encapsulates a lot of boilerplate when making db queries. Call it like this: err = ForQueryRows(ctx, db, query, queryArg1, queryArg2, ..., func(scanVar1 type1, scanVar2 type2, ...) { ...process a row from the result... }) This is equivalent to: rows, err = db.Query(ctx, query, queryA

(ctx context.Context, db DB, query string, args ...interface{})

Source from the content-addressed store, hash-verified

48// single error-type value. If any invocation yields a non-nil
49// result, ForQueryRows will abort and return it.
50func ForQueryRows(ctx context.Context, db DB, query string, args ...interface{}) error {
51 if len(args) == 0 {
52 return errors.Wrap(ErrBadRequest, "too few arguments")
53 }
54
55 fnArg := args[len(args)-1]
56 queryArgs := args[:len(args)-1]
57
58 fnType := reflect.TypeOf(fnArg)
59 if fnType.Kind() != reflect.Func {
60 return errors.Wrap(ErrBadRequest, "fn arg not a function")
61 }
62 if fnType.NumOut() > 1 {
63 return errors.Wrap(ErrBadRequest, "fn arg must return 0 values or 1")
64 }
65 if fnType.NumOut() == 1 && !fnType.Out(0).Implements(errorInterface) {
66 return errors.Wrap(ErrBadRequest, "fn arg return type must be error")
67 }
68
69 rows, err := db.Query(ctx, query, queryArgs...)
70 if err != nil {
71 return errors.Wrap(err, "query")
72 }
73 defer rows.Close()
74
75 fnVal := reflect.ValueOf(fnArg)
76
77 argPtrVals := make([]reflect.Value, 0, fnType.NumIn())
78 scanArgs := make([]interface{}, 0, fnType.NumIn())
79 fnArgs := make([]reflect.Value, 0, fnType.NumIn())
80
81 for rows.Next() {
82 argPtrVals = argPtrVals[:0]
83 scanArgs = scanArgs[:0]
84 fnArgs = fnArgs[:0]
85 for i := 0; i < fnType.NumIn(); i++ {
86 argType := fnType.In(i)
87 argPtrVal := reflect.New(argType)
88 argPtrVals = append(argPtrVals, argPtrVal)
89 scanArgs = append(scanArgs, argPtrVal.Interface())
90 }
91 err = rows.Scan(scanArgs...)
92 if err != nil {
93 return errors.Wrap(err, "scan")
94 }
95 for _, argPtrVal := range argPtrVals {
96 fnArgs = append(fnArgs, argPtrVal.Elem())
97 }
98 res := fnVal.Call(fnArgs)
99 if fnType.NumOut() == 1 && !res[0].IsNil() {
100 return errors.Wrap(res[0].Interface().(error), "callback")
101 }
102 }
103
104 return errors.Wrap(rows.Err(), "end scan")
105}

Callers

nothing calls this directly

Calls 6

NextMethod · 0.80
CallMethod · 0.80
QueryMethod · 0.65
CloseMethod · 0.45
ScanMethod · 0.45
ErrMethod · 0.45

Tested by

no test coverage detected