{{/*
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 "meta" }}

{{- with extend $ "Package" $.Package -}}
	{{ template "header" . }}
{{ end }}

{{ template "import" $ }}

const (
	// Label holds the string label denoting the {{ lower $.Name }} type in the database.
	Label = "{{ $.Label }}"
	// {{ $.ID.Constant }} holds the string denoting the id field in the database.
	{{ $.ID.Constant }} = "{{ $.ID.StorageKey }}"
	{{ range $_, $f := $.Fields -}}{{ $field := $f.Constant -}}
		// {{ $field }} holds the string denoting the {{ lower $f.Name }} vertex property in the database.
		{{ $field }} = "{{ $f.StorageKey }}"
	{{ end -}}
	{{ range $_, $storage := $.Storage }}
		{{ $tmpl := printf "dialect/%s/meta/constants" $storage }}
		{{ xtemplate $tmpl $ }}
	{{ end }}
)

{{ range $_, $storage := $.Storage }}
	{{ $tmpl := printf "dialect/%s/meta/variables" $storage }}
	{{ if hasTemplate $tmpl }}
		{{ xtemplate $tmpl $ }}
	{{ end }}
{{ end }}

{{ if or $.HasDefault $.HasValidators }}
var (
	{{- with $.MixedInWithDefault }}
		mixin = {{ base $.Schema }}.{{ $.Name }}{}.Mixin()
		mixinFields = [...][]ent.Field{
			{{- range $i, $_ := xrange $.NumMixin }}
				mixin[{{ $i }}].Fields(),
			{{- end }}
		}
	{{- end }}
	fields = {{ base $.Schema }}.{{ $.Name }}{}.Fields()
	{{ range $i, $f := $.Fields -}}
		{{- $desc := print "desc" $f.StructField -}}
		{{ if or $f.Default $f.UpdateDefault $f.Validators -}}
			{{- if $f.Position.MixedIn }}
				// {{ $desc }} is the schema descriptor for {{ $f.Name }} field.
				{{ $desc }} = mixinFields[{{ $f.Position.MixinIndex }}][{{ $f.Position.Index }}].Descriptor()
			{{- else }}
				// {{ $desc }} is the schema descriptor for {{ $f.Name }} field.
				{{ $desc }} = fields[{{ $f.Position.Index }}].Descriptor()
			{{- end }}
		{{ end -}}
		{{ if $f.Default }}
			{{- $default := $f.DefaultName -}}
			// {{ $default }} holds the default value on creation for the {{ $f.Name }} field.
			{{ $default }} = {{ $desc }}.Default.({{ if or $f.IsTime $f.IsUUID }}func() {{ end }}{{ $f.Type }})
		{{ end -}}
		{{ if $f.UpdateDefault }}
			{{- $default := $f.UpdateDefaultName -}}
			// {{ $default }} holds the default value on update for the {{ $f.Name }} field.
			{{ $default }} = {{ $desc }}.UpdateDefault.({{ if $f.IsTime }}func() {{ end }}{{ $f.Type }})
		{{ end -}}
		{{ with $f.Validators -}}
			{{ $name := $f.Validator -}}
			{{ $type :=  printf "func (%s) error" $f.Type -}}
			// {{ $name }} is a validator for the "{{ $f.Name }}" field. It is called by the builders before save.
			{{ if eq $f.Validators 1 -}}
				{{ $name }} = {{ $desc }}.Validators[0].({{ $type }})
			{{ else -}}
				{{ $name }} = func() {{ $type }} {
					validators := {{ $desc }}.Validators
					fns := [...]func({{ $f.Type }}) error {
						{{- range $j, $n := xrange $f.Validators }}
							validators[{{ $j }}].(func({{ $f.Type }}) error),
						{{- end }}
					}
					return func({{ $f.BuilderField }} {{ $f.Type }}) error {
						for _, fn := range fns {
							if err := fn({{ $f.BuilderField }}); err != nil {
								return err
							}
						}
						return nil
					}
				}()
			{{ end -}}
		{{ end -}}
	{{ end -}}
)
{{ end }}


{{/* define custom type for enum fields */}}
{{ range $_, $f := $.Fields -}}
	{{ if $f.IsEnum }}
		{{/* omit the package name from the type. */}}
		{{ $enum := trimPackage $f.Type.String $.Package }}
		// {{ $enum }} defines the type for the {{ $f.Name }} enum field.
		type {{ $enum }} string

		const (
			{{- range $_, $e := $f.Enums }}
				{{ pascal $f.Name }}{{ pascal $e }} {{ $enum }} = "{{ $e }}"
			{{-  end }}
		)

		func (s {{ $enum }}) String() string {
			return string(s)
		}

		{{ $name := $f.Validator -}}
		// {{ $name }} is a validator for the "{{ $f.Name }}" field enum values. It is called by the builders before save.
		func {{ $name }}({{ $f.Name }} {{ $enum }}) error {
			switch {{ $f.Name }} {
				case {{ range $i, $e := $f.Enums }}{{ if ne $i 0 }},{{ end }}{{ $f.StructField }}{{ pascal $e }}{{ end }}:
					return nil
				default:
					return fmt.Errorf("{{ $.Package }}: invalid enum value for {{ $f.Name }} field: %q", {{ $f.Name }})
			}
		}
	{{ end }}
{{ end }}

{{ end }}
