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
1 change: 1 addition & 0 deletions generator/generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ func GenerateClient(sch schema.Schema, pkgName string, parentImportPath string,
}
return false
},
"trimPrefix": strings.TrimPrefix,
"hasStringField": func(m *schema.Model) bool {
for _, sf := range m.ScalarFields {
if sf.GoType == "string" || strings.Contains(sf.GoType, "string") {
Expand Down
8 changes: 4 additions & 4 deletions generator/generator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,13 @@ func TestGenerateClient_NativeDBConstraints(t *testing.T) {
t.Fatal("expected item.go in outputs")
}

// Verify length checks are generated
if !strings.Contains(itemCode, "utf8.RuneCountInString(input.Code) > 8") {
// Verify length checks are generated in validate function
if !strings.Contains(itemCode, `utf8.RuneCountInString(v) > 8`) {
t.Errorf("expected generated code to contain VarChar limit check, got:\n%s", itemCode)
}

// Verify SmallInt range checks are generated
if !strings.Contains(itemCode, "input.Count < -32768 || input.Count > 32767") {
// Verify SmallInt range checks are generated in validate function
if !strings.Contains(itemCode, "v < -32768 || v > 32767") {
t.Errorf("expected generated code to contain SmallInt limit check, got:\n%s", itemCode)
}
}
80 changes: 40 additions & 40 deletions generator/templates/builders_create.gotpl
Original file line number Diff line number Diff line change
@@ -1,83 +1,83 @@
type CreateBuilder[M any, I any, S any, O any] struct {
client *Queries
input I
execFunc func(ctx context.Context, input I, s *S, o *O) (*M, error)
type CreateBuilder[M any, S any, O any] struct {
client *Queries
assignments []FieldAssignment
execFunc func(ctx context.Context, assignments []FieldAssignment, s *S, o *O) (*M, error)
}

func (b *CreateBuilder[M, I, S, O]) Select(s S) *CreateSelectBuilder[M, I, S, O] {
return &CreateSelectBuilder[M, I, S, O]{builder: b, selects: s}
func (b *CreateBuilder[M, S, O]) Select(s S) *CreateSelectBuilder[M, S, O] {
return &CreateSelectBuilder[M, S, O]{builder: b, selects: s}
}

func (b *CreateBuilder[M, I, S, O]) Omit(o O) *CreateOmitBuilder[M, I, S, O] {
return &CreateOmitBuilder[M, I, S, O]{builder: b, omits: o}
func (b *CreateBuilder[M, S, O]) Omit(o O) *CreateOmitBuilder[M, S, O] {
return &CreateOmitBuilder[M, S, O]{builder: b, omits: o}
}

func (b *CreateBuilder[M, I, S, O]) Exec(ctx context.Context) (*M, error) {
return b.execFunc(ctx, b.input, nil, nil)
func (b *CreateBuilder[M, S, O]) Exec(ctx context.Context) (*M, error) {
return b.execFunc(ctx, b.assignments, nil, nil)
}

type CreateSelectBuilder[M any, I any, S any, O any] struct {
builder *CreateBuilder[M, I, S, O]
type CreateSelectBuilder[M any, S any, O any] struct {
builder *CreateBuilder[M, S, O]
selects S
}

func (b *CreateSelectBuilder[M, I, S, O]) Exec(ctx context.Context) (*M, error) {
return b.builder.execFunc(ctx, b.builder.input, &b.selects, nil)
func (b *CreateSelectBuilder[M, S, O]) Exec(ctx context.Context) (*M, error) {
return b.builder.execFunc(ctx, b.builder.assignments, &b.selects, nil)
}

type CreateOmitBuilder[M any, I any, S any, O any] struct {
builder *CreateBuilder[M, I, S, O]
type CreateOmitBuilder[M any, S any, O any] struct {
builder *CreateBuilder[M, S, O]
omits O
}

func (b *CreateOmitBuilder[M, I, S, O]) Exec(ctx context.Context) (*M, error) {
return b.builder.execFunc(ctx, b.builder.input, nil, &b.omits)
func (b *CreateOmitBuilder[M, S, O]) Exec(ctx context.Context) (*M, error) {
return b.builder.execFunc(ctx, b.builder.assignments, nil, &b.omits)
}

type CreateManyBuilder[M any, I any] struct {
type CreateManyBuilder[M any] struct {
client *Queries
inputs []I
execFunc func(ctx context.Context, inputs []I) (int64, error)
records []RecordInput
execFunc func(ctx context.Context, records []RecordInput) (int64, error)
}

func (b *CreateManyBuilder[M, I]) Exec(ctx context.Context) (int64, error) {
return b.execFunc(ctx, b.inputs)
func (b *CreateManyBuilder[M]) Exec(ctx context.Context) (int64, error) {
return b.execFunc(ctx, b.records)
}

type CreateManyAndReturnBuilder[M any, I any, S any, O any] struct {
type CreateManyAndReturnBuilder[M any, S any, O any] struct {
client *Queries
inputs []I
execFunc func(ctx context.Context, inputs []I, s *S, o *O) ([]*M, error)
records []RecordInput
execFunc func(ctx context.Context, records []RecordInput, s *S, o *O) ([]*M, error)
}

func (b *CreateManyAndReturnBuilder[M, I, S, O]) Select(s S) *CreateManyAndReturnSelectBuilder[M, I, S, O] {
return &CreateManyAndReturnSelectBuilder[M, I, S, O]{builder: b, selects: s}
func (b *CreateManyAndReturnBuilder[M, S, O]) Select(s S) *CreateManyAndReturnSelectBuilder[M, S, O] {
return &CreateManyAndReturnSelectBuilder[M, S, O]{builder: b, selects: s}
}

func (b *CreateManyAndReturnBuilder[M, I, S, O]) Omit(o O) *CreateManyAndReturnOmitBuilder[M, I, S, O] {
return &CreateManyAndReturnOmitBuilder[M, I, S, O]{builder: b, omits: o}
func (b *CreateManyAndReturnBuilder[M, S, O]) Omit(o O) *CreateManyAndReturnOmitBuilder[M, S, O] {
return &CreateManyAndReturnOmitBuilder[M, S, O]{builder: b, omits: o}
}

func (b *CreateManyAndReturnBuilder[M, I, S, O]) Exec(ctx context.Context) ([]*M, error) {
return b.execFunc(ctx, b.inputs, nil, nil)
func (b *CreateManyAndReturnBuilder[M, S, O]) Exec(ctx context.Context) ([]*M, error) {
return b.execFunc(ctx, b.records, nil, nil)
}

type CreateManyAndReturnSelectBuilder[M any, I any, S any, O any] struct {
builder *CreateManyAndReturnBuilder[M, I, S, O]
type CreateManyAndReturnSelectBuilder[M any, S any, O any] struct {
builder *CreateManyAndReturnBuilder[M, S, O]
selects S
}

func (b *CreateManyAndReturnSelectBuilder[M, I, S, O]) Exec(ctx context.Context) ([]*M, error) {
return b.builder.execFunc(ctx, b.builder.inputs, &b.selects, nil)
func (b *CreateManyAndReturnSelectBuilder[M, S, O]) Exec(ctx context.Context) ([]*M, error) {
return b.builder.execFunc(ctx, b.builder.records, &b.selects, nil)
}

type CreateManyAndReturnOmitBuilder[M any, I any, S any, O any] struct {
builder *CreateManyAndReturnBuilder[M, I, S, O]
type CreateManyAndReturnOmitBuilder[M any, S any, O any] struct {
builder *CreateManyAndReturnBuilder[M, S, O]
omits O
}

func (b *CreateManyAndReturnOmitBuilder[M, I, S, O]) Exec(ctx context.Context) ([]*M, error) {
return b.builder.execFunc(ctx, b.builder.inputs, nil, &b.omits)
func (b *CreateManyAndReturnOmitBuilder[M, S, O]) Exec(ctx context.Context) ([]*M, error) {
return b.builder.execFunc(ctx, b.builder.records, nil, &b.omits)
}

func executeInsert[M any](
Expand Down
28 changes: 28 additions & 0 deletions generator/templates/client.gotpl
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,18 @@ type Queries struct {
provider string
dialect Dialect
{{- range $model := .Schema.Models }}
// {{ $model.Name }} provides CRUD operations for {{ $model.Name }}.
//
{{- $maxName := 0 }}{{ $maxType := 0 }}
{{- range $f := $model.ScalarFields }}
{{- if gt (len $f.Name) $maxName }}{{ $maxName = len $f.Name }}{{ end }}
{{- $t := "" }}{{ if $f.EnumRef }}{{ $t = $f.EnumRef.Name }}{{ else }}{{ $t = trimPrefix $f.GoType "*" }}{{ end }}
{{- if gt (len $t) $maxType }}{{ $maxType = len $t }}{{ end }}
{{- end }}
{{- range $field := $model.ScalarFields }}
{{- $typeStr := "" }}{{ if $field.EnumRef }}{{ $typeStr = $field.EnumRef.Name }}{{ else }}{{ $typeStr = trimPrefix $field.GoType "*" }}{{ end }}
// {{ printf "%-*s" $maxName $field.Name }} {{ printf "%-*s" $maxType $typeStr }} {{ if and (eq $field.Default nil) (not $field.Optional) }}required{{ else if $field.Optional }}optional{{ else if $field.Default }}default: {{ $field.Default.Value }}{{ end }}
{{- end }}
{{ $model.Name }} *{{ $model.Name }}Delegate
{{- end }}
{{- range $enum := .Schema.Enums }}
Expand Down Expand Up @@ -370,6 +382,10 @@ type Field[T any] struct {
Column string
}

func (f Field[T]) Set(val T) FieldAssignment {
return FieldAssignment{Col: f.Column, Val: val}
}

func (f Field[T]) EQ(val T) Predicate {
return StandardPredicate{
Data: PredicateData{
Expand Down Expand Up @@ -462,6 +478,10 @@ type UniqueField[T any] struct {
Column string
}

func (f UniqueField[T]) Set(val T) FieldAssignment {
return FieldAssignment{Col: f.Column, Val: val}
}

type UniqueFieldPredicate struct {
StandardPredicate
}
Expand Down Expand Up @@ -569,6 +589,10 @@ type StringField struct {
Column string
}

func (f StringField) Set(val string) FieldAssignment {
return FieldAssignment{Col: f.Column, Val: val}
}

func (f StringField) EQ(val string) Predicate {
return StandardPredicate{
Data: PredicateData{
Expand Down Expand Up @@ -681,6 +705,10 @@ type StringUniqueField struct {
Column string
}

func (f StringUniqueField) Set(val string) FieldAssignment {
return FieldAssignment{Col: f.Column, Val: val}
}

func (f StringUniqueField) EQ(val string) UniquePredicate {
return UniqueFieldPredicate{
StandardPredicate: StandardPredicate{
Expand Down
8 changes: 8 additions & 0 deletions generator/templates/enums.gotpl
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,24 @@ type {{ $enum.Name }}Type string

const (
{{- range $val := $enum.ValueMap }}
// {{ capitalize $val.Name }} maps to "{{ $val.DBName }}"
{{ $enum.Name }}Type{{ capitalize $val.Name }} {{ $enum.Name }}Type = "{{ $val.DBName }}"
{{- end }}
)

type {{ lowercase $enum.Name }}Namespace struct {
{{- range $val := $enum.ValueMap }}
// {{ capitalize $val.Name }} maps to "{{ $val.DBName }}"
{{ capitalize $val.Name }} {{ $enum.Name }}Type
{{- end }}
}

// {{ $enum.Name }} enum values:
//
{{- $maxVal := 0 }}{{ range $v := $enum.ValueMap }}{{ if gt (len $v.Name) $maxVal }}{{ $maxVal = len $v.Name }}{{ end }}{{ end }}
{{- range $v := $enum.ValueMap }}
// {{ printf "%-*s" $maxVal $v.Name }} {{ $v.DBName }}
{{- end }}
var {{ $enum.Name }} = {{ lowercase $enum.Name }}Namespace{
{{- range $val := $enum.ValueMap }}
{{ capitalize $val.Name }}: {{ $enum.Name }}Type{{ capitalize $val.Name }},
Expand Down
9 changes: 9 additions & 0 deletions generator/templates/header.gotpl
Original file line number Diff line number Diff line change
Expand Up @@ -90,3 +90,12 @@ func (e *ValidationError) HasErrors() bool {
return len(e.Errors) > 0
}

type FieldAssignment struct {
Col string
Val any
}

type RecordInput struct {
Assignments []FieldAssignment
}

Loading
Loading