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/rigoiot/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.

Expand ▾ Collapse ▴

Documentation

Index

Constants

This section is empty.

Variables

View Source
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)

    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)

      ApplyFieldSelection 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)

        ApplyFiltering applies filtering operator f to gorm instance db.

        func ApplyPagination

        func ApplyPagination(ctx context.Context, db *gorm.DB, p *query.Pagination) *gorm.DB

          ApplyPagination 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)

            ApplySorting applies sorting operator s to gorm instance db.

            func BeginFromContext

            func BeginFromContext(ctx context.Context) (*gorm.DB, error)

            func FieldSelectionStringToGorm

            func FieldSelectionStringToGorm(ctx context.Context, fs string, obj interface{}) ([]string, error)

              FieldSelectionStringToGorm is a shortcut to parse a string into FieldSelection struct and receive a list of associations to preload.

              func FieldSelectionToGorm

              func FieldSelectionToGorm(ctx context.Context, fs *query.FieldSelection, obj interface{}) ([]string, error)

                FieldSelectionToGorm receives FieldSelection struct and returns 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)

                    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 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 LogicalOperatorToGorm

                          func LogicalOperatorToGorm(ctx context.Context, lop *query.LogicalOperator, obj interface{}, pb proto.Message) (string, []interface{}, map[string]struct{}, error)

                            LogicalOperatorToGorm returns GORM Plain SQL representation of the logical operator.

                            func MergeWithMask

                            func MergeWithMask(source, dest interface{}, mask *ptypes.FieldMask) error

                              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 NullConditionToGorm

                                func NullConditionToGorm(ctx context.Context, c *query.NullCondition, obj interface{}, pb proto.Message) (string, []interface{}, map[string]struct{}, error)

                                  NullConditionToGorm returns GORM Plain SQL representation of the null condition.

                                  func NumberArrayConditionToGorm

                                  func NumberArrayConditionToGorm(ctx context.Context, c *query.NumberArrayCondition, obj interface{}, pb proto.Message) (string, []interface{}, map[string]struct{}, error)

                                  func NumberConditionToGorm

                                  func NumberConditionToGorm(ctx context.Context, c *query.NumberCondition, obj interface{}, pb proto.Message) (string, []interface{}, map[string]struct{}, error)

                                    NumberConditionToGorm returns GORM Plain SQL representation of the number condition.

                                    func StringArrayConditionToGorm

                                    func StringArrayConditionToGorm(ctx context.Context, c *query.StringArrayCondition, obj interface{}, pb proto.Message) (string, []interface{}, map[string]struct{}, error)

                                    func StringConditionToGorm

                                    func StringConditionToGorm(ctx context.Context, c *query.StringCondition, obj interface{}, pb proto.Message) (string, []interface{}, map[string]struct{}, error)

                                      StringConditionToGorm returns GORM Plain SQL representation of the string condition.

                                      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 EmptyFieldPathError

                                          type EmptyFieldPathError struct {
                                          }

                                          func (*EmptyFieldPathError) Error

                                          func (e *EmptyFieldPathError) Error() string

                                          type MigrationVersionValidator

                                          type MigrationVersionValidator interface {
                                          	ValidVersion(int64) error
                                          }

                                            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 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) 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.

                                                            Directories

                                                            Path Synopsis