src/jdk.incubator.adba/share/classes/jdk/incubator/sql2/Result.java
author lancea
Wed, 20 Jun 2018 15:38:40 -0400
branchJDK-8188051-branch
changeset 56797 fb523d4d9185
parent 56397 729f80d0cf31
child 56824 62e92191354d
permissions -rw-r--r--
JDK-8188051-branch updates

/*
 * Copyright (c)  2018, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */
package jdk.incubator.sql2;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Spliterator;
import java.util.function.Consumer;

/**
 *
 */
public interface Result {

  /**
   * A {@link Result} that is just a number of rows modified, a {@link Long}.
   *
   * Note: It is certainly true that this is not needed; {@link Long} could be
   * used instead. Seems like there might be a documentational advantage to
   * having this type. If you don't like it, just mentally replace it with
   * {@link Long} everywhere it appears.
   */
  public static interface RowCount extends Result {

    /**
     *
     * @return
     */
    public long getCount();
  }

  /**
   * A mutable handle to one value of an ordered sequence of columns of a row or
   * of out parameters. Columns have a 1-based index and optionally an
   * identifier. Identifiers are not guaranteed to be unique. Only {@code clone}
   * and {@code slice} create new instances. All other methods return this
   * instance (modifying it if necessary) including {@code forEach},
   * {@code next}, and {@code iterator}.
   */
  public interface Column extends Result, Iterable<Column>, Iterator<Column>, Cloneable {

    /**
     * Return the value of this column as an instance of the given type.
     *
     * @param <T>
     * @param type
     * @return the value of this {@link Column}
     */
    public <T> T get(Class<T> type);

    /**
     * Return the value of this {@link Column} as an instance of the default
     * Java type for this column.
     *
     * @param <T>
     * @return the value of this {@link Column}
     */
    public default <T> T get() {
      return get(javaType());
    }

    /**
     * Return the identifier of this {@link Column}. May be null.
     *
     * @return the identifier of this {@link Column}. May be null
     */
    public String identifier();

    /**
     * Return the 1-based index of this {@link Column}. The returned value is
     * relative to the slice if this {@link Column} is the result of a call to
     * {@code slice()}. {@code
     * col.slice(n).index() == 1}.
     *
     * @return the index of this {@link Column}
     */
    public int index();

    /**
     * Return the 1-based index of this {@link Column} relative to the original
     * sequence of values.
     * {@code col.absoluteIndex() == col.slice(n).absoluteIndex()}.
     *
     * @return the absolute 1-based index of this {@link Column}
     */
    public int absoluteIndex();

    /**
     * Return the SQL type of the value of this {@link Column}.
     *
     * @return the SQL type of this value
     */
    public SqlType sqlType();

    /**
     * Return the Java type that best represents the value of this
     * {@link Column}.
     *
     * @param <T>
     * @return a {@link Class} that best represents the value of this
     * {@link Column}
     */
    public <T>Class<T> javaType();

    /**
     * The length of the current value if defined.
     *
     * @return
     * @throws UnsupportedOperationException if the length of the current value
     * is undefined
     */
    public long length();

    /**
     * Return the number of remaining values accessible by this {@link Column}
     * excluding the current value. This is the number of times {@code next()}
     * can be called before {@code hasNext()} returns false.
     *
     * @return the number of values remaining
     */
    public int numberOfValuesRemaining();

    /**
     * Modify this {@link Column} to point to a value identified by id.
     *
     * @apiNote The value specified for {@code id} represents the name of a
     * column or parameter marker for the underlying data source and is
     * implementation specific. This may be a simple SQL identifier, a quoted
     * identifier, or any other type of identifier supported by the data source.
     * <p>
     * Consult your implementation&#39;s documentation for additional
     * information.
     *
     * @param id an identifier. Not null
     * @return this {@link Column}
     * @throws NoSuchElementException if id does not identify exactly one value
     */
    public Column at(String id);

    /**
     * Modify this {@link Column} to point to the value at {@code index}. The
     * first value is at index 1. Negative numbers count back from the last
     * value. The last value is at index -1.
     *
     * @param index a new index
     * @return this {@link Column}
     * @throws NoSuchElementException if {@code index > length} or
     * {@code index < -length}
     */
    public Column at(int index);

    /**
     * Modify this {@link Column} to point to the value at the current index +
     * {@code offset}. If {@code offset} is 0 this is a noop. If {@code offset}
     * is negative the new index is less than the current index. If the new
     * index would be less than 1 or greater than length this {@link Column} is
     * not modified and {@link IllegalArgumentException} is thrown.
     *
     * @param offset an increment to the current index
     * @return this {@link Column}
     * @throws NoSuchElementException if the new index would be less than 1 or
     * greater than {@code length}
     */
    public default Column next(int offset) {
      int newIndex = index() + offset;
      if (offset > numberOfValuesRemaining() || newIndex < 1) {
        throw new NoSuchElementException();
      }
      return at(newIndex);
    }

    /**
     * Return a new {@link Column} that is a handle to a subsequence of the
     * sequence of values referenced by this {@link Column}. The subsequence
     * consists of {@code numValues} number of values. If {@code numValues} is
     * positive the values are the value of this column and its successors. If
     * {@code numValues} is negative the values are the predecessors of this
     * column not including this {@link Column}. The order of the values of the
     * new {@link Column} is the same as the order of the values of this
     * {@link Column}. The returned {@link Column} points to the first value of
     * the slice. This {@link Column} is not modified.
     *
     * @param numValues the number of columns to include in the slice
     * @return a new {@link Column}.
     * @throws NoSuchElementException if the current index plus
     * {@code numValues} is greater than the number of values of this
     * {@link Column} or less than 1
     */
    public Column slice(int numValues);

    /**
     * Return a new {@link Column} that is a duplicate of this {@link Column}.
     * This {@link Column} is not modified.
     *
     * @return a new {@link Column}
     */
    public Column clone();

    /**
     * Modify this {@link Column} to point to the next value in the sequence.
     *
     * @return this {@link Column}
     * @throws NoSuchElementException if the new index would be greater than
     * {@code length}
     */
    @Override
    public default Column next() {
      return next(1);
    }

    @Override
    public default boolean hasNext() {
      return numberOfValuesRemaining() > 0;
    }

    @Override
    public default void forEach(Consumer<? super Column> action) {
      do {
        action.accept(this);
      } while (hasNext());
    }

    @Override
    public default Column iterator() {
      return this;
    }

    /**
     * TODO This almost certainly works correctly but it doesn't integrate well
     * with the other access patterns. A better approach would be a Spliterator
     * that overrides trySplit and creates new slices for each batch.
     *
     * There is a fundamental problem with mixing Spliterator with the other
     * access patterns. The other patterns assume navigation from one column to
     * an arbitrary other column. Spliterator.trySplit can divide the column
     * sequence in arbitrary places invalidating the assumption about column
     * navigation.
     *
     * @return a {@link java.util.Spliterator}
     */
    @Override
    public default Spliterator<Column> spliterator() {
      List list = new ArrayList<>(numberOfValuesRemaining());
      this.clone().forEach(c -> list.add(c.slice(1)));
      return java.util.Spliterators.spliterator(list.toArray(), numberOfValuesRemaining());
    }
  }

  /**
   * Used by {@link OutOperation} to expose the out parameters of a stored
   * procedure call.
   *
   * This exists to allow for future additions.
   */
  public interface OutColumn extends Column {

  }

  /**
   * Used by {@link RowOperation} to expose each row of a row sequence.
   */
  public static interface RowColumn extends Column {

    /**
     * The count of rows in the row sequence preceeding this {@link RowColumn}.
     * For the first row in the row sequence the {@code rowNumber} is 0.
     *
     * @return the count of rows in the row sequence preceeding this
     * {@link RowColumn}
     * @throws IllegalStateException if the call that was passed this
     * {@link Result} has ended
     */
    public long rowNumber();

    /**
     * Terminate processing of the rows in this {@link RowOperation}. No further
     * rows in the row sequence will be processed. All subsequent rows, if any,
     * will be ignored. Any rows already fetched will not be processed. Any rows
     * not yet fetched may or may not be fetched. If fetched they will not be
     * processed. The RowOperation will be completed normally, as though the
     * current row were the last row of the row sequence.
     *
     * @throws IllegalStateException if the call that was passed this
     * {@link RowColumn} has ended
     */
    public void cancel();

  }

}