org.squeryl.internals.ResultSetMapper.scala Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of squeryl_2.12.0-RC1 Show documentation
Show all versions of squeryl_2.12.0-RC1 Show documentation
A Scala ORM and DSL for talking with Databases using minimum verbosity and maximum type safety
The newest version!
/*******************************************************************************
* Copyright 2010 Maxime Lévesque
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
***************************************************************************** */
package org.squeryl.internals
import java.sql.ResultSet
import collection.mutable.ArrayBuffer
import org.squeryl.dsl.ast.SelectElement
trait ResultSetUtils {
def dumpRow(rs:ResultSet) = {
val md = rs.getMetaData
(for(i <- 1 to md.getColumnCount)
yield "#" + i + "->"+rs.getObject(i)+":"+_simpleClassName(md.getColumnClassName(i)))
.mkString("ResultSetRow:[",",","]")
}
private def _simpleClassName(className: String) = {
val idx = className.lastIndexOf(".")
if(idx < 0)
className
else
className.substring(idx + 1, className.length)
}
def dumpRowValues(rs:ResultSet) = {
val md = rs.getMetaData
(for(i <- 1 to md.getColumnCount)
yield ""+rs.getObject(i)).mkString("[",",","]")
}
}
object ResultSetUtils extends ResultSetUtils
trait OutMapper[T] extends ResultSetUtils {
override def toString =
Utils.failSafeString(
"$OM(" + index + "," +
jdbcClass.getSimpleName + ")" +
(if(isActive) "*" else "")
)
var index: Int = -1
var isActive = false
def jdbcClass =
sample match {
case Some(x:AnyRef) => x.getClass
case x:AnyRef => x.getClass
}
def map(rs: ResultSet): T =
if(isActive)
try {
doMap(rs)
}
catch {
case e:Exception => throw new RuntimeException(
"Exception while mapping column with OutMapper:\n" + this +
"\nand resultSet :\n" + Utils.failSafeString(dumpRow(rs)),
e)
}
else
sample
def isNull(rs: ResultSet) =
rs.getObject(index) == null
def doMap(rs: ResultSet): T
def sample: T
def typeOfExpressionToString = sample.asInstanceOf[Object].getClass.getName
}
object NoOpOutMapper extends OutMapper[Any] {
def doMap(rs: ResultSet) = sample
def sample = throw new UnsupportedOperationException(" cannot use NoOpOutMapper")
override def typeOfExpressionToString = "NoOpOutMapper"
}
class ColumnToFieldMapper(val index: Int, val fieldMetaData: FieldMetaData, selectElement: SelectElement) {
if(index <= 0)
org.squeryl.internals.Utils.throwError("invalid Jdbc index " + index)
def map(obj: AnyRef, rs: ResultSet): Unit = {
if(selectElement.isActive) {
fieldMetaData.setFromResultSet(obj, rs, index)
}
}
override def toString =
"$(" + index + "->" + fieldMetaData + ")"
}
class ColumnToTupleMapper(val outMappers: Array[OutMapper[_]]) {
override def toString = outMappers.mkString("(",",",")")
def typeOfExpressionToString(idx: Int) = outMappers.apply(idx).typeOfExpressionToString
def activate(i: Int, jdbcIndex: Int) = {
val m = outMappers.apply(i)
m.isActive = true
m.index = jdbcIndex
}
def isActive(i: Int) = outMappers.apply(i).isActive
def isNull(i:Int, rs: ResultSet) = outMappers.apply(i).isNull(rs)
def mapToTuple[T](rs: ResultSet): T = {
val size = outMappers.size
val m = outMappers
val res = size match {
case 1 => (m(0).map(rs))
case 2 => (m(0).map(rs), m(1).map(rs))
case 3 => (m(0).map(rs), m(1).map(rs), m(2).map(rs))
case 4 => (m(0).map(rs), m(1).map(rs), m(2).map(rs), m(3).map(rs))
case 5 => (m(0).map(rs), m(1).map(rs), m(2).map(rs), m(3).map(rs), m(4).map(rs))
case 6 => (m(0).map(rs), m(1).map(rs), m(2).map(rs), m(3).map(rs), m(4).map(rs), m(5).map(rs))
case 7 => (m(0).map(rs), m(1).map(rs), m(2).map(rs), m(3).map(rs), m(4).map(rs), m(5).map(rs), m(6).map(rs))
case 8 => (m(0).map(rs), m(1).map(rs), m(2).map(rs), m(3).map(rs), m(4).map(rs), m(5).map(rs), m(6).map(rs), m(7).map(rs))
case 9 => (m(0).map(rs), m(1).map(rs), m(2).map(rs), m(3).map(rs), m(4).map(rs), m(5).map(rs), m(6).map(rs), m(7).map(rs), m(8).map(rs))
case 10 => (m(0).map(rs), m(1).map(rs), m(2).map(rs), m(3).map(rs), m(4).map(rs), m(5).map(rs), m(6).map(rs), m(7).map(rs), m(8).map(rs), m(9).map(rs))
case 11 => (m(0).map(rs), m(1).map(rs), m(2).map(rs), m(3).map(rs), m(4).map(rs), m(5).map(rs), m(6).map(rs), m(7).map(rs), m(8).map(rs), m(9).map(rs), m(10).map(rs))
case 12 => (m(0).map(rs), m(1).map(rs), m(2).map(rs), m(3).map(rs), m(4).map(rs), m(5).map(rs), m(6).map(rs), m(7).map(rs), m(8).map(rs), m(9).map(rs), m(10).map(rs), m(11).map(rs))
case 13 => (m(0).map(rs), m(1).map(rs), m(2).map(rs), m(3).map(rs), m(4).map(rs), m(5).map(rs), m(6).map(rs), m(7).map(rs), m(8).map(rs), m(9).map(rs), m(10).map(rs), m(11).map(rs), m(12).map(rs))
case 14 => (m(0).map(rs), m(1).map(rs), m(2).map(rs), m(3).map(rs), m(4).map(rs), m(5).map(rs), m(6).map(rs), m(7).map(rs), m(8).map(rs), m(9).map(rs), m(10).map(rs), m(11).map(rs), m(12).map(rs), m(13).map(rs))
case 15 => (m(0).map(rs), m(1).map(rs), m(2).map(rs), m(3).map(rs), m(4).map(rs), m(5).map(rs), m(6).map(rs), m(7).map(rs), m(8).map(rs), m(9).map(rs), m(10).map(rs), m(11).map(rs), m(12).map(rs), m(13).map(rs), m(14).map(rs))
case 16 => (m(0).map(rs), m(1).map(rs), m(2).map(rs), m(3).map(rs), m(4).map(rs), m(5).map(rs), m(6).map(rs), m(7).map(rs), m(8).map(rs), m(9).map(rs), m(10).map(rs), m(11).map(rs), m(12).map(rs), m(13).map(rs), m(14).map(rs), m(15).map(rs))
case 17 => (m(0).map(rs), m(1).map(rs), m(2).map(rs), m(3).map(rs), m(4).map(rs), m(5).map(rs), m(6).map(rs), m(7).map(rs), m(8).map(rs), m(9).map(rs), m(10).map(rs), m(11).map(rs), m(12).map(rs), m(13).map(rs), m(14).map(rs), m(15).map(rs), m(16).map(rs))
case 18 => (m(0).map(rs), m(1).map(rs), m(2).map(rs), m(3).map(rs), m(4).map(rs), m(5).map(rs), m(6).map(rs), m(7).map(rs), m(8).map(rs), m(9).map(rs), m(10).map(rs), m(11).map(rs), m(12).map(rs), m(13).map(rs), m(14).map(rs), m(15).map(rs), m(16).map(rs), m(17).map(rs))
case 19 => (m(0).map(rs), m(1).map(rs), m(2).map(rs), m(3).map(rs), m(4).map(rs), m(5).map(rs), m(6).map(rs), m(7).map(rs), m(8).map(rs), m(9).map(rs), m(10).map(rs), m(11).map(rs), m(12).map(rs), m(13).map(rs), m(14).map(rs), m(15).map(rs), m(16).map(rs), m(17).map(rs), m(18).map(rs))
case 20 => (m(0).map(rs), m(1).map(rs), m(2).map(rs), m(3).map(rs), m(4).map(rs), m(5).map(rs), m(6).map(rs), m(7).map(rs), m(8).map(rs), m(9).map(rs), m(10).map(rs), m(11).map(rs), m(12).map(rs), m(13).map(rs), m(14).map(rs), m(15).map(rs), m(16).map(rs), m(17).map(rs), m(18).map(rs), m(19).map(rs))
case 21 => (m(0).map(rs), m(1).map(rs), m(2).map(rs), m(3).map(rs), m(4).map(rs), m(5).map(rs), m(6).map(rs), m(7).map(rs), m(8).map(rs), m(9).map(rs), m(10).map(rs), m(11).map(rs), m(12).map(rs), m(13).map(rs), m(14).map(rs), m(15).map(rs), m(16).map(rs), m(17).map(rs), m(18).map(rs), m(19).map(rs), m(20).map(rs))
case 22 => (m(0).map(rs), m(1).map(rs), m(2).map(rs), m(3).map(rs), m(4).map(rs), m(5).map(rs), m(6).map(rs), m(7).map(rs), m(8).map(rs), m(9).map(rs), m(10).map(rs), m(11).map(rs), m(12).map(rs), m(13).map(rs), m(14).map(rs), m(15).map(rs), m(16).map(rs), m(17).map(rs), m(18).map(rs), m(19).map(rs), m(20).map(rs), m(21).map(rs))
case z:Any => org.squeryl.internals.Utils.throwError("tuples of size "+size+" and greater are not supported")
}
res.asInstanceOf[T]
}
}
class ResultSetMapper extends ResultSetUtils {
private val _yieldValuePushers = new ArrayBuffer[YieldValuePusher]
private val _fieldMapper = new ArrayBuffer[ColumnToFieldMapper]
var groupKeysMapper: Option[ColumnToTupleMapper] = None
var groupMeasuresMapper: Option[ColumnToTupleMapper] = None
// val createTrace = {
// new Exception().getStackTrace.map(s=>s.toString).mkString("\n")
// }
var isActive = false
override def toString =
'ResultSetMapper + ":" + Integer.toHexString(System.identityHashCode(this)) +
_fieldMapper.mkString("(",",",")") +
"-" + groupKeysMapper.getOrElse("") +
"-" + groupMeasuresMapper.getOrElse("") +
(if(isActive) "*" else "")
def addColumnMapper(cm: ColumnToFieldMapper) =
_fieldMapper.append(cm)
def addYieldValuePusher(yvp: YieldValuePusher) =
_yieldValuePushers.append(yvp)
def pushYieldedValues(resultSet: ResultSet):Unit = {
if(!isActive)
return
for(yvp <- _yieldValuePushers)
yvp.push(resultSet)
}
private lazy val _firstNonOption: Option[ColumnToFieldMapper] =
_fieldMapper.find(!_.fieldMetaData.isOption)
def isNoneInOuterJoin(rs: ResultSet): Boolean = {
//decide based on the nullity of the first non Option field :
if(_firstNonOption != None) {
return rs.getObject(_firstNonOption.get.index) == null
}
//if we get here all fields are optional, decide on the first Option that is not null :
for(c2fm <- _fieldMapper) {
assert(c2fm.fieldMetaData.isOption)
if(rs.getObject(c2fm.index) != null)
return false
}
//outMappers
for(col2TupleMapper <- List(groupKeysMapper, groupMeasuresMapper).filter(_ != None).map(_.get);
outMapper <- col2TupleMapper.outMappers) {
if(outMapper.isActive && rs.getObject(outMapper.index) != null)
return false
}
// if we get here we have matched on a row wit all nulls OR we haven't matched,
// this is an extreme corner case, we will return None, in reality we should
// sometimes return a Some with all fields None
true
}
def map(o: AnyRef, resultSet: ResultSet):Unit = {
if(!isActive)
return
try {
for(fm <- _fieldMapper)
fm.map(o, resultSet)
}
catch {
case e:Exception=> {
throw new RuntimeException("could not map row :\n" + dumpRow(resultSet) + "\n with mapper :\n" + this, e)
}
}
}
}
class YieldValuePusher(val index: Int, val selectElement: SelectElement, mapper: OutMapper[_]) {
mapper.index = index
mapper.isActive = true
def push(rs: ResultSet) = {
if(selectElement.isActive) {
val v = mapper.map(rs)
FieldReferenceLinker.pushYieldValue(v.asInstanceOf[AnyRef])
}
}
override def toString =
"$(" + index + "->&("+selectElement.writeToString+")" +
(if(mapper.isActive) "*" else "")
}