/finagle-mysql-shapes

Finagle MySQL type classes for row and column decoding

Primary LanguageScalaApache License 2.0Apache-2.0

finagle-mysql-shapes

Build Status

This library adds support to Twitter's Finagle MySQL client for boilerplate-free transformation of rows into case classes.

Install

To use this library configure your sbt project with the following line:

libraryDependencies += "com.linecorp" %% "finagle-mysql-shapes" % "0.1.0"

Documentation

Examples

This project uses shapeless's generic representation of case classes for automatic derivation of RowDecoder[A] instances.

Given a client, e.g.:

import com.twitter.finagle.Mysql

val client = Mysql.client.withCredentials(...)

and the following relational schema:

CREATE TABLE users
  (
    firstName VARCHAR(255), NOT NULL
    lastName VARCHAR(255) NOT NULL,
    address VARCHAR(255),
    fruit ENUM('Melon', 'Mango') NOT NULL,
    create_ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP
  ) engine=innodb DEFAULT charset=utf8

Marshalling rows into case classes:

import com.linecorp.finagle.mysql.generic._

case class User(firstName: String, lastName: String, address: Option[String])

val result = client.select("SELECT * FROM users WHERE id = 1") {
  row => RowDecoder[User].from(row)
}

For a slightly nicer syntax:

import com.linecorp.finagle.mysql.syntax._

val result = client.select("SELECT * FROM users WHERE id = 1") {
  row => row.as[User]
}

A streamlined way of unpacking rows into tuples:

import com.linecorp.finagle.mysql.generic.tuples._

val result = client.select("SELECT * FROM users WHERE id = 1") { row =>
  row.as[(String, String)]
}

Decoding ENUM columns into sealed trait hierarchies:

import com.linecorp.finagle.mysql.generic._

sealed trait Fruit
case object Melon extends Fruit
case object Mango extends Fruit

val result = client.select("SELECT fruit FROM users WHERE id = 4") { row =>
  row.get[Fruit](column = "fruit")
}

You can also provide your own instance of RowDecoder[A]:

import com.linecorp.finagle.mysql.RowDecoder

implicit val decoder: RowDecoder[User] = RowDecoder.instance { row =>
  for {
    f <- row.get[String]("firstName")
    l <- row.get[String]("lastName")
  } yield User(f, l)
}

See the RowSpec integration test suite for more examples.

JSON

To parse JSON columns this library provides integration with circe.

import com.linecorp.finagle.mysql.circe._

You can use other JSON libraries by providing an instance of JsonDecoder[A]:

trait JsonDecoder[A] {
  def decode(json: String): Try[A]
}

How to contribute

See CONTRIBUTING.md

LICENSE

Copyright 2019 LINE Corporation

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.

See LICENSE for more detail.