uorm

package
v0.0.0-...-ebe5785 Latest Latest
Warning

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

Go to latest
Published: May 27, 2024 License: MIT Imports: 15 Imported by: 0

README

Database

This package provides four main types:

  • DBConfig: contains the different parameters to be configured.
  • DBHolder: creates the connection to the database and runs SQL migrations.
  • TestDBHolder: is a wrapper of DBHolder that provides a Reset() method that cleans the database and runs again all migrations.
  • DBrepository: is built on top of GORM to provide easier transaction management as well as methods like Save or Find.

Usage

DBConfig
// Returns a *DBConfig initialized by env variables
// Host                 string `env:"POSTGRES_HOST" envDefault:"localhost"`
// Port                 string `env:"POSTGRES_PORT" envDefault:"5432"`
// User                 string `env:"POSTGRES_USER" envDefault:"postgres"`
// Password             string `env:"POSTGRES_PASSWORD" envDefault:"postgres"`
// DatabaseName         string `env:"POSTGRES_DATABASE" envDefault:"postgres"`
// SchemaName           string `env:"POSTGRES_SCHEMA" envDefault:"public"`
// MigrationsDir        string `env:"POSTGRES_MIGRATIONS_DIR" envDefault:"./migrations"`
// RunMigrationsOnReset bool   `env:"POSTGRES_RUN_MIGRATIONS" envDefault:"false"`
dbConfig := NewDBConfigFromEnv()
DBHolder
// Returns a *DBHolder initialized with the provided config.
// In case the *DBConfig object has zero values, those will
// be filled with default values.
dbHolder := NewDBHolder(dbConfig)
// Run SQL migrations found in the folder specified by DBConfig.MigrationsDir
dbHolder.RunMigrations()
DBrepository
type Resource struct {
    ID     string
    Name   string
    Random int
}
// This map will be used in the method Find(context.Context, url.values) to use the filters
// and sorters provided in the url.values parameter. In case the url.values contains a filter
// that it is not in the filters map, it will return an error.
filters := map[string]filters.Filter[*Resource]{
    "id":            filters.TextField[*Resource]("id"),
    "name":          filters.TextField[*Resource]("name"),
    "random":        filters.NumField[*Resource]("random"),
    "sort":          filters.Sorter[*Resource]("name"),
}
repository := NewDBRepository[*Resource](dbHolder, filters)
Transactions
func DoSomething(ctx context.Context) (rErr error) {}
    // ctx must be of type context.Context
    // repository must implement the Transactional interface
    // type Transactional interface {
    //     Begin(ctx context.Context) (context.Context, error)
    //     Commit(ctx context.Context) error
    //     Rollback(ctx context.Context)
    // }
    // DBrepository already implements it.
    // The returned ctx has the transaction within it.
    ctx, err := BeginTx(ctx, repository)
    // If there is an error, the transaction could not be created.

    // Expects an *error as last parameter since it will
    // automatically perform a rollback if the function
    // finishes with an error or a commit in case there is not error.
    defer EndTx(ctx, repository, &rErr)
    // do stuff
    err = repository.Save(ctx, &Resource{
        ID: "an_ID",
        Name: "Name"
        Random: 4,
    })
    // Check err

    // do more stuff
    return err // or nil
}
var obj Resource
var list []*Resource

// It will return the resource found in the variable obj.
// Notice the &.
err = repository.FindByID(ctx, "an_ID", &obj)

// Filtering by id
v := url.values{}
v.Add("id", "an_ID")
// It is necessary to pass the list parameter so
// internally can infer the type and table to use to
// request the data.
// resourcePage is of type:
// type ResourcePage[T any] struct {
//     Total  int64 `json:"total"`
//     Limit  int64 `json:"limit"`
//     Offset int64 `json:"offset"`
//
//     In this example, *[]*Resource.
//     Resources []T `json:"resources"`
// }
// In this example, repository.Find(...) return type is ResourcePage[*Resource].
resourcePage, err = repository.Find(ctx, v)

// Filtering by name
v2 := url.values{}
v2.Add("name", "the name to filter")
resourcePage, err = repository.Find(ctx, v)

// Filtering by a number
v2 := url.values{}
v2.Add("random", "4")
resourcePage, err = repository.Find(ctx, v)

// Sorting by name field in ascending order
v2 := url.values{}
v2.Add("sort", "name")
resourcePage, err = repository.Find(ctx, v)

// Sorting by name field in descending order
v2 := url.values{}
v2.Add("sort", "-name")
resourcePage, err = repository.Find(ctx, v)

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type DBHolder

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

func NewDBHolder

func NewDBHolder(config *udatabase.DBConfig) *DBHolder

Returns a *DBHolder initialized with the provided config. In case the *DBConfig object has zero values, those will be filled with default values.

