Created
September 22, 2011 21:44
-
-
Save dt/1236140 to your computer and use it in GitHub Desktop.
Priming via types?
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
trait Finder[RecordType] { | |
def findAll(ids: Seq[Long]): Seq[RecordType] = Nil | |
def find(id: Long): Option[RecordType] = None | |
} | |
abstract class Bar { def id: Long } ; object Bar extends Finder[Bar] | |
abstract class Baz { def id: Long } ; object Baz extends Finder[Baz] | |
abstract class Foo { | |
def id: Long | |
def barId: Long // this could be here as a MongoForeignObjectId thanks to a Bar.FK trait too | |
def bazId: Long | |
// these can lead to N+1. kill 'em. | |
//def bar: Option[Bar] = Bar.find(barId) | |
//def baz: Option[Baz] = Baz.find(bazId) | |
}; object Foo extends Finder[Foo] | |
object BadExample { | |
// with the above impl of .bar, this would be N+1. bad. | |
// List[Foo]().map{ f => f.bar } | |
// List[Foo]().map{ f => f.baz } | |
} | |
class BarPrimed[T <: Foo](b: Option[Bar], foo: T) extends FooWrapper(foo) { | |
def bar = b | |
} | |
class BazPrimed[T <: Foo](b: Option[Baz], foo: T) extends FooWrapper(foo) { | |
def baz = b | |
} | |
class FooWrapper(foo: Foo) extends Foo { | |
def id = foo.id | |
def barId = foo.barId | |
def bazId = foo.bazId | |
} | |
object BadExample2 { | |
// with the above impl of .bar, this would be N+1. bad. | |
val ex1: Seq[Bar] = primeBars(List[Foo]()).flatMap{ f => f.bar } | |
val ex2: Seq[Baz] = primeBazs(List[Foo]()).flatMap{ f => f.baz } | |
val a = List[Foo]() | |
val b = primeBars(a).filter(_.bar.isDefined) | |
val c = primeBazs(b).filter(_.baz.isDefined) | |
val d = c.map(_.bar) | |
def primeBars[T <: Foo](fooList: Seq[T]): Seq[BarPrimed[T]] = { | |
val ids = Bar.findAll( fooList.map(_.barId) ).groupBy(_.id).mapValues(_.headOption) | |
fooList.map( foo => new BarPrimed(ids.get(foo.barId).getOrElse(None), foo) ) | |
} | |
def primeBazs[T <: Foo](fooList: Seq[T]): Seq[BazPrimed[T]] = { | |
val ids = Baz.findAll( fooList.map(_.bazId) ).groupBy(_.id).mapValues(_.headOption) | |
fooList.map( foo => new BazPrimed(ids.get(foo.bazId).getOrElse(None), foo) ) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment