public GraphTraversal generateTraversal()

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;
        }
    }