Implemented using typeclasses.
Implementation:
- Define the problem with types :
Encoder[A]
&Decoder[A]
.Encoder
takes anA
, and produces anAttributeValue
.Decoder
does the opposite.KeyLike[A]
coproduct for things that can be keys.NamedKeyLike[A]
a key that has a name, an encoder, and a decoder.PrimaryKey
- I suppose it's the Primary Key of the tableRangeKey
... a range key?Key
- just a regular keyMapKey[A]
- helper for working with maps with a string keyMap[String, A]
to aMap[String, AttributeValue]
TableMapper[A]
- key definition used by a
Table[A]
- defines encode & decode for
A
- key definition used by a
Table[A]
where we wire our code to the AWS lib*
: ATableMapper[A]
- Write some boilerplate
- to summon instances of an
Encoder
andDecoder
for anA
(apply[A](implicit d: Decoder[A]) = d
) - to create a
Decoder
from aAttributeValue => A
(do the same for encoder) - implicits for things that we care about (string, bool, &c)
- for higher kinded types in the std lib (Option, CBF, Map)
- for coproducts (either, not shapeless'
:+:
: is that thing called a CList? I don't remember.) - for cats' monad type
- Write some slightly more involved boilerplate
- dynamodb package object integrates an HList of KeyLikes with our implicits:
- add a method
as[B]
to an Hlist that only containsKeyLike
things, and it returns an anonymousTableMapper[B]
- takes a
Generic
(shapeless) so we can get the type of theRepr
of the type we're working with (will be an HList) - takes a
Zipper
so we can zip with the names from the keylikes- I suppose labelledgeneric wasn't used as that's too much convention?
- Anonymous
TableMappers
primaryKey
: Find the first PK in our list, it is the primary key.- set up our PK encoder to delegate to the instance resolved by the PK
- is there no witness type that can make sure there's only one PK?
rangeKey
: do the same procedure as PK for a range key.encode
: zip our hlist of keylikes (a
) with the Hlist of our values fromGeneric
a.zip(entityGen.to(b))
and foldLeft, adding them all to a map[string, attributevalue]decode
: do the opposite ofencode
- TODO: checkout
Poly
andCase.Aux
and why we need so many cases for Poly.
- TODO: checkout
- add a method
Testing
- Done with property based testing
- Using scalacheck for Arbitrary generators
Discipline
forLaws
- looks like an alternative to the Scalacheck builtin test runner... not sure what the benefits are.- nice reduction of boilerplate, though I suppose the effect is the same as other libraries, you still have to have the
checkAll("Codec[Double]", CodecTests[Double].codec)
boilerplate, and it's more to grok than just adef
- has a pretty cool name
- nice reduction of boilerplate, though I suppose the effect is the same as other libraries, you still have to have the
- lots of different stuff used, lots to grok
- org.typelevel.discipline.scalatest.Discipline (???) this is where the Laws thing comes in.
- cats for some laws integration (wildcard import so hard to tell, some implicits somewhere I imagine)... looks like for Equality also.
- scalacheck arbitrary