public static Node build(final List<JoinInfo> joins) {
    Node root = null;

    for (final JoinInfo join : joins) {
      if (root == null) {
        root = new Leaf(join.getLeftSource());
      }

      if (root.containsSource(join.getRightSource()) && root.containsSource(join.getLeftSource())) {
        throw new KsqlException("Cannot perform circular join - both " + join.getRightSource()
            + " and " + join.getLeftJoinExpression()
            + " are already included in the current join tree: " + root.debugString(0));
      } else if (root.containsSource(join.getLeftSource())) {
        root = new Join(root, new Leaf(join.getRightSource()), join);
      } else if (root.containsSource(join.getRightSource())) {
        root = new Join(root, new Leaf(join.getLeftSource()), join.flip());
      } else {
        throw new KsqlException(
            "Cannot build JOIN tree; neither source in the join is the FROM source or included "
                + "in a previous JOIN: " + join + ". The current join tree is "
                + root.debugString(0)
        );
      }
    }

    return root;
  }
@Test
  public void shouldComputeEmptyEquivalenceSetForOuterJoins() {
    // Given:
    when(j1.getLeftSource()).thenReturn(a);
    when(j1.getRightSource()).thenReturn(b);

    when(j1.getType()).thenReturn(JoinType.OUTER);

    final List<JoinInfo> joins = ImmutableList.of(j1);

    // When:
    final Node root = JoinTree.build(joins);

    // Then:
    assertThat(root.joinEquivalenceSet(), is(empty()));
  }