All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.arangodb.util.GraphQueryUtil Maven / Gradle / Ivy

There is a newer version: 7.15.0
Show newest version
package com.arangodb.util;

import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;

import com.arangodb.ArangoDriver;
import com.arangodb.ArangoException;
import com.arangodb.Direction;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;

/**
 * @author Mark - [email protected]
 *
 */
public class GraphQueryUtil {

	private static final String AND = " && ";
	private static final String OR = " || ";
	private static final String GRAPH_NAME = "graphName";
	private static final String VERTEX_EXAMPLE = "vertexExample";
	private static final String START_VERTEX_EXAMPLE = "startVertexExample";
	private static final String END_VERTEX_EXAMPLE = "endVertexExample";
	private static final String SOURCE = "source";
	private static final String TARGET = "target";

	public static String createEdgeQuery(
		final ArangoDriver driver,
		final String graphName,
		final Object vertexExample,
		final GraphEdgesOptions graphEdgesOptions,
		final MapBuilder bindVars) throws ArangoException {

		final StringBuilder sb = new StringBuilder();
		if (vertexExample != null && String.class.isAssignableFrom(vertexExample.getClass())) {
			sb.append("FOR v,e IN ");
			appendDepth(graphEdgesOptions, sb);
			appendDirection(graphEdgesOptions.getDirection(), sb);
			appendBindVar(VERTEX_EXAMPLE, vertexExample, bindVars, sb);
		} else {
			final List startVertexCollectionRestriction = graphEdgesOptions
					.getStartVertexCollectionRestriction();
			final List vertexCollections = startVertexCollectionRestriction != null
					&& startVertexCollectionRestriction.size() > 0 ? startVertexCollectionRestriction
							: driver.graphGetVertexCollections(graphName, true);
			appendFor("start", vertexExample, sb, vertexCollections);
			sb.append(" FOR v,e IN ");
			appendDepth(graphEdgesOptions, sb);
			appendDirection(graphEdgesOptions.getDirection(), sb);
			sb.append(" start");
		}
		final List edgeCollectionRestriction = graphEdgesOptions.getEdgeCollectionRestriction();
		appendEdgeCollectionsOrGraph(graphName, bindVars, sb, edgeCollectionRestriction);
		appendFilter("e", graphEdgesOptions.getEdgeExamples(), sb);
		appendFilter("v", graphEdgesOptions.getNeighborExamples(), sb);
		{
			final List endVertexCollectionRestriction = graphEdgesOptions.getEndVertexCollectionRestriction();
			if (endVertexCollectionRestriction != null && endVertexCollectionRestriction.size() > 0) {
				sb.append(" FILTER ");
				for (String endVertexCollection : endVertexCollectionRestriction) {
					sb.append("IS_SAME_COLLECTION(`");
					sb.append(endVertexCollection);
					sb.append("`,v)");
					sb.append(OR);
				}
				sb.delete(sb.length() - OR.length(), sb.length() - 1);
			}
		}
		final Integer limit = graphEdgesOptions.getLimit();
		if (limit != null) {
			sb.append(" LIMIT ");
			sb.append(limit.intValue());
		}
		sb.append(" RETURN distinct e");
		if (graphEdgesOptions.getIncludeData() != null && !graphEdgesOptions.getIncludeData().booleanValue()) {
			sb.append(".id");
		}

		final String query = sb.toString();
		return query;
	}

	private static void appendEdgeCollectionsOrGraph(
		final String graphName,
		final MapBuilder bindVars,
		final StringBuilder sb,
		final List edgeCollectionRestriction) {
		sb.append(" ");
		if (edgeCollectionRestriction != null && edgeCollectionRestriction.size() > 0) {
			for (String edgeCollection : edgeCollectionRestriction) {
				sb.append("`");
				sb.append(edgeCollection);
				sb.append("`,");
			}
			// remove last ,
			sb.deleteCharAt(sb.length() - 1);
		} else {
			appendGraphName(graphName, bindVars, sb);
		}
	}

	private static void appendBindVar(
		final String param,
		final Object var,
		final MapBuilder bindVars,
		final StringBuilder sb) {
		sb.append(" @");
		sb.append(param);
		bindVars.put(param, var);
	}

