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