gorm_generics

package module
v0.1.2 Latest Latest
Warning

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

Go to latest
Published: Feb 17, 2024 License: MIT Imports: 6 Imported by: 0

README

PoC for Go generics with GORM

Contributor Covenant

Introduction

This repository represents a small PoC for using Go generics together with GORM, an Object-relational mapping library for Golang.

At this stage it emphasizes possibilities, and it is not stable implementation. In this stage, it is not meant to be used for production system.

Future development is the intention for this project, and any contribution is more than welcome.

TODO: Improve the interface for only specifying a Model and the DTO in generated automatically. https://github.com/viant/xunsafe

Example

package main

import (
	"context"
	"fmt"
	"log"

	"github.com/adderly/gorm-generics"
	"gorm.io/driver/sqlite"
	"gorm.io/gorm"
)

// Product is a domain entity
type Product struct {
	ID          uint
	Name        string
	Weight      uint
	IsAvailable bool
}

// ProductGorm is DTO used to map Product entity to database
type ProductGorm struct {
	ID          uint   `gorm:"primaryKey;column:id"`
	Name        string `gorm:"column:name"`
	Weight      uint   `gorm:"column:weight"`
	IsAvailable bool   `gorm:"column:is_available"`
}

// ToEntity respects the gorm_generics.GormModel interface
// Creates new Entity from GORM model.
func (g ProductGorm) ToEntity() Product {
	return Product{
		ID:          g.ID,
		Name:        g.Name,
		Weight:      g.Weight,
		IsAvailable: g.IsAvailable,
	}
}

// FromEntity respects the gorm_generics.GormModel interface
// Creates new GORM model from Entity.
func (g ProductGorm) FromEntity(product Product) interface{} {
	return ProductGorm{
		ID:          product.ID,
		Name:        product.Name,
		Weight:      product.Weight,
		IsAvailable: product.IsAvailable,
	}
}

func main() {
	db, err := gorm.Open(sqlite.Open("file:test?mode=memory&cache=shared&_fk=1"), &gorm.Config{})
	if err != nil {
		log.Fatal(err)
	}

	err = db.AutoMigrate(ProductGorm{})
	if err != nil {
		log.Fatal(err)
	}

	repository := gorm_generics.NewRepository[ProductGorm, Product](db)

	ctx := context.Background()

	product := Product{
		Name:        "product1",
		Weight:      100,
		IsAvailable: true,
	}
	err = repository.Insert(ctx, &product)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println(product)
	// Out:
	// {1 product1 100 true}

	single, err := repository.FindByID(ctx, product.ID)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(single)
	// Out:
	// {1 product1 100 true}

	err = repository.Insert(ctx, &Product{
		Name:        "product2",
		Weight:      50,
		IsAvailable: true,
	})
	if err != nil {
		log.Fatal(err)
	}

	many, err := repository.Find(ctx, gorm_generics.GreaterOrEqual("weight", 50))
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(many)
	// Out:
	// [{1 product1 100 true} {2 product2 50 true}]

	err = repository.Insert(ctx, &Product{
		Name:        "product3",
		Weight:      250,
		IsAvailable: false,
	})
	if err != nil {
		log.Fatal(err)
	}

	many, err = repository.Find(ctx, gorm_generics.GreaterOrEqual("weight", 90))
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(many)
	// Out:
	// [{1 product1 100 true} {3 product3 250 false}]

	many, err = repository.Find(ctx, gorm_generics.And(
		gorm_generics.GreaterOrEqual("weight", 90),
		gorm_generics.Equal("is_available", true)),
	)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(many)
	// Out:
	// [{1 product1 100 true}]
}

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ChunkSlice

func ChunkSlice[T any](slice []T, chunkSize int) [][]T

func Map

func Map[T, U any](ts []T, f func(T) U) []U

Maps a type to another using a function for transforming the data

func MapDto

func MapDto[M GormModel[E], E any, T any](modelArray []M, dtoType T) []T

Types

type GormModel

type GormModel[E any] interface {
	ToEntity() E
	FromEntity(entity E) interface{}
}

type GormRepository

type GormRepository[M GormModel[E], E any] struct {
	// contains filtered or unexported fields
}

func NewRepository

func NewRepository[M GormModel[E], E any](db *gorm.DB) *GormRepository[M, E]

func (*GormRepository[M, E]) Count

func (r *GormRepository[M, E]) Count(ctx context.Context, specifications ...Specification) (i int64, err error)

func (*GormRepository[M, E]) Delete

func (r *GormRepository[M, E]) Delete(ctx context.Context, entity *E) error

