Skip to content

Commit

Permalink
db-repo, apiserver: allow string primary keys and added some generics;
Browse files Browse the repository at this point in the history
This commit changes the way you work with `Repository`s and CRUD
handlers. For repositories, we can now use strings as primary keys as
well (using `DistributedModel`s) and the methods to access entities are
now tied to the actual entities (giving you more type safety). The
repository now returns you the correct values directly, no need to pass
an empty value into the repository anymore.

The CRUD handlers are now also fully typed (so if you have `FooCreateInput`
as your create input, that is exactly the type you are getting in the
`TransformCreate` callback, no manual type casting needed). The
`GetCreateInput` and similar methods have also been removed as we can
now just create a zero value as needed.

** This is a breaking change. **
  • Loading branch information
ajscholl committed Aug 10, 2023
1 parent 58004b9 commit 2b3b4a7
Show file tree
Hide file tree
Showing 121 changed files with 1,852 additions and 2,312 deletions.
68 changes: 48 additions & 20 deletions examples/apiserver/simple-handlers/entity.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ package main

import (
"context"
"fmt"
"time"

db_repo "github.com/justtrackio/gosoline/pkg/db-repo"
"github.com/justtrackio/gosoline/pkg/db-repo"
)

type MyEntity struct {
Expand All @@ -19,6 +20,14 @@ func (e *MyEntity) GetId() *uint {
return &e.Id
}

func (e *MyEntity) GetUpdatedAt() *time.Time {
return e.UpdatedAt
}

func (e *MyEntity) GetCreatedAt() *time.Time {
return e.CreatedAt
}

func (e *MyEntity) SetUpdatedAt(updatedAt *time.Time) {
e.UpdatedAt = updatedAt
}
Expand All @@ -29,40 +38,59 @@ func (e *MyEntity) SetCreatedAt(createdAt *time.Time) {

type MyEntityRepository struct{}

func (*MyEntityRepository) Create(ctx context.Context, value db_repo.ModelBased) error {
func (*MyEntityRepository) Create(ctx context.Context, value *MyEntity) error {
return nil
}

func (*MyEntityRepository) Read(ctx context.Context, id *uint, out db_repo.ModelBased) error {
return nil
func (*MyEntityRepository) Read(ctx context.Context, id uint) (*MyEntity, error) {
if id == 1 {
return &MyEntity{
Id: 1,
Prop1: "text",
}, nil
}

if id == 2 {
return &MyEntity{
Id: 2,
Prop2: "text",
}, nil
}

return nil, db_repo.NewRecordNotFoundError(fmt.Sprintf("%d", id), "myEntity", fmt.Errorf("not found"))
}

func (*MyEntityRepository) Update(ctx context.Context, value db_repo.ModelBased) error {
func (*MyEntityRepository) Update(ctx context.Context, value *MyEntity) error {
return nil
}

func (*MyEntityRepository) Delete(ctx context.Context, value db_repo.ModelBased) error {
func (*MyEntityRepository) Delete(ctx context.Context, value *MyEntity) error {
return nil
}

func (*MyEntityRepository) Query(ctx context.Context, qb *db_repo.QueryBuilder, result interface{}) error {
r := result.(*[]*MyEntity)
func (*MyEntityRepository) Query(ctx context.Context, qb *db_repo.QueryBuilder) ([]*MyEntity, error) {
return []*MyEntity{
{
Id: 1,
Prop1: "text",
},
{
Id: 2,
Prop2: "text",
},
}, nil
}

*r = append(*r, &MyEntity{
Id: 1,
Prop1: "text",
})
*r = append(*r, &MyEntity{
Id: 2,
Prop1: "text",
})
result = r
func (*MyEntityRepository) Count(ctx context.Context, qb *db_repo.QueryBuilder) (int, error) {
return 2, nil
}

return nil
func (r *MyEntityRepository) GetModelId() string {
return "project.family.name.MyEntity"
}

func (*MyEntityRepository) Count(ctx context.Context, qb *db_repo.QueryBuilder, model db_repo.ModelBased) (int, error) {
return 2, nil
func (r *MyEntityRepository) GetModelName() string {
return "MyEntity"
}

func (*MyEntityRepository) GetMetadata() db_repo.Metadata {
Expand Down
48 changes: 13 additions & 35 deletions examples/apiserver/simple-handlers/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"fmt"

"github.com/justtrackio/gosoline/pkg/apiserver"
"github.com/justtrackio/gosoline/pkg/apiserver/crud"
"github.com/justtrackio/gosoline/pkg/db-repo"
)

Expand Down Expand Up @@ -60,7 +59,7 @@ func (h *AdminAuthenticatedHandler) Handle(requestContext context.Context, reque
}

type MyEntityHandler struct {
repo crud.Repository
repo db_repo.Repository[uint, *MyEntity]
}

type MyEntityCreateInput struct {
Expand All @@ -72,50 +71,29 @@ type MyEntityUpdateInput struct {
Prop1 string `json:"prop1"`
}

func (h *MyEntityHandler) GetRepository() crud.Repository {
func (h *MyEntityHandler) GetRepository() db_repo.Repository[uint, *MyEntity] {
return h.repo
}

func (h *MyEntityHandler) GetModel() db_repo.ModelBased {
return &MyEntity{}
}

func (h *MyEntityHandler) TransformOutput(_ context.Context, model db_repo.ModelBased, apiView string) (output interface{}, err error) {
func (h *MyEntityHandler) TransformOutput(_ context.Context, model *MyEntity, apiView string) (output *MyEntity, err error) {
return model, nil
}

func (h *MyEntityHandler) GetCreateInput() interface{} {
return &MyEntityCreateInput{}
func (h *MyEntityHandler) TransformCreate(_ context.Context, input *MyEntityCreateInput) (model *MyEntity, err error) {
return &MyEntity{
Prop1: input.Prop1,
Prop2: input.Prop2,
}, nil
}

func (h *MyEntityHandler) TransformCreate(_ context.Context, input interface{}, model db_repo.ModelBased) (err error) {
i := input.(*MyEntityCreateInput)
b := model.(*MyEntity)

b.Prop1 = i.Prop1
b.Prop2 = i.Prop2
func (h *MyEntityHandler) TransformUpdate(_ context.Context, input *MyEntityUpdateInput, model *MyEntity) (updated *MyEntity, err error) {
model.Prop1 = input.Prop1

return
}

func (h *MyEntityHandler) GetUpdateInput() interface{} {
return &MyEntityUpdateInput{}
}

func (h *MyEntityHandler) TransformUpdate(_ context.Context, input interface{}, model db_repo.ModelBased) (err error) {
i := input.(*MyEntityUpdateInput)
b := model.(*MyEntity)

b.Prop1 = i.Prop1

return
return model, nil
}

func (h *MyEntityHandler) List(ctx context.Context, qb *db_repo.QueryBuilder, apiView string) (out interface{}, err error) {
res := make([]*MyEntity, 0)
err = h.repo.Query(ctx, qb, &res)

return res, err
func (h *MyEntityHandler) List(ctx context.Context, qb *db_repo.QueryBuilder, apiView string) (out []*MyEntity, err error) {
return h.repo.Query(ctx, qb)
}

func (h *MyEntityHandler) Handle(requestContext context.Context, request *apiserver.Request) (response *apiserver.Response, error error) {
Expand Down
2 changes: 1 addition & 1 deletion examples/apiserver/simple-handlers/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ func apiDefiner(ctx context.Context, config cfg.Config, logger log.Logger) (*api

group.GET("/authenticated", apiserver.CreateHandler(&AdminAuthenticatedHandler{}))

crud.AddCrudHandlers(logger, definitions, 0, "/myEntity", &MyEntityHandler{
crud.AddCrudHandlers[MyEntityCreateInput, MyEntityUpdateInput, *MyEntity, uint, *MyEntity](logger, definitions, 0, "/myEntity", &MyEntityHandler{
repo: &MyEntityRepository{},
})

Expand Down
15 changes: 12 additions & 3 deletions examples/integration/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@ func (i *item) GetId() *uint {
return &i.Id
}

func (i *item) GetUpdatedAt() *time.Time {
return &i.UpdatedAt
}

func (i *item) GetCreatedAt() *time.Time {
return &i.UpdatedAt
}

func (i *item) SetUpdatedAt(updatedAt *time.Time) {
i.UpdatedAt = mdl.EmptyIfNil(updatedAt)
}
Expand All @@ -45,15 +53,16 @@ var ddbSettings = &ddb.Settings{
var repoSettings = db_repo.Settings{
AppId: cfg.AppId{},
Metadata: db_repo.Metadata{
TableName: "items",
TableName: "items",
PrimaryKey: "items.id",
},
}

type app struct {
kernel.EssentialModule
kernel.ServiceStage
ddbRepository ddb.Repository
dbRepository db_repo.Repository
dbRepository db_repo.Repository[uint, *item]
}

func newAppModule(ctx context.Context, config cfg.Config, logger log.Logger) (kernel.Module, error) {
Expand All @@ -62,7 +71,7 @@ func newAppModule(ctx context.Context, config cfg.Config, logger log.Logger) (ke
return nil, fmt.Errorf("unable to create dynamodb repository: %w", err)
}

dbRepository, err := db_repo.New(config, logger, repoSettings)
dbRepository, err := db_repo.New[uint, *item](config, logger, repoSettings)
if err != nil {
return nil, fmt.Errorf("unable to create mysql client: %w", err)
}
Expand Down
7 changes: 6 additions & 1 deletion examples/more_details/stream-consumer/config.dist.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,9 @@ stream:
input:
consumerInput:
type: sqs
target_queue_id: inputEvent
target_queue_id: inputEvent

test:
components:
s3:
default: {}
4 changes: 2 additions & 2 deletions pkg/apiserver/auth/chain.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package auth

import (
"github.com/gin-gonic/gin"
"net/http"

"github.com/gin-gonic/gin"
)

func NewChainHandler(authenticators map[string]Authenticator) gin.HandlerFunc {
Expand All @@ -11,7 +12,6 @@ func NewChainHandler(authenticators map[string]Authenticator) gin.HandlerFunc {

for n, a := range authenticators {
valid, err := a.IsValid(ginCtx)

if err != nil {
errors[n] = err.Error()
continue
Expand Down
3 changes: 1 addition & 2 deletions pkg/apiserver/auth/config_google.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,11 @@ import (
"regexp"
"sync"

"golang.org/x/exp/slices"

"github.com/gin-gonic/gin"
"github.com/justtrackio/gosoline/pkg/cfg"
"github.com/justtrackio/gosoline/pkg/log"
"github.com/pkg/errors"
"golang.org/x/exp/slices"
"google.golang.org/api/oauth2/v2"
"google.golang.org/api/option"
)
Expand Down
3 changes: 1 addition & 2 deletions pkg/apiserver/auth/config_key.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,11 @@ import (
"fmt"
"net/http"

"golang.org/x/exp/slices"

"github.com/gin-gonic/gin"
"github.com/justtrackio/gosoline/pkg/cfg"
"github.com/justtrackio/gosoline/pkg/funk"
"github.com/justtrackio/gosoline/pkg/log"
"golang.org/x/exp/slices"
)

const (
Expand Down
25 changes: 13 additions & 12 deletions pkg/apiserver/crud/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,31 +8,34 @@ import (
"github.com/gin-gonic/gin"
"github.com/justtrackio/gosoline/pkg/apiserver"
"github.com/justtrackio/gosoline/pkg/db"
dbRepo "github.com/justtrackio/gosoline/pkg/db-repo"
"github.com/justtrackio/gosoline/pkg/log"
"github.com/justtrackio/gosoline/pkg/mdl"
"github.com/justtrackio/gosoline/pkg/validation"
)

type createHandler struct {
type createHandler[I any, O any, K mdl.PossibleIdentifier, M dbRepo.ModelBased[K]] struct {
logger log.Logger
transformer CreateHandler
transformer CreateHandler[I, O, K, M]
}

func NewCreateHandler(logger log.Logger, transformer CreateHandler) gin.HandlerFunc {
ch := createHandler{
func NewCreateHandler[I any, O any, K mdl.PossibleIdentifier, M dbRepo.ModelBased[K]](logger log.Logger, transformer CreateHandler[I, O, K, M]) gin.HandlerFunc {
ch := createHandler[I, O, K, M]{
transformer: transformer,
logger: logger,
}

return apiserver.CreateJsonHandler(ch)
}

func (ch createHandler) GetInput() interface{} {
return ch.transformer.GetCreateInput()
func (ch createHandler[I, O, K, M]) GetInput() interface{} {
var input I

return &input
}

func (ch createHandler) Handle(ctx context.Context, request *apiserver.Request) (*apiserver.Response, error) {
model := ch.transformer.GetModel()
err := ch.transformer.TransformCreate(ctx, request.Body, model)
func (ch createHandler[I, O, K, M]) Handle(ctx context.Context, request *apiserver.Request) (*apiserver.Response, error) {
model, err := ch.transformer.TransformCreate(ctx, request.Body.(*I))
if err != nil {
return nil, err
}
Expand All @@ -52,9 +55,7 @@ func (ch createHandler) Handle(ctx context.Context, request *apiserver.Request)
return nil, err
}

reload := ch.transformer.GetModel()
err = repo.Read(ctx, model.GetId(), reload)

reload, err := repo.Read(ctx, *model.GetId())
if err != nil {
return nil, err
}
Expand Down
Loading

0 comments on commit 2b3b4a7

Please sign in to comment.