summaryrefslogtreecommitdiff
path: root/src/library/scala/dbc/result/Relation.scala
blob: 006b6dbf07a3b67756b0b6ccd612b7b1630c5e99 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
/*                     __                                               *\
**     ________ ___   / /  ___     Scala API                            **
**    / __/ __// _ | / /  / _ |    (c) 2003-2005, LAMP/EPFL             **
**  __\ \/ /__/ __ |/ /__/ __ |                                         **
** /____/\___/_/ |_/____/_/ | |                                         **
**                          |/                                          **
\*                                                                      */

package scala.dbc.result;

/** An ISO-9075:2003 (SQL) table. This is equivalent to a relation in the
 * relational model. */
abstract class Relation extends Object with Iterable[Tuple] {

  /** The statement that generated this relation. */
  def statement: scala.dbc.statement.Relation;

  /** A JDBC result containing this relation. */
  protected def sqlResult: java.sql.ResultSet;

  /** A JDBC metadata object attached to the relation. */
  protected def sqlMetadata: java.sql.ResultSetMetaData = sqlResult.getMetaData();

  /** Metadata about all fields in a tuple of the relation. */
  def metadata: List[FieldMetadata] =
    for (val count <- List.range(1, sqlMetadata.getColumnCount()+1)) yield
      new FieldMetadata {
	val name: String = sqlMetadata.getColumnName(count);
	val index: Int = count;
	val datatype: DataType = dbc.datatype.Factory.create(sqlMetadata,count);
	val catalog: String = sqlMetadata.getCatalogName(count);
	val schema: String = sqlMetadata.getSchemaName(count);
	val table: String = sqlMetadata.getTableName(count);
      }

  /** Metadata about the field at the given index. If there is no such
   * field <code>None</code> is returned instead. */
  def metadataFor (index:Int): Option[FieldMetadata] =
    try {Some(metadata(index))} catch {case e => None}

  /** Metadata about the field with the given column name. If there is no
   * such field, <code>None</code> is returned instead. */
  def metadataFor (name:String): Option[FieldMetadata] =
    metadata.find(f=>(f.name==name));

  /** An iterator on the tuples of the relation.
   * <h3>Caution</h3> A Relation only has one single iterator, due to limitations
   * in DBMS. This means that if this method is called multiple times, all returned
   * iterators will share the same state. */
  def elements: Iterator[Tuple] = new Iterator[Tuple] {
    protected val result: java.sql.ResultSet = Relation.this.sqlResult;
    def hasNext: Boolean = !(result.isLast());
    def next: Tuple = {
      if (result.next()) {
	new Tuple {
	  val me = this;
	  val originatingRelation = Relation.this;
	  val fields: List[Field] = for (val fieldMetadata <- metadata) yield
	    new Field {
	      val metadata = fieldMetadata;
	      val content = dbc.value.Factory.create(result,metadata.index,metadata.datatype);
	      val originatingTuple = me;
	    }
	}
      } else error("next on empty iterator")
    }
  }
}