GithubHelp home page GithubHelp logo

Comments (7)

guizmaii avatar guizmaii commented on June 9, 2024 1

@Aleks67B @jilen Can you please give a concrete example of code before/after maybe? I'm also suffering from long compilation times with Quill and I'm not sure to understand @jilen suggestion

Also, I think that it'd be good to document this trick. Lots of people are suffering from these compilation times. (I can make the PR to document it, no worries)

from zio-quill.

Aleks67B avatar Aleks67B commented on June 9, 2024 1

@guizmaii

Sure, taking the example from the initial comment regarding the ProductId, our previous implicit mapping was:

case class ProductId(id: Long)

protected implicit val productIdDecoder: MappedEncoding[Long, ProductId] = MappedEncoding(ProductId.apply)
protected implicit val productIdEncoder: MappedEncoding[ProductId, Long] = MappedEncoding(_.id)

Updated with explicit Encoders and Decoders:

protected val ctx: PostgresMonixJdbcContext[SnakeCase.type]

protected implicit val productIdDecoder: ctx.Decoder[ProductId] = ctx.mappedDecoder(MappedEncoding(ProductId.apply), ctx.longDecoder)
protected implicit val productIdEncoder: ctx.Encoder[ProductId] = ctx.mappedEncoder(MappedEncoding(_.id), ctx.longEncoder)

from zio-quill.

guizmaii avatar guizmaii commented on June 9, 2024 1

BTW, if anyone is reading this, here's a generic implementation of this trick for zio-prelude newtypes:

// File: `io.example.extensions.scala`
import zio.prelude._
import io.getquill.MappedEncoding
import io.getquill.context.jdbc.JdbcContextTypes

object extensions {

  trait QuillEncoding[A] {
    self: Newtype[A] =>

    def quillEncoder(ctx: JdbcContextTypes[?, ?])(implicit encoder: ctx.Encoder[A]): ctx.Encoder[Type] =
      ctx.mappedEncoder[Type, A](MappedEncoding(unwrap), encoder)

    def quillDecoder(ctx: JdbcContextTypes[?, ?])(implicit decoder: ctx.Decoder[A]): ctx.Decoder[Type] =
      ctx.mappedDecoder[A, Type](MappedEncoding(wrap), decoder)
  }

}

// File: `io.example.domain.scala`
import zio.prelude._
import io.example.extensions._

object domain {
  
  // Subtype example 
  type ProductId = ProductId.Type
  object ProductId extends Subtype[Long] with QuillEncoding[Long]

  // Newtype example
  type AnotherId = AnotherId.Type
  object AnotherId extends Newtype[String] with QuillEncoding[String]

}


// File: `io.example.db.Codecs.scala`
import io.getquill.context.jdbc.*
import io.example.domain._

/**
 * Note that I'm using PG. Some of the traits I extend here come from the PG extensions of Quill.
 * If you're not using PG, you might need to replace/remove some of them.
 */
trait Codecs
    extends Encoders
    with Decoders
    with ObjectGenericTimeEncoders
    with ObjectGenericTimeDecoders
    with BooleanObjectEncoding
    with UUIDObjectEncoding
    with ArrayDecoders
    with ArrayEncoders { self: JdbcContextTypes[?, ?] =>

  // IntelliJ might not be happy with the implicits required by the `quillEncoder` and `quillDecoder` methods so we tell it to shut up with the following weird comment:
  /*_*/
  implicit val encoderProductId: Encoder[ProductId] = ProductId.quillEncoder(self)
  implicit val decoderProductId: Decoder[ProductId] = ProductId.quillDecoder(self)
  implicit val encoderAnotherId: Encoder[AnotherId] = AnotherId.quillEncoder(self)
  implicit val decoderAnotherId: Decoder[AnotherId] = AnotherId.quillDecoder(self)
  /*_*/
}

// Finally, you need to mixin this `Codecs` trait to your Quill context. Here's an example:
// File: `io.example.db.DBLive.scala`
import io.getquill.context.jdbc.*
import io.getquill.*
import io.example.domain._

trait DB {
  ...
}

object DB {
  def live: ULayer[DB] = ...
}

final class DBLive(dataSource: DataSource) extends DB {
  import DBLive.Context.*
  
  ...
}

object DBLive {

  /**
   *  Note the `with Codecs` here. That's what you need to add to your context
   */
  
  // noinspection TypeAnnotation
  @SuppressWarnings(Array("scalafix:ExplicitResultTypes"))
  private[db] object Context extends PostgresZioJdbcContext(naming = Literal) with Codecs {
    import extras.*
    
    private[db] def products  = quote(querySchema[Product]("products"))
    
    def selectProductsById(id: ProductId) = 
      quote {
        products.filter(_.id === lift(id))
      }
  
  }
}

(Note that the above code wasn't written in an IDE nor was compiled so it might be slightly incorrect but you have the general idea. The QuillEncoding and its methods are correct. It's copy/pasted from my project)

from zio-quill.

jilen avatar jilen commented on June 9, 2024

You may first try to use the -Yprofile-trace to get some insights. (Note seems only works on jdk 8, higher version may need some java9 module system tweak )

We have some evidence that replacing the strongly-typed IDs with bare longs improves query compilation time

And if you can confirm MappedEncoding cause the slow down.
You can just define the val xidEncoder: Encoder[Xid] = mappedEncoder ... directly to reduce the implicit resolution time.

from zio-quill.

Aleks67B avatar Aleks67B commented on June 9, 2024

Thank you for the suggestion @jilen . We have removed our implicit MappedEncodings and changed to defining Encoders and Decoders directly. This has resulted in a ~30% reduction in compile time.

from zio-quill.

guizmaii avatar guizmaii commented on June 9, 2024

Thanks a lot @Aleks67B

from zio-quill.

guizmaii avatar guizmaii commented on June 9, 2024

@Aleks67B Sidenote question: why are you using case classes to implement your typesafe ids and not zio-prelude newtypes? AFAIK, case classes have an overhead at runtime (instantiation) which newtypes don't have

Example:

import zio.prelude._

type ProductId = ProductId.Type
object ProductId extends Subtype[Long] // Can also be `... extends Newtype[Long]` depending on your needs

from zio-quill.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.