2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Modifications Copyright © 2024 DEUTSCHE TELEKOM AG.
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
13 * http://www.apache.org/licenses/LICENSE-2.0
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=========================================================
23 package org.onap.aai.query.builder;
25 import java.io.UnsupportedEncodingException;
27 import java.util.Iterator;
28 import java.util.List;
31 import javax.ws.rs.core.MultivaluedMap;
33 import org.apache.tinkerpop.gremlin.process.traversal.Path;
34 import org.apache.tinkerpop.gremlin.process.traversal.Pop;
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.Edge;
38 import org.apache.tinkerpop.gremlin.structure.Vertex;
39 import org.onap.aai.config.SpringContextAware;
40 import org.onap.aai.db.props.AAIProperties;
41 import org.onap.aai.edges.EdgeIngestor;
42 import org.onap.aai.edges.enums.AAIDirection;
43 import org.onap.aai.edges.enums.EdgeProperty;
44 import org.onap.aai.edges.enums.EdgeType;
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.parsers.query.QueryParser;
49 import org.onap.aai.parsers.query.QueryParserStrategy;
50 import org.springframework.context.ApplicationContext;
53 * The Class QueryBuilder.
55 public abstract class QueryBuilder<E> implements Iterator<E> {
57 protected final GraphTraversalSource source;
58 protected QueryParserStrategy factory = null;
59 protected Loader loader = null;
60 protected EdgeIngestor edgeRules;
61 protected boolean optimize = false;
62 protected Vertex start = null;
64 protected int parentStepIndex = 0;
65 protected int containerStepIndex = 0;
66 protected int stepIndex = 0;
69 * Instantiates a new query builder.
71 * @param loader the loader
73 public QueryBuilder(Loader loader, GraphTraversalSource source) {
80 * Instantiates a new query builder.
82 * @param loader the loader
83 * @param start the start
85 public QueryBuilder(Loader loader, GraphTraversalSource source, Vertex start) {
92 public void changeLoader(Loader loader) {
97 * Creates a new {@link QueryBuilder} that contains the traversal up to the provided index.
101 protected abstract QueryBuilder<E> cloneQueryAtStep(int index);
104 * Gets the vertices by indexed property.
107 * @param value the value
108 * @return the vertices by indexed property
110 public QueryBuilder<Vertex> getVerticesByIndexedProperty(String key, Object value) {
111 return this.getVerticesByProperty(key, value);
115 * Gets the vertices by property.
118 * @param value the value
119 * @return the vertices by property
121 public abstract QueryBuilder<Vertex> getVerticesByProperty(String key, Object value);
124 * Gets the edges by property.
127 * @param value the value
128 * @return the vertices by property
130 public QueryBuilder<Edge> getEdgesByProperty(String key, Object value) {
131 return this.has(key, value.toString());
135 * filters by all the values for this property
139 * @return vertices that match these values
141 public QueryBuilder<Vertex> getVerticesByIndexedProperty(String key, List<?> values) {
142 return this.getVerticesByProperty(key, values);
146 * filters by all the values for this property
150 * @return vertices that match these values
152 public abstract QueryBuilder<Vertex> getVerticesByProperty(String key, List<?> values);
155 * filters by all the values for this property
158 * @param value in comma delimited string format
159 * @return vertices that match these values
161 public abstract QueryBuilder<Vertex> getVerticesByCommaSeperatedValue(String key, String value);
164 * Gets the vertices that have this property key.
167 * @return the vertices by property
169 public abstract QueryBuilder<Vertex> getVerticesByProperty(String key);
172 * Gets the vertices that do not have this property key.
175 * @return the vertices by property
177 public abstract QueryBuilder<Vertex> getVerticesExcludeByProperty(String key);
180 * filters by elements that start with the value for this property
184 * @return vertices that match these values
186 public abstract QueryBuilder<Vertex> getVerticesStartsWithProperty(String key, Object value);
189 * Gets the vertices that are excluded by property.
192 * @param value the value
193 * @return the vertices by property
195 public abstract QueryBuilder<Vertex> getVerticesExcludeByProperty(String key, Object value);
198 * filters by all the values for this property and excludes the vertices
202 * @return vertices that match these values
204 public QueryBuilder<Vertex> getVerticesExcludeByIndexedProperty(String key, List<?> values) {
205 return this.getVerticesExcludeByProperty(key, values);
209 * filters by all the values for this property and excludes the vertices
213 * @return vertices that match these values
215 public abstract QueryBuilder<Vertex> getVerticesExcludeByProperty(String key, List<?> values);
218 * filters by all the values greater than for this property
222 * @return vertices that match these values
224 public abstract QueryBuilder<Vertex> getVerticesGreaterThanProperty(String key, Object value);
227 * filters by all the values less than for this property
231 * @return vertices that match these values
234 public abstract QueryBuilder<Vertex> getVerticesLessThanProperty(String key, Object value);
237 * Gets the child vertices from parent.
239 * @param parentKey the parent key
240 * @param parentValue the parent value
241 * @param childType the child type
242 * @return the child vertices from parent
244 public abstract QueryBuilder<Vertex> getChildVerticesFromParent(String parentKey, String parentValue,
248 * Gets the typed vertices by map.
250 * @param type the type
252 * @return the typed vertices by map
254 public abstract QueryBuilder<Vertex> getTypedVerticesByMap(String type, Map<String, String> map);
257 * Creates the DB query.
260 * @return the query builder
262 public QueryBuilder<Vertex> createDBQuery(Introspector obj) {
263 this.createKeyQuery(obj);
264 this.createContainerQuery(obj);
265 return (QueryBuilder<Vertex>) this;
269 * Creates the key query.
272 * @return the query builder
274 public abstract QueryBuilder<Vertex> createKeyQuery(Introspector obj);
277 * Creates the container query.<br>
278 * A container query is a query that will return a collection of objects:
280 * /cloud-infrastructure/complexes/complex/key1
282 * namespace container object
285 * @param obj the Introspector into the db schema
286 * @return the query builder
288 public abstract QueryBuilder<Vertex> createContainerQuery(Introspector obj);
291 * Creates the edge traversal.
293 * @param parent the parent
294 * @param child the child
295 * @return the query builder
297 public abstract QueryBuilder<Vertex> createEdgeTraversal(EdgeType type, Introspector parent, Introspector child)
300 public abstract QueryBuilder<Vertex> getVerticesByBooleanProperty(String key, Object value);
302 public QueryBuilder<Vertex> getVerticesByBooleanProperty(String key, MissingOptionalParameter value) {
303 return (QueryBuilder<Vertex>) this;
307 * Creates the private edge traversal.
309 * @param parent the parent
310 * @param child the child
311 * @return the query builder
313 public abstract QueryBuilder<Vertex> createPrivateEdgeTraversal(EdgeType type, Introspector parent,
314 Introspector child) throws AAIException;
317 * Creates the edge traversal.
319 * @param parent the parent
320 * @param child the child
321 * @return the query builder
323 public QueryBuilder<Vertex> createEdgeTraversal(EdgeType type, Vertex parent, Introspector child)
324 throws AAIException {
325 String nodeType = parent.<String>property(AAIProperties.NODE_TYPE).orElse(null);
326 this.createEdgeTraversal(type, nodeType, child.getDbName());
327 return (QueryBuilder<Vertex>) this;
336 * @throws AAIException
338 public QueryBuilder<Vertex> createEdgeTraversal(EdgeType type, String outNodeType, String inNodeType)
339 throws AAIException {
340 Introspector out = loader.introspectorFromName(outNodeType);
341 Introspector in = loader.introspectorFromName(inNodeType);
343 return createEdgeTraversal(type, out, in);
352 * @throws AAIException
354 public QueryBuilder<Vertex> createEdgeTraversal(String edgeType, String outNodeType, String inNodeType)
355 throws AAIException {
357 * When the optional parameter edgetype is sent it is a string that needs to be converted to Enum
359 EdgeType type = EdgeType.valueOf(edgeType);
360 Introspector out = loader.introspectorFromName(outNodeType);
361 Introspector in = loader.introspectorFromName(inNodeType);
363 return createEdgeTraversal(type, out, in);
372 * @throws AAIException
374 public QueryBuilder<Vertex> createEdgeTraversal(MissingOptionalParameter edgeType, String outNodeType,
375 String inNodeType) throws AAIException {
377 * When no optional parameter edgetype is sent get all edges between the 2 nodetypes
379 return this.createEdgeTraversal(outNodeType, inNodeType);
388 * @throws AAIException
390 public QueryBuilder<Vertex> createEdgeTraversalWithLabels(MissingOptionalParameter edgeType, String outNodeType,
391 String inNodeType, List<String> labels) throws AAIException {
393 * When no optional parameter edgetype is sent get all edges between the 2 nodetypes
395 return this.createEdgeTraversalWithLabels(outNodeType, inNodeType, labels);
398 public QueryBuilder<Vertex> createEdgeTraversal(String outNodeType, String inNodeType) throws AAIException {
400 Introspector out = loader.introspectorFromName(outNodeType);
401 Introspector in = loader.introspectorFromName(inNodeType);
403 QueryBuilder<Vertex> cousinBuilder = null;
404 QueryBuilder<Vertex> treeBuilder = null;
405 QueryBuilder<Vertex> queryBuilder = null;
408 cousinBuilder = this.newInstance().createEdgeTraversal(EdgeType.COUSIN, out, in);
409 } catch (AAIException e) {
412 if (cousinBuilder != null) {
414 treeBuilder = this.newInstance().createEdgeTraversal(EdgeType.TREE, out, in);
415 } catch (AAIException e) {
417 if (treeBuilder != null) {
418 queryBuilder = this.union(new QueryBuilder[] {cousinBuilder, treeBuilder});
420 queryBuilder = this.union(new QueryBuilder[] {cousinBuilder});
423 treeBuilder = this.newInstance().createEdgeTraversal(EdgeType.TREE, out, in);
424 queryBuilder = this.union(new QueryBuilder[] {treeBuilder});
430 public QueryBuilder<Vertex> createEdgeTraversalWithLabels(String outNodeType, String inNodeType,
431 List<String> labels) throws AAIException {
433 Introspector out = loader.introspectorFromName(outNodeType);
434 Introspector in = loader.introspectorFromName(inNodeType);
436 QueryBuilder<Vertex> cousinBuilder = null;
437 QueryBuilder<Vertex> treeBuilder = null;
438 QueryBuilder<Vertex> queryBuilder = null;
441 cousinBuilder = this.newInstance().createEdgeTraversalWithLabels(EdgeType.COUSIN, out, in, labels);
442 } catch (AAIException e) {
445 if (cousinBuilder != null) {
447 treeBuilder = this.newInstance().createEdgeTraversalWithLabels(EdgeType.TREE, out, in, labels);
448 } catch (AAIException e) {
450 if (treeBuilder != null) {
451 queryBuilder = this.union(new QueryBuilder[] {cousinBuilder, treeBuilder});
453 queryBuilder = this.union(new QueryBuilder[] {cousinBuilder});
456 treeBuilder = this.newInstance().createEdgeTraversalWithLabels(EdgeType.TREE, out, in, labels);
457 queryBuilder = this.union(new QueryBuilder[] {treeBuilder});
463 public QueryBuilder<Vertex> createPrivateEdgeTraversal(EdgeType type, String outNodeType, String inNodeType)
464 throws AAIException {
465 Introspector out = loader.introspectorFromName(outNodeType);
466 Introspector in = loader.introspectorFromName(inNodeType);
467 return createPrivateEdgeTraversal(type, out, in);
477 * @throws AAIException
479 public QueryBuilder<Vertex> createEdgeTraversalWithLabels(EdgeType type, String outNodeType, String inNodeType,
480 List<String> labels) throws AAIException {
481 Introspector out = loader.introspectorFromName(outNodeType);
482 Introspector in = loader.introspectorFromName(inNodeType);
484 return createEdgeTraversalWithLabels(type, out, in, labels);
495 public abstract QueryBuilder<Vertex> createEdgeTraversalWithLabels(EdgeType type, Introspector out, Introspector in,
496 List<String> labels) throws AAIException;
499 * This method and it's overloaded counterpart are conditional statements.
500 * This method creates an edge traversal step if an optional property is present
501 * This is necessary in cases such as "if the Optional Property 1 is sent,
502 * find all Nodes of type A with edges to Nodes of type B with property 1,
503 * otherwise, simply find all nodes of type A".
510 * @throws AAIException
512 public QueryBuilder<Vertex> createEdgeTraversalIfParameterIsPresent(EdgeType type, String outNodeType,
513 String inNodeType, Object value) throws AAIException {
514 return this.createEdgeTraversal(type, outNodeType, inNodeType);
518 * This method and it's overloaded counterpart are conditional statements.
519 * This method skips an edge traversal step if there is an optional property missing.
520 * This is necessary in cases such as "if the Optional Property 1 is sent,
521 * find all Nodes of type A with edges to Nodes of type B with property 1,
522 * otherwise, simply find all nodes of type A".
529 * @throws AAIException
531 public QueryBuilder<Vertex> createEdgeTraversalIfParameterIsPresent(EdgeType type, String outNodeType,
532 String inNodeType, MissingOptionalParameter value) throws AAIException {
533 return (QueryBuilder<Vertex>) this;
542 * @throws AAIException
544 public QueryBuilder<Edge> getEdgesBetween(EdgeType type, String outNodeType, String inNodeType)
545 throws AAIException {
546 this.getEdgesBetweenWithLabels(type, outNodeType, inNodeType, null);
548 return (QueryBuilder<Edge>) this;
559 * @throws AAIException
561 public abstract QueryBuilder<Edge> getEdgesBetweenWithLabels(EdgeType type, String outNodeType, String inNodeType,
562 List<String> labels) throws AAIException;
565 * Creates the query from URI.
568 * @return the query parser
569 * @throws UnsupportedEncodingException the unsupported encoding exception
570 * @throws AAIException the AAI exception
572 public abstract QueryParser createQueryFromURI(URI uri) throws UnsupportedEncodingException, AAIException;
575 * Creates the query from URI.
578 * @param queryParams the query params
579 * @return the query parser
580 * @throws UnsupportedEncodingException the unsupported encoding exception
581 * @throws AAIException the AAI exception
583 public abstract QueryParser createQueryFromURI(URI uri, MultivaluedMap<String, String> queryParams)
584 throws UnsupportedEncodingException, AAIException;
587 * Creates a queryparser from a given object name.
589 * @param objName - name of the object type as it appears in the database
592 public abstract QueryParser createQueryFromObjectName(String objName);
595 * Creates the query from relationship.
597 * @param relationship the relationship
598 * @return the query parser
599 * @throws UnsupportedEncodingException the unsupported encoding exception
600 * @throws AAIException the AAI exception
602 public abstract QueryParser createQueryFromRelationship(Introspector relationship)
603 throws UnsupportedEncodingException, AAIException;
606 * Gets the parent query.
608 * @return the parent query
610 public abstract QueryBuilder<E> getParentQuery();
617 public abstract <E2> E2 getQuery();
622 public abstract void markParentBoundary();
624 public abstract QueryBuilder<E> limit(long amount);
629 * @param start the start
630 * @return the query builder
632 public abstract QueryBuilder<E> newInstance(Vertex start);
637 * @return the query builder
639 public abstract QueryBuilder<E> newInstance();
646 public abstract Vertex getStart();
648 protected Object correctObjectType(Object obj) {
650 if (obj != null && obj.getClass().equals(Long.class)) {
651 return Integer.valueOf(obj.toString());
658 * uses all fields in the introspector to create a query
663 public abstract QueryBuilder<Vertex> exactMatchQuery(Introspector obj);
666 * lets you join any number of QueryBuilders
667 * <b>be careful about starting with a union it will not use indexes</b>
672 public abstract QueryBuilder<E> union(QueryBuilder<E>... builder);
674 public abstract QueryBuilder<E> where(QueryBuilder<E>... builder);
676 public abstract QueryBuilder<E> or(QueryBuilder<E>... builder);
678 public abstract QueryBuilder<E> store(String name);
680 public abstract QueryBuilder<E> cap(String name);
682 public abstract QueryBuilder<E> unfold();
684 public abstract QueryBuilder<E> fold();
686 public abstract QueryBuilder<E> id();
688 public abstract QueryBuilder<E> dedup();
690 public abstract QueryBuilder<E> emit();
692 public abstract QueryBuilder<E> repeat(QueryBuilder<E> builder);
694 public abstract QueryBuilder<Edge> outE();
696 public abstract QueryBuilder<Edge> inE();
698 public abstract QueryBuilder<Vertex> inV();
700 public abstract QueryBuilder<Vertex> outV();
702 public abstract QueryBuilder<E> not(QueryBuilder<E> builder);
704 public abstract QueryBuilder<E> as(String name);
706 public abstract QueryBuilder<E> select(String name);
708 public abstract QueryBuilder<E> select(Pop pop, String name);
710 public abstract QueryBuilder<E> select(String... names);
712 public abstract QueryBuilder<E> until(QueryBuilder<E> builder);
714 public abstract QueryBuilder<E> groupCount();
716 public abstract QueryBuilder<E> by(String name);
718 public abstract QueryBuilder<E> valueMap();
720 public abstract QueryBuilder<E> valueMap(String... names);
722 public abstract QueryBuilder<E> both();
724 public abstract QueryBuilder<Tree> tree();
727 * Used to prevent the traversal from repeating its path through the graph.
728 * See http://tinkerpop.apache.org/docs/3.0.1-incubating/#simplepath-step for more info.
730 * @return a QueryBuilder with the simplePath step appended to its traversal
732 public abstract QueryBuilder<E> simplePath();
736 * @return QueryBuilder with the path step appended to its traversal
738 public abstract QueryBuilder<Path> path();
740 public abstract void markContainer();
742 public abstract QueryBuilder<E> getContainerQuery();
744 public abstract List<E> toList();
747 * Used to skip step if there is an optional property missing.
753 public QueryBuilder<Vertex> getVerticesByProperty(String key, MissingOptionalParameter value) {
754 return (QueryBuilder<Vertex>) this;
758 * TODO the edge direction is hardcoded here, make it more generic
759 * Returns the parent edge of the vertex
763 public QueryBuilder<Edge> getParentEdge() {
764 this.outE().has(EdgeProperty.CONTAINS.toString(), AAIDirection.IN.toString());
765 return (QueryBuilder<Edge>) this;
769 * TODO the edge direction is hardcoded here, make it more generic
770 * Returns the parent vertex of the vertex
774 public QueryBuilder<Vertex> getParentVertex() {
775 this.getParentEdge().inV();
776 return (QueryBuilder<Vertex>) this;
779 protected abstract QueryBuilder<Edge> has(String key, String value);
781 protected void initEdgeIngestor() {
782 // TODO proper spring wiring, but that requires a lot of refactoring so for now we have this
783 ApplicationContext ctx = SpringContextAware.getApplicationContext();
784 EdgeIngestor ei = ctx.getBean(EdgeIngestor.class);
788 protected void setEdgeIngestor(EdgeIngestor ei) {
792 public QueryBuilder<Vertex> getVerticesByNumberProperty(String key, Object value) {
793 return getVerticesByProperty(key, value);
796 public QueryBuilder<Vertex> getVerticesByNumberProperty(String key) {
797 return getVerticesByProperty(key);
800 public QueryBuilder<Vertex> getVerticesByNumberProperty(String key, MissingOptionalParameter value) {
801 return getVerticesByProperty(key, value);
804 protected abstract void vertexHas(String key, Object value);
806 protected abstract void vertexHasNot(String key);
808 protected abstract void vertexHas(String key);
810 // TODO: This probably is not required but need to test
811 // protected abstract void vertexHas(final String key, final P<?> predicate);