bob

package module
v0.0.0-...-b4a328d Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 17, 2025 License: MIT Imports: 14 Imported by: 0

README

Bob: Go SQL Access Toolkit

Test Status GitHub go.mod Go version Go Reference Go Report Card GitHub tag (latest SemVer) Coverage Status

About

Bob is a set of Go packages and tools to work with SQL databases.

Bob's philosophy centres around the following:

  1. Correctness: Things should work correctly. Follow specifications as closely as possible.
  2. Convenience (not magic): Bob provides convenient ways to perform actions, it does not add unexplainable magic, or needless abstraction.
  3. Cooperation: Bob should work well with other tools and packages as much as possible, especially the standard library.

Bob can be progressively adopted from raw SQL query strings, to fully typed queries with models and factories generated for your database.

Components of Bob

Bob consists of several components that build on each other for the full experience.

  1. Query Builder
  2. SQL Executor for convenient scanning of results
  3. Models for convenient database queries
  4. Code generation of Models and Factories from your database schema
  5. Code generation of Queries similar to sqlc.

Check out the documentation for more information.

Support

Queries Models ORM Gen Factory Gen Query Gen
Postgres
MySQL/MariaDB
SQLite

Comparisons

  1. Bob vs GORM
  2. Bob vs Ent
  3. Bob vs SQLBoiler
  4. Bob vs Jet

The layers of Bob

Layer 1: The query builder - Similar to squirrel

This is just a fluent query builder that has no concept of your DB, and by extension cannot offer any type-safety.

The main reason, I consider it better than most alternatives is that since each dialect is hand-crafted, it can support building ANY query for that dialect.

However, each dialect is also independent, so you don't have to worry about creating an invalid query.

IMPORTANT: Queries are built using "Query Mods"

psql.Select(
    sm.From("users"), // This is a query mod
    sm.Where(psql.Quote("age").GTE(psql.Arg(21))), // This is also a mod
)
Layer 2: ORM Code Generation - Similar to SQLBoiler

This is where the type safety comes.

A full ORM, and query mods that is based on the database schema. If you use the generated query mods, these will ensure correct type safety.

Here is the above query using generated query-mods.

models.Users.Query(
    models.SelectWhere.Users.Age.GTE(21), // This is type-safe
)
Layer 3: Factory Code Generation - Inspired by Ruby's FactoryBot

Factories make testing much much easier. Especially when the test depends on a database entry that depends on relations in other tables (e.g. testing comments that rely on posts which in turn rely on users).

With knowledge of the database schema, Bob can generate factories for each table.

// Quickly create a 10 comments (posts and users are created appropriately)
comments, err := f.NewComment().CreateMany(ctx, db, 10)
Layer 4: Generating code for SQL Queries - similar to sqlc

I believe this is the final peice of the puzzle, and extends the type-safety to hand-crafted SQL queries.

For example, you could generate code for the query:

-- UserPosts
SELECT * FROM posts WHERE user_id = $1

This will generate a function UserPosts that takes an int32.

// UserPosts
userPosts, err := queries.UserPosts(1).All(ctx, db)

Then, if you need to, you can add an extra filter to get only published posts.

However whether it is type safe or not depends on if you use the generated mods or not:

// Get only published posts
query := psql.Select(
    UserPosts(1),
    models.PostWhere.Status.EQ("published"), // type-safe
    sm.Where(psql.Quote("posts", "status").Eq(psql.Arg("published"))), // not type-safe
)

Development

Nix

You can get all the tools you need for developing against this repository with nix. Use nix-shell in the root of the repository to get a shell with all the dependencies and tools for development.

Lint

This repository uses golangci-lint for linting. You can run the linter with:

$ golangci-lint run

Before submitting pull requests you should ensure that your changes lint clean:

$ golangci-lint run
0 issues.
Formatting

This repository uses gofumpt for formatting. It's more strict than go fmt. The linter will fail if you haven't formatted for code correctly. You can format your code with:

$ gofumpt -l -w ./some/file
Test

You can test this repository using go test. A simple test of a single module can be run with:

$ go test ./dialect/psql/

A comprehensive test of all modules could be done with:

