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