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

{{ $pkg := base $.Config.Package }}
{{ template "header" $ }}

{{ with extend $ "Imports" $.SiblingImports }}
	{{ template "import" . }}
{{ end }}

{{ template "model/comment" $ }}
{{- with $tmpls := matchTemplate "model/comment/additional/*" }}
	{{- range $tmpl := $tmpls }}
		{{- xtemplate $tmpl $ }}
	{{- end }}
{{- end }}
type {{ $.Name }} struct {
	config {{ template "model/omittags" $ }}
	{{- if $.HasOneFieldID }}
		// ID of the ent.
		{{- if $.ID.Comment }}
			{{- range $line := split $.ID.Comment "\n" }}
				// {{ $line }}
			{{- end }}
		{{- end }}
		ID {{ $.ID.Type }} {{ with $.Annotations.Fields.StructTag.id }}`{{ . }}`{{ else }}`{{ $.ID.StructTag }}`{{ end }}
	{{- end }}
	{{- range $f := $.Fields }}
		{{- $tag := $f.StructTag }}{{ with $tags := $.Annotations.Fields.StructTag }}{{ with index $tags $f.Name }}{{ $tag = . }}{{ end }}{{ end }}
		{{- template "model/fieldcomment" $f }}
		{{ $f.StructField }} {{ if $f.NillableValue }}*{{ end }}{{ $f.Type }} {{ if not $f.Sensitive }}`{{ $tag }}`{{ else }}{{ template "model/omittags" $ }}{{ end }}
	{{- end }}
	{{- with $.Edges }}
		// Edges holds the relations/edges for other nodes in the graph.
		// The values are being populated by the {{ $.Name }}Query when eager-loading is set.
		Edges {{ $.Name }}Edges {{ template "model/edgetags" $ }}
	{{- end -}}
	{{- /* Additional fields to add by the storage driver. */}}
	{{- $tmpl := printf "dialect/%s/model/fields" $.Storage }}
	{{- if hasTemplate $tmpl }}
		{{- xtemplate $tmpl . }}
	{{- end }}
	{{- /* Additional fields to add by the user. */}}
	{{- template "model/fields/additional" $ }}
}

{{- with $.Edges }}
// {{ $.Name }}Edges holds the relations/edges for other nodes in the graph.
type {{ $.Name }}Edges struct {
	{{- range $e := . }}
		{{- template "model/edgecomment" $e }}
		{{ $e.StructField }} {{ if not $e.Unique }}[]{{ end }}*{{ $e.Type.Name }} {{ with $e.StructTag }}`{{ . }}`{{ end }}
	{{- end }}
	// loadedTypes holds the information for reporting if a
	// type was loaded (or requested) in eager-loading or not.
	loadedTypes [{{ len . }}]bool
	{{- /* Additional fields to add by the user. */}}
	{{- template "model/edges/fields/additional" $ }}
}

{{- range $i, $e := . }}
	// {{ $e.StructField }}OrErr returns the {{ $e.StructField }} value or an error if the edge
	// was not loaded in eager-loading{{ if $e.Unique }}, or loaded but was not found{{ end }}.
	func (e {{ $.Name }}Edges) {{ $e.StructField }}OrErr() ({{ if not $e.Unique }}[]{{ end }}*{{ $e.Type.Name }}, error) {
		if e.loadedTypes[{{ $i }}] {
			{{- if $e.Unique }}
				if e.{{ $e.StructField }} == nil {
					// Edge was loaded but was not found.
					return nil, &NotFoundError{label: {{ $e.Type.Package }}.Label}
				}
			{{- end }}
			return e.{{ $e.StructField }}, nil
		}
		return nil, &NotLoadedError{edge: "{{ $e.Name }}"}
	}
{{- end }}
{{- end }}

{{ $tmpl = printf "dialect/%s/decode/one" $.Storage }}
{{ xtemplate $tmpl $ }}

{{ $receiver := $.Receiver }}

{{ range $e := $.Edges }}
	{{ $func := print "Query" $e.StructField }}
	// {{ $func }} queries the "{{ $e.Name }}" edge of the {{ $.Name }} entity.
	func ({{ $receiver }} *{{ $.Name }}) {{ $func }}() *{{ $e.Type.QueryName }} {
		return New{{ $.ClientName }}({{ $receiver }}.config).{{ $func }}({{ $receiver }})
	}
{{ end }}

// Update returns a builder for updating this {{ $.Name }}.
// Note that you need to call {{ $.Name }}.Unwrap() before calling this method if this {{ $.Name }}
// was returned from a transaction, and the transaction was committed or rolled back.
func ({{ $receiver }} *{{ $.Name }}) Update() *{{ $.UpdateOneName }} {
	return New{{ $.ClientName }}({{ $receiver }}.config).UpdateOne({{ $receiver }})
}

// Unwrap unwraps the {{ $.Name }} entity that was returned from a transaction after it was closed,
// so that all future queries will be executed through the driver which created the transaction.
func ({{ $receiver }} *{{ $.Name }}) Unwrap() *{{ $.Name }} {
	_tx, ok := {{ $receiver }}.config.driver.(*txDriver)
	if !ok {
		panic("{{ $pkg }}: {{ $.Name }} is not a transactional entity")
	}
	{{ $receiver }}.config.driver = _tx.drv
	return {{ $receiver }}
}

{{ template "model/stringer" $ }}

{{ template "model/additional" $ }}

{{ $slice := plural $.Name }}
// {{ $slice }} is a parsable slice of {{ $.Name }}.
type {{ $slice }} []*{{ $.Name }}

{{ with extend $ "Slice" $slice }}
	{{ $tmpl := printf "dialect/%s/decode/many" $.Storage }}
	{{ xtemplate $tmpl . }}
{{ end }}
{{ end }}

{{/* A template to generate a fmt.Stringer implementation. */}}
{{ define "model/stringer" }}
	{{ $receiver := $.Receiver }}

	// String implements the fmt.Stringer.
	func ({{ $receiver }} *{{ $.Name }}) String() string {
		var builder strings.Builder
		builder.WriteString("{{ $.Name }}(")
		{{- if $.HasOneFieldID }}
			builder.WriteString(fmt.Sprintf("id=%v{{ if $.Fields }}, {{ end }}", {{ $receiver }}.ID))
		{{- end }}
		{{- range $i, $f := $.Fields }}
			{{- if ne $i 0 }}
				builder.WriteString(", ")
			{{- end }}
			{{- if $f.Sensitive }}
				builder.WriteString("{{ $f.Name }}={{ print "<sensitive>" }}")
			{{- else }}
				{{- $sf := printf "%s.%s" $receiver $f.StructField }}
				{{- if $f.Nillable }}
					if v := {{ $sf }}; v != nil {
						builder.WriteString("{{ $f.Name }}=")
						{{- if and $f.IsTime (not $f.HasGoType) }}
							builder.WriteString(v.Format(time.ANSIC))
						{{- else if and $f.IsString (not $f.HasGoType) }}
							builder.WriteString(*v)
						{{- else }}
							builder.WriteString(fmt.Sprintf("%v", *v))
						{{- end }}
					}
				{{- else }}
					builder.WriteString("{{ $f.Name }}=")
					{{- if and $f.IsTime (not $f.HasGoType) }}
						builder.WriteString({{ $sf }}.Format(time.ANSIC))
					{{- else if and $f.IsString (not $f.HasGoType) }}
						builder.WriteString({{ $sf }})
					{{- else }}
						builder.WriteString(fmt.Sprintf("%v", {{ $sf }}))
					{{- end }}
				{{- end }}
			{{- end }}
		{{- end }}
		builder.WriteByte(')')
		return builder.String()
	}
{{ end }}

{{/* A template for generating the Entity's comment. */}}
{{- define "model/comment" }}
	{{- if and $.Annotations.Comment $.Annotations.Comment.Text }}
		{{- range $line := split $.Annotations.Comment.Text "\n" }}
			// {{ $line }}
		{{- end }}
	{{- else }}
		// {{ $.Name }} is the model entity for the {{ $.Name }} schema.
	{{- end }}
{{- end }}

{{/* A template for generating the tag of the Edges struct-field. */}}
{{- define "model/edgetags" }}
	{{- $tag := `json:"edges"` }}
	{{- with $.Annotations.Edges.StructTag }}
		{{- if tagLookup . "json" }}
			{{- $tag = . }}
		{{- else }}
			{{- $tag = print $tag " " . }}
		{{- end }}
	{{- end }}
	{{- print "`" $tag "`" }}
{{- end }}

{{/* A template for omitting struct-tags. */}}
{{ define "model/omittags" }}{{ with $.TagTypes }}`{{ range $i, $t := . }}{{ if ne $i 0 }} {{ end }}{{ $t }}:"-"{{ end }}`{{ end }}{{ end }}

{{/* A template that can be overridden in order to add additional fields to the each type.*/}}
{{ define "model/fields/additional" }}{{ end }}

{{/* A template for setting the field comment. */}}
{{- define "model/fieldcomment" }}
	{{- if $.Comment }}
		{{- range $line := split $.Comment "\n" }}
			// {{ $line }}
		{{- end }}
	{{- else }}
		// {{ $.StructField }} holds the value of the "{{ $.Name }}" field.
	{{- end }}
{{- end }}

{{/* A template for setting the edge comment. */}}
{{- define "model/edgecomment" }}
	{{- if $.Comment }}
		{{- range $line := split $.Comment "\n" }}
			// {{ $line }}
		{{- end }}
	{{- else }}
		// {{ $.StructField }} holds the value of the {{ $.Name }} edge.
	{{- end }}
{{- end }}

{{/* A template for adding additional methods or helpers for the generated model. */}}
{{ define "model/additional" }}
	{{- with $tmpls := matchTemplate "model/additional/*"  }}
		{{- range $tmpl := $tmpls }}
			{{- xtemplate $tmpl $ }}
		{{- end }}
	{{- end }}

	{{- with $tmpls := matchTemplate (printf "dialect/%s/model/additional/*" $.Storage) }}
		{{- range $tmpl := $tmpls }}
			{{- xtemplate $tmpl $ }}
		{{- end }}
	{{- end }}
{{ end }}

{{/* A template for adding additional fields for the Edges object of the generated model. */}}
{{ define "model/edges/fields/additional" }}
	{{- with $tmpls := matchTemplate "model/edges/fields/additional/*"  }}
		{{- range $tmpl := $tmpls }}
			{{- xtemplate $tmpl $ }}
		{{- end }}
	{{- end }}

	{{- with $tmpls := matchTemplate (printf "dialect/%s/model/edges/fields/additional/*" $.Storage) }}
		{{- range $tmpl := $tmpls }}
			{{- xtemplate $tmpl $ }}
		{{- end }}
	{{- end }}
{{ end }}
