sqldb

package module
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Mar 24, 2023 License: Apache-2.0 Imports: 13 Imported by: 0

README

Introduction

Go Report Card Go Reference

sqldb is a useful package which defines some common types and interfaces in manipulating data of models in sql database.

It also provides an implementation of the interfaces based on the GORM library.

Getting Started

The Model interface

The Model defined in model.go contains a set of commonly used methods when handling data in a database.

type Model[T any] interface {
	// DB returns the db instance.
	DB(context.Context) *gorm.DB
	// Table returns the table name in the database.
	Table() string
	// Columns returns a instance of type T,
	// all fields of type sqldb.Column[U] in the instance are populated with corresponding column name.
	Columns() T
	// ColumnNames returns all column names the model has.
	ColumnNames() []ColumnGetter

	Create(ctx context.Context, entity *T) error
	Get(ctx context.Context, opts []OpQueryOptionInterface) (T, error)
	List(ctx context.Context, opts ListOptions) ([]T, uint64, error)
	Update(ctx context.Context, query FilterOptions, opts []UpdateOptionInterface) (uint64, error)
	Delete(ctx context.Context, opts FilterOptions) error
}

Declaring models

Before using the Model you have to declaring your model, User for example:

import (
	"gorm.io/gorm"
	"github.com/YLonely/sqldb"
)

type User struct {
	ID      sqldb.Column[uint64] `gorm:"column:id;primaryKey"`
	Name    sqldb.Column[string] `gorm:"column:user_name"`
	Age     sqldb.PtrColumn[int]
	CreatedAt sqldb.Column[time.Time]
	DeletedAt sqldb.Column[gorm.DeletedAt]
}

Here sqldb.Column or sqldb.PtrColumn is a generic type which represents a table column in the database, it contains the value of the corresponding field and also the column name of it.

Operating the model

Now we can initialize a Model type for User:

import (
	"context"

	"gorm.io/gorm"
	"github.com/YLonely/sqldb"
)

func main(){
	// Use gorm to open the database.
	dsn := "user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local"
  	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
	if err != nil{
		panic(err)
	}

	Users := sqldb.NewModel[User](db)
	ctx := context.Background()

	// To create a new user
	age := 10
	u := &User{
		Name: sqldb.NewColumn("test"),
		Age: sqldb.NewPtrColumn(age),
	}
	_ = Users.Create(ctx, u)

	// To get the user
	u, err := Users.Get(ctx, []sqldb.OpQueryOptionInterface{
		// No more string literals, use .Columns() instead.
		sqldb.NewEqualOption(Users.Columns().Name, "test"),
		// Not recommended.
		sqldb.OpQueryOption[string]{
			Op: sqldb.OpEq,
			Option: sqldb.Option[string]{
				Column: sqldb.NewColumnName("user_name"),
				Value: "test",
			},
		},
	})
}

It is worth noting that you do not write string literals of columns when constructing query options, every Model[T] type has a method Columns() which returns a instance of type T, all fields of type sqldb.Column in type T are populated with column name during initialization. You can also use the option structs directly, but you have to confirm the column name by yourself, which is extremely not recommended.

Transactions

sqldb.go also defines a function type which abstracts transactions:

type TransactionFunc func(ctx context.Context, run func(context.Context) error) error

To create a TransactionFunc implemented by GORM and process models in the transaction:

Transaction := sqldb.NewTransactionFunc(db)

Transaction(context.Background(), func(ctx context.Context) error {
	if err := Users.Delete(ctx, sqldb.FilterOptions{
		InOptions: []sqldb.RangeQueryOptionInterface{
			sqldb.NewRangeQueryOption(Users.Age, []int{10, 11, 12}),
		}
	}); err != nil {
		return err
	}

	// nested transaction.
	Transaction(ctx, func(ctx context.Context) error {
	})
})

Joining tables

sqldb provides a more convenient way to join tables. The complexity of renaming duplicate column names and writing lengthy sql statements is hidden in the internal processing of sqldb. All you need to do is to call the encapsulated join functions.

import (
	"context"

	"gorm.io/gorm"
	"github.com/YLonely/sqldb"
)

type User struct {
	Name string	
	Age  int
}

type Class struct {
	Name    string
	Address string
	Age     int
}

func main(){
	// Use gorm to open the database.
	users := sqldb.NewModel[User](db)
	classes := sqldb.NewModel[Class](db)
	ctx := context.Background()

	results, total, err := Join(ctx, users, classes, 
		NewJoinOptions(
			append(users.ColumnNames(), classes.ColumnNames()...),
			[]OpJoinOptionInterface{
				NewEqualJoinOption[string](users.Columns().Name, classes.Columns().Name),
			},
		),
	).List(ctx, sqldb.ListOptions{})

	for _, result := range results {
		fmt.Printf("user.name: %s, class.name: %s\n", result.Left.Name, result.Right.Name)
	}
}

The join functions also return a Model type, which allows you to concatenate other complex query operations. The type JoinedEntity contains both Model types that are joined which provides a view of the joined tables.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func MapErr added in v0.0.7

func MapErr[T any, R any](collection []T, iteratee func(T, int) (R, error)) ([]R, error)

func TransactionFrom added in v0.0.5

func TransactionFrom(ctx context.Context) *gorm.DB

func WithTransaction added in v0.0.5

func WithTransaction(ctx context.Context, tx *gorm.DB) context.Context

Types

type Column

type Column[T any] struct {
	ColumnValue[T]
	ColumnName
}

Column represents a column of a table.

func NewColumn

func NewColumn[T any](v T) Column[T]

NewColumn creates a new Column of type T.

type ColumnGetter

type ColumnGetter interface {
	GetColumnName() ColumnName
}

type ColumnName

type ColumnName struct {
	Name string
	// contains filtered or unexported fields
}

func NewColumnName added in v0.1.0

func NewColumnName(name string) ColumnName

func (ColumnName) Full added in v0.1.0

func (cn ColumnName) Full() string

func (ColumnName) GetColumnName

func (cn ColumnName) GetColumnName() ColumnName

func (ColumnName) String added in v0.1.0

func (cn ColumnName) String() string

type ColumnType added in v0.0.3

type ColumnType[T any] interface {
	Column[T] | PtrColumn[T]
}

ColumnType contains valid column types.

type ColumnValue

type ColumnValue[T any] struct {
	V T
}

func (ColumnValue[T]) CreateClauses

func (cv ColumnValue[T]) CreateClauses(f *gormschema.Field) []clause.Interface

CreateClauses implements the CreateClausesInterface interface from GORM.

func (ColumnValue[T]) DeleteClauses

func (cv ColumnValue[T]) DeleteClauses(f *gormschema.Field) []clause.Interface

DeleteClauses implements the DeleteClausesInterface interface from GORM.

func (ColumnValue[T]) MarshalJSON

func (cv ColumnValue[T]) MarshalJSON() ([]byte, error)

func (ColumnValue[T]) QueryClauses

func (cv ColumnValue[T]) QueryClauses(f *gormschema.Field) []clause.Interface

QueryClauses implements the QueryClausesInterface interface from GORM.

func (*ColumnValue[T]) Scan

func (cv *ColumnValue[T]) Scan(src any) error

Scan implements the Scanner interface.

func (*ColumnValue[T]) UnmarshalJSON

func (cv *ColumnValue[T]) UnmarshalJSON(data []byte) error

func (ColumnValue[T]) UpdateClauses

func (cv ColumnValue[T]) UpdateClauses(f *gormschema.Field) []clause.Interface

UpdateClauses implements the UpdateClausesInterface interface from GORM.

func (ColumnValue[T]) Value

func (cv ColumnValue[T]) Value() (driver.Value, error)

Value implements the driver Valuer interface.

