AAI-1523 Batch reformat aai-core
[aai/aai-common.git] / aai-core / src / main / java / org / onap / aai / query / builder / GremlinQueryBuilder.java
1 /**
2  * ============LICENSE_START=======================================================
3  * org.onap.aai
4  * ================================================================================
5  * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Modifications Copyright © 2018 IBM.
8  * ================================================================================
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *    http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  * ============LICENSE_END=========================================================
21  */
22
23 package org.onap.aai.query.builder;
24
25 import com.google.common.base.Joiner;
26 import com.google.common.collect.ArrayListMultimap;
27 import com.google.common.collect.Multimap;
28
29 import java.util.*;
30
31 import org.apache.tinkerpop.gremlin.process.traversal.Path;
32 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
33 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
34 import org.apache.tinkerpop.gremlin.process.traversal.step.util.Tree;
35 import org.apache.tinkerpop.gremlin.structure.Direction;
36 import org.apache.tinkerpop.gremlin.structure.Edge;
37 import org.apache.tinkerpop.gremlin.structure.Vertex;
38 import org.onap.aai.db.props.AAIProperties;
39 import org.onap.aai.edges.EdgeRule;
40 import org.onap.aai.edges.EdgeRuleQuery;
41 import org.onap.aai.edges.enums.EdgeType;
42 import org.onap.aai.edges.exceptions.EdgeRuleNotFoundException;
43 import org.onap.aai.exceptions.AAIException;
44 import org.onap.aai.introspection.Introspector;
45 import org.onap.aai.introspection.Loader;
46 import org.onap.aai.restcore.search.GremlinGroovyShell;
47 import org.onap.aai.schema.enums.ObjectMetadata;
48 import org.onap.aai.serialization.db.exceptions.NoEdgeRuleFoundException;
49
50 /**
51  * The Class GremlinQueryBuilder.
52  */
53 public abstract class GremlinQueryBuilder<E> extends QueryBuilder<E> {
54
55     private static final String ARGUMENT2 = "#!#argument#!#";
56     private static final String HAS = ".has('";
57     private GremlinGroovyShell gremlinGroovy = new GremlinGroovyShell();
58     private GraphTraversal<?, ?> completeTraversal = null;
59     protected List<String> list = null;
60
61     /**
62      * Instantiates a new gremlin query builder.
63      *
64      * @param loader the loader
65      */
66     public GremlinQueryBuilder(Loader loader, GraphTraversalSource source) {
67         super(loader, source);
68         list = new ArrayList<>();
69     }
70
71     /**
72      * Instantiates a new gremlin query builder.
73      *
74      * @param loader the loader
75      * @param start the start
76      */
77     public GremlinQueryBuilder(Loader loader, GraphTraversalSource source, Vertex start) {
78         super(loader, source, start);
79         list = new ArrayList<>();
80     }
81
82     @Override
83     public QueryBuilder<Vertex> exactMatchQuery(Introspector obj) {
84         // TODO not implemented because this is implementation is no longer used
85         this.createKeyQuery(obj);
86         this.createContainerQuery(obj);
87         return (QueryBuilder<Vertex>) this;
88     }
89
90     /**
91      * @{inheritDoc}
92      */
93     @Override
94     public QueryBuilder<Vertex> getVerticesByProperty(String key, Object value) {
95
96         String term = "";
97         if (value != null && !(value instanceof String)) {
98             term = value.toString();
99         } else {
100             term = "'" + value + "'";
101         }
102         list.add(HAS + key + "', " + term + ")");
103         stepIndex++;
104         return (QueryBuilder<Vertex>) this;
105     }
106
107     /**
108      * @{inheritDoc}
109      */
110     @Override
111     public QueryBuilder<Vertex> getVerticesByNumberProperty(String key, Object value) {
112         list.add(HAS + key + "', " + value + ")");
113         stepIndex++;
114         return (QueryBuilder<Vertex>) this;
115     }
116
117     @Override
118     public QueryBuilder<Vertex> getVerticesByBooleanProperty(String key, Object value) {
119
120         if (value != null && !"".equals(value)) {
121             boolean bValue = false;
122             if (value instanceof String) {
123                 bValue = Boolean.valueOf(value.toString());
124             } else if (value instanceof Boolean) {
125                 bValue = (Boolean) value;
126             }
127
128             list.add(HAS + key + "', " + bValue + ")");
129             stepIndex++;
130         }
131         return (QueryBuilder<Vertex>) this;
132     }
133
134     /**
135      * @{inheritDoc}
136      */
137     @Override
138     public QueryBuilder<Vertex> getVerticesByProperty(String key, List<?> values) {
139
140         String predicate = "P.within(#!#argument#!#)";
141         List<String> arguments = new ArrayList<>();
142         for (Object item : values) {
143             if (item != null && !(item instanceof String)) {
144                 arguments.add(item.toString());
145             } else {
146                 arguments.add("'" + item + "'");
147             }
148         }
149         String argument = Joiner.on(",").join(arguments);
150         predicate = predicate.replace(ARGUMENT2, argument);
151         list.add(HAS + key + "', " + predicate + ")");
152         stepIndex++;
153         return (QueryBuilder<Vertex>) this;
154     }
155
156     /**
157      * @{inheritDoc}
158      */
159     @Override
160     public QueryBuilder<Vertex> getVerticesByProperty(String key) {
161
162         list.add(HAS + key + "')");
163         stepIndex++;
164         return (QueryBuilder<Vertex>) this;
165     }
166
167     /**
168      * @{inheritDoc}
169      */
170     @Override
171     public QueryBuilder<Vertex> getVerticesExcludeByProperty(String key) {
172
173         list.add(".hasNot('" + key + "')");
174         stepIndex++;
175         return (QueryBuilder<Vertex>) this;
176     }
177
178     /**
179      * @{inheritDoc}
180      */
181     @Override
182     public QueryBuilder<Vertex> getVerticesStartsWithProperty(String key, Object value) {
183
184         String term = "";
185         String predicate = "org.janusgraph.core.attribute.Text.textPrefix(#!#argument#!#)";
186         if (value != null && !(value instanceof String)) {
187             term = value.toString();
188         } else {
189             term = "'" + value + "'";
190         }
191         predicate = predicate.replace(ARGUMENT2, term);
192         list.add(HAS + key + "', " + predicate + ")");
193         stepIndex++;
194         return (QueryBuilder<Vertex>) this;
195     }
196
197     /**
198      * @{inheritDoc}
199      */
200     @Override
201     public QueryBuilder<Vertex> getVerticesExcludeByProperty(String key, Object value) {
202
203         String term = "";
204         String predicate = "P.neq(#!#argument#!#)";
205         if (value != null && !(value instanceof String)) {
206             term = value.toString();
207         } else {
208             term = "'" + value + "'";
209         }
210         predicate = predicate.replace(ARGUMENT2, term);
211         list.add(HAS + key + "', " + predicate + ")");
212         stepIndex++;
213         return (QueryBuilder<Vertex>) this;
214     }
215
216     /**
217      * @{inheritDoc}
218      */
219     @Override
220     public QueryBuilder<Vertex> getVerticesExcludeByProperty(String key, List<?> values) {
221
222         String predicate = "P.without(#!#argument#!#)";
223         List<String> arguments = new ArrayList<>();
224         for (Object item : values) {
225             if (item != null && !(item instanceof String)) {
226                 arguments.add(item.toString());
227             } else {
228                 arguments.add("'" + item + "'");
229             }
230         }
231         String argument = Joiner.on(",").join(arguments);
232         predicate = predicate.replace(ARGUMENT2, argument);
233         list.add(HAS + key + "', " + predicate + ")");
234         stepIndex++;
235         return (QueryBuilder<Vertex>) this;
236     }
237
238     @Override
239     public QueryBuilder<Vertex> getVerticesGreaterThanProperty(String key, Object value) {
240         String predicate = "P.gte(#!#argument1#!#)";
241         String term;
242         if (value != null && !(value instanceof String)) {
243             term = value.toString();
244         } else {
245             term = "'" + value + "'";
246         }
247         predicate = predicate.replace("#!#argument1#!#", term);
248         list.add(HAS + key + "', " + predicate + ")");
249         stepIndex++;
250         return (QueryBuilder<Vertex>) this;
251     }
252
253     @Override
254     public QueryBuilder<Vertex> getVerticesLessThanProperty(String key, Object value) {
255         String predicate = "P.lte(#!#argument1#!#)";
256         String term;
257         if (value != null && !(value instanceof String)) {
258             term = value.toString();
259         } else {
260             term = "'" + value + "'";
261         }
262         predicate = predicate.replace("#!#argument1#!#", term);
263         list.add(HAS + key + "', " + predicate + ")");
264         stepIndex++;
265         return (QueryBuilder<Vertex>) this;
266     }
267
268     /**
269      * @{inheritDoc}
270      */
271     @Override
272     public QueryBuilder<Vertex> getChildVerticesFromParent(String parentKey, String parentValue, String childType) {
273         // TODO
274         return (QueryBuilder<Vertex>) this;
275     }
276
277     /**
278      * @{inheritDoc}
279      */
280     @Override
281     public QueryBuilder<Vertex> getTypedVerticesByMap(String type, Map<String, String> map) {
282
283         for (Map.Entry<String, String> es : map.entrySet()) {
284             list.add(HAS + es.getKey() + "', '" + es.getValue() + "')");
285             stepIndex++;
286         }
287         list.add(".has('aai-node-type', '" + type + "')");
288         stepIndex++;
289         return (QueryBuilder<Vertex>) this;
290     }
291
292     /**
293      * @{inheritDoc}
294      */
295     @Override
296     public QueryBuilder<Vertex> createKeyQuery(Introspector obj) {
297         Set<String> keys = obj.getKeys();
298
299         for (String key : keys) {
300
301             this.getVerticesByProperty(key, obj.<Object>getValue(key));
302
303         }
304         return (QueryBuilder<Vertex>) this;
305     }
306
307     /**
308      * @throws NoEdgeRuleFoundException
309      * @throws AAIException
310      * @{inheritDoc}
311      */
312     @Override
313     public QueryBuilder createEdgeTraversal(EdgeType type, Introspector parent, Introspector child)
314             throws AAIException {
315         String parentName = parent.getDbName();
316         String childName = child.getDbName();
317         if (parent.isContainer()) {
318             parentName = parent.getChildDBName();
319         }
320         if (child.isContainer()) {
321             childName = child.getChildDBName();
322         }
323         this.edgeQueryToVertex(type, parentName, childName, null);
324         return this;
325
326     }
327
328     @Override
329     public QueryBuilder createPrivateEdgeTraversal(EdgeType type, Introspector parent, Introspector child)
330             throws AAIException {
331         String parentName = parent.getDbName();
332         String childName = child.getDbName();
333         if (parent.isContainer()) {
334             parentName = parent.getChildDBName();
335         }
336         if (child.isContainer()) {
337             childName = child.getChildDBName();
338         }
339         this.edgeQueryToVertex(type, parentName, childName, null, true);
340         return this;
341     }
342
343     /**
344      *
345      * @{inheritDoc}
346      */
347     @Override
348     public QueryBuilder<Vertex> createEdgeTraversalWithLabels(EdgeType type, Introspector out, Introspector in,
349             List<String> labels) throws AAIException {
350         String parentName = out.getDbName();
351         String childName = in.getDbName();
352         if (out.isContainer()) {
353             parentName = out.getChildDBName();
354         }
355         if (in.isContainer()) {
356             childName = in.getChildDBName();
357         }
358         this.edgeQueryToVertex(type, parentName, childName, labels);
359         return (QueryBuilder<Vertex>) this;
360     }
361
362     public QueryBuilder<Edge> getEdgesBetweenWithLabels(EdgeType type, String outNodeType, String inNodeType,
363             List<String> labels) throws AAIException {
364         this.edgeQuery(type, outNodeType, inNodeType, labels);
365         return (QueryBuilder<Edge>) this;
366     }
367
368     private void edgeQueryToVertex(EdgeType type, String outType, String inType, List<String> labels)
369             throws AAIException {
370         this.edgeQueryToVertex(type, outType, inType, labels, false);
371     }
372
373     /**
374      * Edge query.
375      *
376      * @param outType the out type
377      * @param inType the in type
378      * @throws NoEdgeRuleFoundException
379      * @throws AAIException
380      */
381     private void edgeQueryToVertex(EdgeType type, String outType, String inType, List<String> labels,
382             boolean isPrivateEdge) throws AAIException {
383         markParentBoundary();
384         Multimap<String, EdgeRule> rules = ArrayListMultimap.create();
385         EdgeRuleQuery.Builder qB = new EdgeRuleQuery.Builder(outType, inType).edgeType(type).setPrivate(isPrivateEdge);
386
387         try {
388             if (labels == null) {
389                 rules.putAll(edgeRules.getRules(qB.build()));
390             } else {
391                 for (String label : labels) {
392                     rules.putAll(edgeRules.getRules(qB.label(label).build()));
393                 }
394             }
395         } catch (EdgeRuleNotFoundException e) {
396             throw new NoEdgeRuleFoundException(e);
397         }
398
399         final List<String> inLabels = new ArrayList<>();
400         final List<String> outLabels = new ArrayList<>();
401
402         for (EdgeRule rule : rules.values()) {
403             if (labels != null && !labels.contains(rule.getLabel())) {
404                 return;
405             } else {
406                 if (Direction.IN.equals(rule.getDirection())) {
407                     inLabels.add(rule.getLabel());
408                     if (inType.equals(outType)) {// code to handle when a type edges to itself, to add both in and out
409                         outLabels.add(rule.getLabel());
410                     }
411                 } else {
412                     outLabels.add(rule.getLabel());
413                     if (inType.equals(outType)) {// code to handle when a type edges to itself, to add both in and out
414                         inLabels.add(rule.getLabel());
415                     }
416                 }
417             }
418         }
419
420         if (inLabels.isEmpty() && outLabels.isEmpty()) {
421             throw new NoEdgeRuleFoundException(
422                     "no " + type.toString() + " edge rule between " + outType + " and " + inType);
423         } else if (inLabels.isEmpty() && !outLabels.isEmpty()) {
424             list.add(".out('" + String.join("','", outLabels) + "')");
425         } else if (outLabels.isEmpty() && !inLabels.isEmpty()) {
426             list.add(".in('" + String.join("','", inLabels) + "')");
427         } else {
428             list.add(".union(__.in('" + String.join("','", inLabels) + "')" + ", __.out('"
429                     + String.join("','", outLabels) + "'))");
430         }
431         stepIndex++;
432         list.add(HAS + AAIProperties.NODE_TYPE + "', '" + inType + "')");
433         stepIndex++;
434
435     }
436
437     /**
438      * Edge query.
439      *
440      * @param outType the out type
441      * @param inType the in type
442      * @throws NoEdgeRuleFoundException
443      * @throws AAIException
444      */
445     private void edgeQuery(EdgeType type, String outType, String inType, List<String> labels) throws AAIException {
446         markParentBoundary();
447         Multimap<String, EdgeRule> rules = ArrayListMultimap.create();
448         EdgeRuleQuery.Builder qB = new EdgeRuleQuery.Builder(outType, inType).edgeType(type);
449         try {
450             if (labels == null) {
451                 rules.putAll(edgeRules.getRules(qB.build()));
452             } else {
453                 for (String label : labels) {
454                     rules.putAll(edgeRules.getRules(qB.label(label).build()));
455                 }
456             }
457         } catch (EdgeRuleNotFoundException e) {
458             throw new NoEdgeRuleFoundException(e);
459         }
460
461         final List<String> inLabels = new ArrayList<>();
462         final List<String> outLabels = new ArrayList<>();
463
464         for (EdgeRule rule : rules.values()) {
465             if (labels != null && !labels.contains(rule.getLabel())) {
466                 return;
467             } else {
468                 if (Direction.IN.equals(rule.getDirection())) {
469                     inLabels.add(rule.getLabel());
470                 } else {
471                     outLabels.add(rule.getLabel());
472                 }
473             }
474         }
475
476         if (inLabels.isEmpty() && outLabels.isEmpty()) {
477             throw new NoEdgeRuleFoundException(
478                     "no " + type.toString() + " edge rule between " + outType + " and " + inType);
479         } else if (inLabels.isEmpty() && !outLabels.isEmpty()) {
480             list.add(".outE('" + String.join("','", outLabels) + "')");
481         } else if (outLabels.isEmpty() && !inLabels.isEmpty()) {
482             list.add(".inE('" + String.join("','", inLabels) + "')");
483         } else {
484             list.add(".union(__.inE('" + String.join("','", inLabels) + "')" + ", __.outE('"
485                     + String.join("','", outLabels) + "'))");
486         }
487
488         stepIndex++;
489
490     }
491
492     @Override
493     public QueryBuilder<E> limit(long amount) {
494         list.add(".limit(" + amount + ")");
495         return this;
496     }
497
498     /**
499      * @{inheritDoc}
500      */
501     @Override
502     public QueryBuilder<Vertex> createContainerQuery(Introspector obj) {
503         String type = obj.getChildDBName();
504         String abstractType = obj.getMetadata(ObjectMetadata.ABSTRACT);
505         if (abstractType != null) {
506             String[] inheritors = obj.getMetadata(ObjectMetadata.INHERITORS).split(",");
507             String[] wrapped = new String[inheritors.length];
508             StringBuilder command = new StringBuilder();
509             command.append("P.within(");
510             for (int i = 0; i < inheritors.length; i++) {
511                 wrapped[i] = "'" + inheritors[i] + "'";
512             }
513             command.append(Joiner.on(",").join(wrapped));
514             command.append(")");
515             list.add(".has('aai-node-type', " + command + ")");
516
517         } else {
518             list.add(".has('aai-node-type', '" + type + "')");
519         }
520         stepIndex++;
521         this.markContainer();
522         return (QueryBuilder<Vertex>) this;
523     }
524
525     @Override
526     public QueryBuilder<E> union(QueryBuilder<E>... builder) {
527         markParentBoundary();
528         String[] traversals = new String[builder.length];
529         StringBuilder command = new StringBuilder();
530         for (int i = 0; i < builder.length; i++) {
531             traversals[i] = "__" + builder[i].getQuery();
532         }
533         command.append(".union(");
534         command.append(Joiner.on(",").join(traversals));
535         command.append(")");
536         list.add(command.toString());
537         stepIndex++;
538
539         return this;
540     }
541
542     @Override
543     public QueryBuilder<E> where(QueryBuilder<E>... builder) {
544         markParentBoundary();
545         List<String> traversals = new ArrayList<>();
546         for (int i = 0; i < builder.length; i++) {
547             traversals.add(".where(__" + builder[i].getQuery() + ")");
548             stepIndex++;
549         }
550         list.addAll(traversals);
551
552         return this;
553     }
554
555     @Override
556     public QueryBuilder<E> or(QueryBuilder<E>... builder) {
557         markParentBoundary();
558         String[] traversals = new String[builder.length];
559         StringBuilder command = new StringBuilder();
560         for (int i = 0; i < builder.length; i++) {
561             traversals[i] = "__" + builder[i].getQuery();
562         }
563         command.append(".or(");
564         command.append(Joiner.on(",").join(traversals));
565         command.append(")");
566         list.add(command.toString());
567         stepIndex++;
568
569         return this;
570     }
571
572     @Override
573     public QueryBuilder<E> store(String name) {
574         this.list.add(".store('" + name + "')");
575         stepIndex++;
576
577         return this;
578     }
579
580     @Override
581     public QueryBuilder<E> cap(String name) {
582         this.list.add(".cap('" + name + "')");
583         stepIndex++;
584
585         return this;
586     }
587
588     @Override
589     public QueryBuilder<E> unfold() {
590         this.list.add(".unfold()");
591         stepIndex++;
592
593         return this;
594     }
595
596     @Override
597     public QueryBuilder<E> dedup() {
598         this.list.add(".dedup()");
599         stepIndex++;
600
601         return this;
602     }
603
604     @Override
605     public QueryBuilder<E> emit() {
606         this.list.add(".emit()");
607         stepIndex++;
608
609         return this;
610     }
611
612     @Override
613     public QueryBuilder<E> repeat(QueryBuilder<E> builder) {
614         this.list.add(".repeat(__" + builder.getQuery() + ")");
615         stepIndex++;
616
617         return this;
618     }
619
620     @Override
621     public QueryBuilder<E> until(QueryBuilder<E> builder) {
622         this.list.add(".until(__" + builder.getQuery() + ")");
623         stepIndex++;
624
625         return this;
626     }
627
628     @Override
629     public QueryBuilder<E> groupCount() {
630         this.list.add(".groupCount()");
631         stepIndex++;
632
633         return this;
634     }
635
636     @Override
637     public QueryBuilder<E> both() {
638         this.list.add(".both()");
639         stepIndex++;
640
641         return this;
642     }
643
644     @Override
645     public QueryBuilder<Tree> tree() {
646         this.list.add(".tree()");
647         stepIndex++;
648
649         return (QueryBuilder<Tree>) this;
650     }
651
652     @Override
653     public QueryBuilder<E> by(String name) {
654         this.list.add(".by('" + name + "')");
655         stepIndex++;
656
657         return this;
658     }
659
660     /**
661      * {@inheritDoc}
662      */
663     @Override
664     public QueryBuilder<E> simplePath() {
665         this.list.add(".simplePath()");
666         stepIndex++;
667         return this;
668     }
669
670     /**
671      * {@inheritDoc}
672      */
673     @Override
674     public QueryBuilder<Path> path() {
675         this.list.add(".path()");
676         stepIndex++;
677         return (QueryBuilder<Path>) this;
678     }
679
680     @Override
681     public QueryBuilder<Edge> outE() {
682         this.list.add(".outE()");
683         stepIndex++;
684
685         return (QueryBuilder<Edge>) this;
686     }
687
688     @Override
689     public QueryBuilder<Edge> inE() {
690         this.list.add(".inE()");
691         stepIndex++;
692
693         return (QueryBuilder<Edge>) this;
694     }
695
696     @Override
697     public QueryBuilder<Vertex> outV() {
698         this.list.add(".outV()");
699         stepIndex++;
700
701         return (QueryBuilder<Vertex>) this;
702     }
703
704     @Override
705     public QueryBuilder<Vertex> inV() {
706         this.list.add(".inV()");
707         stepIndex++;
708
709         return (QueryBuilder<Vertex>) this;
710     }
711
712     @Override
713     public QueryBuilder<E> not(QueryBuilder<E> builder) {
714         this.list.add(".not(" + "__" + builder.getQuery() + ")");
715         stepIndex++;
716
717         return this;
718     }
719
720     @Override
721     public QueryBuilder<E> as(String name) {
722         this.list.add(".as('" + name + "')");
723         stepIndex++;
724
725         return this;
726     }
727
728     @Override
729     public QueryBuilder<E> select(String name) {
730         this.list.add(".select('" + name + "')");
731         stepIndex++;
732
733         return this;
734     }
735
736     @Override
737     public QueryBuilder<E> select(String... names) {
738         String stepString = ".select('";
739         for (int i = 0; i < names.length; i++) {
740             stepString = stepString + names[i] + "'";
741             if (i != (names.length - 1)) {
742                 stepString = stepString + ",'";
743             }
744         }
745         stepString = stepString + ")";
746         this.list.add(stepString);
747         stepIndex++;
748
749         return this;
750     }
751
752     /**
753      * @{inheritDoc}
754      */
755     @Override
756     public QueryBuilder<E> getParentQuery() {
757         return cloneQueryAtStep(parentStepIndex);
758     }
759
760     @Override
761     public QueryBuilder<E> getContainerQuery() {
762         return cloneQueryAtStep(containerStepIndex);
763     }
764
765     /**
766      * @{inheritDoc}
767      */
768     @Override
769     public <T2> T2 getQuery() {
770         StringBuilder sb = new StringBuilder();
771
772         for (String piece : this.list) {
773             sb.append(piece);
774         }
775
776         return (T2) sb.toString();
777     }
778
779     /**
780      * @{inheritDoc}
781      */
782     @Override
783     public void markParentBoundary() {
784         parentStepIndex = stepIndex;
785     }
786
787     @Override
788     public void markContainer() {
789         this.containerStepIndex = stepIndex;
790     }
791
792     /**
793      * @{inheritDoc}
794      */
795     @Override
796     public Vertex getStart() {
797         return this.start;
798     }
799
800     protected int getParentStepIndex() {
801         return parentStepIndex;
802     }
803
804     protected int getContainerStepIndex() {
805         return containerStepIndex;
806     }
807
808     protected int getStepIndex() {
809         return stepIndex;
810     }
811
812     private void executeQuery() {
813         String queryString = "g" + Joiner.on("").join(list);
814         Map<String, Object> params = new HashMap<>();
815         if (this.start == null) {
816             params.put("g", source.V());
817         } else {
818             params.put("g", source.V(this.start));
819         }
820         this.completeTraversal = this.gremlinGroovy.executeTraversal(queryString, params);
821     }
822
823     @Override
824     public boolean hasNext() {
825         if (this.completeTraversal == null) {
826             executeQuery();
827         }
828
829         return this.completeTraversal.hasNext();
830     }
831
832     @Override
833     public E next() {
834         if (this.completeTraversal == null) {
835             executeQuery();
836         }
837
838         return (E) this.completeTraversal.next();
839     }
840
841     @Override
842     public List<E> toList() {
843         if (this.completeTraversal == null) {
844             executeQuery();
845         }
846
847         return (List<E>) this.completeTraversal.toList();
848     }
849
850     protected QueryBuilder<Edge> has(String key, String value) {
851         this.list.add(HAS + key + "','" + value + "')");
852
853         return (QueryBuilder<Edge>) this;
854     }
855
856 }