in sql-gremlin/src/main/java/org/twilmes/sql/gremlin/adapter/converter/ast/nodes/select/GremlinSqlSelectMulti.java [91:232]
public GraphTraversal<?, ?> generateTraversal() throws SQLException {
final JoinType joinType = sqlJoin.getJoinType();
final JoinConditionType conditionType = sqlJoin.getConditionType();
final GremlinSqlBasicCall left =
GremlinSqlFactory.createNodeCheckType(sqlJoin.getLeft(), GremlinSqlBasicCall.class);
final GremlinSqlBasicCall right =
GremlinSqlFactory.createNodeCheckType(sqlJoin.getRight(), GremlinSqlBasicCall.class);
final GremlinSqlJoinComparison gremlinSqlJoinComparison =
GremlinSqlFactory.createJoinEquality(sqlJoin.getCondition());
if (!joinType.name().equals(JoinType.INNER.name())) {
throw SqlGremlinError.createNotSupported(SqlGremlinError.INNER_JOIN_ONLY);
}
if (!conditionType.equals(JoinConditionType.ON)) {
throw SqlGremlinError.createNotSupported(SqlGremlinError.JOIN_ON_ONLY);
}
if ((left.getGremlinSqlNodes().size() != 2) || (right.getGremlinSqlNodes().size() != 2)) {
throw SqlGremlinError.create(SqlGremlinError.LEFT_RIGHT_CONDITION_OPERANDS);
}
if (!(left.getGremlinSqlOperator() instanceof GremlinSqlAsOperator) ||
!(right.getGremlinSqlOperator() instanceof GremlinSqlAsOperator)) {
throw SqlGremlinError.create(SqlGremlinError.LEFT_RIGHT_AS_OPERATOR);
}
final GremlinSqlAsOperator leftAsOperator = (GremlinSqlAsOperator) left.getGremlinSqlOperator();
final String leftTableName = leftAsOperator.getActual();
final String leftTableRename = leftAsOperator.getRename();
sqlMetadata.addRenamedTable(leftTableName, leftTableRename);
final String leftColumn = gremlinSqlJoinComparison.getColumn(leftTableRename);
final GremlinSqlAsOperator rightAsOperator = (GremlinSqlAsOperator) right.getGremlinSqlOperator();
final String rightTableName = rightAsOperator.getActual();
final String rightTableRename = rightAsOperator.getRename();
sqlMetadata.addRenamedTable(rightTableName, rightTableRename);
final String rightColumn = gremlinSqlJoinComparison.getColumn(rightTableRename);
if (!sqlMetadata.getIsColumnEdge(leftTableRename, leftColumn) ||
!sqlMetadata.getIsColumnEdge(rightTableRename, rightColumn)) {
throw SqlGremlinError.create(SqlGremlinError.JOIN_EDGELESS_VERTICES);
}
final String edgeLabelRight =
rightColumn.replaceAll(GremlinTableBase.IN_ID, "").replaceAll(GremlinTableBase.OUT_ID, "");
final String edgeLabelLeft =
leftColumn.replaceAll(GremlinTableBase.IN_ID, "").replaceAll(GremlinTableBase.OUT_ID, "");
if (!edgeLabelRight.equals(edgeLabelLeft)) {
throw SqlGremlinError.create(SqlGremlinError.CANNOT_JOIN_DIFFERENT_EDGES, edgeLabelLeft, edgeLabelRight);
}
if (rightColumn.endsWith(GremlinTableBase.IN_ID)) {
if (!leftColumn.endsWith(GremlinTableBase.OUT_ID)) {
throw SqlGremlinError.create(SqlGremlinError.JOIN_EDGELESS_VERTICES);
}
} else if (rightColumn.endsWith(GremlinTableBase.OUT_ID)) {
if (!leftColumn.endsWith(GremlinTableBase.IN_ID)) {
throw SqlGremlinError.create(SqlGremlinError.JOIN_EDGELESS_VERTICES);
}
} else {
throw SqlGremlinError.create(SqlGremlinError.JOIN_EDGELESS_VERTICES);
}
final String edgeLabel = sqlMetadata.getColumnEdgeLabel(leftColumn);
// Cases to consider:
// 1. rightLabel == leftLabel
// 2. rightLabel != leftLabel, rightLabel->leftLabel
// 3. rightLabel != leftLabel, leftLabel->rightLabel
// 4. rightLabel != leftLabel, rightLabel->leftLabel, leftLabel->rightLabel
// Case 1 & 4 are logically equivalent.
// Determine which is in and which is out.
final boolean leftInRightOut = sqlMetadata.isLeftInRightOut(leftColumn, rightColumn);
final boolean rightInLeftOut = sqlMetadata.isRightInLeftOut(leftColumn, rightColumn);
final String inVLabel;
final String outVLabel;
final String inVRename;
final String outVRename;
if (leftInRightOut && rightInLeftOut &&
(leftTableName.replace(GremlinTableBase.IN_ID, "").replace(GremlinTableBase.OUT_ID, "")
.equals(rightTableName.replace(GremlinTableBase.IN_ID, "")
.replace(GremlinTableBase.OUT_ID, "")))) {
// Vertices of same label connected by an edge.
// Doesn't matter how we assign these, but renames need to be different.
inVLabel = leftTableName;
outVLabel = leftTableName;
inVRename = leftTableRename;
outVRename = rightTableRename;
} else if (leftInRightOut) {
// Left vertex is in, right vertex is out
inVLabel = leftTableName;
outVLabel = rightTableName;
inVRename = leftTableRename;
outVRename = rightTableRename;
} else if (rightInLeftOut) {
// Right vertex is in, left vertex is out
inVLabel = rightTableName;
outVLabel = leftTableName;
inVRename = rightTableRename;
outVRename = leftTableRename;
} else {
inVLabel = "";
outVLabel = "";
inVRename = "";
outVRename = "";
}
final List<GremlinSqlNode> gremlinSqlNodesIn = new ArrayList<>();
final List<GremlinSqlNode> gremlinSqlNodesOut = new ArrayList<>();
for (final SqlNode sqlNode : sqlSelect.getSelectList().getList()) {
if (GremlinSqlFactory.isTable(sqlNode, inVRename)) {
gremlinSqlNodesIn.add(GremlinSqlFactory.createNode(sqlNode));
} else if (GremlinSqlFactory.isTable(sqlNode, outVRename)) {
gremlinSqlNodesOut.add(GremlinSqlFactory.createNode(sqlNode));
}
}
GraphTraversal<?, ?> graphTraversal = null;
try {
graphTraversal = g.E().hasLabel(edgeLabel)
.where(__.inV().hasLabel(inVLabel))
.where(__.outV().hasLabel(outVLabel));
applyWhere(graphTraversal);
applyGroupBy(graphTraversal, edgeLabel, inVRename, outVRename);
applySelectValues(graphTraversal);
applyOrderBy(graphTraversal, edgeLabel, inVRename, outVRename);
applyHaving(graphTraversal);
SqlTraversalEngine.applyAggregateFold(sqlMetadata, graphTraversal);
graphTraversal.project(inVRename, outVRename);
sqlMetadata.setIsDoneFilters(true);
applyColumnRetrieval(graphTraversal, inVRename, gremlinSqlNodesIn, StepDirection.In);
applyColumnRetrieval(graphTraversal, outVRename, gremlinSqlNodesOut, StepDirection.Out);
return graphTraversal;
} catch (final SQLException e) {
if (graphTraversal != null) {
try {
graphTraversal.close();
} catch (final Exception ignored) {
}
}
throw e;
}
}