From a23dd12a27237a5e0d6883cd30373408a2f28f6e Mon Sep 17 00:00:00 2001 From: Stefan Majewsky Date: Sun, 12 Apr 2026 19:13:50 +0200 Subject: add initial sketches for Store.Insert, Store.Update Currently extremely bad performance for some reason. Need to investigate. --- oblast.go | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) (limited to 'oblast.go') 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 +} -- cgit v1.2.3