Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions generator/templates/enums.gotpl
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,12 @@ var {{ $enum.Name }} = {{ lowercase $enum.Name }}Namespace{
{{ capitalize $val.Name }}: {{ $enum.Name }}Type{{ capitalize $val.Name }},
{{- end }}
}

func (e {{ $enum.Name }}Type) IsValid() bool {
switch e {
case {{ range $i, $val := $enum.ValueMap }}{{ if $i }}, {{ end }}{{ $enum.Name }}Type{{ capitalize $val.Name }}{{ end }}:
return true
}
return false
}
{{- end }}
13 changes: 13 additions & 0 deletions generator/templates/model_create.gotpl
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ func (d *{{ .Model.Name }}Delegate) Create(input {{ .Model.Name }}CreateInput) *
}

func (q *Queries) execute{{ .Model.Name }}Create(ctx context.Context, input {{ .Model.Name }}CreateInput, selects *{{ .Model.Name }}Select, omits *{{ .Model.Name }}Omit) (*{{ .Model.Name }}, error) {
if err := input.Validate(); err != nil {
return nil, err
}
m := q.{{ .Model.Name }}InputToMap(input)
cols, vals := mapToColsVals(m, {{ .Model.Name }}ColOrder)

Expand Down Expand Up @@ -130,6 +133,11 @@ func (q *Queries) execute{{ .Model.Name }}CreateMany(ctx context.Context, inputs
if len(inputs) == 0 {
return 0, nil
}
for i, input := range inputs {
if err := input.Validate(); err != nil {
return 0, fmt.Errorf("validation failed at index %d: %w", i, err)
}
}

if q.dialect.SupportsBulkInsert() {
rowMaps := make([]map[string]any, len(inputs))
Expand Down Expand Up @@ -162,6 +170,11 @@ func (q *Queries) execute{{ .Model.Name }}CreateManyAndReturn(ctx context.Contex
if len(inputs) == 0 {
return nil, nil
}
for i, input := range inputs {
if err := input.Validate(); err != nil {
return nil, fmt.Errorf("validation failed at index %d: %w", i, err)
}
}

hasRelations := selects.hasAnyRelation()
returningCols := q.select{{ .Model.Name }}Cols(selects, omits)
Expand Down
36 changes: 36 additions & 0 deletions generator/templates/model_structs.gotpl
Original file line number Diff line number Diff line change
Expand Up @@ -83,3 +83,39 @@ func (q *Queries) select{{ .Model.Name }}Cols(selects *{{ .Model.Name }}Select,

return cols
}

func (input {{ .Model.Name }}CreateInput) Validate() error {
{{- range $field := .Model.ScalarFields }}
{{- if $field.EnumRef }}
{{- if $field.IsArray }}
for _, val := range input.{{ capitalize $field.Name }} {
if !val.IsValid() {
return fmt.Errorf("invalid enum value %q for field {{ capitalize $field.Name }}", val)
}
}
{{- else if and (eq $field.Default nil) (not $field.Optional) }}
if input.{{ capitalize $field.Name }} == nil {
return fmt.Errorf("field {{ capitalize $field.Name }} is required")
}
if !input.{{ capitalize $field.Name }}.IsValid() {
return fmt.Errorf("invalid enum value %q for field {{ capitalize $field.Name }}", *input.{{ capitalize $field.Name }})
}
{{- else }}
if input.{{ capitalize $field.Name }} != nil {
if !input.{{ capitalize $field.Name }}.IsValid() {
return fmt.Errorf("invalid enum value %q for field {{ capitalize $field.Name }}", *input.{{ capitalize $field.Name }})
}
}
{{- end }}
{{- else }}
{{- if and (eq $field.Default nil) (not $field.Optional) (not $field.IsArray) }}
{{- if eq $field.GoType "string" }}
if input.{{ capitalize $field.Name }} == "" {
return fmt.Errorf("field {{ capitalize $field.Name }} is required")
}
{{- end }}
{{- end }}
{{- end }}
{{- end }}
return nil
}
3 changes: 2 additions & 1 deletion integration/create_many_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ func TestCreateMany(t *testing.T) {

t.Run("CreateManyAndReturn works and supports Select", func(t *testing.T) {
author, err := client.User.Create(valkyrie.UserCreateInput{
Email: "author@example.com",
Email: "author@example.com",
PhoneNum: "+444",
}).Exec(ctx)
if err != nil {
t.Fatalf("failed to create author: %v", err)
Expand Down
30 changes: 30 additions & 0 deletions integration/create_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,3 +132,33 @@ func TestCreateWithCustomEnum(t *testing.T) {
t.Errorf("expected role '%s', got '%s'", valkyrie.UserRole.Admin, u.Role)
}
}

func TestCreateValidation(t *testing.T) {
db, cleanup := setupTestDB(t)
defer cleanup()
ctx := context.Background()

_, err := db.User.Create(valkyrie.UserCreateInput{
// no email
PhoneNum: "+123456789",
}).Exec(ctx)
if err == nil {
t.Fatal("expected error creating user with empty required email, got nil")
}
if !strings.Contains(err.Error(), "field Email is required") {
t.Errorf("expected error message to contain 'field Email is required', got: %v", err)
}

invalidRole := valkyrie.UserRoleType("INVALID_ROLE")
_, err = db.User.Create(valkyrie.UserCreateInput{
Email: "invalid_role@example.com",
PhoneNum: "+123456789",
Role: &invalidRole,
}).Exec(ctx)
if err == nil {
t.Fatal("expected error creating user with invalid enum role, got nil")
}
if !strings.Contains(err.Error(), "invalid enum value \"INVALID_ROLE\" for field Role") {
t.Errorf("expected error message to contain 'invalid enum value \"INVALID_ROLE\" for field Role', got: %v", err)
}
}
20 changes: 20 additions & 0 deletions integration/valkyrie/category.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,13 @@ func (q *Queries) selectCategoryCols(selects *CategorySelect, omits *CategoryOmi
return cols
}

func (input CategoryCreateInput) Validate() error {
if input.Name == "" {
return fmt.Errorf("field Name is required")
}
return nil
}

var CategoryColOrder = []string{
"id",
"name",
Expand All @@ -109,6 +116,9 @@ func (d *CategoryDelegate) Create(input CategoryCreateInput) *CreateBuilder[Cate
}

func (q *Queries) executeCategoryCreate(ctx context.Context, input CategoryCreateInput, selects *CategorySelect, omits *CategoryOmit) (*Category, error) {
if err := input.Validate(); err != nil {
return nil, err
}
m := q.CategoryInputToMap(input)
cols, vals := mapToColsVals(m, CategoryColOrder)

Expand Down Expand Up @@ -173,6 +183,11 @@ func (q *Queries) executeCategoryCreateMany(ctx context.Context, inputs []Catego
if len(inputs) == 0 {
return 0, nil
}
for i, input := range inputs {
if err := input.Validate(); err != nil {
return 0, fmt.Errorf("validation failed at index %d: %w", i, err)
}
}

if q.dialect.SupportsBulkInsert() {
rowMaps := make([]map[string]any, len(inputs))
Expand Down Expand Up @@ -205,6 +220,11 @@ func (q *Queries) executeCategoryCreateManyAndReturn(ctx context.Context, inputs
if len(inputs) == 0 {
return nil, nil
}
for i, input := range inputs {
if err := input.Validate(); err != nil {
return nil, fmt.Errorf("validation failed at index %d: %w", i, err)
}
}

hasRelations := selects.hasAnyRelation()
returningCols := q.selectCategoryCols(selects, omits)
Expand Down
20 changes: 20 additions & 0 deletions integration/valkyrie/categoryToPost.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,13 @@ func (q *Queries) selectCategoryToPostCols(selects *CategoryToPostSelect, omits
return cols
}

func (input CategoryToPostCreateInput) Validate() error {
if input.PostId == "" {
return fmt.Errorf("field PostId is required")
}
return nil
}

var CategoryToPostColOrder = []string{
"postId",
"categoryId",
Expand All @@ -112,6 +119,9 @@ func (d *CategoryToPostDelegate) Create(input CategoryToPostCreateInput) *Create
}

func (q *Queries) executeCategoryToPostCreate(ctx context.Context, input CategoryToPostCreateInput, selects *CategoryToPostSelect, omits *CategoryToPostOmit) (*CategoryToPost, error) {
if err := input.Validate(); err != nil {
return nil, err
}
m := q.CategoryToPostInputToMap(input)
cols, vals := mapToColsVals(m, CategoryToPostColOrder)

Expand Down Expand Up @@ -173,6 +183,11 @@ func (q *Queries) executeCategoryToPostCreateMany(ctx context.Context, inputs []
if len(inputs) == 0 {
return 0, nil
}
for i, input := range inputs {
if err := input.Validate(); err != nil {
return 0, fmt.Errorf("validation failed at index %d: %w", i, err)
}
}

if q.dialect.SupportsBulkInsert() {
rowMaps := make([]map[string]any, len(inputs))
Expand Down Expand Up @@ -205,6 +220,11 @@ func (q *Queries) executeCategoryToPostCreateManyAndReturn(ctx context.Context,
if len(inputs) == 0 {
return nil, nil
}
for i, input := range inputs {
if err := input.Validate(); err != nil {
return nil, fmt.Errorf("validation failed at index %d: %w", i, err)
}
}

hasRelations := selects.hasAnyRelation()
returningCols := q.selectCategoryToPostCols(selects, omits)
Expand Down
8 changes: 8 additions & 0 deletions integration/valkyrie/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,14 @@ var UserRole = userRoleNamespace{
Teacher: UserRoleTypeTeacher,
}

func (e UserRoleType) IsValid() bool {
switch e {
case UserRoleTypeAdmin, UserRoleTypeStudent, UserRoleTypeTeacher:
return true
}
return false
}

type Dialect interface {
Quote(ident string) string
BindVar(idx int) string
Expand Down
29 changes: 29 additions & 0 deletions integration/valkyrie/comment.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,22 @@ func (q *Queries) selectCommentCols(selects *CommentSelect, omits *CommentOmit,
return cols
}

func (input CommentCreateInput) Validate() error {
if input.Dummy3 == "" {
return fmt.Errorf("field Dummy3 is required")
}
if input.Dummy2 == "" {
return fmt.Errorf("field Dummy2 is required")
}
if input.PostId == "" {
return fmt.Errorf("field PostId is required")
}
if input.AuthorId == "" {
return fmt.Errorf("field AuthorId is required")
}
return nil
}

var CommentColOrder = []string{
"id",
"textify",
Expand All @@ -157,6 +173,9 @@ func (d *CommentDelegate) Create(input CommentCreateInput) *CreateBuilder[Commen
}

func (q *Queries) executeCommentCreate(ctx context.Context, input CommentCreateInput, selects *CommentSelect, omits *CommentOmit) (*Comment, error) {
if err := input.Validate(); err != nil {
return nil, err
}
m := q.CommentInputToMap(input)
cols, vals := mapToColsVals(m, CommentColOrder)

Expand Down Expand Up @@ -227,6 +246,11 @@ func (q *Queries) executeCommentCreateMany(ctx context.Context, inputs []Comment
if len(inputs) == 0 {
return 0, nil
}
for i, input := range inputs {
if err := input.Validate(); err != nil {
return 0, fmt.Errorf("validation failed at index %d: %w", i, err)
}
}

if q.dialect.SupportsBulkInsert() {
rowMaps := make([]map[string]any, len(inputs))
Expand Down Expand Up @@ -259,6 +283,11 @@ func (q *Queries) executeCommentCreateManyAndReturn(ctx context.Context, inputs
if len(inputs) == 0 {
return nil, nil
}
for i, input := range inputs {
if err := input.Validate(); err != nil {
return nil, fmt.Errorf("validation failed at index %d: %w", i, err)
}
}

hasRelations := selects.hasAnyRelation()
returningCols := q.selectCommentCols(selects, omits)
Expand Down
23 changes: 23 additions & 0 deletions integration/valkyrie/post.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,16 @@ func (q *Queries) selectPostCols(selects *PostSelect, omits *PostOmit, forceCols
return cols
}

func (input PostCreateInput) Validate() error {
if input.Title == "" {
return fmt.Errorf("field Title is required")
}
if input.AuthorId == "" {
return fmt.Errorf("field AuthorId is required")
}
return nil
}

var PostColOrder = []string{
"id",
"title",
Expand All @@ -142,6 +152,9 @@ func (d *PostDelegate) Create(input PostCreateInput) *CreateBuilder[Post, PostCr
}

func (q *Queries) executePostCreate(ctx context.Context, input PostCreateInput, selects *PostSelect, omits *PostOmit) (*Post, error) {
if err := input.Validate(); err != nil {
return nil, err
}
m := q.PostInputToMap(input)
cols, vals := mapToColsVals(m, PostColOrder)

Expand Down Expand Up @@ -214,6 +227,11 @@ func (q *Queries) executePostCreateMany(ctx context.Context, inputs []PostCreate
if len(inputs) == 0 {
return 0, nil
}
for i, input := range inputs {
if err := input.Validate(); err != nil {
return 0, fmt.Errorf("validation failed at index %d: %w", i, err)
}
}

if q.dialect.SupportsBulkInsert() {
rowMaps := make([]map[string]any, len(inputs))
Expand Down Expand Up @@ -246,6 +264,11 @@ func (q *Queries) executePostCreateManyAndReturn(ctx context.Context, inputs []P
if len(inputs) == 0 {
return nil, nil
}
for i, input := range inputs {
if err := input.Validate(); err != nil {
return nil, fmt.Errorf("validation failed at index %d: %w", i, err)
}
}

hasRelations := selects.hasAnyRelation()
returningCols := q.selectPostCols(selects, omits)
Expand Down
20 changes: 20 additions & 0 deletions integration/valkyrie/profile.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,13 @@ func (q *Queries) selectProfileCols(selects *ProfileSelect, omits *ProfileOmit,
return cols
}

func (input ProfileCreateInput) Validate() error {
if input.UserId == "" {
return fmt.Errorf("field UserId is required")
}
return nil
}

var ProfileColOrder = []string{
"id",
"bio",
Expand All @@ -118,6 +125,9 @@ func (d *ProfileDelegate) Create(input ProfileCreateInput) *CreateBuilder[Profil
}

func (q *Queries) executeProfileCreate(ctx context.Context, input ProfileCreateInput, selects *ProfileSelect, omits *ProfileOmit) (*Profile, error) {
if err := input.Validate(); err != nil {
return nil, err
}
m := q.ProfileInputToMap(input)
cols, vals := mapToColsVals(m, ProfileColOrder)

Expand Down Expand Up @@ -186,6 +196,11 @@ func (q *Queries) executeProfileCreateMany(ctx context.Context, inputs []Profile
if len(inputs) == 0 {
return 0, nil
}
for i, input := range inputs {
if err := input.Validate(); err != nil {
return 0, fmt.Errorf("validation failed at index %d: %w", i, err)
}
}

if q.dialect.SupportsBulkInsert() {
rowMaps := make([]map[string]any, len(inputs))
Expand Down Expand Up @@ -218,6 +233,11 @@ func (q *Queries) executeProfileCreateManyAndReturn(ctx context.Context, inputs
if len(inputs) == 0 {
return nil, nil
}
for i, input := range inputs {
if err := input.Validate(); err != nil {
return nil, fmt.Errorf("validation failed at index %d: %w", i, err)
}
}

hasRelations := selects.hasAnyRelation()
returningCols := q.selectProfileCols(selects, omits)
Expand Down
Loading
Loading