Implemented using typeclasses.
Implementation:
- Define the problem with types :
Encoder[A]&Decoder[A].Encodertakes anA, and produces anAttributeValue.Decoderdoes 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
EncoderandDecoderfor anA(apply[A](implicit d: Decoder[A]) = d) - to create a
Decoderfrom 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 containsKeyLikethings, and it returns an anonymousTableMapper[B] - takes a
Generic(shapeless) so we can get the type of theReprof the type we're working with (will be an HList) - takes a
Zipperso we can zip with the names from the keylikes- I suppose labelledgeneric wasn't used as that's too much convention?
- Anonymous
TableMappersprimaryKey: 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 fromGenerica.zip(entityGen.to(b))and foldLeft, adding them all to a map[string, attributevalue]decode: do the opposite ofencode- TODO: checkout
PolyandCase.Auxand why we need so many cases for Poly.
- TODO: checkout
- add a method
Testing
- Done with property based testing
- Using scalacheck for Arbitrary generators
DisciplineforLaws- 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