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

{{ define "dialect/gremlin/predicate/id" -}}
	func(t *dsl.Traversal) {
		t.HasID(id)
	}
{{- end }}

{{ define "dialect/gremlin/predicate/id/ops" -}}
	{{- $op := $.Scope.Op -}}
	{{- $arg := $.Scope.Arg -}}
	{{- $storage := $.Scope.Storage -}}
	func(t *dsl.Traversal) {
		{{- if $op.Variadic }}
			v := make([]interface{}, len({{ $arg }}))
			for i := range v {
				v[i] = {{ $arg }}[i]
			}
		{{- end }}
		t.HasID(p.{{ call $storage.OpCode $op }}({{ if $op.Variadic }}v...{{ else }}{{ $arg }}{{ end }}))
	}
{{- end }}

{{ define "dialect/gremlin/predicate/field" -}}
	{{- $f := $.Scope.Field -}}
	{{- $arg := $.Scope.Arg -}}
	func(t *dsl.Traversal) {
		t.Has(Label, {{ $f.Constant }}, p.EQ({{ $arg }}))
	}
{{- end }}

{{ define "dialect/gremlin/predicate/field/ops" -}}
	{{- $f := $.Scope.Field -}}
	{{- $op := $.Scope.Op -}}
	{{- $arg := $.Scope.Arg -}}
	{{- $storage := $.Scope.Storage -}}
	func(t *dsl.Traversal) {
		{{- if not $op.Niladic }}
			t.Has(Label, {{ $f.Constant }}, p.{{ call $storage.OpCode $op }}({{ $arg }}{{ if $op.Variadic }}...{{ end }}))
		{{- else }}
			t.HasLabel(Label).{{ call $storage.OpCode $op }}({{ $f.Constant }})
		{{- end }}
	}
{{- end }}

{{ define "dialect/gremlin/predicate/edge/has" -}}
	{{- $e := $.Scope.Edge -}}
	{{- $label := $e.LabelConstant -}}
	{{- $direction := "Out" -}}
	{{- if $e.IsInverse -}}
		{{- $direction = "In" -}}
		{{/* avoid circular dependecies */}}
		{{- $label = $e.InverseLabelConstant -}}
	{{- end -}}
	func(t *dsl.Traversal) {
		{{- /* if it's an edge with self-reference, take the two vertices */}}
		{{- if $e.Bidi }}
			t.Both({{ $label }})
		{{- else }}
			t.{{ $direction }}E({{ $label }}).{{ $direction }}V()
		{{- end }}
	}
{{- end }}

{{ define "dialect/gremlin/predicate/edge/haswith" -}}
	{{- $e := $.Scope.Edge -}}
	{{- $label := $e.LabelConstant -}}
	{{- $direction := "Out" -}}
	{{- $inverse_direction := "In" -}}
	{{- if $e.IsInverse -}}
		{{- $direction = "In" -}}
		{{- $inverse_direction = "Out" -}}
		{{/* avoid circular dependecies */}}
		{{- $label = $e.InverseLabelConstant -}}
	{{- end -}}
	func(t *dsl.Traversal) {
		{{- if $e.Bidi }}{{/* selfref means it should be true in one of the directions */}}
			in, out := __.InV(), __.OutV()
			for _, p := range preds {
				p(in)
				p(out)
			}
			t.Where(
				__.Or(
					__.OutE({{ $label }}).Where(in),
					__.InE({{ $label }}).Where(out),
				),
			)
		{{- else }}
			tr := __.{{ $inverse_direction }}V()
			for _, p := range preds {
				p(tr)
			}
			t.{{ $direction }}E({{ $label }}).Where(tr).{{ $direction }}V()
		{{- end }}
	}
{{- end }}

{{ define "dialect/gremlin/predicate/and" -}}
	func(tr *dsl.Traversal) {
		trs := make([]interface{}, 0, len(predicates))
		for _, p := range predicates {
			t := __.New()
			p(t)
			trs = append(trs, t)
		}
		tr.Where(__.And(trs...))
	}
{{- end }}

{{ define "dialect/gremlin/predicate/or" -}}
	func(tr *dsl.Traversal) {
		trs := make([]interface{}, 0, len(predicates))
		for _, p := range predicates {
			t := __.New()
			p(t)
			trs = append(trs, t)
		}
		tr.Where(__.Or(trs...))
	}
{{- end }}

{{ define "dialect/gremlin/predicate/not" -}}
	func(tr *dsl.Traversal) {
		t := __.New()
		p(t)
		tr.Where(__.Not(t))
	}
{{- end }}
