kra

package module
v0.3.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 25, 2022 License: Apache-2.0 Imports: 10 Imported by: 0

README

kra

PkgGoDev Go Report Card

SQL is the best way to access database.

kra is a relational database access helper library on top of go.

kra works with database/sql, so all of database with database/sql based driver is supported. and kra also works with pgx native API. kra focuses on the convenient use of CopyFrom.

Features

  • Named parameter support with dot notation
  • IN statement variable expansion
  • Rows to structure/map mapping
  • Selectable base API. pgx or database/sql
  • Highly configurable behavior
  • Context is required for network access APIs
  • All wrapper object has escape hatches

Getting Started

Install

go get github.com/taichi/kra

Usage

native pgx based API
package main

import (
	"context"
	"database/sql"
	"fmt"
	"time"

	"github.com/jackc/pgtype"

	"github.com/taichi/kra/pgx"
)

type Film struct {
	Code     string
	Title    string
	Did      int
	DateProd time.Time `db:"date_prod"`
	Kind     string
	Len      pgtype.Interval
}

func main() {
	ctx := context.Background()

	db, err := pgx.Open(ctx, "user=test password=test host=localhost port=5432 database=test sslmode=disable")
	if err != nil {
		fmt.Println("open", err)
		return
	}
	defer db.Close()

	if _, err := db.Exec(ctx, `CREATE TABLE IF NOT EXISTS films (
	    code        char(5) PRIMARY KEY,
	    title       varchar(40) NOT NULL,
	    did         integer NOT NULL,
	    date_prod   date,
	    kind        varchar(10),
	    len         interval hour to minute
	);`); err != nil {
		fmt.Println("create", err)
		return
	}
	defer func() {
		if _, err := db.Exec(ctx, "DROP TABLE films"); err != nil {
			fmt.Println(err)
		}
	}()

	testdata := []Film{
		{"1111", "aaaa", 32, time.Now(), "CDR", pgtype.Interval{Microseconds: 5400000000, Status: pgtype.Present}},
		{"2222", "bbbb", 34, time.Now(), "ZDE", pgtype.Interval{Microseconds: 9000000000, Status: pgtype.Present}},
		{"3333", "cccc", 65, time.Now(), "IOM", pgtype.Interval{Microseconds: 5400000000, Status: pgtype.Present}},
		{"4444", "dddd", 72, time.Now(), "ERW", pgtype.Interval{Microseconds: 7200000000, Status: pgtype.Present}},
	}

	if _, err := db.CopyFrom(ctx, pgx.Identifier{"films"}, testdata); err != nil {
		fmt.Println("CopyFrom", err)
		return
	}

	var films []Film
	if err := db.FindAll(ctx, &films, "SELECT * FROM films WHERE kind IN (:kind)", sql.NamedArg{Name: "kind", Value: []string{"CDR", "ZDE"}}); err != nil {
		fmt.Println("find", err)
		return
	}

	fmt.Printf("%v\n", films)
}
standard database/sql based API
package main

import (
	"context"
	"fmt"
	"time"

	"github.com/jackc/pgtype"
	_ "github.com/jackc/pgx/v4/stdlib"

	"github.com/taichi/kra"
	"github.com/taichi/kra/sql"
)

type Film struct {
	Code     string
	Title    string
	Did      int
	DateProd time.Time `db:"date_prod"`
	Kind     string
	Len      pgtype.Interval
}

func main() {
	ctx := context.Background()

	db, err := sql.Open(kra.NewCore(kra.PostgreSQL), "pgx", "user=test password=test host=localhost port=5432 database=test sslmode=disable")
	if err != nil {
		fmt.Println("open", err)
		return
	}
	defer db.Close()

	if _, err := db.Exec(ctx, `CREATE TABLE IF NOT EXISTS films (
	    code        char(5) PRIMARY KEY,
	    title       varchar(40) NOT NULL,
	    did         integer NOT NULL,
	    date_prod   date,
	    kind        varchar(10),
	    len         interval hour to minute
	);`); err != nil {
		fmt.Println("create", err)
		return
	}
	defer func() {
		if _, err := db.Exec(ctx, "DROP TABLE films"); err != nil {
			fmt.Println(err)
		}
	}()

	if stmt, err := db.Prepare(ctx, "INSERT INTO films (code, title, did, date_prod, kind, len) VALUES (:code, :title, :did, :date_prod, :kind, :len)"); err != nil {
		fmt.Println("prepare", err)
		return
	} else {
		testdata := []Film{
			{"1111", "aaaa", 32, time.Now(), "CDR", pgtype.Interval{Microseconds: 5400000000, Status: pgtype.Present}},
			{"2222", "bbbb", 34, time.Now(), "ZDE", pgtype.Interval{Microseconds: 9000000000, Status: pgtype.Present}},
			{"3333", "cccc", 65, time.Now(), "IOM", pgtype.Interval{Microseconds: 5400000000, Status: pgtype.Present}},
			{"4444", "dddd", 72, time.Now(), "ERW", pgtype.Interval{Microseconds: 7200000000, Status: pgtype.Present}},
		}
		for _, data := range testdata {
			if _, err := stmt.Exec(ctx, data); err != nil {
				fmt.Println("insert", err)
				return
			}
		}
		if err := stmt.Close(); err != nil {
			fmt.Println("close", err)
			return
		}
	}
	var films []Film
	if err := db.FindAll(ctx, &films, "SELECT * FROM films WHERE kind IN (:kind)", kra.NamedArg{Name: "kind", Value: []string{"CDR", "ZDE"}}); err != nil {
		fmt.Println("find", err)
		return
	}

	fmt.Printf("%v\n", films)
}

