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

{{/* gotype: entgo.io/ent/entc/gen.Type*/}}

{{ 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 }} field in the database.
		{{ $field }} = "{{ $f.StorageKey }}"
	{{- end }}
	{{- range $e := $.Edges }}
		{{- $edge := $e.Constant }}
		// {{ $edge }} holds the string denoting the {{ lower $e.Name }} edge name in mutations.
		{{ $edge }} = "{{ $e.Name }}"
	{{- end }}
	{{- $tmpl := printf "dialect/%s/meta/constants" $.Storage }}
	{{- xtemplate $tmpl $ }}
)

{{ $tmpl = printf "dialect/%s/meta/variables" $.Storage }}
{{ if hasTemplate $tmpl }}
	{{ xtemplate $tmpl $ }}
{{ end }}

{{ $tmpl = printf "dialect/%s/meta/functions" $.Storage }}
{{ if hasTemplate $tmpl }}
	{{ xtemplate $tmpl $ }}
{{ end }}

{{/* Has at least one field (not enum) with default value */}}
{{ $fields := $.Fields }}{{ if $.ID.UserDefined }}{{ $fields = append $fields $.ID }}{{ end }}
{{ $hasDefault := false }}{{ range $f := $fields }}{{ if and $f.Default (not $f.IsEnum) }}{{ $hasDefault = true }}{{ end }}{{ end }}

{{/* Generate global variables for hooks, validators and policy checkers */}}
{{ if or $hasDefault $.HasValidators $.NumHooks $.NumPolicy }}
	{{- $numHooks := $.NumHooks }}
	{{- if $.NumPolicy }}
		{{- $numHooks = add $numHooks 1 }}
	{{- end }}
	{{- if $numHooks }}
		// Note that the variables below are initialized by the runtime
		// package on the initialization of the application. Therefore,
		// it should be imported in the main as follows:
		//
		//	import _ "{{ $.Config.Package }}/runtime"
		//
	{{- end }}
	var (
		{{- if $numHooks }}
			Hooks [{{ $numHooks }}]ent.Hook
		{{- end }}
		{{- if $.NumPolicy }}
			Policy ent.Policy
		{{- end }}
		{{- $fields := $.Fields }}{{ if $.ID.UserDefined }}{{ $fields = append $fields $.ID }}{{ end }}
		{{- range $f := $fields }}
			{{- if and $f.Default (not $f.IsEnum) }}
				{{- $default := $f.DefaultName }}
				// {{ $default }} holds the default value on creation for the "{{ $f.Name }}" field.
				{{ $default }} {{ if $f.DefaultFunc }}func() {{ end }}{{ $f.Type }}
			{{- end }}
			{{- if $f.UpdateDefault }}
				{{- $default := $f.UpdateDefaultName }}
				// {{ $default }} holds the default value on update for the "{{ $f.Name }}" field.
				{{ $default }} {{ if $f.IsTime }}func() {{ end }}{{ $f.Type }}
			{{- end }}
			{{- with $f.Validators }}
				{{- $name := $f.Validator }}
				{{- $type :=  printf "func (%s) error" $f.Type.Type }}
				// {{ $name }} is a validator for the "{{ $f.Name }}" field. It is called by the builders before save.
				{{ $name }} {{ $type }}
			{{- end }}
		{{- end }}
	)
{{ end }}

{{/* define custom type for enum fields */}}
{{ range $f := $.EnumFields }}
	{{ $enum := $f.Type }}
	{{ $receiver := receiver $f.BuilderField }}
	{{ if $f.HasGoType }}
		{{ if $f.Default }}
			const {{ $f.DefaultName }} {{ $enum }} = "{{ $f.DefaultValue }}"
		{{ end }}
	{{ else }}
		{{/* 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

		{{- if $f.Default }}
			{{- /*  find the enum that holds the default value. */ -}}
			{{- range $e := $f.Enums }}
				{{- if eq $e.Value $f.DefaultValue }}
					// {{ $e.Name }} is the default value of the {{ $enum }} enum.
					const {{ $f.DefaultName }} = {{ $e.Name }}
				{{- end }}
			{{- end }}
		{{- end }}

		// {{ $enum }} values.
		const (
			{{- range $e := $f.Enums }}
				{{ $e.Name }} {{ $enum }} = "{{ $e.Value }}"
			{{-  end }}
		)

		func ({{ $receiver }} {{ $enum }}) String() string {
			return string({{ $receiver }})
		}
	{{ end }}


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

{{ template "meta/additional" $ }}

{{ with $tmpls := matchTemplate "meta/additional/*" }}
	{{ range $tmpl := $tmpls }}
		{{ xtemplate $tmpl $ }}
	{{ end }}
{{ end }}

{{ end }}

{{/* A template that can be overridden in order to add additional code for the type package. */}}
{{ define "meta/additional" }}{{ end }}
