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

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

{{ template "import" $ }}

// ID filters vertices based on their identifier.
func ID(id {{ $.ID.Type }}) predicate.{{ $.Name }} {
	return predicate.{{ $.Name }}{{ if $.MultiStorage }}PerDialect{{ end }}(
		{{ range $_, $storage := $.Storage -}}
			{{ $tmpl := printf "dialect/%s/predicate/id" $storage }}
			{{- xtemplate $tmpl $ }},
		{{ end -}}
	)
}

{{ range $_, $op := ops $.ID }}
	{{ $arg := "id" }}{{ if $op.Variadic }}{{ $arg = "ids" }}{{ end }}
	{{ $func := printf "ID%s" $op.Name }}
	// {{ $func }} applies the {{ $op.Name }} predicate on the ID field.
	func {{ $func }}({{ $arg }} {{ if $op.Variadic }}...{{ end }}{{ $.ID.Type }}) predicate.{{ $.Name }} {
		return predicate.{{ $.Name }}{{ if $.MultiStorage }}PerDialect{{ end }}(
			{{ range $_, $storage := $.Storage -}}
				{{- with extend $ "Arg" $arg "Op" $op "Storage" $storage -}}
					{{ $tmpl := printf "dialect/%s/predicate/id/ops" $storage }}
					{{- xtemplate $tmpl . }},
				{{ end -}}
			{{ end -}}
		)
	}
{{ end }}

{{ range $_, $f := $.Fields }}
	{{/* JSON cannot be compared using "=" and Enum has a type defined with the field name */}}
	{{- if not (or $f.IsJSON $f.IsEnum) }}
		{{ $func := $f.StructField }}
		// {{ $func }} applies equality check predicate on the {{ quote $f.Name }} field. It's identical to {{ $func }}EQ.
		func {{ $func }}(v {{ $f.Type }}) predicate.{{ $.Name }} {
			return predicate.{{ $.Name }}{{ if $.MultiStorage }}PerDialect{{ end }}(
				{{ range $_, $storage := $.Storage -}}
					{{- with extend $ "Field" $f -}}
						{{ $tmpl := printf "dialect/%s/predicate/field" $storage }}
						{{- xtemplate $tmpl . }},
					{{ end -}}
				{{ end -}}
			)
		}
	{{- end }}
{{ end }}

{{ range $_, $f := $.Fields }}
	{{ $ops := ops $f }}
	{{/* storage specific predicates disabled for multi-storage codegen */}}
	{{ if not $.MultiStorage }}
		{{ $storage := index $.Storage 0 }}
		{{ $ops = appends $ops (call $storage.Ops $f) }}
	{{ end }}
	{{ range $_, $op := $ops }}
	{{ $arg := "v" }}{{ if $op.Variadic }}{{ $arg = "vs" }}{{ end }}
	{{ $func := print $f.StructField $op.Name }}
	{{ $type := $f.Type.String }}{{ if $f.IsEnum }}{{ $type = trimPackage $type $.Package }}{{ end }}
	// {{ $func }} applies the {{ $op.Name }} predicate on the {{ quote $f.Name }} field.
	func {{ $func }}({{ if not $op.Niladic }}{{ $arg }} {{ if $op.Variadic }}...{{ end }}{{ $type }}{{ end }}) predicate.{{ $.Name }} {
		{{- if $op.Variadic }}
			v := make([]interface{}, len({{ $arg }}))
			for i := range v {
				v[i] = {{ $arg }}[i]
			}
		{{- end }}
		return predicate.{{ $.Name }}{{ if $.MultiStorage }}PerDialect{{ end }}(
			{{ range $_, $storage := $.Storage -}}
				{{- with extend $ "Arg" $arg "Field" $f "Op" $op "Storage" $storage -}}
					{{ $tmpl := printf "dialect/%s/predicate/field/ops" $storage }}
					{{- xtemplate $tmpl . }},
				{{ end -}}
			{{ end -}}
		)
	}
	{{ end }}
{{ end }}

{{ range $_, $e := $.Edges }}
	{{ $func := print "Has" $e.StructField }}
	// {{ $func }} applies the HasEdge predicate on the {{ quote $e.Name }} edge.
	func {{ $func }}() predicate.{{ $.Name }} {
		return predicate.{{ $.Name }}{{ if $.MultiStorage }}PerDialect{{ end }}(
			{{ range $_, $storage := $.Storage -}}
				{{- with extend $ "Edge" $e -}}
					{{ $tmpl := printf "dialect/%s/predicate/edge/has" $storage }}
					{{- xtemplate $tmpl . }},
				{{ end -}}
			{{ end -}}
		)
	}
	{{ $func = printf "%sWith" $func }}
	// {{ $func }} applies the HasEdge predicate on the {{ quote $e.Name }} edge with a given conditions (other predicates).
	func {{ $func }}(preds ...predicate.{{ $e.Type.Name }}) predicate.{{ $.Name }} {
		return predicate.{{ $.Name }}{{ if $.MultiStorage }}PerDialect{{ end }}(
			{{ range $_, $storage := $.Storage -}}
				{{- with extend $ "Edge" $e -}}
					{{ $tmpl := printf "dialect/%s/predicate/edge/haswith" $storage }}
					{{- xtemplate $tmpl . }},
				{{ end -}}
			{{ end -}}
		)
	}
{{ end }}

// And groups list of predicates with the AND operator between them.
func And(predicates ...predicate.{{ $.Name }}) predicate.{{ $.Name }} {
	return predicate.{{ $.Name }}{{ if $.MultiStorage }}PerDialect{{ end }}(
		{{ range $_, $storage := $.Storage -}}
			{{ $tmpl := printf "dialect/%s/predicate/and" $storage }}
			{{- xtemplate $tmpl . }},
		{{ end -}}
	)
}

// Or groups list of predicates with the OR operator between them.
func Or(predicates ...predicate.{{ $.Name }}) predicate.{{ $.Name }} {
	return predicate.{{ $.Name }}{{ if $.MultiStorage }}PerDialect{{ end }}(
		{{ range $_, $storage := $.Storage -}}
			{{ $tmpl := printf "dialect/%s/predicate/or" $storage }}
			{{- xtemplate $tmpl . }},
		{{ end -}}
	)
}

// Not applies the not operator on the given predicate.
func Not(p predicate.{{ $.Name }}) predicate.{{ $.Name }} {
	return predicate.{{ $.Name }}{{ if $.MultiStorage }}PerDialect{{ end }}(
		{{ range $_, $storage := $.Storage -}}
			{{ $tmpl := printf "dialect/%s/predicate/not" $storage }}
			{{- xtemplate $tmpl . }},
		{{ end -}}
	)
}

{{ end }}
