Skip to content

Commit

Permalink
Merge pull request #20 from fasibio/add_default_hooks
Browse files Browse the repository at this point in the history
Add default hooks
  • Loading branch information
fasibio committed Mar 15, 2023
2 parents 81fcf9c + f6e6488 commit 151ec03
Show file tree
Hide file tree
Showing 4 changed files with 190 additions and 20 deletions.
11 changes: 11 additions & 0 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,18 @@ You can manipulate each Query and Mutation through Hooks. The Hooks descriptions
- [hooks.go](https://github.com/fasibio/autogql_example/blob/main/hooks.go)
- And to include : [server.go](https://github.com/fasibio/autogql_example/blob/main/server.go#L29-L33)
A default hook implementation will also be added to db package so you did not have to implement all hook functions:
```go
type CompanyGetHook struct {
db.DefaultGetHook[model.Company, int]
}

func (g CompanyGetHook) BeforeCallDb(ctx context.Context, db *gorm.DB) (*gorm.DB, error) {
// your implementation
return db, nil
}
```
11 changes: 11 additions & 0 deletions generate-code-data.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,17 @@ func (db *GenerateData) HookList(suffix, prefix string) []string {
return res
}

func (db *GenerateData) HookListMany2Many(suffix string) []string {
res := make([]string, 0)
for _, v := range db.Handler.List {
m2mEntities := v.Many2ManyRefEntities()
for _, m2me := range m2mEntities {
res = append(res, fmt.Sprintf("%s%sRef2%ssInput", suffix, m2me.GqlTypeName(), v.Name()))
}
}
return res
}

func (db *GenerateData) ModelsMigrations() string {
res := ""
for _, v := range db.Handler.List {
Expand Down
148 changes: 136 additions & 12 deletions generate_code_db.go.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,35 @@
{{- end}}
{{- $root := .}}
{{$hookBaseName := "AutoGql"}}
type QueryName string
type GetName string
type AddName string
type UpdateName string
type DeleteName string
type Many2ManyName string

const (
{{- range $objectName, $object := .Handler.List.Objects }}
{{- range $m2mKey, $m2mEntity := $object.Many2ManyRefEntities }}
Add{{$m2mEntity.GqlTypeName}}2{{$object.Name}}s Many2ManyName = "Add{{$m2mEntity.GqlTypeName}}2{{$object.Name}}s"
{{- end}}
{{- if $object.SQLDirective.Query.Get}}
Get{{$object.Name}} GetName = "Get{{$object.Name}}"
{{- end}}
{{- if $object.SQLDirective.Query.Query}}
Query{{$object.Name}} QueryName = "Query{{$object.Name}}"
{{- end}}
{{- if $object.SQLDirective.Mutation.Add}}
Add{{$object.Name}} AddName = "Add{{$object.Name}}"
{{- end}}
{{- if $object.SQLDirective.Mutation.Update}}
Update{{$object.Name}} UpdateName = "Update{{$object.Name}}"
{{- end}}
{{- if $object.SQLDirective.Mutation.Delete}}
Delete{{$object.Name}} DeleteName = "Delete{{$object.Name}}"
{{- end}}
{{- end}}
)

type {{$hookBaseName}}HookM interface {
{{$root.HookList "model." "" | join "|"}}
Expand All @@ -14,6 +43,13 @@ type {{$hookBaseName}}HookF interface {
{{$root.HookList "model." "FiltersInput" | join "|"}}
}

{{- $m2mV := $root.HookListMany2Many "model."}}
{{- if gt (len $m2mV) 0}}
type {{$hookBaseName}}HookM2M interface {
{{$m2mV | join "|"}}
}
{{- end}}

type {{$hookBaseName}}HookQueryO interface {
{{$root.HookList "model." "Order" | join "|"}}
}
Expand Down Expand Up @@ -55,24 +91,28 @@ func (db *{{$hookBaseName}}DB) Init() {
db.Db.AutoMigrate({{.ModelsMigrations}})
}

func AddGetHook[T {{$hookBaseName}}HookM, I any](db *{{$hookBaseName}}DB, name string, implementation {{$hookBaseName}}HookGet[T,I]) {
db.Hooks[name] = implementation
func AddGetHook[T {{$hookBaseName}}HookM, I any](db *{{$hookBaseName}}DB, name GetName, implementation {{$hookBaseName}}HookGet[T,I]) {
db.Hooks[string(name)] = implementation
}

func AddQueryHook[M {{$hookBaseName}}HookM, F {{$hookBaseName}}HookF, O {{$hookBaseName}}HookQueryO](db *{{$hookBaseName}}DB, name string, implementation {{$hookBaseName}}HookQuery[M, F, O]) {
db.Hooks[name] = implementation
func AddQueryHook[M {{$hookBaseName}}HookM, F {{$hookBaseName}}HookF, O {{$hookBaseName}}HookQueryO](db *{{$hookBaseName}}DB, name QueryName, implementation {{$hookBaseName}}HookQuery[M, F, O]) {
db.Hooks[string(name)] = implementation
}

func AddAddHook[M {{$hookBaseName}}HookM,I {{$hookBaseName}}HookI, AP {{$hookBaseName}}HookAP](db *{{$hookBaseName}}DB, name string, implementation {{$hookBaseName}}HookAdd[M, I, AP]) {
db.Hooks[name] = implementation
func AddAddHook[M {{$hookBaseName}}HookM,I {{$hookBaseName}}HookI, AP {{$hookBaseName}}HookAP](db *{{$hookBaseName}}DB, name AddName, implementation {{$hookBaseName}}HookAdd[M, I, AP]) {
db.Hooks[string(name)] = implementation
}

func AddUpdateHook[M {{$hookBaseName}}HookM, U {{$hookBaseName}}HookU, UP {{$hookBaseName}}HookUP](db *{{$hookBaseName}}DB, name string, implementation {{$hookBaseName}}HookUpdate[U, UP]) {
db.Hooks[name] = implementation
func AddUpdateHook[M {{$hookBaseName}}HookM, U {{$hookBaseName}}HookU, UP {{$hookBaseName}}HookUP](db *{{$hookBaseName}}DB, name UpdateName, implementation {{$hookBaseName}}HookUpdate[U, UP]) {
db.Hooks[string(name)] = implementation
}

func AddDeleteHook[M {{$hookBaseName}}HookM, F {{$hookBaseName}}HookF, DP {{$hookBaseName}}HookDP](db *{{$hookBaseName}}DB, name string, implementation {{$hookBaseName}}HookDelete[M, F, DP]) {
db.Hooks[name] = implementation
func AddMany2ManyHook[M AutoGqlHookM, U AutoGqlHookU, UP AutoGqlHookUP](db *AutoGqlDB, name Many2ManyName, implementation AutoGqlHookUpdate[U, UP]) {
db.Hooks[string(name)] = implementation
}

func AddDeleteHook[F {{$hookBaseName}}HookF, DP {{$hookBaseName}}HookDP](db *{{$hookBaseName}}DB, name DeleteName, implementation {{$hookBaseName}}HookDelete[F, DP]) {
db.Hooks[string(name)] = implementation
}

type {{$hookBaseName}}HookGet[obj {{$hookBaseName}}HookM, identifier any] interface {
Expand All @@ -82,27 +122,111 @@ type {{$hookBaseName}}HookGet[obj {{$hookBaseName}}HookM, identifier any] interf
BeforeReturn(ctx context.Context, data *obj, db *gorm.DB) (*obj, error)
}

type DefaultGetHook[obj {{$hookBaseName}}HookM, identifier any] struct{}

func (d DefaultGetHook[obj, identifier]) Received(ctx context.Context, dbHelper *{{$hookBaseName}}DB, id ...identifier) (*gorm.DB, error) {
return dbHelper.Db, nil
}
func (d DefaultGetHook[obj, identifier]) BeforeCallDb(ctx context.Context, db *gorm.DB) (*gorm.DB, error) {
return db, nil
}
func (d DefaultGetHook[obj, identifier]) AfterCallDb(ctx context.Context, data *obj) (*obj, error) {
return data, nil
}
func (d DefaultGetHook[obj, identifier]) BeforeReturn(ctx context.Context, data *obj, db *gorm.DB) (*obj, error) {
return data, nil
}

type {{$hookBaseName}}HookQuery[obj {{$hookBaseName}}HookM, filter {{$hookBaseName}}HookF, order {{$hookBaseName}}HookQueryO] interface {
Received(ctx context.Context, dbHelper *{{$hookBaseName}}DB, filter *filter, order *order, first, offset *int) (*gorm.DB, *filter, *order, *int, *int, error)
BeforeCallDb(ctx context.Context, db *gorm.DB) (*gorm.DB, error)
AfterCallDb(ctx context.Context, data []*obj) ([]*obj, error)
BeforeReturn(ctx context.Context, data []*obj, db *gorm.DB) ([]*obj, error)
}

type DefaultQueryHook[obj {{$hookBaseName}}HookM, filter {{$hookBaseName}}HookF, order {{$hookBaseName}}HookQueryO] struct{}

func (d DefaultQueryHook[obj, filterType, orderType]) Received(ctx context.Context, dbHelper *AutoGqlDB, filter *filterType, order *orderType, first, offset *int) (*gorm.DB, *filterType, *orderType, *int, *int, error) {
return dbHelper.Db, filter, order, first, offset, nil
}
func (d DefaultQueryHook[obj, filter, order]) BeforeCallDb(ctx context.Context, db *gorm.DB) (*gorm.DB, error) {
return db, nil
}
func (d DefaultQueryHook[obj, filter, order]) AfterCallDb(ctx context.Context, data []*obj) ([]*obj, error) {
return data, nil
}
func (d DefaultQueryHook[obj, filter, order]) BeforeReturn(ctx context.Context, data []*obj, db *gorm.DB) ([]*obj, error) {
return data, nil
}

type {{$hookBaseName}}HookAdd[obj {{$hookBaseName}}HookM, input {{$hookBaseName}}HookI, res {{$hookBaseName}}HookAP] interface {
Received(ctx context.Context, dbHelper *{{$hookBaseName}}DB, input []*input) (*gorm.DB, []*input, error)
BeforeCallDb(ctx context.Context, db *gorm.DB, data []obj) (*gorm.DB,[]obj, error)
BeforeReturn(ctx context.Context, db *gorm.DB, res *res) (*res, error)
}

type DefaultAddHook[obj {{$hookBaseName}}HookM, input {{$hookBaseName}}HookI, res {{$hookBaseName}}HookAP] struct{}

func (d DefaultAddHook[obj, inputType, resType]) Received(ctx context.Context, dbHelper *AutoGqlDB, input []*inputType) (*gorm.DB, []*inputType, error) {
return dbHelper.Db, input, nil
}
func (d DefaultAddHook[obj, inputType, resType]) BeforeCallDb(ctx context.Context, db *gorm.DB, data []obj) (*gorm.DB, []obj, error) {
return db, data, nil
}
func (d DefaultAddHook[obj, inputType, resType]) BeforeReturn(ctx context.Context, db *gorm.DB, res *resType) (*resType, error) {
return res, nil
}

type {{$hookBaseName}}HookUpdate[ input {{$hookBaseName}}HookU, res {{$hookBaseName}}HookUP]interface{
Received(ctx context.Context, dbHelper *{{$hookBaseName}}DB, input *input) (*gorm.DB, input, error)
BeforeCallDb(ctx context.Context, db *gorm.DB, data map[string]interface{}) (*gorm.DB, map[string]interface{}, error)
BeforeReturn(ctx context.Context, db *gorm.DB, res *res) (*res, error)
}

type {{$hookBaseName}}HookDelete[obj {{$hookBaseName}}HookM, input {{$hookBaseName}}HookF, res {{$hookBaseName}}HookDP] interface {
type {{$hookBaseName}}HookMany2Many[input {{$hookBaseName}}HookM2M, res AutoGqlHookUP] interface {
Received(ctx context.Context, dbHelper *AutoGqlDB, input *input) (*gorm.DB, input, error)
BeforeCallDb(ctx context.Context, db *gorm.DB) (*gorm.DB, error)
BeforeReturn(ctx context.Context, db *gorm.DB, res *res) (*res, error)
}

type DefaultMany2ManyHook[input{{$hookBaseName}}HookM2M, res {{$hookBaseName}}HookUP] struct {}

func (d DefaultMany2ManyHook[inputType, resType])Received(ctx context.Context, dbHelper *{{$hookBaseName}}DB, input *inputType) (*gorm.DB, inputType, error){
return dbHelper.Db, *input, nil
}
func (d DefaultMany2ManyHook[inputType, resType])BeforeCallDb(ctx context.Context, db *gorm.DB) (*gorm.DB, error){
return db, nil
}
func (d DefaultMany2ManyHook[inputType, resType])BeforeReturn(ctx context.Context, db *gorm.DB, res *resType) (*resType, error){
return res, nil
}

type DefaultUpdateHook[input {{$hookBaseName}}HookU, res {{$hookBaseName}}HookUP] struct{}

func (d DefaultUpdateHook[inputType, resType]) Received(ctx context.Context, dbHelper *AutoGqlDB, input *inputType) (*gorm.DB, inputType, error) {
return dbHelper.Db, *input, nil
}
func (d DefaultUpdateHook[inputType, resType]) BeforeCallDb(ctx context.Context, db *gorm.DB, data map[string]interface{}) (*gorm.DB, map[string]interface{}, error) {
return db, data, nil
}
func (d DefaultUpdateHook[inputType, resType]) BeforeReturn(ctx context.Context, db *gorm.DB, res *resType) (*resType, error) {
return res, nil
}

type {{$hookBaseName}}HookDelete[input {{$hookBaseName}}HookF, res {{$hookBaseName}}HookDP] interface {
Received(ctx context.Context, dbHelper *{{$hookBaseName}}DB, input *input) (*gorm.DB, input, error)
BeforeCallDb(ctx context.Context, db *gorm.DB) (*gorm.DB, error)
BeforeReturn(ctx context.Context, db *gorm.DB, res *res) (*res, error)
}
}

type DefaultDeleteHook[input {{$hookBaseName}}HookF, res {{$hookBaseName}}HookDP] struct{}

func (d DefaultDeleteHook[inputType, resType]) Received(ctx context.Context, dbHelper *AutoGqlDB, input *inputType) (*gorm.DB, inputType, error) {
return dbHelper.Db, *input, nil
}
func (d DefaultDeleteHook[inputType, resType]) BeforeCallDb(ctx context.Context, db *gorm.DB) (*gorm.DB, error) {
return db, nil
}
func (d DefaultDeleteHook[inputType, resType]) BeforeReturn(ctx context.Context, db *gorm.DB, res *resType) (*resType, error) {
return res, nil
}
40 changes: 32 additions & 8 deletions generate_code_resolver.go.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
// Get{{$object.Name}} is the resolver for the get{{$object.Name}} field.
{{- $primaryFields := $object.PrimaryKeys }}
func (r *queryResolver) Get{{$object.Name}}(ctx context.Context, {{range $primaryFieldKey, $primaryField := $primaryFields}} {{$primaryField.Name}} {{$root.GetGoFieldType $objectName $primaryField false}}, {{end }}) (*model.{{$object.Name}}, error) {
v, okHook := r.Sql.Hooks["Get{{$object.Name}}"].(db.{{$hookBaseName}}HookGet[model.{{$object.Name}}, {{$root.GetMaxMatchGoFieldType $objectName $primaryFields}}])
v, okHook := r.Sql.Hooks[string(db.Get{{$object.Name}})].(db.{{$hookBaseName}}HookGet[model.{{$object.Name}}, {{$root.GetMaxMatchGoFieldType $objectName $primaryFields}}])
db := r.Sql.Db
if okHook {
var err error
Expand Down Expand Up @@ -53,7 +53,7 @@ func (r *queryResolver) Get{{$object.Name}}(ctx context.Context, {{range $primar
{{- if $object.SQLDirective.Query.Query}}
// Query{{$object.Name}} is the resolver for the query{{$object.Name}} field.
func (r *queryResolver) Query{{$object.Name}}(ctx context.Context, filter *model.{{$object.Name}}FiltersInput, order *model.{{$object.Name}}Order, first *int, offset *int) (*model.{{$object.Name}}QueryResult, error) {
v, okHook := r.Sql.Hooks["Query{{$object.Name}}"].(db.{{$hookBaseName}}HookQuery[model.{{$object.Name}}, model.{{$object.Name}}FiltersInput,model.{{$object.Name}}Order])
v, okHook := r.Sql.Hooks[string(db.Query{{$object.Name}})].(db.{{$hookBaseName}}HookQuery[model.{{$object.Name}}, model.{{$object.Name}}FiltersInput,model.{{$object.Name}}Order])
db := r.Sql.Db
if okHook {
var err error
Expand Down Expand Up @@ -133,11 +133,27 @@ func (r *{{lcFirst $object.Name}}PayloadResolver[T]) {{$object.Name}}(ctx contex
}
{{- range $m2mKey, $m2mEntity := $object.Many2ManyRefEntities }}
func (r *mutationResolver) Add{{$m2mEntity.GqlTypeName}}2{{$object.Name}}s(ctx context.Context, input model.{{$m2mEntity.GqlTypeName}}Ref2{{$object.Name}}sInput) (*model.Update{{$object.Name}}Payload, error){
v, okHook := r.Sql.Hooks[string(db.Add{{$m2mEntity.GqlTypeName}}2{{$object.Name}}s)].(db.{{$hookBaseName}}HookMany2Many[model.{{$m2mEntity.GqlTypeName}}Ref2{{$object.Name}}sInput,model.Update{{$object.Name}}Payload])
db := r.Sql.Db
if okHook {
var err error
db, input, err = v.Received(ctx,r.Sql,&input)
if err != nil {
return nil, err
}
}
tableName := r.Sql.Db.Config.NamingStrategy.TableName("{{$object.Name}}")
blackList := make(map[string]struct{})
sql, arguments := runtimehelper.CombineSimpleQuery(input.Filter.ExtendsDatabaseQuery(r.Sql.Db, tableName, false, blackList), "AND")
db := r.Sql.Db.Model(&model.{{$object.Name}}{}).Where(sql, arguments...)
db = db.Model(&model.{{$object.Name}}{}).Where(sql, arguments...)
var res []*model.{{$object.Name}}
if okHook {
var err error
db, err = v.BeforeCallDb(ctx, db )
if err != nil {
return nil, err
}
}
db.Find(&res)
{{- $table1ID := $root.GetGoFieldName $object.Name $object.PrimaryKeyField }}
{{- $tabe2PrimaryEntity := $root.PrimaryKeyEntityOfObject $m2mEntity.GqlTypeName}}
Expand All @@ -156,15 +172,23 @@ func (r *mutationResolver) Add{{$m2mEntity.GqlTypeName}}2{{$object.Name}}s(ctx c
}
}
d := r.Sql.Db.Model(&{{camelcase $m2mKey}}{}).Create(resIds)
return &model.Update{{$object.Name}}Payload{
result := &model.Update{{$object.Name}}Payload{
Count: int(d.RowsAffected),
},d.Error
}
if okHook {
var err error
result, err =v.BeforeReturn(ctx,db, result)
if err != nil {
return nil, err
}
}
return result,d.Error
}
{{- end}}
{{- if $object.SQLDirective.Mutation.Add}}
// Add{{$object.Name}} is the resolver for the add{{$object.Name}} field.
func (r *mutationResolver) Add{{$object.Name}}(ctx context.Context, input []*model.{{$object.Name}}Input) (*model.Add{{$object.Name}}Payload, error) {
v, okHook := r.Sql.Hooks["Add{{$object.Name}}"].(db.{{$hookBaseName}}HookAdd[model.{{$object.Name}}, model.{{$object.Name}}Input, model.Add{{$object.Name}}Payload])
v, okHook := r.Sql.Hooks[string(db.Add{{$object.Name}})].(db.{{$hookBaseName}}HookAdd[model.{{$object.Name}}, model.{{$object.Name}}Input, model.Add{{$object.Name}}Payload])
res := &model.Add{{$object.Name}}Payload{}
db := r.Sql.Db
if okHook {
Expand Down Expand Up @@ -200,7 +224,7 @@ func (r *mutationResolver) Add{{$object.Name}}(ctx context.Context, input []*mod
{{- if $object.SQLDirective.Mutation.Update}}
// Update{{$object.Name}} is the resolver for the update{{$object.Name}} field.
func (r *mutationResolver) Update{{$object.Name}}(ctx context.Context, input model.Update{{$object.Name}}Input) (*model.Update{{$object.Name}}Payload, error) {
v, okHook := r.Sql.Hooks["Update{{$object.Name}}"].(db.{{$hookBaseName}}HookUpdate[ model.Update{{$object.Name}}Input, model.Update{{$object.Name}}Payload])
v, okHook := r.Sql.Hooks[string(db.Update{{$object.Name}})].(db.{{$hookBaseName}}HookUpdate[ model.Update{{$object.Name}}Input, model.Update{{$object.Name}}Payload])
db := r.Sql.Db
if okHook{
var err error
Expand Down Expand Up @@ -239,7 +263,7 @@ func (r *mutationResolver) Update{{$object.Name}}(ctx context.Context, input mod
{{- if $object.SQLDirective.Mutation.Delete}}
// Delete{{$object.Name}} is the resolver for the delete{{$object.Name}} field.
func (r *mutationResolver) Delete{{$object.Name}}(ctx context.Context, filter model.{{$object.Name}}FiltersInput) (*model.Delete{{$object.Name}}Payload, error) {
v, okHook := r.Sql.Hooks["Delete{{$object.Name}}"].(db.{{$hookBaseName}}HookDelete[model.{{$object.Name}}, model.{{$object.Name}}FiltersInput, model.Delete{{$object.Name}}Payload])
v, okHook := r.Sql.Hooks[string(db.Delete{{$object.Name}})].(db.{{$hookBaseName}}HookDelete[model.{{$object.Name}}FiltersInput, model.Delete{{$object.Name}}Payload])
db := r.Sql.Db
if okHook{
var err error
Expand Down

0 comments on commit 151ec03

Please sign in to comment.