	private static void appendFor(
		final String var,
		final Object vertexExample,
		final StringBuilder sb,
		final List vertexCollections) throws ArangoException {
		if (vertexCollections.size() == 1) {
			sb.append("FOR ");
			sb.append(var);
			sb.append(" IN `");
			sb.append(vertexCollections.get(0));
			sb.append("`");
			appendFilter(var, vertexExample, sb);
		} else {
			sb.append("FOR ");
			sb.append(var);
			sb.append(" IN UNION (");
			for (String vertexCollection : vertexCollections) {
				sb.append("(FOR ");
				sb.append(var);
				sb.append(" IN `");
				sb.append(vertexCollection);
				sb.append("`");
				appendFilter(var, vertexExample, sb);
				sb.append(" RETURN ");
				sb.append(var);
				sb.append("),");
			}
			// remove last ,
			sb.deleteCharAt(sb.length() - 1);
			sb.append(")");
		}
		sb.append(" ");
	}

	private static void appendGraphName(final String graphName, final MapBuilder bindVars, final StringBuilder sb) {
		sb.append("GRAPH");
		appendBindVar(GRAPH_NAME, graphName, bindVars, sb);
	}

	private static void appendDepth(final GraphEdgesOptions graphEdgesOptions, final StringBuilder sb) {
		final Integer minDepth = graphEdgesOptions.getMinDepth();
		final Integer maxDepth = graphEdgesOptions.getMaxDepth();
		if (minDepth != null || maxDepth != null) {
			sb.append(minDepth != null ? minDepth : 1);
			sb.append("..");
			sb.append(maxDepth != null ? maxDepth : 1);
			sb.append(" ");
		}
	}

	private static void appendDirection(final Direction direction, final StringBuilder sb) {
		final String directionName = direction != null ? direction.name() : Direction.ANY.name();
		sb.append(directionName);
	}

	private static void appendFilter(final String var, final Object example, final StringBuilder sb)
			throws ArangoException {
		if (example != null) {
			final Gson gson = new Gson();
			final JsonElement json = gson.toJsonTree(example);
			if (json.isJsonObject()) {
				sb.append(" FILTER ");
				appendObjectinFilter(var, json.getAsJsonObject(), sb);
			} else if (json.isJsonArray()) {
				sb.append(" FILTER ");
				final JsonArray jsonArray = json.getAsJsonArray();
				if (jsonArray.size() > 0) {
					for (JsonElement jsonElement : jsonArray) {
						if (jsonElement.isJsonObject()) {
							sb.append("(");
							appendObjectinFilter(var, jsonElement.getAsJsonObject(), sb);
							sb.append(")");
							sb.append(OR);
						} else if (!jsonElement.isJsonNull()) {
							throw new ArangoException("invalide format of entry in array example: "
									+ example.getClass().getSimpleName() + ". only objects in array allowed.");
						}
					}
					sb.delete(sb.length() - OR.length(), sb.length() - 1);
				}
			} else {
				throw new ArangoException("invalide format of example: " + example.getClass().getSimpleName()
						+ ". only object or array allowed.");
			}
		}
	}

	private static void appendObjectinFilter(final String var, final JsonObject jsonObject, final StringBuilder sb) {
		final Set> entrySet = jsonObject.entrySet();
		for (Entry entry : entrySet) {
			sb.append(var);
			sb.append(".`");
			sb.append(entry.getKey());
			sb.append("` == ");
			sb.append(entry.getValue().toString());
			sb.append(AND);
		}
		sb.delete(sb.length() - AND.length(), sb.length() - 1);
	}

	public static String createVerticesQuery(
		final ArangoDriver driver,
		final String graphName,
		final Object vertexExample,
		final GraphVerticesOptions graphVerticesOptions,
		final MapBuilder bindVars) throws ArangoException {

		StringBuilder sb = new StringBuilder();
		final boolean stringVertexExample = vertexExample != null
				&& String.class.isAssignableFrom(vertexExample.getClass());
		if (stringVertexExample) {
			sb.append("RETURN ");
			sb.append("DOCUMENT(");
			appendBindVar(VERTEX_EXAMPLE, vertexExample, bindVars, sb);
			sb.append(")");
		} else {
			final List startVertexCollectionRestriction = graphVerticesOptions.getVertexCollectionRestriction();
			final List vertexCollections = startVertexCollectionRestriction != null
					&& startVertexCollectionRestriction.size() > 0 ? startVertexCollectionRestriction
							: driver.graphGetVertexCollections(graphName, true);
			appendFor("start", vertexExample, sb, vertexCollections);
			sb.append(" RETURN start");
		}

		final String query = sb.toString();
		return query;
	}

	public static String createShortestPathQuery(
		final ArangoDriver driver,
		final String database,
		final String graphName,
		final Object startVertexExample,
		final Object endVertexExample,
		final ShortestPathOptions shortestPathOptions,
		final Class vertexClass,
		final Class edgeClass,
		final MapBuilder bindVars) throws ArangoException {
		/*
		 * 
		 * final String query =
		 * "for i in graph_shortest_path(@graphName, @startVertexExample, @endVertexExample, @options) return i"
		 * ; final Map bindVars = mapBuilder.put("graphName",
		 * graphName) .put("startVertexExample",
		 * startVertexExample).put("endVertexExample", endVertexExample)
		 * .put("options", options).get();
		 */
		final StringBuilder sb = new StringBuilder();
		final boolean notStringStartVertexExample = startVertexExample != null
				&& !String.class.isAssignableFrom(startVertexExample.getClass());
		boolean notStringEndVertexExample = endVertexExample != null
				&& !String.class.isAssignableFrom(endVertexExample.getClass());
		if (notStringStartVertexExample || notStringEndVertexExample) {
			final List startVertexCollectionRestriction = shortestPathOptions
					.getStartVertexCollectionRestriction();
			final List endVertexCollectionRestriction = shortestPathOptions.getEndVertexCollectionRestriction();
			final boolean startVertexCollectionRestrictionNotEmpty = startVertexCollectionRestriction != null
					&& startVertexCollectionRestriction.size() > 0;
			final boolean endVertexCollectionRestrictionNotEmpty = endVertexCollectionRestriction != null
					&& endVertexCollectionRestriction.size() > 0;
			final List vertexCollections = (!startVertexCollectionRestrictionNotEmpty
					|| !endVertexCollectionRestrictionNotEmpty) ? driver.graphGetVertexCollections(graphName, true)
							: new ArrayList();

			if (notStringStartVertexExample) {
				final List tmpStartVertexCollectionRestriction = startVertexCollectionRestrictionNotEmpty
						? startVertexCollectionRestriction : vertexCollections;
				appendFor(SOURCE, startVertexExample, sb, tmpStartVertexCollectionRestriction);
			}
			if (notStringEndVertexExample) {
				final List tmpEndVertexCollectionRestriction = endVertexCollectionRestrictionNotEmpty
						? endVertexCollectionRestriction : vertexCollections;
				appendFor(TARGET, endVertexExample, sb, tmpEndVertexCollectionRestriction);
			}
			if (notStringStartVertexExample && notStringEndVertexExample) {
				sb.append("FILTER target != source ");
			}
		}
		{// p
			sb.append("LET p = ( FOR v, e IN ");
			appendDirection(shortestPathOptions.getDirection(), sb);
			sb.append(" SHORTEST_PATH ");
			if (notStringStartVertexExample) {
				sb.append(SOURCE);
			} else {
				appendBindVar(START_VERTEX_EXAMPLE, startVertexExample, bindVars, sb);
			}
			sb.append(" TO ");
			if (notStringEndVertexExample) {
				sb.append(TARGET);
			} else {
				appendBindVar(END_VERTEX_EXAMPLE, endVertexExample, bindVars, sb);
			}
			List edgeCollectionRestriction = shortestPathOptions.getEdgeCollectionRestriction();
			appendEdgeCollectionsOrGraph(graphName, bindVars, sb, edgeCollectionRestriction);

			final String weight = shortestPathOptions.getWeight();
			if (weight != null) {
				sb.append(" OPTIONS {weightAttribute: @attribute, defaultWeight: @default} ");
				sb.append(
					" RETURN { v: v, e: e, d: IS_NULL(e) ? 0 : (IS_NUMBER(e[@attribute]) ? e[@attribute] : @default)}) ");
				bindVars.put("attribute", weight);
				final Long defaultWeight = shortestPathOptions.getDefaultWeight();
				bindVars.put("default", defaultWeight != null ? defaultWeight : 1);
			} else {
				sb.append(" RETURN {v: v, e: e, d: IS_NULL(e) ? 0 : 1}) ");
			}
		}
		sb.append("FILTER LENGTH(p) > 0 ");
		if (shortestPathOptions.getIncludeData() != null && !shortestPathOptions.getIncludeData().booleanValue()) {
			sb.append(
				"RETURN { vertices: p[*].v._id, edges: p[* FILTER CURRENT.e != null].e._id, distance: SUM(p[*].d)}");
		} else {
			sb.append("RETURN { vertices: p[*].v, edges: p[* FILTER CURRENT.e != null].e, distance: SUM(p[*].d)}");
		}

		final String query = sb.toString();
		return query;
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy