diff options
Diffstat (limited to 'select.go')
| -rw-r--r-- | select.go | 41 |
1 files changed, 21 insertions, 20 deletions
@@ -4,6 +4,7 @@ package oblast import ( + "context" "database/sql" "errors" "fmt" @@ -14,11 +15,11 @@ import ( // according to the column names reported by the database as part of the result set. // // An error is returned if any column name in the result set does not correspond to an addressable field in R. -func (s Store[R]) Select(db Handle, query string, args ...any) ([]R, error) { +func (s Store[R]) Select(ctx context.Context, db Handle, query string, args ...any) ([]R, error) { // NOTE: This function body should be as short as possible to reduce the binary size after monomorphization. // Any expression that does not depend on type R should be factored out into a reusable function. - rows, indexes, err := startSelectQuery(db, s.plan, query, args...) + rows, indexes, err := startSelectQuery(ctx, db, s.plan, query, args...) if err != nil { return nil, err } @@ -50,11 +51,11 @@ func (s Store[R]) Select(db Handle, query string, args ...any) ([]R, error) { // Besides a condition for the WHERE clause, it may contain additional clauses, such as ORDER BY or LIMIT. // // Returns an error if [NewStore] was called without the [TableNameIs] option, which is required to generate a query for this method. -func (s Store[R]) SelectWhere(db Handle, partialQuery string, args ...any) ([]R, error) { +func (s Store[R]) SelectWhere(ctx context.Context, db Handle, partialQuery string, args ...any) ([]R, error) { // NOTE: This function body should be as short as possible to reduce the binary size after monomorphization. // Any expression that does not depend on type R should be factored out into a reusable function. - rows, indexes, err := startSelectWhereQuery(db, s.plan, partialQuery, args...) + rows, indexes, err := startSelectWhereQuery(ctx, db, s.plan, partialQuery, args...) if err != nil { return nil, err } @@ -73,8 +74,8 @@ func (s Store[R]) SelectWhere(db Handle, partialQuery string, args ...any) ([]R, return result, newIOError(err, "Rows.Err", rows.Err()) } -func startSelectQuery(db Handle, plan plan, query string, args ...any) (*sql.Rows, [][]int, error) { - rows, err := db.Query(query, args...) +func startSelectQuery(ctx context.Context, db Handle, plan plan, query string, args ...any) (*sql.Rows, [][]int, error) { + rows, err := db.QueryContext(ctx, query, args...) if err != nil { return nil, nil, fmt.Errorf("during Query(): %w", err) } @@ -100,12 +101,12 @@ func startSelectQuery(db Handle, plan plan, query string, args ...any) (*sql.Row return rows, indexes, nil } -func startSelectWhereQuery(db Handle, plan plan, partialQuery string, args ...any) (rows *sql.Rows, indexes [][]int, err error) { +func startSelectWhereQuery(ctx context.Context, db Handle, plan plan, partialQuery string, args ...any) (rows *sql.Rows, indexes [][]int, err error) { if plan.Select.Query == "" { return nil, nil, errors.New("cannot execute SelectWhere() because query could not be autogenerated") } query := plan.Select.Query + partialQuery - rows, err = db.Query(query, args...) + rows, err = db.QueryContext(ctx, query, args...) if err != nil { err = fmt.Errorf("during Query(): %w", err) } @@ -134,12 +135,12 @@ func collectRow(rows *sql.Rows, plan plan, v reflect.Value, slots []any, indexes // // Warning: Because of limitations in the interface of database/sql, this function is built on [Store.Select] and cannot be any faster than it. // For maximum performance, use [Store.SelectOneWhere] which avoids the overhead of potentially having to read multiple rows. -func (s Store[R]) SelectOne(db Handle, query string, args ...any) (result R, err error) { +func (s Store[R]) SelectOne(ctx context.Context, db Handle, query string, args ...any) (result R, err error) { // NOTE: This function body should be as short as possible to reduce the binary size after monomorphization. // Any expression that does not depend on type R should be factored out into a reusable function. var results []R - results, err = s.Select(db, query, args...) + results, err = s.Select(ctx, db, query, args...) if err == nil { if len(results) == 0 { err = sql.ErrNoRows @@ -155,23 +156,23 @@ func (s Store[R]) SelectOne(db Handle, query string, args ...any) (result R, err // // This method is more efficient than [Store.SelectOne] on CPU runtime, but has a slight memory allocation overhead per call from query preparation. // This can be avoided by using [Store.PrepareSelectQueryWhere] instead. -func (s Store[R]) SelectOneWhere(db Handle, partialQuery string, args ...any) (result R, err error) { +func (s Store[R]) SelectOneWhere(ctx context.Context, db Handle, partialQuery string, args ...any) (result R, err error) { // NOTE: This function body should be as short as possible to reduce the binary size after monomorphization. // Any expression that does not depend on type R should be factored out into a reusable function. - err = selectOneWhere(db, s.plan, reflect.ValueOf(&result).Elem(), partialQuery, args) + err = selectOneWhere(ctx, db, s.plan, reflect.ValueOf(&result).Elem(), partialQuery, args) return } -func selectOneWhere(db Handle, plan plan, v reflect.Value, partialQuery string, args []any) error { +func selectOneWhere(ctx context.Context, db Handle, plan plan, v reflect.Value, partialQuery string, args []any) error { if plan.Select.Query == "" { return errors.New("cannot execute SelectOneWhere() because query could not be autogenerated") } query := plan.Select.Query + partialQuery - return selectOne(db, plan, v, query, args) + return selectOne(ctx, db, plan, v, query, args) } -func selectOne(db Handle, plan plan, v reflect.Value, query string, args []any) error { +func selectOne(ctx context.Context, db Handle, plan plan, v reflect.Value, query string, args []any) error { for _, index := range plan.IndexesOfTransparentPointerStructs { f := v.FieldByIndex(index) f.Set(reflect.New(f.Type().Elem())) @@ -180,7 +181,7 @@ func selectOne(db Handle, plan plan, v reflect.Value, query string, args []any) for idx, index := range plan.Select.ScanIndexes { slots[idx] = v.FieldByIndex(index).Addr().Interface() } - return db.QueryRow(query, args...).Scan(slots...) + return db.QueryRowContext(ctx, query, args...).Scan(slots...) } // PrepareSelectQueryWhere performs the same query string preparation as [Store.SelectWhere] or [Store.SelectOneWhere]. @@ -219,11 +220,11 @@ type PreparedSelectQuery[R any] struct { } // Select behaves the same as [Store.SelectWhere], but uses the query that was precomputed when q was constructed. -func (q PreparedSelectQuery[R]) Select(db Handle, args ...any) ([]R, error) { +func (q PreparedSelectQuery[R]) Select(ctx context.Context, db Handle, args ...any) ([]R, error) { // NOTE: This function body should be as short as possible to reduce the binary size after monomorphization. // Any expression that does not depend on type R should be factored out into a reusable function. - rows, indexes, err := startSelectQuery(db, q.store.plan, q.query, args...) + rows, indexes, err := startSelectQuery(ctx, db, q.store.plan, q.query, args...) if err != nil { return nil, err } @@ -243,10 +244,10 @@ func (q PreparedSelectQuery[R]) Select(db Handle, args ...any) ([]R, error) { } // SelectOne behaves the same as [Store.SelectOneWhere], but uses the query that was precomputed when q was constructed. -func (q PreparedSelectQuery[R]) SelectOne(db Handle, args ...any) (result R, err error) { +func (q PreparedSelectQuery[R]) SelectOne(ctx context.Context, db Handle, args ...any) (result R, err error) { // NOTE: This function body should be as short as possible to reduce the binary size after monomorphization. // Any expression that does not depend on type R should be factored out into a reusable function. - err = selectOne(db, q.store.plan, reflect.ValueOf(&result).Elem(), q.query, args) + err = selectOne(ctx, db, q.store.plan, reflect.ValueOf(&result).Elem(), q.query, args) return } |
