Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upgrade to Cats 0.8.1 #79

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ lazy val testDependencies = Seq(
scalacOptions in Test ++= Seq("-Yrangepos")

lazy val baseSettings = Seq(
scalacOptions ++= compilerOptions,
scalacOptions in (Compile, console) := compilerOptions,
scalacOptions ++= compilerOptions,
scalacOptions in (Compile, console) := compilerOptions,
scalacOptions in (Compile, doc) ++= Seq(
"-doc-title", "roc",
"-doc-version", version.value,
Expand All @@ -59,7 +59,7 @@ lazy val allSettings = buildSettings ++ baseSettings ++ Defaults.itSettings

lazy val coreVersion = "0.0.5"

lazy val catsVersion = "0.6.0"
lazy val catsVersion = "0.8.1"

lazy val finagleVersion = "6.38.0"

Expand Down
43 changes: 21 additions & 22 deletions core/src/main/scala/roc/postgresql/ClientDispatcher.scala
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
package roc
package postgresql

import cats.data.Xor
import cats.std.all._
import cats.instances.all._
import cats.syntax.eq._
import com.twitter.finagle.dispatch.GenSerialClientDispatcher
import com.twitter.finagle.transport.Transport
Expand All @@ -26,14 +25,14 @@ private[roc] final class ClientDispatcher(trans: Transport[Packet, Packet],
private[roc] lazy val paramStatuses: Map[String, String] =
mutableParamStatuses.map(x => (x.parameter, x.value)).toMap

override def apply(req: Request): Future[Result] =
override def apply(req: Request): Future[Result] =
startupPhase.flatMap(_ => super.apply(req))

/** Performs the Startup phase of a Postgresql Connection.
*
* The startup phase is performed once per connection prior to any exchanges
* between the client and server. Failure to startup renders the service unsuable.
* The startup phase consists of two separate but sequential phases
* The startup phase consists of two separate but sequential phases
* 1. Authentication 2. Server Process setting run time parameters
* @see [[http://www.postgresql.org/docs/current/static/protocol-flow.html#AEN108589]]
*/
Expand All @@ -55,8 +54,8 @@ private[roc] final class ClientDispatcher(trans: Transport[Packet, Packet],
for {
packet <- trans.read()
message <- Message.decode(packet) match {
case Xor.Left(l) => Future.exception(l)
case Xor.Right(m) => Future.value(m)
case Left(l) => Future.exception(l)
case Right(m) => Future.value(m)
}
} yield message
}
Expand All @@ -73,7 +72,7 @@ private[roc] final class ClientDispatcher(trans: Transport[Packet, Packet],
for {
_ <- trans.write(encodePacket(query)).rescue(wrapWriteException)
signal = rep.become(readTransport(query, new Promise[Unit]))
} yield signal
} yield signal
}

private[this] def readTransport(req: Transmission, signal: Promise[Unit]): Future[Result] =
Expand All @@ -89,17 +88,17 @@ private[roc] final class ClientDispatcher(trans: Transport[Packet, Packet],
type Collection = (Descriptions, Rows, CommandCompleteString)
def go(xs: Descriptions, ys: Rows, ccStr: CommandCompleteString):
Future[Collection] = trans.read().flatMap(packet => Message.decode(packet) match {
case Xor.Right(RowDescription(a,b)) => go(RowDescription(a,b) :: xs, ys, ccStr)
case Xor.Right(DataRow(a,b)) => go(xs, DataRow(a,b) :: ys, ccStr)
case Xor.Right(EmptyQueryResponse) => go(xs, ys, "EmptyQueryResponse")
case Xor.Right(CommandComplete(x)) => go(xs, ys, x)
case Xor.Right(ErrorResponse(e)) =>
case Right(RowDescription(a,b)) => go(RowDescription(a,b) :: xs, ys, ccStr)
case Right(DataRow(a,b)) => go(xs, DataRow(a,b) :: ys, ccStr)
case Right(EmptyQueryResponse) => go(xs, ys, "EmptyQueryResponse")
case Right(CommandComplete(x)) => go(xs, ys, x)
case Right(ErrorResponse(e)) =>
Future.exception(new PostgresqlServerFailure(e))
case Xor.Right(NoticeResponse(_)) => go(xs, ys, ccStr) // throw Notice Responses away
case Xor.Right(Idle) => Future.value((xs.reverse, ys.reverse, ccStr))
case Xor.Right(u) =>
case Right(NoticeResponse(_)) => go(xs, ys, ccStr) // throw Notice Responses away
case Right(Idle) => Future.value((xs.reverse, ys.reverse, ccStr))
case Right(u) =>
Future.exception(new PostgresqlStateMachineFailure("Query", u.toString))
case Xor.Left(l) => Future.exception(l)
case Left(l) => Future.exception(l)
}
)

Expand Down Expand Up @@ -147,16 +146,16 @@ private[roc] final class ClientDispatcher(trans: Transport[Packet, Packet],

type ParamStatuses = List[ParameterStatus]
type BKDs = List[BackendKeyData]
def go(safetyCheck: Int, xs: ParamStatuses, ys: BKDs): Future[(ParamStatuses, BKDs)] =
def go(safetyCheck: Int, xs: ParamStatuses, ys: BKDs): Future[(ParamStatuses, BKDs)] =
safetyCheck match {
// TODO - create an Error type for this
case x if x > 1000 => Future.exception(new Exception())
case x if x < 1000 => trans.read().flatMap(packet => Message.decode(packet) match {
case Xor.Left(l) => Future.exception(l)
case Xor.Right(ParameterStatus(i, j)) => go(safetyCheck + 1, ParameterStatus(i,j) :: xs, ys)
case Xor.Right(BackendKeyData(i, j)) => go(safetyCheck + 1, xs, BackendKeyData(i, j) :: ys)
case Xor.Right(Idle) => Future.value((xs, ys))
case Xor.Right(message) => Future.exception(
case Left(l) => Future.exception(l)
case Right(ParameterStatus(i, j)) => go(safetyCheck + 1, ParameterStatus(i,j) :: xs, ys)
case Right(BackendKeyData(i, j)) => go(safetyCheck + 1, xs, BackendKeyData(i, j) :: ys)
case Right(Idle) => Future.value((xs, ys))
case Right(message) => Future.exception(
new PostgresqlStateMachineFailure("StartupMessage", message.toString)
)
})
Expand Down
55 changes: 27 additions & 28 deletions core/src/main/scala/roc/postgresql/Messages.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ package roc
package postgresql

import cats.Eq
import cats.data.Xor
import cats.std.all._
import cats.instances.all._
import cats.syntax.eq._
import com.twitter.util.Future
import java.nio.charset.StandardCharsets
Expand All @@ -30,7 +29,7 @@ private[postgresql] object Message {
val TerminateByte: Char = 'X'
val NoticeResponseByte: Char = 'N'

private[postgresql] def decode(packet: Packet): Xor[Failure, Message] = packet.messageType match {
private[postgresql] def decode(packet: Packet): Either[Failure, Message] = packet.messageType match {
case Some(mt) if mt === AuthenticationMessageByte => decodePacket[AuthenticationMessage](packet)
case Some(mt) if mt === ErrorByte => decodePacket[ErrorResponse](packet)
case Some(mt) if mt === NoticeResponseByte => decodePacket[NoticeResponse](packet)
Expand All @@ -40,12 +39,12 @@ private[postgresql] object Message {
case Some(mt) if mt === RowDescriptionByte => decodePacket[RowDescription](packet)
case Some(mt) if mt === DataRowByte => decodePacket[DataRow](packet)
case Some(mt) if mt === CommandCompleteByte => decodePacket[CommandComplete](packet)
case Some(mt) if mt === EmptyQueryResponseByte => Xor.Right(EmptyQueryResponse)
case Some(mt) if mt === EmptyQueryResponseByte => Right(EmptyQueryResponse)
case Some(mt) => {
println(s"Inside Some($mt)")
Xor.Left(new UnknownPostgresqlMessageTypeFailure(mt))
Left(new UnknownPostgresqlMessageTypeFailure(mt))
}
case None => Xor.Left(new UnexpectedNoneFailure(""))
case None => Left(new UnexpectedNoneFailure(""))
}

implicit val messageEq: Eq[Message] = new Eq[Message] {
Expand All @@ -61,7 +60,7 @@ private[postgresql] case class Query(queryString: String) extends FrontendMessag

private[postgresql] case class PasswordMessage(password: String) extends FrontendMessage
private[postgresql] object PasswordMessage {
def encryptMD5Passwd(user: String, passwd: String,
def encryptMD5Passwd(user: String, passwd: String,
salt: Array[Byte]): String = {
val md = MessageDigest.getInstance("MD5")
md.update((passwd + user).getBytes)
Expand All @@ -81,21 +80,21 @@ private[postgresql] case class ErrorResponse(error: PostgresqlMessage) extends B

private[postgresql] sealed abstract class AuthenticationMessage extends BackendMessage
private[postgresql] object AuthenticationMessage {
def apply(tuple: (Int, Option[Array[Byte]])): Failure Xor AuthenticationMessage = tuple match {
case (0, None) => Xor.Right(AuthenticationOk)
case (2, None) => Xor.Right(AuthenticationKerberosV5)
case (3, None) => Xor.Right(AuthenticationClearTxtPasswd)
case (5, Some(bytes)) => Xor.Right(new AuthenticationMD5Passwd(bytes))
case (6, None) => Xor.Right(AuthenticationSCMCredential)
case (7, None) => Xor.Right(AuthenticationGSS)
case (8, Some(bytes)) => Xor.Right(new AuthenticationGSSContinue(bytes))
case (9, None) => Xor.Right(AuthenticationSSPI)
case (x, _) => Xor.Left(new UnknownAuthenticationRequestFailure(x))
def apply(tuple: (Int, Option[Array[Byte]])): Failure Either AuthenticationMessage = tuple match {
case (0, None) => Right(AuthenticationOk)
case (2, None) => Right(AuthenticationKerberosV5)
case (3, None) => Right(AuthenticationClearTxtPasswd)
case (5, Some(bytes)) => Right(new AuthenticationMD5Passwd(bytes))
case (6, None) => Right(AuthenticationSCMCredential)
case (7, None) => Right(AuthenticationGSS)
case (8, Some(bytes)) => Right(new AuthenticationGSSContinue(bytes))
case (9, None) => Right(AuthenticationSSPI)
case (x, _) => Left(new UnknownAuthenticationRequestFailure(x))
}
}
private[postgresql] case object AuthenticationOk extends AuthenticationMessage
private[postgresql] case object AuthenticationClearTxtPasswd extends AuthenticationMessage
private[postgresql] case class AuthenticationMD5Passwd(salt: Array[Byte])
private[postgresql] case class AuthenticationMD5Passwd(salt: Array[Byte])
extends AuthenticationMessage {
def canEqual(a: Any) = a.isInstanceOf[AuthenticationMD5Passwd]

Expand All @@ -110,30 +109,30 @@ private[postgresql] case object AuthenticationKerberosV5 extends AuthenticationM
private[postgresql] case object AuthenticationSCMCredential extends AuthenticationMessage
private[postgresql] case object AuthenticationGSS extends AuthenticationMessage
private[postgresql] case object AuthenticationSSPI extends AuthenticationMessage
private[postgresql] case class AuthenticationGSSContinue(authBytes: Array[Byte])
private[postgresql] case class AuthenticationGSSContinue(authBytes: Array[Byte])
extends AuthenticationMessage {
def canEqual(a: Any) = a.isInstanceOf[AuthenticationGSSContinue]

final override def equals(that: Any): Boolean = that match {
case x: AuthenticationGSSContinue => x.canEqual(this) &&
case x: AuthenticationGSSContinue => x.canEqual(this) &&
authBytes.length == x.authBytes.length &&
(authBytes sameElements x.authBytes)
case _ => false
}
}

private[postgresql] case class ParameterStatus(parameter: String, value: String)
private[postgresql] case class ParameterStatus(parameter: String, value: String)
extends BackendMessage
private[postgresql] case class BackendKeyData(processId: Int, secretKey: Int) extends BackendMessage

private[postgresql] sealed abstract class ReadyForQuery extends BackendMessage
private[postgresql] object ReadyForQuery {
def apply(transactionStatus: Char): ReadyForQueryDecodingFailure Xor ReadyForQuery =
def apply(transactionStatus: Char): ReadyForQueryDecodingFailure Either ReadyForQuery =
transactionStatus match {
case 'I' => Xor.Right(Idle)
case 'T' => Xor.Right(TransactionBlock)
case 'E' => Xor.Right(FailedTransactionBlock)
case c => Xor.Left(new ReadyForQueryDecodingFailure(c))
case 'I' => Right(Idle)
case 'T' => Right(TransactionBlock)
case 'E' => Right(FailedTransactionBlock)
case c => Left(new ReadyForQueryDecodingFailure(c))
}
}

Expand All @@ -144,8 +143,8 @@ private[postgresql] case object FailedTransactionBlock extends ReadyForQuery
private[postgresql] case object EmptyQueryResponse extends BackendMessage

private[postgresql] case class RowDescription(numFields: Short, fields: List[RowDescriptionField])
extends BackendMessage
private[postgresql] case class RowDescriptionField(name: String, tableObjectId: Int,
extends BackendMessage
private[postgresql] case class RowDescriptionField(name: String, tableObjectId: Int,
tableAttributeId: Short, dataTypeObjectId: Int, dataTypeSize: Short, typeModifier: Int,
formatCode: FormatCode)

Expand Down
27 changes: 13 additions & 14 deletions core/src/main/scala/roc/postgresql/results.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package roc
package postgresql

import cats.data.Xor
import cats.Show
import java.nio.charset.StandardCharsets
import roc.postgresql.failures.{ElementNotFoundFailure, UnsupportedDecodingFailure}
Expand Down Expand Up @@ -48,21 +47,21 @@ final class Result(rowDescription: List[RowDescription], data: List[DataRow], cc

/** The command tag. This is usually a single word that identifies which SQL command was completed.
*
* For an INSERT command, the tag is INSERT oid rows, where rows is the number of rows inserted.
* For an INSERT command, the tag is INSERT oid rows, where rows is the number of rows inserted.
* oid is the object ID of the inserted row if rows is 1 and the target table has OIDs;
* otherwise oid is 0.
*
* For a DELETE command, the tag is DELETE rows where rows is the number of rows deleted.
*
*
* For an UPDATE command, the tag is UPDATE rows where rows is the number of rows updated.
*
* For a SELECT or CREATE TABLE AS command, the tag is SELECT rows where rows is the number of
* For a SELECT or CREATE TABLE AS command, the tag is SELECT rows where rows is the number of
* rows retrieved.
*
* For a MOVE command, the tag is MOVE rows where rows is the number of rows the cursor's
* For a MOVE command, the tag is MOVE rows where rows is the number of rows the cursor's
* position has been changed by.
*
* For a FETCH command, the tag is FETCH rows where rows is the number of rows that have been
* For a FETCH command, the tag is FETCH rows where rows is the number of rows that have been
* retrieved from the cursor.
* @see [[http://www.postgresql.org/docs/current/static/protocol-message-formats.html
* CommandComplete]]
Expand Down Expand Up @@ -97,22 +96,22 @@ final case class Column private[roc](name: Symbol, columnType: Int, formatCode:
}
object Column {
implicit val columnShow: Show[Column] = new Show[Column] {
def show(c: Column): String =
def show(c: Column): String =
s"Column(name=${c.name}, columnType=${c.columnType}, formatCode=${c.formatCode})"
}
}

/** A row returned from a Postgresql Server containing at least one
* [[Element]]
* @param elements a collection of all [[row.postgresql.Element Elements]] returned from
* @param elements a collection of all [[row.postgresql.Element Elements]] returned from
* Postgresql via a query.
*/
final class Row private[postgresql](private[postgresql] val elements: List[Element]) {

/** Returns the [[roc.postgresql.Element Element]] found via the column name
*
* @param columnName the column name given the associated [[roc.postgresql.Element Element]]
* @return the element found via the column name
* @return the element found via the column name
*/
def get(columnName: Symbol): Element = elements.find(_.name == columnName) match {
case Some(e) => e
Expand Down Expand Up @@ -144,7 +143,7 @@ sealed abstract class Element(val name: Symbol, columnType: Int) {
* @param f an implicit [[ElementDecoder]] typeclass
* @return A
*/
def as[A](implicit f: ElementDecoder[A]): A =
def as[A](implicit f: ElementDecoder[A]): A =
fold(f.textDecoder, f.binaryDecoder, f.nullDecoder)

/** Decodes this element as a String
Expand All @@ -156,7 +155,7 @@ sealed abstract class Element(val name: Symbol, columnType: Int) {
{(s: String) => s},
{(bs: Array[Byte]) =>
throw new UnsupportedDecodingFailure(s"Attempted String decoding of Binary column.")},
{() =>
{() =>
throw new UnsupportedDecodingFailure(s"Attempted String decoding of Null column.")}
)

Expand All @@ -165,11 +164,11 @@ sealed abstract class Element(val name: Symbol, columnType: Int) {
* @see [[http://www.postgresql.org/docs/current/static/protocol-overview.html
* 50.1.3 Formats and Format Codes]]
* @note Binary representations for integers use network byte order (most significant byte first).
* For other data types consult the documentation or source code to learn about the binary
* For other data types consult the documentation or source code to learn about the binary
* representation.
*/
def asBytes(): Array[Byte] = fold(
{(s: String) =>
{(s: String) =>
throw new UnsupportedDecodingFailure(s"Attempted Binary decoding of String column.")},
{(bs: Array[Byte]) => bs},
{() =>
Expand All @@ -178,7 +177,7 @@ sealed abstract class Element(val name: Symbol, columnType: Int) {
}

case class Null(override val name: Symbol, columnType: Int) extends Element(name, columnType)
case class Text(override val name: Symbol, columnType: Int, value: String)
case class Text(override val name: Symbol, columnType: Int, value: String)
extends Element(name, columnType)
case class Binary(override val name: Symbol, columnType: Int, value: Array[Byte])
extends Element(name, columnType)
Expand Down
Loading