func (*DBHolder) GetDBInstance

func (d *DBHolder) GetDBInstance(ctx context.Context) *gorm.DB

GetDBInstance returns the inner database object *gorm.DB provided by GORM. More on GORM here: https://gorm.io/

func (*DBHolder) RunMigrations

func (d *DBHolder) RunMigrations() error

RunMigrations runs SQL migrations found in the folder specified by DBConfig.MigrationsDir

type DBrepository

type DBrepository[T any] struct {
	// contains filtered or unexported fields
}

DBrepository is built on top of GORM to provide easier transaction management as well as methods like Save or Find.

func NewDBRepository

func NewDBRepository[T any](dbHolder *DBHolder, filtersMap map[string]uormFilters.Filter[T]) *DBrepository[T]

NewDBRepository returns a DBrepository. requires a that map will be used in the method Find(context.Context, url.values) to use the filters and sorters provided in the url.values{} parameter. In case the url.values contains a filter that it is not in the filters map, it will return an error.

func (*DBrepository[T]) Begin

func (r *DBrepository[T]) Begin(ctx context.Context) (context.Context, error)

Begin opens a new transaction. NOTE: Nested transactions not supported.

func (*DBrepository[T]) Commit

func (r *DBrepository[T]) Commit(ctx context.Context) error

Commit closes and confirms the current transaction.

func (*DBrepository[T]) Create

func (r *DBrepository[T]) Create(ctx context.Context, value T) error

Create is a function that creates the resource in the database.

func (*DBrepository[T]) Find

func (r *DBrepository[T]) Find(ctx context.Context, v url.Values) (*udatabase.ResourcePage[T], error)

Find returns a list of elements matching the provided filters. Usage:

type Resource struct {...}
var list []*Resource
repository.Find(ctx, url.values{})

resourcePage is of type:

type ResourcePage[T any] struct {
	   Total  int64 `json:"total"`
	   Limit  int64 `json:"limit"`
	   Offset int64 `json:"offset"`

    // Resource will be a pointer to the type passed as
    // dst parameter in Find method. In this example,
    // *[]*Resource.
    Resources []T`json:"resources"`
}

Filter:

v := url.values{}
v.Add("field", "value to use to filter")
v.Add("sort", "field")  // sort in ascending order
v.Add("sort", "-field") // sort in descending order

func (*DBrepository[T]) FindByID

func (r *DBrepository[T]) FindByID(ctx context.Context, id string, dst any) error

FindByID returns the resource found in the variable dst. Usage:

type Resource struct {...}
var obj Resource
repository.FindByID(ctx, "an_ID", &obj)

func (*DBrepository[T]) FindWithFilters

func (r *DBrepository[T]) FindWithFilters(ctx context.Context,
	fs ...uormFilters.ValuedFilter[T]) (*udatabase.ResourcePage[T], error)

func (*DBrepository[T]) GetDBInstance

func (r *DBrepository[T]) GetDBInstance(ctx context.Context) *gorm.DB

func (*DBrepository[T]) HandleSaveOrUpdateError

func (r *DBrepository[T]) HandleSaveOrUpdateError(err error) error

HandleSaveOrUpdateError in case of running an INSERT/UPDATE query, this method provides an easy way of checking if the returned error is nil or if it violates a PRIMARY KEY/UNIQUE constraint.

func (*DBrepository[T]) IsResourceNotFound

func (r *DBrepository[T]) IsResourceNotFound(err error) bool

IsResourceNotFound in case of running custom SELECT queries using *gorm.DB, this method provides an easy way of checking if the error returned is a NotFound or other type.

func (*DBrepository[T]) ParseFilters

func (r *DBrepository[T]) ParseFilters(v url.Values) ([]uormFilters.ValuedFilter[T], error)

func (*DBrepository[T]) Rollback

func (r *DBrepository[T]) Rollback(ctx context.Context)

Rollback cancels the current transaction.

func (*DBrepository[T]) Save

func (r *DBrepository[T]) Save(ctx context.Context, value T) error

Save is a combination function. If save value does not contain primary key, it will execute Create, otherwise it will execute Update (with all fields).

type Filterer

type Filterer[T any] interface {
	ParseFilters(values url.Values) ([]filters.ValuedFilter[T], error)
}

type FiltererMock

type FiltererMock[T any] struct {
	mock.Mock
}

func (*FiltererMock[T]) ParseFilters

func (m *FiltererMock[T]) ParseFilters(values url.Values) ([]filters.ValuedFilter[T], error)

type TestDBHolder

type TestDBHolder struct {
	*DBHolder
}

func NewTestDBHolder

func NewTestDBHolder(schemaName string) *TestDBHolder

func (*TestDBHolder) Reset

func (d *TestDBHolder) Reset()

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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