Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
supporting typesafe queries using filter. also allowing lazy sql quer…
…ies.
- Loading branch information
1 parent
4e064a2
commit 7e51e7a
Showing
6 changed files
with
187 additions
and
15 deletions.
There are no files selected for viewing
62 changes: 62 additions & 0 deletions
62
src/main/scala/br/com/caelum/hibernatequerydsl/ActiveCollection.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
package br.com.caelum.hibernatequerydsl | ||
|
||
import scala.collection.JavaConversions._ | ||
import net.sf.cglib.proxy.Enhancer | ||
import org.hibernate.criterion.{Criterion, Restrictions} | ||
|
||
trait Cond { | ||
def crit:Criterion | ||
def filter(obj:Object):Boolean | ||
} | ||
class EqCond(field:String, value:Object) extends Cond { | ||
def crit = Restrictions.eq(field, value) | ||
def filter(obj:Object) = (true) | ||
} | ||
// TODO extract list interface so we dont need the cases, | ||
// can simply return the list and thats it | ||
class ActiveCollection[T](var elements:List[T], query:PimpedCriteria[T,T])(implicit entityType:Manifest[T]) { | ||
|
||
private type Myself = ActiveCollection[T] | ||
private def loaded = Option(elements).isDefined | ||
|
||
private implicit def listToAC(l:List[T]):Myself = new Myself(elements, null) | ||
private implicit def queryToAC(q:PimpedCriteria[T,T]):Myself = new Myself(null, q) | ||
|
||
def grabThem():List[T] = { | ||
if(!loaded) { | ||
elements = query.asList[T].toList | ||
} | ||
elements | ||
} | ||
|
||
def take(k: Int):Myself = { | ||
loaded match { | ||
case (false) => query.using(_.setMaxResults(k)) | ||
case (true) => new Myself(elements.take(k), null) | ||
} | ||
} | ||
|
||
def filter(f: (T) => Cond):Myself = { | ||
loaded match { | ||
case (false) => query.and(applyRule(f).crit) | ||
case (true) => elements.filter(toB(f)) | ||
} | ||
} | ||
|
||
def find(f: (T) => Cond): Option[T] = { | ||
loaded match { | ||
case (false) => query.and(applyRule(f).crit).using(_.setMaxResults(1)).headOption | ||
case (true) => elements.find(toB(f)) | ||
} | ||
} | ||
def toB(f:(T) => Cond):((T) => Boolean) = { | ||
throw new RuntimeException("going through the list") | ||
} | ||
|
||
def applyRule(f: (T) => Cond):Cond = { | ||
val handler = new ComparisonCallback | ||
val proxy = Enhancer.create(entityType.erasure, handler).asInstanceOf[T] | ||
f(proxy) | ||
} | ||
|
||
} |
26 changes: 26 additions & 0 deletions
26
src/main/scala/br/com/caelum/hibernatequerydsl/ComparisonCallback.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package br.com.caelum.hibernatequerydsl | ||
|
||
import net.sf.cglib.proxy.InvocationHandler | ||
class ComparisonCallback extends InvocationHandler { | ||
|
||
def invoke(proxy:AnyRef,method:java.lang.reflect.Method,args:Array[AnyRef]) = { | ||
if(method.getReturnType!=classOf[String]) { | ||
throw new RuntimeException("We are not supporting anything but strings right now, sorry") | ||
} | ||
// TODO to implement others, we will need to use the cutest ThreadLocal ever | ||
// we can also use it with a SINGLE proxy per class by doing a list.an[User].getName | ||
|
||
// TODO switch to case or something else | ||
// TODO duplicated code, extract | ||
var _invoked = method.getName | ||
if(_invoked.startsWith("get")) { | ||
_invoked = _invoked.substring(3, _invoked.length) | ||
} else if(_invoked.startsWith("is")) { | ||
_invoked = _invoked.substring(2, _invoked.length) | ||
} | ||
val rest = if (_invoked.length() > 0) _invoked.substring(1,_invoked.length()) else "" | ||
_invoked = Character.toLowerCase(_invoked.charAt(0)) + rest | ||
_invoked | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
80 changes: 80 additions & 0 deletions
80
src/test/scala/br/com/caelum/hibernatequerydsl/ActiveCollectionAcceptanceTest.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
package br.com.caelum.hibernatequerydsl | ||
|
||
import org.hibernate.Session | ||
import org.hibernate.cfg.Configuration | ||
import org.junit.{Test, After, Before} | ||
import org.junit.Assert._ | ||
import br.com.caelum.hibernatequerydsl.PimpedSession._ | ||
import br.com.caelum.hibernatequerydsl.TypeSafe._ | ||
|
||
class ActiveCollectionAcceptanceTest { | ||
|
||
private var session:Session = _ | ||
|
||
@Before | ||
def setUp { | ||
val cfg = new Configuration(); | ||
session = cfg.configure().buildSessionFactory().openSession(); | ||
session.beginTransaction(); | ||
} | ||
|
||
@After | ||
def tearDown{ | ||
if (session != null && session.getTransaction().isActive()) { | ||
session.getTransaction().rollback(); | ||
} | ||
} | ||
|
||
private def withUser(name:String=null,age:Int=0, street:String=null) = { | ||
val user = new User | ||
user setName name | ||
user setAge age | ||
session.save(user) | ||
if(street!=null){ | ||
val address = new Address | ||
address setStreet street | ||
address setUser user | ||
session.save(address) | ||
} | ||
this | ||
} | ||
|
||
private def and(name:String=null,age:Int=0, street:String=null) = { | ||
withUser(name, age, street) | ||
} | ||
|
||
def ar = new ActiveCollection[User](null, session.from[User]) | ||
|
||
@Test | ||
def shouldSupportTake { | ||
withUser("guilherme").and("alberto") | ||
val users = ar.take(1) | ||
assertEquals("guilherme", users(0).getName) | ||
assertEquals(1, users.size) | ||
} | ||
|
||
@Test | ||
def shouldSupportParametersCombinedWithTake { | ||
withUser("guilherme").and("alberto") | ||
val users = ar.filter(_.getName equal "alberto").take(1) | ||
assertEquals("alberto", users(0).getName) | ||
assertEquals(1, users.size) | ||
} | ||
|
||
@Test | ||
def shouldSupportGrabbingAll { | ||
withUser("guilherme").and("alberto") | ||
val users:List[User] = ar | ||
assertEquals(2, users.size) | ||
} | ||
|
||
@Test | ||
def shouldSupportRegrabbing { | ||
withUser("guilherme").and("alberto") | ||
val users = ar | ||
assertEquals(2, users.size) | ||
assertEquals(classOf[ActiveCollection[User]], ar.getClass) | ||
assertEquals(1, users.take(1).size) | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters