Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
    Ramon Marco L. Navarro
    @ramonmaruko
    Hello, is there an artifact for 2.13?
    If not, would it be possible for you to publish one?
    Filippo Mariotti
    @barambani
    Hi, I was about to release a new version that will publish for 2.13 as well.
    it has been a while since the last release so the api has changed and is not code compatible with the previous. Just to keep in mind
    Ramon Marco L. Navarro
    @ramonmaruko
    That's good to hear
    Yes, I'm migrating my codebase to work with the master right now
    Why is there laserdisc.Functor instead of just using cats.Functor?
    Filippo Mariotti
    @barambani
    That’s to avoid a dependency on Cats in the protocol
    Ian de Beer
    @iandebeer
    Hi, I am interested to use laserdisc as a client for Tile38, since it also uses the RESP protocol. Any suggestions where (and how) I start to implement the Tile38 commands?
    Julien Jean Paul Sirocchi
    @sirocchj
    Hi @iandebeer I’m not familiar with tile38 but if it complies to RESP then you should get the wire encoding/decoding and framing for free from laserdisc. The “only” thing you’d need to do is implement the appropriate Protocol instances. Take a look at maybe the Redis LIST commands (https://redis.io/commands#list) and how it got “translated” in laserdisc (https://github.com/laserdisc-io/laserdisc/blob/f3f147d914a00dcf76987e75aa994fc64baaf745/core/src/main/scala/laserdisc/protocol/ListP.scala) to see an example of what you need to do. Ultimately, you want to supply the name on the wire for the command and the parameters (as a scala List if monomorphic - same types - or a shapeless hlist otherwise) and then you need to tie together the RESP response type (String, BulkString, integer etc) with the type you wish to return (the `.as[Num, Int] part). Again, examples in that protocol file (or in all others in that directory) but feel free to ping if you get stuck!
    Filippo Mariotti
    @barambani
    for reference here’s the list of commands
    Ian de Beer
    @iandebeer
    Great, thanks. I'll be happy to contribute an extension library for Tile38 once I have the Protocol instances implemented. (if you think it is worth while)
    Julien Jean Paul Sirocchi
    @sirocchj
    Absolutely! Looking forward to it!
    Ian de Beer
    @iandebeer
    @sirocchj @barambani : I am quite perplexed by the role of the templates? It seems there is a template for each command you implement, but I am unclear as to what is coded in the template for expansion to the xxxExtP.scala
    Julien Jean Paul Sirocchi
    @sirocchj
    The templates are mostly for expanding arities, that is if a command accepts an arbitrary number of fields we generally have one that would take a list (or an HList of a given shape) and use the template to emit versions which are more ergonomic for the end user to use and which call into the more powerful ones
    This is expanding lpush to have versions of it that accept a key: Key and 1-21 a: A types
    But the actual lpush that it’s calling (https://github.com/laserdisc-io/laserdisc/blob/109ec6d0e8401df4bcad73ee5f034d6e1f7e18ae/core/src/main/scala/laserdisc/protocol/ListP.scala#L41) is accepting a key: Key and a values: OneOrMore[A]
    Where OneOrMore is a refined type (see https://github.com/fthomas/refined)
    Julien Jean Paul Sirocchi
    @sirocchj
    This is a simple case and it could have likely been solved also using classic (key: Key, one: A, more: A*)
    But the concept is the same for the other, more complex cases
    The templating used is sbt-boilerplate
    All in all, I don’t think you should worry about them atm
    Again the benefit is mostly ergonomics from the end user pov
    Ian de Beer
    @iandebeer
    Thanks for the clarification.
    Julien Jean Paul Sirocchi
    @sirocchj
    You’re welcome! Let us know if you get stuck and/or need some help or guidance!
    Ian de Beer
    @iandebeer
    Do you have any advice on how to best decode the response I get from Tile38 for instance the SCAN command returns:Arr(
    Num(0),
    Arr(
    Arr(
    Bulk(truck1),
    Bulk({"type":"Point","coordinates":[-112.2693,33.5123]})),
    Arr(
    Bulk(truck2),
    Bulk({"type":"Point","coordinates":[33.4626,-80.1695,100]})
    )
    )
    )
    Julien Jean Paul Sirocchi
    @sirocchj
    For now (we’re exploring ideas for carrying around/recovering more type info) you’d need to define your case class that represents the above arr of Bulk pairs) and then define a Read[Arr, Seq[YourCaseClass]]
    Your protocol return type would be : Protocol.Aux[Arr, Scan[YourCaseClass]]
    And the rest should be resolved by existing instances (see Read.scala lines 213/216)
    Ian de Beer
    @iandebeer
    Great, will give it a try
    Julien Jean Paul Sirocchi
    @sirocchj
    Cool keep us posted and let us know if we can be of more help
    Ian de Beer
    @iandebeer

    If you could please indulge me one more time...

    If I understand your instructions correctly, I must create a case class that comprises of 2 String fields for the Bulk pairs:
    case class ScanAsset(assetId:String,geoJson:String)

    with a Reader implementation :
    // The final implementation will be more complex as I probably need to fold over the Seq of Assets -- this is to test
    implicit def arr2ScanAsset(implicit R:Read[Arr, Seq[ScanAsset]]): Read[Arr,Seq[ScanAsset]] = instancePF(expectation = "Arr,(String,String)"){
    case Arr(Bulk(assetId) +: Bulk(geoJson) +: Seq()) => Seq(ScanAsset(assetId,geoJson))
    }

    and protocol function:
    def scanT (key: Key): Protocol.Aux[Scan[ScanAsset]]= Protocol("SCAN", key :: HNil).as[Arr,Scan[ScanAsset]]

    I test with:

    client.send(
    scanT("fleet")
    ) >>= {
    case Right(assets:Scan[Seq[ScanRKeyValue]]) =>
    log info "result = $assets"
    case other =>
    log.error(s"something went wrong $other") >>
    IO.raiseError(new RuntimeException("boom"))
    }

    However I get a compile error:
    [error] /Users/ian/dev/qanat_proto/src/main/scala/laserdisc/protocol/PKeys.scala:67:88: diverging implicit expansion for type laserdisc.protocol.RESPRead.Aux[laserdisc.protocol.Arr :+: shapeless.CNil,laserdisc.Scan[laserdisc.protocol.PKeys.ScanAsset]]
    [error] starting with method arr2ScanAsset in trait PKeysBase
    [error] def scanT (key: Key): Protocol.Aux[Scan[ScanAsset]]= Protocol("SCAN", key :: HNil).as[Arr,Scan[ScanAsset]]
    [error] ^
    [error] one error found

    Julien Jean Paul Sirocchi
    @sirocchj
    I’m on mobile but if I’m reading correctly you’re defining your implicit in terms of an implicit with the same shape. You should just implicit val arr2ScanAsset: Read[Arr, Seq[ScanAsset]] = instancePF(...)
    Your implementation also likely needs to look at the outer shape (Arr, which will become your Seq, even if you’re going to be emitting for testing purposes just one element) and the inner shape (Arr of the two Bulk strings)
    So something more like
    case Arr(Arr(Bulk(assetId) +: Bulk(geoJson) +: Seq()) +: Seq()) => Seq(ScanAsset(assetId, geoJson))
    Ian de Beer
    @iandebeer

    Thanks for all help thus far. I have managed to resolve my issues with decoding Tile38 responses. One of the issues with Tile38 commands/queries is that it allows for multiple optional parameters. I though it best to create a Command case class with Options and default None's for the parameters and then derive and HList from the case class.

    final case class Command(command: String, key: String, cursor: Option[Int] = None, limit: Option[Int] = None, `match`: Option[String] = None,
                             where: Option[String] = None, whereIn: Option[String] = None, whereEval: Option[String] = None,
                             whereEvalSHA: Option[String] = None, output: Option[String] = Some("OBJECTS")) extends CommandLike {
      override def toHList(): (String, HList) = toHList(this)
    }

    So instead of a command like:

      def scan(key: Key): Protocol.Aux[ScanTile[ScanAsset]] = Protocol("SCAN", "fleet3" :: "LIMIT" :: 1 :: "OBJECTS" :: HNil).as[Arr, ScanTile[ScanAsset]]

    I use:

     def exec(command: Command): Protocol.Aux[ScanTile[ScanAsset]] = {
        val t: (String, HList) = command.toHList()
         Protocol( t._1, t._2).as[Arr, ScanTile[ScanAsset]]
      }

    But this gives a compile error despite the shape of both HList being exactly the same. Probably more of a Shapeless issue than a Laserdisc one, but any advice will be much appreciated:

    [error] /Users/ian/dev/qanat_proto/src/main/scala/laserdisc/protocol/PKeys.scala:123:14: Implicit not found RESPParamWrite[shapeless.HList].
    [error]
    [error] Normally you would not need to define one manually, as one will be derived for you automatically iff:
    [error] - an instance of Show[shapeless.HList] is in scope
    [error] - shapeless.HList is a List whose LUB has a RESPParamWrite instance defined
    [error] - shapeless.HList is an HList whose elements all have a RESPParamWrite instance defined
    [error]      Protocol( t._1, t._2).as[Arr, ScanTile[ScanAsset]]
    [error]              ^
    [error] one error found
    Julien Jean Paul Sirocchi
    @sirocchj
    GM and great to hear you’re making progress! I’ve been long debating also whether go with something similiar to what you ended up with - it looks appealing for sure, especially when (to support more “ergonomic” usage) you’d otherwise be exploding the many combinations that a given command may have. The problem you have at hand, however, is very much “ours”, meaning that in order for Protocol.apply to work an instance of RESPParamWrite needs to exist for the supplied shape (see https://github.com/laserdisc-io/laserdisc/blob/master/core/src/main/scala/laserdisc/protocol/Protocol.scala#L90). However, the shape you’re supplying is not known at compile time as anything more than HList (i.e. it’s not - as it could be - String :: Option[Int] :: Option[Int] :: Option[String] :: Option[String] :: Option[String] :: Option[String] :: Option[String] :: Option[String] :: HNil, deriving it from the product type Command stripped of the head) and we don’t have in laserdisc an implicitly available RESPParamWrite[HList] (nor Show[HList] for that matter). I’d suggest, if you want to go down this road, to separate the command name from it’s args and define your method as def exec[L <: HList](command: String, params: Parameters)(implicit G: Generic.Aux[Parameters, L], ev1: RESPParamWrite[L]): Protocol.Aux[ScanTile[ScanAsset]] = Protocol(command, G.to(params)).as.[Arr, ScanTile[ScanAsset]]. OTOH, I suspect you may need to intersperse some of the actual values with “prefixes”, e.g. “WHERE” :: where :: “WHEREIN” :: whereIn etc… so you may need to do a bit more work inside the method definition. HTH!