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

{{ define "schema" }}

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

import (
	{{ range $n := $.Nodes }}
		"{{ $.Config.Package }}/{{ $n.Package }}"
	{{- end }}

	"entgo.io/ent/dialect/entsql"
	"entgo.io/ent/dialect/sql/schema"
	"entgo.io/ent/schema/field"
)

var (
	{{- range $t := $.Tables }}
		{{- /* find type node in the graph of this table, if exists */}}
		{{- $node := index $.Nodes 0 }}
		{{- range $n := $.Nodes }}{{ if eq $t.Name $n.Table }}{{ $node = $n }}{{ end }}{{ end }}
		{{- $columns := pascal $t.Name | printf "%sColumns" }}
		// {{ $columns }} holds the columns for the "{{ $t.Name }}" table.
		{{ $columns }} = []*schema.Column{
			{{- range $c := $t.Columns }}
				{ Name: "{{ $c.Name }}", Type: field.{{ $c.Type.ConstName }},
				{{- if $c.Unique }} Unique: true,{{ end }}
				{{- if $c.Increment }} Increment: true,{{ end }}
				{{- if $c.Nullable }} Nullable: {{ $c.Nullable }},{{ end }}
				{{- with $c.Size }} Size: {{ . }},{{ end }}
				{{- with $c.Attr }} Attr: "{{ . }}",{{ end }}
				{{- with $c.Enums }} Enums: []string{ {{ range $e := . }}"{{ $e }}",{{ end }} },{{ end }}
				{{- if not (isNil $c.Default) }} Default: {{ $c.Default }},{{ end }}
				{{- if ne (len $c.Collation) 0 }} Collation: {{ $c.Collation }},{{ end }}
				{{- with $c.SchemaType }} SchemaType: map[string]string{ {{ range $k, $v := . }}"{{ $k }}": "{{ $v }}",{{ end }}}{{ end }}},
			{{- end }}
		}
		{{- $table := pascal $t.Name | printf "%sTable" }}
		// {{ $table }} holds the schema information for the "{{ $t.Name }}" table.
		{{ $table }} = &schema.Table{
			Name: "{{ $t.Name }}",
			Columns: {{ $columns }},
			PrimaryKey: []*schema.Column{
				{{- range $pk := $t.PrimaryKey }}
					{{- range $i, $c := $t.Columns }}
						{{- if eq $pk.Name $c.Name }}{{ $columns }}[{{ $i }}],{{ end }}
					{{- end }}
				{{- end }}
			},
			{{- with $fks := $t.ForeignKeys }}
				ForeignKeys: []*schema.ForeignKey{
					{{- range $fk := $fks }}
						{
							Symbol: "{{ $fk.Symbol }}",
							Columns: []*schema.Column{
								{{- range $c1 := $fk.Columns }}
									{{- range $i, $c2 := $t.Columns }}
										{{- if eq $c1.Name $c2.Name }}{{ $columns }}[{{ $i }}],{{ end }}
									{{- end }}
								{{- end }}
							},
							{{- /* postpone refrencing to avoid typechecking loops */}}
							RefColumns: []*schema.Column{
								{{- range $c1 := $fk.RefColumns }}
									{{- range $i, $c2 := $fk.RefTable.Columns }}
										{{- if eq $c1.Name $c2.Name }}{{ pascal $fk.RefTable.Name | printf "%sColumns" }}[{{ $i }}],{{ end }}
									{{- end }}
								{{- end }}
							},
							{{- with $fk.OnUpdate.ConstName }}
								OnUpdate: schema.{{ . }},
							{{- end }}
							{{- with $fk.OnDelete.ConstName }}
								OnDelete: schema.{{ . }},
							{{- end }}
						},
					{{- end }}
				},
			{{- end }}
			{{- if $t.Indexes }}
				Indexes: []*schema.Index{
					{{- range $idx := $t.Indexes }}
						{
							Name: "{{ $idx.Name }}",
							Unique: {{ $idx.Unique }},
							Columns: []*schema.Column{
								{{- range $c1 := $idx.Columns }}
									{{- range $i, $c2 := $t.Columns }}
										{{- if eq $c1.Name $c2.Name }}{{ $columns }}[{{ $i }}],{{ end }}
									{{- end }}
								{{- end }}
							},
							{{- with $ant := $idx.Annotation }}
								Annotation: &entsql.IndexAnnotation{
									{{- with $ant.Prefix }}
										Prefix: {{ . }},
									{{- end }}
									{{- with $keys := keys $ant.PrefixColumns }}
										PrefixColumns: map[string]uint{
											{{- range $k := $keys }}
												{{- /* Use the column reference instead of using raw string. */}}
												{{- range $i, $c := $t.Columns }}
													{{- if eq $k $c.Name }}
														{{ $columns }}[{{ $i }}].Name: {{ index $ant.PrefixColumns $k }},
													{{ end }}
												{{- end }}
											{{- end }}
										},
									{{- end }}
								},
							{{- end }}
						},
					{{- end }}
				},
			{{- end }}
		}
	{{- end }}
	// Tables holds all the tables in the schema.
	Tables = []*schema.Table{
		{{- range $t := $.Tables }}
			{{ pascal $t.Name | printf "%sTable" }},
		{{- end }}
	}
)

func init() {
	{{- range $t := $.Tables }}
		{{- $table := pascal $t.Name | printf "%sTable" }}
		{{- range $i, $fk := $t.ForeignKeys }}
			{{ $table }}.ForeignKeys[{{ $i }}].RefTable = {{ pascal $fk.RefTable.Name | printf "%sTable" }}
		{{- end }}
		{{- with $ant := $t.Annotation }}
			{{ $table }}.Annotation = &entsql.Annotation{
				{{- with $ant.Table }}
					Table: "{{ . }}",
				{{- end }}
				{{- with $ant.Charset }}
					Charset: "{{ . }}",
				{{- end }}
				{{- with $ant.Collation }}
					Collation: "{{ . }}",
				{{- end }}
				{{- with $ant.Options }}
					Options: "{{ . }}",
				{{- end }}
				{{- with $ant.Check }}
					Check: "{{ . }}",
				{{- end }}
			}
			{{- with $ant.Incremental }}
				{{ $table }}.Annotation.Incremental = new(bool)
				*{{ $table }}.Annotation.Incremental = {{ with indirect . }}true{{ else }}false{{ end }}
			{{- end }}
			{{- with $keys := keys $ant.Checks }}
				{{ $table }}.Annotation.Checks = map[string]string{
					{{- range $k := $keys }}
						"{{ $k }}": "{{ index $ant.Checks $k }}",
					{{- end }}
				}
			{{- end }}
		{{- end }}
	{{- end }}
}

{{ end }}
