octobe

package module
v0.3.0 Latest Latest
Warning

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

Go to latest
Published: May 13, 2022 License: MIT Imports: 5 Imported by: 0

README

Alt text

License Tag Version Codacy Badge Go Reference

A slim golang package for programmers that love to write raw SQL, but has a problem with boilerplate code. This package will help you structure and unify the way you work with your database.

The main advantage with this library is to enable developers to build a predictable and consistent database layer without losing the feeling of freedom. The octobe library draws inspiration from http handlers, but where handlers interface with the database instead.

Read package documentation at https://pkg.go.dev/github.com/Kansuler/octobe

Usage

WatchTransaction

This is a method that can watch the whole transaction, and where you don't have to define rollback or commit.

WatchTransaction will rollback in case error is returned, otherwise it will proceed to commit.

func Method(db *sql.DB, ctx context.Context) error {
  ob := octobe.New(db)

  // Example of chaining multiple handlers in a transaction
  return ob.WatchTransaction(ctx, func(scheme *octobe.Scheme) error {
    p1 := Product{Name: "home made baguette"}
    err := scheme.Handle(InsertProduct(&p1))
    if err != nil {
      return err
    }

    // Execute other non-database logic that can return an error and rollback the transaction
    err = anotherFunctionWithLogic()
    if err != nil {
      return err
    }

    p2 := Product{Name: "another home made baguette"}
    // For illustration, you can also suppress specific errors in the scheme handler
    err = scheme.Handle(InsertProduct(&p2), octobe.SuppressError(sql.ErrNoRows), octobe.SuppressError(sql.ErrTxDone))
    if err != nil {
      return err
    }

    return nil
  })
}

// InsertProduct will take a pointer of a product, and insert it
// This method could be in a separate package.
func InsertProduct(p *Product) octobe.Handler {
  return func(scheme *octobe.Scheme) error {
    seg := scheme.Segment(`
      INSERT INTO
        products(name)
      VALUES($1)
      RETURNING id
    `)

    seg.Arguments(p.Name)

    // QueryRow and scan of RETURNING from query.
    return seg.QueryRow(&p.ID)
  }
}
Transaction

Run a query with transaction, and chain handlers.

func Method(db *sql.DB, ctx context.Context) error {
  ob := octobe.New(db)
  scheme, err := ob.BeginTx(ctx)
  if err != nil {
    return err
  }

  // WatchRollback returns error that is defined in the scope of this Method.
  // if err is not nil, octobe will perform a rollback.
  defer scheme.WatchRollback(func() error {
    return err
  })

  p := Product{Name: "home made baguette"}
  err = scheme.Handle(InsertProduct(&p))
  if err != nil {
    return err
  }

  // Finish with a commit
  return scheme.Commit()
}

// InsertProduct will take a pointer of a product, and insert it
// This method could be in a separate package.
func InsertProduct(p *Product) octobe.Handler {
  return func(scheme *octobe.Scheme) error {
    seg := scheme.Segment(`
      INSERT INTO
        products(name)
      VALUES($1)
      RETURNING id
    `)

    seg.Arguments(p.Name)

    // QueryRow and scan of RETURNING from query.
    return seg.QueryRow(&p.ID)
  }
}
Basic Handler

Run a simple query where you chain database handlers.

func Method(db *sql.DB, ctx context.Context) error {
  // New creates an octobe context around an *sql.DB instance
  // SuppressError is option and can be used to ignore specific errors, like sql.ErrNoRows"
  ob := octobe.New(db, octobe.SuppressError(sql.ErrNoRows))

  // Begin is used to start without a database transaction
  scheme := ob.Begin(ctx)

  var p1 Product
  // Handle a database query in another method, perfect for separating out queries to a database package
  err := scheme.Handle(SelectNameHandler(1, &p1))
  if err != nil {
    return err
  }

  var p2 Product
  err := scheme.Handle(SelectNameHandler(2, &p2))
    if err != nil {
    return err
  }

  return
}

// Handler func that implements the octobe.Handler
func SelectNameHandler(id string, p *Product) octobe.Handler {
  return func(scheme *octobe.Scheme) error {
    // A segment is a specific query, you can chain many queries in here, or split chained logic into multiple handler funcs if you'd like.
    seg := scheme.Segment(`
      SELECT name FROM products WHERE id = $1;
    `)

    // Arguments takes any input to the query
    seg.Arguments(id)

    // Segment has all the normal methods you expect such as QueryRow, Query and Exec.
    return seg.QueryRow(&p.Name)
  }
}

Contributing

Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.

Please make sure to update tests as appropriate.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ErrNeedInput = errors.New("insert method require at least one argument")

ErrNeedInput is an error that require inputs for the inser method

View Source
var ErrUsed = errors.New("this query has already executed")

ErrUsed is an error that emits if used is true on Segment.

Functions

This section is empty.

Types

type Handler

type Handler func(scheme *Scheme) error

Handler is a signature that can be used for handling database segments in a separate function

type Octobe

type Octobe struct {
	// DB is the database instance
	DB dblike
}

Octobe struct that holds the database session

func New

func New(db dblike) Octobe

New initiates a DB instance and connection.

func (Octobe) Begin

func (ob Octobe) Begin(ctx context.Context) (scheme Scheme)

Begin initiates a query run, but not as a transaction

func (Octobe) BeginTx

func (ob Octobe) BeginTx(ctx context.Context, opts ...*sql.TxOptions) (scheme Scheme, err error)

BeginTx initiates a transaction against database

func (Octobe) WatchTransaction

func (ob Octobe) WatchTransaction(ctx context.Context, cb func(scheme *Scheme) error, opts ...*sql.TxOptions) error

WatchTransaction will perform the whole transaction, or do rollback if error occurred.

type Option added in v0.1.1

type Option interface {
	Type() string
}

Option interface that tells what type of option it is

func SuppressError added in v0.1.1

func SuppressError(err error) Option

SuppressError will tell the library to suppress the error if it occurs in this lib or sql libs

type Scheme

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

Scheme holds context for the duration of the operation

func (*Scheme) Commit

func (scheme *Scheme) Commit() error

Commit will commit a transaction

func (*Scheme) Handle

func (scheme *Scheme) Handle(handler Handler, opts ...Option) error

Handle is a method that handle a handler

func (*Scheme) Rollback

func (scheme *Scheme) Rollback() error

Rollback will rollback a transaction

func (*Scheme) Segment

func (scheme *Scheme) Segment(query string) *Segment

Segment created a new query segment

func (*Scheme) WatchRollback

func (scheme *Scheme) WatchRollback(cb func() error) error

WatchRollback will perform a rollback if an error is given This method can be used as a defer in the function that performs the database operations.

type Segment

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

Segment is a specific query that can be run only once it keeps a few fields for keeping track on the segment

func (*Segment) Arguments

func (segment *Segment) Arguments(args ...interface{}) *Segment

Arguments receives unknown amount of arguments to use in the query

func (*Segment) Exec

func (segment *Segment) Exec() (result sql.Result, err error)

Exec will execute a query. Used for inserts or updates

func (*Segment) Query

func (segment *Segment) Query(cb func(*sql.Rows) error) error

Query will perform a normal query against database that returns rows

func (*Segment) QueryRow

func (segment *Segment) QueryRow(dest ...interface{}) error

QueryRow will return one result and put them into destination pointers

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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