func (*GormRepository[M, E]) DeleteById

func (r *GormRepository[M, E]) DeleteById(ctx context.Context, id any) error

func (*GormRepository[M, E]) Find

func (r *GormRepository[M, E]) Find(ctx context.Context, specifications ...Specification) ([]E, error)

func (*GormRepository[M, E]) FindAll

func (r *GormRepository[M, E]) FindAll(ctx context.Context) ([]E, error)

func (*GormRepository[M, E]) FindByEntity

func (r *GormRepository[M, E]) FindByEntity(ctx context.Context, e any) ([]E, error)

func (*GormRepository[M, E]) FindByEntityWithOptions

func (r *GormRepository[M, E]) FindByEntityWithOptions(ctx context.Context, e any, eagerLoad bool) ([]E, error)

func (*GormRepository[M, E]) FindByID

func (r *GormRepository[M, E]) FindByID(ctx context.Context, id any) (E, error)

func (*GormRepository[M, E]) FindByIDWithOptions

func (r *GormRepository[M, E]) FindByIDWithOptions(ctx context.Context, id any, eagerLoad bool) (E, error)

func (*GormRepository[M, E]) FindByModel

func (r *GormRepository[M, E]) FindByModel(ctx context.Context, entity *M) (M, error)

func (*GormRepository[M, E]) FindByModelMulti

func (r *GormRepository[M, E]) FindByModelMulti(ctx context.Context, entity *M) ([]M, error)

func (*GormRepository[M, E]) FindPaged added in v0.1.2

func (r *GormRepository[M, E]) FindPaged(ctx context.Context, specifications ...Specification) ([]E, error)

func (*GormRepository[M, E]) FindPagedWithLimit added in v0.1.2

func (r *GormRepository[M, E]) FindPagedWithLimit(ctx context.Context, pageCfg PageConfig, specifications ...Specification) (PageResult[M, E], error)

func (*GormRepository[M, E]) FindWithLimit

func (r *GormRepository[M, E]) FindWithLimit(ctx context.Context, limit int, offset int, specifications ...Specification) ([]E, error)

func (*GormRepository[M, E]) FromModelToDto

func (r *GormRepository[M, E]) FromModelToDto(models []M) []E

func (*GormRepository[M, E]) Insert

func (r *GormRepository[M, E]) Insert(ctx context.Context, entity *E) error

func (*GormRepository[M, E]) InsertDirect

func (r *GormRepository[M, E]) InsertDirect(ctx context.Context, entity *M) error

func (*GormRepository[M, E]) InsertFromInterface

func (r *GormRepository[M, E]) InsertFromInterface(ctx context.Context, data interface{}) error

func (*GormRepository[M, E]) Update

func (r *GormRepository[M, E]) Update(ctx context.Context, entity *E) error

func (*GormRepository[M, E]) UpdateDirect

func (r *GormRepository[M, E]) UpdateDirect(ctx context.Context, entity *M) error

func (*GormRepository[M, E]) UpdateDirectMulti added in v0.1.2

func (r *GormRepository[M, E]) UpdateDirectMulti(ctx context.Context, entity []M) error

type PageConfig added in v0.1.2

type PageConfig struct {
	Page int   `json:"page"`
	Size int64 `json:"size"`
	// By default the count is generated when asking for the first page so that the user
	// receives the total amount, but with this we can optimize out this count
	IgnoreCount bool `json:"IngoreCount"`
	// if you want the count to always be returned.
	ForceCount bool `json:"ForceCount"`
}

type PageResult added in v0.1.2

type PageResult[M GormModel[E], E any] struct {
	Data  []M   `json:"data"`
	Count int64 `json:"count"`
	Page  int   `json:"page"`
}

type Specification

type Specification interface {
	GetQuery() string
	GetValues() []any
}

func And

func And(specifications ...Specification) Specification

func Equal

func Equal[T any](field string, value T) Specification

func GreaterOrEqual

func GreaterOrEqual[T comparable](field string, value T) Specification

func GreaterThan

func GreaterThan[T comparable](field string, value T) Specification

func In

func In[T any](field string, value []T) Specification

func IsNull

func IsNull(field string) Specification

func LessOrEqual

func LessOrEqual[T comparable](field string, value T) Specification

func LessThan

func LessThan[T comparable](field string, value T) Specification

func Like

func Like[T any](field string, value T) Specification

func Not

func Not(specification Specification) Specification

func Or

func Or(specifications ...Specification) Specification

Jump to

Keyboard shortcuts

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