type FilterOptions

type FilterOptions struct {
	OpOptions    []OpQueryOptionInterface
	FuzzyOptions []FuzzyQueryOptionInterface
	InOptions    []RangeQueryOptionInterface
	NotInOptions []RangeQueryOptionInterface
}

FilterOptions contains options that related to data filtering.

type FuzzyQueryOption

type FuzzyQueryOption[T comparable] struct {
	ValuesOption[T]
}

FuzzyQueryOption implements the FuzzyQueryOptionInterface.

func NewFuzzyQueryOption

func NewFuzzyQueryOption[T comparable, C ColumnType[T]](col C, vs []T) FuzzyQueryOption[T]

NewFuzzyQueryOption creates a new FuzzyQueryOption.

type FuzzyQueryOptionInterface

type FuzzyQueryOptionInterface interface {
	ValuesOptionInterface
}

FuzzyQueryOptionInterface represents a query that find data that match given patterns approximately.

type JoinOptions added in v0.1.0

type JoinOptions struct {
	SelectedColumns []ColumnName
	Conditions      []OpJoinOptionInterface
}

func NewJoinOptions added in v0.1.0

func NewJoinOptions(selected []ColumnGetter, conditions []OpJoinOptionInterface) JoinOptions

type JoinedEntity added in v0.1.0

type JoinedEntity[L, R any] struct {
	Left  L `gorm:"embedded"`
	Right R `gorm:"embedded"`
}

type ListOptions

type ListOptions struct {
	FilterOptions
	Offset      uint64
	Limit       uint64
	SortOptions []SortOptionInterface
}

ListOptions contains options and parameters that related to data listing.

type Model

type Model[T any] interface {
	// DB returns the db instance.
	DB(context.Context) *gorm.DB
	// Table returns the table name in the database.
	Table() string
	// Columns returns a instance of type T,
	// all fields of type sqldb.Column[U] in the instance are populated with corresponding column name.
	Columns() T
	// ColumnNames returns all column names the model has.
	ColumnNames() []ColumnGetter
	Create(ctx context.Context, entity *T) error
	Get(ctx context.Context, opts []OpQueryOptionInterface) (T, error)
	List(ctx context.Context, opts ListOptions) ([]T, uint64, error)
	Update(ctx context.Context, query FilterOptions, opts []UpdateOptionInterface) (uint64, error)
	Delete(ctx context.Context, opts FilterOptions) error
}

Model is an interface defines commonly used methods to manipulate data.

func Join added in v0.1.0

func Join[L, R any](ctx context.Context, left Model[L], right Model[R], opts JoinOptions) Model[JoinedEntity[L, R]]

func LeftJoin added in v0.1.0

func LeftJoin[L, R any](ctx context.Context, left Model[L], right Model[R], opts JoinOptions) Model[JoinedEntity[L, R]]

func NewModel added in v0.0.5

func NewModel[T any](db *gorm.DB, opts ...ModelOption) Model[T]

NewModel returns a new Model.

type ModelOption added in v0.1.0

type ModelOption func(*modelConfig)

func WithDBInitialFunc added in v0.1.0

func WithDBInitialFunc(initial func(*gorm.DB) *gorm.DB) ModelOption

type OpJoinOption added in v0.1.0

type OpJoinOption struct {
	Left, Right ColumnName
	Op          QueryOp
}

func NewEqualJoinOption added in v0.1.0

func NewEqualJoinOption[T any, C ColumnType[T]](left, right C) OpJoinOption

func NewGreaterEqualJoinOption added in v0.1.0

func NewGreaterEqualJoinOption[T any, C ColumnType[T]](left, right C) OpJoinOption

func NewGreaterJoinOption added in v0.1.0

func NewGreaterJoinOption[T any, C ColumnType[T]](left, right C) OpJoinOption

func NewLessEqualJoinOption added in v0.1.0

func NewLessEqualJoinOption[T any, C ColumnType[T]](left, right C) OpJoinOption

func NewLessJoinOption added in v0.1.0

func NewLessJoinOption[T any, C ColumnType[T]](left, right C) OpJoinOption

func NewNotEqualJoinOption added in v0.1.0

func NewNotEqualJoinOption[T any, C ColumnType[T]](left, right C) OpJoinOption

func NewOpJoinOption added in v0.1.0

func NewOpJoinOption[T any, C ColumnType[T]](left C, op QueryOp, right C) OpJoinOption

func (OpJoinOption) GetLeftTargetColumn added in v0.1.0

func (opt OpJoinOption) GetLeftTargetColumn() ColumnName

func (OpJoinOption) GetRightTargetColumn added in v0.1.0

func (opt OpJoinOption) GetRightTargetColumn() ColumnName

func (OpJoinOption) QueryOp added in v0.1.0

func (opt OpJoinOption) QueryOp() QueryOp

type OpJoinOptionInterface added in v0.1.0

type OpJoinOptionInterface interface {
	GetLeftTargetColumn() ColumnName
	GetRightTargetColumn() ColumnName
	QueryOp() QueryOp
}

type OpQueryOption

type OpQueryOption[T comparable] struct {
	Option[T]
	Op QueryOp
}

OpQueryOption implements the OpQueryOptionInterface.

func NewEqualOption

func NewEqualOption[T comparable, C ColumnType[T]](col C, v T) OpQueryOption[T]

NewEqualOption creates an OpQueryOption with operator OpEq.

func NewGreaterEqualOption

func NewGreaterEqualOption[T comparable, C ColumnType[T]](col C, v T) OpQueryOption[T]

NewGreaterEqualOption creates an OpQueryOption with operator OpGte.

func NewGreaterOption

func NewGreaterOption[T comparable, C ColumnType[T]](col C, v T) OpQueryOption[T]

NewGreaterOption creates an OpQueryOption with operator OpGt.

func NewLessEqualOption

func NewLessEqualOption[T comparable, C ColumnType[T]](col C, v T) OpQueryOption[T]

NewLessEqualOption creates an OpQueryOption with operator OpLte.

func NewLessOption

func NewLessOption[T comparable, C ColumnType[T]](col C, v T) OpQueryOption[T]

NewLessOption creates an OpQueryOption with operator OpLt.

func NewNotEqualOption

func NewNotEqualOption[T comparable, C ColumnType[T]](col C, v T) OpQueryOption[T]

NewNotEqualOption creates an OpQueryOption with operator OpNe.

func NewOpQueryOption

func NewOpQueryOption[T comparable, C ColumnType[T]](col C, op QueryOp, v T) OpQueryOption[T]

NewOpQueryOption creates an OpQueryOption.

func (OpQueryOption[T]) QueryOp

func (opt OpQueryOption[T]) QueryOp() QueryOp

type OpQueryOptionInterface

type OpQueryOptionInterface interface {
	OptionInterface
	QueryOp() QueryOp
}

OpQueryOptionInterface represents a query which use the given query operator to search data.

type Option

type Option[T any] struct {
	Column ColumnName
	Value  T
}

Option implements the OptionInterface.

func NewOption

func NewOption[T any, C ColumnType[T]](col C, v T) Option[T]

NewOption returns an new Option.

func (Option[T]) GetTargetColumn added in v0.1.0

func (opt Option[T]) GetTargetColumn() ColumnName

func (Option[T]) GetValue

func (opt Option[T]) GetValue() any

type OptionInterface

type OptionInterface interface {
	// GetTargetColumn returns the column the operation processes against.
	GetTargetColumn() ColumnName
	// GetValue returns the value the option carries. It is used by the operation to query or update the target column.
	GetValue() any
}

OptionInterface wraps basic methods of options.

type PtrColumn

type PtrColumn[T any] struct {
	ColumnValue[*T]
	ColumnName
}

PtrColumn is used when declaring models with pointer fields, for example:

type Model struct{
	Name PtrColumn[string]
}

equals to

type Model struct{
	Name *string
}

func NewPtrColumn

func NewPtrColumn[T any](v T) PtrColumn[T]

NewPtrColumn creates a new PtrColumn of type T.

type QueryOp

type QueryOp string
const (
	OpEq  QueryOp = "="
	OpNe  QueryOp = "!="
	OpGt  QueryOp = ">"
	OpLt  QueryOp = "<"
	OpGte QueryOp = ">="
	OpLte QueryOp = "<="
)

type RangeQueryOption

type RangeQueryOption[T comparable] struct {
	ValuesOption[T]
}

RangeQueryOption implements the RangeQueryOptionInterface.

func NewRangeQueryOption

func NewRangeQueryOption[T comparable, C ColumnType[T]](col C, vs []T) RangeQueryOption[T]

NewRangeQueryOption creates a new RangeQueryOption.

type RangeQueryOptionInterface

type RangeQueryOptionInterface interface {
	ValuesOptionInterface
}

RangeQueryOptionInterface represents a query that find data from a given range of values.

type SortOption

type SortOption[T comparable] struct {
	Column ColumnName
	Order  SortOrder
}

SortOption implements the SortOptionInterface.

func NewSortOption

func NewSortOption[T comparable, C ColumnType[T]](col C, order SortOrder) SortOption[T]

NewSortOption creates a new SortOption.

func (SortOption[T]) GetTargetColumn added in v0.1.0

func (opt SortOption[T]) GetTargetColumn() ColumnName

func (SortOption[T]) SortOrder

func (opt SortOption[T]) SortOrder() SortOrder

type SortOptionInterface

type SortOptionInterface interface {
	GetTargetColumn() ColumnName
	SortOrder() SortOrder
}

SortOptionInterface represents an sort operation.

type SortOrder

type SortOrder string
const (
	SortOrderAscending  SortOrder = "asc"
	SortOrderDescending SortOrder = "desc"
)

type TransactionFunc

type TransactionFunc func(ctx context.Context, run func(context.Context) error) error

A TransactionFunc starts a transaction.

func NewTransactionFunc added in v0.0.5

func NewTransactionFunc(db *gorm.DB) TransactionFunc

NewTransactionFunc returns a TransactionFunc.

type UpdateOption

type UpdateOption[T any] struct {
	Option[T]
}

UpdateOption implements the UpdateOptionInterface.

func NewUpdateOption

func NewUpdateOption[T any, C ColumnType[T]](col C, v T) UpdateOption[T]

NewUpdateOption creates a new UpdateOption.

type UpdateOptionInterface

type UpdateOptionInterface interface {
	OptionInterface
}

UpdateOptionInterface represents an update operation that updates the target column with given value.

type ValuesOption

type ValuesOption[T comparable] struct {
	Column ColumnName
	Values []T
}

ValuesOption implements the ValuesOptionInterface.

func NewValuesOption

func NewValuesOption[T comparable, C ColumnType[T]](col C, vs []T) ValuesOption[T]

NewValuesOption returns a new ValuesOption.

func (ValuesOption[T]) GetTargetColumn added in v0.1.0

func (opt ValuesOption[T]) GetTargetColumn() ColumnName

func (ValuesOption[T]) GetValues

func (opt ValuesOption[T]) GetValues() []any

type ValuesOptionInterface

type ValuesOptionInterface interface {
	// GetTargetColumn returns the column the operation processes against.
	GetTargetColumn() ColumnName
	// GetValues returns the values the option carries. Those values are used to query data.
	GetValues() []any
}

ValuesOptionInterface wraps basic method of options which carry multiple values.

Directories

Path Synopsis
internal
sql
Package sql provides a generic interface around SQL (or SQL-like) databases.
Package sql provides a generic interface around SQL (or SQL-like) databases.

Jump to

Keyboard shortcuts

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