From 1383c6fbaa6b9e0b7cc5e44b74a905352d596758 Mon Sep 17 00:00:00 2001 From: Stefan Majewsky Date: Fri, 17 Jul 2026 19:35:55 +0200 Subject: cache buildPlan results --- oblast.go | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) (limited to 'oblast.go') diff --git a/oblast.go b/oblast.go index 00aaa3f..68e6db8 100644 --- a/oblast.go +++ b/oblast.go @@ -138,23 +138,26 @@ func StructTagKeyIs(key string) PlanOption { // Store holds information on how to read and write data into record type R, // and can also be used to execute autogenerated queries if the respective [PlanOption] values were provided during [NewStore]. type Store[R any] struct { - dialect Dialect - plan plan + plan plan } // NewStore initializes a store for record type R. // Returns an error if R is not a struct type. +// +// In most situations, the intended usage pattern is to call NewStore (or [MustNewStore]) once per record type, +// and hold the result in a global variable. +// +// When dealing with private one-off record types that are declared within the function or method using them, +// NewStore (or [MustNewStore]) may also be called once per function call. +// NewStore will internally cache its results and return a cheap copy on subsequent calls with the same arguments, +// only incurring the cost of a read lock on a mutex. func NewStore[R any](dialect Dialect, opts ...PlanOption) (Store[R], error) { - var popts planOpts - for _, opt := range opts { - opt(&popts) - } - plan, err := buildPlan(reflect.TypeFor[R](), dialect, popts) + plan, err := getOrBuildPlan(reflect.TypeFor[R](), dialect, collectPlanOptions(opts)) if err != nil { var zero R return Store[R]{}, fmt.Errorf("cannot use type %T for queries: %w", zero, err) } - return Store[R]{dialect, plan}, err + return Store[R]{plan}, err } // MustNewStore is like [NewStore], but panics on error. -- cgit v1.3.1