$ go test ./...

If you're interested in data race detection and coverage, both of which are done by the Github workflow prior to merging code, you'll need to add a few more arguments:

$ go test -race -covermode atomic --coverprofile=covprofile.out -coverpkg=github.com/templatedop/bob/... ./...
Workflows

The project uses Github Actions as defined in .github/workflows. Pull requests are expected to pass linting and testing workflows before being accepted.

Contributing

Thanks to all the people who have contributed to Bob!

contributors

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrBadArgType       = errors.New("bind type of multiple named args must be a struct, pointer to struct or map with ~string keys")
	ErrTooManyNamedArgs = errors.New("too many named args for single arg binder")
)
View Source
var ErrHookableTypeMismatch = errors.New("hookable type mismatch: the slice type is not hookable, but the single type is")
View Source
var ErrNoNamedArgs = errors.New("Dialect does not support named arguments")

Functions

func All

func All[T any](ctx context.Context, exec Executor, q Query, m scan.Mapper[T]) ([]T, error)

func Allx

func Allx[Tr Transformer[T, V], T, V any](ctx context.Context, exec Executor, q Query, m scan.Mapper[T]) (V, error)

Allx in addition to the scan.Mapper, Allx takes a Transformer that will transform the scanned slice into a different type. For common use cases, you can use SliceTransformer to transform a scanned slice of type T into a custom slice type like ~[]T.

func Build

func Build(ctx context.Context, q Query) (string, []any, error)

Convinient function to build query from start

func BuildN

func BuildN(ctx context.Context, q Query, start int) (string, []any, error)

Convinient function to build query from a point

func Cursor

func Cursor[T any](ctx context.Context, exec Executor, q Query, m scan.Mapper[T]) (scan.ICursor[T], error)

Cursor returns a cursor that works similar to *sql.Rows

func Exec

func Exec(ctx context.Context, exec Executor, q Query) (sql.Result, error)

func Express

func Express(ctx context.Context, w io.Writer, d Dialect, start int, e any) ([]any, error)

func ExpressIf

func ExpressIf(ctx context.Context, w io.Writer, d Dialect, start int, e any, cond bool, prefix, suffix string) ([]any, error)

ExpressIf expands an express if the condition evaluates to true it can also add a prefix and suffix

func ExpressSlice

func ExpressSlice[T any](ctx context.Context, w io.Writer, d Dialect, start int, expressions []T, prefix, sep, suffix string) ([]any, error)

ExpressSlice is used to express a slice of expressions along with a prefix and suffix

func MustBuild

func MustBuild(ctx context.Context, q Query) (string, []any)

MustBuild builds a query and panics on error useful for initializing queries that need to be reused

func MustBuildN

func MustBuildN(ctx context.Context, q Query, start int) (string, []any)

func One

func One[T any](ctx context.Context, exec Executor, q Query, m scan.Mapper[T]) (T, error)

func SkipHooks

func SkipHooks(ctx context.Context) context.Context

SkipHooks modifies a context to prevent hooks from running for any query it encounters.

func SkipModelHooks

func SkipModelHooks(ctx context.Context) context.Context

SkipModelHooks modifies a context to prevent hooks from running on models.

func SkipQueryHooks

func SkipQueryHooks(ctx context.Context) context.Context

SkipQueryHooks modifies a context to prevent hooks from running on querys.

Types

type BaseQuery

type BaseQuery[E Expression] struct {
	Expression E
	Dialect    Dialect
	QueryType  QueryType
}

BaseQuery wraps common functionality such as cloning, applying new mods and the actual query interface implementation

func Cache

func Cache(ctx context.Context, exec Executor, q Query) (BaseQuery[*cached], error)

func CacheN

func CacheN(ctx context.Context, exec Executor, q Query, start int) (BaseQuery[*cached], error)

func (BaseQuery[E]) Apply

func (b BaseQuery[E]) Apply(mods ...Mod[E])

func (BaseQuery[E]) Build

func (q BaseQuery[E]) Build(ctx context.Context) (string, []any, error)

Convinient function to build query from start

func (BaseQuery[E]) BuildN

func (q BaseQuery[E]) BuildN(ctx context.Context, start int) (string, []any, error)

Convinient function to build query from a point

func (BaseQuery[E]) Cache

func (q BaseQuery[E]) Cache(ctx context.Context, exec Executor) (BaseQuery[*cached], error)

Convinient function to cache a query

func (BaseQuery[E]) CacheN

func (q BaseQuery[E]) CacheN(ctx context.Context, exec Executor, start int) (BaseQuery[*cached], error)

Convinient function to cache a query from a point

func (BaseQuery[E]) Clone

func (b BaseQuery[E]) Clone() BaseQuery[E]

func (BaseQuery[E]) Exec

func (b BaseQuery[E]) Exec(ctx context.Context, exec Executor) (sql.Result, error)

func (BaseQuery[E]) GetLoaders

func (b BaseQuery[E]) GetLoaders() []Loader

func (BaseQuery[E]) GetMapperMods

func (b BaseQuery[E]) GetMapperMods() []scan.MapperMod

func (BaseQuery[E]) MustBuild

func (q BaseQuery[E]) MustBuild(ctx context.Context) (string, []any)

MustBuild builds the query and panics on error useful for initializing queries that need to be reused

func (BaseQuery[E]) MustBuildN

func (q BaseQuery[E]) MustBuildN(ctx context.Context, start int) (string, []any)

MustBuildN builds the query and panics on error start numbers the arguments from a different point

func (BaseQuery[E]) RunHooks

func (b BaseQuery[E]) RunHooks(ctx context.Context, exec Executor) (context.Context, error)

func (BaseQuery[E]) Type

func (b BaseQuery[E]) Type() QueryType

func (BaseQuery[E]) WriteQuery

func (b BaseQuery[E]) WriteQuery(ctx context.Context, w io.Writer, start int) ([]any, error)

func (BaseQuery[E]) WriteSQL

func (b BaseQuery[E]) WriteSQL(ctx context.Context, w io.Writer, d Dialect, start int) ([]any, error)

Satisfies the Expression interface, but uses its own dialect instead of the dialect passed to it

type BoundQuery

type BoundQuery[Arg any] struct {
	Query
	// contains filtered or unexported fields
}

func BindNamed

func BindNamed[Arg any](ctx context.Context, q Query, args Arg) BoundQuery[Arg]

func (BoundQuery[E]) Exec

func (b BoundQuery[E]) Exec(ctx context.Context, exec Executor) (sql.Result, error)

func (BoundQuery[E]) GetLoaders

func (b BoundQuery[E]) GetLoaders() []Loader

func (BoundQuery[E]) GetMapperMods

func (b BoundQuery[E]) GetMapperMods() []scan.MapperMod

func (BoundQuery[E]) RunHooks

func (b BoundQuery[E]) RunHooks(ctx context.Context, exec Executor) (context.Context, error)

func (BoundQuery[Arg]) WriteQuery

func (b BoundQuery[Arg]) WriteQuery(ctx context.Context, w io.Writer, start int) ([]any, error)

func (BoundQuery[E]) WriteSQL

func (b BoundQuery[E]) WriteSQL(ctx context.Context, w io.Writer, d Dialect, start int) ([]any, error)

Satisfies the Expression interface, but uses its own dialect instead of the dialect passed to it

type Conn

type Conn struct {
	*sql.Conn
}

Conn is similar to *sql.Conn but implements [Queryer]

func NewConn

func NewConn(conn *sql.Conn) Conn

NewConn wraps an *sql.Conn and returns a type that implements [Queryer] This is useful when an existing *sql.Conn is used in other places in the codebase

func (Conn) Begin

func (d Conn) Begin(ctx context.Context) (Tx, error)

Begin is similar to *sql.DB.BeginTx, but return a transaction that implements [Queryer]

func (Conn) BeginTx

func (d Conn) BeginTx(ctx context.Context, opts *sql.TxOptions) (Tx, error)

BeginTx is similar to *sql.DB.BeginTx, but return a transaction that implements [Queryer]

func (Conn) PrepareContext

func (d Conn) PrepareContext(ctx context.Context, query string) (StdPrepared, error)

PrepareContext creates a prepared statement for later queries or executions

func (Conn) QueryContext

func (d Conn) QueryContext(ctx context.Context, query string, args ...any) (scan.Rows, error)

QueryContext executes a query that returns rows, typically a SELECT. The args are for any placeholder parameters in the query.

type ContextualMod

type ContextualMod[T any] interface {
	Apply(context.Context, T) (context.Context, error)
}

ContextualMods are special types of mods that require a context. they are only applied at the point of building the query where possible, prefer using regular mods since they are applied once while contextual mods are applied every time a query is built

type ContextualModFunc

type ContextualModFunc[T any] func(context.Context, T) (context.Context, error)

func (ContextualModFunc[T]) Apply

func (c ContextualModFunc[T]) Apply(ctx context.Context, o T) (context.Context, error)

type ContextualModdable

type ContextualModdable[T any] struct {
	Mods []ContextualMod[T]
}

func (*ContextualModdable[T]) AppendContextualMod

func (h *ContextualModdable[T]) AppendContextualMod(mods ...ContextualMod[T])

AppendContextualMod a hook to the set

func (*ContextualModdable[T]) AppendContextualModFunc

func (h *ContextualModdable[T]) AppendContextualModFunc(f func(context.Context, T) (context.Context, error))

AppendContextualMod a hook to the set

func (*ContextualModdable[T]) RunContextualMods

func (h *ContextualModdable[T]) RunContextualMods(ctx context.Context, o T) (context.Context, error)

type DB

type DB struct {
	*sql.DB
}

DB is similar to *sql.DB but implement [Queryer]

func NewDB

func NewDB(db *sql.DB) DB

NewDB wraps an *sql.DB and returns a type that implements [Queryer] but still retains the expected methods used by *sql.DB This is useful when an existing *sql.DB is used in other places in the codebase

func Open

func Open(driverName, dataSource string) (DB, error)

Open works just like sql.Open, but converts the returned *sql.DB to DB

func OpenDB

func OpenDB(c driver.Connector) DB

OpenDB works just like sql.OpenDB, but converts the returned *sql.DB to DB

func (DB) Begin

func (d DB) Begin(ctx context.Context) (Tx, error)

Begin is similar to *sql.DB.BeginTx, but return a transaction that implements [Queryer]

func (DB) BeginTx

func (d DB) BeginTx(ctx context.Context, opts *sql.TxOptions) (Tx, error)

BeginTx is similar to *sql.DB.BeginTx, but return a transaction that implements [Queryer]

func (DB) PrepareContext

func (d DB) PrepareContext(ctx context.Context, query string) (StdPrepared, error)

PrepareContext creates a prepared statement for later queries or executions

func (DB) QueryContext

func (d DB) QueryContext(ctx context.Context, query string, args ...any) (scan.Rows, error)

QueryContext executes a query that returns rows, typically a SELECT. The args are for any placeholder parameters in the query.

func (DB) RunInTx

func (d DB) RunInTx(ctx context.Context, txOptions *sql.TxOptions, fn func(context.Context, Executor) error) error

RunInTx runs the provided function in a transaction. If the function returns an error, the transaction is rolled back. Otherwise, the transaction is committed.

type DebugPrinter

type DebugPrinter interface {
	PrintQuery(query string, args ...any)
}

DebugPrinter is used to print queries and arguments

type Dialect

type Dialect interface {
	// WriteArg should write an argument placeholder to the writer with the given index
	WriteArg(w io.Writer, position int)

	// WriteQuoted writes the given string to the writer surrounded by the appropriate
	// quotes for the dialect
	WriteQuoted(w io.Writer, s string)
}

Dialect provides expressions with methods to write parts of the query

type DialectWithNamed

type DialectWithNamed interface {
	Dialect
	// WriteNamedArg should write an argument placeholder to the writer with the given name
	WriteNamedArg(w io.Writer, name string)
}

DialectWithNamed is a Dialect with the additional ability to WriteNamedArgs

type EmbeddedHook

type EmbeddedHook struct {
	Hooks []func(context.Context, Executor) (context.Context, error)
}

func (*EmbeddedHook) AppendHooks

func (h *EmbeddedHook) AppendHooks(hooks ...func(context.Context, Executor) (context.Context, error))

func (*EmbeddedHook) RunHooks

func (h *EmbeddedHook) RunHooks(ctx context.Context, exec Executor) (context.Context, error)

func (*EmbeddedHook) SetHooks

func (h *EmbeddedHook) SetHooks(hooks ...func(context.Context, Executor) (context.Context, error))

type Executor

type Executor interface {
	scan.Queryer
	ExecContext(context.Context, string, ...any) (sql.Result, error)
}

func Debug

func Debug(exec Executor) Executor

Debug wraps an Executor and prints the queries and args to os.Stdout

func DebugToPrinter

func DebugToPrinter(exec Executor, w DebugPrinter) Executor

DebugToPrinter wraps an existing Executor and writes all queries and args to the given DebugPrinter if w is nil, it fallsback to writing to os.Stdout

func DebugToWriter

func DebugToWriter(exec Executor, w io.Writer) Executor

DebugToWriter wraps an existing Executor and writes all queries and args to the given io.Writer if w is nil, it fallsback to os.Stdout

type Expression

type Expression interface {
	// Writes the textual representation of the expression to the writer
	// using the given dialect.
	// start is the beginning index of the args if it needs to write any
	WriteSQL(ctx context.Context, w io.Writer, d Dialect, start int) (args []any, err error)
}

Expression represents a section of a query

func Named

func Named(names ...string) Expression

Named args should ONLY be used to prepare statements

func NamedGroup

func NamedGroup(names ...string) Expression

NamedGroup is like Named, but wraps in parentheses

type ExpressionFunc

type ExpressionFunc func(ctx context.Context, w io.Writer, d Dialect, start int) ([]any, error)

func (ExpressionFunc) WriteSQL

func (e ExpressionFunc) WriteSQL(ctx context.Context, w io.Writer, d Dialect, start int) ([]any, error)

type Hook

type Hook[T any] func(context.Context, Executor, T) (context.Context, error)

Hook is a function that can be called during lifecycle of an object the context can be modified and returned The caller is expected to use the returned context for subsequent processing

type HookableQuery

type HookableQuery interface {
	RunHooks(context.Context, Executor) (context.Context, error)
}

type HookableType

type HookableType interface {
	AfterQueryHook(context.Context, Executor, QueryType) error
}

If a type implements this interface, it will be called after the query has been executed and it is scanned

type Hooks

type Hooks[T any, K any] struct {
	// contains filtered or unexported fields
}

Hooks is a set of hooks that can be called all at once

func (*Hooks[T, K]) AppendHooks

func (h *Hooks[T, K]) AppendHooks(hooks ...Hook[T])

AppendHooks a hook to the set

func (*Hooks[T, K]) GetHooks

func (h *Hooks[T, K]) GetHooks() []Hook[T]

GetHooks returns all the hooks in the set

func (*Hooks[T, K]) RunHooks

func (h *Hooks[T, K]) RunHooks(ctx context.Context, exec Executor, o T) (context.Context, error)

RunHooks calls all the registered hooks. if the context is set to skip hooks using SkipHooks, then RunHooks simply returns the context

type Load

type Load struct {
	// contains filtered or unexported fields
}

Load is an embeddable struct that enables Preloading and AfterLoading

func (*Load) AppendLoader

func (l *Load) AppendLoader(f ...Loader)

AppendLoader add to the query's loaders

func (*Load) AppendMapperMod

func (l *Load) AppendMapperMod(f scan.MapperMod)

AppendMapperMod adds to the query's mapper mods

func (*Load) GetLoaders

func (l *Load) GetLoaders() []Loader

GetLoaders implements the Loadable interface

func (*Load) GetMapperMods

func (l *Load) GetMapperMods() []scan.MapperMod

GetMapperMods implements the MapperModder interface

func (*Load) SetLoaders

func (l *Load) SetLoaders(loaders ...Loader)

SetLoaders sets the query's loaders

func (*Load) SetMapperMods

