aboutsummaryrefslogtreecommitdiff
path: root/oblast.go
diff options
context:
space:
mode:
Diffstat (limited to 'oblast.go')
-rw-r--r--oblast.go51
1 files changed, 51 insertions, 0 deletions
diff --git a/oblast.go b/oblast.go
index 415b6cb..5a46042 100644
--- a/oblast.go
+++ b/oblast.go
@@ -43,6 +43,7 @@ package oblast // import "go.xyrillian.de/oblast"
import (
"database/sql"
"errors"
+ "reflect"
"go.xyrillian.de/oblast/internal"
)
@@ -79,3 +80,53 @@ var (
// ErrMultipleRows is returned by [Store.SelectOne] if the query returned multiple rows.
var ErrMultipleRows = errors.New("sql: multiple rows in result set")
+
+// Store is the main interface of this library.
+//
+// It 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 internal.Plan
+}
+
+// NewStore initializes a store for record type R.
+// Returns an error if R is not a struct type.
+//
+// For the purpose of loading and storing records (i.e. instances of type R) into the database,
+// this function establishes a mapping between fields of type R and database columns by inspecting the "db" tag.
+// For example:
+//
+// type MyRecord struct {
+// ID int64 `db:"record_id,auto"`
+// Foo string `db:"foo"`
+// Bar string
+// Cache map[string]any `db:"-"`
+// action func()
+// }
+//
+// In this type:
+// - The fields "ID" and "Foo" correspond to the database columns "record_id" and "foo" because of the declaration in the "db" tag.
+// - The field "Bar" corresponds to the database column "Bar" because, when no "db" tag is given, the column name is set equal to the field name.
+// - The field "Cache" is not mapped to any database column because it is declared with a "db" tag of "-". Loads and stores will ignore it.
+// - The field "action" is private, so loads and stores will ignore it, too.
+//
+// Besides the declaration of a column name, the following extra tags are understood (as a comma-separated list following the column name):
+// - "auto": During [Store.Insert], do not store this field's value. Instead, the database will auto-generate a value, which will be read back into the record.
+func NewStore[R any](dialect Dialect, opts ...PlanOption) (Store[R], error) {
+ var popts internal.PlanOpts
+ for _, opt := range opts {
+ opt(&popts)
+ }
+ plan, err := internal.BuildPlan(reflect.TypeFor[R](), dialect, popts)
+ return Store[R]{dialect, plan}, err
+}
+
+// MustNewStore is like [NewStore], but panics on error.
+func MustNewStore[R any](dialect Dialect, opts ...PlanOption) Store[R] {
+ store, err := NewStore[R](dialect, opts...)
+ if err != nil {
+ panic(err.Error())
+ }
+ return store
+}