Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Activity
    Mason Lazalier Edmison
    @masonedmison
    I see. Cool, thanks for sharing. I have to step away for awhile, but I'll give this a look soon.
    Luis Miguel Mejía Suárez
    @BalmungSan
    :+1:
    Mason Lazalier Edmison
    @masonedmison
    After reading that thread, I am inspired again to try to make shapeless3 work :sweat_smile:. I finally figured out a way to derive "decode-like" typeclasses which is ultimately, IIUC, what we need for ResultMapper - though this currently doesn't work for recursive types but I think unfold is the answer for these types of typeclasses.
      // TODO this doesn't work for recursive types
      given [T] (using inst: K0.ProductInstances[ColumnDecoder, T], labels: Labelling[T]): CSVDecoder[T] with
        def decode(values: List[String]): DecodeError[T] =
          val ((_, errOpt), decodeOpt) = inst.unfold[(List[String], Option[Throwable])](values, None) {
            [t] =>
              (acc: (List[String], Option[Throwable]), dec: ColumnDecoder[t]) => {
                val (vs, err) = acc
                val result = dec.decode(vs.head)
                ((vs.tail, result.left.toOption), result.toOption)
              }
          }
          decodeOpt.toRight(errOpt.getOrElse(new Exception("Oopsies.")))
    Mason Lazalier Edmison
    @masonedmison
    I just pushed some changes where ResultMapper is derived using a similar approach as above. auto, semiauto and derives seem to work (from some simple testing) using this current approach. There are still some todos around fixing tests, resolving some not so good errors, and ambiguous implicit errors when having multiple DerivedResultMapper givens declared. All in all, I think this approach should work out.
    Luis Miguel Mejía Suárez
    @BalmungSan
    :tada:
    Thomas Järvstrand
    @tjarvstrand
    Awesome work!
    Mason Lazalier Edmison
    @masonedmison
    :heart: I'll keep plugging away and will probably have some more questions along the way.
    Luis Miguel Mejía Suárez
    @BalmungSan
    :+1:
    Mason Lazalier Edmison
    @masonedmison
    Unless I am missing something, I believe we will need to break out the HList stuff into a separate scala-2 directory within core-test. Any ideas on how we might do that? I was checking kittens for inspo.
    Luis Miguel Mejía Suárez
    @BalmungSan
    @masonedmison it should work the same as with the main, doesn't it?
    Mason Lazalier Edmison
    @masonedmison
    I believe so, yes. I was more asking about how we should name the tests and extract them out, e.g. what is the best way to extract out the hlist tests from DriverSpec.
    I could imagine us
    1) have a DriverSpec in each the scala-2 and scala-3 directories and the only differing bits would be hlist vs. tuple, respectively
    or
    2) Have a base BaseDriverSpec with the "common" tests that work for both versions in scala and then extend this within scala-2 and scala-3 directories (as DriverSpec) adding the hlist and tuple tests there.
    Luis Miguel Mejía Suárez
    @BalmungSan
    @masonedmison I would follow the typelevel style here.
    A empty class that extends a platform depedant trait that contains the actual tests.
    That way, we can refer to that class in the DriverSpec
    Mason Lazalier Edmison
    @masonedmison
    Ah yes very nice. I'll follow this pattern, thanks @BalmungSan
    Luis Miguel Mejía Suárez
    @BalmungSan
    Let meknow if you find any other problem :)
    Mason Lazalier Edmison
    @masonedmison
    Sounds good. I was going to start looking at the Cypher interpolator macro tonight along with fixing the tests using the above suggestion
    Luis Miguel Mejía Suárez
    @BalmungSan
    :tada:
    Luis Miguel Mejía Suárez
    @BalmungSan

    Hi @/all I just opened an issue that brings some complex topics on the table for discussion, I would be very grateful if you can find the time to read it and leave your thoughts.
    Thanks in advance!

    neotypes/neotypes#561

    Mason Lazalier Edmison
    @masonedmison
    Hey all, sort of an update/non-update. Spinning my wheels regarding the CypherStringInterpolator scala3 port. Particularly the bit I am struggling with is how to work with the args: Any* (within c). In scala3, this ends up being Expr[Seq[Any]] to whereas (IIUC) scala2 we are able to get an Iterator[Expr[Any]] (in which we can ultimately get the Tree and type for each element to splice in the code the QueryArgMapper for said type).
    Luis Miguel Mejía Suárez
    @BalmungSan
    Did you checked how literally does it?
    Mason Lazalier Edmison
    @masonedmison
    Ah I have not, good call.
    I was looking at protoquill for some inspo but that stuff is still above my head.
    Mason Lazalier Edmison
    @masonedmison
    Ah it doesn't look like Literally actually uses the Expr[Seq[Any]] - only in reporting an error if interpolation is not supported (here)[https://github.com/typelevel/literally/blob/main/core/shared/src/main/scala-3/org/typelevel/literally/Literally.scala#L41]

    Alex Ioffe suggested doing something like this

    def myMacro(builder: DeferredQueryBuilder): Something = ${ myMacroImpl('builder) }
    def myMacroImpl(builder: Expr[DeferredQueryBuilder])(using Quotes): Expr[Something] =
      builder match
        case '{ CypherStringInterpolator($partsExpr).c(${ Varargs(params) }: _*) } => 
          partsExpr match
            case '{ StringContext.apply(${ Varargs(parts) }: _*) } =>
              // at this point you have parts: Expr[Seq[String]] and params: Expr[Seq[Any]] or something like that

    but I am not sure how we would pass in DeferredQueryBuilder since that is what the macro itself returns.

    Luis Miguel Mejía Suárez
    @BalmungSan
    So I think it should be the opposite.
    def myMacroImpl(builder: Expr[Seq[Any]])(using Quotes): Expr[DeferredQueryBuilder] =
    Or something, I really have not even looked into a hello world example of Scala 3 macros
    Mason Lazalier Edmison
    @masonedmison
    Still plugging away on this. Getting... closer I think/hope?
    Luis Miguel Mejía Suárez
    @BalmungSan
    No worries, thanks a lot fot he hard work!
    Mason Lazalier Edmison
    @masonedmison
    This still needs a lot of work (and the way parts is currently is downright wonky) but after a few days of wrestling with this, I at least have something that compiles so I will savor this as a milestone :sweat_smile:
    package neotypes
    
    import scala.quoted._
    import internal.utils.queryparts.createQuery
    import scala.reflect.*
    import neotypes.types.QueryParam
    import scala.annotation.tailrec
    
    final case class CypherStringInterpolator(private val sc: StringContext) extends AnyVal {
      inline def c(inline args: Any*): DeferredQueryBuilder = ${ CypherStringInterpolator.macroImpl('args, 'sc) }
    }
    
    object CypherStringInterpolator {
    
      type Res = Either[String, QueryArg]
    
      def macroImpl(argsExpr: Expr[Seq[Any]], clz: Expr[StringContext])(using quotes: Quotes): Expr[DeferredQueryBuilder] =
        import quotes.reflect.*
    
        def invert[T: Type](exprs: Expr[Seq[T]]): List[Expr[T]] =
          exprs match {
            case Varargs(props)                     => props.toList
            case '{ Seq(${ Varargs(props) }) }      => props.toList.map(_.asExprOf[T])
            case _ => println(s"Unable to match ${exprs.show} "); null
          }
    
        def argMapperFor(tt: TypeRepr) =
          TypeRepr.of[QueryArgMapper].appliedTo(tt)
    
        def asRightQueryArg(expr: Expr[Any]): Expr[Res] =  
          val tt = expr.asTerm.tpe.widen
          Implicits.search(argMapperFor(tt)) match {
            case iss: ImplicitSearchSuccess => {
              val tcl = iss.tree
              val e = Apply(Select.unique(tcl, "toArg"), expr.asTerm :: Nil)
                .asExprOf[QueryArg]
              '{ Right($e) }  
    
          }
            case isf: ImplicitSearchFailure =>
              val e = Expr(isf.explanation)
              '{ compiletime.error($e) }
        }
    
        def parts: List[Expr[Boolean => Res]] = {
          val inverted = invert(argsExpr)
          inverted  
            .map { (expr: Expr[Any]) => 
              val qarg: Expr[Res] = asRightQueryArg(expr)
              '{
                (b: Boolean) => 
                  if (b) 
                    $qarg
                  else Left($expr.toString)
              } 
            }
        }
    
        val partsPacked: Expr[List[Boolean => Res]] = Expr.ofList(parts)
    
        val boolsAndRes: Expr[(List[Boolean], List[Res])] = '{ 
          $clz
            .parts
            .foldLeft((List.empty[Boolean], List.empty[Res])) { case ((hashTags, res), s) =>
                val nextRes = Left(s) :: res
                if (s.endsWith("#"))
                  (false :: hashTags) -> nextRes
                else
                  (true :: hashTags) -> nextRes
            }
        }
    
        val interleaved: Expr[List[Res]] = 
          '{
            Interleave($partsPacked, $boolsAndRes._2, $boolsAndRes._1)
          }
        '{ createQuery($interleaved: _*) }
      }
    
      object Interleave {
        import CypherStringInterpolator.Res
        def apply(parts: List[Boolean => Res], queries: List[Res], endWithHashTags: List[Boolean]): List[Res] =
          interleave(parts, queries, endWithHashTags, List.empty)
        private[this] def interleave(parts: List[Boolean => Res], queries: List[Res], endWithHashTags: List[Boolean], acc: List[Res]): List[Res] =
          (queries, parts, endWithHashTags) match {
            case (Nil, l2, b)            => acc.reverse ++ (l2 zip b).map { case (e, b) => e(b)} 
            case (l1, Nil, _)            => acc.reverse ++ l1
            case (h1 :: t1, h2 :: t2, bh :: bt) => interleave(t2, t1, bt, h2(bh) +: h1 +: acc)
            case _ => acc
        }
      }
    Luis Miguel Mejía Suárez
    @BalmungSan
    :tada: :tada: :tada:
    Aaron Hiniker
    @hindog
    hey all, is there a way to execute a query with results and ALSO get the ResultSummary somehow? From what I've seen, the only way to get a ResultSummary back is by using the execute method but I also want to return records
    Luis Miguel Mejía Suárez
    @BalmungSan
    @hindog hi, not really, you are right.
    But, it should be possible quite easily to fix that.
    Please, open an issue
    Aaron Hiniker
    @hindog
    will do, thanks
    Luis Miguel Mejía Suárez
    @BalmungSan
    Hi @masonedmison now that neotypes/neotypes#563 is ready
    I was planning to merge and release 0.23.0 soon. However, wanted to confirm first with you, because I would rather publish for Scala 3 before doing that.
    (BTW, any review in that PR would be welcome)
    Mason Lazalier Edmison
    @masonedmison
    @BalmungSan Hi. Sorry I haven't done much work on the scala3 support since my last post above. Assuming my first attempts at the generic and CypherStringInterpolator stuff is not totally off base, the remaining work to be done it to move the shapeless2 specific tests to a separate scala-2 directory. I can try to spend some time on this week in which case we might have something ready for review in the next week or two? Sorry this is taking so long btw.
    I'll try to peek that MR in the next day or two :)
    Luis Miguel Mejía Suárez
    @BalmungSan
    @masonedmison hey no worries, I didn't want to push rather to know the current state and maybe to know if I can help.
    I don't mind waiting a couple of days more, since I would rather publish Scala 3 support before dropping Java 8 and Java 11 support.
    But, also, I actually don't mind that much since I personally am already using Java 17 but no Scala 3.
    And based on the feedback from the issue it seems most folks using neotypes also don't have a problem upgrading Java
    Mason Lazalier Edmison
    @masonedmison
    @BalmungSan Sounds good. I will try to push my latest changes tomorrow and provide a more detailed to-do list in case you would like to help out a bit :).
    Luis Miguel Mejía Suárez
    @BalmungSan
    :D
    Luis Miguel Mejía Suárez
    @BalmungSan
    Oh, I forgot to mention here, sorry.
    @/all neotypes version 0.23.0 was released last weekend! It upgraded to the Java driver series 5 and thus requires Java 17.
    Luis Miguel Mejía Suárez
    @BalmungSan
    @/all neotypes version 0.23.1 was released! It upgraded to the Java driver to 5.3.0
    geoffjohn11
    @geoffjohn11
    :tada: