Skip to content

Commit

Permalink
Adding HTTP Support
Browse files Browse the repository at this point in the history
  • Loading branch information
kclay committed Aug 16, 2014
1 parent eb09ffc commit 7fa0c65
Show file tree
Hide file tree
Showing 7 changed files with 403 additions and 20 deletions.
17 changes: 1 addition & 16 deletions core/src/main/scala/com/rethinkscala/Implicits.scala
Expand Up @@ -84,26 +84,11 @@ trait ToAst[A] {

}


trait ToFunctionalImplicts{



implicit def docToFunctional[T <: Document](seq: Sequence[T]) = new ToFunctional[T, Var](seq)


implicit def toFunctional[T](seq: Sequence[T])(implicit ast: ToAst[T]): ToFunctional[T, ast.TypeMember] = new ToFunctional[T, ast.TypeMember](seq)


}
class ToFunctional[T, A >: Var](seq: Sequence[T]) {


def concatMap[B <: Typed, Inner](f: A => B)(implicit cm: CanMap[T, B, Inner]) = ConcatMap[Inner](seq.underlying, FuncWrap(f))

def map[B <: Typed, Inner](f: A => B)(implicit cm: CanMap[T, B, Inner]) = RMap[Inner](seq.underlying, FuncWrap(f))


def reduce[P ](f: (A, A) =>Produce0[P]) = Reduce[T,P](seq.underlying, f)

}
Expand Down Expand Up @@ -284,7 +269,7 @@ object Implicits {


trait Common extends CanMapImplicits
with ToAstImplicts with ToFunctionalImplicts
with ToAstImplicts
with ReceptacleImplicits with ImplicitConversions with net.Versions with Helpers{


Expand Down
101 changes: 100 additions & 1 deletion core/src/main/scala/com/rethinkscala/Options.scala
@@ -1,5 +1,7 @@
package com.rethinkscala

import com.rethinkscala.ast._

/**
* Created with IntelliJ IDEA.
* User: keyston
Expand Down Expand Up @@ -73,4 +75,101 @@ object Durability extends Enumeration {
type Kind = Value
val Hard = Value("hard")
val Soft = Value("soft")
}
}



trait RequestOptionsOps{

import HttpMethod._
type OptionType

def lift(f:RequestOptions=>RequestOptions):OptionType
def asPost =lift(_.copy(method=Some(POST)))
def asGet = lift(_.copy(method= Some(GET)))
def asHead = lift(_.copy(method= Some(HEAD)))
def asPatch = lift(_.copy(method= Some(PATCH)))
def asPut = lift(_.copy(method= Some(PUT)))



def withHeader(headers:HttpHeader*) = :=(headers)
def withHeaders(headers: HttpHeaders) = :=(headers)
def :=(headers:HttpHeaders) = lift(_.copy(headers = headers))
def :=(headers:Seq[HttpHeader]) = lift(_.copy(headers = HttpHeaders(headers)))
def ++(headers:HttpHeaders) = lift(o=>o.copy(headers = o.headers ++headers))
def ++(headers:Seq[HttpHeader]) = lift(o=>o.copy(headers=o.headers++headers))
def addHeaders(headers:HttpHeaders) = ++(headers)
def addHeaders(headers:HttpHeader*)= ++(headers)

def withBasic(user:String,pass:String) =lift(_.copy(auth = Some(BasicAuth(user,pass))))
def withDigest(user:String,pass:String) = lift(_.copy(auth = Some(DigestAuth(user,pass))))
def withData(data:HttpBody[_]) = lift(_.copy(data = Some(data)))
}
case class RequestOptions(method:Option[HttpMethod.Value]=None,
auth:Option[HttpAuth] = None,params:Map[String,Any]=Map.empty,
headers:HttpHeaders = HttpHeaders.empty,
data:Option[HttpBody[_]] = None
) extends Options with RequestOptionsOps{

override type OptionType = RequestOptions

override def lift(f: (RequestOptions) => RequestOptions) = f(this)

override def toMap = Map("method"->method,"auth"->auth,"params"->Some(params))
}


trait PaginationOptionsOps{
type OptionType
protected def liftPagination(f:PaginationOptions=>PaginationOptions):OptionType

def withPage(strategy:PaginationStrategy):OptionType = liftPagination(_.copy(strategy=Some(strategy)))
def withPage(f:PaginationData=>Typed):OptionType = withPage(PaginationStrategy(f))
def limit(amount:Int) = liftPagination(_.copy(limit = Some(amount)))


}
case class PaginationOptions(strategy:Option[PaginationStrategy]= None,limit:Option[Int]=None)
extends Options with PaginationOptionsOps{

override type OptionType = PaginationOptions

override def liftPagination(f: (PaginationOptions) => PaginationOptions) = f(this)


override def toMap = Map("page"->strategy.map(_.value),"page_limit"->limit)
}

case class HttpOptions(
timeout:Option[Int]=None,
reattempts:Option[Int] = None,
redirect:Option[Int] = None,
verify:Option[Boolean] = None,
resultFormat:Option[ResultFormat.Kind] = None,
request:RequestOptions = RequestOptions(),
pagination:PaginationOptions = PaginationOptions()
) extends Options with RequestOptionsOps with PaginationOptionsOps{

lazy val mapValue = Map("timeout"->timeout,"reattempts"->reattempts,
"redirect"->redirect,"verify"->verify ,"result_format"->resultFormat
)
override def toMap =(mapValue/:request.toMap)(_+_)
def withTimeout(amount:Int) = copy(timeout=Some(amount))
def withReattempts(amount:Int) = copy(reattempts=Some(amount))
def withRedirect(amount:Int) = copy(redirect=Some(amount))
def withVerify(value:Boolean) = copy(verify=Some(value))
def asJson = copy(resultFormat=Some(ResultFormat.Json))
def asJsonp = copy(resultFormat=Some(ResultFormat.Jsonp))
def asText = copy(resultFormat = Some(ResultFormat.Text))


override type OptionType = HttpOptions

override def lift(f: (RequestOptions) => RequestOptions) = copy(request=f(request))

override def liftPagination(f: (PaginationOptions) => PaginationOptions) = copy(pagination = f(pagination))
}



1 change: 1 addition & 0 deletions core/src/main/scala/com/rethinkscala/R.scala
Expand Up @@ -44,6 +44,7 @@ trait RethinkApi extends TimeNames {



// def http

def expr(term: Term): Term = term
def expr(value: String): StringDatum = Expr(value)
Expand Down
146 changes: 146 additions & 0 deletions core/src/main/scala/com/rethinkscala/ast/Http.scala
@@ -0,0 +1,146 @@
package com.rethinkscala.ast


import java.io.File

import com.rethinkscala.HttpOptions
import ql2.Ql2.Term.TermType

/**
* Created with IntelliJ IDEA.
* User: keyston
* Date: 7/19/14
* Time: 12:23 PM
*
*/
case class Http(url: String, options: HttpOptions) extends ProduceAnyDocument {

override lazy val args = buildArgs(url)
override lazy val optargs = buildOptArgs(options.toMap)

override def termType = TermType.HTTP
}


object ResultFormat extends Enumeration {
type Kind = Value
val Text = Value("text")
val Json = Value("json")
val Jsonp = Value("jsonp")
val Auto = Value("auto")
}

object HttpMethod extends Enumeration {
type Kind = Value
val GET = Value("GET")
val POST = Value("POST")
val PUT = Value("PUT")
val PATCH = Value("PATCH")
val DELETE = Value("DELETE")
val HEAD = Value("HEAD")


}

sealed abstract class HttpAuth {
val user: String
val pass: String
val `type`: String
}

case class BasicAuth(user: String, pass: String) extends HttpAuth {
override val `type`: String = "basic"
}

case class DigestAuth(user: String, pass: String) extends HttpAuth {
override val `type`: String = "digest"
}

object HttpHeader {
implicit def tuple2ToHttpHeader(t: (String, String)) = HttpHeader(t._1, t._2)
}

object HttpHeaders {
implicit def iterableTupleToHttpHeaders(i: Seq[(String, String)]) = HttpHeaders(i.map(h => HttpHeader(h._1, h._2)))

def empty = HttpHeaders(List.empty)
}

case class HttpHeaders(headers: Seq[HttpHeader]) {
def ++(other: HttpHeaders) = copy(headers = headers ++ other.headers)

def ++(other: Seq[HttpHeader]) = copy(headers = headers ++ other)
}

case class HttpHeader(key: String, value: String)


object HttpBody {
implicit def stringToHttpBody(value: String) = HttpStringBody(value)

implicit def mapToHttpFormBody(value: Map[String, Any]) = HttpFormBody(value)

implicit def fileToHttpFormBody(value: File) = HttpFileBody(value)
}

trait HttpBody[T] {
val value: T
}

case class HttpStringBody(value: String) extends HttpBody[String]

case class HttpFormBody(value: Map[String, Any]) extends HttpBody[Map[String, Any]]

case class HttpFileBody(file: File) extends HttpBody[String] {

private[this] lazy val contents = {
val source = scala.io.Source.fromFile(file)
try {
source.getLines() mkString "\n"
} finally {
source.close()
}
}
lazy val value: String = contents
}

trait PaginationStrategy {
type T
val value: T
}

object LinkNext extends PaginationStrategy {
type T = String
override val value = "link-next"
}

object PaginationStrategy {

implicit def funcToPredicte(f: PaginationData => Typed) = new PaginationPredicate(f)

implicit def predicateToStrategy(f: PaginationPredicate) = FunctionPaginationStrategy(f)

def apply(f: PaginationData => Typed) = FunctionPaginationStrategy(f)

}

object PaginationData {
implicit def varToPaginationData(v: Var) = new PaginationData(v)
}

class PaginationData(v: Var) {
lazy val params = v \ "params"
lazy val header = v \ "header"
lazy val value = v \ "value"
}

class PaginationPredicate(f: PaginationData => Typed) extends Predicate1 {
protected def _invoke(vars: Seq[Var]) = f(vars(0))

val amount: Int = 1
}

case class FunctionPaginationStrategy(value: PaginationPredicate) extends PaginationStrategy {
type T = PaginationPredicate

}
4 changes: 4 additions & 0 deletions core/src/main/scala/com/rethinkscala/ast/Sequence.scala
Expand Up @@ -14,6 +14,10 @@ import com.rethinkscala.magnets.GroupFilterMagnet
object Sequence {
implicit def mapDocumentToSequence[T <: Document, ST, S[ST] <: Sequence[ST]] = CanMap[T, S[ST], ST]

implicit def docToFunctional[T <: Document](seq: Sequence[T]) = new ToFunctional[T, Var](seq)
implicit def toFunctional[T](seq: Sequence[T])(implicit ast: ToAst[T]): ToFunctional[T, ast.TypeMember] = new ToFunctional[T, ast.TypeMember](seq)


implicit class ScalaSequence[T](underlying: Sequence[T]) {

def ++(sequence: Sequence[_]) = underlying.union(sequence)
Expand Down

0 comments on commit 7fa0c65

Please sign in to comment.