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