func (l *Load) SetMapperMods(mods ...scan.MapperMod)

type Loadable

type Loadable interface {
	GetLoaders() []Loader
}

Loadable is an object that has loaders if a query implements this interface, the loaders are called after executing the query

type Loader

type Loader interface {
	Load(ctx context.Context, exec Executor, retrieved any) error
}

Loader is an object that is called after the main query is performed when called from Exec, retrieved is nil when called from One, retrieved is the retrieved object when called from All, retrieved is a slice retrieved objects this is used for loading relationships

type LoaderFunc

type LoaderFunc func(ctx context.Context, exec Executor, retrieved any) error

Loader builds a query mod that makes an extra query after the object is retrieved it can be used to prevent N+1 queries by loading relationships in batches

func (LoaderFunc) Load

func (l LoaderFunc) Load(ctx context.Context, exec Executor, retrieved any) error

Load is called after the original object is retrieved

type MapperModder

type MapperModder interface {
	GetMapperMods() []scan.MapperMod
}

type MissingArgError

type MissingArgError struct{ Name string }

func (MissingArgError) Error

func (e MissingArgError) Error() string

type Mod

type Mod[T any] interface {
	Apply(T)
}

Mod is a generic interface for modifying a query It is the building block for creating queries

type ModFunc

type ModFunc[T any] func(T)

func (ModFunc[T]) Apply

func (m ModFunc[T]) Apply(query T)

type Mods

type Mods[T any] []Mod[T]

func ToMods

func ToMods[T Mod[Q], Q any](r ...T) Mods[Q]

ToMods converts a slice of a type that implements Mod[T] to Mods[T] this is useful since a slice of structs that implement Mod[T] cannot be directly used as a slice of Mod[T]

func (Mods[T]) Apply

func (m Mods[T]) Apply(query T)

type PreparedExecutor

type PreparedExecutor interface {
	ExecContext(ctx context.Context, args ...any) (sql.Result, error)
	QueryContext(ctx context.Context, args ...any) (scan.Rows, error)
	Close() error
}

type Preparer

type Preparer[P PreparedExecutor] interface {
	Executor
	PrepareContext(ctx context.Context, query string) (P, error)
}

type Query

type Query interface {
	// It should satisfy the Expression interface so that it can be used
	// in places such as a sub-select
	// However, it is allowed for a query to use its own dialect and not
	// the dialect given to it
	Expression
	// start is the index of the args, usually 1.
	// it is present to allow re-indexing in cases of a subquery
	// The method returns the value of any args placed
	WriteQuery(ctx context.Context, w io.Writer, start int) (args []any, err error)
	// Type returns the query type
	Type() QueryType
}

type QueryStmt

type QueryStmt[Arg, T any, Ts ~[]T] struct {
	Stmt[Arg]
	// contains filtered or unexported fields
}

func PrepareQuery

func PrepareQuery[Arg any, P PreparedExecutor, T any](ctx context.Context, exec Preparer[P], q Query, m scan.Mapper[T]) (QueryStmt[Arg, T, []T], error)

func PrepareQueryx

func PrepareQueryx[Arg any, P PreparedExecutor, T any, Ts ~[]T](ctx context.Context, exec Preparer[P], q Query, m scan.Mapper[T]) (QueryStmt[Arg, T, Ts], error)

func (QueryStmt[Arg, T, Ts]) All

func (s QueryStmt[Arg, T, Ts]) All(ctx context.Context, arg Arg) (Ts, error)

func (QueryStmt[Arg, T, Ts]) Cursor

func (s QueryStmt[Arg, T, Ts]) Cursor(ctx context.Context, arg Arg) (scan.ICursor[T], error)

func (QueryStmt[Arg, T, Ts]) One

func (s QueryStmt[Arg, T, Ts]) One(ctx context.Context, arg Arg) (T, error)

type QueryType

type QueryType int
const (
	QueryTypeUnknown QueryType = iota
	QueryTypeSelect
	QueryTypeInsert
	QueryTypeUpdate
	QueryTypeDelete
)

func (QueryType) String

func (q QueryType) String() string

type RawNamedArgError

type RawNamedArgError struct {
	Name string
}

func (RawNamedArgError) Error

func (e RawNamedArgError) Error() string

type SkipContextualModsKey

type SkipContextualModsKey struct{}

If set to true, contextual mods are skipped

type SkipModelHooksKey

type SkipModelHooksKey struct{}

If set to true, model hooks are skipped

type SkipQueryHooksKey

type SkipQueryHooksKey struct{}

If set to true, query hooks are skipped

type SliceTransformer

type SliceTransformer[T any, Ts ~[]T] struct{}

SliceTransformer is a Transformer that transforms a scanned slice of type T into a slice of type Ts.

func (SliceTransformer[T, Ts]) TransformScanned

func (SliceTransformer[T, Ts]) TransformScanned(scanned []T) (Ts, error)

type StdPrepared

type StdPrepared struct {
	*sql.Stmt
}

func (StdPrepared) QueryContext

func (s StdPrepared) QueryContext(ctx context.Context, args ...any) (scan.Rows, error)

type Stmt

type Stmt[Arg any] struct {
	// contains filtered or unexported fields
}

Stmt is similar to *sql.Stmt but implements [Queryer] instead of taking a list of args, it takes a struct to bind to the query

func InTx

func InTx[Arg any, S PreparedExecutor](ctx context.Context, s Stmt[Arg], tx txForStmt[S]) Stmt[Arg]

InTx returns a new MappedStmt that will be executed in the given transaction

func Prepare

func Prepare[Arg any, P PreparedExecutor](ctx context.Context, exec Preparer[P], q Query) (Stmt[Arg], error)

Prepare prepares a query using the Preparer and returns a [NamedStmt]

func (Stmt[Arg]) Close

func (s Stmt[Arg]) Close() error

Close closes the statement.

func (Stmt[Arg]) Exec

func (s Stmt[Arg]) Exec(ctx context.Context, arg Arg) (sql.Result, error)

Exec executes a query without returning any rows. The args are for any placeholder parameters in the query.

func (Stmt[Arg]) NamedArgs

func (s Stmt[Arg]) NamedArgs() []string

type Transaction

type Transaction interface {
	Executor
	Commit(context.Context) error
	Rollback(context.Context) error
}

type Transactor

type Transactor[Tx Transaction] interface {
	Executor
	Begin(context.Context) (Tx, error)
}

type Transformer

type Transformer[T any, V any] interface {
	TransformScanned([]T) (V, error)
}

type Tx

type Tx struct {
	*sql.Tx
}

Tx is similar to *sql.Tx but implements [Queryer]

func NewTx

func NewTx(tx *sql.Tx) Tx

NewTx wraps an *sql.Tx and returns a type that implements [Queryer] but still retains the expected methods used by *sql.Tx This is useful when an existing *sql.Tx is used in other places in the codebase

func (Tx) Commit

func (t Tx) Commit(_ context.Context) error

Commit works the same as *sql.Tx.Commit

func (Tx) PrepareContext

func (t Tx) PrepareContext(ctx context.Context, query string) (StdPrepared, error)

PrepareContext creates a prepared statement for later queries or executions

func (Tx) QueryContext

func (t Tx) QueryContext(ctx context.Context, query string, args ...any) (scan.Rows, error)

QueryContext executes a query that returns rows, typically a SELECT. The args are for any placeholder parameters in the query.

func (Tx) Rollback

func (t Tx) Rollback(_ context.Context) error

Rollback works the same as *sql.Tx.Rollback

func (Tx) StmtContext

func (tx Tx) StmtContext(ctx context.Context, stmt StdPrepared) StdPrepared

type WrongStartError

type WrongStartError struct {
	Expected int
	Got      int
}

func (WrongStartError) Error

func (e WrongStartError) Error() string

Directories

Path Synopsis
dialect
drivers
pgx
gen
bobgen-mysql command
bobgen-psql command
bobgen-sql command
bobgen-sqlite command
drivers
Package drivers talks to various database backends and retrieves table, column, type, and foreign key information
Package drivers talks to various database backends and retrieves table, column, type, and foreign key information
test
gen

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL