README
¶
GORM
This package contains a set of utilities for famous GORM library. If used together they can significantly help you to enable persistency in your application.
Collection Operators
The package provides some helpers which are able to apply collection operators defined in query package to a GORM query.
Applying query.Filtering
...
// given that Person is a protobuf message and PersonORM is a corresponding GORM model
db, assoc, err = gorm.ApplyFiltering(ctx, db, filtering, &PersonORM{}, &Person{})
if err != nil {
...
}
// Join required associations(for nested field support)
db, err = gorm.JoinAssociations(ctx, db, assoc, &PersonORM{})
if err != nil {
...
}
var people []Person
db.Find(&people)
...
Applying query.Sorting
...
db, assoc, err = gorm.ApplySorting(ctx, db, sorting, &PersonORM{}, &Person{})
if err != nil {
...
}
// Join required associations(for nested field support)
db, err = gorm.JoinAssociations(ctx, db, assoc, &PersonORM{})
if err != nil {
...
}
var people []Person
db.Find(&people)
...
Applying query.Pagination
...
db = gorm.ApplyPagination(ctx, db, pagination, &PersonORM{}, &Person{})
if err != nil {
...
}
var people []Person
db.Find(&people)
...
Applying query.FieldSelection
...
db, err = gorm.ApplyFieldSelection(ctx, db, fields, &PersonORM{}, &Person{})
if err != nil {
...
}
var people []Person
db.Find(&people)
...
Applying everything
...
db, err = gorm.ApplyCollectionOperators(ctx, db, &PersonORM{}, &Person{}, filtering, sorting, pagination, fields)
if err != nil {
...
}
var people []Person
db.Find(&people)
...
Transaction Management
We provide transaction management by offering gorm.Transaction
wrapper and gorm.UnaryServerInterceptor
.
The gorm.Transaction
works as a singleton to prevent an application of creating more than one transaction instance per incoming request.
The gorm.UnaryServerInterceptor
performs management on transactions.
Interceptor creates new transaction on each incoming request and commits it if request finishes without error, otherwise transaction is aborted.
The created transaction is stored in context.Context
and passed to the request handler as usual.
NOTE Client is responsible to call txn.Begin()
to open transaction.
// add gorm interceptor to the chain
server := grpc.NewServer(
grpc.UnaryInterceptor(
grpc_middleware.ChainUnaryServer( // middleware chain
...
gorm.UnaryServerInterceptor(), // transaction management
...
),
),
)
import (
"github.com/infobloxopen/atlas-app-toolkit/gorm"
)
func (s *MyService) MyMethod(ctx context.Context, req *MyMethodRequest) (*MyMethodResponse, error) {
// extract gorm transaction from context
txn, ok := gorm.FromContext(ctx)
if !ok {
return panic("transaction is not opened") // don't panic in production!
}
// start transaction
gormDB := txn.Begin()
if err := gormDB.Error; err != nil {
return nil, err
}
// do stuff with *gorm.DB
return &MyMethodResponse{...}, nil
}
Migration version validation
The toolkit does not require any specific method for database provisioning and setup. However, if golang-migrate or the infobloxopen fork of it is used, a couple helper functions are provided here for verifying that the database version matches a required version without having to import the entire migration package.
Documentation
¶
Index ¶
- Variables
- func ApplyCollectionOperators(ctx context.Context, db *gorm.DB, obj interface{}, pb proto.Message, ...) (*gorm.DB, error)
- func ApplyCollectionOperatorsEx(ctx context.Context, db *gorm.DB, obj interface{}, ...) (*gorm.DB, error)
- func ApplyFieldSelection(ctx context.Context, db *gorm.DB, fs *query.FieldSelection, obj interface{}) (*gorm.DB, error)
- func ApplyFieldSelectionEx(ctx context.Context, db *gorm.DB, fs *query.FieldSelection, obj interface{}, ...) (*gorm.DB, error)
- func ApplyFiltering(ctx context.Context, db *gorm.DB, f *query.Filtering, obj interface{}, ...) (*gorm.DB, map[string]struct{}, error)
- func ApplyFilteringEx(ctx context.Context, db *gorm.DB, f *query.Filtering, obj interface{}, ...) (*gorm.DB, map[string]struct{}, error)
- func ApplyPagination(ctx context.Context, db *gorm.DB, p *query.Pagination) *gorm.DB
- func ApplyPaginationEx(ctx context.Context, db *gorm.DB, p *query.Pagination, c PaginationConverter) *gorm.DB
- func ApplySorting(ctx context.Context, db *gorm.DB, s *query.Sorting, obj interface{}) (*gorm.DB, map[string]struct{}, error)
- func ApplySortingEx(ctx context.Context, db *gorm.DB, s *query.Sorting, obj interface{}, ...) (*gorm.DB, map[string]struct{}, error)
- func BeginFromContext(ctx context.Context) (*gorm.DB, error)
- func BeginWithOptionsFromContext(ctx context.Context, opts *sql.TxOptions) (*gorm.DB, error)
- func FieldSelectionStringToGorm(ctx context.Context, fs string, obj interface{}) ([]string, error)
- func FilterStringToGorm(ctx context.Context, filter string, obj interface{}, pb proto.Message) (string, []interface{}, map[string]struct{}, error)
- func FilteringToGorm(ctx context.Context, m *query.Filtering, obj interface{}, pb proto.Message) (string, []interface{}, map[string]struct{}, error)
- func FilteringToGormEx(ctx context.Context, m *query.Filtering, obj interface{}, ...) (string, []interface{}, map[string]struct{}, error)
- func HandleFieldPath(ctx context.Context, fieldPath []string, obj interface{}) (string, string, error)
- func HandleJSONFieldPath(ctx context.Context, fieldPath []string, obj interface{}, values ...string) (string, string, error)
- func IsJSONCondition(ctx context.Context, fieldPath []string, obj interface{}) bool
- func JoinAssociations(ctx context.Context, db *gorm.DB, assoc map[string]struct{}, obj interface{}) (*gorm.DB, error)
- func JoinInfo(ctx context.Context, obj interface{}, assoc string) (string, []string, []string, error)
- func MergeWithMask(source, dest interface{}, mask *fieldmask.FieldMask) error
- func NewContext(parent context.Context, txn *Transaction) context.Context
- func UnaryServerInterceptor(db *gorm.DB) grpc.UnaryServerInterceptor
- func VerifyMigrationVersion(db *jgorm.DB, v MigrationVersionValidator) error
- type CollectionOperatorsConverter
- type DefaultFieldSelectionConverter
- type DefaultFilteringConditionConverter
- func (converter *DefaultFilteringConditionConverter) LogicalOperatorToGorm(ctx context.Context, lop *query.LogicalOperator, obj interface{}) (string, []interface{}, map[string]struct{}, error)
- func (converter *DefaultFilteringConditionConverter) NullConditionToGorm(ctx context.Context, c *query.NullCondition, obj interface{}) (string, []interface{}, map[string]struct{}, error)
- func (converter *DefaultFilteringConditionConverter) NumberArrayConditionToGorm(ctx context.Context, c *query.NumberArrayCondition, obj interface{}) (string, []interface{}, map[string]struct{}, error)
- func (converter *DefaultFilteringConditionConverter) NumberConditionToGorm(ctx context.Context, c *query.NumberCondition, obj interface{}) (string, []interface{}, map[string]struct{}, error)
- func (converter *DefaultFilteringConditionConverter) StringArrayConditionToGorm(ctx context.Context, c *query.StringArrayCondition, obj interface{}) (string, []interface{}, map[string]struct{}, error)
- func (converter *DefaultFilteringConditionConverter) StringConditionToGorm(ctx context.Context, c *query.StringCondition, obj interface{}) (string, []interface{}, map[string]struct{}, error)
- type DefaultFilteringConditionProcessor
- type DefaultPaginationConverter
- type DefaultPbToOrmConverter
- type DefaultSortingCriteriaConverter
- type EmptyFieldPathError
- type FieldSelectionConverter
- type FilteringConditionConverter
- type FilteringConditionProcessor
- type LogicalOperatorConverter
- type MigrationVersionValidator
- type NullConditionConverter
- type NumberArrayConditionConverter
- type NumberConditionConverter
- type PaginationConverter
- type SortingCriteriaConverter
- type StringArrayConditionConverter
- type StringConditionConverter
- type Transaction
Constants ¶
Variables ¶
var ( ErrCtxTxnMissing = errors.New("Database transaction for request missing in context") ErrCtxTxnNoDB = errors.New("Transaction in context, but DB is nil") )
Functions ¶
func ApplyCollectionOperators ¶
func ApplyCollectionOperators(ctx context.Context, db *gorm.DB, obj interface{}, pb proto.Message, f *query.Filtering, s *query.Sorting, p *query.Pagination, fs *query.FieldSelection) (*gorm.DB, error)
Deprecated: use ApplyCollectionOperatorsEx instead ApplyCollectionOperators applies collection operators to gorm instance db.
func ApplyFieldSelection ¶
func ApplyFieldSelection(ctx context.Context, db *gorm.DB, fs *query.FieldSelection, obj interface{}) (*gorm.DB, error)
Deprecated: use ApplyFieldSelectionEx instead ApplyFieldSelection applies field selection operator fs to gorm instance db.
func ApplyFieldSelectionEx ¶
func ApplyFieldSelectionEx(ctx context.Context, db *gorm.DB, fs *query.FieldSelection, obj interface{}, c FieldSelectionConverter) (*gorm.DB, error)
ApplyFieldSelectionEx applies field selection operator fs to gorm instance db.
func ApplyFiltering ¶
func ApplyFiltering(ctx context.Context, db *gorm.DB, f *query.Filtering, obj interface{}, pb proto.Message) (*gorm.DB, map[string]struct{}, error)
Deprecated: use ApplyFilteringEx instead ApplyFiltering applies filtering operator f to gorm instance db.
func ApplyFilteringEx ¶
func ApplyFilteringEx(ctx context.Context, db *gorm.DB, f *query.Filtering, obj interface{}, c FilteringConditionConverter) (*gorm.DB, map[string]struct{}, error)
ApplyFiltering applies filtering operator f to gorm instance db.
func ApplyPagination ¶
ApplyPagination applies pagination operator p to gorm instance db.
func ApplyPaginationEx ¶
func ApplyPaginationEx(ctx context.Context, db *gorm.DB, p *query.Pagination, c PaginationConverter) *gorm.DB
ApplyPaginationEx applies pagination operator p to gorm instance db.
func ApplySorting ¶
func ApplySorting(ctx context.Context, db *gorm.DB, s *query.Sorting, obj interface{}) (*gorm.DB, map[string]struct{}, error)
Deprecated: use ApplySortingEx instead ApplySorting applies sorting operator s to gorm instance db.
func ApplySortingEx ¶
func ApplySortingEx(ctx context.Context, db *gorm.DB, s *query.Sorting, obj interface{}, c SortingCriteriaConverter) (*gorm.DB, map[string]struct{}, error)
ApplySorting applies sorting operator s to gorm instance db.
func BeginFromContext ¶
BeginFromContext will extract transaction wrapper from context and start new transaction. As result new instance of `*gorm.DB` will be returned. Error will be returned in case either transaction or db connection info is missing in context. Gorm specific error can be checked by `*gorm.DB.Error`.
func BeginWithOptionsFromContext ¶
BeginWithOptionsFromContext will extract transaction wrapper from context and start new transaction, options can be specified to control isolation level for transaction. As result new instance of `*gorm.DB` will be returned. Error will be returned in case either transaction or db connection info is missing in context. Gorm specific error can be checked by `*gorm.DB.Error`.
func FieldSelectionStringToGorm ¶
FieldSelectionStringToGorm is a shortcut to parse a string into FieldSelection struct and receive a list of associations to preload.
func FilterStringToGorm ¶
func FilterStringToGorm(ctx context.Context, filter string, obj interface{}, pb proto.Message) (string, []interface{}, map[string]struct{}, error)
FilterStringToGorm is a shortcut to parse a filter string using default FilteringParser implementation and call FilteringToGorm on the returned filtering expression.
func FilteringToGorm ¶
func FilteringToGorm(ctx context.Context, m *query.Filtering, obj interface{}, pb proto.Message) (string, []interface{}, map[string]struct{}, error)
Deprecated: Use FilteringToGormEx instead FilteringToGorm returns GORM Plain SQL representation of the filtering expression.
func FilteringToGormEx ¶
func FilteringToGormEx(ctx context.Context, m *query.Filtering, obj interface{}, c FilteringConditionConverter) (string, []interface{}, map[string]struct{}, error)
FilteringToGorm returns GORM Plain SQL representation of the filtering expression.
func HandleFieldPath ¶
func HandleFieldPath(ctx context.Context, fieldPath []string, obj interface{}) (string, string, error)
HandleFieldPath converts fieldPath to appropriate db string for use in where/order by clauses according to obj GORM model. If fieldPath cannot be found in obj then original fieldPath is returned to allow tables joined by a third party. If association join is required to resolve the field path then it's name is returned as a second return value.
func HandleJSONFieldPath ¶
func HandleJSONFieldPath(ctx context.Context, fieldPath []string, obj interface{}, values ...string) (string, string, error)
HandleJSONFiledPath translate field path to JSONB path for postgres jsonb
func IsJSONCondition ¶
TODO: add supprt for embeded objects
func JoinAssociations ¶
func JoinAssociations(ctx context.Context, db *gorm.DB, assoc map[string]struct{}, obj interface{}) (*gorm.DB, error)
JoinAssociations joins obj's associations from assoc to the current gorm query.
func JoinInfo ¶
func JoinInfo(ctx context.Context, obj interface{}, assoc string) (string, []string, []string, error)
JoinInfo extracts the following information for assoc association of obj: - association table name - source join keys - target join keys
func MergeWithMask ¶
MergeWithMask will take the fields of `source` that are included as paths in `mask` and write them to the corresponding fields of `dest`
func NewContext ¶
func NewContext(parent context.Context, txn *Transaction) context.Context
NewContext returns a new Context that carries value txn.
func UnaryServerInterceptor ¶
func UnaryServerInterceptor(db *gorm.DB) grpc.UnaryServerInterceptor
UnaryServerInterceptor returns grpc.UnaryServerInterceptor that manages a `*Transaction` instance. New *Transaction instance is created before grpc.UnaryHandler call. Client is responsible to call `txn.Begin()` to open transaction. If call of grpc.UnaryHandler returns with an error the transaction is aborted, otherwise committed.
func VerifyMigrationVersion ¶
func VerifyMigrationVersion(db *jgorm.DB, v MigrationVersionValidator) error
VerifyMigrationVersion checks the schema_migrations table of the db passed against the ValidVersion function of the given validator, returning an error for an invalid version or a dirty database
Types ¶
type CollectionOperatorsConverter ¶
type CollectionOperatorsConverter interface { FilteringConditionConverter SortingCriteriaConverter FieldSelectionConverter PaginationConverter }
func NewDefaultPbToOrmConverter ¶
func NewDefaultPbToOrmConverter(pb proto.Message) CollectionOperatorsConverter
NewDefaultPbToOrmConverter creates default converter for all collection operators
type DefaultFieldSelectionConverter ¶
type DefaultFieldSelectionConverter struct{}
DefaultFieldSelectionConverter performs default convertion for FieldSelection collection operator
func (*DefaultFieldSelectionConverter) FieldSelectionToGorm ¶
func (converter *DefaultFieldSelectionConverter) FieldSelectionToGorm(ctx context.Context, fs *query.FieldSelection, obj interface{}) ([]string, error)
FieldSelectionToGorm receives FieldSelection struct and returns a list of associations to preload.
type DefaultFilteringConditionConverter ¶
type DefaultFilteringConditionConverter struct {
Processor FilteringConditionProcessor
}
DefaultFilteringConditionConverter performs default convertion for Filter collection operator
func (*DefaultFilteringConditionConverter) LogicalOperatorToGorm ¶
func (converter *DefaultFilteringConditionConverter) LogicalOperatorToGorm(ctx context.Context, lop *query.LogicalOperator, obj interface{}) (string, []interface{}, map[string]struct{}, error)
LogicalOperatorToGorm returns GORM Plain SQL representation of the logical operator.
func (*DefaultFilteringConditionConverter) NullConditionToGorm ¶
func (converter *DefaultFilteringConditionConverter) NullConditionToGorm(ctx context.Context, c *query.NullCondition, obj interface{}) (string, []interface{}, map[string]struct{}, error)
NullConditionToGorm returns GORM Plain SQL representation of the null condition.
func (*DefaultFilteringConditionConverter) NumberArrayConditionToGorm ¶
func (converter *DefaultFilteringConditionConverter) NumberArrayConditionToGorm(ctx context.Context, c *query.NumberArrayCondition, obj interface{}) (string, []interface{}, map[string]struct{}, error)
func (*DefaultFilteringConditionConverter) NumberConditionToGorm ¶
func (converter *DefaultFilteringConditionConverter) NumberConditionToGorm(ctx context.Context, c *query.NumberCondition, obj interface{}) (string, []interface{}, map[string]struct{}, error)
NumberConditionToGorm returns GORM Plain SQL representation of the number condition.
func (*DefaultFilteringConditionConverter) StringArrayConditionToGorm ¶
func (converter *DefaultFilteringConditionConverter) StringArrayConditionToGorm(ctx context.Context, c *query.StringArrayCondition, obj interface{}) (string, []interface{}, map[string]struct{}, error)
func (*DefaultFilteringConditionConverter) StringConditionToGorm ¶
func (converter *DefaultFilteringConditionConverter) StringConditionToGorm(ctx context.Context, c *query.StringCondition, obj interface{}) (string, []interface{}, map[string]struct{}, error)
StringConditionToGorm returns GORM Plain SQL representation of the string condition.
type DefaultFilteringConditionProcessor ¶
type DefaultFilteringConditionProcessor struct {
// contains filtered or unexported fields
}
DefaultFilteringConditionProcessor processes filter operator conversion
func (*DefaultFilteringConditionProcessor) ProcessStringCondition ¶
func (p *DefaultFilteringConditionProcessor) ProcessStringCondition(ctx context.Context, fieldPath []string, value string) (interface{}, error)
ProcessStringCondition processes a string condition to GORM Plain SQL representation
type DefaultPaginationConverter ¶
type DefaultPaginationConverter struct{}
DefaultPaginationConverter performs default convertion for Paging collection operator
func (*DefaultPaginationConverter) PaginationToGorm ¶
func (converter *DefaultPaginationConverter) PaginationToGorm(ctx context.Context, p *query.Pagination) (offset, limit int32)
type DefaultPbToOrmConverter ¶
type DefaultPbToOrmConverter struct { DefaultFilteringConditionConverter DefaultSortingCriteriaConverter DefaultFieldSelectionConverter DefaultPaginationConverter }
DefaultPbToOrmConverter performs default convertion for all collection operators
type DefaultSortingCriteriaConverter ¶
type DefaultSortingCriteriaConverter struct{}
DefaultSortingCriteriaConverter performs default convertion for Sorting collection operator
func (*DefaultSortingCriteriaConverter) SortingCriteriaToGorm ¶
func (converter *DefaultSortingCriteriaConverter) SortingCriteriaToGorm(ctx context.Context, cr *query.SortCriteria, obj interface{}) (string, string, error)
type EmptyFieldPathError ¶
type EmptyFieldPathError struct { }
func (*EmptyFieldPathError) Error ¶
func (e *EmptyFieldPathError) Error() string
type FieldSelectionConverter ¶
type FilteringConditionConverter ¶
type FilteringConditionConverter interface { LogicalOperatorConverter NullConditionConverter StringConditionConverter StringArrayConditionConverter NumberConditionConverter NumberArrayConditionConverter }
type MigrationVersionValidator ¶
MigrationVersionValidator has a function for checking the database version
func MaxVersionFrom ¶
func MaxVersionFrom(path string) (MigrationVersionValidator, error)
MaxVersionFrom returns a MigrationVersionValidator with a target based on the highest numbered migration file detected in the given directory
func VersionExactly ¶
func VersionExactly(version int64) MigrationVersionValidator
VersionExactly returns a MigrationVersionValidator with a specific target version
func VersionRange ¶
func VersionRange(lower, upper int64) MigrationVersionValidator
VersionRange returns a MigrationVersionValidator with a given lower and upper bound
type NullConditionConverter ¶
type PaginationConverter ¶
type PaginationConverter interface {
PaginationToGorm(ctx context.Context, p *query.Pagination) (offset, limit int32)
}
type Transaction ¶
type Transaction struct {
// contains filtered or unexported fields
}
Transaction serves as a wrapper around `*gorm.DB` instance. It works as a singleton to prevent an application of creating more than one transaction instance per incoming request.
func FromContext ¶
func FromContext(ctx context.Context) (txn *Transaction, ok bool)
FromContext returns the *Transaction value stored in ctx, if any.
func NewTransaction ¶
func NewTransaction(db *gorm.DB) Transaction
func (*Transaction) AddAfterCommitHook ¶
func (t *Transaction) AddAfterCommitHook(hooks ...func(context.Context))
func (*Transaction) Begin ¶
func (t *Transaction) Begin() *gorm.DB
Begin starts new transaction by calling `*gorm.DB.Begin()` Returns new instance of `*gorm.DB` (error can be checked by `*gorm.DB.Error`)
func (*Transaction) BeginWithOptions ¶
func (t *Transaction) BeginWithOptions(opts *sql.TxOptions) *gorm.DB
BeginWithOptions starts new transaction by calling `*gorm.DB.BeginTx()` Returns new instance of `*gorm.DB` (error can be checked by `*gorm.DB.Error`)
func (*Transaction) Commit ¶
func (t *Transaction) Commit(ctx context.Context) error
Commit finishes transaction by calling `*gorm.DB.Commit()` Reset current transaction and returns an error if any.
func (*Transaction) Rollback ¶
func (t *Transaction) Rollback() error
Rollback terminates transaction by calling `*gorm.DB.Rollback()` Reset current transaction and returns an error if any.