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

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

{{ template "import" $ }}

// {{ $.Name }} is the model entity for the {{ $.Name }} schema.
type {{ $.Name }} struct {
	config {{ template "model/omittags" $ }}
	// ID of the ent.
	ID {{ $.ID.Type }} `json:"id,omitempty"`
	{{ range $_, $f := $.Fields -}}
		// {{ $f.StructField }} holds the value of the "{{ $f.Name }}" field.
    	{{ $f.StructField }} {{ if $f.Nillable }}*{{ end }}{{ $f.Type }} {{ if not $f.Sensitive }}`{{ $f.StructTag }}`{{ else }}{{ template "model/omittags" $ }}{{ end }}
	{{ end -}}
	{{ range $_, $e := $.Edges -}}
		{{/* ignore generating edge fields */}}
		{{- with $e.StructTag -}}
			// {{ $e.StructField }} holds the value of the {{ $e.Name }} edge. The value set to nil, and should be updated manually.
			{{ $e.StructField }} {{ if not $e.Unique }}[]{{ end }}*{{ $e.Type.Name }} `{{ $e.StructTag }}`
		{{ end -}}
	{{ end -}}
	{{ template "model/fields/additional" $ }}
}

{{ range $_, $storage := $.Storage }}
	{{ $tmpl := printf "dialect/%s/decode/one" $storage }}
	{{ xtemplate $tmpl $ }}
{{ end }}

{{ $receiver := $.Receiver }}

{{ range $_, $e := $.Edges }}
	{{ $func := print "Query" $e.StructField }}
	// {{ $func }} queries the {{ $e.Name }} edge of the {{ $.Name }}.
	func ({{ $receiver }} *{{ $.Name }}) {{ $func }}() *{{ $e.Type.Name}}Query {
		return (&{{ $.Name }}Client{ {{ $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() *{{ $.Name }}UpdateOne {
	return (&{{ $.Name }}Client{ {{ $receiver }}.config}).UpdateOne({{ $receiver }})
}

// Unwrap unwraps the entity that was returned from a transaction after it was closed,
// so that all next 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 }}
}

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

{{- if $.ID.IsString }}
// id returns the int representation of the ID field.
func ({{ $receiver }} *{{ $.Name }}) id() int {
	id, _ := strconv.Atoi({{ $receiver }}.ID)
	return id
}
{{- end }}

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

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

func ({{ $receiver }} {{ $slice }}) config(cfg config) {
	for _i := range {{ $receiver }} {
		{{ $receiver }}[_i].config = cfg
	}
}
{{ 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 overrided in order to add additional fields to the each type.*/}}
{{ define "model/fields/additional" }}{{end}}