Documentation

Overview

Copyright 2022 taichi

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

Index

Constants

View Source
const DefaultTagName = "db"

Variables

View Source
var ErrEmptySlice = errors.New("kra: empty slice set to in query parameter")
View Source
var ErrFieldNotFound = errors.New("kra: field not found")
View Source
var ErrFieldUnexported = errors.New("kra: field not exported")
View Source
var ErrInvalidMapKeyType = errors.New("kra: invalid map key type")
View Source
var ErrLackOfQueryParameters = errors.New("kra: require example parameters for prepare query with IN operator")
View Source
var ErrMultipleParameterStyles = errors.New("kra: 2 or more bind variables style contains in 1 statement. Use only 1 bind variables style in 1 query, such as ? or $1,$2,$3... or :foo,:bar,:baz... ")
View Source
var ErrMultipleStatements = errors.New("kra: 2 or more statements in 1 query. Use batch queries. ")
View Source
var ErrNilPointer = errors.New("kra: destination is typed nil pointer")
View Source
var ErrNoColumns = errors.New("kra: no scannable columns")
View Source
var ErrNoPointer = errors.New("kra: destination is not a pointer")
View Source
var ErrNoRecord = errors.New("kra: no record")
View Source
var ErrNoSlice = errors.New("kra: destination is not a slice")
View Source
var ErrParameterNotFound = errors.New("kra: parameter not found")
View Source
var ErrUnsupportedValueType = errors.New("kra: unsupported value type")

Functions

func AsSlice

func AsSlice(object interface{}) []interface{}

func FindCaller added in v0.2.0

func FindCaller(skip int, bufferSize int, filter func(frame *runtime.Frame) (found bool)) *runtime.Frame

func Indirect

func Indirect(t reflect.Type) reflect.Type

func Scan

func Scan(src Rows, dest interface{}) error

func ScanAll

func ScanAll(src Rows, elementType reflect.Type, appender func(reflect.Value)) error

func ScanAllMap

func ScanAllMap(src Rows, columns []string, mapType reflect.Type, appender func(reflect.Value)) error

func ScanMap

func ScanMap(src Rows, columns []string, value reflect.Value) error

func ToPackageName added in v0.2.0

func ToPackageName(name string) string

func VisitChildren

func VisitChildren(visitor parser.NamedVisitor, node antlr.RuleNode) interface{}

Types

type BindVar

type BindVar func(int) string

type BindingStyle

type BindingStyle uint
const (
	NAMED BindingStyle = 1 << iota
	QMARK
	DEC
)

type Core

type Core struct {
	BindVar        func(index int) string
	Parse          func(query string) (QueryAnalyzer, error)
	NewResolver    func(args ...interface{}) (ValueResolver, error)
	NewTransformer func() Transformer
	TagName        string
	Repository     *TypeRepository
}

func NewCore

func NewCore(db DB) *Core

func (*Core) Analyze

func (core *Core) Analyze(hooks []*CoreHook, query string, args ...interface{}) (rawQuery string, vars []interface{}, err error)

type CoreHook added in v0.2.0

type CoreHook struct {
	Parse          func(invocation *CoreParse, query string) (QueryAnalyzer, error)
	NewResolver    func(invocation *CoreNewResolver, args ...interface{}) (ValueResolver, error)
	NewTransformer func(invocation *CoreNewTransformer) Transformer
}

type CoreNewResolver added in v0.2.0

type CoreNewResolver coreInvocation[func(args ...interface{}) (ValueResolver, error)]

func NewCoreNewResolver added in v0.2.0

func NewCoreNewResolver(recv *Core, hooks []*CoreHook) *CoreNewResolver

func (*CoreNewResolver) Proceed added in v0.2.0

func (invocation *CoreNewResolver) Proceed(args ...interface{}) (ValueResolver, error)

type CoreNewTransformer added in v0.2.0

type CoreNewTransformer coreInvocation[func() Transformer]

func NewCoreNewTransformer added in v0.2.0

func NewCoreNewTransformer(recv *Core, hooks []*CoreHook) *CoreNewTransformer

func (*CoreNewTransformer) Proceed added in v0.2.0

func (invocation *CoreNewTransformer) Proceed() Transformer

type CoreParse added in v0.2.0

type CoreParse coreInvocation[func(query string) (QueryAnalyzer, error)]

func NewCoreParse added in v0.2.0

func NewCoreParse(recv *Core, hooks []*CoreHook) *CoreParse

func (*CoreParse) Proceed added in v0.2.0

func (invocation *CoreParse) Proceed(query string) (QueryAnalyzer, error)

type DB

type DB uint8
const (
	PostgreSQL DB = iota
	MySQL
	SQLite
	SQLServer
)

type DefaultTransformer

type DefaultTransformer struct {
	// contains filtered or unexported fields
}

func NewDefaultTransformer

func NewDefaultTransformer(core *Core) *DefaultTransformer

func (*DefaultTransformer) ScanAllStruct

func (transformer *DefaultTransformer) ScanAllStruct(src Rows, columns []string, elementType reflect.Type, appender func(reflect.Value)) error

func (*DefaultTransformer) ScanStruct

func (transformer *DefaultTransformer) ScanStruct(src Rows, columns []string, root reflect.Value) error

func (*DefaultTransformer) Transform

func (transformer *DefaultTransformer) Transform(src Rows, dest interface{}) error

func (*DefaultTransformer) TransformAll

func (transformer *DefaultTransformer) TransformAll(src Rows, dest interface{}) error

type DefaultValueResolver

type DefaultValueResolver struct {
	// contains filtered or unexported fields
}

func (*DefaultValueResolver) BindVar

func (resolver *DefaultValueResolver) BindVar(index int) string

func (*DefaultValueResolver) ByIndex

func (resolver *DefaultValueResolver) ByIndex(index int) (interface{}, error)

func (*DefaultValueResolver) ByName

func (resolver *DefaultValueResolver) ByName(name string) (interface{}, error)

type FieldDef

type FieldDef struct {
	Indices    []int
	Self       *StructDef
	Unexported bool
	Options    map[string]string
}

type NamedArg

type NamedArg sql.NamedArg

type ParameterVisitor

type ParameterVisitor struct {
	parser.BaseNamedVisitor
	// contains filtered or unexported fields
}

func (*ParameterVisitor) VisitDecParameter

func (visitor *ParameterVisitor) VisitDecParameter(ctx *parser.DecParameterContext) interface{}

func (*ParameterVisitor) VisitInExpr

func (visitor *ParameterVisitor) VisitInExpr(ctx *parser.InExprContext) interface{}

func (*ParameterVisitor) VisitNamedParameter added in v0.3.0

func (visitor *ParameterVisitor) VisitNamedParameter(ctx *parser.NamedParameterContext) interface{}

func (*ParameterVisitor) VisitParameter

func (visitor *ParameterVisitor) VisitParameter(ctx *parser.ParameterContext) interface{}

func (*ParameterVisitor) VisitQmarkParameter

func (visitor *ParameterVisitor) VisitQmarkParameter(ctx *parser.QmarkParameterContext) interface{}

func (*ParameterVisitor) VisitStaticParameter

func (visitor *ParameterVisitor) VisitStaticParameter(ctx *parser.StaticParameterContext) interface{}

type PartsCollector

type PartsCollector struct {
	// contains filtered or unexported fields
}

func (*PartsCollector) Add

func (collector *PartsCollector) Add(fn StmtPartFn) error

func (*PartsCollector) Use

func (collector *PartsCollector) Use(style BindingStyle)

func (*PartsCollector) Use2orMoreStyles

func (collector *PartsCollector) Use2orMoreStyles() bool

func (*PartsCollector) Validate

func (collector *PartsCollector) Validate() error

func (*PartsCollector) Visit

func (collector *PartsCollector) Visit(tree antlr.ParseTree) interface{}

func (*PartsCollector) VisitAnyStmtParts

func (collector *PartsCollector) VisitAnyStmtParts(ctx *parser.AnyStmtPartsContext) interface{}

func (*PartsCollector) VisitChildren

func (collector *PartsCollector) VisitChildren(node antlr.RuleNode) interface{}

func (*PartsCollector) VisitDecParameter

func (collector *PartsCollector) VisitDecParameter(ctx *parser.DecParameterContext) interface{}

func (*PartsCollector) VisitErrorNode

func (collector *PartsCollector) VisitErrorNode(node antlr.ErrorNode) interface{}

func (*PartsCollector) VisitInExpr

func (collector *PartsCollector) VisitInExpr(ctx *parser.InExprContext) interface{}

func (*PartsCollector) VisitNamedParameter added in v0.3.0

func (collector *PartsCollector) VisitNamedParameter(ctx *parser.NamedParameterContext) interface{}

func (*PartsCollector) VisitParameter

func (collector *PartsCollector) VisitParameter(ctx *parser.ParameterContext) interface{}

func (*PartsCollector) VisitParse

func (collector *PartsCollector) VisitParse(ctx *parser.ParseContext) interface{}

func (*PartsCollector) VisitQmarkParameter

func (collector *PartsCollector) VisitQmarkParameter(ctx *parser.QmarkParameterContext) interface{}

func (*PartsCollector) VisitStaticParameter

func (collector *PartsCollector) VisitStaticParameter(ctx *parser.StaticParameterContext) interface{}

func (*PartsCollector) VisitStmt

func (collector *PartsCollector) VisitStmt(ctx *parser.StmtContext) interface{}

func (*PartsCollector) VisitTerminal

func (collector *PartsCollector) VisitTerminal(node antlr.TerminalNode) interface{}

type Query

type Query struct {
	// contains filtered or unexported fields
}

func NewQuery

func NewQuery(src string) (*Query, error)

func (*Query) Analyze

func (query *Query) Analyze(resolver ValueResolver) (rawQuery string, vars []interface{}, err error)

func (*Query) Verify

func (query *Query) Verify(resolver ValueResolver) error

type QueryAnalyzer

type QueryAnalyzer interface {
	Verify(ValueResolver) error
	Analyze(ValueResolver) (query string, vars []interface{}, err error)
}

type ResolveFn

type ResolveFn func(string) (interface{}, bool, error)

type ResolvingState

type ResolvingState struct {
	// contains filtered or unexported fields
}

func (*ResolvingState) AppendStmt

func (state *ResolvingState) AppendStmt(part string)

func (*ResolvingState) AppendVar

func (state *ResolvingState) AppendVar(val interface{})

func (*ResolvingState) ConcatVar

func (state *ResolvingState) ConcatVar(val []interface{})

func (*ResolvingState) NextIndex

func (state *ResolvingState) NextIndex() int

type Rows

type Rows interface {
	Close() error
	Err() error
	Next() bool
	Columns() ([]string, error)
	Scan(dest ...interface{}) error
}

type SilentValueResolver

type SilentValueResolver struct {
	// contains filtered or unexported fields
}

func (*SilentValueResolver) BindVar

func (resolver *SilentValueResolver) BindVar(index int) string

func (*SilentValueResolver) ByIndex

func (resolver *SilentValueResolver) ByIndex(index int) (interface{}, error)

func (*SilentValueResolver) ByName

func (resolver *SilentValueResolver) ByName(name string) (interface{}, error)

type StmtPart

type StmtPart func(*ResolvingState, ValueResolver) error

func NewDMarkParameterPart

func NewDMarkParameterPart(digit string) (StmtPart, error)

func NewInPart

func NewInPart(in, src string) (StmtPart, error)

func NewNamedParameterPart

func NewNamedParameterPart(src string) (StmtPart, error)

func NewQMarkParameterPart

func NewQMarkParameterPart(src string) (StmtPart, error)

func NewStaticInPart

func NewStaticInPart(in string, parts []StmtPartFn) (StmtPart, error)

func NewStaticParameterPart

func NewStaticParameterPart(src string) (StmtPart, error)

func NewStringPart

func NewStringPart(src string) (StmtPart, error)

type StmtPartFn

type StmtPartFn = func() (StmtPart, error)

type StructDef

type StructDef struct {
	Target     reflect.Type
	Members    map[string]*FieldDef
	RawMembers map[string]*FieldDef
}

func (*StructDef) ByName

func (def *StructDef) ByName(root reflect.Value, name string) (*FieldDef, *reflect.Value, error)

type Transformer

type Transformer interface {
	Transform(src Rows, dest interface{}) error
	TransformAll(src Rows, dest interface{}) error
}

type TypeRepository

type TypeRepository struct {
	// contains filtered or unexported fields
}

func NewTypeRepository

func NewTypeRepository(core *Core) *TypeRepository

func (*TypeRepository) Lookup

func (repo *TypeRepository) Lookup(root reflect.Type) (*StructDef, error)

func (*TypeRepository) LookupOrTraverse

func (repo *TypeRepository) LookupOrTraverse(target reflect.Type, history ...*StructDef) (*StructDef, error)

func (*TypeRepository) Traverse

func (repo *TypeRepository) Traverse(target reflect.Type, history ...*StructDef) (*StructDef, error)

type ValueResolver

type ValueResolver interface {
	BindVar(index int) string
	ByIndex(index int) (interface{}, error)
	ByName(name string) (interface{}, error)
}

func KeepSilent

func KeepSilent(resolver ValueResolver) ValueResolver

func NewDefaultResolver

func NewDefaultResolver(core *Core, args ...interface{}) (ValueResolver, error)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL