fix camelize generated fields

This commit is contained in:
Nimer Farahty 2025-06-09 03:03:33 +03:00
parent b0120532af
commit 8f649f2a59
8 changed files with 239 additions and 20 deletions

View File

@ -7,6 +7,7 @@ import (
"os" "os"
"strings" "strings"
"git.farahty.com/nimer/go-mongo/utils"
"github.com/99designs/gqlgen/api" "github.com/99designs/gqlgen/api"
"github.com/99designs/gqlgen/codegen/config" "github.com/99designs/gqlgen/codegen/config"
"github.com/99designs/gqlgen/plugin/modelgen" "github.com/99designs/gqlgen/plugin/modelgen"
@ -29,7 +30,7 @@ func mutateHook(b *modelgen.ModelBuild) *modelgen.ModelBuild {
field.Tag = strings.TrimSuffix(field.Tag, `"`) + `,omitempty" bson:"-"` field.Tag = strings.TrimSuffix(field.Tag, `"`) + `,omitempty" bson:"-"`
} }
} else { } else {
field.Tag = strings.TrimSuffix(field.Tag, `"`) + `" bson:"` + strings.ToLower(field.Name) + `,omitempty"` field.Tag = strings.TrimSuffix(field.Tag, `"`) + `" bson:"` + utils.Camelize(field.Name) + `,omitempty"`
} }
} }
} }

View File

@ -58,6 +58,7 @@ type DirectiveRoot struct {
type ComplexityRoot struct { type ComplexityRoot struct {
Category struct { Category struct {
Body func(childComplexity int) int Body func(childComplexity int) int
Children func(childComplexity int) int
CreatedAt func(childComplexity int) int CreatedAt func(childComplexity int) int
CreatedBy func(childComplexity int) int CreatedBy func(childComplexity int) int
CreatedByID func(childComplexity int) int CreatedByID func(childComplexity int) int
@ -130,6 +131,8 @@ type ComplexityRoot struct {
type CategoryResolver interface { type CategoryResolver interface {
Parent(ctx context.Context, obj *models.Category) (*models.Category, error) Parent(ctx context.Context, obj *models.Category) (*models.Category, error)
Children(ctx context.Context, obj *models.Category) ([]*models.Category, error)
CreatedBy(ctx context.Context, obj *models.Category) (*models.User, error) CreatedBy(ctx context.Context, obj *models.Category) (*models.User, error)
UpdatedBy(ctx context.Context, obj *models.Category) (*models.User, error) UpdatedBy(ctx context.Context, obj *models.Category) (*models.User, error)
@ -189,6 +192,13 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
return e.complexity.Category.Body(childComplexity), true return e.complexity.Category.Body(childComplexity), true
case "Category.children":
if e.complexity.Category.Children == nil {
break
}
return e.complexity.Category.Children(childComplexity), true
case "Category.createdAt": case "Category.createdAt":
if e.complexity.Category.CreatedAt == nil { if e.complexity.Category.CreatedAt == nil {
break break
@ -752,6 +762,9 @@ input TranslatedInput {
parent: Category @goField(forceResolver: true) parent: Category @goField(forceResolver: true)
parentId: ID parentId: ID
"#bson:ignore"
children: [Category] @goField(forceResolver: true)
createdAt: Time! createdAt: Time!
updatedAt: Time! updatedAt: Time!
@ -1389,6 +1402,8 @@ func (ec *executionContext) fieldContext_Category_parent(_ context.Context, fiel
return ec.fieldContext_Category_parent(ctx, field) return ec.fieldContext_Category_parent(ctx, field)
case "parentId": case "parentId":
return ec.fieldContext_Category_parentId(ctx, field) return ec.fieldContext_Category_parentId(ctx, field)
case "children":
return ec.fieldContext_Category_children(ctx, field)
case "createdAt": case "createdAt":
return ec.fieldContext_Category_createdAt(ctx, field) return ec.fieldContext_Category_createdAt(ctx, field)
case "updatedAt": case "updatedAt":
@ -1453,6 +1468,77 @@ func (ec *executionContext) fieldContext_Category_parentId(_ context.Context, fi
return fc, nil return fc, nil
} }
func (ec *executionContext) _Category_children(ctx context.Context, field graphql.CollectedField, obj *models.Category) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_Category_children(ctx, field)
if err != nil {
return graphql.Null
}
ctx = graphql.WithFieldContext(ctx, fc)
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
}()
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
ctx = rctx // use context from middleware stack in children
return ec.resolvers.Category().Children(rctx, obj)
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
return graphql.Null
}
res := resTmp.([]*models.Category)
fc.Result = res
return ec.marshalOCategory2ᚕᚖgitᚗfarahtyᚗcomᚋnimerᚋgoᚑmongoᚋmodelsᚐCategory(ctx, field.Selections, res)
}
func (ec *executionContext) fieldContext_Category_children(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "Category",
Field: field,
IsMethod: true,
IsResolver: true,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
switch field.Name {
case "id":
return ec.fieldContext_Category_id(ctx, field)
case "title":
return ec.fieldContext_Category_title(ctx, field)
case "body":
return ec.fieldContext_Category_body(ctx, field)
case "parent":
return ec.fieldContext_Category_parent(ctx, field)
case "parentId":
return ec.fieldContext_Category_parentId(ctx, field)
case "children":
return ec.fieldContext_Category_children(ctx, field)
case "createdAt":
return ec.fieldContext_Category_createdAt(ctx, field)
case "updatedAt":
return ec.fieldContext_Category_updatedAt(ctx, field)
case "createdBy":
return ec.fieldContext_Category_createdBy(ctx, field)
case "createdById":
return ec.fieldContext_Category_createdById(ctx, field)
case "updatedBy":
return ec.fieldContext_Category_updatedBy(ctx, field)
case "updatedById":
return ec.fieldContext_Category_updatedById(ctx, field)
case "owner":
return ec.fieldContext_Category_owner(ctx, field)
case "ownerId":
return ec.fieldContext_Category_ownerId(ctx, field)
}
return nil, fmt.Errorf("no field named %q was found under type Category", field.Name)
},
}
return fc, nil
}
func (ec *executionContext) _Category_createdAt(ctx context.Context, field graphql.CollectedField, obj *models.Category) (ret graphql.Marshaler) { func (ec *executionContext) _Category_createdAt(ctx context.Context, field graphql.CollectedField, obj *models.Category) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_Category_createdAt(ctx, field) fc, err := ec.fieldContext_Category_createdAt(ctx, field)
if err != nil { if err != nil {
@ -2102,6 +2188,8 @@ func (ec *executionContext) fieldContext_Mutation_createCategory(ctx context.Con
return ec.fieldContext_Category_parent(ctx, field) return ec.fieldContext_Category_parent(ctx, field)
case "parentId": case "parentId":
return ec.fieldContext_Category_parentId(ctx, field) return ec.fieldContext_Category_parentId(ctx, field)
case "children":
return ec.fieldContext_Category_children(ctx, field)
case "createdAt": case "createdAt":
return ec.fieldContext_Category_createdAt(ctx, field) return ec.fieldContext_Category_createdAt(ctx, field)
case "updatedAt": case "updatedAt":
@ -2327,6 +2415,8 @@ func (ec *executionContext) fieldContext_Query_categories(_ context.Context, fie
return ec.fieldContext_Category_parent(ctx, field) return ec.fieldContext_Category_parent(ctx, field)
case "parentId": case "parentId":
return ec.fieldContext_Category_parentId(ctx, field) return ec.fieldContext_Category_parentId(ctx, field)
case "children":
return ec.fieldContext_Category_children(ctx, field)
case "createdAt": case "createdAt":
return ec.fieldContext_Category_createdAt(ctx, field) return ec.fieldContext_Category_createdAt(ctx, field)
case "updatedAt": case "updatedAt":
@ -2399,6 +2489,8 @@ func (ec *executionContext) fieldContext_Query_category(ctx context.Context, fie
return ec.fieldContext_Category_parent(ctx, field) return ec.fieldContext_Category_parent(ctx, field)
case "parentId": case "parentId":
return ec.fieldContext_Category_parentId(ctx, field) return ec.fieldContext_Category_parentId(ctx, field)
case "children":
return ec.fieldContext_Category_children(ctx, field)
case "createdAt": case "createdAt":
return ec.fieldContext_Category_createdAt(ctx, field) return ec.fieldContext_Category_createdAt(ctx, field)
case "updatedAt": case "updatedAt":
@ -5979,6 +6071,39 @@ func (ec *executionContext) _Category(ctx context.Context, sel ast.SelectionSet,
out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) })
case "parentId": case "parentId":
out.Values[i] = ec._Category_parentId(ctx, field, obj) out.Values[i] = ec._Category_parentId(ctx, field, obj)
case "children":
field := field
innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) {
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
}
}()
res = ec._Category_children(ctx, field, obj)
return res
}
if field.Deferrable != nil {
dfs, ok := deferred[field.Deferrable.Label]
di := 0
if ok {
dfs.AddField(field)
di = len(dfs.Values) - 1
} else {
dfs = graphql.NewFieldSet([]graphql.CollectedField{field})
deferred[field.Deferrable.Label] = dfs
}
dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler {
return innerFunc(ctx, dfs)
})
// don't run the out.Concurrently() call below
out.Values[i] = graphql.Null
continue
}
out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) })
case "createdAt": case "createdAt":
out.Values[i] = ec._Category_createdAt(ctx, field, obj) out.Values[i] = ec._Category_createdAt(ctx, field, obj)
if out.Values[i] == graphql.Null { if out.Values[i] == graphql.Null {
@ -7584,6 +7709,47 @@ func (ec *executionContext) marshalOBoolean2ᚖbool(ctx context.Context, sel ast
return res return res
} }
func (ec *executionContext) marshalOCategory2ᚕᚖgitᚗfarahtyᚗcomᚋnimerᚋgoᚑmongoᚋmodelsᚐCategory(ctx context.Context, sel ast.SelectionSet, v []*models.Category) graphql.Marshaler {
if v == nil {
return graphql.Null
}
ret := make(graphql.Array, len(v))
var wg sync.WaitGroup
isLen1 := len(v) == 1
if !isLen1 {
wg.Add(len(v))
}
for i := range v {
i := i
fc := &graphql.FieldContext{
Index: &i,
Result: &v[i],
}
ctx := graphql.WithFieldContext(ctx, fc)
f := func(i int) {
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = nil
}
}()
if !isLen1 {
defer wg.Done()
}
ret[i] = ec.marshalOCategory2ᚖgitᚗfarahtyᚗcomᚋnimerᚋgoᚑmongoᚋmodelsᚐCategory(ctx, sel, v[i])
}
if isLen1 {
f(i)
} else {
go f(i)
}
}
wg.Wait()
return ret
}
func (ec *executionContext) marshalOCategory2ᚖgitᚗfarahtyᚗcomᚋnimerᚋgoᚑmongoᚋmodelsᚐCategory(ctx context.Context, sel ast.SelectionSet, v *models.Category) graphql.Marshaler { func (ec *executionContext) marshalOCategory2ᚖgitᚗfarahtyᚗcomᚋnimerᚋgoᚑmongoᚋmodelsᚐCategory(ctx context.Context, sel ast.SelectionSet, v *models.Category) graphql.Marshaler {
if v == nil { if v == nil {
return graphql.Null return graphql.Null

View File

@ -8,6 +8,9 @@ type Category implements Base {
parent: Category @goField(forceResolver: true) parent: Category @goField(forceResolver: true)
parentId: ID parentId: ID
"#bson:ignore"
children: [Category] @goField(forceResolver: true)
createdAt: Time! createdAt: Time!
updatedAt: Time! updatedAt: Time!

View File

@ -28,18 +28,20 @@ type Category struct {
Body []*Translated `json:"body,omitempty" bson:"body,omitempty"` Body []*Translated `json:"body,omitempty" bson:"body,omitempty"`
// #bson:ignore // #bson:ignore
Parent *Category `json:"parent,omitempty,omitempty" bson:"-"` Parent *Category `json:"parent,omitempty,omitempty" bson:"-"`
ParentID *primitive.ObjectID `json:"parentId,omitempty" bson:"parentid,omitempty"` ParentID *primitive.ObjectID `json:"parentId,omitempty" bson:"parentId,omitempty"`
CreatedAt time.Time `json:"createdAt" bson:"createdat,omitempty"` // #bson:ignore
UpdatedAt time.Time `json:"updatedAt" bson:"updatedat,omitempty"` Children []*Category `json:"children,omitempty,omitempty" bson:"-"`
CreatedAt time.Time `json:"createdAt" bson:"createdAt,omitempty"`
UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt,omitempty"`
// #bson:ignore // #bson:ignore
CreatedBy *User `json:"createdBy,omitempty" bson:"-"` CreatedBy *User `json:"createdBy,omitempty" bson:"-"`
CreatedByID primitive.ObjectID `json:"createdById" bson:"createdbyid,omitempty"` CreatedByID primitive.ObjectID `json:"createdById" bson:"createdById,omitempty"`
// #bson:ignore // #bson:ignore
UpdatedBy *User `json:"updatedBy,omitempty" bson:"-"` UpdatedBy *User `json:"updatedBy,omitempty" bson:"-"`
UpdatedByID primitive.ObjectID `json:"updatedById" bson:"updatedbyid,omitempty"` UpdatedByID primitive.ObjectID `json:"updatedById" bson:"updatedById,omitempty"`
// #bson:ignore // #bson:ignore
Owner *User `json:"owner,omitempty,omitempty" bson:"-"` Owner *User `json:"owner,omitempty,omitempty" bson:"-"`
OwnerID primitive.ObjectID `json:"ownerId" bson:"ownerid,omitempty"` OwnerID primitive.ObjectID `json:"ownerId" bson:"ownerId,omitempty"`
} }
func (Category) IsBase() {} func (Category) IsBase() {}
@ -53,7 +55,7 @@ func (this Category) GetOwner() *User { return this.Owner }
type CreateCategoryInput struct { type CreateCategoryInput struct {
Title []*TranslatedInput `json:"title" bson:"title,omitempty"` Title []*TranslatedInput `json:"title" bson:"title,omitempty"`
Body []*TranslatedInput `json:"body,omitempty" bson:"body,omitempty"` Body []*TranslatedInput `json:"body,omitempty" bson:"body,omitempty"`
ParentID *primitive.ObjectID `json:"parentId,omitempty" bson:"parentid,omitempty"` ParentID *primitive.ObjectID `json:"parentId,omitempty" bson:"parentId,omitempty"`
} }
type CreateTodoInput struct { type CreateTodoInput struct {
@ -75,8 +77,8 @@ type LoginInput struct {
type LoginResponse struct { type LoginResponse struct {
User *User `json:"user" bson:"user,omitempty"` User *User `json:"user" bson:"user,omitempty"`
AccessToken string `json:"accessToken" bson:"accesstoken,omitempty"` AccessToken string `json:"accessToken" bson:"accessToken,omitempty"`
RefreshToken string `json:"refreshToken" bson:"refreshtoken,omitempty"` RefreshToken string `json:"refreshToken" bson:"refreshToken,omitempty"`
} }
type Mutation struct { type Mutation struct {
@ -92,17 +94,17 @@ type Todo struct {
ID primitive.ObjectID `json:"id,omitempty" bson:"_id,omitempty"` ID primitive.ObjectID `json:"id,omitempty" bson:"_id,omitempty"`
Title *string `json:"title,omitempty" bson:"title,omitempty"` Title *string `json:"title,omitempty" bson:"title,omitempty"`
Completed *bool `json:"completed,omitempty" bson:"completed,omitempty"` Completed *bool `json:"completed,omitempty" bson:"completed,omitempty"`
CreatedAt time.Time `json:"createdAt" bson:"createdat,omitempty"` CreatedAt time.Time `json:"createdAt" bson:"createdAt,omitempty"`
UpdatedAt time.Time `json:"updatedAt" bson:"updatedat,omitempty"` UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt,omitempty"`
// #bson:ignore // #bson:ignore
CreatedBy *User `json:"createdBy,omitempty" bson:"-"` CreatedBy *User `json:"createdBy,omitempty" bson:"-"`
CreatedByID primitive.ObjectID `json:"createdById" bson:"createdbyid,omitempty"` CreatedByID primitive.ObjectID `json:"createdById" bson:"createdById,omitempty"`
// #bson:ignore // #bson:ignore
UpdatedBy *User `json:"updatedBy,omitempty" bson:"-"` UpdatedBy *User `json:"updatedBy,omitempty" bson:"-"`
UpdatedByID primitive.ObjectID `json:"updatedById" bson:"updatedbyid,omitempty"` UpdatedByID primitive.ObjectID `json:"updatedById" bson:"updatedById,omitempty"`
// #bson:ignore // #bson:ignore
Owner *User `json:"owner,omitempty,omitempty" bson:"-"` Owner *User `json:"owner,omitempty,omitempty" bson:"-"`
OwnerID primitive.ObjectID `json:"ownerId" bson:"ownerid,omitempty"` OwnerID primitive.ObjectID `json:"ownerId" bson:"ownerId,omitempty"`
} }
func (Todo) IsBase() {} func (Todo) IsBase() {}
@ -115,13 +117,13 @@ func (this Todo) GetOwner() *User { return this.Owner }
type Translated struct { type Translated struct {
Value string `json:"value" bson:"value,omitempty"` Value string `json:"value" bson:"value,omitempty"`
IsPrimary bool `json:"isPrimary" bson:"isprimary,omitempty"` IsPrimary bool `json:"isPrimary" bson:"isPrimary,omitempty"`
Language string `json:"language" bson:"language,omitempty"` Language string `json:"language" bson:"language,omitempty"`
} }
type TranslatedInput struct { type TranslatedInput struct {
Value string `json:"value" bson:"value,omitempty"` Value string `json:"value" bson:"value,omitempty"`
IsPrimary bool `json:"isPrimary" bson:"isprimary,omitempty"` IsPrimary bool `json:"isPrimary" bson:"isPrimary,omitempty"`
Language string `json:"language" bson:"language,omitempty"` Language string `json:"language" bson:"language,omitempty"`
} }
@ -132,8 +134,8 @@ type User struct {
Type *string `json:"type,omitempty" bson:"type,omitempty"` Type *string `json:"type,omitempty" bson:"type,omitempty"`
Status *string `json:"status,omitempty" bson:"status,omitempty"` Status *string `json:"status,omitempty" bson:"status,omitempty"`
Verified *bool `json:"verified,omitempty" bson:"verified,omitempty"` Verified *bool `json:"verified,omitempty" bson:"verified,omitempty"`
Password *string `json:"-" bson:"password,omitempty"` Password *string `json:"-" bson:"Password,omitempty"`
Token *string `json:"-" bson:"token,omitempty"` Token *string `json:"-" bson:"Token,omitempty"`
} }
type Role string type Role string

View File

@ -22,6 +22,11 @@ func (r *categoryResolver) Parent(ctx context.Context, obj *models.Category) (*m
return categoryService.FindByID(ctx, *obj.ParentID) return categoryService.FindByID(ctx, *obj.ParentID)
} }
// Children is the resolver for the children field.
func (r *categoryResolver) Children(ctx context.Context, obj *models.Category) ([]*models.Category, error) {
return categoryService.FindChildren(ctx, obj.ID)
}
// CreatedBy is the resolver for the createdBy field. // CreatedBy is the resolver for the createdBy field.
func (r *categoryResolver) CreatedBy(ctx context.Context, obj *models.Category) (*models.User, error) { func (r *categoryResolver) CreatedBy(ctx context.Context, obj *models.Category) (*models.User, error) {
return userService.FindById(ctx, obj.CreatedByID) return userService.FindById(ctx, obj.CreatedByID)

View File

@ -33,6 +33,7 @@ func Login(ctx context.Context, loginInput *models.LoginInput, redisClient redis
user, err := app.FindOne[models.User](ctx, "users", filter) user, err := app.FindOne[models.User](ctx, "users", filter)
if err != nil { if err != nil {
logFailedLoginAttempt(ctx, loginInput.Identity, redisClient) // optional
return nil, err return nil, err
} }

View File

@ -16,6 +16,10 @@ func Find(ctx context.Context) ([]*models.Category, error) {
return app.Find[models.Category](ctx, coll, bson.D{}) return app.Find[models.Category](ctx, coll, bson.D{})
} }
func FindChildren(ctx context.Context, id primitive.ObjectID) ([]*models.Category, error) {
return app.Find[models.Category](ctx, coll, bson.M{"parentId": id})
}
func Create(ctx context.Context, input models.CreateCategoryInput) (*models.Category, error) { func Create(ctx context.Context, input models.CreateCategoryInput) (*models.Category, error) {
return app.InsertOne[models.Category](ctx, coll, input) return app.InsertOne[models.Category](ctx, coll, input)
} }

37
utils/camelize.go Normal file
View File

@ -0,0 +1,37 @@
package utils
import (
"strings"
"unicode"
)
func Camelize(s string) string {
// If input has no delimiters, assume it's already in camelCase or PascalCase
if !strings.ContainsAny(s, "_- ") {
return s[:1] + s[1:] // No change (optionally lowercase first letter: strings.ToLower(s[:1]) + s[1:])
}
// Otherwise, split and camelCase it
parts := strings.FieldsFunc(s, func(r rune) bool {
return r == '_' || r == '-' || unicode.IsSpace(r)
})
if len(parts) == 0 {
return ""
}
var b strings.Builder
b.WriteString(strings.ToLower(parts[0]))
for _, part := range parts[1:] {
if len(part) == 0 {
continue
}
b.WriteString(strings.ToUpper(part[:1]))
if len(part) > 1 {
b.WriteString(part[1:])
}
}
return b.String()
}