Documentation ¶
Overview ¶
Package sqlz contains core types such as Kind and Record.
Index ¶
- Constants
- Variables
- func ExecAffected(ctx context.Context, db Execer, query string, args ...any) (affected int64, err error)
- func SetKindIfUnknown(meta RecordMeta, i int, k kind.Kind)
- func ValidRecord(recMeta RecordMeta, rec Record) (i int, err error)
- type ColumnTypeData
- type DB
- type Execer
- type FieldMeta
- func (fm *FieldMeta) DatabaseTypeName() string
- func (fm *FieldMeta) DecimalSize() (precision, scale int64, ok bool)
- func (fm *FieldMeta) Kind() kind.Kind
- func (fm *FieldMeta) Length() (length int64, ok bool)
- func (fm *FieldMeta) Name() string
- func (fm *FieldMeta) Nullable() (nullable, ok bool)
- func (fm *FieldMeta) ScanType() reflect.Type
- func (fm *FieldMeta) String() string
- type NullBool
- type Preparer
- type Queryer
- type Record
- type RecordMeta
Constants ¶
const ( TableTypeTable = "table" TableTypeView = "view" )
Canonical driver-independent names for "table" and "view".
Variables ¶
var ( RTypeInt = reflect.TypeOf(0) RTypeInt8 = reflect.TypeOf(int8(0)) RTypeInt16 = reflect.TypeOf(int16(0)) RTypeInt32 = reflect.TypeOf(int32(0)) RTypeInt64 = reflect.TypeOf(int64(0)) RTypeInt64P = reflect.TypeOf((*int64)(nil)) RTypeNullInt64 = reflect.TypeOf(sql.NullInt64{}) RTypeFloat32 = reflect.TypeOf(float32(0)) RTypeFloat64 = reflect.TypeOf(float64(0)) RTypeFloat64P = reflect.TypeOf((*float64)(nil)) RTypeNullFloat64 = reflect.TypeOf(sql.NullFloat64{}) RTypeBool = reflect.TypeOf(true) RTypeBoolP = reflect.TypeOf((*bool)(nil)) RTypeNullBool = reflect.TypeOf(sql.NullBool{}) RTypeString = reflect.TypeOf("") RTypeStringP = reflect.TypeOf((*string)(nil)) RTypeNullString = reflect.TypeOf(sql.NullString{}) RTypeTime = reflect.TypeOf(time.Time{}) RTypeTimeP = reflect.TypeOf((*time.Time)(nil)) RTypeNullTime = reflect.TypeOf(sql.NullTime{}) RTypeBytes = reflect.TypeOf([]byte{}) RTypeBytesP = reflect.TypeOf((*[]byte)(nil)) RTypeNil = reflect.TypeOf(nil) RTypeAny = reflect.TypeOf((any)(nil)) )
Cached results from reflect.TypeOf for commonly used types.
Functions ¶
func ExecAffected ¶ added in v0.15.0
func ExecAffected(ctx context.Context, db Execer, query string, args ...any) (affected int64, err error)
ExecAffected invokes db.ExecContext, returning the count of rows affected and any error.
func SetKindIfUnknown ¶ added in v0.17.0
func SetKindIfUnknown(meta RecordMeta, i int, k kind.Kind)
SetKindIfUnknown sets meta[i].kind to k, iff the kind is currently kind.Unknown or kind.Null. This function can be used to set the kind after-the-fact, which is useful for some databases that don't always return sufficient type info upfront.
func ValidRecord ¶
func ValidRecord(recMeta RecordMeta, rec Record) (i int, err error)
ValidRecord checks that each element of the record vals is of an acceptable type. On the first unacceptable element, the index of that element and an error are returned. On success (-1, nil) is returned.
These acceptable types, per the stdlib sql pkg, are:
nil, *int64, *float64, *bool, *string, *[]byte, *time.Time
Types ¶
type ColumnTypeData ¶
type ColumnTypeData struct { Name string `json:"name"` HasNullable bool `json:"has_nullable"` HasLength bool `json:"has_length"` HasPrecisionScale bool `json:"has_precision_scale"` Nullable bool `json:"nullable"` Length int64 `json:"length"` DatabaseTypeName string `json:"database_type_name"` Precision int64 `json:"precision"` Scale int64 `json:"scale"` ScanType reflect.Type `json:"scan_type"` Kind kind.Kind `json:"kind"` }
ColumnTypeData contains the same data as sql.ColumnType as well SQ's derived data kind. This type exists with exported fields instead of methods (as on sql.ColumnType) due to the need to work with the fields for testing, and also because for some drivers it's useful to twiddle with the scan type.
This is all a bit ugly.
func NewColumnTypeData ¶
func NewColumnTypeData(col *sql.ColumnType, knd kind.Kind) *ColumnTypeData
NewColumnTypeData returns a new instance with field values taken from col, supplemented with the kind param.
type DB ¶
DB is a union of Execer, Queryer and Preparer. DB's method set is implemented by sql.DB, sql.Conn and sql.Tx. This can probably be better named, as it conflicts with sql.DB.
type Execer ¶
type Execer interface { // ExecContext is documented by sql.DB.ExecContext. ExecContext(ctx context.Context, query string, args ...any) (sql.Result, error) }
Execer abstracts the ExecContext method from sql.DB and friends.
type FieldMeta ¶
type FieldMeta struct {
// contains filtered or unexported fields
}
FieldMeta is a bit of a strange entity, and in an ideal world, it wouldn't exist. It's here because:
- The DB driver impls that sq utilizes (postgres, sqlite, etc) often have individual quirks (not reporting nullability etc) that necessitate modifying sql.ColumnType so that there's consistent behavior across the drivers.
- We wanted to retain (and supplement) the method set of sql.ColumnType (basically, use the same "interface", even though sql.ColumnType is a struct, not interface) so that devs don't need to learn a whole new thing.
- For that reason, stdlib sql.ColumnType needs to be supplemented with kind.Kind, and there needs to be a mechanism for modifying sql.ColumnType's fields.
- But sql.ColumnType is sealed (its fields cannot be changed from outside its package).
- Hence this construct where we have FieldMeta (which abstractly is an adapter around sql.ColumnType) and also a data holder struct (ColumnDataType), which permits the mutation of the column type fields.
Likely there's a better design available than this one, but it suffices.
func NewFieldMeta ¶
func NewFieldMeta(data *ColumnTypeData) *FieldMeta
NewFieldMeta returns a new instance backed by the data arg.
func (*FieldMeta) DatabaseTypeName ¶
DatabaseTypeName is documented by sql.ColumnType.DatabaseTypeName.
func (*FieldMeta) DecimalSize ¶
DecimalSize is documented by sql.ColumnType.DecimalSize.
type NullBool ¶
NullBool is similar to sql.NullBool, but accepts more boolean representations, e.g. "YES", "Y", "NO", "N", etc. These boolean values are returned by SQL Server and Postgres at times.
type Preparer ¶
type Preparer interface { // PrepareContext is documented by sql.DB.PrepareContext. PrepareContext(ctx context.Context, query string) (*sql.Stmt, error) }
Preparer abstracts the PrepareContext method from sql.DB and friends.
type Queryer ¶
type Queryer interface { // QueryContext is documented by sql.DB.QueryContext. QueryContext(ctx context.Context, query string, args ...any) (*sql.Rows, error) // QueryRowContext is documented by sql.DB.QueryRowContext. QueryRowContext(ctx context.Context, query string, args ...any) *sql.Row }
Queryer abstracts the QueryContext and QueryRowContext methods from sql.DB and friends.
type Record ¶
type Record []any
Record is a []any row of field values returned from a query.
In the codebase, we distinguish between a "Record" and a "ScanRow", although both are []any and are closely related.
An instance of ScanRow is passed to the sql rows.Scan method, and its elements may include implementations of the sql.Scanner interface such as sql.NullString, sql.NullInt64 or even driver-specific types.
A Record is typically built from a ScanRow, unwrapping and munging elements such that the Record only contains standard types:
nil, *int64, *float64, *bool, *string, *[]byte, *time.Time
It is an error for a Record to contain elements of any other type.
type RecordMeta ¶
type RecordMeta []*FieldMeta
RecordMeta is a slice of *FieldMeta, encapsulating the metadata for a record.
func (RecordMeta) Kinds ¶
func (rm RecordMeta) Kinds() []kind.Kind
Kinds returns the data kinds for the record.
func (RecordMeta) NewScanRow ¶
func (rm RecordMeta) NewScanRow() []any
NewScanRow returns a new []any that can be scanned into by sql.Rows.Scan.
func (RecordMeta) ScanTypes ¶
func (rm RecordMeta) ScanTypes() []reflect.Type
ScanTypes returns the scan types for the record.