Merge "AAIAuthCore-replace duplicate literal by constant"
[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         boolean bValue = false;
119
120         if(value instanceof String){
121             bValue = Boolean.valueOf(value.toString());
122         } else if(value instanceof Boolean){
123             bValue = (Boolean) value;
124         }
125
126         list.add(HAS + key + "', " + bValue + ")");
127         stepIndex++;
128         return (QueryBuilder<Vertex>) this;
129     }
130
131     /**
132      * @{inheritDoc}
133      */
134     @Override
135     public QueryBuilder<Vertex> getVerticesByProperty(String key, List<?> values) {
136
137         String predicate = "P.within(#!#argument#!#)";
138         List<String> arguments = new ArrayList<>();
139         for (Object item : values) {
140             if (item != null && !(item instanceof String)) {
141                 arguments.add(item.toString());
142             } else {
143                 arguments.add("'" + item + "'");
144             }
145         }
146         String argument = Joiner.on(",").join(arguments);
147         predicate = predicate.replace(ARGUMENT2, argument);
148         list.add(HAS + key + "', " + predicate + ")");
149         stepIndex++;
150         return (QueryBuilder<Vertex>) this;
151     }
152
153     /**
154      * @{inheritDoc}
155      */
156     @Override
157     public QueryBuilder<Vertex> getVerticesByProperty(String key) {
158
159         list.add(HAS + key + "')");
160         stepIndex++;
161         return (QueryBuilder<Vertex>) this;
162     }
163
164     /**
165      * @{inheritDoc}
166      */
167     @Override
168     public QueryBuilder<Vertex> getVerticesExcludeByProperty(String key) {
169
170         list.add(".hasNot('" + key + "')");
171         stepIndex++;
172         return (QueryBuilder<Vertex>) this;
173     }
174
175     /**
176      * @{inheritDoc}
177      */
178     @Override
179     public QueryBuilder<Vertex> getVerticesStartsWithProperty(String key, Object value) {
180
181         String term = "";
182         String predicate = "org.janusgraph.core.attribute.Text.textPrefix(#!#argument#!#)";
183         if (value != null && !(value instanceof String) ) {
184             term = value.toString();
185         } else {
186             term = "'" + value + "'";
187         }
188         predicate = predicate.replace(ARGUMENT2, term);
189         list.add(HAS + key + "', " + predicate + ")");
190         stepIndex++;
191         return (QueryBuilder<Vertex>) this;
192     }
193
194     /**
195      * @{inheritDoc}
196      */
197     @Override
198     public QueryBuilder<Vertex> getVerticesExcludeByProperty(String key, Object value) {
199
200         String term = "";
201         String predicate = "P.neq(#!#argument#!#)";
202         if (value != null && !(value instanceof String) ) {
203             term = value.toString();
204         } else {
205             term = "'" + value + "'";
206         }
207         predicate = predicate.replace(ARGUMENT2, term);
208         list.add(HAS + key + "', " + predicate + ")");
209         stepIndex++;
210         return (QueryBuilder<Vertex>) this;
211     }
212
213     /**
214      * @{inheritDoc}
215      */
216     @Override
217     public QueryBuilder<Vertex> getVerticesExcludeByProperty(String key, List<?> values) {
218
219         String predicate = "P.without(#!#argument#!#)";
220         List<String> arguments = new ArrayList<>();
221         for (Object item : values) {
222             if (item != null && !(item instanceof String)) {
223                 arguments.add(item.toString());
224             } else {
225                 arguments.add("'" + item + "'");
226             }
227         }
228         String argument = Joiner.on(",").join(arguments);
229         predicate = predicate.replace(ARGUMENT2, argument);
230         list.add(HAS + key + "', " + predicate + ")");
231         stepIndex++;
232         return (QueryBuilder<Vertex>) this;
233     }
234
235     @Override
236     public QueryBuilder<Vertex> getVerticesGreaterThanProperty(String key, Object value) {
237         String predicate = "P.gte(#!#argument1#!#)";
238         String term;
239         if (value != null && !(value instanceof String) ) {
240             term = value.toString();
241         } else {
242             term = "'" + value + "'";
243         }
244         predicate = predicate.replace("#!#argument1#!#", term);
245         list.add(HAS + key + "', " + predicate + ")");
246         stepIndex++;
247         return (QueryBuilder<Vertex>) this;
248     }
249
250     @Override
251     public QueryBuilder<Vertex> getVerticesLessThanProperty(String key, Object value) {
252         String predicate = "P.lte(#!#argument1#!#)";
253         String term;
254         if (value != null && !(value instanceof String) ) {
255             term = value.toString();
256         } else {
257             term = "'" + value + "'";
258         }
259         predicate = predicate.replace("#!#argument1#!#", term);
260         list.add(HAS + key + "', " + predicate + ")");
261         stepIndex++;
262         return (QueryBuilder<Vertex>) this;
263     }
264
265
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) throws AAIException {
314         String parentName = parent.getDbName();
315         String childName = child.getDbName();
316         if (parent.isContainer()) {
317             parentName = parent.getChildDBName();
318         }
319         if (child.isContainer()) {
320             childName = child.getChildDBName();
321         }
322         this.edgeQueryToVertex(type, parentName, childName, null);
323         return this;
324
325     }
326
327     @Override
328     public QueryBuilder createPrivateEdgeTraversal(EdgeType type, Introspector parent, Introspector child) throws AAIException{
329         String parentName = parent.getDbName();
330         String childName = child.getDbName();
331         if (parent.isContainer()) {
332             parentName = parent.getChildDBName();
333         }
334         if (child.isContainer()) {
335             childName = child.getChildDBName();
336         }
337         this.edgeQueryToVertex(type, parentName, childName, null, true);
338         return this;
339     }
340
341     /**
342      *
343      * @{inheritDoc}
344      */
345     @Override
346     public QueryBuilder<Vertex> createEdgeTraversalWithLabels(EdgeType type, Introspector out, Introspector in, List<String> labels) throws AAIException {
347         String parentName = out.getDbName();
348         String childName = in.getDbName();
349         if (out.isContainer()) {
350             parentName = out.getChildDBName();
351         }
352         if (in.isContainer()) {
353             childName = in.getChildDBName();
354         }
355         this.edgeQueryToVertex(type, parentName, childName, labels);
356         return (QueryBuilder<Vertex>) this;
357     }
358
359
360     public QueryBuilder<Edge> getEdgesBetweenWithLabels(EdgeType type, String outNodeType, String inNodeType, List<String> labels) throws AAIException {
361         this.edgeQuery(type, outNodeType, inNodeType, labels);
362         return (QueryBuilder<Edge>)this;
363     }
364
365     private void edgeQueryToVertex(EdgeType type, String outType, String inType, List<String> labels) throws AAIException {
366         this.edgeQueryToVertex(type, outType, inType, labels, false);
367     }
368
369     /**
370      * Edge query.
371      *
372      * @param outType the out type
373      * @param inType the in type
374      * @throws NoEdgeRuleFoundException
375      * @throws AAIException
376      */
377     private void edgeQueryToVertex(EdgeType type, String outType, String inType, List<String> labels, boolean isPrivateEdge) throws AAIException {
378         markParentBoundary();
379         Multimap<String, EdgeRule> rules = ArrayListMultimap.create();
380         EdgeRuleQuery.Builder qB = new EdgeRuleQuery.Builder(outType, inType).edgeType(type).setPrivate(isPrivateEdge);
381
382         try {
383             if (labels == null) {
384                 rules.putAll(edgeRules.getRules(qB.build()));
385             } else {
386                 for (String label : labels) {
387                     rules.putAll(edgeRules.getRules(qB.label(label).build()));
388                 }
389             }
390         } catch (EdgeRuleNotFoundException e) {
391             throw new NoEdgeRuleFoundException(e);
392         }
393
394         final List<String> inLabels = new ArrayList<>();
395         final List<String> outLabels = new ArrayList<>();
396
397         for (EdgeRule rule : rules.values()) {
398             if (labels != null && !labels.contains(rule.getLabel())) {
399                 return;
400             } else {
401                 if (Direction.IN.equals(rule.getDirection())) {
402                     inLabels.add(rule.getLabel());
403                     if(inType.equals(outType)) {//code to handle when a type edges to itself, to add both in and out
404                         outLabels.add(rule.getLabel());
405                     }
406                 } else {
407                     outLabels.add(rule.getLabel());
408                     if(inType.equals(outType)) {//code to handle when a type edges to itself, to add both in and out
409                         inLabels.add(rule.getLabel());
410                     }
411                 }
412             }
413         }
414
415         if(inLabels.isEmpty() && outLabels.isEmpty()) {
416             throw new NoEdgeRuleFoundException("no " + type.toString() + " edge rule between " + outType + " and " + inType );
417         } else if (inLabels.isEmpty() && !outLabels.isEmpty()) {
418             list.add(".out('" + String.join("','", outLabels) + "')");
419         } else if (outLabels.isEmpty() && !inLabels.isEmpty()) {
420             list.add(".in('" + String.join("','", inLabels) + "')");
421         } else {
422             list.add(".union(__.in('" + String.join("','", inLabels) + "')" + ", __.out('" + String.join("','", outLabels) + "'))");
423         }
424         stepIndex++;
425         list.add(HAS + AAIProperties.NODE_TYPE + "', '" + inType + "')");
426         stepIndex++;
427
428     }
429
430     /**
431      * Edge query.
432      *
433      * @param outType the out type
434      * @param inType the in type
435      * @throws NoEdgeRuleFoundException
436      * @throws AAIException
437      */
438     private void edgeQuery(EdgeType type, String outType, String inType, List<String> labels) throws AAIException {
439         markParentBoundary();
440         Multimap<String, EdgeRule> rules = ArrayListMultimap.create();
441         EdgeRuleQuery.Builder qB = new EdgeRuleQuery.Builder(outType, inType).edgeType(type);
442         try {
443             if (labels == null) {
444                 rules.putAll(edgeRules.getRules(qB.build()));
445             } else {
446                 for (String label : labels) {
447                     rules.putAll(edgeRules.getRules(qB.label(label).build()));
448                 }
449             }
450         } catch (EdgeRuleNotFoundException e) {
451             throw new NoEdgeRuleFoundException(e);
452         }
453
454         final List<String> inLabels = new ArrayList<>();
455         final List<String> outLabels = new ArrayList<>();
456
457         for (EdgeRule rule : rules.values()) {
458             if (labels != null && !labels.contains(rule.getLabel())) {
459                 return;
460             } else {
461                 if (Direction.IN.equals(rule.getDirection())) {
462                     inLabels.add(rule.getLabel());
463                 } else {
464                     outLabels.add(rule.getLabel());
465                 }
466             }
467         }
468
469         if(inLabels.isEmpty() && outLabels.isEmpty()) {
470             throw new NoEdgeRuleFoundException("no " + type.toString() + " edge rule between " + outType + " and " + inType );
471         } else if (inLabels.isEmpty() && !outLabels.isEmpty()) {
472             list.add(".outE('" + String.join("','", outLabels) + "')");
473         } else if (outLabels.isEmpty() && !inLabels.isEmpty()) {
474             list.add(".inE('" + String.join("','", inLabels) + "')");
475         } else {
476             list.add(".union(__.inE('" + String.join("','", inLabels) + "')" + ", __.outE('" + String.join("','", outLabels) + "'))");
477         }
478
479         stepIndex++;
480
481     }
482     @Override
483     public QueryBuilder<E> limit(long amount) {
484         list.add(".limit(" + amount + ")");
485         return this;
486     }
487     /**
488      * @{inheritDoc}
489      */
490     @Override
491     public QueryBuilder<Vertex> createContainerQuery(Introspector obj) {
492         String type = obj.getChildDBName();
493         String abstractType = obj.getMetadata(ObjectMetadata.ABSTRACT);
494         if (abstractType != null) {
495             String[] inheritors = obj.getMetadata(ObjectMetadata.INHERITORS).split(",");
496             String[] wrapped = new String[inheritors.length];
497             StringBuilder command = new StringBuilder();
498             command.append("P.within(");
499             for (int i = 0; i < inheritors.length; i++) {
500                 wrapped[i] = "'" + inheritors[i] + "'";
501             }
502             command.append(Joiner.on(",").join(wrapped));
503             command.append(")");
504             list.add(".has('aai-node-type', " + command + ")");
505
506         } else {
507             list.add(".has('aai-node-type', '" + type + "')");
508         }
509         stepIndex++;
510         this.markContainer();
511         return (QueryBuilder<Vertex>) this;
512     }
513
514     @Override
515     public QueryBuilder<E> union(QueryBuilder<E>... builder) {
516         markParentBoundary();
517         String[] traversals = new String[builder.length];
518         StringBuilder command = new StringBuilder();
519         for (int i = 0; i < builder.length; i++) {
520             traversals[i] = "__" + builder[i].getQuery();
521         }
522         command.append(".union(");
523         command.append(Joiner.on(",").join(traversals));
524         command.append(")");
525         list.add(command.toString());
526         stepIndex++;
527
528         return this;
529     }
530
531     @Override
532     public QueryBuilder<E> where(QueryBuilder<E>... builder) {
533         markParentBoundary();
534         List<String> traversals = new ArrayList<>();
535         for (int i = 0; i < builder.length; i++) {
536             traversals.add(".where(__" + builder[i].getQuery() + ")");
537             stepIndex++;
538         }
539         list.addAll(traversals);
540
541
542         return this;
543     }
544
545     @Override
546     public QueryBuilder<E> or(QueryBuilder<E>... builder) {
547         markParentBoundary();
548         String[] traversals = new String[builder.length];
549         StringBuilder command = new StringBuilder();
550         for (int i = 0; i < builder.length; i++) {
551             traversals[i] = "__" + builder[i].getQuery();
552         }
553         command.append(".or(");
554         command.append(Joiner.on(",").join(traversals));
555         command.append(")");
556         list.add(command.toString());
557         stepIndex++;
558
559         return this;
560     }
561
562     @Override
563     public QueryBuilder<E> store(String name) {
564         this.list.add(".store('"+ name + "')");
565         stepIndex++;
566
567         return this;
568     }
569
570     @Override
571     public QueryBuilder<E> cap(String name) {
572         this.list.add(".cap('"+ name + "')");
573         stepIndex++;
574
575         return this;
576     }
577
578     @Override
579     public QueryBuilder<E> unfold() {
580         this.list.add(".unfold()");
581         stepIndex++;
582
583         return this;
584     }
585
586     @Override
587     public QueryBuilder<E> dedup() {
588         this.list.add(".dedup()");
589         stepIndex++;
590
591         return this;
592     }
593
594     @Override
595     public QueryBuilder<E> emit() {
596         this.list.add(".emit()");
597         stepIndex++;
598
599         return this;
600     }
601
602     @Override
603     public QueryBuilder<E> repeat(QueryBuilder<E> builder) {
604         this.list.add(".repeat(__" + builder.getQuery()  + ")");
605         stepIndex++;
606
607         return this;
608     }
609
610     @Override
611     public QueryBuilder<E> until(QueryBuilder<E> builder) {
612         this.list.add(".until(__" + builder.getQuery() + ")");
613         stepIndex++;
614
615         return this;
616     }
617
618     @Override
619     public QueryBuilder<E> groupCount() {
620         this.list.add(".groupCount()");
621         stepIndex++;
622
623         return this;
624     }
625
626     @Override
627     public QueryBuilder<E> both() {
628         this.list.add(".both()");
629         stepIndex++;
630
631         return this;
632     }
633
634     @Override
635     public QueryBuilder<Tree> tree() {
636         this.list.add(".tree()");
637         stepIndex++;
638
639         return (QueryBuilder<Tree>)this;
640     }
641
642     @Override
643     public QueryBuilder<E> by(String name) {
644         this.list.add(".by('"+ name + "')");
645         stepIndex++;
646
647         return this;
648     }
649
650     /**
651      * {@inheritDoc}
652      */
653     @Override
654     public QueryBuilder<E> simplePath(){
655         this.list.add(".simplePath()");
656         stepIndex++;
657         return this;
658     }
659
660     /**
661      * {@inheritDoc}
662      */
663     @Override
664     public QueryBuilder<Path> path(){
665         this.list.add(".path()");
666         stepIndex++;
667         return (QueryBuilder<Path>)this;
668     }
669
670     @Override
671     public QueryBuilder<Edge> outE() {
672         this.list.add(".outE()");
673         stepIndex++;
674
675         return (QueryBuilder<Edge>)this;
676     }
677
678     @Override
679     public QueryBuilder<Edge> inE() {
680         this.list.add(".inE()");
681         stepIndex++;
682
683         return (QueryBuilder<Edge>)this;
684     }
685
686     @Override
687     public QueryBuilder<Vertex> outV() {
688         this.list.add(".outV()");
689         stepIndex++;
690
691         return (QueryBuilder<Vertex>)this;
692     }
693
694     @Override
695     public QueryBuilder<Vertex> inV() {
696         this.list.add(".inV()");
697         stepIndex++;
698
699         return (QueryBuilder<Vertex>)this;
700     }
701
702     @Override
703     public QueryBuilder<E> not(QueryBuilder<E> builder) {
704         this.list.add(".not(" + "__" + builder.getQuery() + ")");
705         stepIndex++;
706
707         return this;
708     }
709
710     @Override
711     public QueryBuilder<E> as(String name) {
712         this.list.add(".as('" + name + "')");
713         stepIndex++;
714
715         return this;
716     }
717
718     @Override
719     public QueryBuilder<E> select(String name) {
720         this.list.add(".select('" + name + "')");
721         stepIndex++;
722
723         return this;
724     }
725
726     @Override
727     public QueryBuilder<E> select(String... names) {
728         String stepString = ".select('";
729         for(int i = 0; i<names.length; i++) {
730                 stepString = stepString + names[i] +"'";
731                 if(i!=(names.length-1)) {
732                         stepString = stepString + ",'";
733                 }
734         }
735         stepString = stepString + ")";
736         this.list.add(stepString);
737         stepIndex++;
738
739         return this;
740     }
741     /**
742      * @{inheritDoc}
743      */
744     @Override
745     public QueryBuilder<E> getParentQuery() {
746         return cloneQueryAtStep(parentStepIndex);
747     }
748
749     @Override
750     public QueryBuilder<E> getContainerQuery() {
751         return cloneQueryAtStep(containerStepIndex);
752     }
753
754     /**
755      * @{inheritDoc}
756      */
757     @Override
758     public <T2> T2 getQuery() {
759         StringBuilder sb = new StringBuilder();
760
761         for (String piece : this.list) {
762             sb.append(piece);
763         }
764
765         return (T2)sb.toString();
766     }
767
768     /**
769      * @{inheritDoc}
770      */
771     @Override
772     public void markParentBoundary() {
773         parentStepIndex = stepIndex;
774     }
775
776     @Override
777     public void markContainer() {
778         this.containerStepIndex = stepIndex;
779     }
780
781     /**
782      * @{inheritDoc}
783      */
784     @Override
785     public Vertex getStart() {
786         return this.start;
787     }
788
789     protected int getParentStepIndex() {
790         return parentStepIndex;
791     }
792
793     protected int getContainerStepIndex() {
794         return containerStepIndex;
795     }
796
797     protected int getStepIndex() {
798         return stepIndex;
799     }
800
801     private void executeQuery() {
802         String queryString = "g" + Joiner.on("").join(list);
803         Map<String, Object> params = new HashMap<>();
804         if (this.start == null) {
805             params.put("g", source.V());
806         } else {
807             params.put("g", source.V(this.start));
808         }
809         this.completeTraversal = this.gremlinGroovy.executeTraversal(queryString, params);
810     }
811     @Override
812     public boolean hasNext() {
813         if (this.completeTraversal == null) {
814             executeQuery();
815         }
816
817         return this.completeTraversal.hasNext();
818     }
819
820     @Override
821     public E next() {
822         if (this.completeTraversal == null) {
823             executeQuery();
824         }
825
826         return (E)this.completeTraversal.next();
827     }
828
829     @Override
830     public List<E> toList() {
831         if (this.completeTraversal == null) {
832             executeQuery();
833         }
834
835         return (List<E>)this.completeTraversal.toList();
836     }
837
838     protected QueryBuilder<Edge> has(String key, String value) {
839         this.list.add(HAS + key + "','" + value + "')");
840
841         return (QueryBuilder<Edge>)this;
842     }
843
844 }