{{/*
Copyright 2019-present Facebook Inc. All rights reserved.
This source code is licensed under the Apache 2.0 license found
in the LICENSE file in the root directory of this source tree.
*/}}

{{ define "create" }}
{{ $pkg := base $.Config.Package }}

{{ template "header" $ }}

{{ template "import" $ }}

{{ $builder := print (pascal $.Name) "Create" }}
{{ $receiver := receiver $builder }}

// {{ $builder }} is the builder for creating a {{ $.Name }} entity.
type {{ $builder }} struct {
	config
	{{- if $.ID.UserDefined }}
		{{ $.ID.BuilderField }} *{{ $.ID.Type }}
	{{- end }}
	{{ range $_, $f := $.Fields }}
		{{- $f.BuilderField }} *{{ $f.Type }}
	{{ end }}
	{{- range $_, $e := $.Edges }}
		{{- $e.BuilderField }} map[{{ $e.Type.ID.Type }}]struct{}
	{{ end -}}
}

{{ with extend $ "Builder" $builder }}
	{{ template "setter" . }}
{{ end }}

// Save creates the {{ $.Name }} in the database.
func ({{ $receiver }} *{{ $builder }}) Save(ctx context.Context) (*{{ $.Name }}, error) {
	{{ range $_, $f := $.Fields -}}
		{{- if or $f.Default (not $f.Optional) -}}
			if {{ $receiver }}.{{ $f.BuilderField }} == nil {
				{{ if $f.Default -}}
					v := {{ $.Package }}.{{ $f.DefaultName }}{{ if or $f.IsTime $f.IsUUID }}(){{ end }}
					{{ $receiver }}.{{ $f.BuilderField }} = &v
				{{ else -}}
					return nil, errors.New("{{ $pkg }}: missing required field \"{{ $f.Name }}\"")
				{{ end -}}
			}
		{{ end -}}
		{{ with or $f.Validators $f.IsEnum -}}
			{{/* add nullable check only for optional fields without default value */ -}}
			{{ $nullable := and $f.Optional (not $f.Default) -}}
			{{- if $nullable }} if {{ $receiver }}.{{ $f.BuilderField }} != nil { {{ end -}}
				if err := {{ $.Package }}.{{ $f.Validator }}(*{{ $receiver }}.{{ $f.BuilderField }}); err != nil {
					return nil, fmt.Errorf("{{ $pkg }}: validator failed for field \"{{ $f.Name }}\": %v", err)
				}
			{{- if $nullable }} } {{ end }}
		{{ end -}}
	{{ end -}}
	{{- range $_, $e := $.Edges }}
		{{- if $e.Unique -}}
			if len({{ $receiver }}.{{ $e.BuilderField }}) > 1 {
				return nil, errors.New("{{ $pkg }}: multiple assignments on a unique edge \"{{ $e.Name }}\"")
			}
		{{ end -}}
		{{- if not $e.Optional -}}
			if {{ $receiver }}.{{ $e.BuilderField }} == nil {
				return nil, errors.New("{{ $pkg }}: missing required edge \"{{ $e.Name }}\"")
			}
		{{ end -}}
	{{ end -}}
	{{- if $.MultiStorage -}}
		switch {{ $receiver }}.driver.Dialect() {
		{{- range $_, $storage := $.Storage }}
		case {{ join $storage.Dialects ", " }}:
			return {{ $receiver }}.{{ $storage }}Save(ctx)
		{{- end }}
		default:
			return nil, errors.New("{{ $pkg }}: unsupported dialect")
		}
	{{- else -}}
		return {{ $receiver }}.{{ index $.Storage 0 }}Save(ctx)
	{{- end }}
}

// SaveX calls Save and panics if Save returns an error.
func ({{ $receiver }} *{{ $builder }}) SaveX(ctx context.Context) *{{ $.Name }} {
	v, err := {{ $receiver }}.Save(ctx)
	if err != nil {
		panic(err)
	}
	return v
}

{{- range $_, $storage := $.Storage }}
	{{ with extend $ "Builder" $builder }}
		{{ $tmpl := printf "dialect/%s/create" $storage }}
		{{ xtemplate $tmpl . }}
	{{ end }}
{{ end }}

{{ end }}
