pg

package module
v0.0.0-...-372f682 Latest Latest
Warning

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

Go to latest
Published: Feb 7, 2025 License: MIT Imports: 15 Imported by: 0

README

PG Middleware

PG middleware is a package for Iris web framework that provides easy and type-safe access to PostgreSQL database.

Features

  • Supports PostgreSQL 9.5 and above.
  • Uses pg package and pgx driver under the hood.
  • Supports transactions, schema creation and validation, query tracing and error handling.
  • Allows registering custom types and table models using a schema object.
  • Provides a generic repository interface for common CRUD operations.

Installation

To install PG middleware, use the following command:

go get github.com/iris-contrib/middleware/pg@master

Usage

To use PG middleware, you need to:

  1. Import the package in your code:
import (
	"github.com/kataras/iris/v12"

	"github.com/iris-contrib/middleware/pg"
)
  1. Define your database table models as structs with json and pg tags:
// The Customer database table model.
type Customer struct {
	ID   string `json:"id" pg:"type=uuid,primary"`
	Name string `json:"name" pg:"type=varchar(255)"`
}
  1. Create a schema object and register your models:
schema := pg.NewSchema()
schema.MustRegister("customers", Customer{})
  1. Create a PG middleware instance with the schema and database options:
opts := pg.Options{
	Host:          "localhost",
	Port:          5432,
	User:          "postgres",
	Password:      "admin!123",
	DBName:        "test_db",
	Schema:        "public",
	SSLMode:       "disable",
	Transactional: true, // or false to disable the transactional feature.
	Trace:         true, // or false to production to disable query logging.
	CreateSchema:  true, // true to create the schema if it doesn't exist.
	CheckSchema:   true, // true to check the schema for missing tables and columns.
	ErrorHandler: func(ctx iris.Context, err error) {
		ctx.StopWithError(iris.StatusInternalServerError, err)
	},
}

p := pg.New(schema, opts)
  1. Attach the middleware handler to your Iris app or routes:
app := iris.New()

postgresMiddleware := newPostgresMiddleware()

{
	customerAPI := app.Party("/api/customer", postgresMiddleware)
	customerAPI.Post("/", createCustomer)
	customerAPI.Get("/{id:uuid}", getCustomer)
}
  1. Use the pg.DB or pg.Repository package-level functions to access the database instance or the repository interface in your handlers:
func createCustomer(ctx iris.Context) {
	var payload = struct {
		Name string `json:"name"`
	}{}
	err := ctx.ReadJSON(&payload)
	if err != nil {
		ctx.StopWithError(iris.StatusBadRequest, err)
		return
	}

	// Get the current database instance through pg.DB middleware package-level function.
	// db := pg.DB(ctx)
	// [Work with db instance...]
	// OR, initialize a new repository of Customer type and work with it (type-safety).
	customers := pg.Repository[Customer](ctx)

	// Insert a new Customer.
	customer := Customer{
		Name: payload.Name,
	}
	err = customers.InsertSingle(ctx, customer, &customer.ID)
	if err != nil {
		ctx.StopWithError(iris.StatusInternalServerError, err)
		return
	}

	// Display the result ID.
	ctx.StatusCode(iris.StatusCreated)
	ctx.JSON(iris.Map{"id": customer.ID})
}

func getCustomer(ctx iris.Context) {
	// Get the id from the path parameter.
	id := ctx.Params().Get("id")

	// Get the repository of Customer type through pg.Repository middleware package-level function.
	customers := pg.Repository[Customer](ctx)

	// Get the customer by the id.
	customer, err := customers.SelectByID(ctx, id)
	if err != nil {
		if pg.IsErrNoRows(err) {
			ctx.StopWithStatus(iris.StatusNotFound)
		} else {
			ctx.StopWithError(iris.StatusInternalServerError, err)
		}

		return
	}

	// Display the retrieved Customer.
	ctx.JSON(customer)
}

Examples

You can find more examples of using PG middleware in the examples folder.

License

PG middleware is licensed under the MIT License.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var DefaultErrorHandler = func(ctx iris.Context, err error) bool {
	if _, ok := pg.IsErrDuplicate(err); ok {
		errors.AlreadyExists.Details(ctx, "resource already exists", err.Error())
	} else if _, ok = pg.IsErrInputSyntax(err); ok {
		errors.InvalidArgument.Err(ctx, err)
	} else if errors.Is(err, pg.ErrNoRows) {
		errors.NotFound.Details(ctx, "resource not found", err.Error())
	} else if _, ok = pg.IsErrForeignKey(err); ok {
		errors.InvalidArgument.Message(ctx, "reference entity does not exist")
	} else if errors.Is(err, strconv.ErrSyntax) {
		errors.InvalidArgument.Err(ctx, err)
	} else if _, ok = pg.IsErrInputSyntax(err); ok {
		errors.InvalidArgument.Err(ctx, err)
	} else if errMsg := err.Error(); strings.Contains(errMsg, "syntax error in") ||
		strings.Contains(errMsg, "invalid input syntax") {
		if strings.Contains(errMsg, "invalid input syntax for type uuid") {
			errors.InvalidArgument.Err(ctx, err)
		} else {
			errors.InvalidArgument.Details(ctx, "invalid syntax", errMsg)
		}
	} else {
		errors.Internal.Err(ctx, err)
	}

	return true
}

DefaultErrorHandler is the default error handler for the PG middleware.

View Source
var ErrNoRows = pg.ErrNoRows

ErrNoRows is a type alias of pg.ErrNoRows.

View Source
var NewSchema = pg.NewSchema

NewSchema returns a new Schema instance, it's a shortcut of pg.NewSchema.

Functions

func DB

func DB(ctx iris.Context) *pg.DB

DB returns the *pg.DB binded to the "iris.contrib.pgdb" context key.

func IsErrNoRows

func IsErrNoRows(err error) bool

IsErrNoRows reports whether the error is of type pg.ErrNoRows.

func Repository

func Repository[T any](ctx iris.Context) *pg.Repository[T]

Repository returns a new Repository of T type by the database instance binded to the request Context.

Types

type EntityController

type EntityController[T any] struct {
	iris.Singleton

	// GetID returns the entity ID for GET/{id} and DELETE/{id} paths from the request Context.
	GetID func(ctx iris.Context) any

	// ErrorHandler defaults to the PG's error handler. It can be customized for this controller.
	// Setting this to nil will panic the application on the first error.
	ErrorHandler func(ctx iris.Context, err error) bool

	// AfterPayloadRead is called after the payload is read.
	// It can be used to validate the payload or set default fields based on the request Context.
	AfterPayloadRead func(ctx iris.Context, payload T) (T, bool)
	// contains filtered or unexported fields
}

EntityController is a controller for a single entity. It can be used to create a RESTful API for a single entity. It is a wrapper around the pg.Repository. It can be used as a base controller for a custom controller. The T is the entity type (e.g. a custom type, Customer).

The controller registers the following routes: - GET /schema - returns the entity's JSON schema. - POST / - creates a new entity. - PUT / - updates an existing entity. - GET /{id} - gets an entity by ID. - DELETE /{id} - deletes an entity by ID. The {id} parameter is the entity ID. It can be a string, int, uint, uuid, etc.

func NewEntityController

func NewEntityController[T any](middleware *PG) *EntityController[T]

NewEntityController returns a new EntityController[T]. The T is the entity type (e.g. a custom type, Customer).

Read the type's documentation for more information.

func (*EntityController[T]) Configure

func (c *EntityController[T]) Configure(r iris.Party)

Configure registers the controller's routes. It is called automatically by the Iris API Builder when registered to the Iris Application.

func (*EntityController[T]) WithoutSchemaRoute

func (c *EntityController[T]) WithoutSchemaRoute() *EntityController[T]

WithoutSchemaRoute disables the GET /schema route.

type Options

type Options struct {
	// Connection options.
	Host     string `yaml:"Host"`
	Port     int    `yaml:"Port"`
	User     string `yaml:"User"`
	Password string `yaml:"Password"`
	Schema   string `yaml:"Schema"`
	DBName   string `yaml:"DBName"`
	SSLMode  string `yaml:"SSLMode"`
	//
	Trace bool `yaml:"Trace"` // If true then database tracer with Logger will be registered.
	//
	Transactional bool `yaml:"Transactional"` // If true then all requests will be executed in transaction.
	CreateSchema  bool `yaml:"CreateSchema"`  // If true then schema will be created if not exists.
	CheckSchema   bool `yaml:"CheckSchema"`   // If true then check the schema for missing tables and columns.
	//
	// The error handler for the middleware.
	// The implementation can ignore the error and return false to continue to the default error handler.
	ErrorHandler func(ctx iris.Context, err error) bool
}

Options is the configuration for the PG middleware. It is used to customize the connection to the database.

See https://pkg.go.dev/github.com/kataras/pg for more information.

type PG

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

PG is the PG middleware. It holds the *pg.DB instance and the options.

Its `Handler` method should be registered to the Iris Application.

func New

func New(schema *pg.Schema, opts Options) *PG

New returns a new PG middleware instance.

func NewFromDB

func NewFromDB(db *pg.DB, opts Options) *PG

NewFromDB returns a new PG middleware instance from an existing *pg.DB.

func (*PG) Close

func (p *PG) Close()

Close calls the underlying *pg.DB.Close method.

func (*PG) GetDB

func (p *PG) GetDB() *pg.DB

GetDB returns the underlying *pg.DB instance.

func (*PG) Handler

func (p *PG) Handler() iris.Handler

Handler returns a middleware which adds a *pg.DB binded to the request Context.

Directories

Path Synopsis
_examples

Jump to

Keyboard shortcuts

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