pg

package module
v1.0.69 Latest Latest
Warning

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

Go to latest
Published: May 22, 2025 License: MPL-2.0 Imports: 7 Imported by: 0

README

Golang module for CRUD database operations management

The library is simplifying write database access layer in Go programs by supplying ORM approach - defining Entities and Repositories with minimal required code and utilize them during your regular development without needs to write a lot of boilerplate code.

Unlike other ORM libraries and frameworks this library doesn't use reflection and have other performance relevant code optimisation therefore has no performance penalty comparing to all-by-hand written code

Examples

1. Create specific entity/repository

Up to date working examples locates here and here


package repository

import (
	"context"
	sq "github.com/Masterminds/squirrel"
	"github.com/jackc/pgx/v5"
	"github.com/simpleGorm/pg"
)

// Mandatory declare ID field
type TestObj struct {
	ID     int64
	Field1 int64
	Field2 string
}

type TestObjRepository struct {
	pg.Repository[TestObj]
}

const TABLE_NAME = "TestObjTable"

var increaseField1Builder = sq.Update(TABLE_NAME).PlaceholderFormat(sq.Dollar).
	Set("field1", sq.Expr("field1 + 1")).Suffix("RETURNING id, field1, field2")

func NewMyObjRepository(db pg.DbClient) TestObjRepository {
	return TestObjRepository{
		pg.NewPostgreRepository[TestObj](
			db,
			sq.Insert(TABLE_NAME).PlaceholderFormat(sq.Dollar).Columns("field1", "field2"),
			sq.Select("id", "field1", "field2").PlaceholderFormat(sq.Dollar).From(TABLE_NAME),
			sq.Update(TABLE_NAME).PlaceholderFormat(sq.Dollar),
			sq.Delete(TABLE_NAME).PlaceholderFormat(sq.Dollar),
			myObjConverter),
	}
}

func myObjConverter(row pgx.Row) TestObj {
	var myObj TestObj
	if err := row.Scan(&myObj.ID, &myObj.Field1, &myObj.Field2); err != nil {
		panic(err)
	}
	return myObj
}

func (repo *TestObjRepository) GetOneByField2(ctx context.Context, field2 string) TestObj {
	list := repo.GetBy(ctx, sq.Eq{"field2": field2})
	if list != nil && len(list) > 0 {
		return (list)[0]
	}
	var ret TestObj
	return ret
}

func (repo *TestObjRepository) IncreaseField1(ctx context.Context, id int64) int64 {
	updated := repo.UpdateReturning(ctx, increaseField1Builder.Where(sq.Eq{"id": id}))
	return updated.Field1
}

2. Usage

Up to date working examples locates here and here

    DSN := "connection string"
    ctx := context.Background()
    dbClient, err := pg.NewPgDBClient(ctx, DSN)
    
    // Define dbclient gracefull shutdown
    closer.Add(dbClient.Close)
    defer func() {
        if r := recover(); r != nil {
            // handle panic errors
        }
        // Close db connection
        closer.CloseAll()
        closer.Wait()
    }()
	
    myRepository := NewMyRepository(dbClient)
    field1_value := 10
    field2_value := "field2_value"
    id := myRepository.Create(ctx, field1_value, field2_value)
    ....
    myRepository.GetById(ctx,id)
    ....
    myRepository.GetByField2(ctx, field2_value)
    ....
    myRepository.GetAll(ctx)
    ....
    newField1Value := myRepository.IncreaseField1(ctx, id)
    print(newField1Value) // 11
    .....
    
   fields := map[string]interface{}{"field2": "updated_field2"}

   updated := myRepository.Update(ctx, fields, id)
   if updated != 1 {
      return errors.New("MyObject not updated")
   }
   
   where := squirrel.Eq{"field2": field2}
   updated = myRepository.UpdateCollection(ctx, fields, where)
   if updated == 0 {
      return errors.New("No objects was updated")
   }
    
    // Transaction
    err := dbClient.RunTransaction(ctx, transaction.TxOptions{IsoLevel: transaction.ReadCommitted},
		func(ctx context.Context) error {
			id1 := myRepository.Create(ctx, ...)
			id2 := myRepository.Create(ctx, ...)
			if(...some error condition...){
			    // Rollback
			    return errors.Wrap(err, "Error condition achieved")
			}
			// Commit
			return nil
		}
   )
   if err != nil {
     ...  // handle the error
   }

Documentation

Index

Constants

View Source
const (
	RETURNING_ID = "RETURNING id"
)

Variables

This section is empty.

Functions

This section is empty.

Types

type Closer added in v1.0.49

type Closer interface {
	Close() error
}

type DbApi

type DbApi interface {
	pg_api.SQLExecutor
	pg_api.Transactor
	Pinger
	Closer
}

type DbClient

type DbClient struct {
	DbApi
}

func NewDBClient

func NewDBClient(ctx context.Context, dsn string) (DbClient, error)

func (DbClient) Logger added in v1.0.49

func (db DbClient) Logger() *slog.Logger

func (DbClient) SetLogger added in v1.0.49

func (db DbClient) SetLogger(l *slog.Logger)

type IRepository

type IRepository interface {
	Create(ctx context.Context, values ...interface{}) int64
	Upsert(ctx context.Context, values ...interface{}) int64
	GetById(ctx context.Context, id int64) any
	GetAll(ctx context.Context) []any
	GetBy(ctx context.Context, where sq.Sqlizer) []any
	GetByBuilder(ctx context.Context, selectBuilder sq.SelectBuilder) []any
	Delete(ctx context.Context, id int64) int64
	UpdateCollection(ctx context.Context, fields map[string]interface{}, where sq.Sqlizer) int64
	Update(ctx context.Context, fields map[string]interface{}, id int64) int64
	UpdateReturning(ctx context.Context, builder sq.UpdateBuilder, entityConverter func(row pgx.Row) any) any
}

type Identifiable

type Identifiable interface {
	GetID() int64
}

type Pinger

type Pinger interface {
	Ping(ctx context.Context) error
}
type Related interface {
	GetParentID() int64
	PushToParent(parent any)
}

type Relation

type Relation[R any] struct {
	ForeignKey     string
	Repo           Repository[R]
	ParentIdGetter func(R) int64
}

func WrapRelation

func WrapRelation[R any](r Relation[R]) Relation[any]

func (Relation[R]) GetForeignKey

func (r Relation[R]) GetForeignKey() string

func (Relation[R]) GetParentId

func (r Relation[R]) GetParentId(child R) int64

type Repository

type Repository[T any] struct {
	DB            DbClient
	InsertBuilder sq.InsertBuilder
	SelectBuilder sq.SelectBuilder
	UpdateBuilder sq.UpdateBuilder
	DeleteBuilder sq.DeleteBuilder
	UpsertBuilder sq.InsertBuilder
	ExtraBuilders []builder.Builder
	Converter     func(row pgx.Row) any // type is any to allow generalization
	Relations     []Relation[any]       // the relation type is any because it really any entity
	AddRelated    func(*T, any)
	AddRelation   func(Relation[any])
	// contains filtered or unexported fields
}

func NewRepository

func NewRepository[T any](
	anchor T,
	db DbClient,
	insertBuilder sq.InsertBuilder,
	selectBuilder sq.SelectBuilder,
	updateBuilder sq.UpdateBuilder,
	deleteBuilder sq.DeleteBuilder,
	upsertBuilder sq.InsertBuilder,
	extraBuilders []builder.Builder,
	converter func(row pgx.Row) *T) Repository[T]

func WrapRepository

func WrapRepository[R any](repo Repository[R]) Repository[any]

func (Repository[T]) Create

func (repo Repository[T]) Create(ctx context.Context, values ...interface{}) int64

func (Repository[T]) Delete

func (repo Repository[T]) Delete(ctx context.Context, id int64) int64

func (Repository[T]) GetAll

func (repo Repository[T]) GetAll(ctx context.Context) []T

func (Repository[T]) GetBy

func (repo Repository[T]) GetBy(ctx context.Context, where sq.Sqlizer) []T

func (Repository[T]) GetByBuilder added in v1.0.68

func (repo Repository[T]) GetByBuilder(ctx context.Context, selectBuilder sq.SelectBuilder) []T

func (Repository[T]) GetById

func (repo Repository[T]) GetById(ctx context.Context, id int64) T

func (Repository[T]) Update

func (repo Repository[T]) Update(ctx context.Context, fields map[string]interface{}, id int64) int64

func (Repository[T]) UpdateCollection

func (repo Repository[T]) UpdateCollection(ctx context.Context, fields map[string]interface{}, where sq.Sqlizer) int64

func (Repository[T]) UpdateReturning

func (repo Repository[T]) UpdateReturning(ctx context.Context, builder sq.UpdateBuilder) any

func (Repository[T]) UpdateReturningWithExtendedConverter

func (repo Repository[T]) UpdateReturningWithExtendedConverter(ctx context.Context, builder sq.UpdateBuilder, entityConverter func(row pgx.Row) any) any

func (Repository[T]) Upsert added in v1.0.66

func (repo Repository[T]) Upsert(ctx context.Context, values ...interface{}) int64

Directories

Path Synopsis
internal
pkg

Jump to

Keyboard shortcuts

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