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.dsl.graph.GraphTraversalSource;
35 import org.apache.tinkerpop.gremlin.process.traversal.step.util.Tree;
36 import org.apache.tinkerpop.gremlin.structure.Edge;
37 import org.apache.tinkerpop.gremlin.structure.Vertex;
38 import org.onap.aai.config.SpringContextAware;
39 import org.onap.aai.db.props.AAIProperties;
40 import org.onap.aai.edges.EdgeIngestor;
41 import org.onap.aai.edges.enums.AAIDirection;
42 import org.onap.aai.edges.enums.EdgeProperty;
43 import org.onap.aai.edges.enums.EdgeType;
44 import org.onap.aai.exceptions.AAIException;
45 import org.onap.aai.introspection.Introspector;
46 import org.onap.aai.introspection.Loader;
47 import org.onap.aai.parsers.query.QueryParser;
48 import org.onap.aai.parsers.query.QueryParserStrategy;
49 import org.springframework.context.ApplicationContext;
52 * The Class QueryBuilder.
54 public abstract class QueryBuilder<E> implements Iterator<E> {
56 protected final GraphTraversalSource source;
57 protected QueryParserStrategy factory = null;
58 protected Loader loader = null;
59 protected EdgeIngestor edgeRules;
60 protected boolean optimize = false;
61 protected Vertex start = null;
63 protected int parentStepIndex = 0;
64 protected int containerStepIndex = 0;
65 protected int stepIndex = 0;
68 * Instantiates a new query builder.
70 * @param loader the loader
72 public QueryBuilder(Loader loader, GraphTraversalSource source) {
79 * Instantiates a new query builder.
81 * @param loader the loader
82 * @param start the start
84 public QueryBuilder(Loader loader, GraphTraversalSource source, Vertex start) {
91 public void changeLoader(Loader loader) {
96 * Creates a new {@link QueryBuilder} that contains the traversal up to the provided index.
100 protected abstract QueryBuilder<E> cloneQueryAtStep(int index);
103 * Gets the vertices by indexed property.
106 * @param value the value
107 * @return the vertices by indexed property
109 public QueryBuilder<Vertex> getVerticesByIndexedProperty(String key, Object value) {
110 return this.getVerticesByProperty(key, value);
114 * Gets the vertices by property.
117 * @param value the value
118 * @return the vertices by property
120 public abstract QueryBuilder<Vertex> getVerticesByProperty(String key, Object value);
123 * Gets the edges by property.
126 * @param value the value
127 * @return the vertices by property
129 public QueryBuilder<Edge> getEdgesByProperty(String key, Object value) {
130 return this.has(key, value.toString());
134 * filters by all the values for this property
138 * @return vertices that match these values
140 public QueryBuilder<Vertex> getVerticesByIndexedProperty(String key, List<?> values) {
141 return this.getVerticesByProperty(key, values);
145 * filters by all the values for this property
149 * @return vertices that match these values
151 public abstract QueryBuilder<Vertex> getVerticesByProperty(String key, List<?> values);
154 * filters by all the values for this property
157 * @param value in comma delimited string format
158 * @return vertices that match these values
160 public abstract QueryBuilder<Vertex> getVerticesByCommaSeperatedValue(String key, String value);
163 * Gets the vertices that have this property key.
166 * @return the vertices by property
168 public abstract QueryBuilder<Vertex> getVerticesByProperty(String key);
171 * Gets the vertices that do not have this property key.
174 * @return the vertices by property
176 public abstract QueryBuilder<Vertex> getVerticesExcludeByProperty(String key);
179 * filters by elements that start with the value for this property
183 * @return vertices that match these values
185 public abstract QueryBuilder<Vertex> getVerticesStartsWithProperty(String key, Object value);
188 * Gets the vertices that are excluded by property.
191 * @param value the value
192 * @return the vertices by property
194 public abstract QueryBuilder<Vertex> getVerticesExcludeByProperty(String key, Object value);
197 * filters by all the values for this property and excludes the vertices
201 * @return vertices that match these values
203 public QueryBuilder<Vertex> getVerticesExcludeByIndexedProperty(String key, List<?> values) {
204 return this.getVerticesExcludeByProperty(key, values);
208 * filters by all the values for this property and excludes the vertices
212 * @return vertices that match these values
214 public abstract QueryBuilder<Vertex> getVerticesExcludeByProperty(String key, List<?> values);
217 * filters by all the values greater than for this property
221 * @return vertices that match these values
223 public abstract QueryBuilder<Vertex> getVerticesGreaterThanProperty(String key, Object value);
226 * filters by all the values less than for this property
230 * @return vertices that match these values
233 public abstract QueryBuilder<Vertex> getVerticesLessThanProperty(String key, Object value);
236 * Gets the child vertices from parent.
238 * @param parentKey the parent key
239 * @param parentValue the parent value
240 * @param childType the child type
241 * @return the child vertices from parent
243 public abstract QueryBuilder<Vertex> getChildVerticesFromParent(String parentKey, String parentValue,
247 * Gets the typed vertices by map.
249 * @param type the type
251 * @return the typed vertices by map
253 public abstract QueryBuilder<Vertex> getTypedVerticesByMap(String type, Map<String, String> map);
256 * Creates the DB query.
259 * @return the query builder
261 public QueryBuilder<Vertex> createDBQuery(Introspector obj) {
262 this.createKeyQuery(obj);
263 this.createContainerQuery(obj);
264 return (QueryBuilder<Vertex>) this;
268 * Creates the key query.
271 * @return the query builder
273 public abstract QueryBuilder<Vertex> createKeyQuery(Introspector obj);
276 * Creates the container query.<br>
277 * A container query is a query that will return a collection of objects:
279 * /cloud-infrastructure/complexes/complex/key1
281 * namespace container object
284 * @param obj the Introspector into the db schema
285 * @return the query builder
287 public abstract QueryBuilder<Vertex> createContainerQuery(Introspector obj);
290 * Creates the edge traversal.
292 * @param parent the parent
293 * @param child the child
294 * @return the query builder
296 public abstract QueryBuilder<Vertex> createEdgeTraversal(EdgeType type, Introspector parent, Introspector child)
299 public abstract QueryBuilder<Vertex> getVerticesByBooleanProperty(String key, Object value);
301 public QueryBuilder<Vertex> getVerticesByBooleanProperty(String key, MissingOptionalParameter value) {
302 return (QueryBuilder<Vertex>) this;
306 * Creates the private edge traversal.
308 * @param parent the parent
309 * @param child the child
310 * @return the query builder
312 public abstract QueryBuilder<Vertex> createPrivateEdgeTraversal(EdgeType type, Introspector parent,
313 Introspector child) throws AAIException;
316 * Creates the edge traversal.
318 * @param parent the parent
319 * @param child the child
320 * @return the query builder
322 public QueryBuilder<Vertex> createEdgeTraversal(EdgeType type, Vertex parent, Introspector child)
323 throws AAIException {
324 String nodeType = parent.<String>property(AAIProperties.NODE_TYPE).orElse(null);
325 this.createEdgeTraversal(type, nodeType, child.getDbName());
326 return (QueryBuilder<Vertex>) this;
335 * @throws AAIException
337 public QueryBuilder<Vertex> createEdgeTraversal(EdgeType type, String outNodeType, String inNodeType)
338 throws AAIException {
339 Introspector out = loader.introspectorFromName(outNodeType);
340 Introspector in = loader.introspectorFromName(inNodeType);
342 return createEdgeTraversal(type, out, in);
351 * @throws AAIException
353 public QueryBuilder<Vertex> createEdgeTraversal(String edgeType, String outNodeType, String inNodeType)
354 throws AAIException {
356 * When the optional parameter edgetype is sent it is a string that needs to be converted to Enum
358 EdgeType type = EdgeType.valueOf(edgeType);
359 Introspector out = loader.introspectorFromName(outNodeType);
360 Introspector in = loader.introspectorFromName(inNodeType);
362 return createEdgeTraversal(type, out, in);
371 * @throws AAIException
373 public QueryBuilder<Vertex> createEdgeTraversal(MissingOptionalParameter edgeType, String outNodeType,
374 String inNodeType) throws AAIException {
376 * When no optional parameter edgetype is sent get all edges between the 2 nodetypes
378 return this.createEdgeTraversal(outNodeType, inNodeType);
387 * @throws AAIException
389 public QueryBuilder<Vertex> createEdgeTraversalWithLabels(MissingOptionalParameter edgeType, String outNodeType,
390 String inNodeType, List<String> labels) throws AAIException {
392 * When no optional parameter edgetype is sent get all edges between the 2 nodetypes
394 return this.createEdgeTraversalWithLabels(outNodeType, inNodeType, labels);
397 public QueryBuilder<Vertex> createEdgeTraversal(String outNodeType, String inNodeType) throws AAIException {
399 Introspector out = loader.introspectorFromName(outNodeType);
400 Introspector in = loader.introspectorFromName(inNodeType);
402 QueryBuilder<Vertex> cousinBuilder = null;
403 QueryBuilder<Vertex> treeBuilder = null;
404 QueryBuilder<Vertex> queryBuilder = null;
407 cousinBuilder = this.newInstance().createEdgeTraversal(EdgeType.COUSIN, out, in);
408 } catch (AAIException e) {
411 if (cousinBuilder != null) {
413 treeBuilder = this.newInstance().createEdgeTraversal(EdgeType.TREE, out, in);
414 } catch (AAIException e) {
416 if (treeBuilder != null) {
417 queryBuilder = this.union(new QueryBuilder[] {cousinBuilder, treeBuilder});
419 queryBuilder = this.union(new QueryBuilder[] {cousinBuilder});
422 treeBuilder = this.newInstance().createEdgeTraversal(EdgeType.TREE, out, in);
423 queryBuilder = this.union(new QueryBuilder[] {treeBuilder});
429 public QueryBuilder<Vertex> createEdgeTraversalWithLabels(String outNodeType, String inNodeType,
430 List<String> labels) throws AAIException {
432 Introspector out = loader.introspectorFromName(outNodeType);
433 Introspector in = loader.introspectorFromName(inNodeType);
435 QueryBuilder<Vertex> cousinBuilder = null;
436 QueryBuilder<Vertex> treeBuilder = null;
437 QueryBuilder<Vertex> queryBuilder = null;
440 cousinBuilder = this.newInstance().createEdgeTraversalWithLabels(EdgeType.COUSIN, out, in, labels);
441 } catch (AAIException e) {
444 if (cousinBuilder != null) {
446 treeBuilder = this.newInstance().createEdgeTraversalWithLabels(EdgeType.TREE, out, in, labels);
447 } catch (AAIException e) {
449 if (treeBuilder != null) {
450 queryBuilder = this.union(new QueryBuilder[] {cousinBuilder, treeBuilder});
452 queryBuilder = this.union(new QueryBuilder[] {cousinBuilder});
455 treeBuilder = this.newInstance().createEdgeTraversalWithLabels(EdgeType.TREE, out, in, labels);
456 queryBuilder = this.union(new QueryBuilder[] {treeBuilder});
462 public QueryBuilder<Vertex> createPrivateEdgeTraversal(EdgeType type, String outNodeType, String inNodeType)
463 throws AAIException {
464 Introspector out = loader.introspectorFromName(outNodeType);
465 Introspector in = loader.introspectorFromName(inNodeType);
466 return createPrivateEdgeTraversal(type, out, in);
476 * @throws AAIException
478 public QueryBuilder<Vertex> createEdgeTraversalWithLabels(EdgeType type, String outNodeType, String inNodeType,
479 List<String> labels) throws AAIException {
480 Introspector out = loader.introspectorFromName(outNodeType);
481 Introspector in = loader.introspectorFromName(inNodeType);
483 return createEdgeTraversalWithLabels(type, out, in, labels);
494 public abstract QueryBuilder<Vertex> createEdgeTraversalWithLabels(EdgeType type, Introspector out, Introspector in,
495 List<String> labels) throws AAIException;
498 * This method and it's overloaded counterpart are conditional statements.
499 * This method creates an edge traversal step if an optional property is present
500 * This is necessary in cases such as "if the Optional Property 1 is sent,
501 * find all Nodes of type A with edges to Nodes of type B with property 1,
502 * otherwise, simply find all nodes of type A".
509 * @throws AAIException
511 public QueryBuilder<Vertex> createEdgeTraversalIfParameterIsPresent(EdgeType type, String outNodeType,
512 String inNodeType, Object value) throws AAIException {
513 return this.createEdgeTraversal(type, outNodeType, inNodeType);
517 * This method and it's overloaded counterpart are conditional statements.
518 * This method skips an edge traversal step if there is an optional property missing.
519 * This is necessary in cases such as "if the Optional Property 1 is sent,
520 * find all Nodes of type A with edges to Nodes of type B with property 1,
521 * otherwise, simply find all nodes of type A".
528 * @throws AAIException
530 public QueryBuilder<Vertex> createEdgeTraversalIfParameterIsPresent(EdgeType type, String outNodeType,
531 String inNodeType, MissingOptionalParameter value) throws AAIException {
532 return (QueryBuilder<Vertex>) this;
541 * @throws AAIException
543 public QueryBuilder<Edge> getEdgesBetween(EdgeType type, String outNodeType, String inNodeType)
544 throws AAIException {
545 this.getEdgesBetweenWithLabels(type, outNodeType, inNodeType, null);
547 return (QueryBuilder<Edge>) this;
558 * @throws AAIException
560 public abstract QueryBuilder<Edge> getEdgesBetweenWithLabels(EdgeType type, String outNodeType, String inNodeType,
561 List<String> labels) throws AAIException;
564 * Creates the query from URI.
567 * @return the query parser
568 * @throws UnsupportedEncodingException the unsupported encoding exception
569 * @throws AAIException the AAI exception
571 public abstract QueryParser createQueryFromURI(URI uri) throws UnsupportedEncodingException, AAIException;
574 * Creates the query from URI.
577 * @param queryParams the query params
578 * @return the query parser
579 * @throws UnsupportedEncodingException the unsupported encoding exception
580 * @throws AAIException the AAI exception
582 public abstract QueryParser createQueryFromURI(URI uri, MultivaluedMap<String, String> queryParams)
583 throws UnsupportedEncodingException, AAIException;
586 * Creates a queryparser from a given object name.
588 * @param objName - name of the object type as it appears in the database
591 public abstract QueryParser createQueryFromObjectName(String objName);
594 * Creates the query from relationship.
596 * @param relationship the relationship
597 * @return the query parser
598 * @throws UnsupportedEncodingException the unsupported encoding exception
599 * @throws AAIException the AAI exception
601 public abstract QueryParser createQueryFromRelationship(Introspector relationship)
602 throws UnsupportedEncodingException, AAIException;
605 * Gets the parent query.
607 * @return the parent query
609 public abstract QueryBuilder<E> getParentQuery();
616 public abstract <E2> E2 getQuery();
621 public abstract void markParentBoundary();
623 public abstract QueryBuilder<E> limit(long amount);
628 * @param start the start
629 * @return the query builder
631 public abstract QueryBuilder<E> newInstance(Vertex start);
636 * @return the query builder
638 public abstract QueryBuilder<E> newInstance();
645 public abstract Vertex getStart();
647 protected Object correctObjectType(Object obj) {
649 if (obj != null && obj.getClass().equals(Long.class)) {
650 return Integer.valueOf(obj.toString());
657 * uses all fields in the introspector to create a query
662 public abstract QueryBuilder<Vertex> exactMatchQuery(Introspector obj);
665 * lets you join any number of QueryBuilders
666 * <b>be careful about starting with a union it will not use indexes</b>
671 public abstract QueryBuilder<E> union(QueryBuilder<E>... builder);
673 public abstract QueryBuilder<E> where(QueryBuilder<E>... builder);
675 public abstract QueryBuilder<E> or(QueryBuilder<E>... builder);
677 public abstract QueryBuilder<E> store(String name);
679 public abstract QueryBuilder<E> cap(String name);
681 public abstract QueryBuilder<E> unfold();
683 public abstract QueryBuilder<E> fold();
685 public abstract QueryBuilder<E> id();
687 public abstract QueryBuilder<E> dedup();
689 public abstract QueryBuilder<E> emit();
691 public abstract QueryBuilder<E> repeat(QueryBuilder<E> builder);
693 public abstract QueryBuilder<Edge> outE();
695 public abstract QueryBuilder<Edge> inE();
697 public abstract QueryBuilder<Vertex> inV();
699 public abstract QueryBuilder<Vertex> outV();
701 public abstract QueryBuilder<E> not(QueryBuilder<E> builder);
703 public abstract QueryBuilder<E> as(String name);
705 public abstract QueryBuilder<E> select(String name);
707 public abstract QueryBuilder<E> select(String... names);
709 public abstract QueryBuilder<E> until(QueryBuilder<E> builder);
711 public abstract QueryBuilder<E> groupCount();
713 public abstract QueryBuilder<E> by(String name);
715 public abstract QueryBuilder<E> valueMap();
717 public abstract QueryBuilder<E> valueMap(String... names);
719 public abstract QueryBuilder<E> both();
721 public abstract QueryBuilder<Tree> tree();
724 * Used to prevent the traversal from repeating its path through the graph.
725 * See http://tinkerpop.apache.org/docs/3.0.1-incubating/#simplepath-step for more info.
727 * @return a QueryBuilder with the simplePath step appended to its traversal
729 public abstract QueryBuilder<E> simplePath();
733 * @return QueryBuilder with the path step appended to its traversal
735 public abstract QueryBuilder<Path> path();
737 public abstract void markContainer();
739 public abstract QueryBuilder<E> getContainerQuery();
741 public abstract List<E> toList();
744 * Used to skip step if there is an optional property missing.
750 public QueryBuilder<Vertex> getVerticesByProperty(String key, MissingOptionalParameter value) {
751 return (QueryBuilder<Vertex>) this;
755 * TODO the edge direction is hardcoded here, make it more generic
756 * Returns the parent edge of the vertex
760 public QueryBuilder<Edge> getParentEdge() {
761 this.outE().has(EdgeProperty.CONTAINS.toString(), AAIDirection.IN.toString());
762 return (QueryBuilder<Edge>) this;
766 * TODO the edge direction is hardcoded here, make it more generic
767 * Returns the parent vertex of the vertex
771 public QueryBuilder<Vertex> getParentVertex() {
772 this.getParentEdge().inV();
773 return (QueryBuilder<Vertex>) this;
776 protected abstract QueryBuilder<Edge> has(String key, String value);
778 protected void initEdgeIngestor() {
779 // TODO proper spring wiring, but that requires a lot of refactoring so for now we have this
780 ApplicationContext ctx = SpringContextAware.getApplicationContext();
781 EdgeIngestor ei = ctx.getBean(EdgeIngestor.class);
785 protected void setEdgeIngestor(EdgeIngestor ei) {
789 public QueryBuilder<Vertex> getVerticesByNumberProperty(String key, Object value) {
790 return getVerticesByProperty(key, value);
793 public QueryBuilder<Vertex> getVerticesByNumberProperty(String key) {
794 return getVerticesByProperty(key);
797 public QueryBuilder<Vertex> getVerticesByNumberProperty(String key, MissingOptionalParameter value) {
798 return getVerticesByProperty(key, value);
801 protected abstract void vertexHas(String key, Object value);
803 protected abstract void vertexHasNot(String key);
805 protected abstract void vertexHas(String key);
807 // TODO: This probably is not required but need to test
808 // protected abstract void vertexHas(final String key, final P<?> predicate);