Skip to main content
Version: 0.7.0

Configuration Reference

Quark configuration is per client. quark.New(driverName, dataSource, ...options) does not modify global ORM state.

Minimal Client

client, err := quark.New("sqlite", "file:app.db?cache=shared")

quark.New opens the connection itself and pings it with a five-second startup timeout. The dialect is auto-detected from the driver name.

Production Shape

limits := quark.DefaultLimits()
limits.MaxResults = 10_000
limits.MaxWhereConditions = 20
limits.MaxJoins = 5
limits.QueryTimeout = 30 * time.Second
limits.AllowRawQueries = false
limits.SafeMigrations = true

store := memory.New()

client, err := quark.New("postgres", dsn,
quark.WithLogger(logger),
quark.WithLimits(limits),
quark.WithCacheStore(store),
quark.WithMiddleware(quarkotel.New()),
quark.WithQueryObserver(metricsObserver),
)

Start from DefaultLimits() and override fields selectively. WithLimits replaces the entire Limits struct; a zero QueryTimeout creates immediately expired query contexts in the current implementation.

Options

OptionPurpose
WithDialect(d Dialect)Overrides the dialect that would be auto-detected from the driver name.
WithLogger(l *slog.Logger)Sets the client logger.
WithLimits(l Limits)Sets security and performance limits.
WithCacheStore(s CacheStore)Enables query cache storage.
WithMiddleware(m Middleware)Adds execution middleware.
WithQueryObserver(o QueryObserver)Adds post-execution query observers.
WithMaxOpenConns(n int)Sets *sql.DB.SetMaxOpenConns.
WithMaxIdleConns(n int)Sets *sql.DB.SetMaxIdleConns.
WithConnMaxLifetime(d time.Duration)Sets *sql.DB.SetConnMaxLifetime.

Dialect

quark.WithDialect(quark.PostgreSQL())
quark.WithDialect(quark.MySQL())
quark.WithDialect(quark.MariaDB())
quark.WithDialect(quark.SQLite())
quark.WithDialect(quark.MSSQL())
quark.WithDialect(quark.Oracle())

The dialect controls placeholders, identifier quoting, RETURNING, last-insert ID behavior, upsert SQL, JSON extraction, pagination, routines, and schema DDL.

quark.New auto-detects the dialect from the driver name. Pass WithDialect only when the driver name is ambiguous (e.g. pgx shared between PostgreSQL and CockroachDB) or when registering a custom dialect.

Logger

logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))

client, err := quark.New("postgres", dsn,
quark.WithLogger(logger),
)

The logger is used for client initialization, safe default limit warnings, schema sync messages, cache hits, and migration diagnostics.

Limits

type Limits struct {
MaxQueryLength int
MaxResults int
MaxJoins int
MaxWhereConditions int
QueryTimeout time.Duration
AllowRawQueries bool
SafeMigrations bool
}

Defaults:

FieldDefaultNotes
MaxQueryLength10 * 1024Rejects generated SELECT SQL above this byte length.
MaxResults10000Intended cap for list-style reads. Prefer explicit Limit.
MaxJoins5Rejects SELECT queries with too many joins.
MaxWhereConditions20Rejects excessive predicate chains.
QueryTimeout30 * time.SecondApplied to ORM query contexts.
AllowRawQueriesfalseRequired for RawQuery, Exec, and WhereSubquery.
SafeMigrationstruePrevents Sync from dropping columns.

Recommended pattern:

limits := quark.DefaultLimits()
limits.AllowRawQueries = true // only for migration/admin clients
limits.MaxWhereConditions = 30

client, err := quark.New("postgres", dsn,
quark.WithLimits(limits),
)

Use separate app and migration clients when possible: app clients can keep AllowRawQueries disabled, while migration commands can opt in explicitly.

Cache Store

Memory:

import "github.com/jcsvwinston/quark/cache/memory"

store := memory.New()
defer store.Close()

client, err := quark.New("sqlite", "file:app.db?cache=shared",
quark.WithCacheStore(store),
)

Redis:

import rediscache "github.com/jcsvwinston/quark/cache/redis"

store := rediscache.New(rediscache.Options{
Addr: "localhost:6379",
Password: "",
DB: 0,
})

client, err := quark.New("postgres", dsn,
quark.WithCacheStore(store),
)

Queries are cached only when .Cache(ttl, tags...) is present.

Middleware

type AuditMiddleware struct {
quark.BaseMiddleware
}

func (m *AuditMiddleware) WrapQuery(next quark.QueryFunc) quark.QueryFunc {
return func(ctx context.Context, exec quark.Executor, sqlStr string, args []any) (*sql.Rows, error) {
rows, err := next(ctx, exec, sqlStr, args)
auditQuery(ctx, sqlStr, err)
return rows, err
}
}

client, err := quark.New("postgres", dsn,
quark.WithMiddleware(&AuditMiddleware{}),
)

Middleware can wrap:

MethodPath
WrapQueryQueryContext, used by list and streaming reads.
WrapQueryRowQueryRowContext, used by counts, inserts with returning, aggregates.
WrapExecExecContext, used by writes and DDL helpers.

Multiple middleware are executed in registration order.

Query Observers

type MetricsObserver struct{}

func (m *MetricsObserver) ObserveQuery(event quark.QueryEvent) {
metrics.Record(event.Table, event.Operation, event.Duration, event.Rows, event.Error)
}

client, err := quark.New("postgres", dsn,
quark.WithQueryObserver(&MetricsObserver{}),
)

QueryEvent fields:

FieldTypeDescription
SQLstringSQL sent to the driver.
Args[]anyBound arguments.
Durationtime.DurationExecution duration measured by Quark.
Rowsint64Rows returned or affected when known.
ErrorerrorNil on success.
TablestringModel table when known.
OperationstringSELECT, EXEC, QUERY_ROW, RAW_QUERY, RAW_EXEC, etc.